> ## 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.

# Agent-SDK-Verwendung

> Einen ersten Agenten mit Tools im Phaseo Agent SDK bauen und nachvollziehen, wie ein Lauf abläuft.

Definiere ein Tool, erstelle einen Agenten und führe ihn mit einem Gateway-Client aus. Das Modell ruft dein Tool auf, das SDK führt es aus und sendet das Ergebnis zurück, und der Lauf endet, wenn das Modell ohne Tool-Aufruf antwortet, für einen Menschen pausiert oder eine [Stoppbedingung](https://phaseo.app/docs/de/v1/sdk-reference/agent/stop-conditions.md) zutrifft. Erreicht der Lauf vorher sein Schrittlimit, wirft das SDK einen Fehler; nur Rust gibt den Lauf mit dem Status `stopped` zurück. Phaseo hostet weder den Agenten noch speichert es seine Läufe; das übernimmt deine Anwendung.

## Einen ersten Agenten bauen

```typescript TypeScript theme={null}
import {
  createAgent,
  createGatewayAgentClient,
  defineTool,
} from "@phaseo/agent-sdk";

const lookupDocs = defineTool({
  id: "lookup-docs",
  description: "Look up an internal docs page by slug.",
  parameters: {
    type: "object",
    properties: {
      slug: { type: "string" },
    },
    required: ["slug"],
    additionalProperties: false,
  },
  async execute(input: { slug: string }) {
    return {
      slug: input.slug,
      url: `https://phaseo.app/docs/v1/${input.slug}`,
    };
  },
});

const agent = createAgent({
  id: "support-docs-agent",
  model: "openai/gpt-6-astra",
  instructions: "Use tools when helpful and finish with a concise answer.",
  tools: [lookupDocs],
});

const result = await agent.run({
  input: "Find the docs page for presets and explain when to use them.",
  client: createGatewayAgentClient({
    clientOptions: {
      apiKey: process.env.PHASEO_API_KEY!,
    },
  }),
});

console.log(result.output);
```

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

lookup_docs = define_tool(AgentTool(
    id="lookup-docs",
    description="Look up an internal docs page by slug.",
    parameters={
        "type": "object",
        "properties": {"slug": {"type": "string"}},
        "required": ["slug"],
        "additionalProperties": False,
    },
    execute=lambda tool_input, runtime: {
        "slug": tool_input["slug"],
        "url": f"https://phaseo.app/docs/v1/{tool_input['slug']}",
    },
))

agent = create_agent({
    "id": "support-docs-agent",
    "model": "openai/gpt-6-astra",
    "instructions": "Use tools when helpful and finish with a concise answer.",
    "tools": [lookup_docs],
})

result = agent.run(
    input="Find the docs page for presets and explain when to use them.",
    client=create_gateway_agent_client(client_options={"api_key": os.environ["PHASEO_API_KEY"]}),
)

print(result.output)
```

```go Go theme={null}
package main

import (
  "context"
  "fmt"

  phaseoagent "github.com/phaseoteam/Phaseo/packages/sdk/agent-sdk-go"
)

func main() {
  client, err := phaseoagent.CreateGatewayAgentClient(phaseoagent.GatewayAgentClientOptions{})
  if err != nil {
    panic(err) // PHASEO_API_KEY ist erforderlich
  }

  lookup := phaseoagent.DefineTool(phaseoagent.Tool{
    ID:          "lookup_docs",
    Description: "Look up a Phaseo documentation topic",
    Parameters: map[string]any{
      "type":       "object",
      "properties": map[string]any{"topic": map[string]any{"type": "string"}},
      "required":   []string{"topic"},
    },
    Execute: func(input any, runtime phaseoagent.RuntimeContext) (any, error) {
      args, _ := input.(map[string]any)
      return map[string]any{"topic": args["topic"], "found": true}, nil
    },
  })

  agent := phaseoagent.CreateAgent(phaseoagent.AgentDefinition{
    ID:           "docs-agent",
    Model:        "openai/gpt-6-astra",
    Instructions: "Use tools when helpful and finish with a concise answer.",
    Tools:        []phaseoagent.Tool{lookup},
    MaxSteps:     6,
  })

  result, err := agent.Run(context.Background(), phaseoagent.RunOptions{
    Input:  "Explain when to use routing presets.",
    Client: client,
  })
  if err != nil {
    panic(err)
  }

  fmt.Println(result.Output)
  fmt.Println(result.Run.Status, result.Usage.TotalTokens)
}
```

