react-observer-agent 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/tools/registerTool.ts","../src/tools/validateToolNames.ts","../src/provider/AIAgentProvider.tsx","../src/state/resolveState.ts","../src/state/createStateSnapshot.ts","../src/permissions/filterTools.ts","../src/permissions/validateToolCall.ts","../src/tools/validateArgs.ts","../src/provider/executeAgentLoop.ts","../src/provider/useAgent.ts","../src/permissions/filterState.ts","../src/adapters/openai.ts","../src/adapters/claude.ts"],"sourcesContent":["// Tools\nexport { registerTool } from './tools/registerTool';\nexport { validateToolNames } from './tools/validateToolNames';\n\n// Provider\nexport { AIAgentProvider } from './provider/AIAgentProvider';\nexport { useAgent } from './provider/useAgent';\n\n// Permissions\nexport { filterState } from './permissions/filterState';\nexport { filterTools } from './permissions/filterTools';\nexport { validateToolCall } from './permissions/validateToolCall';\n\n// Adapters\nexport { openAIAdapter } from './adapters/openai';\nexport { claudeAdapter } from './adapters/claude';\n\n// Types\nexport type {\n ToolDefinition,\n AnyToolDefinition,\n ToolOptions,\n AIAgentProviderProps,\n PermissionsConfig,\n AgentOptions,\n AgentContext,\n AgentResponse,\n ToolCallResult,\n ConversationEntry,\n ModelAdapter,\n ModelRequest,\n ModelResponse,\n StateSource,\n PendingToolCall,\n ToolCallEvent,\n SendOptions,\n AgentError,\n JSONSchema,\n LLMToolCall,\n LLMToolDefinition,\n ConversationMessage,\n OpenAIAdapterConfig,\n ClaudeAdapterConfig,\n} from './types';\n","import type { ToolDefinition, ToolOptions } from '../types';\n\nexport function registerTool<TArgs = unknown>(\n name: string,\n handler: (args: TArgs) => unknown | Promise<unknown>,\n options?: ToolOptions,\n): ToolDefinition<TArgs> {\n return {\n name,\n handler,\n description: options?.description,\n parameters: options?.parameters,\n confirm: options?.confirm ?? false,\n };\n}\n","import type { AnyToolDefinition } from '../types';\n\nconst RESERVED_PREFIX = '__';\n\nexport function validateToolNames(tools: AnyToolDefinition[]): void {\n const seen = new Set<string>();\n for (const tool of tools) {\n if (tool.name.startsWith(RESERVED_PREFIX)) {\n throw new Error(\n `Tool name \"${tool.name}\" uses the reserved \"${RESERVED_PREFIX}\" prefix. ` +\n `Names beginning with \"${RESERVED_PREFIX}\" are reserved for internal tools.`,\n );\n }\n if (seen.has(tool.name)) {\n throw new Error(\n `Duplicate tool name \"${tool.name}\". All tools passed to a single provider must have unique names.`,\n );\n }\n seen.add(tool.name);\n }\n}\n","import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n AgentContext,\n AgentResponse,\n AIAgentProviderProps,\n ConversationEntry,\n ConversationMessage,\n SendOptions,\n} from '../types';\nimport { validateToolNames } from '../tools/validateToolNames';\nimport { executeAgentLoop } from './executeAgentLoop';\n\nexport const AgentContextValue = createContext<AgentContext | null>(null);\n\nexport function AIAgentProvider({\n model,\n state,\n tools,\n permissions,\n options,\n children,\n}: AIAgentProviderProps) {\n const [isProcessing, setIsProcessing] = useState(false);\n const [history, setHistory] = useState<ConversationEntry[]>([]);\n const [lastResponse, setLastResponse] = useState<AgentResponse | null>(null);\n\n // Store latest props in refs so send() always sees current values\n const modelRef = useRef(model);\n const stateRef = useRef(state);\n const toolsRef = useRef(tools);\n const permissionsRef = useRef(permissions);\n const optionsRef = useRef(options);\n\n modelRef.current = model;\n stateRef.current = state;\n toolsRef.current = tools;\n permissionsRef.current = permissions;\n optionsRef.current = options;\n\n useEffect(() => {\n validateToolNames(tools);\n }, [tools]);\n\n // The LLM-facing transcript, kept separately from the user-facing history so\n // structured tool calls survive across interactions.\n const transcriptRef = useRef<ConversationMessage[]>([]);\n\n const clearHistory = useCallback(() => {\n setHistory([]);\n setLastResponse(null);\n transcriptRef.current = [];\n }, []);\n\n const send = useCallback(async (\n message: string,\n sendOptions?: SendOptions,\n ): Promise<AgentResponse> => {\n setIsProcessing(true);\n\n const userEntry: ConversationEntry = {\n role: 'user',\n content: message,\n timestamp: Date.now(),\n };\n\n setHistory((prev) => [...prev, userEntry]);\n\n try {\n const { response, messages } = await executeAgentLoop(message, {\n model: modelRef.current,\n state: stateRef.current,\n tools: toolsRef.current,\n permissions: permissionsRef.current,\n options: optionsRef.current,\n conversationHistory: transcriptRef.current,\n signal: sendOptions?.signal,\n });\n\n // An abort can land between an assistant message and the tool results\n // answering it. Providers reject that shape, so the partial turn is\n // dropped rather than replayed.\n if (response.error?.code !== 'ABORTED') {\n transcriptRef.current = messages;\n }\n\n const assistantEntry: ConversationEntry = {\n role: 'assistant',\n content: response.message,\n toolCalls: response.toolCalls,\n timestamp: Date.now(),\n };\n\n setHistory((prev) => [...prev, assistantEntry]);\n setLastResponse(response);\n\n // The loop reports failures it recovered from by returning them, rather\n // than throwing, so the error handler still needs to hear about them.\n // A user-initiated cancel is not an application error.\n if (response.error && response.error.code !== 'ABORTED') {\n optionsRef.current?.onError?.(response.error);\n }\n\n return response;\n } catch (error) {\n const agentError = {\n message: error instanceof Error ? error.message : 'Unknown error',\n cause: error,\n };\n const errorResponse: AgentResponse = {\n message: '',\n toolCalls: [],\n error: agentError,\n };\n setLastResponse(errorResponse);\n optionsRef.current?.onError?.(agentError);\n return errorResponse;\n } finally {\n setIsProcessing(false);\n }\n }, []);\n\n const contextValue = useMemo<AgentContext>(\n () => ({\n send,\n isProcessing,\n history,\n clearHistory,\n lastResponse,\n }),\n [send, isProcessing, history, clearHistory, lastResponse],\n );\n\n return (\n <AgentContextValue.Provider value={contextValue}>\n {children}\n </AgentContextValue.Provider>\n );\n}\n","import type { StateSource } from '../types';\n\nexport function resolveState(state: StateSource): Record<string, unknown> {\n const resolved = typeof state === 'function' ? state() : state;\n return resolved as Record<string, unknown>;\n}\n","import type { StateSource } from '../types';\nimport { resolveState } from './resolveState';\n\nexport function stripNonSerializable(\n obj: Record<string, unknown>,\n debug: boolean = false,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n try {\n JSON.stringify(value);\n result[key] = value;\n } catch {\n if (debug) {\n console.warn(\n `[react-observer-agent] Non-serializable value stripped from state key \"${key}\"`,\n );\n }\n }\n }\n\n return result;\n}\n\nfunction isSerializableValue(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'function' || typeof value === 'symbol') return false;\n if (typeof value === 'bigint') return false;\n return true;\n}\n\nexport function createStateSnapshot(\n state: StateSource,\n canAccess: string[],\n debug: boolean = false,\n): Record<string, unknown> {\n const resolved = resolveState(state);\n const filtered: Record<string, unknown> = {};\n\n for (const key of canAccess) {\n if (key in resolved) {\n const value = resolved[key];\n if (!isSerializableValue(value)) {\n if (debug) {\n console.warn(\n `[react-observer-agent] Non-serializable value stripped from state key \"${key}\"`,\n );\n }\n continue;\n }\n filtered[key] = value;\n }\n }\n\n return stripNonSerializable(filtered, debug);\n}\n","import type { AnyToolDefinition } from '../types';\n\nexport function filterTools(\n tools: AnyToolDefinition[],\n canExecute: string[],\n): AnyToolDefinition[] {\n const allowed = new Set(canExecute);\n return tools.filter((tool) => allowed.has(tool.name));\n}\n","export function validateToolCall(\n name: string,\n canExecute: string[],\n): boolean {\n return canExecute.includes(name);\n}\n","import type { JSONSchema } from '../types';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Validates tool arguments against a deliberate subset of JSON Schema:\n * `type`, `properties`, `required`, `items`, and `enum`. Every other keyword\n * is ignored rather than rejected, so a richer real-world schema still\n * validates on the parts this understands instead of failing outright.\n */\nexport function validateArgs(\n args: unknown,\n schema: JSONSchema,\n): ValidationResult {\n const errors: string[] = [];\n validateValue(args, schema, '', errors);\n return { valid: errors.length === 0, errors };\n}\n\nfunction describeType(value: unknown): string {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n if (Array.isArray(value)) return 'array';\n if (typeof value === 'number') {\n return Number.isInteger(value) ? 'integer' : 'number';\n }\n return typeof value;\n}\n\nfunction matchesType(value: unknown, expected: string): boolean {\n const actual = describeType(value);\n // Every integer is a valid number, but not the reverse.\n if (expected === 'number') return actual === 'number' || actual === 'integer';\n return actual === expected;\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (\n a === null ||\n b === null ||\n typeof a !== 'object' ||\n typeof b !== 'object'\n ) {\n return false;\n }\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction label(path: string): string {\n return path === '' ? 'value' : path;\n}\n\nfunction validateValue(\n value: unknown,\n schema: JSONSchema,\n path: string,\n errors: string[],\n): void {\n if (!schema || typeof schema !== 'object') return;\n\n const expectedType = schema.type;\n if (typeof expectedType === 'string' && !matchesType(value, expectedType)) {\n errors.push(\n `${label(path)} should be ${expectedType}, got ${describeType(value)}`,\n );\n // Anything further would just restate the same mismatch.\n return;\n }\n\n if (\n Array.isArray(schema.enum) &&\n !schema.enum.some((option) => sameValue(option, value))\n ) {\n errors.push(\n `${label(path)} should be one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`,\n );\n }\n\n if (isPlainObject(value)) {\n validateObject(value, schema, path, errors);\n }\n\n if (Array.isArray(value) && isPlainObject(schema.items)) {\n const itemSchema = schema.items as JSONSchema;\n value.forEach((item, index) => {\n validateValue(item, itemSchema, `${label(path)}[${index}]`, errors);\n });\n }\n}\n\nfunction validateObject(\n value: Record<string, unknown>,\n schema: JSONSchema,\n path: string,\n errors: string[],\n): void {\n if (Array.isArray(schema.required)) {\n for (const key of schema.required) {\n if (typeof key === 'string' && value[key] === undefined) {\n errors.push(`${path === '' ? '' : `${path}.`}${key} is required`);\n }\n }\n }\n\n if (isPlainObject(schema.properties)) {\n const properties = schema.properties as Record<string, JSONSchema>;\n for (const [key, propertySchema] of Object.entries(properties)) {\n if (value[key] !== undefined && isPlainObject(propertySchema)) {\n validateValue(\n value[key],\n propertySchema,\n path === '' ? key : `${path}.${key}`,\n errors,\n );\n }\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import type {\n AgentOptions,\n AgentResponse,\n AnyToolDefinition,\n ConversationMessage,\n JSONSchema,\n LLMToolDefinition,\n ModelAdapter,\n PermissionsConfig,\n StateSource,\n ToolCallResult,\n} from '../types';\nimport { createStateSnapshot } from '../state/createStateSnapshot';\nimport { filterTools } from '../permissions/filterTools';\nimport { validateToolCall } from '../permissions/validateToolCall';\nimport { validateArgs } from '../tools/validateArgs';\n\nconst DEFAULT_MAX_TURNS = 5;\nconst READ_STATE_TOOL_NAME = '__readState';\nconst EMPTY_OBJECT_SCHEMA: JSONSchema = { type: 'object', properties: {} };\n\ninterface ExecutionContext {\n model: ModelAdapter;\n state: StateSource;\n tools: AnyToolDefinition[];\n permissions: PermissionsConfig;\n options?: AgentOptions;\n conversationHistory: ConversationMessage[];\n signal?: AbortSignal;\n}\n\n/**\n * The loop returns the LLM-facing message list alongside the response so the\n * provider can replay it verbatim on the next interaction. Structured tool\n * calls survive that way, which plain history text cannot express.\n */\nexport interface AgentLoopResult {\n response: AgentResponse;\n messages: ConversationMessage[];\n}\n\n/** Accumulates token usage across the turns of one interaction. */\nclass UsageTotal {\n private promptTokens = 0;\n private completionTokens = 0;\n private reported = false;\n\n add(usage?: { promptTokens: number; completionTokens: number }): void {\n if (!usage) return;\n this.reported = true;\n this.promptTokens += usage.promptTokens ?? 0;\n this.completionTokens += usage.completionTokens ?? 0;\n }\n\n /** Undefined when no adapter response carried usage, rather than a false zero. */\n total(): { promptTokens: number; completionTokens: number } | undefined {\n if (!this.reported) return undefined;\n return {\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n };\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError';\n}\n\nfunction buildStateManifest(\n canAccess: string[],\n descriptions?: Record<string, string>,\n): { key: string; description: string }[] {\n return canAccess.map((key) => ({\n key,\n description: descriptions?.[key] ?? key,\n }));\n}\n\nfunction buildStateManifestPrompt(manifest: { key: string; description: string }[]): string {\n if (manifest.length === 0) return '';\n const lines = manifest.map((m) => `- ${m.key}: ${m.description}`);\n return [\n 'Available application state (use the __readState tool to access specific keys when needed):',\n ...lines,\n '',\n 'Only request state keys relevant to the user\\'s question. Do not read all keys at once unless necessary.',\n ].join('\\n');\n}\n\nfunction buildReadStateToolDef(): LLMToolDefinition {\n return {\n name: READ_STATE_TOOL_NAME,\n description: 'Read specific keys from the application state. Only request keys you need.',\n parameters: {\n type: 'object',\n properties: {\n keys: {\n type: 'array',\n items: { type: 'string' },\n description: 'State keys to read',\n },\n },\n required: ['keys'],\n },\n };\n}\n\nexport async function executeAgentLoop(\n message: string,\n ctx: ExecutionContext,\n): Promise<AgentLoopResult> {\n const { model, state, tools, permissions, options, signal } = ctx;\n const debug = options?.debug ?? false;\n const maxTurns = options?.maxTurns ?? DEFAULT_MAX_TURNS;\n\n // Key names and descriptions only. Values stay behind __readState.\n const stateManifest = buildStateManifest(\n permissions.canAccess,\n permissions.stateDescriptions,\n );\n\n if (debug) {\n console.log('[react-observer-agent] State manifest:', stateManifest.map((m) => m.key));\n }\n\n const allowedTools = filterTools(tools, permissions.canExecute);\n const llmTools: LLMToolDefinition[] = [];\n\n for (const tool of allowedTools) {\n // A tool without a description gives the LLM nothing to decide on, so it\n // stays hidden. It remains executable if the model names it anyway.\n if (!tool.description) {\n if (debug) {\n console.warn(\n `[react-observer-agent] Tool \"${tool.name}\" has no description and is hidden from the LLM.`,\n );\n }\n continue;\n }\n\n llmTools.push({\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters ?? EMPTY_OBJECT_SCHEMA,\n });\n }\n\n if (stateManifest.length > 0) {\n llmTools.push(buildReadStateToolDef());\n }\n\n if (debug) {\n console.log('[react-observer-agent] Available tools:', llmTools.map((t) => t.name));\n }\n\n const toolMap = new Map(allowedTools.map((t) => [t.name, t]));\n\n const messages: ConversationMessage[] = [\n ...ctx.conversationHistory,\n { role: 'user', content: message },\n ];\n\n const manifestPrompt = buildStateManifestPrompt(stateManifest);\n const systemPrompt = [options?.systemPrompt, manifestPrompt]\n .filter(Boolean)\n .join('\\n\\n') || undefined;\n\n const allToolCalls: ToolCallResult[] = [];\n const usage = new UsageTotal();\n let turns = 0;\n let finalMessage = '';\n let completed = false;\n\n const abortedResult = (): AgentLoopResult => ({\n response: {\n message: '',\n toolCalls: allToolCalls,\n error: { message: 'Interaction aborted', code: 'ABORTED' },\n usage: usage.total(),\n },\n messages,\n });\n\n while (turns < maxTurns) {\n if (signal?.aborted) return abortedResult();\n\n turns++;\n\n if (debug) {\n console.log(`[react-observer-agent] Turn ${turns}/${maxTurns}`);\n }\n\n // `state` stays empty: the model pulls what it needs through __readState.\n const modelRequest = {\n // A snapshot, since the loop keeps appending to `messages` after this\n // call and an adapter that reads it asynchronously would see the churn.\n messages: [...messages],\n tools: llmTools,\n state: {} as Record<string, unknown>,\n systemPrompt,\n stateManifest,\n signal,\n };\n\n if (debug) {\n console.log('[react-observer-agent] LLM request:', {\n messageCount: modelRequest.messages.length,\n toolCount: modelRequest.tools.length,\n hasSystemPrompt: !!modelRequest.systemPrompt,\n });\n }\n\n let modelResponse;\n try {\n modelResponse = await model.sendMessage(modelRequest);\n } catch (error) {\n // An adapter that forwarded the signal rejects rather than resolving.\n if (isAbortError(error) || signal?.aborted) {\n return abortedResult();\n }\n throw error;\n }\n\n usage.add(modelResponse.usage);\n\n if (signal?.aborted) return abortedResult();\n\n if (debug) {\n console.log('[react-observer-agent] LLM response:', {\n content: modelResponse.content?.slice(0, 200),\n toolCalls: modelResponse.toolCalls?.map((tc) => tc.name),\n });\n }\n\n // Nothing left to run, so this is the answer.\n if (!modelResponse.toolCalls || modelResponse.toolCalls.length === 0) {\n finalMessage = modelResponse.content ?? '';\n completed = true;\n break;\n }\n\n messages.push({\n role: 'assistant',\n content: modelResponse.content ?? '',\n toolCalls: modelResponse.toolCalls,\n });\n\n for (const llmCall of modelResponse.toolCalls) {\n // Stop before starting any further side effects.\n if (signal?.aborted) return abortedResult();\n\n if (llmCall.name === READ_STATE_TOOL_NAME) {\n const args = llmCall.arguments as { keys?: string[] };\n const requestedKeys = args?.keys ?? [];\n\n const allowedKeys = requestedKeys.filter((k) => permissions.canAccess.includes(k));\n const snapshot = createStateSnapshot(state, allowedKeys, debug);\n\n if (debug) {\n console.log('[react-observer-agent] readState requested:', requestedKeys);\n console.log('[react-observer-agent] readState allowed:', allowedKeys);\n console.log('[react-observer-agent] readState result:', snapshot);\n }\n\n messages.push({\n role: 'tool',\n content: JSON.stringify(snapshot),\n toolCallId: llmCall.id,\n });\n // Internal, so it never reaches allToolCalls or onToolCall.\n continue;\n }\n\n // Re-checked after the model answered, so a hallucinated or injected\n // name is rejected even though it was never advertised.\n if (!validateToolCall(llmCall.name, permissions.canExecute)) {\n const deniedResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: `Tool \"${llmCall.name}\" is not permitted`,\n status: 'denied',\n };\n allToolCalls.push(deniedResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: deniedResult.result,\n status: 'denied',\n });\n\n messages.push({\n role: 'tool',\n content: JSON.stringify({ error: deniedResult.result }),\n toolCallId: llmCall.id,\n });\n continue;\n }\n\n const toolDef = toolMap.get(llmCall.name);\n if (!toolDef) {\n const deniedResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: `Tool \"${llmCall.name}\" not found`,\n status: 'denied',\n };\n allToolCalls.push(deniedResult);\n messages.push({\n role: 'tool',\n content: JSON.stringify({ error: deniedResult.result }),\n toolCallId: llmCall.id,\n });\n continue;\n }\n\n // Validated before anything acts on the arguments, so the user is never\n // asked to confirm a malformed call.\n if (toolDef.parameters) {\n const validation = validateArgs(llmCall.arguments, toolDef.parameters);\n if (!validation.valid) {\n const errorMessage = `Invalid arguments for tool \"${llmCall.name}\": ${validation.errors.join('; ')}`;\n\n if (debug) {\n console.warn(`[react-observer-agent] ${errorMessage}`);\n }\n\n const invalidResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: errorMessage,\n status: 'error',\n };\n allToolCalls.push(invalidResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: errorMessage,\n status: 'error',\n });\n messages.push({\n role: 'tool',\n content: JSON.stringify({ error: errorMessage }),\n toolCallId: llmCall.id,\n });\n continue;\n }\n }\n\n if (toolDef.confirm) {\n if (!options?.onConfirm) {\n if (debug) {\n console.warn(\n `[react-observer-agent] Tool \"${llmCall.name}\" requires confirmation but no onConfirm handler provided. Skipping.`,\n );\n }\n const cancelledResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: 'Tool execution cancelled: no confirmation handler provided',\n status: 'cancelled',\n };\n allToolCalls.push(cancelledResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: cancelledResult.result,\n status: 'cancelled',\n });\n messages.push({\n role: 'tool',\n content: JSON.stringify({ status: 'cancelled', reason: 'No confirmation handler' }),\n toolCallId: llmCall.id,\n });\n continue;\n }\n\n const confirmed = await options.onConfirm({\n toolName: llmCall.name,\n args: llmCall.arguments,\n description: toolDef.description,\n });\n\n if (!confirmed) {\n const cancelledResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: 'Tool execution cancelled by user',\n status: 'cancelled',\n };\n allToolCalls.push(cancelledResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: cancelledResult.result,\n status: 'cancelled',\n });\n messages.push({\n role: 'tool',\n content: JSON.stringify({ status: 'cancelled', reason: 'User denied' }),\n toolCallId: llmCall.id,\n });\n continue;\n }\n }\n\n try {\n const result = await toolDef.handler(llmCall.arguments);\n const status = toolDef.confirm ? 'confirmed' : 'success';\n\n if (debug) {\n console.log(`[react-observer-agent] Tool \"${llmCall.name}\" executed:`, { status, result });\n }\n\n const toolResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result,\n status,\n };\n allToolCalls.push(toolResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result,\n status,\n });\n messages.push({\n role: 'tool',\n content: JSON.stringify({ result }),\n toolCallId: llmCall.id,\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n const errorResult: ToolCallResult = {\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: errorMessage,\n status: 'error',\n };\n allToolCalls.push(errorResult);\n options?.onToolCall?.({\n toolName: llmCall.name,\n args: llmCall.arguments,\n result: errorMessage,\n status: 'error',\n });\n messages.push({\n role: 'tool',\n content: JSON.stringify({ error: errorMessage }),\n toolCallId: llmCall.id,\n });\n }\n }\n\n // The next turn carries the tool results back to the model.\n }\n\n // The model was still calling tools when the turn budget ran out, so it never\n // got to answer. Surface that as an error rather than an empty message.\n if (!completed) {\n if (debug) {\n console.warn(`[react-observer-agent] Max turns (${maxTurns}) reached`);\n }\n return {\n response: {\n message: '',\n toolCalls: allToolCalls,\n error: {\n message: `Agent did not produce a final response within ${maxTurns} turns`,\n code: 'MAX_TURNS',\n },\n usage: usage.total(),\n },\n messages,\n };\n }\n\n messages.push({ role: 'assistant', content: finalMessage });\n\n return {\n response: {\n message: finalMessage,\n toolCalls: allToolCalls,\n usage: usage.total(),\n },\n messages,\n };\n}\n","import { useContext } from 'react';\nimport type { AgentContext } from '../types';\nimport { AgentContextValue } from './AIAgentProvider';\n\nexport function useAgent(): AgentContext {\n const context = useContext(AgentContextValue);\n if (!context) {\n throw new Error(\n 'useAgent() must be used within an <AIAgentProvider>. ' +\n 'Wrap your component tree with <AIAgentProvider> to use this hook.',\n );\n }\n return context;\n}\n","export function filterState(\n state: Record<string, unknown>,\n canAccess: string[],\n): Record<string, unknown> {\n const filtered: Record<string, unknown> = {};\n for (const key of canAccess) {\n if (key in state) {\n filtered[key] = state[key];\n }\n }\n return filtered;\n}\n","import type {\n ConversationMessage,\n ModelAdapter,\n ModelRequest,\n ModelResponse,\n OpenAIAdapterConfig,\n} from '../types';\n\nconst DEFAULT_MODEL = 'gpt-4o';\nconst DEFAULT_TEMPERATURE = 0.2;\nconst OPENAI_BASE_URL = 'https://api.openai.com/v1';\n\nexport function openAIAdapter(config: OpenAIAdapterConfig): ModelAdapter {\n if (!config.apiKey && !config.baseURL) {\n throw new Error(\n 'openAIAdapter requires either \"apiKey\" or \"baseURL\". ' +\n 'Provide an API key for direct access, or a baseURL to route through your backend proxy.',\n );\n }\n\n const baseURL = config.baseURL\n ? config.baseURL.replace(/\\/+$/, '')\n : OPENAI_BASE_URL;\n const model = config.model ?? DEFAULT_MODEL;\n const temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n\n return {\n async sendMessage(request: ModelRequest): Promise<ModelResponse> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...config.headers,\n };\n\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n }\n\n const messages = request.systemPrompt\n ? [\n { role: 'system' as const, content: request.systemPrompt },\n ...request.messages.map(formatMessage),\n ]\n : request.messages.map(formatMessage);\n\n const tools =\n request.tools.length > 0\n ? request.tools.map((t) => ({\n type: 'function' as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n },\n }))\n : undefined;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n };\n\n if (tools) {\n body.tools = tools;\n }\n\n const url = baseURL.includes('/chat/completions')\n ? baseURL\n : `${baseURL}/chat/completions`;\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: request.signal,\n });\n } catch (error) {\n // An abort is a caller decision, not a transport failure. Rewrapping it\n // would hide the AbortError name the agent loop checks for.\n if (error instanceof Error && error.name === 'AbortError') throw error;\n throw new Error(\n `Network error calling OpenAI API: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(\n `OpenAI API error (${res.status}): ${text || res.statusText}`,\n );\n }\n\n let data: unknown;\n try {\n data = await res.json();\n } catch {\n throw new Error('Failed to parse OpenAI API response as JSON');\n }\n\n return parseResponse(data);\n },\n };\n}\n\nfunction formatMessage(msg: ConversationMessage) {\n const formatted: Record<string, unknown> = {\n role: msg.role,\n content: msg.content,\n };\n\n if (msg.toolCallId) {\n formatted.tool_call_id = msg.toolCallId;\n }\n\n // OpenAI rejects tool messages that do not follow an assistant message\n // carrying the matching tool_calls entry.\n if (msg.toolCalls && msg.toolCalls.length > 0) {\n formatted.tool_calls = msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.name,\n arguments:\n typeof tc.arguments === 'string'\n ? tc.arguments\n : JSON.stringify(tc.arguments ?? {}),\n },\n }));\n if (msg.content === '') {\n formatted.content = null;\n }\n }\n\n return formatted;\n}\n\nfunction parseResponse(data: unknown): ModelResponse {\n const obj = data as Record<string, unknown>;\n const choices = obj.choices as Array<Record<string, unknown>> | undefined;\n\n if (!choices || choices.length === 0) {\n throw new Error('Malformed OpenAI response: no choices returned');\n }\n\n const message = choices[0].message as Record<string, unknown> | undefined;\n if (!message) {\n throw new Error('Malformed OpenAI response: no message in first choice');\n }\n\n const content = (message.content as string) ?? null;\n const toolCalls = message.tool_calls as\n | Array<{\n id: string;\n function: { name: string; arguments: string };\n }>\n | undefined;\n\n const usage = obj.usage as\n | { prompt_tokens: number; completion_tokens: number }\n | undefined;\n\n return {\n content,\n toolCalls: toolCalls?.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: safeParseJSON(tc.function.arguments),\n })),\n usage: usage\n ? {\n promptTokens: usage.prompt_tokens,\n completionTokens: usage.completion_tokens,\n }\n : undefined,\n };\n}\n\nfunction safeParseJSON(str: string): unknown {\n try {\n return JSON.parse(str);\n } catch {\n return str;\n }\n}\n","import type {\n ClaudeAdapterConfig,\n ConversationMessage,\n LLMToolCall,\n ModelAdapter,\n ModelRequest,\n ModelResponse,\n} from '../types';\n\nconst DEFAULT_MODEL = 'claude-opus-5';\nconst DEFAULT_MAX_TOKENS = 16000;\nconst ANTHROPIC_BASE_URL = 'https://api.anthropic.com';\nconst ANTHROPIC_VERSION = '2023-06-01';\n\ninterface TextBlock {\n type: 'text';\n text: string;\n}\n\ninterface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n}\n\ninterface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n content: string;\n}\n\ntype ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock;\n\ninterface AnthropicMessage {\n role: 'user' | 'assistant';\n content: string | ContentBlock[];\n}\n\nexport function claudeAdapter(config: ClaudeAdapterConfig): ModelAdapter {\n if (!config.apiKey && !config.baseURL) {\n throw new Error(\n 'claudeAdapter requires either \"apiKey\" or \"baseURL\". ' +\n 'Provide an API key for direct access, or a baseURL to route through your backend proxy.',\n );\n }\n\n const baseURL = config.baseURL\n ? config.baseURL.replace(/\\/+$/, '')\n : ANTHROPIC_BASE_URL;\n const model = config.model ?? DEFAULT_MODEL;\n const maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;\n\n return {\n async sendMessage(request: ModelRequest): Promise<ModelResponse> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'anthropic-version': ANTHROPIC_VERSION,\n };\n\n if (config.apiKey) {\n headers['x-api-key'] = config.apiKey;\n }\n\n // Spread last so consumers can override anything above, including adding\n // the CORS opt-in header needed for direct browser access.\n Object.assign(headers, config.headers);\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: toAnthropicMessages(request.messages),\n };\n\n if (request.systemPrompt) {\n body.system = request.systemPrompt;\n }\n\n if (request.tools.length > 0) {\n body.tools = request.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n }\n\n const url = baseURL.includes('/v1/messages')\n ? baseURL\n : `${baseURL}/v1/messages`;\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: request.signal,\n });\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n throw new Error(\n `Network error calling Anthropic API: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(\n `Anthropic API error (${res.status}): ${text || res.statusText}`,\n );\n }\n\n let data: unknown;\n try {\n data = await res.json();\n } catch {\n throw new Error('Failed to parse Anthropic API response as JSON');\n }\n\n return parseResponse(data);\n },\n };\n}\n\n/**\n * Anthropic expects tool calls as `tool_use` blocks on an assistant message and\n * their results as `tool_result` blocks on a following user message, so a run of\n * internal tool messages collapses into one user message.\n */\nfunction toAnthropicMessages(\n messages: ConversationMessage[],\n): AnthropicMessage[] {\n const result: AnthropicMessage[] = [];\n let pendingToolResults: ToolResultBlock[] = [];\n\n const flushToolResults = () => {\n if (pendingToolResults.length > 0) {\n result.push({ role: 'user', content: pendingToolResults });\n pendingToolResults = [];\n }\n };\n\n for (const message of messages) {\n if (message.role === 'tool') {\n pendingToolResults.push({\n type: 'tool_result',\n tool_use_id: message.toolCallId ?? '',\n content: message.content,\n });\n continue;\n }\n\n flushToolResults();\n\n if (\n message.role === 'assistant' &&\n message.toolCalls &&\n message.toolCalls.length > 0\n ) {\n const blocks: ContentBlock[] = [];\n if (message.content) {\n blocks.push({ type: 'text', text: message.content });\n }\n for (const call of message.toolCalls) {\n blocks.push({\n type: 'tool_use',\n id: call.id,\n name: call.name,\n input: isPlainObject(call.arguments) ? call.arguments : {},\n });\n }\n result.push({ role: 'assistant', content: blocks });\n continue;\n }\n\n result.push({ role: message.role, content: message.content });\n }\n\n flushToolResults();\n\n return result;\n}\n\nfunction parseResponse(data: unknown): ModelResponse {\n const obj = data as Record<string, unknown>;\n const blocks = obj.content;\n\n if (!Array.isArray(blocks)) {\n throw new Error('Malformed Anthropic response: no content blocks returned');\n }\n\n const textParts: string[] = [];\n const toolCalls: LLMToolCall[] = [];\n\n for (const block of blocks as ContentBlock[]) {\n if (block?.type === 'text') {\n textParts.push(block.text);\n } else if (block?.type === 'tool_use') {\n // Already parsed by the API, unlike OpenAI's JSON-string arguments.\n toolCalls.push({\n id: block.id,\n name: block.name,\n arguments: block.input,\n });\n }\n // Other block types (thinking, for example) carry nothing this loop needs.\n }\n\n const usage = obj.usage as\n | { input_tokens: number; output_tokens: number }\n | undefined;\n\n return {\n content: textParts.length > 0 ? textParts.join('') : null,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n usage: usage\n ? {\n promptTokens: usage.input_tokens,\n completionTokens: usage.output_tokens,\n }\n : undefined,\n };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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","names":["import_react","DEFAULT_MODEL","parseResponse","isPlainObject"]}
@@ -0,0 +1,171 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type JSONSchema = Record<string, unknown>;
4
+ interface ToolOptions {
5
+ description?: string;
6
+ parameters?: JSONSchema;
7
+ confirm?: boolean;
8
+ }
9
+ interface ToolDefinition<TArgs = unknown> {
10
+ name: string;
11
+ handler: (args: TArgs) => unknown | Promise<unknown>;
12
+ description?: string;
13
+ parameters?: JSONSchema;
14
+ confirm: boolean;
15
+ }
16
+ /**
17
+ * A tool definition with its argument type erased. Tools registered with
18
+ * different argument types can only share one array through this type, since
19
+ * handler parameters are contravariant.
20
+ */
21
+ type AnyToolDefinition = ToolDefinition<any>;
22
+ interface ToolCallResult {
23
+ toolName: string;
24
+ args: unknown;
25
+ result: unknown;
26
+ status: 'success' | 'error' | 'denied' | 'confirmed' | 'cancelled';
27
+ }
28
+ interface ConversationEntry {
29
+ role: 'user' | 'assistant' | 'tool';
30
+ content: string;
31
+ toolCalls?: ToolCallResult[];
32
+ timestamp: number;
33
+ }
34
+ interface AgentError {
35
+ message: string;
36
+ code?: string;
37
+ cause?: unknown;
38
+ }
39
+ interface AgentResponse {
40
+ message: string;
41
+ toolCalls: ToolCallResult[];
42
+ error?: AgentError;
43
+ /** Totalled across every model call in the interaction, when the adapter reports it. */
44
+ usage?: {
45
+ promptTokens: number;
46
+ completionTokens: number;
47
+ };
48
+ }
49
+ interface SendOptions {
50
+ /** Cancels the interaction. The pending response resolves with an ABORTED error. */
51
+ signal?: AbortSignal;
52
+ }
53
+ interface AgentContext {
54
+ send: (message: string, options?: SendOptions) => Promise<AgentResponse>;
55
+ isProcessing: boolean;
56
+ history: ConversationEntry[];
57
+ clearHistory: () => void;
58
+ lastResponse: AgentResponse | null;
59
+ }
60
+ interface PermissionsConfig {
61
+ canAccess: string[];
62
+ canExecute: string[];
63
+ stateDescriptions?: Record<string, string>;
64
+ }
65
+ interface ConversationMessage {
66
+ role: 'user' | 'assistant' | 'tool';
67
+ content: string;
68
+ toolCallId?: string;
69
+ toolCalls?: LLMToolCall[];
70
+ }
71
+ interface LLMToolDefinition {
72
+ name: string;
73
+ description: string;
74
+ parameters: JSONSchema;
75
+ }
76
+ interface LLMToolCall {
77
+ id: string;
78
+ name: string;
79
+ arguments: unknown;
80
+ }
81
+ interface ModelRequest {
82
+ messages: ConversationMessage[];
83
+ tools: LLMToolDefinition[];
84
+ state: Record<string, unknown>;
85
+ systemPrompt?: string;
86
+ stateManifest?: {
87
+ key: string;
88
+ description: string;
89
+ }[];
90
+ /** Adapters should forward this to their transport so requests cancel in flight. */
91
+ signal?: AbortSignal;
92
+ }
93
+ interface ModelResponse {
94
+ content: string | null;
95
+ toolCalls?: LLMToolCall[];
96
+ usage?: {
97
+ promptTokens: number;
98
+ completionTokens: number;
99
+ };
100
+ }
101
+ interface ModelAdapter {
102
+ sendMessage(request: ModelRequest): Promise<ModelResponse>;
103
+ }
104
+ /**
105
+ * Application state, as an object read on each access or a getter called on
106
+ * each access. Any object shape is accepted: store interfaces rarely carry the
107
+ * index signature that `Record<string, unknown>` would demand.
108
+ */
109
+ type StateSource = object | (() => object);
110
+ interface PendingToolCall {
111
+ toolName: string;
112
+ args: unknown;
113
+ description?: string;
114
+ }
115
+ interface ToolCallEvent {
116
+ toolName: string;
117
+ args: unknown;
118
+ result: unknown;
119
+ status: ToolCallResult['status'];
120
+ }
121
+ interface AgentOptions {
122
+ debug?: boolean;
123
+ maxTurns?: number;
124
+ systemPrompt?: string;
125
+ onError?: (error: AgentError) => void;
126
+ onToolCall?: (call: ToolCallEvent) => void;
127
+ onConfirm?: (call: PendingToolCall) => Promise<boolean>;
128
+ }
129
+ interface AIAgentProviderProps {
130
+ model: ModelAdapter;
131
+ state: StateSource;
132
+ tools: AnyToolDefinition[];
133
+ permissions: PermissionsConfig;
134
+ options?: AgentOptions;
135
+ children: React.ReactNode;
136
+ }
137
+ interface OpenAIAdapterConfig {
138
+ apiKey?: string;
139
+ model?: string;
140
+ baseURL?: string;
141
+ temperature?: number;
142
+ headers?: Record<string, string>;
143
+ }
144
+ interface ClaudeAdapterConfig {
145
+ apiKey?: string;
146
+ model?: string;
147
+ baseURL?: string;
148
+ /** Required by the Anthropic API. Defaults to 16000. */
149
+ maxTokens?: number;
150
+ headers?: Record<string, string>;
151
+ }
152
+
153
+ declare function registerTool<TArgs = unknown>(name: string, handler: (args: TArgs) => unknown | Promise<unknown>, options?: ToolOptions): ToolDefinition<TArgs>;
154
+
155
+ declare function validateToolNames(tools: AnyToolDefinition[]): void;
156
+
157
+ declare function AIAgentProvider({ model, state, tools, permissions, options, children, }: AIAgentProviderProps): react_jsx_runtime.JSX.Element;
158
+
159
+ declare function useAgent(): AgentContext;
160
+
161
+ declare function filterState(state: Record<string, unknown>, canAccess: string[]): Record<string, unknown>;
162
+
163
+ declare function filterTools(tools: AnyToolDefinition[], canExecute: string[]): AnyToolDefinition[];
164
+
165
+ declare function validateToolCall(name: string, canExecute: string[]): boolean;
166
+
167
+ declare function openAIAdapter(config: OpenAIAdapterConfig): ModelAdapter;
168
+
169
+ declare function claudeAdapter(config: ClaudeAdapterConfig): ModelAdapter;
170
+
171
+ export { AIAgentProvider, type AIAgentProviderProps, type AgentContext, type AgentError, type AgentOptions, type AgentResponse, type AnyToolDefinition, type ClaudeAdapterConfig, type ConversationEntry, type ConversationMessage, type JSONSchema, type LLMToolCall, type LLMToolDefinition, type ModelAdapter, type ModelRequest, type ModelResponse, type OpenAIAdapterConfig, type PendingToolCall, type PermissionsConfig, type SendOptions, type StateSource, type ToolCallEvent, type ToolCallResult, type ToolDefinition, type ToolOptions, claudeAdapter, filterState, filterTools, openAIAdapter, registerTool, useAgent, validateToolCall, validateToolNames };
@@ -0,0 +1,171 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type JSONSchema = Record<string, unknown>;
4
+ interface ToolOptions {
5
+ description?: string;
6
+ parameters?: JSONSchema;
7
+ confirm?: boolean;
8
+ }
9
+ interface ToolDefinition<TArgs = unknown> {
10
+ name: string;
11
+ handler: (args: TArgs) => unknown | Promise<unknown>;
12
+ description?: string;
13
+ parameters?: JSONSchema;
14
+ confirm: boolean;
15
+ }
16
+ /**
17
+ * A tool definition with its argument type erased. Tools registered with
18
+ * different argument types can only share one array through this type, since
19
+ * handler parameters are contravariant.
20
+ */
21
+ type AnyToolDefinition = ToolDefinition<any>;
22
+ interface ToolCallResult {
23
+ toolName: string;
24
+ args: unknown;
25
+ result: unknown;
26
+ status: 'success' | 'error' | 'denied' | 'confirmed' | 'cancelled';
27
+ }
28
+ interface ConversationEntry {
29
+ role: 'user' | 'assistant' | 'tool';
30
+ content: string;
31
+ toolCalls?: ToolCallResult[];
32
+ timestamp: number;
33
+ }
34
+ interface AgentError {
35
+ message: string;
36
+ code?: string;
37
+ cause?: unknown;
38
+ }
39
+ interface AgentResponse {
40
+ message: string;
41
+ toolCalls: ToolCallResult[];
42
+ error?: AgentError;
43
+ /** Totalled across every model call in the interaction, when the adapter reports it. */
44
+ usage?: {
45
+ promptTokens: number;
46
+ completionTokens: number;
47
+ };
48
+ }
49
+ interface SendOptions {
50
+ /** Cancels the interaction. The pending response resolves with an ABORTED error. */
51
+ signal?: AbortSignal;
52
+ }
53
+ interface AgentContext {
54
+ send: (message: string, options?: SendOptions) => Promise<AgentResponse>;
55
+ isProcessing: boolean;
56
+ history: ConversationEntry[];
57
+ clearHistory: () => void;
58
+ lastResponse: AgentResponse | null;
59
+ }
60
+ interface PermissionsConfig {
61
+ canAccess: string[];
62
+ canExecute: string[];
63
+ stateDescriptions?: Record<string, string>;
64
+ }
65
+ interface ConversationMessage {
66
+ role: 'user' | 'assistant' | 'tool';
67
+ content: string;
68
+ toolCallId?: string;
69
+ toolCalls?: LLMToolCall[];
70
+ }
71
+ interface LLMToolDefinition {
72
+ name: string;
73
+ description: string;
74
+ parameters: JSONSchema;
75
+ }
76
+ interface LLMToolCall {
77
+ id: string;
78
+ name: string;
79
+ arguments: unknown;
80
+ }
81
+ interface ModelRequest {
82
+ messages: ConversationMessage[];
83
+ tools: LLMToolDefinition[];
84
+ state: Record<string, unknown>;
85
+ systemPrompt?: string;
86
+ stateManifest?: {
87
+ key: string;
88
+ description: string;
89
+ }[];
90
+ /** Adapters should forward this to their transport so requests cancel in flight. */
91
+ signal?: AbortSignal;
92
+ }
93
+ interface ModelResponse {
94
+ content: string | null;
95
+ toolCalls?: LLMToolCall[];
96
+ usage?: {
97
+ promptTokens: number;
98
+ completionTokens: number;
99
+ };
100
+ }
101
+ interface ModelAdapter {
102
+ sendMessage(request: ModelRequest): Promise<ModelResponse>;
103
+ }
104
+ /**
105
+ * Application state, as an object read on each access or a getter called on
106
+ * each access. Any object shape is accepted: store interfaces rarely carry the
107
+ * index signature that `Record<string, unknown>` would demand.
108
+ */
109
+ type StateSource = object | (() => object);
110
+ interface PendingToolCall {
111
+ toolName: string;
112
+ args: unknown;
113
+ description?: string;
114
+ }
115
+ interface ToolCallEvent {
116
+ toolName: string;
117
+ args: unknown;
118
+ result: unknown;
119
+ status: ToolCallResult['status'];
120
+ }
121
+ interface AgentOptions {
122
+ debug?: boolean;
123
+ maxTurns?: number;
124
+ systemPrompt?: string;
125
+ onError?: (error: AgentError) => void;
126
+ onToolCall?: (call: ToolCallEvent) => void;
127
+ onConfirm?: (call: PendingToolCall) => Promise<boolean>;
128
+ }
129
+ interface AIAgentProviderProps {
130
+ model: ModelAdapter;
131
+ state: StateSource;
132
+ tools: AnyToolDefinition[];
133
+ permissions: PermissionsConfig;
134
+ options?: AgentOptions;
135
+ children: React.ReactNode;
136
+ }
137
+ interface OpenAIAdapterConfig {
138
+ apiKey?: string;
139
+ model?: string;
140
+ baseURL?: string;
141
+ temperature?: number;
142
+ headers?: Record<string, string>;
143
+ }
144
+ interface ClaudeAdapterConfig {
145
+ apiKey?: string;
146
+ model?: string;
147
+ baseURL?: string;
148
+ /** Required by the Anthropic API. Defaults to 16000. */
149
+ maxTokens?: number;
150
+ headers?: Record<string, string>;
151
+ }
152
+
153
+ declare function registerTool<TArgs = unknown>(name: string, handler: (args: TArgs) => unknown | Promise<unknown>, options?: ToolOptions): ToolDefinition<TArgs>;
154
+
155
+ declare function validateToolNames(tools: AnyToolDefinition[]): void;
156
+
157
+ declare function AIAgentProvider({ model, state, tools, permissions, options, children, }: AIAgentProviderProps): react_jsx_runtime.JSX.Element;
158
+
159
+ declare function useAgent(): AgentContext;
160
+
161
+ declare function filterState(state: Record<string, unknown>, canAccess: string[]): Record<string, unknown>;
162
+
163
+ declare function filterTools(tools: AnyToolDefinition[], canExecute: string[]): AnyToolDefinition[];
164
+
165
+ declare function validateToolCall(name: string, canExecute: string[]): boolean;
166
+
167
+ declare function openAIAdapter(config: OpenAIAdapterConfig): ModelAdapter;
168
+
169
+ declare function claudeAdapter(config: ClaudeAdapterConfig): ModelAdapter;
170
+
171
+ export { AIAgentProvider, type AIAgentProviderProps, type AgentContext, type AgentError, type AgentOptions, type AgentResponse, type AnyToolDefinition, type ClaudeAdapterConfig, type ConversationEntry, type ConversationMessage, type JSONSchema, type LLMToolCall, type LLMToolDefinition, type ModelAdapter, type ModelRequest, type ModelResponse, type OpenAIAdapterConfig, type PendingToolCall, type PermissionsConfig, type SendOptions, type StateSource, type ToolCallEvent, type ToolCallResult, type ToolDefinition, type ToolOptions, claudeAdapter, filterState, filterTools, openAIAdapter, registerTool, useAgent, validateToolCall, validateToolNames };