export type Role = "user" | "assistant" | "system" | "tool"; /** Tool call envelope normalized across providers */ export interface ToolCall { id: string; name: string; arguments: unknown; } /** Messages are discriminated by role for precision */ export type Message = SystemMessage | UserMessage | AssistantMessage | ToolMessage; export interface SystemMessage { role: "system"; content: string; name?: string; } export interface UserMessage { role: "user"; content: string; name?: string; } export interface AssistantMessage { role: "assistant"; content: string; name?: string; /** When the model wants to call tools, it returns one or more tool calls */ tool_calls?: ToolCall[]; /** * Reasoning details from thinking/reasoning models (e.g., o1, o3, ChatGPT 5.1). * This field must be preserved when passing the message back to the model * for multi-turn conversations to maintain reasoning context. * @internal The structure is provider-specific and should be treated as opaque. */ reasoning_details?: unknown; } export interface ToolMessage { role: "tool"; /** Tool JSON/string result to be fed back to the model */ content: string; /** Link back to the specific assistant tool call */ tool_call_id: string; /** (optional) echo the tool name for debugging/trace */ name?: string; } /** LLM call options */ export type ToolChoice = "auto" | "none" | "required" | { name: string; }; export interface GenerateOptions { temperature?: number; maxTokens?: number; toolChoice?: ToolChoice; signal?: globalThis.AbortSignal; tools?: Tool[]; parallelToolCalls?: boolean; stream?: boolean; /** * Enable extended reasoning/thinking for models that support it (e.g., o1, o3, ChatGPT 5.1). * - `true` or `false`: Simple enable/disable * - `{ enabled: true }`: OpenAI-style object notation * - Custom object: Provider-specific options * * @example * // Enable reasoning * { reasoning: true } * * @example * // OpenAI format * { reasoning: { enabled: true } } */ reasoning?: boolean | { enabled: boolean; } | Record; } /** Streaming events */ export type ModelEvent = { type: "token"; token: string; } | { type: "tool_call"; call: ToolCall; } | { type: "assistant_message"; message: AssistantMessage; } | { type: "usage"; usage: Usage; }; export interface Usage { promptTokens?: number; completionTokens?: number; totalTokens?: number; costUSD?: number; } /** Final response */ export interface ModelResponse { message: AssistantMessage; usage?: Usage; } export type ExecutionStrategy = "single" | "iterative"; export interface ExecuteOptions { /** * Tool-calling strategy: * - `iterative` (default): keep tool-calling enabled across rounds * - `single`: first round may call tools, then finalize with toolChoice "none" */ strategy?: ExecutionStrategy; /** * Override tool choice for the first model call. Defaults to: * - "auto" when tools are available * - "none" when no tools are available */ toolChoice?: ToolChoice; /** Maximum rounds before failing. Defaults: iterative=12, single=6 */ maxRounds?: number; /** Provider hint for parallel tool calls. Defaults to false */ parallelToolCalls?: boolean; } export interface ExecuteStreamOptions extends ExecuteOptions { /** Optional stream sink override. Falls back to `ctx.stream`. */ sink?: TokenStream; } export interface ToolExecutionRecord { aliasName: string; canonicalName: string; callId?: string; args: unknown; result: unknown; } export interface ExecuteResult { message: AssistantMessage; text: string; usage?: Usage; rounds: number; toolExecutions: ToolExecutionRecord[]; } export type ExecuteStreamEvent = { type: "token"; token: string; } | { type: "tool_call_started"; call: ToolCall; round: number; } | { type: "tool_call_finished"; call: ToolCall; round: number; result: unknown; } | { type: "assistant_message"; message: AssistantMessage; } | { type: "usage"; usage: Usage; } | { type: "done"; result: ExecuteResult; } | { type: "error"; error: Error; }; export interface EmbedOptions { model?: string; signal?: globalThis.AbortSignal; } export interface EmbeddingsProvider { embed(input: string[], opts?: EmbedOptions): Promise; } /** Adapter contract */ export interface LLM { name: string; capabilities: { functionCall?: boolean; streaming?: boolean; }; generate(messages: Message[], opts?: GenerateOptions): Promise; generate(messages: Message[], opts?: GenerateOptions): AsyncIterable; generate(messages: Message[], opts?: GenerateOptions): Promise>; } /** Logger, Memory, TokenStream: unchanged */ export interface Logger { debug(...args: unknown[]): void; info(...args: unknown[]): void; warn(...args: unknown[]): void; error(...args: unknown[]): void; span?(name: string, attrs?: Record): void; } export interface Memory { get(key: string): Promise; set(key: string, val: unknown): Promise; retrieval?(index: string): { search: (q: string, topK?: number) => Promise>; }; } export interface TokenStream { write(token: string): void; end(): void; } /** * Restricted context for tool execution. * Tools have access to a sandboxed subset of Ctx to prevent: * - Tools calling other tools (no tools registry access) * - Tools manipulating conversation history (no messages access) * - Tools accessing middleware state (no state access) * - Tools interfering with user I/O (no input/stream access) * * Tools CAN: * - Use the model for meta-operations (e.g., summarizeText) * - Access persistent memory * - Respect cancellation signals * - Log their operations * - Access injected dependencies (for testing/configuration) */ export interface ToolContext { readonly memory: Memory; readonly signal: globalThis.AbortSignal; readonly log: Logger; readonly model: LLM; /** Optional dependency injection container for testing or runtime configuration */ readonly deps?: Record; } export interface Tool { name: string; description?: string; schema: unknown; handler(args: TArgs, ctx: ToolContext): Promise; } /** Registry */ export interface ToolRegistry { list(): Tool[]; get(name: string): Tool | undefined; register(tool: Tool): void; } /** Context */ export interface Ctx { input?: string; messages: Message[]; model: LLM; tools: ToolRegistry; memory: Memory; stream: TokenStream; /** * Extensible state object for middleware to share data. * * Well-known keys used by SISU middleware: * - `toolAliases` (Map): Map of tool names to API aliases set by registerTools * - `toolExecutions` (ToolExecutionRecord[]): Tool execution records populated by execution helpers * - `executionResult` (ExecuteResult): Latest execution result populated by execute/executeStream middleware * - `executionEvents` (ExecuteStreamEvent[]): Streaming execution events populated by executeStream middleware */ state: Record; signal: globalThis.AbortSignal; log: Logger; }