```csharp C# theme={null}
using System.Text.Json;
using PhaseoAgentSdk;

var lookup = AgentSdk.DefineTool(new Tool(
    "lookup_docs",
    async (input, runtime) =>
    {
        var topic = ((JsonElement)input!).GetProperty("topic").GetString();
        return new { topic, found = true };
    },
    "Look up a Phaseo documentation topic",
    new Dictionary<string, object?>
    {
        ["type"] = "object",
        ["properties"] = new Dictionary<string, object?> { ["topic"] = new { type = "string" } },
        ["required"] = new[] { "topic" },
    }));

var agent = AgentSdk.CreateAgent(new AgentDefinition
{
    Id = "docs-agent",
    Model = "openai/gpt-6-astra",
    Instructions = "Use tools when helpful and finish with a concise answer.",
    Tools = new[] { lookup },
    MaxSteps = 6,
});

var result = await agent.Run(new RunOptions
{
    Input = "Explain when to use routing presets.",
    Client = AgentSdk.CreateGatewayAgentClient(), // wirft, wenn PHASEO_API_KEY fehlt
});

Console.WriteLine(result.Output);
Console.WriteLine($"{result.Run.Status} {result.Usage.TotalTokens}");
```

```php PHP theme={null}
<?php
require "vendor/autoload.php";

use Phaseo\AgentSdk\AgentDefinition;
use Phaseo\AgentSdk\AgentSdk;
use Phaseo\AgentSdk\Tool;

$lookup = AgentSdk::defineTool(new Tool(
    id: "lookup_docs",
    execute: fn (array $input, $runtime) => ["topic" => $input["topic"], "found" => true],
    description: "Look up a Phaseo documentation topic",
    parameters: [
        "type" => "object",
        "properties" => ["topic" => ["type" => "string"]],
        "required" => ["topic"],
    ],
));

$agent = AgentSdk::createAgent(new AgentDefinition(
    id: "docs-agent",
    model: "openai/gpt-6-astra",
    instructions: "Use tools when helpful and finish with a concise answer.",
    tools: [$lookup],
    maxSteps: 6,
));

$result = $agent->run(
    input: "Explain when to use routing presets.",
    client: AgentSdk::createGatewayAgentClient() // wirft, wenn PHASEO_API_KEY fehlt
);

echo $result->output . PHP_EOL;
echo $result->run->status . " " . $result->usage["total_tokens"] . PHP_EOL;
```

```ruby Ruby theme={null}
require "phaseo_agent_sdk"

lookup = PhaseoAgentSdk.define_tool(
  PhaseoAgentSdk::Tool.new(
    id: "lookup_docs",
    description: "Look up a Phaseo documentation topic",
    parameters: {
      type: "object",
      properties: { topic: { type: "string" } },
      required: ["topic"]
    },
    execute: ->(input, runtime) { { topic: input["topic"], found: true } }
  )
)

agent = PhaseoAgentSdk.create_agent(
  id: "docs-agent",
  model: "openai/gpt-6-astra",
  instructions: "Use tools when helpful and finish with a concise answer.",
  tools: [lookup],
  max_steps: 6
)

result = agent.run(
  input: "Explain when to use routing presets.",
  client: PhaseoAgentSdk.create_gateway_agent_client # löst aus, wenn PHASEO_API_KEY fehlt
)

puts result.output
puts "#{result.run.status} #{result.usage[:total_tokens]}"
```

