> ## Documentation Index
> Fetch the complete documentation index at: https://phaseo.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Phaseo Gateway base URL: https://api.phaseo.app/v1. Send `Authorization: Bearer $PHASEO_API_KEY` with every request.
> Model IDs look like `provider/model`, for example `openai/gpt-6-astra`. Do not guess IDs: list them with `GET /v1/models` or check https://phaseo.app/models. `phaseo/free` routes to an available free model and needs no wallet balance.
> For new text integrations prefer `POST /v1/responses`. `POST /v1/chat/completions` (OpenAI format) and `POST /v1/messages` (Anthropic format) suit existing code.
> The full API contract is https://phaseo.app/docs/openapi/v1/openapi.yaml. Official SDKs: `@phaseo/sdk` (TypeScript) and `phaseo` (Python), plus Go, C#, PHP, Ruby and Rust.
> Search these docs over MCP at https://phaseo.app/docs/mcp, and install Phaseo skills with `npx skills add https://phaseo.app/docs`. If a page is wrong or out of date, report it with the MCP `submit_feedback` tool.
> Manage Phaseo accounts with the `phaseo` CLI (`npm install -g @phaseo/cli`, then `phaseo login` or `phaseo login --device-code`), the `/v1` Management API or the MCP server at `https://mcp.phaseo.app/mcp?access=manage`. Do not send users to the dashboard for account tasks. A person is still needed for sign-up, approving a sign-in, paying the first top-up on the checkout link that `phaseo credits add` returns when no card is saved, confirming each saved-card top-up from the emailed link, and account security (password, MFA, passkeys). Create API keys with `phaseo keys create --name <name> --json`; never guess one. Credit top-ups need `phaseo login --scopes billing:write` first. Task map: https://phaseo.app/docs/v1/developers/manage-from-an-agent.md.

# Beispiele

> Gezielte Agent-SDK-Muster für Freigaben, Streaming und begrenzte Läufe kopieren oder mit einem vollständigen Rezept starten.

Beginne mit einem Agenten, ein oder zwei deterministischen Tools und einer Freigabe rund um Nebeneffekte. Die Snippets unten setzen einen Gateway-Agenten-Client in `client` voraus (und in Go einen `ctx`). Sie dienen der Veranschaulichung: `deployments`, `store`, `search` und `fetchPage` stehen für deinen eigenen Code.

## Freigabepflichtiges Deployment

Das Deploy-Tool pausiert den Lauf, bis ein Mensch genau diesen Aufruf freigibt. Speichere das pausierte Ergebnis, zeige den ausstehenden Aufruf einer prüfenden Person und setze dann mit der Entscheidung fort.

```typescript TypeScript theme={null}
const deploy = defineTool({
  id: "deploy",
  requireApproval: ({ environment }) => environment === "production",
  async execute(input: { environment: string }) {
    return deployments.deploy(input.environment);
  },
});

const agent = createAgent({ id: "release-agent", model: "openai/gpt-6-astra", tools: [deploy] });

let result = await agent.run({ input: "Ship release 42 to production", client });
if (result.run.status === "waiting_for_human") {
  await store.save(result); // result.run.pause.pendingToolCalls einer prüfenden Person zeigen

  // Später, nachdem die prüfende Person freigegeben hat:
  const callId = result.run.pause!.pendingToolCalls[0].call.id;
  result = await agent.continueRun({ run: result, client, approvals: [{ toolCallId: callId }] });
}
```

```python Python theme={null}
from phaseo_agent import AgentTool, AgentToolDecision, create_agent, define_tool

deploy = define_tool(AgentTool(
    id="deploy",
    description="Deploy the selected release",
    parameters={"type": "object", "properties": {"environment": {"type": "string"}}},
    require_approval=True,
    execute=lambda tool_input, runtime: deployments.deploy(tool_input["environment"]),
))

agent = create_agent({"id": "release-agent", "model": "openai/gpt-6-astra", "tools": [deploy]})

result = agent.run(input="Ship release 42", client=client)
if result.run.status == "waiting_for_human":
    store.save(result)  # result.run.pause.pending_tool_calls einer prüfenden Person zeigen

    # Später, nachdem die prüfende Person freigegeben hat:
    call_id = result.run.pause.pending_tool_calls[0].call.id
    result = agent.continue_run(run=result, client=client, approvals=[AgentToolDecision(call_id)])
```

