/** * Claude-backed {@link Reasoner}: the bundled reference LLM provider. * * `createClaudeReasoner(config)` builds a model-completion transport and adapts it * with {@link createLLMReasoner}, so a Claude model becomes an escalation target on * the default `rule-first` router (`grid.aiReasoner = createClaudeReasoner(...)`). * Two transports: a server **proxy** (`endpoint`, recommended for production, the * key stays on your backend) or a **direct** browser call (`apiKey` + * `dangerouslyAllowBrowser`, development only, the key is exposed to the page). * * Control mode uses tool use: the grid's {@link toJSONSchema} is the tool's * `input_schema`, so the returned patch is shaped by the grid's advertised * vocabulary (and is sanitized again on apply). Ask mode is a plain, read-only * message over the schema and a bounded data sample. The reasoner interface is * provider-agnostic; this is the reference implementation. * * @see plans/ai-reasoning-layer-spec.md (section 4.8) */ import type Anthropic from '@anthropic-ai/sdk'; import { type StatePatch } from '../ai-schema.js'; import type { Reasoner } from './reasoner.js'; import type { LLMRequest } from './reasoner-llm.js'; /** * Configures {@link createClaudeReasoner}. Two transports: a server **proxy** * (`endpoint`, recommended for production: the key stays on your backend) or a * **direct** browser call (`apiKey` + `dangerouslyAllowBrowser`, development * only: the key is exposed to the page). The reasoner interface itself is * provider-agnostic; this is the bundled Anthropic/Claude reference. */ export interface ClaudeReasonerConfig { /** Production transport: POST `{ prompt, mode, schema, data }` to your backend. */ endpoint?: string; /** Development transport: call Anthropic directly. Requires {@link dangerouslyAllowBrowser}. */ apiKey?: string; /** Acknowledge that an in-browser `apiKey` is exposed to the page. Dev only. */ dangerouslyAllowBrowser?: boolean; /** Model id. Defaults to `claude-opus-4-8`. */ model?: string; /** Max output tokens. Defaults to 1024. */ maxTokens?: number; /** Rows of the current data to include in the prompt (0 disables). Defaults to 50. */ maxDataRows?: number; /** Extra system-prompt text appended to the built-in grid instructions. */ system?: string; /** Override `fetch` (proxy transport), e.g. to add auth headers or for testing. */ fetch?: typeof fetch; /** Supply the Anthropic client (or a stub) instead of the bundled dynamic import. */ client?: ClaudeClient; /** Reasoner name stamped on plans. Defaults to `'llm:claude'`. */ name?: string; /** Router triage score in `[0, 1]`. Defaults to the bridge default (`0.6`). */ score?: number; } /** The slice of an Anthropic message the reasoner reads. */ export interface ClaudeMessage { content: ReadonlyArray<{ type: string; text?: string; input?: unknown; name?: string; }>; stop_reason?: string | null; stop_details?: { explanation?: string | null; } | null; } /** Minimal structural view of the Anthropic client (the part the reasoner uses). */ export interface ClaudeClient { messages: { create(body: Anthropic.MessageCreateParamsNonStreaming): Promise; }; } /** Build the control-mode (tool-use) request. Exported for testing. */ export declare function buildControlRequest(request: LLMRequest, config: ClaudeReasonerConfig): Anthropic.MessageCreateParamsNonStreaming; /** Build the ask-mode (plain message) request. Exported for testing. */ export declare function buildAskRequest(request: LLMRequest, config: ClaudeReasonerConfig): Anthropic.MessageCreateParamsNonStreaming; /** Read the state patch out of the tool-use block. Exported for testing. */ export declare function extractPatch(message: ClaudeMessage): StatePatch; /** Concatenate the text blocks of an answer. Exported for testing. */ export declare function extractAnswer(message: ClaudeMessage): string; /** * The first-class Anthropic/Claude reference {@link Reasoner}. Set it on * `grid.aiReasoner`, then call `grid.runPrompt(...)`; the rule engine handles * simple prompts and only unmapped ones escalate to the model. * * @example Production (server proxy holds the key) * ```ts * grid.aiReasoner = createClaudeReasoner({ endpoint: '/api/grid-ai' }); * ``` * @example Development (browser key; never ship this) * ```ts * grid.aiReasoner = createClaudeReasoner({ apiKey, dangerouslyAllowBrowser: true }); * ``` */ export declare function createClaudeReasoner(config: ClaudeReasonerConfig): Reasoner;