/** * Provider-agnostic agent seam. * * The Hub's agent loop talks to models through this interface, not through any * vendor SDK. The request/response shape follows the OpenAI chat-completions * de-facto standard (messages + tools + tool_calls) because that is the common * surface OpenRouter and most OpenAI-compatible providers expose; it is the * lingua franca, not an OpenAI commitment. * * ADR-0017: the agent layer is provider-agnostic. `@Claude` is a trigger brand, * not a provider contract. Switching model = new session (provider-bound), so * the seam never assumes cross-provider session continuity. * * This file defines the contract; see {@link OpenRouterProvider} for the * concrete adapter that points an OpenAI-compatible client at OpenRouter. */ /** Why a run terminated. Mirrors the common provider surface. */ export type FinishReason = "stop" | "tool_calls" | "length" | "error"; /** A contiguous text span in a message. */ export interface TextPart { readonly type: "text"; readonly text: string; } /** A tool call the model wants the runner to execute. `arguments` is a JSON string. */ export interface ToolCallPart { readonly type: "tool_call"; readonly id: string; readonly name: string; readonly arguments: string; } /** The result of a tool execution, addressed back to the originating call. */ export interface ToolResultPart { readonly type: "tool_result"; readonly tool_call_id: string; /** Free-form string content; structured payloads are JSON-encoded here. */ readonly content: string; } export type MessagePart = TextPart | ToolCallPart | ToolResultPart; export type Role = "system" | "user" | "assistant" | "tool"; /** A single chat message: a role plus an ordered list of parts. */ export interface Message { readonly role: Role; readonly parts: readonly MessagePart[]; } /** JSON-schema description of a tool the model may call. */ export interface ToolSpec { readonly name: string; readonly description: string; /** A JSON Schema object describing the tool's parameters. */ readonly parameters: unknown; } export interface ChatRequest { readonly model: string; readonly messages: readonly Message[]; readonly tools: readonly ToolSpec[]; } export interface ChatResponse { readonly finishReason: FinishReason; /** The assistant message produced. May contain tool_calls. */ readonly message: Message; readonly usage?: { readonly inputTokens: number; readonly outputTokens: number }; } /** * The seam a model provider implements. Implementations are expected to be * OpenAI-compatible HTTP clients (OpenRouter, direct vendor APIs, local * gateways); the Hub does not hard-depend on any single-vendor agent SDK. */ export interface AgentProvider { readonly id: string; chat(req: ChatRequest): Promise; } /** Extract tool calls from an assistant message, if any. */ export function toolCallsOf(msg: Message): readonly ToolCallPart[] { if (msg.role !== "assistant") return []; return msg.parts.filter((p): p is ToolCallPart => p.type === "tool_call"); }