/** * vapor-chamber — Schema layer * * Flat runtime schema. One source of truth for: * - TypeScript types (inferred, no separate CommandMap needed) * - schemaLogger: enriched logging with descriptions and field validation * - toTools(): Anthropic / OpenAI tool definitions * - synthesize(): natural language → dispatch via LLM tool use */ import type { CommandBus, AsyncCommandBus, Plugin, CommandResult, CommandBusOptions, CommandMap, BusErrorCode, BusSeverity, BusEmitter } from './command-bus'; export type FieldType = 'string' | 'number' | 'boolean' | 'array' | 'object' | 'any'; export type FieldMap = Record; export type ActionSchema = { description?: string; target?: FieldMap; payload?: FieldMap; result?: FieldMap; /** * Laravel Gate ability name required to run this action — declarative, * server-enforced authorization. Purely descriptive on the bus itself * (auth must be server-side, so * `schemaValidator` never checks it); `scripts/generate-laravel.mjs` reads * it to emit `Gate::forUser($user)->authorize('', ...)` into the * generated action-class stub, ahead of the existing validation block. * * @example * cartCheckout: { * authorize: 'checkout', * target: { cartId: 'number' }, * }, */ authorize?: string; }; export type BusSchema = Record; type InferField = F extends 'string' ? string : F extends 'number' ? number : F extends 'boolean' ? boolean : F extends 'array' ? any[] : F extends 'object' ? Record : any; type InferFields = M extends FieldMap ? { [K in keyof M]: InferField; } : any; export type InferMap = { [K in keyof S]: { target: InferFields; payload: InferFields; result: InferFields; }; }; /** Alias for {@link InferMap} — reads better at GlobalCommands augmentation sites. */ export type CommandsOf = InferMap; /** * defineSchema — identity helper that PRESERVES field-type literals, so the * schema keeps its inference power. Without it, `{ id: 'number' }` widens to * `Record` and every inferred type collapses to `any`. * * The complete one-source-of-truth wiring: * * @example * // commands.ts — define once * export const schema = defineSchema({ * cartAdd: { * description: 'Add a product to the cart', * target: { id: 'number', name: 'string' }, * payload: { qty: 'number' }, * result: { count: 'number', total: 'number' }, * }, * cartCheckout: { * description: 'Charge the cart and place the order', * authorize: 'checkout', // → Gate::forUser($user)->authorize('checkout', ...) * target: { cartId: 'number' }, * }, * }); * * // → typed schema bus (validation + LLM tools included) * const bus = createSchemaCommandBus(schema); * * // → typed SHARED bus for every useCommand()/getCommandBus() call site * declare module 'vapor-chamber' { * interface GlobalCommands extends CommandsOf {} * } * setCommandBus(bus); * * // → Laravel stubs + registry: node scripts/generate-laravel.mjs commands.mjs * // → agent tools: bus.toTools() / vapor-chamber/mcp */ export declare function defineSchema(schema: S): S; export type AnthropicTool = { name: string; description?: string; input_schema: { type: 'object'; properties: { target?: { type: 'object'; properties: Record; }; payload?: { type: 'object'; properties: Record; }; }; }; }; export type OpenAITool = { type: 'function'; function: { name: string; description?: string; parameters: { type: 'object'; properties: { target?: { type: 'object'; properties: Record; }; payload?: { type: 'object'; properties: Record; }; }; }; }; }; export declare function toAnthropicTools(schema: BusSchema): AnthropicTool[]; export declare function toOpenAITools(schema: BusSchema): OpenAITool[]; export declare function toTools(schema: BusSchema, provider?: 'anthropic' | 'openai'): AnthropicTool[] | OpenAITool[]; export declare function schemaValidator(schema: BusSchema): Plugin; export type SchemaLoggerOptions = { collapsed?: boolean; }; export declare function schemaLogger(schema: BusSchema, options?: SchemaLoggerOptions): Plugin; /** * Custom LLM adapter for synthesize(). Receives the Anthropic-format tools, user text, * and options, and must return a ToolCallInput (same shape as an LLM tool_use block). * Use this to route LLM calls through your own proxy, OpenAI, or any other provider. * * @example * const adapter: LlmAdapter = async (tools, text) => { * const res = await myLlmProxy.complete({ tools, prompt: text }); * return { name: res.toolName, input: res.args }; * }; */ export type LlmAdapter = (tools: AnthropicTool[], text: string, options: SynthesizeOptions) => Promise; export type SynthesizeOptions = { /** LLM adapter — required. Receives tool definitions + text, returns a ToolCallInput. */ adapter?: LlmAdapter; /** Passed through to the adapter for provider-specific config. */ [key: string]: unknown; }; /** * synthesize — natural language → bus dispatch via LLM tool use. * * Requires an `adapter` — a function that takes tool definitions + user text * and returns a ToolCallInput. This keeps vapor-chamber vendor-agnostic: * bring your own Anthropic SDK, OpenAI SDK, or custom proxy. * * @example * const result = await synthesize(schema, bus, 'add 2 of item 5', { * adapter: async (tools, text) => { * const res = await anthropic.messages.create({ tools, messages: [{ role: 'user', content: text }] }); * const toolUse = res.content.find(b => b.type === 'tool_use'); * return { name: toolUse.name, input: toolUse.input }; * }, * }); */ export declare function synthesize(schema: BusSchema, bus: CommandBus | AsyncCommandBus, text: string, options?: SynthesizeOptions): Promise; export declare function describeSchema(schema: BusSchema): string; export type ToolCallInput = { name: string; input?: { target?: Record; payload?: Record; } & Record; }; export type SchemaCommandBusOptions = CommandBusOptions & { /** * Auto-install schemaValidator plugin on creation. Default: `true`. * Set to `false` to skip validation (e.g. in production with pre-validated inputs). */ validate?: boolean; }; export type SchemaCommandBus = CommandBus & { toTools(provider?: 'anthropic' | 'openai'): AnthropicTool[] | OpenAITool[]; synthesize(text: string, options?: SynthesizeOptions): Promise; getSchema(): BusSchema; describe(): string; fromToolCall(toolUse: ToolCallInput): CommandResult; }; export type AsyncSchemaCommandBus = AsyncCommandBus & { toTools(provider?: 'anthropic' | 'openai'): AnthropicTool[] | OpenAITool[]; synthesize(text: string, options?: SynthesizeOptions): Promise; getSchema(): BusSchema; describe(): string; fromToolCall(toolUse: ToolCallInput): Promise; }; /** * Creates a CommandBus typed from a flat runtime schema. * No separate CommandMap needed — TypeScript types are inferred automatically. * * @example * const bus = createSchemaCommandBus({ * cartAdd: { * description: 'Add item to cart', * target: { id: 'number' }, * payload: { qty: 'number' }, * result: { newTotal: 'number' }, * }, * }); * * bus.dispatch('cartAdd', { id: 1 }, { qty: 2 }); // fully typed * const tools = bus.toTools(); // Anthropic tool definitions * const result = await bus.synthesize('add 2 of item 5', { adapter: myAdapter }); */ /** * Creates an AsyncCommandBus typed from a flat runtime schema. * Use this when handlers perform async work (API calls, DB, LLM). * * @example * const bus = createAsyncSchemaCommandBus({ * cartAdd: { description: 'Add item', target: { id: 'number' }, payload: { qty: 'number' } }, * }); * bus.register('cartAdd', async (cmd) => fetchCart(cmd.target.id, cmd.payload.qty)); * const result = await bus.synthesize('add 2 of item 5', { adapter: myAdapter }); */ export declare function createAsyncSchemaCommandBus(schema: S, options?: SchemaCommandBusOptions): AsyncSchemaCommandBus>; export declare function createSchemaCommandBus(schema: S, options?: SchemaCommandBusOptions): SchemaCommandBus>; /** * Error code definition — every BusError code has a structured entry. * Useful for generating documentation, i18n lookups, and LLM error handling. */ export type ErrorCodeEntry = { code: BusErrorCode; severity: BusSeverity; emitter: BusEmitter; /** * Whether re-dispatching can plausibly succeed (transient failure, e.g. * throttle/timeout) — false for permanent failures (validation, config). * Must stay in sync with RETRYABLE_CODES in command-bus.ts (asserted in tests). */ retryable: boolean; /** Broad failure category for filtering, telemetry, and LLM error handling. */ category: 'general' | 'network' | 'validation' | 'internal' | 'logic'; message: string; /** Human-readable fix suggestion for LLMs and developers. */ fix: string; }; /** * Complete registry of all BusError codes with their metadata. * This is the single source of truth for error documentation. * * @example * import { ERROR_CODE_REGISTRY } from 'vapor-chamber'; * // Lookup an error code * const entry = ERROR_CODE_REGISTRY.find(e => e.code === 'VC_CORE_NO_HANDLER'); * console.log(entry?.fix); // "Register a handler with bus.register(action, handler)" * * @example * // Generate an LLM system prompt with all error codes * const prompt = ERROR_CODE_REGISTRY * .map(e => `${e.code} (${e.severity}): ${e.message} → Fix: ${e.fix}`) * .join('\n'); */ export declare const ERROR_CODE_REGISTRY: readonly ErrorCodeEntry[]; /** * Get the error registry entry for a BusError code. * * @example * if (result.error instanceof BusError) { * const entry = getErrorEntry(result.error.code); * console.log(entry?.fix); // actionable fix suggestion * } */ export declare function getErrorEntry(code: BusErrorCode): ErrorCodeEntry | undefined; /** * Is this BusError code a transient (retryable) failure? Consults the registry. * Returns undefined for codes not in ERROR_CODE_REGISTRY. * * @example * if (result.error instanceof BusError && isRetryableCode(result.error.code) === false) { * // permanent failure — don't re-dispatch * } */ export declare function isRetryableCode(code: string): boolean | undefined; /** * Describe all error codes as plain text — useful for LLM system prompts. * * @example * const systemPrompt = `When the bus returns an error, use this table:\n${describeErrorCodes()}`; */ export declare function describeErrorCodes(): string; /** * Generates a JSON Schema-style description of the bus API. * Include this in LLM system prompts so the model knows exactly what methods * are available and their signatures — reduces hallucinated method calls. * * @example * const schema = busApiSchema(); * const systemPrompt = `Use the vapor-chamber bus API:\n${JSON.stringify(schema, null, 2)}`; */ export declare function busApiSchema(): Record; returns: string; }>; export {}; //# sourceMappingURL=schema.d.ts.map