```java Java theme={null}
import app.phaseo.agent.AgentSdk;
import java.time.Duration;
import java.util.List;
import java.util.Map;

var lookup = AgentSdk.defineTool(new AgentSdk.Tool(
    "lookup_docs",
    (input, context) -> Map.of("topic", ((Map<?, ?>) input).get("topic"), "found", true),
    "Look up a Phaseo documentation topic",
    Map.of(
        "type", "object",
        "properties", Map.of("topic", Map.of("type", "string")),
        "required", List.of("topic")),
    Duration.ofSeconds(10)
));

var agent = AgentSdk.createAgent(new AgentSdk.AgentDefinition(
    "docs-agent",                       // id
    "openai/gpt-6-astra",               // model
    null,                               // preset
    "Use tools when helpful and finish with a concise answer.", // instructions
    List.of(lookup),                    // tools
    6,                                  // maxSteps
    null, null, null, null              // parseOutput, humanReview, modelRetry, toolExecution
));

var result = agent.run(new AgentSdk.RunOptions(
    "Explain when to use routing presets.",  // input
    AgentSdk.createGatewayAgentClient(),     // wirft, wenn PHASEO_API_KEY fehlt
    null, null, null, null, null, null, null, null
));

System.out.println(result.output());
System.out.println(result.run().status() + " " + result.usage().totalTokens());
```

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

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let lookup = define_tool(Tool::new(
        "lookup_docs",
        "Look up a Phaseo documentation topic",
        json!({
            "type": "object",
            "properties": {
                "topic": { "type": "string" }
            },
            "required": ["topic"]
        }),
        |input, context| {
            Ok(json!({
                "topic": input["topic"],
                "run_id": context.run_id,
                "found": true
            }))
        },
    ));

    let agent = create_agent(
        AgentDefinition::new("docs-agent", "openai/gpt-6-astra")
            .instructions("Use lookup_docs when helpful. Answer concisely.")
            .max_steps(6)
            .tool(lookup),
    );

    let mut client = create_gateway_agent_client("openai/gpt-6-astra")?;
    let result = agent.run(
        &mut client,
        RunOptions::new("Explain when to use routing presets."),
    )?;

    println!("{}", result.output);
    println!("steps: {}", result.run.step_count);
    println!("tokens: {}", result.usage.total_tokens);
    Ok(())
}
```

Die ID des Tools ist der Funktionsname, den das Modell sieht, und seine Parameter sind das JSON-Schema, das das Modell ausfüllt. Die Argumente erreichen deinen Code in der jeweils nativen Form der Sprache:

| Sprache | Tool erhält | Hinweise |
| - | - | - |
| TypeScript | Typisiertes Objekt | `execute(input, context)` |
| Python | `dict` | `execute(tool_input, runtime)` |
| Go | `any` (dekodiertes JSON, meist `map[string]any`) | `Execute(input, runtime) (any, error)` |
| C# | `JsonElement` | `Execute(input, runtime)`, mit `await` |
| PHP | Assoziatives Array | `execute(array $input, $runtime)` |
| Ruby | Hash mit String-Schlüsseln | Baue Tools mit `PhaseoAgentSdk::Tool.new`; `define_tool` gibt zurück, was du übergibst, daher funktioniert ein einfacher Hash nicht |
| Java | `Map` | Records sind positional; übergib `null` für alles, was du nicht setzt |
| Rust | `serde_json::Value` | Die Closure läuft lokal; `RuntimeContext` enthält die Lauf-ID, die Agenten-ID, den Schrittindex, den Anwendungskontext und den Tool-Aufruf |

Wenn weder Agent noch Lauf noch Client ein Modell oder Preset setzen, sendet der Gateway-Client `phaseo/free`. `create_gateway_agent_client` in Rust nimmt das Modell als Argument.

## So läuft ein Lauf ab

```mermaid theme={null}
flowchart TD
  start([Lauf]) --> turn[Nachrichten an das Modell senden]
  turn --> exec[Tool-Aufrufe ohne nötige Eingabe ausführen, Ergebnisse anhängen]
  exec --> gate{{"Wartet ein Aufruf auf Freigabe, einen Menschen oder manuelle Ausgabe?"}}
  gate -- Ja --> paused([Lauf zurückgeben: waiting_for_human])
  gate -- Nein --> stopcheck{{"Stoppbedingung erfüllt?"}}
  stopcheck -- Ja --> stopped([Lauf zurückgeben: stopped])
  stopcheck -- Nein --> more{{"Hat das Modell Tools aufgerufen?"}}
  more -- Nein --> done([Lauf zurückgeben: completed])
  more -- Ja --> limit{{"Schrittlimit ausgeschöpft?"}}
  limit -- Ja --> failed([Fehler: Max steps exceeded])
  limit -- Nein --> turn
  paused -. fortsetzen .-> turn