```go Go theme={null}
deploy := phaseoagent.DefineTool(phaseoagent.Tool{
  ID:              "deploy",
  Description:     "Deploy the selected release",
  RequireApproval: true,
  Execute: func(input any, runtime phaseoagent.RuntimeContext) (any, error) {
    return deploymentService.Deploy(input)
  },
})

agent := phaseoagent.CreateAgent(phaseoagent.AgentDefinition{
  ID: "release-agent", Model: "openai/gpt-6-astra", Tools: []phaseoagent.Tool{deploy},
})

result, err := agent.Run(ctx, phaseoagent.RunOptions{Input: "Ship release 42", Client: client})
if err == nil && result.Run.Status == "waiting_for_human" {
  store.Save(result) // result.Run.Pause.PendingToolCalls einer prüfenden Person zeigen

  // Später, nachdem die prüfende Person freigegeben hat:
  callID := result.Run.Pause.PendingToolCalls[0].Call.ID
  result, err = agent.Continue(ctx, phaseoagent.ContinueOptions{
    Run: result, Client: client,
    Approvals: []phaseoagent.ToolDecision{{ToolCallID: callID}},
  })
}
```

```csharp C# theme={null}
var deploy = AgentSdk.DefineTool(new Tool(
    "deploy",
    async (input, runtime) => await deployments.DeployAsync(input, runtime.CancellationToken),
    "Deploy the selected release")
{
    RequireApproval = true,
});

var agent = AgentSdk.CreateAgent(new AgentDefinition
{
    Id = "release-agent", Model = "openai/gpt-6-astra", Tools = new[] { deploy },
});

var result = await agent.Run(new RunOptions { Input = "Ship release 42", Client = client });
if (result.Run.Status == "waiting_for_human")
{
    await store.SaveAsync(result); // result.Run.Pause.PendingToolCalls einer prüfenden Person zeigen

    // Später, nachdem die prüfende Person freigegeben hat:
    var callId = result.Run.Pause!.PendingToolCalls![0].Call.Id;
    result = await agent.ContinueRun(new ContinueOptions
    {
        Run = result, Client = client, Approvals = new[] { new ToolDecision(callId) },
    });
}
```

```php PHP theme={null}
use Phaseo\AgentSdk\{AgentDefinition, AgentSdk, Tool, ToolDecision};

$deploy = AgentSdk::defineTool(new Tool(
    id: "deploy",
    execute: fn (array $input, $runtime) => $deployments->deploy($input),
    description: "Deploy the selected release",
    requireApproval: true,
));

$agent = AgentSdk::createAgent(new AgentDefinition(
    id: "release-agent", model: "openai/gpt-6-astra", tools: [$deploy],
));

$result = $agent->run(input: "Ship release 42", client: $client);
if ($result->run->status === "waiting_for_human") {
    $store->save($result); // $result->run->pause->pendingToolCalls einer prüfenden Person zeigen

    // Später, nachdem die prüfende Person freigegeben hat:
    $callId = $result->run->pause->pendingToolCalls[0]->call->id;
    $result = $agent->continueRun(run: $result, client: $client, approvals: [new ToolDecision($callId)]);
}
```

```ruby Ruby theme={null}
deploy = PhaseoAgentSdk.define_tool(
  PhaseoAgentSdk::Tool.new(
    id: "deploy",
    description: "Deploy the selected release",
    require_approval: true,
    execute: ->(input, runtime) { deployments.deploy(input) }
  )
)

agent = PhaseoAgentSdk.create_agent(id: "release-agent", model: "openai/gpt-6-astra", tools: [deploy])

result = agent.run(input: "Ship release 42", client: client)
if result.run.status == "waiting_for_human"
  store.save(result) # result.run.pause.pending_tool_calls einer prüfenden Person zeigen

  # Später, nachdem die prüfende Person freigegeben hat:
  call_id = result.run.pause.pending_tool_calls.first.call.id
  result = agent.continue_run(
    run: result,
    client: client,
    approvals: [PhaseoAgentSdk::ToolDecision.new(tool_call_id: call_id)]
  )
end
```

