@directive-run/ai 1.23.0 → 1.24.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.
- package/README.md +27 -0
- package/dist/anthropic.cjs +1 -1
- package/dist/anthropic.cjs.map +1 -1
- package/dist/anthropic.d.cts +33 -1
- package/dist/anthropic.d.ts +33 -1
- package/dist/anthropic.js +1 -1
- package/dist/anthropic.js.map +1 -1
- package/dist/{chunk-MPMBFW2P.cjs → chunk-25OLDNZ3.cjs} +3 -3
- package/dist/chunk-25OLDNZ3.cjs.map +1 -0
- package/dist/chunk-2Y4YWZDV.js +3 -0
- package/dist/chunk-2Y4YWZDV.js.map +1 -0
- package/dist/{chunk-J2Q5KKPN.js → chunk-437ADRES.js} +3 -3
- package/dist/{chunk-J2Q5KKPN.js.map → chunk-437ADRES.js.map} +1 -1
- package/dist/{chunk-ESJQSOKJ.cjs → chunk-4LENWYLG.cjs} +7 -7
- package/dist/{chunk-ESJQSOKJ.cjs.map → chunk-4LENWYLG.cjs.map} +1 -1
- package/dist/chunk-4TDH6ZTX.cjs +3 -0
- package/dist/chunk-4TDH6ZTX.cjs.map +1 -0
- package/dist/{chunk-K64WKZ22.cjs → chunk-AEX7HKNM.cjs} +2 -2
- package/dist/chunk-AEX7HKNM.cjs.map +1 -0
- package/dist/{chunk-7KCLEIAG.js → chunk-CMH5TJGN.js} +15 -15
- package/dist/chunk-CMH5TJGN.js.map +1 -0
- package/dist/{chunk-LOHC2KP5.js → chunk-EUB4NVVN.js} +3 -3
- package/dist/{chunk-LOHC2KP5.js.map → chunk-EUB4NVVN.js.map} +1 -1
- package/dist/{chunk-CXWHLEBQ.js → chunk-H7UFBMLV.js} +3 -3
- package/dist/{chunk-CXWHLEBQ.js.map → chunk-H7UFBMLV.js.map} +1 -1
- package/dist/{chunk-TEPEQE42.js → chunk-L6H6Y6IK.js} +3 -3
- package/dist/chunk-L6H6Y6IK.js.map +1 -0
- package/dist/{chunk-PEM2LPOC.cjs → chunk-L7QHLH6U.cjs} +4 -4
- package/dist/{chunk-PEM2LPOC.cjs.map → chunk-L7QHLH6U.cjs.map} +1 -1
- package/dist/{chunk-GWWZXJOG.cjs → chunk-LPTC3N2Z.cjs} +15 -15
- package/dist/chunk-LPTC3N2Z.cjs.map +1 -0
- package/dist/{chunk-GTB6HTZV.js → chunk-MRKU3UXH.js} +2 -2
- package/dist/chunk-MRKU3UXH.js.map +1 -0
- package/dist/{chunk-UR5BMWEN.js → chunk-XMEJN4FA.js} +2 -2
- package/dist/chunk-XMEJN4FA.js.map +1 -0
- package/dist/{chunk-MDXDPECP.cjs → chunk-Y4A4UJPU.cjs} +2 -2
- package/dist/chunk-Y4A4UJPU.cjs.map +1 -0
- package/dist/{chunk-XN5LUOVS.cjs → chunk-ZUNORULG.cjs} +7 -7
- package/dist/{chunk-XN5LUOVS.cjs.map → chunk-ZUNORULG.cjs.map} +1 -1
- package/dist/{debug-timeline-DpnRMnLU.d.cts → debug-timeline-B_bXRStF.d.cts} +1 -1
- package/dist/{debug-timeline-L13P-U2I.d.ts → debug-timeline-Btt-iaak.d.ts} +1 -1
- package/dist/devtools.d.cts +5 -5
- package/dist/devtools.d.ts +5 -5
- package/dist/evals.cjs +1 -1
- package/dist/evals.d.cts +2 -2
- package/dist/evals.d.ts +2 -2
- package/dist/evals.js +1 -1
- package/dist/gemini.cjs +1 -1
- package/dist/gemini.d.cts +1 -1
- package/dist/gemini.d.ts +1 -1
- package/dist/gemini.js +1 -1
- package/dist/{guardrails-export-CxCOi3sd.d.ts → guardrails-export-lvaBJlt6.d.ts} +5 -5
- package/dist/{guardrails-export-D3pKHiPp.d.cts → guardrails-export-pmpQjIKb.d.cts} +5 -5
- package/dist/guardrails.cjs +1 -1
- package/dist/guardrails.d.cts +2 -2
- package/dist/guardrails.d.ts +2 -2
- package/dist/guardrails.js +1 -1
- package/dist/{health-monitor-C6xoXrQz.d.cts → health-monitor-DqAzufyM.d.cts} +1 -1
- package/dist/{health-monitor-qL9RNMH3.d.ts → health-monitor-DrlBF6n9.d.ts} +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +12 -8
- package/dist/index.d.ts +12 -8
- package/dist/index.js +1 -1
- package/dist/{multi-agent-orchestrator-FIF4GLVR.js → multi-agent-orchestrator-PI7X7ZGP.js} +2 -2
- package/dist/{multi-agent-orchestrator-FIF4GLVR.js.map → multi-agent-orchestrator-PI7X7ZGP.js.map} +1 -1
- package/dist/multi-agent-orchestrator-Z5NK4HIJ.cjs +2 -0
- package/dist/{multi-agent-orchestrator-PHDHFCW3.cjs.map → multi-agent-orchestrator-Z5NK4HIJ.cjs.map} +1 -1
- package/dist/multi-agent.cjs +1 -1
- package/dist/multi-agent.d.cts +6 -6
- package/dist/multi-agent.d.ts +6 -6
- package/dist/multi-agent.js +1 -1
- package/dist/ollama.cjs +1 -1
- package/dist/ollama.d.cts +1 -1
- package/dist/ollama.d.ts +1 -1
- package/dist/ollama.js +1 -1
- package/dist/openai.cjs +1 -1
- package/dist/openai.d.cts +1 -1
- package/dist/openai.d.ts +1 -1
- package/dist/openai.js +1 -1
- package/dist/{orchestrator-types-DxWn77qo.d.cts → orchestrator-types-B9nrJYFx.d.cts} +3 -3
- package/dist/{orchestrator-types-BxOJllSa.d.ts → orchestrator-types-ByqFuu3O.d.ts} +3 -3
- package/dist/predicate.cjs +1 -1
- package/dist/predicate.d.cts +2 -2
- package/dist/predicate.d.ts +2 -2
- package/dist/predicate.js +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +4 -4
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +1 -1
- package/dist/{types-DJ09LjZX.d.cts → types-BzpGfUA2.d.cts} +11 -0
- package/dist/{types-DJ09LjZX.d.ts → types-BzpGfUA2.d.ts} +11 -0
- package/package.json +2 -2
- package/dist/chunk-3WO4MWJM.cjs +0 -3
- package/dist/chunk-3WO4MWJM.cjs.map +0 -1
- package/dist/chunk-7KCLEIAG.js.map +0 -1
- package/dist/chunk-GTB6HTZV.js.map +0 -1
- package/dist/chunk-GWWZXJOG.cjs.map +0 -1
- package/dist/chunk-K64WKZ22.cjs.map +0 -1
- package/dist/chunk-MDXDPECP.cjs.map +0 -1
- package/dist/chunk-MPMBFW2P.cjs.map +0 -1
- package/dist/chunk-TEPEQE42.js.map +0 -1
- package/dist/chunk-UR5BMWEN.js.map +0 -1
- package/dist/chunk-ZFLHWJ56.js +0 -3
- package/dist/chunk-ZFLHWJ56.js.map +0 -1
- package/dist/multi-agent-orchestrator-PHDHFCW3.cjs +0 -2
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":["GuardrailError","options","isGuardrailError","error","AGENT_KEY","APPROVAL_KEY","CONVERSATION_KEY","TOOL_CALLS_KEY","BREAKPOINT_KEY","SCRATCHPAD_KEY","orchestratorBridgeSchema","t"],"mappings":"qDA8jBO,IAAMA,EAAN,cAA6B,KAAM,CAC/B,IAAA,CACA,aAAA,CACA,aAAA,CACA,WAAA,CAEA,UAGT,WAAA,CAAYC,CAAAA,CAUT,CACD,KAAA,CAAMA,CAAAA,CAAQ,QAAS,CAAE,KAAA,CAAOA,CAAAA,CAAQ,KAAM,CAAC,CAAA,CAC/C,IAAA,CAAK,KAAO,gBAAA,CACZ,IAAA,CAAK,KAAOA,CAAAA,CAAQ,IAAA,CACpB,IAAA,CAAK,aAAA,CAAgBA,EAAQ,aAAA,CAC7B,IAAA,CAAK,cAAgBA,CAAAA,CAAQ,aAAA,CAC7B,KAAK,WAAA,CAAcA,CAAAA,CAAQ,WAAA,EAAeA,CAAAA,CAAQ,QAClD,IAAA,CAAK,SAAA,CAAYA,EAAQ,SAAA,CAEzB,MAAA,CAAO,eAAe,IAAA,CAAM,OAAA,CAAS,CACnC,KAAA,CAAOA,EAAQ,KAAA,CACf,UAAA,CAAY,MACZ,QAAA,CAAU,KAAA,CACV,aAAc,KAChB,CAAC,CAAA,CACD,MAAA,CAAO,eAAe,IAAA,CAAM,MAAA,CAAQ,CAClC,KAAA,CAAOA,CAAAA,CAAQ,KACf,UAAA,CAAY,KAAA,CACZ,SAAU,KAAA,CACV,YAAA,CAAc,KAChB,CAAC,EACH,CAEA,MAAA,EAAkC,CAChC,OAAO,CACL,IAAA,CAAM,IAAA,CAAK,IAAA,CACX,KAAM,IAAA,CAAK,IAAA,CACX,QAAS,IAAA,CAAK,OAAA,CACd,cAAe,IAAA,CAAK,aAAA,CACpB,aAAA,CAAe,IAAA,CAAK,cACpB,WAAA,CAAa,IAAA,CAAK,YAClB,SAAA,CAAW,IAAA,CAAK,SAClB,CACF,CACF,EAGO,SAASC,EAAiBC,CAAAA,CAAyC,CACxE,OAAOA,CAAAA,YAAiBH,CAC1B,CAqBO,IAAMI,CAAAA,CAAY,UACZC,CAAAA,CAAe,YAAA,CACfC,EAAmB,gBAAA,CACnBC,CAAAA,CAAiB,cACjBC,CAAAA,CAAiB,oBA2kBjBC,CAAAA,CAAiB,cAAA,CA0YjBC,CAAAA,CAA2B,CACtC,MAAO,CACL,CAACN,CAAS,EAAGO,MAAA,CAAE,QAAO,CACtB,CAACN,CAAY,EAAGM,OAAE,MAAA,EAAO,CACzB,CAACL,CAAgB,EAAGK,OAAE,KAAA,EAAM,CAC5B,CAACJ,CAAc,EAAGI,MAAA,CAAE,KAAA,GACpB,CAACH,CAAc,EAAGG,MAAA,CAAE,MAAA,EACtB,CAAA,CACA,WAAA,CAAa,EAAC,CACd,MAAA,CAAQ,EAAC,CACT,YAAA,CAAc,EAChB","file":"chunk-K64WKZ22.cjs","sourcesContent":["/**\n * Shared types for AI adapter — used by orchestrator, guardrails, helpers, and stack.\n */\n\nimport type {\n ModuleSchema,\n Requirement,\n SchemaType,\n} from \"@directive-run/core\";\nimport { t } from \"@directive-run/core\";\nimport type {\n BreakpointRequest,\n BreakpointState as BreakpointStateFromBreakpoints,\n} from \"./breakpoints.js\";\n\n// ============================================================================\n// Agent Types (LLM-agnostic)\n// ============================================================================\n\n/** Simplified Agent interface */\nexport interface AgentLike {\n name: string;\n instructions?: string;\n model?: string;\n tools?: unknown[];\n}\n\n/** Agent run result */\nexport interface RunResult<T = unknown> {\n output: T;\n messages: Message[];\n toolCalls: ToolCall[];\n totalTokens: number;\n /** Breakdown of input vs output tokens, when available from the provider */\n tokenUsage?: TokenUsage;\n /** True when result was served from semantic cache */\n isCached?: boolean;\n}\n\n/** Breakdown of token usage by input/output */\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n}\n\n/** Message from agent run */\nexport interface Message {\n role: \"user\" | \"assistant\" | \"tool\" | \"system\";\n content: string;\n toolCallId?: string;\n}\n\n/** Tool call record */\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: string;\n result?: string;\n}\n\n/** Run function type */\nexport type AgentRunner = <T = unknown>(\n agent: AgentLike,\n input: string,\n options?: RunOptions,\n) => Promise<RunResult<T>>;\n\n/** Callback-based streaming run function (e.g. for SSE-based LLM APIs) */\nexport type StreamingCallbackRunner = (\n agent: AgentLike,\n input: string,\n callbacks: {\n onToken?: (token: string) => void;\n onToolStart?: (tool: string, id: string, args: string) => void;\n onToolEnd?: (tool: string, id: string, result: string) => void;\n onMessage?: (message: Message) => void;\n signal?: AbortSignal;\n },\n) => Promise<RunResult<unknown>>;\n\n/** Run options */\nexport interface RunOptions {\n maxTurns?: number;\n signal?: AbortSignal;\n onMessage?: (message: Message) => void;\n onToolCall?: (toolCall: ToolCall) => void | Promise<void>;\n}\n\n// ============================================================================\n// Adapter Lifecycle Hooks\n// ============================================================================\n\n/**\n * Lifecycle hooks for adapter-level observability.\n *\n * Attach to any adapter (runner or streaming runner) to trace, log,\n * or measure individual LLM calls without modifying application code.\n *\n * @example\n * ```typescript\n * const runner = createOpenAIRunner({\n * apiKey: process.env.OPENAI_API_KEY!,\n * hooks: {\n * onBeforeCall: ({ agent, input }) => console.log(`→ ${agent.name}`, input.slice(0, 50)),\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * metrics.track('llm_call', { durationMs, ...tokenUsage });\n * },\n * onError: ({ error }) => Sentry.captureException(error),\n * },\n * });\n * ```\n */\nexport interface AdapterHooks {\n /** Fires before each LLM API call. */\n onBeforeCall?: (event: {\n agent: AgentLike;\n input: string;\n timestamp: number;\n }) => void;\n\n /** Fires after a successful LLM API call. */\n onAfterCall?: (event: {\n agent: AgentLike;\n input: string;\n output: string;\n totalTokens: number;\n tokenUsage: TokenUsage;\n durationMs: number;\n timestamp: number;\n }) => void;\n\n /** Fires when an LLM API call fails. */\n onError?: (event: {\n agent: AgentLike;\n input: string;\n error: Error;\n durationMs: number;\n timestamp: number;\n }) => void;\n}\n\n// ============================================================================\n// Guardrail Types\n// ============================================================================\n\n/** Guardrail function */\nexport type GuardrailFn<T = unknown> = (\n data: T,\n context: GuardrailContext,\n) => GuardrailResult | Promise<GuardrailResult>;\n\n/** Guardrail context */\nexport interface GuardrailContext {\n agentName: string;\n input: string;\n facts: Record<string, unknown>;\n}\n\n/** Guardrail result */\nexport interface GuardrailResult {\n passed: boolean;\n reason?: string;\n transformed?: unknown;\n}\n\n/** Input guardrail data */\nexport interface InputGuardrailData {\n input: string;\n agentName: string;\n}\n\n/** Output guardrail data */\nexport interface OutputGuardrailData {\n output: unknown;\n agentName: string;\n input: string;\n messages: Message[];\n}\n\n/** Tool call guardrail data */\nexport interface ToolCallGuardrailData {\n toolCall: ToolCall;\n agentName: string;\n input: string;\n}\n\n/** Retry configuration for guardrails */\nexport interface GuardrailRetryConfig {\n /** Total attempts (1 = no retries, 2 = one retry, etc.). @default 1 */\n attempts?: number;\n /** @default \"exponential\" */\n backoff?: \"exponential\" | \"linear\" | \"fixed\";\n /** @default 100 */\n baseDelayMs?: number;\n /** @default 5000 */\n maxDelayMs?: number;\n}\n\n/** Named guardrail for better debugging */\nexport interface NamedGuardrail<T = unknown> {\n name: string;\n fn: GuardrailFn<T>;\n /** @default true */\n critical?: boolean;\n retry?: GuardrailRetryConfig;\n}\n\n/** Guardrails configuration */\nexport interface GuardrailsConfig {\n input?: Array<\n GuardrailFn<InputGuardrailData> | NamedGuardrail<InputGuardrailData>\n >;\n output?: Array<\n GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>\n >;\n toolCall?: Array<\n GuardrailFn<ToolCallGuardrailData> | NamedGuardrail<ToolCallGuardrailData>\n >;\n}\n\n// ============================================================================\n// Retry Configuration\n// ============================================================================\n\n/** Retry configuration for agent runs */\nexport interface AgentRetryConfig {\n /** @default 1 */\n attempts?: number;\n /** @default \"exponential\" */\n backoff?: \"exponential\" | \"linear\" | \"fixed\";\n /** @default 1000 */\n baseDelayMs?: number;\n /** @default 30000 */\n maxDelayMs?: number;\n isRetryable?: (error: Error) => boolean;\n onRetry?: (attempt: number, error: Error, delayMs: number) => void;\n}\n\n// ============================================================================\n// Orchestrator State Types\n// ============================================================================\n\n/** Agent state in facts */\nexport interface AgentState {\n status: \"idle\" | \"running\" | \"paused\" | \"completed\" | \"error\";\n currentAgent: string | null;\n input: string | null;\n output: unknown | null;\n error: string | null;\n tokenUsage: number;\n turnCount: number;\n startedAt: number | null;\n completedAt: number | null;\n}\n\n/** Approval state */\nexport interface ApprovalState {\n pending: ApprovalRequest[];\n approved: string[];\n rejected: RejectedRequest[];\n}\n\n/** Rejected request with tracking information */\nexport interface RejectedRequest {\n id: string;\n reason?: string;\n rejectedAt: number;\n}\n\n/** Approval request */\nexport interface ApprovalRequest {\n id: string;\n type: \"tool_call\" | \"output\" | \"handoff\";\n agentName: string;\n description: string;\n data: unknown;\n requestedAt: number;\n}\n\n/** Combined orchestrator state */\nexport interface OrchestratorState {\n agent: AgentState;\n approval: ApprovalState;\n conversation: Message[];\n toolCalls: ToolCall[];\n}\n\n// ============================================================================\n// Orchestrator Config Types\n// ============================================================================\n\n/** Constraint for orchestrator */\nexport interface OrchestratorConstraint<F extends Record<string, unknown>> {\n when: (facts: F & OrchestratorState) => boolean | Promise<boolean>;\n require: Requirement | ((facts: F & OrchestratorState) => Requirement);\n priority?: number;\n}\n\n/** Resolver context for orchestrator */\nexport interface OrchestratorResolverContext<\n F extends Record<string, unknown>,\n> {\n facts: F & OrchestratorState;\n runAgent: <T>(\n agent: AgentLike,\n input: string,\n options?: RunOptions,\n ) => Promise<RunResult<T>>;\n signal: AbortSignal;\n}\n\n/** Resolver for orchestrator */\nexport interface OrchestratorResolver<\n F extends Record<string, unknown>,\n R extends Requirement = Requirement,\n> {\n requirement: (req: Requirement) => req is R;\n key?: (req: R) => string;\n resolve: (\n req: R,\n context: OrchestratorResolverContext<F>,\n ) => void | Promise<void>;\n}\n\n/** Lifecycle hooks for observability */\nexport interface OrchestratorLifecycleHooks {\n onAgentStart?: (event: {\n agentName: string;\n input: string;\n timestamp: number;\n }) => void;\n onAgentComplete?: (event: {\n agentName: string;\n input: string;\n output: unknown;\n tokenUsage: number;\n durationMs: number;\n timestamp: number;\n }) => void;\n onAgentError?: (event: {\n agentName: string;\n input: string;\n error: Error;\n durationMs: number;\n timestamp: number;\n }) => void;\n onGuardrailCheck?: (event: {\n agentId?: string;\n guardrailName: string;\n guardrailType: \"input\" | \"output\" | \"toolCall\";\n passed: boolean;\n reason?: string;\n durationMs: number;\n timestamp: number;\n }) => void;\n onAgentRetry?: (event: {\n agentName: string;\n input: string;\n attempt: number;\n error: Error;\n delayMs: number;\n timestamp: number;\n }) => void;\n /** Called when a breakpoint is hit and waiting for resolution. */\n onBreakpoint?: (request: BreakpointRequest) => void;\n}\n\n/** Lifecycle hooks for multi-agent orchestrator observability */\nexport interface MultiAgentLifecycleHooks {\n onAgentStart?: (event: {\n agentId: string;\n agentName: string;\n input: string;\n timestamp: number;\n }) => void;\n onAgentComplete?: (event: {\n agentId: string;\n agentName: string;\n input: string;\n output: unknown;\n tokenUsage: number;\n durationMs: number;\n timestamp: number;\n }) => void;\n onAgentError?: (event: {\n agentId: string;\n agentName: string;\n input: string;\n error: Error;\n durationMs: number;\n timestamp: number;\n }) => void;\n onGuardrailCheck?: (event: {\n agentId: string;\n guardrailName: string;\n guardrailType: \"input\" | \"output\" | \"toolCall\";\n passed: boolean;\n reason?: string;\n durationMs: number;\n timestamp: number;\n }) => void;\n onAgentRetry?: (event: {\n agentId: string;\n agentName: string;\n input: string;\n attempt: number;\n error: Error;\n delayMs: number;\n timestamp: number;\n }) => void;\n onHandoff?: (request: {\n id: string;\n fromAgent: string;\n toAgent: string;\n input: string;\n requestedAt: number;\n }) => void;\n onHandoffComplete?: (result: {\n request: { id: string; fromAgent: string; toAgent: string };\n completedAt: number;\n }) => void;\n onPatternStart?: (event: {\n patternId: string;\n patternType:\n | \"parallel\"\n | \"sequential\"\n | \"supervisor\"\n | \"dag\"\n | \"reflect\"\n | \"race\"\n | \"debate\"\n | \"goal\";\n input: string;\n timestamp: number;\n }) => void;\n onPatternComplete?: (event: {\n patternId: string;\n patternType:\n | \"parallel\"\n | \"sequential\"\n | \"supervisor\"\n | \"dag\"\n | \"reflect\"\n | \"race\"\n | \"debate\"\n | \"goal\";\n durationMs: number;\n timestamp: number;\n error?: Error;\n }) => void;\n onDagNodeStart?: (event: {\n patternId: string;\n nodeId: string;\n agentId: string;\n nodeType: \"agent\" | \"task\";\n timestamp: number;\n }) => void;\n onDagNodeComplete?: (event: {\n patternId: string;\n nodeId: string;\n agentId: string;\n nodeType: \"agent\" | \"task\";\n durationMs: number;\n timestamp: number;\n }) => void;\n onDagNodeError?: (event: {\n patternId: string;\n nodeId: string;\n agentId: string;\n nodeType: \"agent\" | \"task\";\n error: Error;\n durationMs: number;\n timestamp: number;\n }) => void;\n onDagNodeSkipped?: (event: {\n patternId: string;\n nodeId: string;\n agentId: string;\n nodeType: \"agent\" | \"task\";\n reason: string;\n timestamp: number;\n }) => void;\n onHealthChange?: (event: {\n agentId: string;\n oldScore: number;\n newScore: number;\n timestamp: number;\n }) => void;\n onReroute?: (event: RerouteEvent) => void;\n /** Called when a breakpoint is hit and waiting for resolution. */\n onBreakpoint?: (request: BreakpointRequest) => void;\n /** Called when a cross-agent derivation value updates */\n onDerivationUpdate?: (event: {\n derivationId: string;\n value: unknown;\n timestamp: number;\n }) => void;\n /** Called when a cross-agent derivation throws an error */\n onDerivationError?: (event: {\n derivationId: string;\n error: Error;\n timestamp: number;\n }) => void;\n /** Called when scratchpad values are updated */\n onScratchpadUpdate?: (event: { keys: string[]; timestamp: number }) => void;\n /** Called when a task starts executing */\n onTaskStart?: (event: {\n patternId: string;\n taskId: string;\n label: string;\n timestamp: number;\n }) => void;\n /** Called when a task completes successfully */\n onTaskComplete?: (event: {\n patternId: string;\n taskId: string;\n label: string;\n durationMs: number;\n timestamp: number;\n }) => void;\n /** Called when a task fails */\n onTaskError?: (event: {\n patternId: string;\n taskId: string;\n label: string;\n error: Error;\n durationMs: number;\n timestamp: number;\n }) => void;\n /** Called when a task reports progress */\n onTaskProgress?: (event: {\n patternId: string;\n taskId: string;\n label: string;\n percent: number;\n message?: string;\n timestamp: number;\n }) => void;\n /** Called when a pattern checkpoint is saved */\n onCheckpointSave?: (event: {\n checkpointId: string;\n patternType: string;\n step: number;\n timestamp: number;\n }) => void;\n /** Called when a checkpoint save fails */\n onCheckpointError?: (event: {\n patternType: string;\n step: number;\n error: Error;\n timestamp: number;\n }) => void;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/** Error codes for guardrail errors */\nexport type GuardrailErrorCode =\n | \"INPUT_GUARDRAIL_FAILED\"\n | \"OUTPUT_GUARDRAIL_FAILED\"\n | \"TOOL_CALL_GUARDRAIL_FAILED\"\n | \"APPROVAL_REJECTED\"\n | \"BUDGET_EXCEEDED\"\n | \"RATE_LIMIT_EXCEEDED\"\n | \"AGENT_ERROR\";\n\n/**\n * Structured error for guardrail failures.\n *\n * **Security:** The `input` and `data` properties are non-enumerable to prevent\n * accidental leakage of sensitive data via JSON.stringify or console.log.\n */\nexport class GuardrailError extends Error {\n readonly code: GuardrailErrorCode;\n readonly guardrailName: string;\n readonly guardrailType: \"input\" | \"output\" | \"toolCall\";\n readonly userMessage: string;\n declare readonly data: unknown;\n readonly agentName: string;\n declare readonly input: string;\n\n constructor(options: {\n code: GuardrailErrorCode;\n message: string;\n guardrailName: string;\n guardrailType: \"input\" | \"output\" | \"toolCall\";\n userMessage?: string;\n data?: unknown;\n agentName: string;\n input: string;\n cause?: Error;\n }) {\n super(options.message, { cause: options.cause });\n this.name = \"GuardrailError\";\n this.code = options.code;\n this.guardrailName = options.guardrailName;\n this.guardrailType = options.guardrailType;\n this.userMessage = options.userMessage ?? options.message;\n this.agentName = options.agentName;\n\n Object.defineProperty(this, \"input\", {\n value: options.input,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.defineProperty(this, \"data\", {\n value: options.data,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n guardrailName: this.guardrailName,\n guardrailType: this.guardrailType,\n userMessage: this.userMessage,\n agentName: this.agentName,\n };\n }\n}\n\n/** Check if an error is a GuardrailError. */\nexport function isGuardrailError(error: unknown): error is GuardrailError {\n return error instanceof GuardrailError;\n}\n\n// ============================================================================\n// Schema Validation Types (used by built-in guardrails)\n// ============================================================================\n\n/** Schema validation result */\nexport interface SchemaValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\n/** Schema validator function type */\nexport type SchemaValidator<_T = unknown> = (\n value: unknown,\n) => SchemaValidationResult | boolean;\n\n// ============================================================================\n// Bridge Schema Constants\n// ============================================================================\n\nexport const AGENT_KEY = \"__agent\" as const;\nexport const APPROVAL_KEY = \"__approval\" as const;\nexport const CONVERSATION_KEY = \"__conversation\" as const;\nexport const TOOL_CALLS_KEY = \"__toolCalls\" as const;\nexport const BREAKPOINT_KEY = \"__breakpoints\" as const;\n\n// ============================================================================\n// DAG Execution Types (Multi-Agent)\n// ============================================================================\n\n/** Status of a DAG node during execution */\nexport type DagNodeStatus =\n | \"pending\"\n | \"ready\"\n | \"running\"\n | \"completed\"\n | \"error\"\n | \"skipped\";\n\n/** Execution context available to DAG node callbacks */\nexport interface DagExecutionContext {\n /** Original input to the DAG */\n input: string;\n /** Outputs keyed by node ID (populated as nodes complete) */\n outputs: Record<string, unknown>;\n /** Statuses keyed by node ID */\n statuses: Record<string, DagNodeStatus>;\n /** Error messages keyed by node ID */\n errors: Record<string, string>;\n /** Full RunResult keyed by node ID */\n results: Record<string, RunResult<unknown>>;\n}\n\n/** A node in a DAG execution pattern */\nexport interface DagNode {\n /** Registered handler ID (agent or task) to run for this node */\n handler: string;\n /** Upstream node IDs this node depends on */\n deps?: string[];\n /** Conditional edge — evaluated when deps are met. @default unconditional */\n when?: (context: DagExecutionContext) => boolean;\n /** Build input string for this node's agent. @default JSON.stringify(upstream outputs) */\n transform?: (context: DagExecutionContext) => string;\n /** Per-node timeout (ms) */\n timeout?: number;\n /** Tiebreaker when multiple nodes are ready (higher = first). @default 0 */\n priority?: number;\n}\n\n/** DAG execution pattern — nodes are agents, edges are reactive conditions */\nexport interface DagPattern<T = unknown> {\n type: \"dag\";\n /** Nodes keyed by node ID */\n nodes: Record<string, DagNode>;\n /** Merge all node outputs into the final result */\n merge: (context: DagExecutionContext) => T | Promise<T>;\n /** Overall DAG timeout (ms) */\n timeout?: number;\n /** Maximum nodes running concurrently. @default Infinity. Consider setting this to avoid API rate limits. */\n maxConcurrent?: number;\n /** Error handling strategy. @default \"fail\" */\n onNodeError?: \"fail\" | \"skip-downstream\" | \"continue\";\n /** Checkpoint configuration for mid-execution fault tolerance */\n checkpoint?: PatternCheckpointConfig;\n}\n\n// ============================================================================\n// Debug Configuration\n// ============================================================================\n\n/** Debug configuration for orchestrators */\nexport interface OrchestratorDebugConfig {\n verboseTimeline?: boolean;\n}\n\n// ============================================================================\n// Debug Timeline Types\n// ============================================================================\n\n/** All debug event types */\nexport type DebugEventType =\n | \"agent_start\"\n | \"agent_complete\"\n | \"agent_error\"\n | \"agent_retry\"\n | \"guardrail_check\"\n | \"constraint_evaluate\"\n | \"resolver_start\"\n | \"resolver_complete\"\n | \"resolver_error\"\n | \"approval_request\"\n | \"approval_response\"\n | \"handoff_start\"\n | \"handoff_complete\"\n | \"pattern_start\"\n | \"pattern_complete\"\n | \"dag_node_update\"\n | \"breakpoint_hit\"\n | \"breakpoint_resumed\"\n | \"derivation_update\"\n | \"scratchpad_update\"\n | \"reflection_iteration\"\n | \"race_start\"\n | \"race_winner\"\n | \"race_cancelled\"\n | \"debate_round\"\n | \"reroute\"\n | \"checkpoint_save\"\n | \"checkpoint_restore\"\n | \"task_start\"\n | \"task_complete\"\n | \"task_error\"\n | \"task_progress\"\n | \"goal_step\";\n\n/** Base debug event */\nexport interface DebugEventBase {\n id: number;\n type: DebugEventType;\n timestamp: number;\n agentId?: string;\n snapshotId: number | null;\n}\n\n/** Agent start event */\nexport interface AgentStartEvent extends DebugEventBase {\n type: \"agent_start\";\n agentId: string;\n inputLength: number;\n /** Truncated input text (max 5000 chars) */\n input?: string;\n}\n\n/** Agent complete event */\nexport interface AgentCompleteEvent extends DebugEventBase {\n type: \"agent_complete\";\n agentId: string;\n outputLength: number;\n totalTokens: number;\n inputTokens: number;\n outputTokens: number;\n durationMs: number;\n modelId?: string;\n /** Truncated output text (max 5000 chars) */\n output?: string;\n}\n\n/** Agent error event */\nexport interface AgentErrorEvent extends DebugEventBase {\n type: \"agent_error\";\n agentId: string;\n errorMessage: string;\n durationMs: number;\n}\n\n/** Agent retry event */\nexport interface AgentRetryEvent extends DebugEventBase {\n type: \"agent_retry\";\n agentId: string;\n attempt: number;\n errorMessage: string;\n delayMs: number;\n}\n\n/** Guardrail check event */\nexport interface GuardrailCheckEvent extends DebugEventBase {\n type: \"guardrail_check\";\n guardrailName: string;\n guardrailType: \"input\" | \"output\" | \"toolCall\";\n passed: boolean;\n reason?: string;\n durationMs: number;\n}\n\n/** Constraint evaluate event */\nexport interface ConstraintEvaluateEvent extends DebugEventBase {\n type: \"constraint_evaluate\";\n constraintId: string;\n fired: boolean;\n}\n\n/** Resolver start event */\nexport interface ResolverStartEvent extends DebugEventBase {\n type: \"resolver_start\";\n resolverId: string;\n requirementType: string;\n}\n\n/** Resolver complete event */\nexport interface ResolverCompleteEvent extends DebugEventBase {\n type: \"resolver_complete\";\n resolverId: string;\n durationMs: number;\n}\n\n/** Resolver error event */\nexport interface ResolverErrorEvent extends DebugEventBase {\n type: \"resolver_error\";\n resolverId: string;\n errorMessage: string;\n durationMs: number;\n}\n\n/** Approval request event */\nexport interface ApprovalRequestEvent extends DebugEventBase {\n type: \"approval_request\";\n requestId: string;\n approvalType: \"tool_call\" | \"output\" | \"handoff\";\n}\n\n/** Approval response event */\nexport interface ApprovalResponseEvent extends DebugEventBase {\n type: \"approval_response\";\n requestId: string;\n approved: boolean;\n reason?: string;\n}\n\n/** Handoff start event */\nexport interface HandoffStartEvent extends DebugEventBase {\n type: \"handoff_start\";\n fromAgent: string;\n toAgent: string;\n}\n\n/** Handoff complete event */\nexport interface HandoffCompleteEvent extends DebugEventBase {\n type: \"handoff_complete\";\n fromAgent: string;\n toAgent: string;\n durationMs: number;\n}\n\n/** Pattern start event */\nexport interface PatternStartEvent extends DebugEventBase {\n type: \"pattern_start\";\n patternId: string;\n patternType:\n | \"parallel\"\n | \"sequential\"\n | \"supervisor\"\n | \"dag\"\n | \"reflect\"\n | \"race\"\n | \"debate\"\n | \"goal\";\n /** All handler IDs in this pattern (agents + tasks) */\n handlers?: string[];\n /** Which handler IDs are tasks (rest are agents) */\n taskIds?: string[];\n}\n\n/** Pattern complete event */\nexport interface PatternCompleteEvent extends DebugEventBase {\n type: \"pattern_complete\";\n patternId: string;\n patternType:\n | \"parallel\"\n | \"sequential\"\n | \"supervisor\"\n | \"dag\"\n | \"reflect\"\n | \"race\"\n | \"debate\"\n | \"goal\";\n durationMs: number;\n error?: string;\n}\n\n/** DAG node update event */\nexport interface DagNodeUpdateEvent extends DebugEventBase {\n type: \"dag_node_update\";\n nodeId: string;\n status: DagNodeStatus;\n deps?: string[];\n}\n\n/** Breakpoint hit event */\nexport interface BreakpointHitEvent extends DebugEventBase {\n type: \"breakpoint_hit\";\n breakpointId: string;\n breakpointType: string;\n label?: string;\n}\n\n/** Breakpoint resumed event */\nexport interface BreakpointResumedEvent extends DebugEventBase {\n type: \"breakpoint_resumed\";\n breakpointId: string;\n modified: boolean;\n skipped: boolean;\n}\n\n/** Derivation update event */\nexport interface DerivationUpdateEvent extends DebugEventBase {\n type: \"derivation_update\";\n derivationId: string;\n valueType: string;\n}\n\n/** Scratchpad update event */\nexport interface ScratchpadUpdateEvent extends DebugEventBase {\n type: \"scratchpad_update\";\n keys: string[];\n}\n\n/** Reflection iteration event */\nexport interface ReflectionIterationEvent extends DebugEventBase {\n type: \"reflection_iteration\";\n iteration: number;\n passed: boolean;\n score?: number;\n durationMs: number;\n producerTokens: number;\n evaluatorTokens: number;\n}\n\n/** Race start event */\nexport interface RaceStartEvent extends DebugEventBase {\n type: \"race_start\";\n patternId: string;\n agents: string[];\n}\n\n/** Race winner event */\nexport interface RaceWinnerEvent extends DebugEventBase {\n type: \"race_winner\";\n patternId: string;\n winnerId: string;\n durationMs: number;\n}\n\n/** Race cancelled event */\nexport interface RaceCancelledEvent extends DebugEventBase {\n type: \"race_cancelled\";\n patternId: string;\n cancelledIds: string[];\n reason: \"winner_found\" | \"timeout\" | \"all_failed\";\n}\n\n/** Debate round event — emitted after each round's judgement */\nexport interface DebateRoundEvent extends DebugEventBase {\n type: \"debate_round\";\n patternId: string;\n round: number;\n totalRounds: number;\n winnerId: string;\n score?: number;\n agentCount: number;\n}\n\n/** Reroute debug event recorded when self-healing reroutes to an alternate agent */\nexport interface RerouteDebugEvent extends DebugEventBase {\n type: \"reroute\";\n agentId: string;\n from: string;\n to: string;\n reason: string;\n}\n\n/** Checkpoint save event */\nexport interface CheckpointSaveEvent extends DebugEventBase {\n type: \"checkpoint_save\";\n checkpointId: string;\n patternType: string;\n step: number;\n}\n\n/** Checkpoint restore event */\nexport interface CheckpointRestoreEvent extends DebugEventBase {\n type: \"checkpoint_restore\";\n checkpointId: string;\n patternType: string;\n step: number;\n}\n\n/** Task start event */\nexport interface TaskStartEvent extends DebugEventBase {\n type: \"task_start\";\n taskId: string;\n label: string;\n description?: string;\n inputLength: number;\n}\n\n/** Task complete event */\nexport interface TaskCompleteEvent extends DebugEventBase {\n type: \"task_complete\";\n taskId: string;\n label: string;\n durationMs: number;\n}\n\n/** Task error event */\nexport interface TaskErrorEvent extends DebugEventBase {\n type: \"task_error\";\n taskId: string;\n label: string;\n error: string;\n durationMs: number;\n attempt?: number;\n}\n\n/** Task progress event */\nexport interface TaskProgressEvent extends DebugEventBase {\n type: \"task_progress\";\n taskId: string;\n label: string;\n percent: number;\n message?: string;\n}\n\n/** Goal step event — emitted for each agent invocation within a goal step */\nexport interface GoalStepEvent extends DebugEventBase {\n type: \"goal_step\";\n agentId: string;\n step: number;\n nodeId: string;\n satisfaction: number;\n satisfactionDelta: number;\n}\n\n/** Union of all debug event types */\nexport type DebugEvent =\n | AgentStartEvent\n | AgentCompleteEvent\n | AgentErrorEvent\n | AgentRetryEvent\n | GuardrailCheckEvent\n | ConstraintEvaluateEvent\n | ResolverStartEvent\n | ResolverCompleteEvent\n | ResolverErrorEvent\n | ApprovalRequestEvent\n | ApprovalResponseEvent\n | HandoffStartEvent\n | HandoffCompleteEvent\n | PatternStartEvent\n | PatternCompleteEvent\n | DagNodeUpdateEvent\n | BreakpointHitEvent\n | BreakpointResumedEvent\n | DerivationUpdateEvent\n | ScratchpadUpdateEvent\n | ReflectionIterationEvent\n | RaceStartEvent\n | RaceWinnerEvent\n | RaceCancelledEvent\n | DebateRoundEvent\n | RerouteDebugEvent\n | CheckpointSaveEvent\n | CheckpointRestoreEvent\n | TaskStartEvent\n | TaskCompleteEvent\n | TaskErrorEvent\n | TaskProgressEvent\n | GoalStepEvent;\n\n// ============================================================================\n// Self-Healing Types\n// ============================================================================\n\n/** Health state for an agent stored in facts */\nexport interface AgentHealthState {\n circuitState: \"CLOSED\" | \"OPEN\" | \"HALF_OPEN\";\n healthScore: number;\n lastUpdated: number;\n}\n\n/** Reroute event fired when an agent is rerouted */\nexport interface RerouteEvent {\n originalAgent: string;\n reroutedTo: string;\n reason: string;\n timestamp: number;\n}\n\n/** Health monitor configuration */\nexport interface HealthMonitorConfig {\n /** Rolling window for metrics (ms). @default 60000 */\n windowMs?: number;\n /** Weights for health score computation (must sum to ~1.0) */\n weights?: {\n /** Weight for success rate (0-1). @default 0.5 */\n successRate?: number;\n /** Weight for latency (0-1). @default 0.3 */\n latency?: number;\n /** Weight for circuit state (0-1). @default 0.2 */\n circuitState?: number;\n };\n /** Max latency considered \"normal\" (ms). @default 5000 */\n maxNormalLatencyMs?: number;\n /** Max events per agent before FIFO eviction. @default 1000 */\n maxEventsPerAgent?: number;\n}\n\n/** Self-healing configuration for single-agent orchestrator */\nexport interface SelfHealingConfig {\n /** Fallback runners to try in order when primary CB is open */\n fallbackRunners?: AgentRunner[];\n /** Fallback agent to try when all runners fail */\n fallbackAgent?: AgentLike;\n /** Circuit breaker config for primary runner */\n circuitBreaker?: AgentCircuitBreakerConfig;\n /** Health score below which to trigger reroute. @default 30 */\n healthThreshold?: number;\n /** Behavior when all fallbacks exhausted */\n degradation?: \"reject\" | \"fallback-response\";\n /** Static response to return when degradation is \"fallback-response\" */\n fallbackResponse?: unknown;\n /** Callback when reroute occurs */\n onReroute?: (event: RerouteEvent) => void;\n}\n\n/** Self-healing configuration for multi-agent orchestrator */\nexport interface MultiAgentSelfHealingConfig {\n /** Default circuit breaker config for agents without their own */\n circuitBreakerDefaults?: AgentCircuitBreakerConfig;\n /** Health score below which to trigger reroute. @default 30 */\n healthThreshold?: number;\n /** Explicit equivalency groups (group name → agent IDs) */\n equivalencyGroups?: Record<string, string[]>;\n /** Use capability matching for implicit equivalency. @default true */\n useCapabilities?: boolean;\n /** Strategy for selecting equivalent agent */\n selectionStrategy?: \"healthiest\" | \"round-robin\";\n /** Behavior when all equivalents are down */\n degradation?: \"reject\" | \"fallback-response\";\n /** Static response for \"fallback-response\" degradation */\n fallbackResponse?: unknown;\n /** Callback when reroute occurs */\n onReroute?: (event: RerouteEvent) => void;\n /** Callback when agent health changes */\n onHealthChange?: (event: {\n agentId: string;\n oldScore: number;\n newScore: number;\n }) => void;\n /** Health monitor configuration */\n healthMonitor?: HealthMonitorConfig;\n}\n\n/** Circuit breaker config for AI agent self-healing (simplified subset of core CircuitBreakerConfig) */\nexport interface AgentCircuitBreakerConfig {\n /** Number of failures before opening. @default 5 */\n failureThreshold?: number;\n /** Time before trying half-open (ms). @default 30000 */\n resetTimeoutMs?: number;\n /** Successes needed to close from half-open. @default 2 */\n halfOpenSuccesses?: number;\n /** State change callback */\n onStateChange?: (from: string, to: string) => void;\n}\n\n/** Internal key for health state in coordinator facts */\nexport const HEALTH_KEY = \"__agentHealth\" as const;\n\n/** Breakpoint state stored in bridge schema — canonical definition in breakpoints.ts */\nexport type BreakpointState = BreakpointStateFromBreakpoints;\n\n// ============================================================================\n// Cross-Agent Derivation Types\n// ============================================================================\n\n/** Snapshot of all agent states for cross-agent derivations */\nexport interface CrossAgentSnapshot {\n agents: Record<\n string,\n {\n status: \"idle\" | \"running\" | \"completed\" | \"error\";\n lastInput?: string;\n lastOutput?: unknown;\n lastError?: string;\n runCount: number;\n totalTokens: number;\n }\n >;\n coordinator: { globalTokens: number; status: string };\n scratchpad?: Record<string, unknown>;\n}\n\n/** Function that computes a derived value from a cross-agent snapshot */\nexport type CrossAgentDerivationFn<T = unknown> = (\n snapshot: CrossAgentSnapshot,\n) => T;\n\n// ============================================================================\n// Shared Scratchpad Types\n// ============================================================================\n\n/** Internal key for scratchpad fact on coordinator module */\nexport const SCRATCHPAD_KEY = \"__scratchpad\" as const;\n\n/** Shared scratchpad interface for multi-agent collaboration */\nexport interface Scratchpad<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n get<K extends keyof T>(key: K): T[K];\n set<K extends keyof T>(key: K, value: T[K]): void;\n /** Check if a key exists in the scratchpad */\n has<K extends keyof T>(key: K): boolean;\n /** Delete a key from the scratchpad */\n delete<K extends keyof T>(key: K): void;\n update(values: Partial<T>): void;\n getAll(): T;\n subscribe(\n keys: (keyof T)[],\n callback: (key: keyof T, value: unknown) => void,\n ): () => void;\n onChange(callback: (key: string, value: unknown) => void): () => void;\n reset(): void;\n}\n\n// ============================================================================\n// Goal Pattern Types\n// ============================================================================\n\n/** A node in a goal execution pattern */\nexport interface GoalNode {\n /** Handler ID — agent or task registered on the orchestrator */\n handler: string;\n /** Fact keys this node can produce */\n produces: string[];\n /** Fact keys this node needs (must be satisfied before running) */\n requires?: string[];\n /** Allow re-run if input facts change after completion */\n allowRerun?: boolean;\n /** Priority for selection when multiple nodes are ready. Higher = first */\n priority?: number;\n /** Build the input string from current facts */\n buildInput?: (facts: Record<string, unknown>) => string;\n /** Extract output facts from the agent's result */\n extractOutput?: (result: RunResult<unknown>) => Record<string, unknown>;\n}\n\n/** Goal step metrics */\nexport interface GoalStepMetrics {\n step: number;\n durationMs: number;\n nodesRun: string[];\n factsProduced: string[];\n satisfaction: number;\n satisfactionDelta: number;\n tokensConsumed: number;\n}\n\n/** Goal progress metrics */\nexport interface GoalMetrics {\n satisfaction: number;\n progressRate: number;\n estimatedStepsRemaining: number | null;\n decelerating: boolean;\n}\n\n/** Agent selection strategy for goal pattern */\nexport interface AgentSelectionStrategy {\n /**\n * Select which ready agents to run this step.\n *\n * @param readyAgents - Agent IDs whose `requires` are satisfied\n * @param metrics - Per-agent performance metrics (runs, avgSatisfactionDelta, tokens)\n * @param goalMetrics - Global goal progress metrics. Built-in strategies use per-agent\n * metrics only; this parameter enables custom strategies that account for overall goal\n * progress (e.g., switching to cheaper agents as satisfaction approaches 1.0).\n */\n select: (\n readyAgents: string[],\n metrics: Record<\n string,\n { runs: number; avgSatisfactionDelta: number; tokens: number }\n >,\n goalMetrics: GoalMetrics,\n ) => string[];\n}\n\n/** Relaxation context passed to custom relaxation strategies */\nexport interface RelaxationContext {\n step: number;\n facts: Record<string, unknown>;\n metrics: GoalMetrics;\n completedNodes: Set<string>;\n failedNodes: Map<string, number>;\n}\n\n/** Relaxation strategy for when goal pursuit stalls */\nexport type RelaxationStrategy =\n | { type: \"allow_rerun\"; nodes: string[] }\n | { type: \"alternative_nodes\"; nodes: GoalNode[] }\n | { type: \"inject_facts\"; facts: Record<string, unknown> }\n | { type: \"accept_partial\" }\n | {\n type: \"custom\";\n apply: (context: RelaxationContext) => void | Promise<void>;\n };\n\n/** Relaxation tier — progressively applied when goal pursuit stalls */\nexport interface RelaxationTier {\n label: string;\n /** Steps of no progress before applying. @default 3 */\n afterStallSteps?: number;\n strategy: RelaxationStrategy;\n}\n\n/** Record of a relaxation event */\nexport interface RelaxationRecord {\n step: number;\n tierIndex: number;\n label: string;\n strategy: RelaxationStrategy[\"type\"];\n}\n\n/** Goal execution pattern — declare desired state, let the runtime resolve */\nexport interface GoalPattern<T = unknown> {\n type: \"goal\";\n /** Nodes with produces/requires declarations */\n nodes: Record<string, GoalNode>;\n /** Goal condition — when this returns true, the goal is achieved */\n when: (facts: Record<string, unknown>) => boolean;\n /** Quantitative satisfaction: 0.0 to 1.0. Enables progress tracking.\n * If omitted, binary: 0.0 when when() is false, 1.0 when true. */\n satisfaction?: (facts: Record<string, unknown>) => number;\n /** Max goal steps. @default 50 */\n maxSteps?: number;\n /** Extract final result from achieved facts */\n extract?: (facts: Record<string, unknown>) => T;\n /** Timeout in ms. @default 300000 */\n timeout?: number;\n /** Abort signal */\n signal?: AbortSignal;\n /** Agent selection strategy. @default \"all-ready\" */\n selectionStrategy?: AgentSelectionStrategy;\n /** Relaxation tiers — progressively applied when goal pursuit stalls */\n relaxation?: RelaxationTier[];\n /** Lifecycle hooks */\n onStep?: (\n step: number,\n facts: Record<string, unknown>,\n readyAgents: string[],\n ) => void;\n onStall?: (step: number, metrics: GoalMetrics) => void;\n /** Checkpoint configuration for mid-execution fault tolerance */\n checkpoint?: PatternCheckpointConfig;\n}\n\n/** Result of a goal pattern execution */\nexport interface GoalResult<T = unknown> {\n /** Whether the when() condition was satisfied */\n achieved: boolean;\n /** Final value (from extract, or raw facts) */\n result: T;\n /** Final facts state */\n facts: Record<string, unknown>;\n /** Nodes that ran, in execution order */\n executionOrder: string[];\n /** Per-node results */\n nodeResults: Record<string, RunResult<unknown>>;\n /** Total goal steps taken */\n steps: number;\n /** Total tokens consumed */\n totalTokens: number;\n /** Total duration (ms) */\n durationMs: number;\n /** Per-step metrics (satisfaction, nodes run, etc.) */\n stepMetrics: GoalStepMetrics[];\n /** Relaxation events applied */\n relaxations: RelaxationRecord[];\n /** Error message if goal was not achieved */\n error?: string;\n}\n\n// ============================================================================\n// Pattern Checkpoint Types (Universal)\n// ============================================================================\n\n/** Universal checkpoint configuration for all execution patterns */\nexport interface PatternCheckpointConfig {\n /** Save a checkpoint every N steps/rounds/iterations. @default 5 */\n everyN?: number;\n /** Checkpoint store. Uses the orchestrator's store if not provided. */\n store?: import(\"./checkpoint.js\").CheckpointStore;\n /** Label prefix for checkpoints. @default pattern type name */\n labelPrefix?: string;\n /** Conditional: only save when this returns true */\n when?: (context: CheckpointContext) => boolean;\n}\n\n/** Context passed to conditional checkpoint predicates */\nexport interface CheckpointContext {\n /** Current step/round/iteration number */\n step: number;\n /** Pattern type identifier */\n patternType: string;\n /** Pattern-specific facts (goal only) */\n facts?: Record<string, unknown>;\n /** Satisfaction score 0-1 (goal only) */\n satisfaction?: number;\n}\n\nexport type GoalCheckpointConfig = PatternCheckpointConfig;\n\n// ---- Common checkpoint state fields ----\n\n/** Common fields present on all pattern checkpoint states */\nexport interface PatternCheckpointBase {\n /** Checkpoint format version */\n version: 1;\n /** Unique ID */\n id: string;\n /** ISO timestamp */\n createdAt: string;\n /** User label */\n label?: string;\n /** Pattern ID */\n patternId: string;\n /** Total expected steps/rounds/iterations (null for unbounded) */\n stepsTotal?: number | null;\n}\n\n// ---- Per-pattern checkpoint states ----\n\n/** Checkpoint state for sequential pattern */\nexport interface SequentialCheckpointState extends PatternCheckpointBase {\n type: \"sequential\";\n /** Next agent index to run */\n step: number;\n /** Current input for the next agent */\n currentInput: string;\n /** Results collected so far (output + tokens) */\n results: Array<{ agentId: string; output: unknown; totalTokens: number }>;\n}\n\n/** Checkpoint state for supervisor pattern */\nexport interface SupervisorCheckpointState extends PatternCheckpointBase {\n type: \"supervisor\";\n /** Next round number */\n round: number;\n /** Last supervisor output */\n supervisorOutput: unknown;\n /** Worker results so far */\n workerResults: Array<{ output: unknown; totalTokens: number }>;\n /** Current input to supervisor */\n currentInput: string;\n}\n\n/** Checkpoint state for reflect pattern */\nexport interface ReflectCheckpointState extends PatternCheckpointBase {\n type: \"reflect\";\n /** Next iteration number */\n iteration: number;\n /** Current effective input */\n effectiveInput: string;\n /** Iteration history */\n history: Array<{\n iteration: number;\n passed: boolean;\n score?: number;\n feedback?: string;\n durationMs: number;\n producerTokens: number;\n evaluatorTokens: number;\n }>;\n /** Producer outputs so far */\n producerOutputs: Array<{ output: unknown; score?: number }>;\n /** Last producer output */\n lastProducerOutput: unknown | null;\n}\n\n/** Checkpoint state for debate pattern */\nexport interface DebateCheckpointState extends PatternCheckpointBase {\n type: \"debate\";\n /** Next round number */\n round: number;\n /** Current input for the round */\n currentInput: string;\n /** Completed rounds */\n rounds: Array<{\n proposals: Array<{ agentId: string; output: unknown }>;\n judgement: { winnerId: string; feedback?: string; score?: number };\n }>;\n /** Last winning agent ID */\n lastWinnerId: string;\n /** Last winning output */\n lastWinnerOutput: unknown;\n /** Tokens consumed so far */\n tokensConsumed: number;\n}\n\n/** Checkpoint state for DAG pattern */\nexport interface DagCheckpointState extends PatternCheckpointBase {\n type: \"dag\";\n /** Per-node statuses */\n statuses: Record<string, DagNodeStatus>;\n /** Per-node outputs */\n outputs: Record<string, unknown>;\n /** Per-node errors */\n errors: Record<string, string>;\n /** Number of completed nodes */\n completedCount: number;\n /** Full results (output + tokens per node) */\n nodeResults: Record<string, { output: unknown; totalTokens: number }>;\n /** Original input */\n input: string;\n}\n\n/** Serializable mid-goal state for save/resume */\nexport interface GoalCheckpointState extends PatternCheckpointBase {\n /** Pattern type discriminator */\n type: \"goal\";\n /** Current step */\n step: number;\n /** Current facts snapshot */\n facts: Record<string, unknown>;\n /** Completed node IDs */\n completedNodes: string[];\n /** Failed node IDs with consecutive failure counts */\n failedNodes: Record<string, number>;\n /** Node input hashes (for allowRerun detection) */\n nodeInputHashes: Record<string, string>;\n /** Per-node results (serialized — output only, not the full RunResult) */\n nodeOutputs: Record<string, { output: unknown; totalTokens: number }>;\n /** Execution order so far */\n executionOrder: string[];\n /** Step metrics collected so far */\n stepMetrics: GoalStepMetrics[];\n /** Relaxations applied so far */\n relaxations: RelaxationRecord[];\n /** Applied relaxation tier index */\n appliedRelaxationTiers: number;\n /** Stall step counter */\n stallSteps: number;\n /** Last satisfaction value */\n lastSatisfaction: number;\n /** Per-agent metrics */\n agentMetrics: Record<\n string,\n { runs: number; totalDelta: number; tokens: number }\n >;\n}\n\n/** Discriminated union of all pattern checkpoint states */\nexport type PatternCheckpointState =\n | SequentialCheckpointState\n | SupervisorCheckpointState\n | ReflectCheckpointState\n | DebateCheckpointState\n | DagCheckpointState\n | GoalCheckpointState;\n\n// ---- Checkpoint utilities ----\n\n/** Progress computed from a checkpoint state */\nexport interface CheckpointProgress {\n /** 0-100 percentage complete */\n percentage: number;\n /** Steps/rounds/iterations completed */\n stepsCompleted: number;\n /** Total expected steps (null for unbounded patterns) */\n stepsTotal: number | null;\n /** Tokens consumed so far */\n tokensConsumed: number;\n /** Estimated tokens remaining (null when unknowable) */\n estimatedTokensRemaining: number | null;\n /** Estimated steps remaining (null when unknowable) */\n estimatedStepsRemaining: number | null;\n}\n\n/** Diff between two checkpoint states */\nexport interface CheckpointDiff {\n /** Pattern type */\n patternType: string;\n /** Step/round/iteration difference */\n stepDelta: number;\n /** Token difference */\n tokensDelta: number;\n /** Fact changes (goal only) */\n facts?: {\n added: string[];\n removed: string[];\n changed: Array<{ key: string; before: unknown; after: unknown }>;\n };\n /** Nodes completed between checkpoints (DAG/goal) */\n nodesCompleted?: string[];\n}\n\n/** Bridge schema for orchestrator (internal plumbing — types cast to bypass t.object constraint) */\nexport const orchestratorBridgeSchema = {\n facts: {\n [AGENT_KEY]: t.object() as unknown as SchemaType<AgentState>,\n [APPROVAL_KEY]: t.object() as unknown as SchemaType<ApprovalState>,\n [CONVERSATION_KEY]: t.array() as unknown as SchemaType<Message[]>,\n [TOOL_CALLS_KEY]: t.array() as unknown as SchemaType<ToolCall[]>,\n [BREAKPOINT_KEY]: t.object() as unknown as SchemaType<BreakpointState>,\n },\n derivations: {},\n events: {},\n requirements: {},\n} satisfies ModuleSchema;\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/predicate-from-intent.ts"],"names":["djb2Hash","str","hash","i","hashStringSha256","raw","subtle","enc","buf","bytes","hex","b","PredicateFromIntentError","message","attempts","errors","lastRawOutput","SYSTEM_PROMPT_HEADER","renderKindForPrompt","node","nullableTag","k","v","buildSystemPrompt","kindMap","factPath","lines","path","ops","getOperatorsForKind","buildErrorFeedback","intent","pathsToShow","e","shown","remaining","validateOneAttempt","rawOutput","opts","parsed","extractJsonFromOutput","err","validatePredicate","schemaResult","validatePredicateAgainstSchema","DEFAULT_MAX_RETRIES","DEFAULT_MAX_PREDICATE_BYTES","DEFAULT_MAX_OPERATOR_COUNT","DEFAULT_MAX_ARRAY_OPERAND_LENGTH","predicateFromIntent","result","predicateFromIntentRaw","rawIntent","schema","runner","agent","maxRetries","maxPredicateBytes","maxOperatorCount","maxArrayOperandLength","redact","signal","getSchemaFieldKinds","systemPrompt","baseAgent","promptAgent","attempt","validateOpts","input","runResult","validated","buildSchemaSummary","buildDescription","summary","override","predicateToolSpecOpenAI","name","description","predicateToolSpecAnthropic","predicateToolSpec","predicateFromIntentWithProvenance","sanitizedIntent","model","predicateHashValue","predicateHash","intentHash","provenance"],"mappings":"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","file":"chunk-MDXDPECP.cjs","sourcesContent":["/**\n * predicateFromIntent — let an LLM emit a typed FactPredicate as JSON,\n * structurally + semantically validated before it ever reaches your\n * constraint engine.\n *\n * Pipeline per call attempt:\n *\n * 1. Output-size check (reject before JSON.parse for DoS guard)\n * 2. JSON.parse via extractJsonFromOutput (handles surrounding prose)\n * 3. validatePredicate (structural: closed operator set, depth, JSON safety)\n * 4. Operator-count check\n * 5. validatePredicateAgainstSchema (semantic: operator-on-kind matrix)\n *\n * On any failure: a structured error message — including the offending\n * clause's path, the allowed operators for that fact's kind, and the\n * original schema kinds — is fed back to the LLM in the next attempt.\n *\n * Returns the validated FactPredicate. Throws PredicateFromIntentError\n * on retry exhaustion. NEVER returns a partial / unvalidated predicate.\n */\n\nimport {\n type FactPredicate,\n type SchemaKindNode,\n type SchemaValidationError,\n getOperatorsForKind,\n getSchemaFieldKinds,\n predicateHash,\n validatePredicate,\n validatePredicateAgainstSchema,\n} from \"@directive-run/core\";\n\nimport { extractJsonFromOutput } from \"./structured-output.js\";\nimport type { AgentLike, AgentRunner } from \"./types.js\";\n\n// ============================================================================\n// Hashing helpers\n// ============================================================================\n//\n// Provenance hashing has two flavors:\n//\n// - `predicateHash(spec)` — synchronous djb2 of a stable-stringified\n// predicate. Imported from `@directive-run/core` (the supported,\n// semver-stable surface). Two semantically-identical predicates emitted\n// with different whitespace / key-order produce the same hash. (N3)\n//\n// - `hashStringSha256(str)` — async SHA-256 via crypto.subtle when\n// available, djb2 fallback otherwise. Used for `intentHash` —\n// intents are free-form strings, no canonicalization to do.\n//\n\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\n }\n\n return (hash >>> 0).toString(16);\n}\n\nasync function hashStringSha256(raw: string): Promise<string> {\n // Prefer crypto.subtle SHA-256 when available (browsers, Node 19+, workers).\n // Fall back to a sync djb2 — collision-prone, but adequate for telemetry\n // alongside the persisted predicate.\n try {\n const subtle = (globalThis as { crypto?: { subtle?: SubtleCrypto } }).crypto\n ?.subtle;\n if (subtle && typeof subtle.digest === \"function\") {\n const enc = new TextEncoder();\n const buf = await subtle.digest(\"SHA-256\", enc.encode(raw));\n const bytes = new Uint8Array(buf);\n let hex = \"\";\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\");\n }\n\n return hex;\n }\n } catch {\n // fall through to djb2\n }\n\n return djb2Hash(raw);\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PredicateFromIntentOptions<_F = Record<string, unknown>> {\n /** Natural-language intent (untrusted user input — sanitize via `redact`). */\n intent: string;\n /**\n * Module schema (must expose builders with `_typeName` or `_kind`).\n * Pass either `{ facts: {...} }` or a bare `Record<string, builder>`.\n */\n schema: unknown;\n /** AgentRunner from `@directive-run/ai` adapters (createOpenAIRunner, etc.). */\n runner: AgentRunner;\n /**\n * Optional agent override. Default is `{ name: \"predicate-emitter\" }`\n * with our system prompt; pass `instructions` to append additional\n * context.\n */\n agent?: AgentLike;\n /**\n * Optional dotted-path namespace; useful for cross-module systems\n * where the LLM should emit a predicate over `auth.token` (default:\n * the schema's root facts).\n */\n factPath?: string;\n /** Max retries on validation failure. Default 3. */\n maxRetries?: number;\n /**\n * Hard byte cap on the LLM's raw output, BEFORE JSON.parse. Defaults\n * to 64 KiB. A larger predicate is rejected outright; protects\n * against multi-MB-payload DoS where the predicate is technically\n * structurally valid.\n */\n maxPredicateBytes?: number;\n /**\n * Hard cap on the number of operator clauses in the predicate.\n * Defaults to 256. Protects against `{ $any: [{ x: 1 }, … x100,000 ] }`\n * style operator-count exhaustion.\n */\n maxOperatorCount?: number;\n /**\n * Optional sanitizer applied to `intent` BEFORE it lands in the\n * system prompt. Useful for stripping or redacting user-controlled\n * content that looks like prompt-injection.\n */\n redact?: (intent: string) => string;\n /**\n * Hard cap on the length of each `$in` / `$nin` array operand the LLM\n * may emit. Defaults to 1000. Forwarded to\n * `validatePredicateAgainstSchema`'s `maxArrayOperandLength`.\n */\n maxArrayOperandLength?: number;\n /**\n * Optional `AbortSignal` for cooperative cancellation. (N6)\n *\n * The retry loop checks `signal.aborted` between attempts AND forwards\n * the signal into the runner call itself (`runner(agent, input, { signal })`).\n * Whether the in-flight LLM call honors the signal depends on the runner:\n * fetch-based adapters (the bundled OpenAI / Anthropic / Ollama runners)\n * thread it through to `fetch`, so the network call aborts mid-stream.\n * A custom runner that ignores the signal still delivers cancellation\n * at the next retry boundary.\n *\n * On abort: throws `Error(\"aborted\")`.\n *\n * NOTE: `predicateFromIntent` does NOT limit in-flight calls — callers\n * MUST wrap with a concurrency limiter (e.g. `p-limit`) to bound\n * fan-out under load.\n */\n signal?: AbortSignal;\n /**\n * When `true`, the {@link PredicateFromIntentProvenance} returned by\n * `predicateFromIntentWithProvenance` omits the raw `intent` string and\n * stores only the SHA-256 `intentHash`. Use this in PII-sensitive\n * contexts where the original intent must not be persisted. (M6)\n *\n * **Default `false` for back-compat.** For PII-sensitive deployments,\n * ALWAYS set `redactIntent: true` — the raw intent may contain\n * user-supplied content (names, emails, medical or financial details,\n * customer messages) that becomes a permanent record in\n * `provenance.intent`. The default is opt-in only because flipping it\n * now would silently strip diagnostic data from existing callers; v2\n * may flip this default (tracked in IDEAS.md).\n *\n * Pair with a `redact:` sanitizer when the intent itself must be\n * scrubbed BEFORE it lands in the LLM prompt — `redactIntent` controls\n * only what enters the provenance record, not what the LLM sees.\n */\n redactIntent?: boolean;\n}\n\nexport interface PredicateFromIntentDiagnostics<F = Record<string, unknown>> {\n /** The validated predicate (`null` if all retries failed). */\n predicate: FactPredicate<F> | null;\n /** Number of LLM calls actually made. */\n attempts: number;\n /** Errors encountered across all attempts (most recent last). */\n errors: ReadonlyArray<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }>;\n /** The raw LLM output from the final attempt — useful for debugging. */\n lastRawOutput?: string;\n}\n\n/** Thrown by `predicateFromIntent` on retry exhaustion. `predicateFromIntentRaw` returns these as a diagnostics payload instead. */\nexport class PredicateFromIntentError extends Error {\n override readonly name = \"PredicateFromIntentError\";\n constructor(\n message: string,\n public readonly attempts: number,\n public readonly errors: ReadonlyArray<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }>,\n public readonly lastRawOutput: string | undefined,\n ) {\n super(message);\n }\n}\n\n// ============================================================================\n// Prompt builder\n// ============================================================================\n\nconst SYSTEM_PROMPT_HEADER = `You emit ONLY a JSON object describing a Directive FactPredicate — no prose, no markdown fences, no explanation.\n\nA FactPredicate is a JSON tree of fact paths and operators:\n- Object form (preferred): { \"factName\": { \"$op\": operand }, \"otherFact\": { \"$op\": operand } }\n- Combinators: { \"$all\": [predicateA, predicateB] }, { \"$any\": [...] }, { \"$not\": predicate }\n- Bare value (equality shortcut): { \"factName\": value }\n\nOperator set (CLOSED — only these are valid):\n $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $between,\n $matches, $startsWith, $endsWith, $contains, $changed\nCombinators: $all, $any, $not\n\nEach operator is only valid for certain kinds (see below). Emit ONLY operators valid for the fact's kind.\n`;\n\nfunction renderKindForPrompt(node: SchemaKindNode): string {\n const nullableTag = node.nullable ? \" (nullable)\" : \"\";\n switch (node.kind) {\n case \"literal\":\n return `literal ${JSON.stringify(node.value)} (${node.primitive})${nullableTag}`;\n case \"enum\":\n return `enum ${JSON.stringify(node.values)} (${node.primitive})${nullableTag}`;\n case \"array\":\n return `array of ${renderKindForPrompt(node.element)}${nullableTag}`;\n case \"tuple\":\n return `tuple [${node.elements.map(renderKindForPrompt).join(\", \")}]${nullableTag}`;\n case \"object\":\n return `object { ${Object.entries(node.shape)\n .map(([k, v]) => `${k}: ${renderKindForPrompt(v)}`)\n .join(\", \")} }${nullableTag}`;\n case \"record\":\n return `record<string, ${renderKindForPrompt(node.value)}>${nullableTag}`;\n case \"union\":\n return `union (${node.members.map(renderKindForPrompt).join(\" | \")})${nullableTag}`;\n case \"branded\":\n return `branded(${renderKindForPrompt(node.inner)})${nullableTag}`;\n default:\n return `${node.kind}${nullableTag}`;\n }\n}\n\nfunction buildSystemPrompt(\n kindMap: Map<string, SchemaKindNode>,\n factPath?: string,\n): string {\n const lines: string[] = [SYSTEM_PROMPT_HEADER];\n\n lines.push(\"\\nFacts in this schema (path → kind → allowed operators):\");\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(\n ` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`,\n );\n }\n if (factPath) {\n lines.push(\n `\\nThe user intent will be over the namespace \"${factPath}\". Use only facts at or below that path.`,\n );\n }\n\n lines.push(\n '\\nRespond with ONLY the JSON predicate object. No prose. No markdown fences. No \"Here is...\".',\n );\n\n return lines.join(\"\\n\");\n}\n\nfunction buildErrorFeedback(\n intent: string,\n kindMap: Map<string, SchemaKindNode>,\n errors: readonly SchemaValidationError[] | string,\n): string {\n const lines: string[] = [];\n lines.push(\n \"Your previous response was rejected. Original intent (still applies):\",\n );\n lines.push(` ${intent}`);\n\n // M16: When we have structured errors, scope the schema reminder to only\n // the offending fact paths instead of dumping the full schema. Falls back\n // to the full schema for non-structural failures (string errors).\n let pathsToShow: Set<string> | null = null;\n\n if (typeof errors === \"string\") {\n lines.push(`\\nReason: ${errors}`);\n } else {\n lines.push(\"\\nValidation errors (fix every one):\");\n pathsToShow = new Set();\n for (const e of errors) {\n lines.push(` - path \"${e.path}\", op \"${e.op}\": ${e.reason}`);\n if (e.allowedOps && e.allowedOps.length > 0) {\n lines.push(\n ` → allowed operators for this fact: ${e.allowedOps.join(\", \")}`,\n );\n }\n // Collect every path mentioned by an error. If a path isn't in the\n // kindMap (unknown fact), the offending key may be a dotted prefix of\n // a real fact — include the closest known ancestor too.\n pathsToShow.add(e.path);\n }\n }\n\n lines.push(\"\\nSchema reminder:\");\n if (pathsToShow && pathsToShow.size > 0) {\n let shown = 0;\n for (const path of pathsToShow) {\n const node = kindMap.get(path);\n if (node) {\n const ops = getOperatorsForKind(node);\n lines.push(\n ` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`,\n );\n shown++;\n } else {\n lines.push(\n ` ${path}: (not in schema — pick from the available facts below)`,\n );\n }\n }\n const remaining = kindMap.size - shown;\n if (remaining > 0) {\n lines.push(\n ` …and ${remaining} more fact(s) available — ask if you need the full list.`,\n );\n }\n } else {\n for (const [path, node] of kindMap.entries()) {\n const ops = getOperatorsForKind(node);\n lines.push(\n ` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`,\n );\n }\n }\n\n lines.push(\"\\nEmit ONLY a corrected JSON FactPredicate object. No prose.\");\n\n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Validation pipeline (one attempt)\n// ============================================================================\n\nfunction validateOneAttempt(\n rawOutput: string,\n kindMap: Map<string, SchemaKindNode>,\n opts: {\n maxPredicateBytes: number;\n maxOperatorCount: number;\n maxArrayOperandLength: number;\n },\n):\n | { ok: true; predicate: unknown }\n | { ok: false; reason: string; details?: readonly SchemaValidationError[] } {\n // 1. Byte cap (pre-parse — kills 10MB-payload DoS)\n if (rawOutput.length > opts.maxPredicateBytes) {\n return {\n ok: false,\n reason: `Output exceeded maxPredicateBytes=${opts.maxPredicateBytes} (got ${rawOutput.length}). Emit a smaller predicate.`,\n };\n }\n\n // 2. JSON parse (handles surrounding prose)\n let parsed: unknown;\n try {\n parsed = extractJsonFromOutput(rawOutput);\n } catch (err) {\n return {\n ok: false,\n reason: `Could not extract JSON from output: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 3. Structural validation (closed operator set, depth, JSON-safety)\n try {\n validatePredicate(parsed);\n } catch (err) {\n return {\n ok: false,\n reason: `Structural validation failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 4 + 5. Operator-count cap + array-operand cap + schema validation\n const schemaResult = validatePredicateAgainstSchema(parsed, kindMap, {\n maxOperatorCount: opts.maxOperatorCount,\n maxArrayOperandLength: opts.maxArrayOperandLength,\n });\n\n if (!schemaResult.ok) {\n return {\n ok: false,\n reason: `Predicate has ${schemaResult.errors.length} schema-validation error(s).`,\n details: schemaResult.errors,\n };\n }\n\n return { ok: true, predicate: parsed };\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_MAX_PREDICATE_BYTES = 65_536; // 64 KiB\nconst DEFAULT_MAX_OPERATOR_COUNT = 256;\nconst DEFAULT_MAX_ARRAY_OPERAND_LENGTH = 1000;\n\n/**\n * Ask an LLM to emit a FactPredicate matching the user's intent, then\n * validate it structurally + semantically before returning. On validation\n * failure, retries with structured error feedback in the next prompt.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion. NEVER\n * returns a partial / unvalidated predicate.\n *\n * **Rate limiting:** this function does NOT limit in-flight calls. Wrap\n * with a concurrency limiter (e.g. `p-limit` / `Bottleneck`) before\n * exposing it to user-driven traffic. Pass an `AbortSignal` via `opts.signal`\n * for cooperative cancellation between retry attempts.\n *\n * @example\n * ```ts\n * import { createOpenAIRunner } from \"@directive-run/ai/openai\";\n * import { predicateFromIntent } from \"@directive-run/ai\";\n *\n * const runner = createOpenAIRunner({ apiKey, model: \"gpt-4o-mini\" });\n *\n * const predicate = await predicateFromIntent({\n * intent: \"checkout is unblocked when the cart total is at least 50\",\n * schema: myModule.schema,\n * runner,\n * });\n * // → { cartTotal: { $gte: 50 } }\n * ```\n */\nexport async function predicateFromIntent<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<FactPredicate<F>> {\n const result = await predicateFromIntentRaw(opts);\n if (result.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntent: failed after ${result.attempts} attempt(s). Last error: ${\n result.errors[result.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n result.attempts,\n result.errors,\n result.lastRawOutput,\n );\n }\n\n return result.predicate;\n}\n\n/**\n * Lower-level variant — returns the validated predicate (or null) plus\n * full diagnostics. Use when you want to surface validation telemetry,\n * preview the LLM's last raw output, or display per-attempt errors in\n * a UI.\n */\nexport async function predicateFromIntentRaw<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentDiagnostics<F>> {\n const {\n intent: rawIntent,\n schema,\n runner,\n agent,\n factPath,\n maxRetries = DEFAULT_MAX_RETRIES,\n maxPredicateBytes = DEFAULT_MAX_PREDICATE_BYTES,\n maxOperatorCount = DEFAULT_MAX_OPERATOR_COUNT,\n maxArrayOperandLength = DEFAULT_MAX_ARRAY_OPERAND_LENGTH,\n redact,\n signal,\n } = opts;\n\n if (typeof rawIntent !== \"string\" || rawIntent.length === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: `intent` must be a non-empty string.\",\n );\n }\n\n const intent = redact ? redact(rawIntent) : rawIntent;\n const kindMap = getSchemaFieldKinds(schema);\n\n if (kindMap.size === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: schema has no introspectable facts. Pass a module schema or a bare facts record.\",\n );\n }\n\n const systemPrompt = buildSystemPrompt(kindMap, factPath);\n const baseAgent: AgentLike = agent ?? { name: \"predicate-emitter\" };\n const promptAgent: AgentLike = {\n ...baseAgent,\n instructions: `${baseAgent.instructions ?? \"\"}\\n\\n${systemPrompt}`.trim(),\n };\n\n const errors: Array<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }> = [];\n\n let lastRawOutput: string | undefined;\n let attempt = 0;\n const validateOpts = {\n maxPredicateBytes,\n maxOperatorCount,\n maxArrayOperandLength,\n };\n\n while (attempt < maxRetries + 1) {\n // M7: cooperative cancellation — bail between attempts when aborted.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n attempt++;\n const input =\n attempt === 1\n ? `Intent: ${intent}\\n\\nEmit the predicate now.`\n : buildErrorFeedback(\n intent,\n kindMap,\n errors[errors.length - 1]!.details ??\n errors[errors.length - 1]!.reason,\n );\n\n let runResult: Awaited<ReturnType<typeof runner>>;\n try {\n // (N6) Forward the abort signal to the runner so in-flight LLM\n // calls can be cancelled mid-fetch. fetch-based adapters honor\n // this via the underlying fetch's `signal` option. Custom runners\n // that ignore the third arg fall back to between-retry cancellation.\n runResult = await runner(promptAgent, input, { signal });\n } catch (err) {\n // If the abort happened during the in-flight call (and the runner\n // honored it), surface that as a plain `Error(\"aborted\")` rather\n // than burning a retry attempt on a cancellation error.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n errors.push({\n attempt,\n reason: `LLM runner threw: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n\n const rawOutput =\n typeof runResult.output === \"string\"\n ? runResult.output\n : JSON.stringify(runResult.output);\n lastRawOutput = rawOutput;\n\n const validated = validateOneAttempt(rawOutput, kindMap, validateOpts);\n\n if (validated.ok) {\n return {\n predicate: validated.predicate as FactPredicate<F>,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n }\n\n errors.push({\n attempt,\n reason: validated.reason,\n details: validated.details,\n });\n }\n\n return {\n predicate: null,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n}\n\n// ============================================================================\n// Tool-spec presets (OpenAI + Anthropic function-calling)\n// ============================================================================\n\nexport interface PredicateToolSpecOptions {\n /** Tool name. Default `\"emit_predicate\"`. */\n name?: string;\n /** Tool description. Default: a one-liner describing predicate emission. */\n description?: string;\n /** Optional dotted-path namespace to restrict the tool's scope. */\n factPath?: string;\n}\n\n/**\n * Anthropic Messages API tool shape. Drop into the `tools: [...]` array.\n * Anthropic's API expects `input_schema` at the top level of the tool.\n */\nexport interface PredicateToolSpecAnthropic {\n name: string;\n description: string;\n input_schema: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool shape. Drop into the\n * `tools: [...]` array. OpenAI nests the function payload under\n * `function: { name, description, parameters }`.\n */\nexport interface PredicateToolSpecOpenAI {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * @deprecated Use {@link PredicateToolSpecAnthropic} (or\n * {@link PredicateToolSpecOpenAI}) directly. Kept as an alias for the\n * pre-split shape that v1.12.x callers depend on; identical to\n * `PredicateToolSpecAnthropic`.\n */\nexport type PredicateToolSpec = PredicateToolSpecAnthropic;\n\nfunction buildSchemaSummary(\n schema: unknown,\n factPath: string | undefined,\n): string {\n const kindMap = getSchemaFieldKinds(schema);\n const lines: string[] = [];\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(\n `${path}: ${renderKindForPrompt(node)} — ops: ${ops.join(\", \")}`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction buildDescription(summary: string, override?: string): string {\n return (\n override ??\n `Emit a Directive FactPredicate (JSON tree of facts and operators) matching the user's intent. Schema:\\n${summary}`\n );\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool spec for predicate\n * emission. Drop the result into your `tools: [...]` array; the model\n * will be told to emit a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecOpenAI(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await openai.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecOpenAI(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecOpenAI {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n type: \"function\",\n function: {\n name,\n description,\n parameters: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * Anthropic Messages API tool spec for predicate emission. Drop the\n * result into your `tools: [...]` array; the model will be told to emit\n * a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecAnthropic(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await anthropic.messages.create({\n * model: \"claude-3-5-sonnet-latest\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecAnthropic(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecAnthropic {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n name,\n description,\n input_schema: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * @deprecated Use {@link predicateToolSpecAnthropic} (or\n * {@link predicateToolSpecOpenAI}) directly. Back-compat alias for\n * v1.12.x callers — emits the Anthropic shape, unchanged.\n */\nexport function predicateToolSpec(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpec {\n return predicateToolSpecAnthropic(schema, opts);\n}\n\n// ============================================================================\n// Provenance (M24)\n// ============================================================================\n\nexport interface PredicateFromIntentProvenance {\n /**\n * Resolved model name when the caller passes `agent: { model }`,\n * otherwise `\"unknown\"`.\n *\n * NOTE: most callers omit `agent` (the default `predicate-emitter`\n * agent has no model field set), so `model` is `\"unknown\"` by default.\n * v1 does NOT read provider-detected model strings from `RunResult` —\n * that requires every adapter to surface `runResult.model`, which the\n * current `AgentRunner` contract does not. Tracked for v2; callers who\n * need provider attribution today should pass `agent: { name, model: \"...\" }`.\n */\n readonly model: string;\n /**\n * Sanitized intent string actually sent to the LLM (post-redact). When\n * `redactIntent: true` was passed, this field is omitted entirely — only\n * `intentHash` is populated.\n */\n readonly intent?: string;\n /**\n * SHA-256 hex hash of the sanitized intent string (or djb2 fallback\n * when `crypto.subtle` is unavailable). Always present — even when\n * `intent` is omitted via `redactIntent`. (M6)\n */\n readonly intentHash: string;\n /** Number of LLM calls that ran before the final predicate was accepted. */\n readonly attemptCount: number;\n /** ISO timestamp when the predicate was returned. */\n readonly emittedAt: string;\n /**\n * Hash of the VALIDATED predicate (canonicalized via stableStringify\n * before hashing). Two semantically-identical predicates emitted with\n * different whitespace or key order produce the SAME `predicateHash`.\n * Sufficient as a tamper-evident pointer alongside the persisted\n * predicate. (N3)\n *\n * Renamed from `rawOutputHash` in v1.13.x — the old name hashed the\n * raw LLM output string, which made two whitespace-different responses\n * for the same logical predicate hash differently. Callers persisting\n * the old `rawOutputHash` value should re-derive it from the stored\n * predicate using `hashObject(predicate)` from `@directive-run/core/internals`.\n */\n readonly predicateHash: string;\n}\n\nexport interface PredicateFromIntentWithProvenanceResult<\n F = Record<string, unknown>,\n> {\n readonly predicate: FactPredicate<F>;\n readonly provenance: PredicateFromIntentProvenance;\n}\n\n/**\n * Like {@link predicateFromIntent} but additionally returns a structured\n * provenance record — the model name, sanitized intent (or its hash),\n * attempt count, timestamp, and a canonical hash of the validated\n * predicate.\n *\n * **Production deployments MUST persist the provenance record alongside\n * the predicate.** Without it, auditing \"where did this rule come from?\"\n * becomes guesswork.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion — same\n * semantics as the un-provenanced variant.\n *\n * **PII guidance (M6):** pass `redactIntent: true` to omit the raw\n * intent from the provenance record and persist only the `intentHash`.\n * Useful when the intent itself is sensitive (medical, financial,\n * customer messages, etc.).\n *\n * **Hash semantics (N3):**\n * - `predicateHash` hashes the VALIDATED predicate object via stable\n * stringification — two whitespace-different LLM outputs that parse to\n * the same predicate produce the same hash.\n * - `intentHash` hashes the sanitized intent STRING (SHA-256 when\n * available, djb2 fallback).\n *\n * @example\n * ```ts\n * const { predicate, provenance } = await predicateFromIntentWithProvenance({\n * intent: \"block checkout when cart > 10k\",\n * schema: checkoutModule.schema,\n * runner,\n * agent: { name: \"predicate-emitter\", model: \"gpt-4o-mini\" },\n * redactIntent: false, // default: store both intent + intentHash\n * });\n *\n * await db.predicates.insert({\n * predicate,\n * model: provenance.model,\n * intent: provenance.intent, // omitted when redactIntent: true\n * intentHash: provenance.intentHash,\n * emittedAt: provenance.emittedAt,\n * predicateHash: provenance.predicateHash,\n * attempts: provenance.attemptCount,\n * });\n * ```\n */\nexport async function predicateFromIntentWithProvenance<\n F = Record<string, unknown>,\n>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentWithProvenanceResult<F>> {\n const raw = await predicateFromIntentRaw(opts);\n if (raw.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntentWithProvenance: failed after ${raw.attempts} attempt(s). Last error: ${\n raw.errors[raw.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n raw.attempts,\n raw.errors,\n raw.lastRawOutput,\n );\n }\n\n const sanitizedIntent = opts.redact ? opts.redact(opts.intent) : opts.intent;\n const model = opts.agent?.model ?? \"unknown\";\n // (N3) Hash the VALIDATED predicate (stable canonical form), not the\n // raw LLM output — two semantically-identical responses with different\n // whitespace / key order produce the same hash. Uses the supported\n // public `predicateHash` helper from `@directive-run/core`.\n const predicateHashValue = predicateHash(raw.predicate);\n // (M6) Always hash the intent; raw intent string is included only when\n // `redactIntent` is not set.\n const intentHash = await hashStringSha256(sanitizedIntent);\n\n const provenance: PredicateFromIntentProvenance = opts.redactIntent\n ? {\n model,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n }\n : {\n model,\n intent: sanitizedIntent,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n };\n\n return {\n predicate: raw.predicate,\n provenance,\n };\n}\n"]}
|