### Subagent Invocation Examples Source: https://context7.com/xibbon/piswift/llms.txt Demonstrates how to invoke subagents using JSON payloads for single, parallel, or chained task execution. The `{previous}` placeholder is used for chaining outputs. ```json // Single { "agent": "reviewer", "task": "Review Sources/PiSwiftAgent/ for concurrency issues." } ``` ```json // Parallel { "tasks": [ { "agent": "reviewer", "task": "Review Sources/PiSwiftAgent/" }, { "agent": "fetcher", "task": "Fetch https://example.com/spec.json to /tmp/spec.json" } ] } ``` ```json // Chain — {previous} expands to the prior step's output { "chain": [ { "agent": "reviewer", "task": "Review Sources/ and list all issues." }, { "agent": "worker", "task": "Fix the issues listed here:\n{previous}" } ] } ``` -------------------------------- ### Subagent Tool Usage: Single Task Source: https://github.com/xibbon/piswift/blob/main/README.md Example of using the 'subagent' tool for a single task. Specify the agent name and the task to be performed. ```json { "agent": "worker", "task": "Summarize the tests in Tests/." } ``` -------------------------------- ### Subagent Tool Usage: Chained Tasks Source: https://github.com/xibbon/piswift/blob/main/README.md Example of using the 'subagent' tool for chained tasks. The output of one task can be passed as input to the next using '{previous}'. ```json { "chain": [ { "agent": "planner", "task": "Plan the fix for X." }, { "agent": "worker", "task": "Implement the plan:\n{previous}" } ] } ``` -------------------------------- ### Subagent Tool Usage: Parallel Tasks Source: https://github.com/xibbon/piswift/blob/main/README.md Example of using the 'subagent' tool for parallel tasks. Define multiple tasks, each with its own agent and task description. ```json { "tasks": [ { "agent": "worker", "task": "Scan Sources/ for concurrency violations." }, { "agent": "reviewer", "task": "Review README for updates." } ] } ``` -------------------------------- ### Subagent Markdown Definition Example Source: https://context7.com/xibbon/piswift/llms.txt Defines a subagent using Markdown with YAML frontmatter for metadata and the file body as the system prompt. This format is used for agents placed in user or project agent directories. ```markdown --- name: reviewer description: Code reviewer that checks for Swift concurrency issues model: anthropic/claude-opus-4-5 tools: read,grep,find,ls outputFormat: | ## Issues Found ## Recommendations ## Summary --- You are an expert Swift concurrency reviewer. Scan source files for data races, missing `Sendable` conformances, and incorrect `async`/`await` usage. Always cite the file path and line range for each issue. ``` -------------------------------- ### Stream LLM Response as Event Sequence Source: https://context7.com/xibbon/piswift/llms.txt Use `stream` to get a fine-grained event sequence from an LLM. Iterate through events like `textDelta` and `done` to process the response incrementally. Requires an API key for the chosen provider. ```swift import PiSwiftAI // 1. Pick a model from the built-in registry let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") // 2. Build a conversation context let context = Context( systemPrompt: "You are a helpful assistant.", messages: [ .user(UserMessage(content: .text("What is 2 + 2?"))) ] ) // 3. Stream with an API key let options = StreamOptions(apiKey: ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"]) let eventStream = try stream(model: model, context: context, options: options) // 4. Consume events for await event in eventStream { switch event { case .textDelta(_, let delta, _): print(delta, terminator: "") case .done(_, let message): print("\n[tokens used: \(message.usage.totalTokens)]") case .error(_, let msg): print("Error: \(msg.errorMessage ?? \"unknown\")") default: break } } ``` -------------------------------- ### Implement an Agent with Tool Execution Source: https://context7.com/xibbon/piswift/llms.txt Demonstrates creating and running a stateful AI agent using `PiSwiftAgent`. This includes defining a custom tool, configuring the agent with options like API key retrieval and model selection, and subscribing to streaming events. ```swift import PiSwiftAI import PiSwiftAgent // Define a custom tool let echoTool = AgentTool( label: "Echo", name: "echo", description: "Returns the input text unchanged", parameters: AnyCodable([ "type": "object", "properties": ["text": ["type": "string", "description": "Text to echo"]], "required": ["text"] ] as [String: Any]) ) { _, params, _, _ in let text = (params["text"]?.value as? String) ?? "" return AgentToolResult(content: [.text(TextContent(text: text))]) } // Configure and create the agent let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") let agent = Agent(AgentOptions( getApiKey: { provider in getEnvApiKey(provider: provider) } )) agent.systemPrompt = "You are a helpful assistant with an echo tool." agent.model = model agent.tools = [echoTool] agent.thinkingLevel = .off // Subscribe to streaming events let unsubscribe = agent.subscribe { event, _ in switch event { case .messageUpdate(let msg, _): if case .assistant(let a) = msg { for block in a.content { if case .text(let t) = block { print(t.text, terminator: "") } } } case .toolExecutionStart(_, let name, let args): print("\n[tool] \(name)(\(args))") case .agentEnd: print("\n[done]") default: break } } // Send a prompt and wait try await agent.prompt("Echo back: hello world") await agent.waitForIdle() unsubscribe() ``` -------------------------------- ### agent.prompt(_:images:) / agent.steer(_:) / agent.followUp(_:) Source: https://context7.com/xibbon/piswift/llms.txt Send initial prompts, inject steering messages mid-run, or queue follow-up messages to continue after the agent would otherwise stop. ```APIDOC ## `agent.prompt(_:images:)` / `agent.steer(_:)` / `agent.followUp(_:)` — Message dispatch ### Description Send initial prompts, inject steering messages mid-run, or queue follow-up messages to continue after the agent would otherwise stop. ### Usage ```swift import PiSwiftAI import PiSwiftAgent let agent = Agent() agent.model = getModel(provider: .openai, modelId: "gpt-4o-mini") agent.getApiKey = { provider in getEnvApiKey(provider: provider) } // Send a prompt with an image let imageData = Data(contentsOf: URL(fileURLWithPath: "/tmp/screenshot.png"))! let image = ImageContent(data: imageData.base64EncodedString(), mimeType: "image/png") try await agent.prompt("Describe this screenshot.", images: [image]) // Inject a steering correction while the agent runs agent.steer(AgentMessage.user(UserMessage(content: .text("Focus on the error messages only.")))) // Queue a follow-up that runs after the current task completes agent.followUp(AgentMessage.user(UserMessage(content: .text("Now summarise your findings in one sentence.")))) await agent.waitForIdle() // Abort a long-running turn agent.abort() ``` ``` -------------------------------- ### Create Coding Agent Session with PiSwiftCodingAgent Source: https://context7.com/xibbon/piswift/llms.txt Use `createAgentSession` as the primary entry point for the SDK to discover and configure models, hooks, tools, and settings. Minimal usage auto-discovers configuration; custom options allow for specific settings like working directory, model, thinking level, and tool allowlisting. ```swift import PiSwiftCodingAgent // Minimal usage — auto-discovers all configuration from ~/.pi/agent/ and .pi/ let result = await createAgentSession() let session = result.session let agent = result.session.agent if let msg = result.modelFallbackMessage { print("Warning: \(msg)") } // Customised usage let options = CreateAgentSessionOptions( cwd: "/path/to/my/project", model: getModel(provider: .anthropic, modelId: "claude-opus-4-5"), thinkingLevel: .medium, toolNames: ["read", "edit", "write", "bash", "grep"], // allowlist tools systemPrompt: .text("You are an expert Swift engineer."), hooks: await discoverHooks() ) let customResult = await createAgentSession(options) try await customResult.session.agent.prompt("Refactor the authentication module.") await customResult.session.agent.waitForIdle() ``` -------------------------------- ### createAgentSession(_:) Source: https://context7.com/xibbon/piswift/llms.txt The primary SDK entry point. Discovers models, hooks, custom tools, extensions, and settings, wires everything together, and returns a ready-to-use `AgentSession` and `Agent` via `CreateAgentSessionResult`. ```APIDOC ## `createAgentSession(_:)` — Create a full coding agent session ### Description The primary SDK entry point. Discovers models, hooks, custom tools, extensions, and settings, wires everything together, and returns a ready-to-use `AgentSession` and `Agent` via `CreateAgentSessionResult`. ### Usage ```swift import PiSwiftCodingAgent // Minimal usage — auto-discovers all configuration from ~/.pi/agent/ and .pi/ let result = await createAgentSession() let session = result.session let agent = result.session.agent if let msg = result.modelFallbackMessage { print("Warning: \(msg)") } // Customised usage let options = CreateAgentSessionOptions( cwd: "/path/to/my/project", model: getModel(provider: .anthropic, modelId: "claude-opus-4-5"), thinkingLevel: .medium, toolNames: ["read", "edit", "write", "bash", "grep"], // allowlist tools systemPrompt: .text("You are an expert Swift engineer."), hooks: await discoverHooks() ) let customResult = await createAgentSession(options) try await customResult.session.agent.prompt("Refactor the authentication module.") await customResult.session.agent.waitForIdle() ``` ``` -------------------------------- ### Write Compiled Swift Extension with `withExtensionAPI` Source: https://context7.com/xibbon/piswift/llms.txt Use this to create compiled Swift extensions for the Pi agent. Import `PiExtensionSDK` and expose the `piExtensionMain` entry point. The `HookAPI` provides access to various agent functionalities. ```swift // ~/.pi/agent/extensions/session-timer.swift import PiExtensionSDK private actor TimerState { var startDate: Date? func start() { startDate = Date() } func elapsed() -> String { guard let start = startDate else { return "not started" } let s = Int(Date().timeIntervalSince(start)) return String(format: "%d:%02d", s / 60, s % 60) } } private let state = TimerState() @_cdecl("piExtensionMain") public func piExtensionMain(_ raw: UnsafeMutableRawPointer) { withExtensionAPI(raw) { pi in pi.on("session_start") { (event: SessionStartEvent, ctx: HookContext) in await state.start() await ctx.ui.setStatus("timer", "0:00") return nil } pi.on("agent_end") { (event: AgentEndEvent, ctx: HookContext) in let elapsed = await state.elapsed() await ctx.ui.setStatus("timer", elapsed) return nil } pi.registerCommand("timer", description: "Show session elapsed time") { args, ctx in let elapsed = await state.elapsed() await ctx.ui.notify("Session time: \(elapsed)", .info) } pi.registerShortcut(.init("shift+t"), description: "Show timer") { ctx in let elapsed = await state.elapsed() await ctx.ui.notify(elapsed, .info) } } } ``` -------------------------------- ### loadSettings(cwd:agentDir:) Source: https://context7.com/xibbon/piswift/llms.txt Reads a snapshot of user and project agent settings. ```APIDOC ## loadSettings(cwd:agentDir:) ### Description Returns a `SettingsSnapshot` with all user/project settings including default provider, model, thinking level, compaction, retry, transport, and image handling. ### Parameters #### Path Parameters - **cwd** (string) - Optional - The current working directory to load settings from. - **agentDir** (string) - Optional - A custom directory to load settings from. ### Response #### Success Response (SettingsSnapshot) - **defaultProvider** (string) - Optional - The default AI provider. - **defaultModel** (string) - Optional - The default AI model. - **thinkingBudgets** (Dictionary) - Optional - Configuration for thinking budgets. - **transport** (Transport) - The transport mechanism used (e.g., `sse`). - **compaction** (boolean) - Indicates if compaction is enabled. ### Request Example ```swift import PiSwiftCodingAgent let settings = loadSettings(cwd: "/path/to/project") print("Default model: \(settings.defaultProvider ?? "auto")/\(settings.defaultModel ?? "auto")") print("Transport: \(settings.transport.rawValue)") // "sse" print("Compaction enabled: \(settings.compaction)") print("Thinking budgets: \(settings.thinkingBudgets ?? [:])") ``` ``` -------------------------------- ### discoverAuthStorage(agentDir:) / discoverModels(authStorage:agentDir:) Source: https://context7.com/xibbon/piswift/llms.txt Load the persisted auth store and build a `ModelRegistry` that resolves API keys from OAuth tokens, environment variables, and stored credentials. ```APIDOC ## `discoverAuthStorage(agentDir:)` / `discoverModels(authStorage:agentDir:)` — Auth and model registry ### Description Load the persisted auth store and build a `ModelRegistry` that resolves API keys from OAuth tokens, environment variables, and stored credentials. ### Usage ```swift import PiSwiftCodingAgent // Load auth from ~/.pi/agent/auth.json let authStorage = discoverAuthStorage() // Build a model registry with OAuth and env key support let registry = discoverModels(authStorage: authStorage) // Check which providers have valid keys let available = await registry.getAvailable() for model in available { if let key = await registry.getApiKeyForProvider(model.provider) { print("\(model.provider)/\(model.id) — key length: \(key.count)") } } ``` ``` -------------------------------- ### Load Agent Settings Snapshot Source: https://context7.com/xibbon/piswift/llms.txt Loads a snapshot of all user and project settings, including default provider, model, thinking level, and transport configuration. This provides a consolidated view of agent operational parameters. ```swift import PiSwiftCodingAgent let settings = loadSettings(cwd: "/path/to/project") print("Default model: \(settings.defaultProvider ?? "auto")/\(settings.defaultModel ?? "auto")") print("Transport: \(settings.transport.rawValue)") // "sse" print("Compaction enabled: \(settings.compaction)") print("Thinking budgets: \(settings.thinkingBudgets ?? [:])") ``` -------------------------------- ### Discover and Load Hook Bundles Source: https://context7.com/xibbon/piswift/llms.txt Automatically discovers compiled hook bundles from default search paths or specified directories. The discovered hooks can then be passed to create an agent session. ```swift import PiSwiftCodingAgent // Auto-discover hooks from default search paths let hooks = await discoverHooks() print("Loaded \(hooks.count) hook(s)") // Discover from a specific project and custom agent dir let projectHooks = await discoverHooks( cwd: "/path/to/project", agentDir: "/path/to/custom-agent-dir" ) // Pass hooks into the session let options = CreateAgentSessionOptions(hooks: projectHooks) let result = await createAgentSession(options) ``` -------------------------------- ### Register MCP Servers as Agent Tools with `McpAdapter.hookDefinition()` Source: https://context7.com/xibbon/piswift/llms.txt Bridge Model Context Protocol servers into the agent as tools. Configure MCP servers via a JSON config file. Pass `McpAdapter.hookDefinition()` in the hooks array during agent session creation. ```swift import PiSwiftCodingAgent import PiMCPAdapter // Create an MCP config at ~/.pi/agent/mcp.json: // { // "mcpServers": { // "filesystem": { // "command": "npx", // "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] // }, // "github": { // "command": "npx", // "args": ["-y", "@modelcontextprotocol/server-github"], // "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..." } // } // } // } // Wire MCP adapter into the agent session via hooks let options = CreateAgentSessionOptions( hooks: [McpAdapter.hookDefinition()] // Pass --mcp-config /path/to/mcp.json via CLI flags, or rely on auto-discovery ) let result = await createAgentSession(options) // MCP tools are now available to the agent under prefixed names: // e.g. "mcp__filesystem__read_file", "mcp__github__search_repositories" try await result.session.agent.prompt("List all .swift files in /tmp using the filesystem MCP tool.") await result.session.agent.waitForIdle() ``` -------------------------------- ### Dispatch Messages with PiSwiftAI Agent Source: https://context7.com/xibbon/piswift/llms.txt Use `agent.prompt`, `agent.steer`, and `agent.followUp` to send initial prompts, inject steering messages, or queue follow-up messages. Ensure the agent is idle before aborting. ```swift import PiSwiftAI import PiSwiftAgent let agent = Agent() agent.model = getModel(provider: .openai, modelId: "gpt-4o-mini") agent.getApiKey = { provider in getEnvApiKey(provider: provider) } // Send a prompt with an image let imageData = Data(contentsOf: URL(fileURLWithPath: "/tmp/screenshot.png"))! let image = ImageContent(data: imageData.base64EncodedString(), mimeType: "image/png") try await agent.prompt("Describe this screenshot.", images: [image]) // Inject a steering correction while the agent runs agent.steer(AgentMessage.user(UserMessage(content: .text("Focus on the error messages only.")))) // Queue a follow-up that runs after the current task completes agent.followUp(AgentMessage.user(UserMessage(content: .text("Now summarise your findings in one sentence.")))) await agent.waitForIdle() // Abort a long-running turn agent.abort() ``` -------------------------------- ### Enumerate In-Process Subagent Definitions Source: https://context7.com/xibbon/piswift/llms.txt Enumerates subagent definitions from user and/or project directories. Each discovered subagent's configuration, including name, description, tools, and model override, is accessible. ```swift import PiSwiftCodingAgent // Load both user (~/.pi/agent/agents) and project (.pi/agents) subagents let discovery = discoverSubagents(scope: .both) for agent in discovery.agents { print("[\(agent.source.rawValue)] \(agent.name): \(agent.description)") print(" tools: \(agent.tools.joined(separator: ", "))") print(" model: \(agent.model ?? "inherit")") } ``` -------------------------------- ### complete(model:context:options:) Source: https://context7.com/xibbon/piswift/llms.txt A convenience wrapper around the `stream` method that awaits the complete `AssistantMessage` in a single call. This is useful when you need the entire response at once rather than processing events incrementally. ```APIDOC ## complete(model:context:options:) ### Description Convenience wrapper around `stream` that awaits the complete `AssistantMessage` in one call. ### Method `complete` ### Parameters - **model**: The model to use for completion. - **context**: The conversation context, including system prompt and messages. - **options**: Streaming options, such as API key. ### Request Example ```swift import PiSwiftAI let model = getModel(provider: .openai, modelId: "gpt-4o-mini") let context = Context( systemPrompt: "Translate the following to French.", messages: [.user(UserMessage(content: .text("Hello, world!")))] ) let options = StreamOptions(apiKey: ProcessInfo.processInfo.environment["OPENAI_API_KEY"]) let message = try await complete(model: model, context: context, options: options) // message.content[0] is a .text(TextContent) if case .text(let t) = message.content.first { print(t.text) // "Bonjour le monde !" } print("Stop reason: \(message.stopReason)") // .stop print("Cost: \(message.usage.cost.total)") ``` ``` -------------------------------- ### Discover Auth Storage and Models Source: https://context7.com/xibbon/piswift/llms.txt Use `discoverAuthStorage` to load authentication details and `discoverModels` to build a `ModelRegistry` for resolving API keys. This allows checking available providers and retrieving their corresponding API keys. ```swift import PiSwiftCodingAgent // Load auth from ~/.pi/agent/auth.json let authStorage = discoverAuthStorage() // Build a model registry with OAuth and env key support let registry = discoverModels(authStorage: authStorage) // Check which providers have valid keys let available = await registry.getAvailable() for model in available { if let key = await registry.getApiKeyForProvider(model.provider) { print("\(model.provider)/\(model.id) — key length: \(key.count)") } } ``` -------------------------------- ### discoverHooks(cwd:agentDir:) Source: https://context7.com/xibbon/piswift/llms.txt Scans project and user directories for compiled hook bundles and returns HookDefinition objects. ```APIDOC ## discoverHooks(cwd:agentDir:) ### Description Scans the project's `.pi/hooks/` and the user's `~/.pi/agent/hooks/` directories for compiled hook bundles and returns `[HookDefinition]` suitable for passing to `CreateAgentSessionOptions.hooks`. ### Parameters #### Path Parameters - **cwd** (string) - Optional - The current working directory to scan for hooks. - **agentDir** (string) - Optional - A custom directory to scan for hooks. ### Response #### Success Response (Array of HookDefinition) - **HookDefinition** - An object representing a loaded hook. ### Request Example ```swift import PiSwiftCodingAgent // Auto-discover hooks from default search paths let hooks = await discoverHooks() print("Loaded \(hooks.count) hook(s)") // Discover from a specific project and custom agent dir let projectHooks = await discoverHooks( cwd: "/path/to/project", agentDir: "/path/to/custom-agent-dir" ) // Pass hooks into the session let options = CreateAgentSessionOptions(hooks: projectHooks) let result = await createAgentSession(options) ``` ``` -------------------------------- ### Fetch Remote File with Curl Source: https://github.com/xibbon/piswift/blob/main/examples/subagents/fetcher.md Use this command to download a file from a URL. The `-L` flag follows redirects, and `-f` ensures failure on HTTP errors. Specify the output path with `-o`. ```bash curl -L -f -o /tmp/example.txt https://example.com/example.txt ``` -------------------------------- ### Await Full LLM Response Source: https://context7.com/xibbon/piswift/llms.txt Use `complete` as a convenience wrapper to await the entire LLM response in a single call. This method simplifies fetching the final `AssistantMessage`. ```swift import PiSwiftAI let model = getModel(provider: .openai, modelId: "gpt-4o-mini") let context = Context( systemPrompt: "Translate the following to French.", messages: [.user(UserMessage(content: .text("Hello, world!")))] ) let options = StreamOptions(apiKey: ProcessInfo.processInfo.environment["OPENAI_API_KEY"]) let message = try await complete(model: model, context: context, options: options) // message.content[0] is a .text(TextContent) if case .text(let t) = message.content.first { print(t.text) // "Bonjour le monde !" } print("Stop reason: \(message.stopReason)") // .stop print("Cost: \(message.usage.cost.total)") ``` -------------------------------- ### stream(model:context:options:) Source: https://context7.com/xibbon/piswift/llms.txt Streams an LLM response as an event sequence. This method calls the appropriate registered provider for the given model and returns an `AssistantMessageEventStream`. You can iterate over this stream to receive fine-grained events such as `textDelta`, `toolCallEnd`, and `done`. Use `await stream.result()` to obtain the final `AssistantMessage`. ```APIDOC ## stream(model:context:options:) ### Description Calls the appropriate registered provider for the given model and returns an `AssistantMessageEventStream`. Iterate with `for await event in stream` to receive fine-grained events (`textDelta`, `toolCallEnd`, `done`, etc.). Use `await stream.result()` to get the final `AssistantMessage`. ### Method `stream` ### Parameters - **model**: The model to use for streaming. - **context**: The conversation context, including system prompt and messages. - **options**: Streaming options, such as API key. ### Request Example ```swift import PiSwiftAI // 1. Pick a model from the built-in registry let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") // 2. Build a conversation context let context = Context( systemPrompt: "You are a helpful assistant.", messages: [ .user(UserMessage(content: .text("What is 2 + 2?"))) ] ) // 3. Stream with an API key let options = StreamOptions(apiKey: ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"]) let eventStream = try stream(model: model, context: context, options: options) // 4. Consume events for await event in eventStream { switch event { case .textDelta(_, let delta, _): print(delta, terminator: "") case .done(_, let message): print("\n[tokens used: \(message.usage.totalTokens)]") case .error(_, let msg): print("Error: \(msg.errorMessage ?? "unknown")") default: break } } ``` ``` -------------------------------- ### Agent: High-level stateful AI agent with tool execution Source: https://context7.com/xibbon/piswift/llms.txt The main class for running a multi-turn, tool-using AI agent. It allows for custom tool integration, prompt management, and event subscription for streaming output. ```APIDOC ## PiSwiftAgent — Agentic Loop ### `Agent` — High-level stateful AI agent with tool execution `Agent` is the main class for running a multi-turn, tool-using AI agent. Construct it with `AgentOptions`, call `prompt(_:)` to send user messages, and subscribe to events for streaming output. Tool calls are executed in parallel by default and results fed back automatically. ```swift import PiSwiftAI import PiSwiftAgent // Define a custom tool let echoTool = AgentTool( label: "Echo", name: "echo", description: "Returns the input text unchanged", parameters: AnyCodable([ "type": "object", "properties": ["text": ["type": "string", "description": "Text to echo"]], "required": ["text"] ] as [String: Any]) ) { _, params, _, _ in let text = (params["text"]?.value as? String) ?? "" return AgentToolResult(content: [.text(TextContent(text: text))]) } // Configure and create the agent let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") let agent = Agent(AgentOptions( getApiKey: { provider in getEnvApiKey(provider: provider) } )) agent.systemPrompt = "You are a helpful assistant with an echo tool." agent.model = model agent.tools = [echoTool] agent.thinkingLevel = .off // Subscribe to streaming events let unsubscribe = agent.subscribe { event, _ in switch event { case .messageUpdate(let msg, _): if case .assistant(let a) = msg { for block in a.content { if case .text(let t) = block { print(t.text, terminator: "") } } } case .toolExecutionStart(_, let name, let args): print("\n[tool] \(name)(\(args))") case .agentEnd: print("\n[done]") default: break } } // Send a prompt and wait try await agent.prompt("Echo back: hello world") await agent.waitForIdle() unsubscribe() ``` ``` -------------------------------- ### Resolve Provider API Key from Environment Source: https://context7.com/xibbon/piswift/llms.txt Retrieves API keys for various AI providers from environment variables, respecting provider-specific naming conventions. ```APIDOC ## `getEnvApiKey(provider:)` — Resolve provider API key from environment Returns the API key for a provider from standard environment variables, handling provider-specific naming conventions (GitHub Copilot, Amazon Bedrock credentials, Anthropic OAuth token, etc.). ```swift import PiSwiftAI // Reads ANTHROPIC_API_KEY or ANTHROPIC_OAUTH_TOKEN let anthropicKey = getEnvApiKey(provider: .anthropic) // Reads OPENAI_API_KEY let openaiKey = getEnvApiKey(provider: .openai) // Reads AWS_ACCESS_KEY_ID / AWS_PROFILE / etc. — returns "" if present let bedrockKey = getEnvApiKey(provider: .amazonBedrock) // All providers at once for provider in KnownProvider.allCases { if let key = getEnvApiKey(provider: provider) { print("\(provider.rawValue): \(key.prefix(8))...") } } ``` ``` -------------------------------- ### Retrieve API Keys with getEnvApiKey Source: https://context7.com/xibbon/piswift/llms.txt Fetches the API key for a given provider from standard environment variables. It handles provider-specific naming conventions and returns '' for AWS providers if credentials are found. ```swift import PiSwiftAI // Reads ANTHROPIC_API_KEY or ANTHROPIC_OAUTH_TOKEN let anthropicKey = getEnvApiKey(provider: .anthropic) // Reads OPENAI_API_KEY let openaiKey = getEnvApiKey(provider: .openai) // Reads AWS_ACCESS_KEY_ID / AWS_PROFILE / etc. — returns "" if present let bedrockKey = getEnvApiKey(provider: .amazonBedrock) // All providers at once for provider in KnownProvider.allCases { if let key = getEnvApiKey(provider: provider) { print("\(provider.rawValue): \(key.prefix(8))...") } } ``` -------------------------------- ### Lookup AI Models with getModel and getModels Source: https://context7.com/xibbon/piswift/llms.txt Use `getModel` for exact model lookups, which will fatalError if the model is not found. `getModel` can also be used for custom providers. Use `getModels` to enumerate all models registered for a specific provider. ```swift import PiSwiftAI // Exact lookup — fatalError if not found let claude = getModel(provider: .anthropic, modelId: "claude-opus-4-5") print(claude.name) // "Claude Opus 4.5" print(claude.contextWindow) // e.g. 200000 print(claude.reasoning) // true — supports extended thinking // Optional lookup (unknown/custom providers) if let custom = getModel(provider: "my-provider", modelId: "my-model") { print(custom.baseUrl) } // List all OpenAI models let openaiModels = getModels(provider: .openai) openaiModels.forEach { print("\($0.id) — \($0.cost.input)$/M input tokens") } ``` -------------------------------- ### streamSimple(model:context:options:) Source: https://context7.com/xibbon/piswift/llms.txt Streams LLM responses using unified `SimpleStreamOptions`. This option type is provider-agnostic and can be used with all providers via the agent loop. It's ideal for setting cross-provider options like reasoning effort, cache retention, transport, and other settings without needing to instantiate provider-specific option structs. ```APIDOC ## streamSimple(model:context:options:) ### Description Stream with unified `SimpleStreamOptions`. `SimpleStreamOptions` is a provider-agnostic options type accepted by all providers via the agent loop. Use it when you want to set reasoning effort, cache retention, transport, and other cross-provider options without instantiating provider-specific option structs. ### Method `streamSimple` ### Parameters - **model**: The model to use for streaming. - **context**: The conversation context, including system prompt and messages. - **options**: Unified streaming options, including reasoning, cache retention, max tokens, and timeout. ### Request Example ```swift import PiSwiftAI let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") let context = Context( messages: [.user(UserMessage(content: .text("Explain async/await in Swift.")))] ) let options = SimpleStreamOptions( apiKey: ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"], reasoning: .medium, // enable extended thinking cacheRetention: .long, // prompt-cache retention hint maxTokens: 4096, timeoutMs: 60_000 ) let response = try streamSimple(model: model, context: context, options: options) let finalMessage = await response.result() // Access thinking content if present: for block in finalMessage.content { if case .thinking(let t) = block { print("[thinking] \(t.thinking)") } else if case .text(let t) = block { print(t.text) } } ``` ``` -------------------------------- ### discoverSubagents(cwd:agentDir:scope:) Source: https://context7.com/xibbon/piswift/llms.txt Enumerates in-process subagent definitions from specified directories. ```APIDOC ## discoverSubagents(cwd:agentDir:scope:) ### Description Returns `SubagentDiscoveryResult` listing all `.md` agent files found in user and/or project agent directories. Each `SubagentConfig` exposes name, description, allowed tools, model override, and the parsed system prompt. ### Parameters #### Path Parameters - **cwd** (string) - Optional - The current working directory to scan for agents. - **agentDir** (string) - Optional - A custom directory to scan for agents. - **scope** (Scope) - Required - Specifies whether to load from user, project, or both directories. Enum with values: `.user`, `.project`, `.both`. ### Response #### Success Response (SubagentDiscoveryResult) - **agents** (Array of SubagentConfig) - A list of discovered subagents. - **SubagentConfig** - **name** (string) - The name of the subagent. - **description** (string) - A brief description of the subagent. - **tools** (Array of string) - The tools the subagent can use. - **model** (string) - Optional - The model override for the subagent. - **source** (Source) - The source of the subagent definition (e.g., `.user`, `.project`). ### Request Example ```swift import PiSwiftCodingAgent // Load both user (~/.pi/agent/agents) and project (.pi/agents) subagents let discovery = discoverSubagents(scope: .both) for agent in discovery.agents { print("[\(agent.source.rawValue)] \(agent.name): \(agent.description)") print(" tools: \(agent.tools.joined(separator: ", "))") print(" model: \(agent.model ?? "inherit")") } ``` ``` -------------------------------- ### agentLoop(prompts:context:config:signal:streamFn:) Source: https://context7.com/xibbon/piswift/llms.txt The functional API for running a single-shot agent loop that returns an `EventStream`. Use this when you need explicit control over the event stream lifecycle without the `Agent` class state machine. ```APIDOC ## `agentLoop(prompts:context:config:signal:streamFn:)` — Low-level event-stream loop ### Description The functional API for running a single-shot agent loop that returns an `EventStream`. Use this when you need explicit control over the event stream lifecycle without the `Agent` class state machine. ### Usage ```swift import PiSwiftAI import PiSwiftAgent let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") // Create a custom cancellation token let cancel = CancellationToken() let context = AgentContext( systemPrompt: "You are a concise assistant.", messages: [], tools: [] ) let config = AgentLoopConfig( model: model, maxTokens: 1024, convertToLlm: { messages in messages.compactMap { $0.asMessage } }, getApiKey: { provider in getEnvApiKey(provider: provider) } ) let prompts: [AgentMessage] = [.user(UserMessage(content: .text("List three Swift concurrency primitives.")))] let eventStream = agentLoop(prompts: prompts, context: context, config: config, signal: cancel) for await event in eventStream { if case .agentEnd(let messages) = event { for msg in messages { if case .assistant(let a) = msg { for block in a.content { if case .text(let t) = block { print(t.text) } } } } } } // Retrieve the final [AgentMessage] result let finalMessages = await eventStream.result() ``` ``` -------------------------------- ### Stream with Unified SimpleStreamOptions Source: https://context7.com/xibbon/piswift/llms.txt Use `streamSimple` with `SimpleStreamOptions` for provider-agnostic configuration. This option type allows setting cross-provider parameters like reasoning effort and cache retention without provider-specific structs. ```swift import PiSwiftAI let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") let context = Context( messages: [.user(UserMessage(content: .text("Explain async/await in Swift.")))] ) let options = SimpleStreamOptions( apiKey: ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"], reasoning: .medium, // enable extended thinking cacheRetention: .long, // prompt-cache retention hint maxTokens: 4096, timeoutMs: 60_000 ) let response = try streamSimple(model: model, context: context, options: options) let finalMessage = await response.result() // Access thinking content if present: for block in finalMessage.content { if case .thinking(let t) = block { print("[thinking] \(t.thinking)") } else if case .text(let t) = block { print(t.text) } } ``` -------------------------------- ### Compute Token Cost Source: https://context7.com/xibbon/piswift/llms.txt Calculates the token cost for a given model and usage, populating the usage object and returning a detailed cost breakdown. ```APIDOC ## `calculateCost(model:usage:)` — Compute token cost Populates `usage.cost` in-place and returns a `UsageCost` struct with per-category and total USD costs. ```swift import PiSwiftAI let model = getModel(provider: .openai, modelId: "gpt-4o-mini") var usage = Usage(input: 1200, output: 340, cacheRead: 0, cacheWrite: 0, totalTokens: 1540) let cost = calculateCost(model: model, usage: &usage) print(String(format: "Total: $%.6f", cost.total)) // e.g. Total: $0.000228 ``` ``` -------------------------------- ### Model Registry Lookup Source: https://context7.com/xibbon/piswift/llms.txt Functions to look up specific models by provider and model ID, or to enumerate all models registered for a given provider. ```APIDOC ## `getModel(provider:modelId:)` / `getModels(provider:)` — Model registry lookup Look up a specific model or enumerate all models registered for a provider. ```swift import PiSwiftAI // Exact lookup — fatalError if not found let claude = getModel(provider: .anthropic, modelId: "claude-opus-4-5") print(claude.name) // "Claude Opus 4.5" print(claude.contextWindow) // e.g. 200000 print(claude.reasoning) // true — supports extended thinking // Optional lookup (unknown/custom providers) if let custom = getModel(provider: "my-provider", modelId: "my-model") { print(custom.baseUrl) } // List all OpenAI models let openaiModels = getModels(provider: .openai) openaiModels.forEach { print("\($0.id) — \($0.cost.input)$/M input tokens") } ``` ``` -------------------------------- ### Define a Worker Subagent Source: https://github.com/xibbon/piswift/blob/main/README.md Defines a worker subagent with specified tools and output format. The body of the Markdown file serves as the agent's system prompt. ```markdown --- name: worker description: General-purpose subagent model: gpt-5.2 tools: read,edit,write,bash outputFormat: | ## Completed ## Files Changed ## Notes --- You are a worker agent with full capabilities. ``` -------------------------------- ### Low-level Agent Event-Stream Loop Source: https://context7.com/xibbon/piswift/llms.txt Utilize `agentLoop` for explicit control over the event stream lifecycle when not using the `Agent` class state machine. This function returns an `EventStream` for managing agent events and messages. ```swift import PiSwiftAI import PiSwiftAgent let model = getModel(provider: .anthropic, modelId: "claude-opus-4-5") // Create a custom cancellation token let cancel = CancellationToken() let context = AgentContext( systemPrompt: "You are a concise assistant.", messages: [], tools: [] ) let config = AgentLoopConfig( model: model, maxTokens: 1024, convertToLlm: { messages in messages.compactMap { $0.asMessage } }, getApiKey: { provider in getEnvApiKey(provider: provider) } ) let prompts: [AgentMessage] = [.user(UserMessage(content: .text("List three Swift concurrency primitives.")))] let eventStream = agentLoop(prompts: prompts, context: context, config: config, signal: cancel) for await event in eventStream { if case .agentEnd(let messages) = event { for msg in messages { if case .assistant(let a) = msg { for block in a.content { if case .text(let t) = block { print(t.text) } } } } } } // Retrieve the final [AgentMessage] result let finalMessages = await eventStream.result() ``` -------------------------------- ### Calculate Token Cost with calculateCost Source: https://context7.com/xibbon/piswift/llms.txt The `calculateCost` function computes the token cost for a given model and usage. It populates the `usage.cost` property in-place and returns a `UsageCost` struct containing per-category and total USD costs. ```swift import PiSwiftAI let model = getModel(provider: .openai, modelId: "gpt-4o-mini") var usage = Usage(input: 1200, output: 340, cacheRead: 0, cacheWrite: 0, totalTokens: 1540) let cost = calculateCost(model: model, usage: &usage) print(String(format: "Total: $%.6f", cost.total)) // e.g. Total: $0.000228 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.