```java Java theme={null}
var deploy = AgentSdk.defineTool(new AgentSdk.Tool(
    "deploy", (input, context) -> deployments.deploy(input), "Deploy the selected release",
    Map.of("type", "object"), null,
    null, null, null,
    true, null,             // requireApproval
    null, null, "fail-run"));

var agent = AgentSdk.createAgent(new AgentSdk.AgentDefinition(
    "release-agent", "openai/gpt-6-astra", null, null, List.of(deploy), 12, null, null, null, null));

var result = agent.run(new AgentSdk.RunOptions(
    "Ship release 42", client, null, null, null, null, null, null, null, null));

if (result.run().status().equals("waiting_for_human")) {
    store.save(result); // result.run().pause().pendingToolCalls() einer prüfenden Person zeigen

    // Später, nachdem die prüfende Person freigegeben hat:
    var callId = result.run().pause().pendingToolCalls().get(0).call().id();
    result = agent.continueRun(new AgentSdk.ContinueOptions(
        result, client, null, null, null, null, null, null, null, null, null,
        List.of(new AgentSdk.ToolDecision(callId)), List.of(), List.of()));
}
```

```rust Rust theme={null}
use phaseo_agent::{
    create_agent, AgentDefinition, ContinueOptions, RunOptions, Tool, ToolDecision,
};
use serde_json::json;

let deploy = Tool::new(
    "deploy",
    "Deploy the selected release",
    json!({ "type": "object", "properties": { "environment": { "type": "string" } } }),
    |input, _context| Ok(json!({ "environment": input["environment"], "deployed": true })),
)
.require_approval();

let agent = create_agent(AgentDefinition::new("release-agent", "openai/gpt-6-astra").tool(deploy));

let mut result = agent.run(&mut client, RunOptions::new("Ship release 42"))?;
if result.run.status == "waiting_for_human" {
    store.save(&result)?; // die ausstehenden Tool-Aufrufe einer prüfenden Person zeigen

    // Später, nachdem die prüfende Person freigegeben hat:
    let call_id = result.run.pause.as_ref().unwrap().pending_tool_calls[0].call.id.clone();
    let mut options = ContinueOptions::new(result);
    options.approvals = vec![ToolDecision { tool_call_id: call_id, reason: None }];
    result = agent.continue_run(&mut client, options)?;
}
```