```

Jeder Schritt wird im zurückgegebenen Laufergebnis als Checkpoint gespeichert. Um über Anfragen oder Neustarts hinweg fortzusetzen, speicherst du dieses Ergebnis in deinem eigenen Speicher und übergibst es an die Fortsetzungsmethode, oder du gibst dem Agenten einen Status-Accessor; siehe [Status und Freigabe](https://phaseo.app/docs/de/v1/sdk-reference/agent/state-and-approval.md). Das Schrittlimit und was passiert, wenn es ausgeschöpft ist, unterscheiden sich je nach Sprache:

> [tab] TypeScript
>
> Jeder Aufruf von `run()` oder `continueRun()` umfasst bis zu 12 Schritte, sofern du `maxSteps` nicht setzt; darüber hinaus wirft er `Max steps exceeded`. Mit [Stoppbedingungen](https://phaseo.app/docs/de/v1/sdk-reference/agent/stop-conditions.md) beendest du einen Lauf sauber.

> [tab] Python
>
> Ein Lauf umfasst bis zu 12 Schritte, sofern du `max_steps` nicht setzt; darüber hinaus löst er `RuntimeError` aus. Stoppbedingungen werden nur bei einem Schritt geprüft, in dem das Modell keine Tools aufruft, daher weicht die Reihenfolge vom Diagramm ab: Eine Tool-Schleife läuft, bis sie pausiert, antwortet oder `max_steps` ausschöpft.

> [tab] Go
>
> Ein Lauf, der mehr als `MaxSteps` Modell-Turns braucht (Standard 8), schlägt mit `Max steps exceeded (N)` fehl.

> [tab] C#
>
> Ein Lauf, der mehr als `MaxSteps` Modell-Turns braucht (Standard 12), wirft `InvalidOperationException("Max steps exceeded (N)")`.

> [tab] PHP
>
> Ein Lauf, der mehr als `maxSteps` Modell-Turns braucht (Standard 12), wirft `Max steps exceeded (N)`.

> [tab] Ruby
>
> Ein Lauf, der mehr als `max_steps` Modell-Turns braucht (Standard 12), löst `Max steps exceeded (N)` aus.

> [tab] Java
>
> Ein Lauf, der mehr als `maxSteps` Modell-Turns braucht (Standard 12), wirft `Max steps exceeded (N)`.

> [tab] Rust
>
> Ein Lauf umfasst bis zu 8 Modell-Turns, sofern du nicht `.max_steps(n)` aufrufst oder `RunOptions.max_steps` setzt. Das Erreichen des Limits ist kein Fehler: Der Lauf kehrt mit `run.status` `stopped` und `run.stop_reason` `max_steps:<limit>` zurück. Läufe sind synchron, und lokale Tools werden nacheinander ausgeführt; verwende daher einen Worker-Thread oder eine Task-Grenze, wenn ein Lauf keinen Request-Handler blockieren soll.

## Das Laufergebnis lesen

Jeder Lauf gibt dieselben Teile zurück. Die Feldnamen folgen der Schreibweise der jeweiligen Sprache (`output`, `Output`, `output()`):

| Teil | Inhalt |
| - | - |
| `run` | Status, IDs, effektives Modell, Schrittlimit, Kontext, Pausenstatus und Stoppgrund |
| `steps` | Ein Eintrag pro Modell-Turn: Request-ID, Anbieter, Modell, Finish-Reason, Warnungen, Tool-Aufrufe und Nutzung |
| `messages` | Die gesamte Unterhaltung einschließlich der Tool-Ergebnisse |
| `output` | Die endgültige Ausgabe |
| `usage` | Eingabe-, Ausgabe-, gecachte und Gesamt-Tokens sowie Kosten |

`usage.cost` kommt in Rust nur aus einem numerischen `meta.cost` oder `cost` in der Antwort; `cost_nanos` oder `cost_cents` werden nicht übernommen. Für Ausgabenberichte in Rust verwendest du die Gateway-Antwort oder den Generierungseintrag.

## Die passende Funktion finden

| Um… | Seite |
| - | - |
| dem Modell lokale, manuelle oder fortschrittsmeldende Tools zu geben | [Tools](https://phaseo.app/docs/de/v1/sdk-reference/agent/tools.md) |
| für eine Freigabe oder einen Menschen zu pausieren und dann fortzusetzen | [Status und Freigabe](https://phaseo.app/docs/de/v1/sdk-reference/agent/state-and-approval.md) |
| Text und Tool-Aktivität live anzuzeigen | [Streaming](https://phaseo.app/docs/de/v1/sdk-reference/agent/streaming.md) |
| eine Timeline aus Nachrichten, Reasoning und Tool-Aufrufen darzustellen | [Items](https://phaseo.app/docs/de/v1/sdk-reference/agent/items.md) |
| Schritte, Tokens, Kosten oder Zeit zu begrenzen | [Stoppbedingungen](https://phaseo.app/docs/de/v1/sdk-reference/agent/stop-conditions.md) |
| Modell oder Tools zwischen Turns zu ändern | [Dynamische Turns](https://phaseo.app/docs/de/v1/sdk-reference/agent/dynamic-turns.md) |
| typisierte Ausgabe zu erhalten, Modellaufrufe zu wiederholen oder ein Preset zu verwenden | [Ausgaben und Wiederholungen](https://phaseo.app/docs/de/v1/sdk-reference/agent/run-controls.md) |
| jeden Schritt zu protokollieren oder zu prüfen | [Lifecycle-Hooks](https://phaseo.app/docs/de/v1/sdk-reference/agent/lifecycle-hooks.md) |
| Nutzung, Kosten und Request-IDs eines Laufs zu erfassen | [Beobachtbarkeit](https://phaseo.app/docs/de/v1/sdk-reference/agent/observability.md) |
| Gateway-, Schema- und Schrittlimit-Fehler zu behandeln | [Events und Fehler](https://phaseo.app/docs/de/v1/sdk-reference/agent/events-and-errors.md) |
| Läufe lokal zu untersuchen | [DevTools](https://phaseo.app/docs/de/v1/sdk-reference/agent/devtools.md) |

Jeder Export ist in der [API-Referenz](https://phaseo.app/docs/de/v1/sdk-reference/agent/api-reference.md) aufgeführt, und vollständige Agenten findest du unter [Beispiele](https://phaseo.app/docs/de/v1/sdk-reference/agent/examples.md).


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