Ablehnungen, manuelle Tool-Ausgaben und das Speichern von Läufen behandelt [Status und Freigabe](https://phaseo.app/docs/de/v1/sdk-reference/agent/state-and-approval.md).

## In ein Terminal streamen

```typescript TypeScript theme={null}
const stream = agent.stream({ input, client });

for await (const delta of stream.getTextStream()) {
  process.stdout.write(delta);
}

const completed = await stream.getResult();
```

```python Python theme={null}
stream = agent.stream(input="Research this topic", client=client)

for delta in stream.text_stream():
    print(delta, end="", flush=True)

completed = stream.result()
```

```go Go theme={null}
stream := agent.Stream(ctx, phaseoagent.RunOptions{Input: prompt, Client: client})
for delta := range stream.Text() {
  fmt.Print(delta)
}
result, err := stream.Result()
```

```csharp C# theme={null}
var stream = agent.Stream(new RunOptions { Input = prompt, Client = client });
await foreach (var delta in stream.TextStream()) Console.Write(delta);
var completed = await stream.GetResult();
```

```php PHP theme={null}
$stream = $agent->stream(input: $prompt, client: $client);
foreach ($stream->textStream() as $delta) { echo $delta; }
$result = $stream->getResult();
```

```ruby Ruby theme={null}
stream = agent.stream(input: prompt, client: client)
stream.text_stream.each { |delta| print delta }
result = stream.result
```

```java Java theme={null}
// textStream() in Java wird erst nach dem Ende des Laufs gefüllt; gib Deltas daher aus onEvent aus
var options = new AgentSdk.RunOptions(prompt, client, null, null, null, null, null, null,
    event -> { if (event.type().equals("response.output_text.delta")) System.out.print(event.details().get("delta")); },
    null);
var completed = agent.stream(options).getResult();
```

Rust `0.2` hat kein Streaming; `run` kehrt zurück, sobald der Lauf endet. Siehe [Streaming](https://phaseo.app/docs/de/v1/sdk-reference/agent/streaming.md).

## Autonome Recherche begrenzen

Kombiniere mehrere Limits; das zuerst erreichte beendet den Lauf mit dem Status `stopped` und einem Stoppgrund wie `max_cost:1`.

```typescript TypeScript theme={null}
import { maxCost, maxDuration, maxTokensUsed, stepCountIs } from "@phaseo/agent-sdk";

const agent = createAgent({
  id: "researcher",
  model: "openai/gpt-6-astra",
  tools: [search, fetchPage],
  maxSteps: 25,
  stopWhen: [
    stepCountIs(20),
    maxTokensUsed(100_000),
    maxCost(1),
    maxDuration(300_000),
  ],
});
```

```python Python theme={null}
from phaseo_agent import create_agent, max_cost, max_duration, max_tokens_used, step_count_is

agent = create_agent({
    "id": "researcher",
    "model": "openai/gpt-6-astra",
    "tools": [search, fetch_page],
    "max_steps": 25,
    "stop_when": [
        step_count_is(20),
        max_tokens_used(100_000),
        max_cost(1),
        max_duration(300_000),
    ],
})
```

```go Go theme={null}
agent := phaseoagent.CreateAgent(phaseoagent.AgentDefinition{
  ID:    "researcher",
  Model: "openai/gpt-6-astra",
  Tools: []phaseoagent.Tool{search, fetchPage},
  StopWhen: []phaseoagent.StopCondition{
    phaseoagent.StepCountIs(20),
    phaseoagent.MaxTokensUsed(100_000),
    phaseoagent.MaxCost(1.00),
    phaseoagent.MaxDuration(5 * time.Minute),
  },
  MaxSteps: 25,
})
```

```csharp C# theme={null}
var agent = AgentSdk.CreateAgent(new AgentDefinition
{
    Id = "researcher",
    Model = "openai/gpt-6-astra",
    Tools = new[] { search, fetchPage },
    StopWhen = new[]
    {
        AgentSdk.StepCountIs(20),
        AgentSdk.MaxTokensUsed(100_000),
        AgentSdk.MaxCost(1.00),
        AgentSdk.MaxDuration(TimeSpan.FromMinutes(5)),
    },
    MaxSteps = 25,
});
```

```php PHP theme={null}
$agent = AgentSdk::createAgent(new AgentDefinition(
    id: "researcher",
    model: "openai/gpt-6-astra",
    tools: [$search, $fetchPage],
    maxSteps: 25,
    stopWhen: [
        AgentSdk::stepCountIs(20),
        AgentSdk::maxTokensUsed(100000),
        AgentSdk::maxCost(1.00),
        AgentSdk::maxDuration(300000),
    ],
));
```

```ruby Ruby theme={null}
agent = PhaseoAgentSdk.create_agent(
  id: "researcher",
  model: "openai/gpt-6-astra",
  tools: [search, fetch_page],
  max_steps: 25,
  stop_when: [
    PhaseoAgentSdk.step_count_is(20),
    PhaseoAgentSdk.max_tokens_used(100_000),
    PhaseoAgentSdk.max_cost(1.00),
    PhaseoAgentSdk.max_duration(300_000)
  ]
)
```

```java Java theme={null}
var agent = AgentSdk.createAgent(new AgentSdk.AgentDefinition(
    "researcher", "openai/gpt-6-astra", null, null, List.of(search, fetchPage), 25,
    null, null, null, null,
    List.of(
        AgentSdk.stepCountIs(20),
        AgentSdk.maxTokensUsed(100_000),
        AgentSdk.maxCost(1.00),
        AgentSdk.maxDuration(Duration.ofMinutes(5))),
    null, null));
```

```rust Rust theme={null}
// Rust 0.2 hat keine Stoppbedingungen; begrenze stattdessen die Modell-Turns.
let agent = create_agent(
    AgentDefinition::new("researcher", "openai/gpt-6-astra")
        .tool(search)
        .tool(fetch_page)
        .max_steps(20),
);
```

Die Zahlenformatierung im Stoppgrund folgt der Sprache: `max_cost:1` in Go, C# und PHP, `max_cost:1.0` in Ruby und Java. In Rust beendet das Erreichen des Schrittlimits den Lauf als `stopped` mit dem Grund `max_steps:20`. Siehe [Stoppbedingungen](https://phaseo.app/docs/de/v1/sdk-reference/agent/stop-conditions.md).

## Funktionen für gängige Produkte kombinieren

| Produkt | Kombiniere |
| - | - |
| Strukturierte Extraktion | [Ausgabevalidierung](https://phaseo.app/docs/de/v1/sdk-reference/agent/run-controls.md#validate-the-final-output), ein striktes Antwortformat am Gateway-Client, begrenzte Wiederholungen |
| Support-Triage | Ein `preset` für das Routing, Lookup-[Tools](https://phaseo.app/docs/de/v1/sdk-reference/agent/tools.md), strukturierte Ausgabe für die endgültige Klassifizierung |
| Recherche-Briefing | Verwaltete Suche über die Gateway-Tools des Gateway-Clients, [gestreamter](https://phaseo.app/docs/de/v1/sdk-reference/agent/streaming.md) Text, [Stoppbedingungen](https://phaseo.app/docs/de/v1/sdk-reference/agent/stop-conditions.md) |
| Code-Review oder Coding-Assistent | Datei-Tools, Fortschritts-Events, [Freigabe](https://phaseo.app/docs/de/v1/sdk-reference/agent/state-and-approval.md) vor Änderungen |
| Betriebs-Runbook | Status-Tools, manuelle Eskalation, ein gespeicherter Lauf, der später fortgesetzt wird |

Das TypeScript-Paket enthält in seinem Ordner `examples/` vollständige Versionen von vier davon: `research-brief-agent.ts`, `support-triage-agent.ts`, `coding-review-agent.ts` und `parallel-tool-agent.ts` (unabhängige lokale Tools laufen parallel).

## Ein Rezept durcharbeiten

> [card] [Dauerhafte Agentenschleife](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-durable-loop.md)
>
> Einen zurückgegebenen Lauf speichern und in einer späteren Anfrage fortsetzen.

> [card] [Recherche-Briefing](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-research-brief.md)
>
> Einen Agenten mit fundierter Webrecherche kombinieren.

> [card] [Support-Triage](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-support-triage.md)
>
> Routing- und Prompt-Standardwerte in einem verwalteten Preset halten.

> [card] [Code-Review](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-coding-review.md)
>
> Gezielte lokale Tools mit einem Coding-Workflow verbinden.

> [card] [Parallele Tools](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-parallel-tools.md)
>
> Unabhängige Tool-Aufrufe parallel ausführen, ohne die Reihenfolge der Ergebnisse zu ändern.

> [card] [Strukturierte Extraktion (Python)](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-python-structured-extraction.md)
>
> Strukturiertes JSON mit dem Python-Agent-SDK extrahieren.

> [card] [Ops-Runbook (Go)](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-go-ops-runbook.md)
>
> Einen Agenten für ein Betriebs-Runbook in Go bauen.

> [card] [Ticket-Triage (C#)](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-csharp-ticket-triage.md)
>
> Tickets mit dem C#-Agent-SDK triagieren.

> [card] [Inhaltsprüfung (PHP)](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-php-content-review.md)
>
> CMS-Inhalte mit dem PHP-Agent-SDK prüfen.

> [card] [Notizen zusammenfassen (Ruby)](https://phaseo.app/docs/de/v1/cookbook/agent-sdk-ruby-rag-notes.md)
>
> Interne Notizen mit dem Ruby-Agent-SDK zusammenfassen.

Die ersten fünf Rezepte verwenden TypeScript.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.