@directive-run/ai 1.13.0 → 1.14.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/dist/anthropic.d.cts +1 -1
- package/dist/anthropic.d.ts +1 -1
- package/dist/{chunk-XV2QSBBE.cjs → chunk-2TD4ZSGZ.cjs} +7 -7
- package/dist/{chunk-XV2QSBBE.cjs.map → chunk-2TD4ZSGZ.cjs.map} +1 -1
- package/dist/chunk-5JQ2A3JK.js +2 -0
- package/dist/chunk-5JQ2A3JK.js.map +1 -0
- package/dist/chunk-A22KLB23.cjs +67 -0
- package/dist/chunk-A22KLB23.cjs.map +1 -0
- package/dist/chunk-A5K77UDX.cjs +4 -0
- package/dist/chunk-A5K77UDX.cjs.map +1 -0
- package/dist/chunk-DN5NAJM6.js +6 -0
- package/dist/chunk-DN5NAJM6.js.map +1 -0
- package/dist/chunk-FABDFT74.cjs +6 -0
- package/dist/chunk-FABDFT74.cjs.map +1 -0
- package/dist/chunk-FBT73WFY.js +2 -0
- package/dist/chunk-FBT73WFY.js.map +1 -0
- package/dist/chunk-FFRWQNK7.cjs +7 -0
- package/dist/chunk-FFRWQNK7.cjs.map +1 -0
- package/dist/chunk-IR3IHBVQ.cjs +2 -0
- package/dist/chunk-IR3IHBVQ.cjs.map +1 -0
- package/dist/chunk-IUGSMTBE.js +16 -0
- package/dist/{chunk-Q3PQLWBR.js.map → chunk-IUGSMTBE.js.map} +1 -1
- package/dist/chunk-J2Q5KKPN.js +37 -0
- package/dist/chunk-J2Q5KKPN.js.map +1 -0
- package/dist/chunk-K64WKZ22.cjs +2 -0
- package/dist/chunk-K64WKZ22.cjs.map +1 -0
- package/dist/chunk-LKY4K5TV.cjs +11 -0
- package/dist/chunk-LKY4K5TV.cjs.map +1 -0
- package/dist/chunk-LXUMJKGJ.js +67 -0
- package/dist/chunk-LXUMJKGJ.js.map +1 -0
- package/dist/chunk-NNAQ4ZH2.js +11 -0
- package/dist/chunk-NNAQ4ZH2.js.map +1 -0
- package/dist/chunk-PD772MSE.cjs +30 -0
- package/dist/chunk-PD772MSE.cjs.map +1 -0
- package/dist/chunk-POBEEJR6.js +30 -0
- package/dist/chunk-POBEEJR6.js.map +1 -0
- package/dist/chunk-QRXWLD6H.js +4 -0
- package/dist/chunk-QRXWLD6H.js.map +1 -0
- package/dist/chunk-UR4ZGO7V.js +7 -0
- package/dist/chunk-UR4ZGO7V.js.map +1 -0
- package/dist/chunk-UR5BMWEN.js +2 -0
- package/dist/chunk-UR5BMWEN.js.map +1 -0
- package/dist/chunk-WOFIBIPW.cjs +2 -0
- package/dist/chunk-WOFIBIPW.cjs.map +1 -0
- package/dist/chunk-XN5LUOVS.cjs +37 -0
- package/dist/chunk-XN5LUOVS.cjs.map +1 -0
- package/dist/debug-timeline-DpnRMnLU.d.cts +87 -0
- package/dist/debug-timeline-L13P-U2I.d.ts +87 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +354 -0
- package/dist/devtools.d.ts +354 -0
- package/dist/devtools.js +2 -0
- package/dist/devtools.js.map +1 -0
- package/dist/evals.cjs +2 -0
- package/dist/evals.cjs.map +1 -0
- package/dist/evals.d.cts +361 -0
- package/dist/evals.d.ts +361 -0
- package/dist/evals.js +2 -0
- package/dist/evals.js.map +1 -0
- package/dist/gemini.d.cts +1 -1
- package/dist/gemini.d.ts +1 -1
- package/dist/guardrails.cjs +2 -0
- package/dist/guardrails.cjs.map +1 -0
- package/dist/guardrails.d.cts +618 -0
- package/dist/guardrails.d.ts +618 -0
- package/dist/guardrails.js +2 -0
- package/dist/guardrails.js.map +1 -0
- package/dist/health-monitor-C6xoXrQz.d.cts +55 -0
- package/dist/health-monitor-qL9RNMH3.d.ts +55 -0
- package/dist/index.cjs +21 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1197 -4735
- package/dist/index.d.ts +1197 -4735
- package/dist/index.js +21 -99
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +2 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +450 -0
- package/dist/mcp.d.ts +450 -0
- package/dist/mcp.js +2 -0
- package/dist/mcp.js.map +1 -0
- package/dist/multi-agent-orchestrator-QWWQKKGX.js +2 -0
- package/dist/{multi-agent-orchestrator-4PXNYRHB.js.map → multi-agent-orchestrator-QWWQKKGX.js.map} +1 -1
- package/dist/multi-agent-orchestrator-Y5U4JCFO.cjs +2 -0
- package/dist/{multi-agent-orchestrator-KFGTEGE5.cjs.map → multi-agent-orchestrator-Y5U4JCFO.cjs.map} +1 -1
- package/dist/multi-agent.cjs +2 -0
- package/dist/multi-agent.cjs.map +1 -0
- package/dist/multi-agent.d.cts +1429 -0
- package/dist/multi-agent.d.ts +1429 -0
- package/dist/multi-agent.js +2 -0
- package/dist/multi-agent.js.map +1 -0
- package/dist/ollama.d.cts +1 -1
- package/dist/ollama.d.ts +1 -1
- package/dist/openai.d.cts +2 -2
- package/dist/openai.d.ts +2 -2
- package/dist/{orchestrator-types-CTfIKk0W.d.ts → orchestrator-types-DGBhL6mc.d.ts} +5 -138
- package/dist/{orchestrator-types-Bh8r3_Sq.d.cts → orchestrator-types-DeIMRLR7.d.cts} +5 -138
- package/dist/predicate.cjs +2 -0
- package/dist/predicate.cjs.map +1 -0
- package/dist/predicate.d.cts +371 -0
- package/dist/predicate.d.ts +371 -0
- package/dist/predicate.js +2 -0
- package/dist/predicate.js.map +1 -0
- package/dist/{semantic-cache-nBpQqILc.d.cts → semantic-cache-DM7ev7NQ.d.cts} +1 -1
- package/dist/{semantic-cache-nBpQqILc.d.ts → semantic-cache-DM7ev7NQ.d.ts} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -2
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/{types-CRmwFnVk.d.cts → types-DJ09LjZX.d.cts} +1 -1
- package/dist/{types-CRmwFnVk.d.ts → types-DJ09LjZX.d.ts} +1 -1
- package/package.json +32 -2
- package/dist/chunk-Q3PQLWBR.js +0 -16
- package/dist/chunk-RW4R3O5P.js +0 -72
- package/dist/chunk-RW4R3O5P.js.map +0 -1
- package/dist/chunk-X3VQ5F7D.cjs +0 -72
- package/dist/chunk-X3VQ5F7D.cjs.map +0 -1
- package/dist/multi-agent-orchestrator-4PXNYRHB.js +0 -2
- package/dist/multi-agent-orchestrator-KFGTEGE5.cjs +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/builtin-guardrails.ts","../src/guardrails/pii-enhanced.ts","../src/guardrails/prompt-injection.ts","../src/guardrails/semantic-cache.ts","../src/guardrails/ann-index.ts"],"names":["createPIIGuardrail","options","patterns","redact","redactReplacement","data","text","hasPII","pattern","createModerationGuardrail","checkFn","message","flagged","createRateLimitGuardrail","maxTokensPerMinute","maxRequestsPerMinute","maxEntries","tokenTimestamps","requestTimestamps","windowMs","findCutoffIndex","arr","cutoffTime","low","high","mid","guardrail","_data","context","now","tokenCutoff","requestCutoff","tokenUsage","AGENT_KEY","recentTokens","recentRequests","createToolGuardrail","allowlist","denylist","caseSensitive","normalizedAllowlist","t","normalizedDenylist","toolName","createOutputSchemaGuardrail","validate","errorPrefix","result","createOutputTypeGuardrail","type","requiredFields","minLength","maxLength","minStringLength","maxStringLength","output","field","createLengthGuardrail","maxCharacters","maxTokens","estimateTokens","safeStringify","tokens","createContentFilterGuardrail","blockedPatterns","compiledPatterns","p","escaped","PII_PATTERNS","match","digits","sum","isEven","i","char","digit","octets","a","b","detectAddresses","results","streetTypes","addressPattern","NAME_PREFIXES","detectNames","prefixPattern","nameRegex","name","prefix","MAX_PII_INPUT_LENGTH","matchPattern","regex","group","value","start","end","regexDetector","types","typeSet","SENSITIVE_CATEGORY_TYPES","hasValidSpan","item","textLength","buildRedactionReplacement","style","fnv1aHash","redactPII","items","byPriority","aSpan","bSpan","kept","k","sorted","replacement","str","hash","DEFAULT_PII_TYPES","createEnhancedPIIGuardrail","detector","redactionStyle","minConfidence","onDetected","minItemsToBlock","detectorTimeout","detectorInstance","allowSet","v","detectWithTimeout","piiTypes","timer","detectPromise","timeoutPromise","_","reject","filtered","typeCounts","count","createOutputPIIGuardrail","inputGuardrail","detectPII","timeout","detectAndRedactPII","DEFAULT_INJECTION_PATTERNS","STRICT_INJECTION_PATTERNS","MAX_INJECTION_INPUT_LENGTH","detectPromptInjection","matches","severity","category","severityScores","totalScore","m","riskScore","sanitizeInjection","sanitized","allPatterns","hasGlobal","hasIgnoreCase","hasMultiline","flags","combinedRegex","createPromptInjectionGuardrail","additionalPatterns","replacePatterns","strictMode","blockThreshold","sanitize","onBlocked","ignoreCategories","ignoredSet","topPatterns","order","markUntrustedContent","content","source","createUntrustedContentGuardrail","baseGuardrail","untrustedMarkerRegex","fullResult","strictResult","cosineSimilarity","dotProduct","normA","normB","ai","bi","findSimilar","queryEmbedding","entries","threshold","agentName","bestMatch","entry","similarity","createInMemoryStorage","storage","getNamespace","namespace","ns","id","updates","createSemanticCache","config","embedder","similarityThreshold","maxCacheSize","ttlMs","onHit","onMiss","onError","perAgent","stats","totalSimilaritySum","updateStats","times","e","evictExpiredAndExcess","remainingEntries","toRemove","query","error","response","metadata","predicate","removed","allEntries","createSemanticCacheGuardrail","cache","createTestEmbedder","dimensions","embedding","charCode","norm","val","createBatchedEmbedder","batchSize","embedBatch","maxWaitMs","pendingBatch","batchTimer","isDestroyed","flushBatch","batch","texts","embeddings","err","resolve","createBruteForceIndex","vectors","expectedDimension","validateDimension","cosineDistance","buildVPTree","random","vpIdx","vp","rest","distances","medianIdx","mu","leftItems","d","rightItems","searchVPTree","node","maxDist","dist","createVPTreeIndex","vpConfig","root","needsRebuild","itemArray"],"mappings":"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","file":"chunk-QRXWLD6H.js","sourcesContent":["/**\n * Built-in guardrails for AI adapter — PII, moderation, rate limiting, tool allowlists, schema validation.\n */\n\nimport type {\n AgentState,\n GuardrailFn,\n InputGuardrailData,\n OutputGuardrailData,\n SchemaValidator,\n ToolCallGuardrailData,\n} from \"./types.js\";\nimport { AGENT_KEY } from \"./types.js\";\n\nimport { safeStringify } from \"@directive-run/core/internals\";\n\n// ============================================================================\n// PII Guardrail\n// ============================================================================\n\n/**\n * Create a PII detection guardrail that scans input text for personally identifiable\n * information. Blocks input when PII is detected, or optionally redacts matches and\n * passes the sanitized text through.\n *\n * @param options - Configuration for PII detection: `patterns` sets the RegExp list (defaults to SSN, credit card, email), `redact` replaces matches instead of blocking, `redactReplacement` sets the replacement string (defaults to `\"[REDACTED]\"`).\n * @returns An input guardrail that blocks or redacts PII in user input.\n *\n * @example\n * ```typescript\n * const piiGuardrail = createPIIGuardrail({\n * patterns: [\n * /\\b\\d{3}-\\d{2}-\\d{4}\\b/, // SSN\n * /\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/i, // Email\n * ],\n * redact: true,\n * });\n * ```\n *\n * @public\n */\nexport function createPIIGuardrail(options: {\n patterns?: RegExp[];\n redact?: boolean;\n redactReplacement?: string;\n}): GuardrailFn<InputGuardrailData> {\n const {\n patterns = [\n /\\b\\d{3}-\\d{2}-\\d{4}\\b/g, // SSN\n /\\b\\d{16}\\b/g, // Credit card\n /\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi, // Email\n ],\n redact = false,\n redactReplacement = \"[REDACTED]\",\n } = options;\n\n return (data) => {\n let text = data.input;\n let hasPII = false;\n\n for (const pattern of patterns) {\n pattern.lastIndex = 0;\n if (pattern.test(text)) {\n hasPII = true;\n if (redact) {\n pattern.lastIndex = 0;\n text = text.replace(pattern, redactReplacement);\n }\n }\n }\n\n if (hasPII && !redact) {\n return { passed: false, reason: \"Input contains PII\" };\n }\n\n return { passed: true, transformed: redact && hasPII ? text : undefined };\n };\n}\n\n// ============================================================================\n// Moderation Guardrail\n// ============================================================================\n\n/**\n * Create a content moderation guardrail that delegates to a user-supplied check function.\n * Works on both input and output data — the guardrail extracts the text content\n * automatically and passes it to {@link options.checkFn}.\n *\n * @param options - Configuration for content moderation: `checkFn` returns `true` when content should be flagged (supports async), `message` sets the rejection reason (defaults to `\"Content flagged by moderation\"`).\n * @returns A guardrail that blocks content flagged by the check function.\n *\n * @example\n * ```typescript\n * const moderationGuardrail = createModerationGuardrail({\n * checkFn: async (text) => {\n * const result = await openai.moderations.create({ input: text });\n * return result.results[0].flagged;\n * },\n * });\n * ```\n *\n * @public\n */\nexport function createModerationGuardrail(options: {\n checkFn: (text: string) => boolean | Promise<boolean>;\n message?: string;\n}): GuardrailFn<InputGuardrailData | OutputGuardrailData> {\n const { checkFn, message = \"Content flagged by moderation\" } = options;\n\n return async (data) => {\n const text =\n \"output\" in data\n ? typeof data.output === \"string\"\n ? data.output\n : JSON.stringify(data.output)\n : data.input;\n\n const flagged = await checkFn(text);\n\n return { passed: !flagged, reason: flagged ? message : undefined };\n };\n}\n\n// ============================================================================\n// Rate Limit Guardrail\n// ============================================================================\n\n/** Rate limiter with reset capability for testing */\nexport interface RateLimitGuardrail extends GuardrailFn<InputGuardrailData> {\n reset(): void;\n}\n\n/**\n * Create a rate limit guardrail that tracks token and request counts over a sliding\n * one-minute window. Returns a {@link RateLimitGuardrail} — a guardrail function with\n * an additional `reset()` method for testing.\n *\n * @param options - Configuration for rate limiting: `maxTokensPerMinute` caps tokens in the sliding window (defaults to `100000`), `maxRequestsPerMinute` caps requests (defaults to `60`).\n * @returns A rate limit guardrail with an attached `reset()` method.\n *\n * @example\n * ```typescript\n * const rateLimiter = createRateLimitGuardrail({\n * maxTokensPerMinute: 50000,\n * maxRequestsPerMinute: 30,\n * });\n * ```\n *\n * @public\n */\nexport function createRateLimitGuardrail(options: {\n maxTokensPerMinute?: number;\n maxRequestsPerMinute?: number;\n}): RateLimitGuardrail {\n const { maxTokensPerMinute = 100000, maxRequestsPerMinute = 60 } = options;\n\n const maxEntries = Math.max(maxRequestsPerMinute, 1000);\n let tokenTimestamps: number[] = [];\n let requestTimestamps: number[] = [];\n const windowMs = 60000;\n\n function findCutoffIndex(arr: number[], cutoffTime: number): number {\n let low = 0;\n let high = arr.length;\n while (low < high) {\n const mid = (low + high) >>> 1;\n if ((arr[mid] ?? 0) < cutoffTime) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n return low;\n }\n\n const guardrail: RateLimitGuardrail = (_data, context) => {\n const now = Date.now();\n const cutoffTime = now - windowMs;\n\n const tokenCutoff = findCutoffIndex(tokenTimestamps, cutoffTime);\n if (tokenCutoff > 0) {\n tokenTimestamps = tokenTimestamps.slice(tokenCutoff);\n }\n\n const requestCutoff = findCutoffIndex(requestTimestamps, cutoffTime);\n if (requestCutoff > 0) {\n requestTimestamps = requestTimestamps.slice(requestCutoff);\n }\n\n const factsObj = context.facts as Record<string, unknown>;\n const agentState = factsObj[AGENT_KEY] as AgentState | undefined;\n const tokenUsage = agentState?.tokenUsage ?? 0;\n const recentTokens = tokenTimestamps.length;\n const recentRequests = requestTimestamps.length;\n\n if (recentTokens + tokenUsage > maxTokensPerMinute) {\n return { passed: false, reason: \"Token rate limit exceeded\" };\n }\n\n if (recentRequests >= maxRequestsPerMinute) {\n return { passed: false, reason: \"Request rate limit exceeded\" };\n }\n\n if (requestTimestamps.length < maxEntries) {\n requestTimestamps.push(now);\n }\n if (tokenTimestamps.length < maxEntries) {\n tokenTimestamps.push(now);\n }\n\n return { passed: true };\n };\n\n guardrail.reset = () => {\n tokenTimestamps = [];\n requestTimestamps = [];\n };\n\n return guardrail;\n}\n\n// ============================================================================\n// Tool Guardrail\n// ============================================================================\n\n/**\n * Create a tool-call guardrail that restricts which tools an agent may invoke.\n * Supports allowlist mode, denylist mode, or both — when both are provided, a tool\n * must appear in the allowlist and not appear in the denylist.\n *\n * @param options - Configuration for tool filtering: `allowlist` sets permitted tool names, `denylist` sets blocked tool names, `caseSensitive` controls case matching (defaults to `false`).\n * @returns A tool-call guardrail that enforces the allowlist/denylist rules.\n *\n * @example\n * ```typescript\n * const toolGuardrail = createToolGuardrail({\n * allowlist: [\"search\", \"calculate\"],\n * denylist: [\"delete_account\"],\n * });\n * ```\n *\n * @public\n */\nexport function createToolGuardrail(options: {\n allowlist?: string[];\n denylist?: string[];\n /** @default false */\n caseSensitive?: boolean;\n}): GuardrailFn<ToolCallGuardrailData> {\n const { allowlist, denylist, caseSensitive = false } = options;\n\n const normalizedAllowlist = allowlist?.map((t) =>\n caseSensitive ? t : t.toLowerCase(),\n );\n const normalizedDenylist = denylist?.map((t) =>\n caseSensitive ? t : t.toLowerCase(),\n );\n\n return (data) => {\n const toolName = caseSensitive\n ? data.toolCall.name\n : data.toolCall.name.toLowerCase();\n\n if (normalizedAllowlist && !normalizedAllowlist.includes(toolName)) {\n return {\n passed: false,\n reason: `Tool \"${data.toolCall.name}\" not in allowlist`,\n };\n }\n\n if (normalizedDenylist?.includes(toolName)) {\n return {\n passed: false,\n reason: `Tool \"${data.toolCall.name}\" is blocked`,\n };\n }\n\n return { passed: true };\n };\n}\n\n// ============================================================================\n// Output Schema Guardrail\n// ============================================================================\n\n/**\n * Create an output guardrail that validates agent output against a schema using\n * a user-supplied {@link SchemaValidator}. Compatible with any validation library\n * (Zod, Valibot, ArkType, etc.) via the adapter pattern.\n *\n * @param options - Configuration for schema validation: `validate` checks the output against the expected schema, `errorPrefix` is prepended to error messages (defaults to `\"Output schema validation failed\"`).\n * @returns An output guardrail that rejects output failing schema validation.\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n *\n * const schemaGuardrail = createOutputSchemaGuardrail({\n * validate: (value) => {\n * const result = z.object({ answer: z.string() }).safeParse(value);\n * return { valid: result.success, errors: result.error?.issues.map(i => i.message) };\n * },\n * });\n * ```\n *\n * @public\n */\nexport function createOutputSchemaGuardrail<T = unknown>(options: {\n validate: SchemaValidator<T>;\n errorPrefix?: string;\n}): GuardrailFn<OutputGuardrailData> {\n const { validate, errorPrefix = \"Output schema validation failed\" } = options;\n\n return (data) => {\n const result = validate(data.output);\n\n if (typeof result === \"boolean\") {\n return {\n passed: result,\n reason: result ? undefined : errorPrefix,\n };\n }\n\n if (result.valid) {\n return { passed: true };\n }\n\n const errorMessage = result.errors?.length\n ? `${errorPrefix}: ${result.errors.join(\"; \")}`\n : errorPrefix;\n\n return { passed: false, reason: errorMessage };\n };\n}\n\n// ============================================================================\n// Output Type Guardrail\n// ============================================================================\n\n/**\n * Create an output guardrail that performs lightweight runtime type checks without\n * requiring a schema library. Supports `\"string\"`, `\"number\"`, `\"boolean\"`, `\"object\"`,\n * and `\"array\"` with optional size and field constraints.\n *\n * @param options - Configuration for type checking: `type` sets the expected JS type, `requiredFields` lists object keys that must exist, `minLength`/`maxLength` constrain array size, `minStringLength`/`maxStringLength` constrain string length.\n * @returns An output guardrail that rejects output not matching the expected type or constraints.\n *\n * @example\n * ```typescript\n * const typeGuardrail = createOutputTypeGuardrail({\n * type: \"object\",\n * requiredFields: [\"id\", \"name\"],\n * });\n * ```\n *\n * @public\n */\nexport function createOutputTypeGuardrail(options: {\n type: \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\";\n requiredFields?: string[];\n minLength?: number;\n maxLength?: number;\n minStringLength?: number;\n maxStringLength?: number;\n}): GuardrailFn<OutputGuardrailData> {\n const {\n type,\n requiredFields = [],\n minLength,\n maxLength,\n minStringLength,\n maxStringLength,\n } = options;\n\n return (data) => {\n const output = data.output;\n\n switch (type) {\n case \"string\":\n if (typeof output !== \"string\") {\n return {\n passed: false,\n reason: `Expected string, got ${typeof output}`,\n };\n }\n if (minStringLength !== undefined && output.length < minStringLength) {\n return {\n passed: false,\n reason: `String too short: ${output.length} < ${minStringLength}`,\n };\n }\n if (maxStringLength !== undefined && output.length > maxStringLength) {\n return {\n passed: false,\n reason: `String too long: ${output.length} > ${maxStringLength}`,\n };\n }\n return { passed: true };\n\n case \"number\":\n if (typeof output !== \"number\" || Number.isNaN(output)) {\n return {\n passed: false,\n reason: `Expected number, got ${typeof output}`,\n };\n }\n return { passed: true };\n\n case \"boolean\":\n if (typeof output !== \"boolean\") {\n return {\n passed: false,\n reason: `Expected boolean, got ${typeof output}`,\n };\n }\n return { passed: true };\n\n case \"object\":\n if (\n typeof output !== \"object\" ||\n output === null ||\n Array.isArray(output)\n ) {\n return {\n passed: false,\n reason: `Expected object, got ${Array.isArray(output) ? \"array\" : typeof output}`,\n };\n }\n for (const field of requiredFields) {\n if (!(field in output)) {\n return {\n passed: false,\n reason: `Missing required field: ${field}`,\n };\n }\n }\n return { passed: true };\n\n case \"array\":\n if (!Array.isArray(output)) {\n return {\n passed: false,\n reason: `Expected array, got ${typeof output}`,\n };\n }\n if (minLength !== undefined && output.length < minLength) {\n return {\n passed: false,\n reason: `Array too short: ${output.length} < ${minLength}`,\n };\n }\n if (maxLength !== undefined && output.length > maxLength) {\n return {\n passed: false,\n reason: `Array too long: ${output.length} > ${maxLength}`,\n };\n }\n return { passed: true };\n\n default:\n return { passed: false, reason: `Unknown type: ${type}` };\n }\n };\n}\n\n// ============================================================================\n// Length Guardrail\n// ============================================================================\n\n/**\n * Create an output guardrail that enforces maximum length constraints on agent output,\n * measured in characters or estimated tokens.\n *\n * @param options - Configuration for length limits: `maxCharacters` caps character count, `maxTokens` caps estimated token count, `estimateTokens` provides a custom token estimator (defaults to `Math.ceil(text.length / 4)`).\n * @returns An output guardrail that rejects output exceeding the configured length limits.\n *\n * @example\n * ```typescript\n * const lengthGuardrail = createLengthGuardrail({\n * maxCharacters: 5000,\n * maxTokens: 1200,\n * });\n * ```\n *\n * @public\n */\nexport function createLengthGuardrail(options: {\n /** Maximum characters in output */\n maxCharacters?: number;\n /** Maximum estimated tokens in output */\n maxTokens?: number;\n /** Custom token estimator (default: chars / 4) */\n estimateTokens?: (text: string) => number;\n}): GuardrailFn<OutputGuardrailData> {\n const {\n maxCharacters,\n maxTokens,\n estimateTokens = (text: string) => Math.ceil(text.length / 4),\n } = options;\n\n return (data) => {\n const text = safeStringify(data.output);\n\n if (maxCharacters !== undefined && text.length > maxCharacters) {\n return {\n passed: false,\n reason: `Output too long: ${text.length} characters (max: ${maxCharacters})`,\n };\n }\n\n if (maxTokens !== undefined) {\n const tokens = estimateTokens(text);\n if (tokens > maxTokens) {\n return {\n passed: false,\n reason: `Output too long: ~${tokens} tokens (max: ${maxTokens})`,\n };\n }\n }\n\n return { passed: true };\n };\n}\n\n// ============================================================================\n// Content Filter Guardrail\n// ============================================================================\n\n/**\n * Create an output guardrail that blocks content matching any of the provided patterns.\n * String patterns are escaped and compiled to RegExp; RegExp patterns are used as-is.\n *\n * @remarks\n * A warning is logged when `blockedPatterns` is empty, since an empty list means no\n * content will ever be filtered.\n *\n * @param options - Configuration for content filtering: `blockedPatterns` lists strings or RegExps to match against output, `caseSensitive` controls case matching for string patterns (defaults to `false`).\n * @returns An output guardrail that rejects output containing any blocked pattern.\n *\n * @example\n * ```typescript\n * const contentFilter = createContentFilterGuardrail({\n * blockedPatterns: [\n * /\\bpassword\\b/i,\n * /\\bsecret\\b/i,\n * 'internal-only',\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createContentFilterGuardrail(options: {\n /** Patterns to block — strings or RegExp */\n blockedPatterns: Array<string | RegExp>;\n /** Case-sensitive matching for string patterns (default: false) */\n caseSensitive?: boolean;\n}): GuardrailFn<OutputGuardrailData> {\n const { blockedPatterns, caseSensitive = false } = options;\n\n if (blockedPatterns.length === 0) {\n console.warn(\n \"[Directive] createContentFilterGuardrail: blockedPatterns is empty — no content will be filtered\",\n );\n }\n\n const compiledPatterns = blockedPatterns.map((p) => {\n if (p instanceof RegExp) return p;\n const escaped = p.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(escaped, caseSensitive ? \"g\" : \"gi\");\n });\n\n return (data) => {\n const text = safeStringify(data.output);\n\n for (const pattern of compiledPatterns) {\n pattern.lastIndex = 0; // Reset required for global flags across iterations\n if (pattern.test(text)) {\n return {\n passed: false,\n reason: `Output contains blocked content matching: ${pattern.source}`,\n };\n }\n }\n\n return { passed: true };\n };\n}\n","/**\n * Enhanced PII Detection Guardrail\n *\n * Provides comprehensive PII detection beyond basic regex patterns:\n * - Multiple PII types (SSN, credit cards, emails, phones, addresses, names)\n * - Pluggable detection backends (regex, custom, or external services)\n * - Context-aware detection (reduces false positives)\n * - Redaction with reversible or irreversible options\n *\n * @example\n * ```typescript\n * import { createEnhancedPIIGuardrail } from '@directive-run/ai';\n *\n * const guardrail = createEnhancedPIIGuardrail({\n * types: ['ssn', 'credit_card', 'email'],\n * redact: true,\n * detector: 'regex', // or 'custom' with custom detector\n * });\n * ```\n */\n\nimport type {\n GuardrailFn,\n GuardrailResult,\n InputGuardrailData,\n OutputGuardrailData,\n} from \"../types.js\";\n\n// ============================================================================\n// PII Types\n// ============================================================================\n\n/** Supported PII types */\nexport type PIIType =\n | \"ssn\" // Social Security Number\n | \"credit_card\" // Credit/debit card numbers\n | \"email\" // Email addresses\n | \"phone\" // Phone numbers (various formats)\n | \"address\" // Physical addresses\n | \"name\" // Personal names (requires context)\n | \"date_of_birth\" // Birth dates\n | \"passport\" // Passport numbers\n | \"driver_license\" // Driver's license numbers\n | \"ip_address\" // IP addresses\n | \"bank_account\" // Bank account numbers\n | \"medical_id\" // Medical record numbers\n | \"national_id\"; // Non-US national IDs\n\n/** Detected PII instance */\nexport interface DetectedPII {\n type: PIIType;\n value: string;\n position: { start: number; end: number };\n confidence: number; // 0-1\n context?: string; // Surrounding text for debugging\n}\n\n/** PII detection result */\nexport interface PIIDetectionResult {\n detected: boolean;\n items: DetectedPII[];\n typeCounts: Partial<Record<PIIType, number>>;\n /** Text with PII redacted (if requested) */\n redactedText?: string;\n}\n\n// ============================================================================\n// Regex Patterns\n// ============================================================================\n\n/** PII pattern with validation */\ninterface PIIPattern {\n type: PIIType;\n pattern: RegExp;\n /**\n * Capture group holding the PII value itself. Defaults to 1.\n * Keyword-anchored patterns set this to 2 — group 1 is the keyword\n * (\"account\", \"passport\", …) and group 2 is the actual identifier.\n * `value` is read from this group; the redacted span still covers the\n * whole match (keyword included) so the category is not re-disclosed.\n */\n valueGroup?: number;\n /** Additional validation function (reduces false positives) */\n validate?: (match: string, context: string) => boolean;\n /** Confidence score (0-1) */\n confidence: number;\n}\n\n/** Comprehensive PII patterns */\nconst PII_PATTERNS: PIIPattern[] = [\n // SSN - US Social Security Number\n {\n type: \"ssn\",\n pattern: /\\b(\\d{3}[-\\s]?\\d{2}[-\\s]?\\d{4})\\b/g,\n validate: (match) => {\n // Remove separators and validate format\n const digits = match.replace(/[-\\s]/g, \"\");\n // SSN cannot start with 000, 666, or 9xx\n if (\n digits.startsWith(\"000\") ||\n digits.startsWith(\"666\") ||\n digits.startsWith(\"9\")\n ) {\n return false;\n }\n // Middle 2 digits cannot be 00\n if (digits.slice(3, 5) === \"00\") {\n return false;\n }\n // Last 4 digits cannot be 0000\n if (digits.slice(5) === \"0000\") {\n return false;\n }\n return true;\n },\n confidence: 0.95,\n },\n\n // Credit Card Numbers (Luhn validated)\n {\n type: \"credit_card\",\n // One capture group wraps both branches so the value group is always 1\n // (default valueGroup): the 4-4-4-4 separated grouping, or an unseparated\n // \\d{13,19} run matching the Luhn validator's 13-19 range (previously\n // \\d{15,16} left 13/14/17/18/19-digit PANs undetected).\n pattern: /\\b((?:\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4})|\\d{13,19})\\b/g,\n validate: (match) => {\n const digits = match.replace(/[-\\s]/g, \"\");\n if (digits.length < 13 || digits.length > 19) return false;\n // Luhn algorithm\n let sum = 0;\n let isEven = false;\n for (let i = digits.length - 1; i >= 0; i--) {\n const char = digits[i];\n if (!char) continue;\n let digit = Number.parseInt(char, 10);\n if (isEven) {\n digit *= 2;\n if (digit > 9) digit -= 9;\n }\n sum += digit;\n isEven = !isEven;\n }\n return sum % 10 === 0;\n },\n confidence: 0.95,\n },\n\n // Email addresses\n {\n type: \"email\",\n pattern: /\\b([A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,})\\b/gi,\n confidence: 0.9,\n },\n\n // Phone numbers (US/NANP only — not international)\n {\n type: \"phone\",\n // Matches US/NANP formats only: (555) 555-5555, 555-555-5555,\n // +1 555 555 5555. Does NOT support non-NANP international numbers.\n pattern: /\\b(\\+?1?[-.\\s]?\\(?[0-9]{3}\\)?[-.\\s]?[0-9]{3}[-.\\s]?[0-9]{4})\\b/g,\n validate: (match) => {\n const digits = match.replace(/\\D/g, \"\");\n // US numbers should be 10 or 11 digits\n return digits.length >= 10 && digits.length <= 11;\n },\n confidence: 0.8,\n },\n\n // Date of birth patterns\n {\n type: \"date_of_birth\",\n // Various formats: MM/DD/YYYY, YYYY-MM-DD, DD-MM-YYYY\n pattern:\n /\\b(born|dob|birth.?date|date.?of.?birth)[:.\\s]+(\\d{1,4}[-/]\\d{1,2}[-/]\\d{1,4})\\b/gi,\n valueGroup: 2,\n confidence: 0.85,\n },\n\n // IP addresses (IPv4 only — IPv6 deferred)\n {\n type: \"ip_address\",\n pattern: /\\b(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\b/g,\n validate: (match) => {\n const parts = match.split(\".\");\n const octets = parts.map((p) => Number.parseInt(p, 10));\n // Each octet must be a valid 0-255 number\n if (octets.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {\n return false;\n }\n const [a, b] = octets as [number, number, number, number];\n // Skip non-PII infrastructure noise: RFC1918 private ranges,\n // loopback, link-local, and the unspecified/broadcast addresses.\n if (a === 10) return false; // 10.0.0.0/8 private\n if (a === 172 && b >= 16 && b <= 31) return false; // 172.16.0.0/12 private\n if (a === 192 && b === 168) return false; // 192.168.0.0/16 private\n if (a === 127) return false; // 127.0.0.0/8 loopback\n if (a === 169 && b === 254) return false; // 169.254.0.0/16 link-local\n if (match === \"0.0.0.0\" || match === \"255.255.255.255\") return false;\n\n return true;\n },\n confidence: 0.9,\n },\n\n // Bank account numbers (generic)\n {\n type: \"bank_account\",\n // Account number followed by routing or preceded by \"account\"\n pattern: /\\b(account|acct)[\\s#:]+(\\d{8,17})\\b/gi,\n valueGroup: 2,\n confidence: 0.7,\n },\n\n // Passport numbers (various countries)\n {\n type: \"passport\",\n // US passports: 9 digits, UK: 9 digits, etc.\n pattern: /\\b(passport)[\\s#:]+([A-Z0-9]{6,9})\\b/gi,\n valueGroup: 2,\n confidence: 0.75,\n },\n\n // Driver's license (US - state specific patterns would be better)\n {\n type: \"driver_license\",\n pattern: /\\b(driver'?s?\\s*licen[cs]e|dl)[\\s#:]+([A-Z0-9]{5,15})\\b/gi,\n valueGroup: 2,\n confidence: 0.7,\n },\n\n // Medical record numbers\n {\n type: \"medical_id\",\n pattern: /\\b(mrn|medical.?record|patient.?id)[\\s#:]+([A-Z0-9-]{6,15})\\b/gi,\n valueGroup: 2,\n confidence: 0.7,\n },\n\n // National IDs (non-US) — keyword-anchored, alphanumeric ID 6-20 chars\n {\n type: \"national_id\",\n pattern:\n /\\b(national.?id|nin|identity.?number|identity.?card|id.?number)[\\s#:]+([A-Z0-9-]{6,20})\\b/gi,\n valueGroup: 2,\n confidence: 0.85,\n },\n];\n\n// ============================================================================\n// Address Detection\n// ============================================================================\n\n/** Detect US physical addresses */\nfunction detectAddresses(text: string): DetectedPII[] {\n const results: DetectedPII[] = [];\n\n // Simplified US address pattern to avoid ReDoS\n // Matches: \"123 Main Street, City, CA 12345\" or similar\n // Uses possessive-like matching and limits word count to prevent catastrophic backtracking\n const streetTypes =\n \"street|st|avenue|ave|road|rd|drive|dr|lane|ln|court|ct|way|boulevard|blvd|circle|cir|place|pl\";\n const addressPattern = new RegExp(\n `\\\\b(\\\\d{1,5}\\\\s+(?:\\\\w+\\\\s+){1,4}(?:${streetTypes})\\\\b[^\\\\n]{0,50}\\\\b[A-Z]{2}\\\\s+\\\\d{5}(?:-\\\\d{4})?)\\\\b`,\n \"gi\",\n );\n\n let match: RegExpExecArray | null;\n while ((match = addressPattern.exec(text)) !== null) {\n results.push({\n type: \"address\",\n value: match[0],\n position: { start: match.index, end: match.index + match[0].length },\n confidence: 0.7, // Lower confidence due to simpler pattern\n });\n }\n\n return results;\n}\n\n// ============================================================================\n// Name Detection (Context-Aware)\n// ============================================================================\n\n/** Common prefixes that indicate names */\nconst NAME_PREFIXES = [\n \"mr\",\n \"mrs\",\n \"ms\",\n \"miss\",\n \"dr\",\n \"prof\",\n \"sir\",\n \"madam\",\n \"name is\",\n \"called\",\n \"known as\",\n \"signed by\",\n \"from\",\n \"dear\",\n \"hi\",\n \"hello\",\n \"contact\",\n \"recipient\",\n];\n\n/** Detect personal names (requires context) */\nfunction detectNames(text: string): DetectedPII[] {\n const results: DetectedPII[] = [];\n\n // Simplified name pattern to avoid ReDoS\n // Matches: \"Mr. John Smith\" or \"name is Jane Doe\"\n // Uses non-capturing groups and limits repetition\n const prefixPattern = NAME_PREFIXES.join(\"|\");\n const nameRegex = new RegExp(\n `\\\\b(${prefixPattern})[.,:]?\\\\s+([A-Z][a-z]{1,20}(?:\\\\s[A-Z][a-z]{1,20}){0,2})\\\\b`,\n \"gi\",\n );\n\n let match: RegExpExecArray | null;\n\n while ((match = nameRegex.exec(text)) !== null) {\n const name = match[2];\n const prefix = match[1];\n // Skip if name is undefined\n if (!name) continue;\n // Ignore single-word names that might be common words\n if (\n name.split(/\\s+/).length >= 2 ||\n (prefix && NAME_PREFIXES.some((p) => prefix.toLowerCase().includes(p)))\n ) {\n results.push({\n type: \"name\",\n value: name,\n position: { start: match.index, end: match.index + match[0].length },\n confidence: 0.6,\n context: match[0],\n });\n }\n }\n\n return results;\n}\n\n// ============================================================================\n// Detection Backend Types\n// ============================================================================\n\n/** Maximum input length for PII detection (100KB) */\nconst MAX_PII_INPUT_LENGTH = 100_000;\n\n/** Custom PII detector interface */\nexport interface PIIDetector {\n detect(text: string, types: PIIType[]): Promise<DetectedPII[]>;\n name: string;\n}\n\n/**\n * Run a single PII pattern over `text` and collect every (validated) match.\n * `position` spans the FULL match: for keyword-anchored patterns the keyword\n * is redacted along with the identifier, so the redacted output never\n * re-discloses the PII category (e.g. \"MRN: ABC123\" → \"[REDACTED]\"). `value`\n * reports just the identifier (the value group) for masking/hashing/allowlist.\n */\nfunction matchPattern(pattern: PIIPattern, text: string): DetectedPII[] {\n const results: DetectedPII[] = [];\n const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);\n const group = pattern.valueGroup ?? 1;\n let match: RegExpExecArray | null;\n\n // biome-ignore lint/suspicious/noAssignInExpressions: standard regex.exec loop\n while ((match = regex.exec(text)) !== null) {\n const value = match[group] ?? match[0];\n const start = match.index;\n const end = match.index + match[0].length;\n const context = text.slice(Math.max(0, start - 20), end + 20);\n\n if (pattern.validate && !pattern.validate(value, context)) {\n continue;\n }\n\n results.push({\n type: pattern.type,\n value,\n position: { start, end },\n confidence: pattern.confidence,\n context,\n });\n }\n\n return results;\n}\n\n/** Built-in regex detector */\nexport const regexDetector: PIIDetector = {\n name: \"regex\",\n async detect(text: string, types: PIIType[]): Promise<DetectedPII[]> {\n // Security: Prevent DoS via extremely large inputs\n if (text.length > MAX_PII_INPUT_LENGTH) {\n throw new Error(\n `[Directive] Input exceeds maximum length of ${MAX_PII_INPUT_LENGTH} characters for PII detection. ` +\n \"Truncate input or process in chunks.\",\n );\n }\n\n const results: DetectedPII[] = [];\n const typeSet = new Set(types);\n\n // Pattern-based detection\n for (const pattern of PII_PATTERNS) {\n if (typeSet.has(pattern.type)) {\n results.push(...matchPattern(pattern, text));\n }\n }\n\n // Address detection (separate logic)\n if (typeSet.has(\"address\")) {\n results.push(...detectAddresses(text));\n }\n\n // Name detection (context-aware)\n if (typeSet.has(\"name\")) {\n results.push(...detectNames(text));\n }\n\n return results;\n },\n};\n\n// ============================================================================\n// Redaction Functions\n// ============================================================================\n\n/** Redaction style */\nexport type RedactionStyle =\n /** Replace with [REDACTED] */\n | \"placeholder\"\n /** Replace with type-specific placeholder like [EMAIL] */\n | \"typed\"\n /**\n * Replace with a fixed-width `****` mask plus the last 4 characters\n * (e.g. `****6789`). Does not preserve or reveal the original length.\n */\n | \"masked\"\n /**\n * Replace with a deterministic FNV-1a hash.\n *\n * **WARNING — this is PSEUDONYMIZATION, not anonymization.** FNV-1a is a\n * fast, non-cryptographic 32-bit hash. For low-entropy structured PII (SSNs,\n * card numbers, phone numbers) the output is trivially RE-IDENTIFIABLE via\n * brute force or a precomputed rainbow table. It MUST NOT be relied on for\n * GDPR / HIPAA de-identification. Use it only for referential integrity\n * (correlating the same value across audit logs).\n */\n | \"hashed\";\n\n/**\n * PII types whose *category name* is itself sensitive. For these, `typed`\n * redaction emits a generic `[REDACTED]` instead of the type name so the\n * redacted text does not reveal that the user has, e.g., an SSN, a credit\n * card, a medical record, a passport, or a bank account on file. Only the\n * mundane contact/network types (email, phone, name, address, ip_address)\n * keep their `[TYPE]` label.\n */\nconst SENSITIVE_CATEGORY_TYPES: ReadonlySet<PIIType> = new Set<PIIType>([\n \"ssn\",\n \"credit_card\",\n \"date_of_birth\",\n \"medical_id\",\n \"national_id\",\n \"passport\",\n \"driver_license\",\n \"bank_account\",\n]);\n\n/** Whether a detected item's span is a valid, in-bounds slice of `text`. */\nfunction hasValidSpan(item: DetectedPII, textLength: number): boolean {\n const { start, end } = item.position;\n\n return (\n Number.isInteger(start) &&\n Number.isInteger(end) &&\n start >= 0 &&\n start < end &&\n end <= textLength\n );\n}\n\n/** Build the replacement string for one detected item under a given style. */\nfunction buildRedactionReplacement(\n item: DetectedPII,\n style: RedactionStyle,\n): string {\n switch (style) {\n case \"placeholder\":\n return \"[REDACTED]\";\n case \"typed\":\n // For sensitive-category types, emit a generic [REDACTED] — the\n // category name itself would otherwise reveal the presence of, e.g.,\n // medical, passport, or national-ID data.\n return SENSITIVE_CATEGORY_TYPES.has(item.type)\n ? \"[REDACTED]\"\n : `[${item.type.toUpperCase()}]`;\n case \"masked\": {\n // A full-length `*` run would reveal the exact digit count of\n // structured PII. Use a fixed-width `****` mask. Only a credit-card\n // PAN may show a last-4 tail (PCI-permitted for display); the tail\n // is digit-normalized so separators never leak. Every other type —\n // SSN especially, whose last 4 are an auth token — is fully masked.\n if (item.type !== \"credit_card\") {\n return \"****\";\n }\n\n const digits = item.value.replace(/\\D/g, \"\");\n\n return `****${digits.length > 4 ? digits.slice(-4) : \"\"}`;\n }\n case \"hashed\":\n // FNV-1a hash for referential integrity (not for security). Same\n // input always produces same hash, useful for audit trails.\n return `[HASH:${fnv1aHash(item.value)}]`;\n }\n}\n\n/** Redact detected PII from text */\nexport function redactPII(\n text: string,\n items: DetectedPII[],\n style: RedactionStyle = \"typed\",\n): string {\n // Items may come from an untrusted custom PIIDetector. Drop any with a\n // malformed span before splicing — a negative, fractional, out-of-range,\n // or inverted range would corrupt offsets and could re-expose raw PII.\n const safeItems = items.filter((item) => hasValidSpan(item, text.length));\n\n // The same span can be matched by multiple patterns (e.g. a 16-digit\n // number flagged as both credit_card and phone). Splicing overlapping\n // or nested ranges shifts offsets and can leave raw PII in the output.\n // Dedupe order-independently: sort by confidence (then longer span,\n // then earlier start) so the strongest match claims its range first,\n // and keep a later item only if it overlaps nothing already kept. This\n // handles chains of three or more overlapping spans.\n const byPriority = [...safeItems].sort((a, b) => {\n if (b.confidence !== a.confidence) {\n return b.confidence - a.confidence;\n }\n\n const aSpan = a.position.end - a.position.start;\n const bSpan = b.position.end - b.position.start;\n if (bSpan !== aSpan) {\n return bSpan - aSpan;\n }\n\n return a.position.start - b.position.start;\n });\n\n const kept: DetectedPII[] = [];\n for (const item of byPriority) {\n const overlaps = kept.some(\n (k) =>\n item.position.start < k.position.end &&\n k.position.start < item.position.end,\n );\n\n if (!overlaps) {\n kept.push(item);\n }\n }\n\n // Redact the surviving non-overlapping set descending by start so earlier\n // splices do not shift the offsets of later ones.\n const sorted = kept.sort((a, b) => b.position.start - a.position.start);\n\n let result = text;\n for (const item of sorted) {\n const replacement = buildRedactionReplacement(item, style);\n\n result =\n result.slice(0, item.position.start) +\n replacement +\n result.slice(item.position.end);\n }\n\n return result;\n}\n\n/**\n * FNV-1a hash function for referential integrity.\n *\n * **WARNING — PSEUDONYMIZATION, NOT ANONYMIZATION.** This is NOT a\n * cryptographic hash. FNV-1a 32-bit is fast and unkeyed, so for low-entropy\n * structured PII (SSNs, card numbers, phone numbers) the hash is trivially\n * RE-IDENTIFIABLE by brute force or a precomputed rainbow table. The output\n * MUST NOT be treated as de-identified data under GDPR or HIPAA.\n *\n * It is designed only for:\n * - Consistent redaction references (same PII → same hash)\n * - Audit trail correlation (track redacted values across logs)\n *\n * For security-sensitive hashing, use a keyed cryptographic hash via the\n * Web Crypto API externally.\n *\n * @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function\n */\nfunction fnv1aHash(str: string): string {\n // FNV-1a 32-bit parameters\n const FNV_PRIME = 0x01000193;\n const FNV_OFFSET = 0x811c9dc5;\n\n let hash = FNV_OFFSET;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, FNV_PRIME);\n }\n\n // Convert to unsigned 32-bit and return as hex\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n// ============================================================================\n// Guardrail Factory\n// ============================================================================\n\n/** Options for enhanced PII guardrail */\nexport interface EnhancedPIIGuardrailOptions {\n /** PII types to detect (default: all) */\n types?: PIIType[];\n /** Detection backend (default: 'regex') */\n detector?: \"regex\" | PIIDetector;\n /** Redact instead of blocking */\n redact?: boolean;\n /** Redaction style (default: 'typed') */\n redactionStyle?: RedactionStyle;\n /** Minimum confidence to flag (0-1, default: 0.7) */\n minConfidence?: number;\n /** Callback when PII is detected */\n onDetected?: (items: DetectedPII[]) => void;\n /** Allow specific values (whitelist) */\n allowlist?: string[];\n /** Block only if count exceeds threshold */\n minItemsToBlock?: number;\n /** Timeout for custom detector in milliseconds (default: 5000) */\n detectorTimeout?: number;\n}\n\n/** Default PII types to detect */\nconst DEFAULT_PII_TYPES: PIIType[] = [\n \"ssn\",\n \"credit_card\",\n \"email\",\n \"phone\",\n \"date_of_birth\",\n \"bank_account\",\n];\n\n/**\n * Create an enhanced PII detection guardrail.\n *\n * @example\n * ```typescript\n * // Basic usage\n * const guardrail = createEnhancedPIIGuardrail();\n *\n * // Redact instead of blocking\n * const redactGuardrail = createEnhancedPIIGuardrail({\n * redact: true,\n * redactionStyle: 'masked',\n * });\n *\n * // Custom detection with external service\n * const customGuardrail = createEnhancedPIIGuardrail({\n * detector: myPresidioDetector,\n * types: ['ssn', 'credit_card', 'medical_id'],\n * });\n * ```\n */\nexport function createEnhancedPIIGuardrail(\n options: EnhancedPIIGuardrailOptions = {},\n): GuardrailFn<InputGuardrailData> {\n const {\n types = DEFAULT_PII_TYPES,\n detector = \"regex\",\n redact = false,\n redactionStyle = \"typed\",\n minConfidence = 0.7,\n onDetected,\n allowlist = [],\n minItemsToBlock = 1,\n detectorTimeout = 5000,\n } = options;\n\n const detectorInstance = detector === \"regex\" ? regexDetector : detector;\n // Normalize allowlist: lowercase and trim for consistent comparison\n const allowSet = new Set(allowlist.map((v) => v.toLowerCase().trim()));\n\n // Wrap detector with timeout to prevent DoS via slow external services\n async function detectWithTimeout(\n text: string,\n piiTypes: PIIType[],\n ): Promise<DetectedPII[]> {\n // Built-in regex detector doesn't need timeout (it's synchronous)\n if (detectorInstance === regexDetector) {\n return detectorInstance.detect(text, piiTypes);\n }\n\n // Custom detectors get a timeout. Whichever promise loses the race\n // still settles afterwards — attach a no-op .catch() to each so the\n // loser's rejection (timeout firing after detector wins, or detector\n // throwing after timeout wins) never surfaces as an unhandledRejection.\n let timer: ReturnType<typeof setTimeout>;\n const detectPromise = detectorInstance.detect(text, piiTypes);\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new Error(\n `[Directive] PII detector '${detectorInstance.name}' timed out after ${detectorTimeout}ms`,\n ),\n ),\n detectorTimeout,\n );\n });\n detectPromise.catch(() => {});\n timeoutPromise.catch(() => {});\n try {\n return await Promise.race([detectPromise, timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n }\n\n return async (data): Promise<GuardrailResult> => {\n const items = await detectWithTimeout(data.input, types);\n\n // Filter by confidence and allowlist (normalize value for comparison)\n const filtered = items.filter((item) => {\n if (item.confidence < minConfidence) return false;\n // Normalize detected value for allowlist comparison\n if (allowSet.has(item.value.toLowerCase().trim())) return false;\n return true;\n });\n\n if (filtered.length > 0) {\n onDetected?.(filtered);\n }\n\n if (filtered.length >= minItemsToBlock) {\n if (redact) {\n const redactedText = redactPII(data.input, filtered, redactionStyle);\n return {\n passed: true,\n transformed: redactedText,\n };\n }\n\n const typeCounts: Record<string, number> = {};\n for (const item of filtered) {\n typeCounts[item.type] = (typeCounts[item.type] || 0) + 1;\n }\n\n const summary = Object.entries(typeCounts)\n .map(([type, count]) => `${type}: ${count}`)\n .join(\", \");\n\n return {\n passed: false,\n reason: `PII detected (${summary})`,\n };\n }\n\n return { passed: true };\n };\n}\n\n/**\n * Create an output PII guardrail (for checking agent responses).\n *\n * @example\n * ```typescript\n * const outputGuardrail = createOutputPIIGuardrail({\n * types: ['ssn', 'credit_card'],\n * redact: true,\n * });\n * ```\n */\nexport function createOutputPIIGuardrail(\n options: EnhancedPIIGuardrailOptions = {},\n): GuardrailFn<OutputGuardrailData> {\n const inputGuardrail = createEnhancedPIIGuardrail(options);\n\n return async (data, context): Promise<GuardrailResult> => {\n const text =\n typeof data.output === \"string\"\n ? data.output\n : JSON.stringify(data.output);\n\n return inputGuardrail({ input: text, agentName: data.agentName }, context);\n };\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Detect PII in text without using as a guardrail.\n * Useful for analysis and logging.\n *\n * @example\n * ```typescript\n * const result = await detectPII('My SSN is 123-45-6789');\n * console.log(result.items); // [{ type: 'ssn', value: '123-45-6789', ... }]\n *\n * // With custom detector and timeout\n * const result = await detectPII(text, {\n * detector: myPresidioDetector,\n * timeout: 10000, // 10 seconds\n * });\n * ```\n */\nexport async function detectPII(\n text: string,\n options: {\n types?: PIIType[];\n detector?: \"regex\" | PIIDetector;\n minConfidence?: number;\n /** Timeout for custom detectors in milliseconds (default: 5000) */\n timeout?: number;\n } = {},\n): Promise<PIIDetectionResult> {\n const {\n types = DEFAULT_PII_TYPES,\n detector = \"regex\",\n minConfidence = 0.7,\n timeout = 5000,\n } = options;\n\n const detectorInstance = detector === \"regex\" ? regexDetector : detector;\n\n // Apply timeout for custom detectors to prevent DoS\n let items: DetectedPII[];\n if (detectorInstance === regexDetector) {\n // Built-in regex detector is synchronous, no timeout needed\n items = await detectorInstance.detect(text, types);\n } else {\n // Custom detectors get a timeout. Attach a no-op .catch() to each\n // racer so the losing promise's rejection (timeout after detector\n // wins, or detector throwing after timeout wins) never surfaces as\n // an unhandledRejection.\n let timer: ReturnType<typeof setTimeout>;\n const detectPromise = detectorInstance.detect(text, types);\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new Error(\n `[Directive] PII detector '${detectorInstance.name}' timed out after ${timeout}ms`,\n ),\n ),\n timeout,\n );\n });\n detectPromise.catch(() => {});\n timeoutPromise.catch(() => {});\n try {\n items = await Promise.race([detectPromise, timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n }\n\n const filtered = items.filter((item) => item.confidence >= minConfidence);\n\n const typeCounts: Partial<Record<PIIType, number>> = {};\n for (const item of filtered) {\n typeCounts[item.type] = (typeCounts[item.type] || 0) + 1;\n }\n\n return {\n detected: filtered.length > 0,\n items: filtered,\n typeCounts,\n };\n}\n\n/**\n * Detect PII in text and return a result whose `redactedText` is populated.\n *\n * This composes {@link detectPII} and {@link redactPII} so callers do not have\n * to manually wire the two together (and do not have to mutate the detection\n * result). When no PII is detected, `redactedText` is left `undefined` — it is\n * deliberately NOT defaulted to the raw input.\n *\n * @example\n * ```typescript\n * const result = await detectAndRedactPII('My SSN is 123-45-6789', {\n * types: ['ssn'],\n * style: 'typed',\n * });\n * console.log(result.detected); // true\n * // ssn is a sensitive-category type, so `typed` emits a generic [REDACTED]\n * console.log(result.redactedText); // 'My SSN is [REDACTED]'\n *\n * const clean = await detectAndRedactPII('nothing here', { types: ['ssn'] });\n * console.log(clean.detected); // false\n * console.log(clean.redactedText); // undefined\n * ```\n */\nexport async function detectAndRedactPII(\n text: string,\n options: {\n types?: PIIType[];\n detector?: \"regex\" | PIIDetector;\n minConfidence?: number;\n /** Timeout for custom detectors in milliseconds (default: 5000) */\n timeout?: number;\n /** Redaction style applied when PII is detected (default: 'typed') */\n style?: RedactionStyle;\n } = {},\n): Promise<PIIDetectionResult> {\n const result = await detectPII(text, options);\n\n if (!result.detected) {\n return { ...result };\n }\n\n return {\n ...result,\n redactedText: redactPII(text, result.items, options.style ?? \"typed\"),\n };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport {\n detectPII as detect,\n redactPII as redact,\n createEnhancedPIIGuardrail as create,\n createOutputPIIGuardrail as createOutput,\n};\n","/**\n * Prompt Injection Detection Guardrail\n *\n * Detects and blocks prompt injection attacks including:\n * - Direct injection attempts (\"ignore previous instructions\")\n * - Jailbreak patterns (\"DAN mode\", \"pretend you can\")\n * - Indirect injection via external content\n * - Encoding-based evasion attempts\n *\n * @example\n * ```typescript\n * import { createPromptInjectionGuardrail } from '@directive-run/ai';\n *\n * const guardrail = createPromptInjectionGuardrail({\n * strictMode: true,\n * onBlocked: (input, patterns) => logSecurityEvent(input, patterns),\n * });\n * ```\n */\n\nimport type {\n GuardrailFn,\n GuardrailResult,\n InputGuardrailData,\n} from \"../types.js\";\n\n// ============================================================================\n// Pattern Categories\n// ============================================================================\n\n/** Pattern with metadata for better debugging */\nexport interface InjectionPattern {\n pattern: RegExp;\n name: string;\n severity: \"low\" | \"medium\" | \"high\" | \"critical\";\n category: InjectionCategory;\n}\n\n/** Categories of injection attacks */\nexport type InjectionCategory =\n | \"instruction_override\" // \"ignore previous instructions\"\n | \"jailbreak\" // \"DAN mode\", \"pretend you can\"\n | \"role_manipulation\" // \"you are now\", \"act as\"\n | \"encoding_evasion\" // base64, rot13, unicode tricks\n | \"delimiter_injection\" // XML/JSON injection, markdown escape\n | \"context_manipulation\" // \"system:\", \"assistant:\", fake messages\n | \"indirect_injection\"; // URL loading, file inclusion\n\n// ============================================================================\n// Built-in Patterns\n// ============================================================================\n\n/** Default injection patterns - well-tested and low false-positive rate */\nexport const DEFAULT_INJECTION_PATTERNS: InjectionPattern[] = [\n // Instruction override patterns\n {\n pattern:\n /ignore\\s+(all\\s+)?(previous|prior|above|earlier)\\s+(instructions?|prompts?|rules?|guidelines?)/i,\n name: \"ignore-previous\",\n severity: \"critical\",\n category: \"instruction_override\",\n },\n {\n pattern:\n /disregard\\s+(all\\s+)?(previous|prior|above|earlier)\\s+(instructions?|prompts?)/i,\n name: \"disregard-previous\",\n severity: \"critical\",\n category: \"instruction_override\",\n },\n {\n pattern:\n /forget\\s+(all\\s+)?(previous|prior|above|earlier)\\s+(instructions?|prompts?)/i,\n name: \"forget-previous\",\n severity: \"critical\",\n category: \"instruction_override\",\n },\n {\n pattern: /override\\s+(the\\s+)?(system|base)\\s+(prompt|instructions?)/i,\n name: \"override-system\",\n severity: \"critical\",\n category: \"instruction_override\",\n },\n\n // Jailbreak patterns\n {\n pattern: /\\bDAN\\s+(mode|jailbreak)\\b/i,\n name: \"dan-mode\",\n severity: \"critical\",\n category: \"jailbreak\",\n },\n {\n pattern: /\\bjailbreak(ed)?\\s*(mode)?\\b/i,\n name: \"jailbreak-keyword\",\n severity: \"high\",\n category: \"jailbreak\",\n },\n {\n pattern: /developer\\s+mode\\s+(enabled|activated|on)/i,\n name: \"developer-mode\",\n severity: \"critical\",\n category: \"jailbreak\",\n },\n {\n pattern:\n /pretend\\s+(you\\s+)?(are|can|have)\\s+(no\\s+)?(restrictions?|limits?|boundaries?|ethics)/i,\n name: \"pretend-no-restrictions\",\n severity: \"high\",\n category: \"jailbreak\",\n },\n {\n pattern:\n /you\\s+(now\\s+)?have\\s+no\\s+(ethical\\s+)?(restrictions?|guidelines?|boundaries?)/i,\n name: \"no-restrictions\",\n severity: \"high\",\n category: \"jailbreak\",\n },\n\n // Role manipulation\n {\n pattern: /you\\s+are\\s+now\\s+(a|an)\\s+\\w+\\s+(that|who)\\s+(can|will|must)/i,\n name: \"role-assignment\",\n severity: \"medium\",\n category: \"role_manipulation\",\n },\n {\n pattern: /from\\s+now\\s+on,?\\s+(you\\s+)?(will|must|should)\\s+(only\\s+)?/i,\n name: \"from-now-on\",\n severity: \"medium\",\n category: \"role_manipulation\",\n },\n\n // Context manipulation (fake message markers)\n {\n pattern: /^(system|assistant|user):\\s*/im,\n name: \"fake-role-marker\",\n severity: \"high\",\n category: \"context_manipulation\",\n },\n {\n pattern: /<\\|?(system|endofprompt|im_start|im_end)\\|?>/i,\n name: \"special-token-injection\",\n severity: \"critical\",\n category: \"context_manipulation\",\n },\n\n // Delimiter injection\n {\n pattern: /```(system|assistant|instructions?)\\n/i,\n name: \"markdown-code-injection\",\n severity: \"medium\",\n category: \"delimiter_injection\",\n },\n {\n pattern: /<system>|<\\/system>|<instructions?>|<\\/instructions?>/i,\n name: \"xml-tag-injection\",\n severity: \"high\",\n category: \"delimiter_injection\",\n },\n\n // Indirect injection indicators\n {\n pattern: /fetch\\s+(content\\s+)?(from|at)\\s+(the\\s+)?url/i,\n name: \"url-fetch-instruction\",\n severity: \"medium\",\n category: \"indirect_injection\",\n },\n {\n pattern: /execute\\s+(the\\s+)?(code|script|command)\\s+(from|in|at)/i,\n name: \"execute-from-source\",\n severity: \"high\",\n category: \"indirect_injection\",\n },\n];\n\n/** Strict patterns - more aggressive, may have higher false positives */\nexport const STRICT_INJECTION_PATTERNS: InjectionPattern[] = [\n ...DEFAULT_INJECTION_PATTERNS,\n\n // Additional strict patterns\n {\n pattern: /act\\s+as\\s+(if\\s+)?(you\\s+)?(were|are|can)/i,\n name: \"act-as\",\n severity: \"low\",\n category: \"role_manipulation\",\n },\n {\n pattern: /new\\s+instructions?:/i,\n name: \"new-instructions\",\n severity: \"medium\",\n category: \"instruction_override\",\n },\n {\n pattern: /\\[system\\]|\\[admin\\]|\\[developer\\]/i,\n name: \"bracket-role-marker\",\n severity: \"medium\",\n category: \"context_manipulation\",\n },\n {\n pattern: /base64|rot13|decode\\s+(this|the)/i,\n name: \"encoding-reference\",\n severity: \"low\",\n category: \"encoding_evasion\",\n },\n {\n pattern: /\\u200b|\\u200c|\\u200d|\\u2060|\\ufeff/,\n name: \"zero-width-chars\",\n severity: \"medium\",\n category: \"encoding_evasion\",\n },\n];\n\n// ============================================================================\n// Detection Result Types\n// ============================================================================\n\n/** Detailed detection result */\nexport interface InjectionDetectionResult {\n detected: boolean;\n patterns: Array<{\n name: string;\n category: InjectionCategory;\n severity: InjectionPattern[\"severity\"];\n match: string;\n position: number;\n }>;\n riskScore: number; // 0-100\n sanitizedInput?: string;\n}\n\n// ============================================================================\n// Core Detection Function\n// ============================================================================\n\n/** Maximum input length for injection detection (100KB) */\nconst MAX_INJECTION_INPUT_LENGTH = 100_000;\n\n/**\n * Detect prompt injection patterns in text.\n * Returns detailed results about what was detected.\n *\n * @throws Error if input exceeds MAX_INJECTION_INPUT_LENGTH (100KB)\n */\nexport function detectPromptInjection(\n text: string,\n patterns: InjectionPattern[] = DEFAULT_INJECTION_PATTERNS,\n): InjectionDetectionResult {\n // Security: Prevent DoS via extremely large inputs\n if (text.length > MAX_INJECTION_INPUT_LENGTH) {\n throw new Error(\n `[Directive] Input exceeds maximum length of ${MAX_INJECTION_INPUT_LENGTH} characters for injection detection. ` +\n \"Truncate input or process in chunks.\",\n );\n }\n\n const matches: InjectionDetectionResult[\"patterns\"] = [];\n\n for (const { pattern, name, severity, category } of patterns) {\n // Reset regex state\n const regex = new RegExp(pattern.source, pattern.flags);\n const match = regex.exec(text);\n\n if (match) {\n matches.push({\n name,\n category,\n severity,\n match: match[0],\n position: match.index,\n });\n }\n }\n\n // Calculate risk score based on severity and number of matches\n const severityScores = {\n low: 10,\n medium: 25,\n high: 50,\n critical: 100,\n };\n\n const totalScore = matches.reduce(\n (sum, m) => sum + severityScores[m.severity],\n 0,\n );\n const riskScore = Math.min(100, totalScore);\n\n return {\n detected: matches.length > 0,\n patterns: matches,\n riskScore,\n };\n}\n\n/**\n * Sanitize text by removing detected injection patterns.\n * Warning: This is a best-effort sanitization, not a security guarantee.\n *\n * Uses a single-pass approach to prevent infinite loops where a replacement\n * could create a new pattern match.\n */\nexport function sanitizeInjection(\n text: string,\n patterns: InjectionPattern[] = DEFAULT_INJECTION_PATTERNS,\n): string {\n // Remove zero-width characters first (always safe)\n let sanitized = text.replace(/\\u200b|\\u200c|\\u200d|\\u2060|\\ufeff/g, \"\");\n\n // Build a combined regex for single-pass replacement to prevent\n // infinite loops where \"[REDACTED]\" could match another pattern\n const allPatterns = patterns.map((p) => `(${p.pattern.source})`);\n if (allPatterns.length === 0) return sanitized;\n\n // Combine all patterns with alternation, using the most permissive flags\n const hasGlobal = patterns.some((p) => p.pattern.flags.includes(\"g\"));\n const hasIgnoreCase = patterns.some((p) => p.pattern.flags.includes(\"i\"));\n const hasMultiline = patterns.some((p) => p.pattern.flags.includes(\"m\"));\n\n const flags = `${hasGlobal ? \"g\" : \"\"}${hasIgnoreCase ? \"i\" : \"\"}${hasMultiline ? \"m\" : \"\"}`;\n const combinedRegex = new RegExp(allPatterns.join(\"|\"), flags || \"gi\");\n\n // Single-pass replacement prevents cascade issues\n sanitized = sanitized.replace(combinedRegex, \"[REDACTED]\");\n\n return sanitized;\n}\n\n// ============================================================================\n// Guardrail Factory\n// ============================================================================\n\n/** Options for prompt injection guardrail */\nexport interface PromptInjectionGuardrailOptions {\n /** Additional patterns to check (added to defaults) */\n additionalPatterns?: InjectionPattern[];\n /** Replace default patterns entirely */\n replacePatterns?: InjectionPattern[];\n /** Use strict mode with more aggressive detection */\n strictMode?: boolean;\n /** Minimum risk score to block (0-100, default: 50) */\n blockThreshold?: number;\n /** Attempt to sanitize instead of blocking */\n sanitize?: boolean;\n /** Callback when injection is detected */\n onBlocked?: (input: string, result: InjectionDetectionResult) => void;\n /** Categories to ignore (e.g., allow 'role_manipulation' for roleplay apps) */\n ignoreCategories?: InjectionCategory[];\n}\n\n/**\n * Create a prompt injection detection guardrail.\n *\n * @example\n * ```typescript\n * // Basic usage\n * const guardrail = createPromptInjectionGuardrail();\n *\n * // Strict mode for high-security applications\n * const strictGuardrail = createPromptInjectionGuardrail({\n * strictMode: true,\n * blockThreshold: 25,\n * });\n *\n * // Allow role manipulation for roleplay apps\n * const roleplayGuardrail = createPromptInjectionGuardrail({\n * ignoreCategories: ['role_manipulation'],\n * });\n * ```\n */\nexport function createPromptInjectionGuardrail(\n options: PromptInjectionGuardrailOptions = {},\n): GuardrailFn<InputGuardrailData> {\n const {\n additionalPatterns = [],\n replacePatterns,\n strictMode = false,\n blockThreshold = 50,\n sanitize = false,\n onBlocked,\n ignoreCategories = [],\n } = options;\n\n // Build pattern list\n let patterns: InjectionPattern[];\n if (replacePatterns) {\n patterns = replacePatterns;\n } else {\n patterns = strictMode\n ? [...STRICT_INJECTION_PATTERNS]\n : [...DEFAULT_INJECTION_PATTERNS];\n }\n patterns = [...patterns, ...additionalPatterns];\n\n // Filter out ignored categories\n if (ignoreCategories.length > 0) {\n const ignoredSet = new Set(ignoreCategories);\n patterns = patterns.filter((p) => !ignoredSet.has(p.category));\n }\n\n return (data): GuardrailResult => {\n const result = detectPromptInjection(data.input, patterns);\n\n if (result.detected && result.riskScore >= blockThreshold) {\n onBlocked?.(data.input, result);\n\n if (sanitize) {\n const sanitized = sanitizeInjection(data.input, patterns);\n return {\n passed: true,\n transformed: sanitized,\n };\n }\n\n const topPatterns = result.patterns\n .sort((a, b) => {\n const order = { critical: 0, high: 1, medium: 2, low: 3 };\n return order[a.severity] - order[b.severity];\n })\n .slice(0, 3)\n .map((p) => p.name)\n .join(\", \");\n\n return {\n passed: false,\n reason: `Prompt injection detected (risk: ${result.riskScore}%, patterns: ${topPatterns})`,\n };\n }\n\n return { passed: true };\n };\n}\n\n// ============================================================================\n// Indirect Injection Defense\n// ============================================================================\n\n/**\n * Mark content as potentially untrusted (from external sources).\n * This wraps the content with markers that injection detection will scrutinize more closely.\n *\n * @example\n * ```typescript\n * const userUpload = await readFile(path);\n * const markedContent = markUntrustedContent(userUpload, 'user-upload');\n * const prompt = `Summarize this document: ${markedContent}`;\n * ```\n */\nexport function markUntrustedContent(content: string, source: string): string {\n // Use a delimiter that's unlikely to appear in normal content\n // and that injection patterns will trigger on\n return `[UNTRUSTED_CONTENT source=\"${source}\"]\\n${content}\\n[/UNTRUSTED_CONTENT]`;\n}\n\n/**\n * Create a guardrail that applies stricter checks to marked untrusted content.\n *\n * @example\n * ```typescript\n * const guardrail = createUntrustedContentGuardrail({\n * baseGuardrail: createPromptInjectionGuardrail({ strictMode: true }),\n * });\n * ```\n */\nexport function createUntrustedContentGuardrail(options: {\n /** Guardrail to apply to untrusted sections */\n baseGuardrail?: GuardrailFn<InputGuardrailData>;\n /** Block if untrusted content contains these patterns */\n additionalPatterns?: InjectionPattern[];\n}): GuardrailFn<InputGuardrailData> {\n const {\n baseGuardrail = createPromptInjectionGuardrail({\n strictMode: true,\n blockThreshold: 25,\n }),\n additionalPatterns = [],\n } = options;\n\n const untrustedMarkerRegex =\n /\\[UNTRUSTED_CONTENT source=\"([^\"]+)\"\\]([\\s\\S]*?)\\[\\/UNTRUSTED_CONTENT\\]/g;\n\n return async (data, context): Promise<GuardrailResult> => {\n // First, check the entire input\n const fullResult = await baseGuardrail(data, context);\n if (!fullResult.passed) {\n return fullResult;\n }\n\n // Then, apply additional scrutiny to untrusted sections\n const matches = data.input.matchAll(untrustedMarkerRegex);\n for (const match of matches) {\n const [, source, content] = match;\n\n // Skip if content is undefined\n if (!content) continue;\n\n // Check with stricter patterns\n const strictResult = detectPromptInjection(content, [\n ...STRICT_INJECTION_PATTERNS,\n ...additionalPatterns,\n ]);\n\n if (strictResult.detected && strictResult.riskScore >= 25) {\n return {\n passed: false,\n reason: `Untrusted content from \"${source}\" contains potential injection (risk: ${strictResult.riskScore}%)`,\n };\n }\n }\n\n return { passed: true };\n };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport {\n detectPromptInjection as detect,\n sanitizeInjection as sanitize,\n createPromptInjectionGuardrail as create,\n};\n","/**\n * Semantic Caching Guardrail\n *\n * Caches agent responses based on semantic similarity to reduce redundant LLM calls.\n * Uses vector embeddings to find semantically similar previous queries.\n *\n * @example\n * ```typescript\n * import { createSemanticCacheGuardrail } from '@directive-run/ai';\n *\n * const cacheGuardrail = createSemanticCacheGuardrail({\n * embedder: async (text) => {\n * // Use your embedding model (OpenAI, local model, etc.)\n * return await getEmbedding(text);\n * },\n * similarityThreshold: 0.95,\n * maxCacheSize: 1000,\n * ttlMs: 3600000, // 1 hour\n * });\n *\n * const orchestrator = createAgentOrchestrator({\n * guardrails: {\n * input: [cacheGuardrail],\n * },\n * runner: run,\n * });\n * ```\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Vector embedding (array of numbers) */\nexport type Embedding = number[];\n\n/** Function to generate embeddings for text */\nexport type EmbedderFn = (text: string) => Promise<Embedding>;\n\n/** Cached response entry */\nexport interface CacheEntry {\n id: string;\n query: string;\n queryEmbedding: Embedding;\n response: string;\n metadata: Record<string, unknown>;\n createdAt: number;\n accessedAt: number;\n accessCount: number;\n agentName?: string;\n}\n\n/** Cache lookup result */\nexport interface CacheLookupResult {\n hit: boolean;\n entry?: CacheEntry;\n similarity?: number;\n latencyMs: number;\n}\n\n/** Semantic cache configuration */\nexport interface SemanticCacheConfig {\n /** Function to generate embeddings */\n embedder: EmbedderFn;\n /** Similarity threshold (0.0 to 1.0) for cache hits */\n similarityThreshold?: number;\n /** Maximum number of entries to cache */\n maxCacheSize?: number;\n /** Time-to-live in milliseconds for cache entries */\n ttlMs?: number;\n /** Cache namespace for multi-tenant scenarios */\n namespace?: string;\n /** Custom storage backend (defaults to in-memory) */\n storage?: SemanticCacheStorage;\n /** Callback when cache hit occurs */\n onHit?: (entry: CacheEntry, similarity: number) => void;\n /** Callback when cache miss occurs */\n onMiss?: (query: string) => void;\n /** Callback when cache lookup encounters an error */\n onError?: (error: Error) => void;\n /** Whether to include agent name in cache key */\n perAgent?: boolean;\n}\n\n/** Storage interface for cache backends */\nexport interface SemanticCacheStorage {\n /** Get all entries for a namespace */\n getEntries(namespace: string): Promise<CacheEntry[]>;\n /** Add an entry to the cache */\n addEntry(namespace: string, entry: CacheEntry): Promise<void>;\n /** Update an entry (e.g., access count) */\n updateEntry(\n namespace: string,\n id: string,\n updates: Partial<CacheEntry>,\n ): Promise<void>;\n /** Remove an entry */\n removeEntry(namespace: string, id: string): Promise<void>;\n /** Clear all entries in a namespace */\n clear(namespace: string): Promise<void>;\n}\n\n/** Semantic cache instance */\nexport interface SemanticCache {\n /** Look up a query in the cache */\n lookup(query: string, agentName?: string): Promise<CacheLookupResult>;\n /** Store a response in the cache */\n store(\n query: string,\n response: string,\n agentName?: string,\n metadata?: Record<string, unknown>,\n ): Promise<void>;\n /** Invalidate cache entries matching a predicate */\n invalidate(predicate: (entry: CacheEntry) => boolean): Promise<number>;\n /** Clear all cache entries */\n clear(): Promise<void>;\n /** Get cache statistics */\n getStats(): CacheStats;\n /** Export cache entries (for persistence) */\n export(): Promise<CacheEntry[]>;\n /** Import cache entries (from persistence) */\n import(entries: CacheEntry[]): Promise<void>;\n}\n\n/** Cache statistics */\nexport interface CacheStats {\n totalEntries: number;\n totalHits: number;\n totalMisses: number;\n hitRate: number;\n avgSimilarityOnHit: number;\n oldestEntry: number | null;\n newestEntry: number | null;\n}\n\n// ============================================================================\n// Vector Math Utilities\n// ============================================================================\n\n/**\n * Calculate cosine similarity between two vectors.\n */\nexport function cosineSimilarity(a: Embedding, b: Embedding): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimensions must match: ${a.length} vs ${b.length}`);\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n const ai = a[i]!; // Safe: i is within bounds\n const bi = b[i]!; // Safe: dimensions match and i is within bounds\n dotProduct += ai * bi;\n normA += ai * ai;\n normB += bi * bi;\n }\n\n normA = Math.sqrt(normA);\n normB = Math.sqrt(normB);\n\n if (normA === 0 || normB === 0) {\n return 0;\n }\n\n return dotProduct / (normA * normB);\n}\n\n/**\n * Find the most similar entries to a query embedding.\n */\nfunction findSimilar(\n queryEmbedding: Embedding,\n entries: CacheEntry[],\n threshold: number,\n agentName?: string,\n): { entry: CacheEntry; similarity: number } | null {\n let bestMatch: { entry: CacheEntry; similarity: number } | null = null;\n\n for (const entry of entries) {\n // Filter by agent if specified\n if (agentName && entry.agentName && entry.agentName !== agentName) {\n continue;\n }\n\n const similarity = cosineSimilarity(queryEmbedding, entry.queryEmbedding);\n\n if (similarity >= threshold) {\n if (!bestMatch || similarity > bestMatch.similarity) {\n bestMatch = { entry, similarity };\n }\n }\n }\n\n return bestMatch;\n}\n\n// ============================================================================\n// In-Memory Storage\n// ============================================================================\n\n/**\n * Create an in-memory cache storage backend.\n */\nexport function createInMemoryStorage(): SemanticCacheStorage {\n const storage = new Map<string, Map<string, CacheEntry>>();\n\n function getNamespace(namespace: string): Map<string, CacheEntry> {\n let ns = storage.get(namespace);\n if (!ns) {\n ns = new Map();\n storage.set(namespace, ns);\n }\n return ns;\n }\n\n return {\n async getEntries(namespace: string): Promise<CacheEntry[]> {\n return Array.from(getNamespace(namespace).values());\n },\n\n async addEntry(namespace: string, entry: CacheEntry): Promise<void> {\n getNamespace(namespace).set(entry.id, entry);\n },\n\n async updateEntry(\n namespace: string,\n id: string,\n updates: Partial<CacheEntry>,\n ): Promise<void> {\n const ns = getNamespace(namespace);\n const entry = ns.get(id);\n if (entry) {\n ns.set(id, { ...entry, ...updates });\n }\n },\n\n async removeEntry(namespace: string, id: string): Promise<void> {\n getNamespace(namespace).delete(id);\n },\n\n async clear(namespace: string): Promise<void> {\n storage.delete(namespace);\n },\n };\n}\n\n// ============================================================================\n// Semantic Cache Factory\n// ============================================================================\n\n/**\n * Create a semantic cache instance.\n *\n * @example\n * ```typescript\n * const cache = createSemanticCache({\n * embedder: async (text) => {\n * const response = await openai.embeddings.create({\n * model: 'text-embedding-3-small',\n * input: text,\n * });\n * return response.data[0].embedding;\n * },\n * similarityThreshold: 0.92,\n * maxCacheSize: 500,\n * ttlMs: 3600000, // 1 hour\n * });\n *\n * // Check cache before calling agent\n * const result = await cache.lookup(userQuery);\n * if (result.hit) {\n * return result.entry!.response;\n * }\n *\n * // Call agent and cache response\n * const response = await runAgent(userQuery);\n * await cache.store(userQuery, response);\n * ```\n */\nexport function createSemanticCache(\n config: SemanticCacheConfig,\n): SemanticCache {\n const {\n embedder,\n similarityThreshold = 0.9,\n maxCacheSize = 1000,\n ttlMs = 3600000, // 1 hour default\n namespace = \"default\",\n storage = createInMemoryStorage(),\n onHit,\n onMiss,\n onError,\n perAgent = false,\n } = config;\n\n // Statistics\n let stats: CacheStats = {\n totalEntries: 0,\n totalHits: 0,\n totalMisses: 0,\n hitRate: 0,\n avgSimilarityOnHit: 0,\n oldestEntry: null,\n newestEntry: null,\n };\n\n let totalSimilaritySum = 0;\n\n function updateStats(entries: CacheEntry[]): void {\n stats.totalEntries = entries.length;\n stats.hitRate =\n stats.totalHits + stats.totalMisses > 0\n ? stats.totalHits / (stats.totalHits + stats.totalMisses)\n : 0;\n stats.avgSimilarityOnHit =\n stats.totalHits > 0 ? totalSimilaritySum / stats.totalHits : 0;\n\n if (entries.length > 0) {\n const times = entries.map((e) => e.createdAt);\n stats.oldestEntry = Math.min(...times);\n stats.newestEntry = Math.max(...times);\n } else {\n stats.oldestEntry = null;\n stats.newestEntry = null;\n }\n }\n\n async function evictExpiredAndExcess(): Promise<void> {\n const entries = await storage.getEntries(namespace);\n const now = Date.now();\n\n // Remove expired entries\n for (const entry of entries) {\n if (now - entry.createdAt > ttlMs) {\n await storage.removeEntry(namespace, entry.id);\n }\n }\n\n // Get fresh list after expiration\n const remainingEntries = await storage.getEntries(namespace);\n\n // Remove oldest entries if over max size (LRU based on accessedAt)\n if (remainingEntries.length > maxCacheSize) {\n const sorted = remainingEntries.sort(\n (a, b) => a.accessedAt - b.accessedAt,\n );\n const toRemove = sorted.slice(0, remainingEntries.length - maxCacheSize);\n for (const entry of toRemove) {\n await storage.removeEntry(namespace, entry.id);\n }\n }\n }\n\n return {\n async lookup(\n query: string,\n agentName?: string,\n ): Promise<CacheLookupResult> {\n const start = Date.now();\n\n try {\n // Generate embedding for query\n const queryEmbedding = await embedder(query);\n\n // Get all entries\n const entries = await storage.getEntries(namespace);\n\n // Find similar entry\n const match = findSimilar(\n queryEmbedding,\n entries,\n similarityThreshold,\n perAgent ? agentName : undefined,\n );\n\n if (match) {\n // Update access stats\n await storage.updateEntry(namespace, match.entry.id, {\n accessedAt: Date.now(),\n accessCount: match.entry.accessCount + 1,\n });\n\n stats.totalHits++;\n totalSimilaritySum += match.similarity;\n updateStats(entries);\n\n onHit?.(match.entry, match.similarity);\n\n return {\n hit: true,\n entry: match.entry,\n similarity: match.similarity,\n latencyMs: Date.now() - start,\n };\n }\n\n stats.totalMisses++;\n updateStats(entries);\n\n onMiss?.(query);\n\n return {\n hit: false,\n latencyMs: Date.now() - start,\n };\n } catch (error) {\n // On error, treat as cache miss\n stats.totalMisses++;\n onError?.(error instanceof Error ? error : new Error(String(error)));\n return {\n hit: false,\n latencyMs: Date.now() - start,\n };\n }\n },\n\n async store(\n query: string,\n response: string,\n agentName?: string,\n metadata: Record<string, unknown> = {},\n ): Promise<void> {\n // Generate embedding\n const queryEmbedding = await embedder(query);\n\n const entry: CacheEntry = {\n id:\n globalThis.crypto?.randomUUID?.() ??\n `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,\n query,\n queryEmbedding,\n response,\n metadata,\n createdAt: Date.now(),\n accessedAt: Date.now(),\n accessCount: 0,\n agentName: perAgent ? agentName : undefined,\n };\n\n await storage.addEntry(namespace, entry);\n\n // Evict if necessary\n await evictExpiredAndExcess();\n\n const entries = await storage.getEntries(namespace);\n updateStats(entries);\n },\n\n async invalidate(\n predicate: (entry: CacheEntry) => boolean,\n ): Promise<number> {\n const entries = await storage.getEntries(namespace);\n let removed = 0;\n\n for (const entry of entries) {\n if (predicate(entry)) {\n await storage.removeEntry(namespace, entry.id);\n removed++;\n }\n }\n\n const remainingEntries = await storage.getEntries(namespace);\n updateStats(remainingEntries);\n\n return removed;\n },\n\n async clear(): Promise<void> {\n await storage.clear(namespace);\n stats = {\n totalEntries: 0,\n totalHits: 0,\n totalMisses: 0,\n hitRate: 0,\n avgSimilarityOnHit: 0,\n oldestEntry: null,\n newestEntry: null,\n };\n totalSimilaritySum = 0;\n },\n\n getStats(): CacheStats {\n return { ...stats };\n },\n\n async export(): Promise<CacheEntry[]> {\n return storage.getEntries(namespace);\n },\n\n async import(entries: CacheEntry[]): Promise<void> {\n for (const entry of entries) {\n await storage.addEntry(namespace, entry);\n }\n await evictExpiredAndExcess();\n const allEntries = await storage.getEntries(namespace);\n updateStats(allEntries);\n },\n };\n}\n\n// ============================================================================\n// Guardrail Integration\n// ============================================================================\n\n/** Input guardrail data for semantic cache */\nexport interface SemanticCacheGuardrailData {\n input: string;\n agentName?: string;\n}\n\n/**\n * Result of semantic cache guardrail.\n *\n * **Important semantics:**\n * - `passed: false` + `cacheHit: true` = Short-circuit with cached response (not an error!)\n * - `passed: true` + `cacheHit: false` = No cache hit, proceed with agent call\n *\n * The `passed: false` follows guardrail convention where \"not passing\" stops the flow,\n * but in this case stopping is desirable (returning cached data is good).\n */\nexport interface SemanticCacheGuardrailResult {\n /**\n * Whether to proceed with the agent call.\n * `false` means short-circuit with cached response (this is good, not an error).\n * `true` means no cache hit, proceed with agent.\n */\n passed: boolean;\n /** Indicates whether this was a cache hit */\n cacheHit: boolean;\n /** Reason for the result */\n reason?: string;\n /** The cached response (only present on cache hit) */\n cachedResponse?: string;\n /** Similarity score (0-1) of the cache hit */\n similarity?: number;\n}\n\n/**\n * Create a semantic caching input guardrail.\n *\n * **How it works:**\n * - On cache HIT: Returns `{ passed: false, cacheHit: true, cachedResponse: \"...\" }`\n * The orchestrator should detect `cacheHit: true` and return the cached response.\n * - On cache MISS: Returns `{ passed: true, cacheHit: false }`\n * Proceed with normal agent execution.\n *\n * **Important:** `passed: false` with `cacheHit: true` is SUCCESS, not failure.\n * The guardrail \"short-circuits\" the flow to return cached data efficiently.\n *\n * @example\n * ```typescript\n * const cacheGuardrail = createSemanticCacheGuardrail({\n * cache: mySemanticCache,\n * });\n *\n * const orchestrator = createAgentOrchestrator({\n * guardrails: {\n * input: [\n * {\n * name: 'semantic-cache',\n * fn: cacheGuardrail,\n * },\n * ],\n * },\n * runner: run,\n * });\n *\n * // In your orchestrator wrapper, check for cache hits:\n * const guardrailResult = await cacheGuardrail({ input: userQuery });\n * if (guardrailResult.cacheHit) {\n * return guardrailResult.cachedResponse; // Fast path!\n * }\n * // Otherwise proceed with agent call...\n * ```\n */\nexport function createSemanticCacheGuardrail(config: {\n cache: SemanticCache;\n}): (\n data: SemanticCacheGuardrailData,\n) => Promise<SemanticCacheGuardrailResult> {\n const { cache } = config;\n\n return async (\n data: SemanticCacheGuardrailData,\n ): Promise<SemanticCacheGuardrailResult> => {\n const result = await cache.lookup(data.input, data.agentName);\n\n if (result.hit && result.entry) {\n return {\n passed: false, // Short-circuit: don't proceed to agent\n cacheHit: true,\n reason: `Cache hit (similarity: ${(result.similarity! * 100).toFixed(1)}%)`,\n cachedResponse: result.entry.response,\n similarity: result.similarity,\n };\n }\n\n return {\n passed: true, // No cache hit, proceed with agent call\n cacheHit: false,\n };\n };\n}\n\n// ============================================================================\n// Embedding Utilities\n// ============================================================================\n\n/**\n * Create a simple hash-based \"embedder\" for testing.\n * NOT suitable for production - use a real embedding model.\n */\nexport function createTestEmbedder(dimensions = 128): EmbedderFn {\n return async (text: string): Promise<Embedding> => {\n const embedding = new Array(dimensions).fill(0);\n\n // Simple hash-based embedding for testing\n for (let i = 0; i < text.length; i++) {\n const charCode = text.charCodeAt(i);\n embedding[i % dimensions] += charCode / 256;\n }\n\n // Normalize\n const norm = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));\n if (norm > 0) {\n for (let i = 0; i < dimensions; i++) {\n embedding[i] /= norm;\n }\n }\n\n return embedding;\n };\n}\n\n/** Batched embedder instance with destroy capability */\nexport interface BatchedEmbedder {\n /** Embed a single text (batched internally) */\n embed: EmbedderFn;\n /** Flush any pending batch immediately */\n flush(): Promise<void>;\n /** Destroy the embedder, clearing timers and rejecting pending requests */\n destroy(): void;\n}\n\n/**\n * Create a batched embedder that groups multiple texts into single API calls.\n *\n * **BREAKING CHANGE:** Previously returned `EmbedderFn` directly. Now returns\n * a `BatchedEmbedder` object with `embed`, `flush`, and `destroy` methods.\n *\n * To migrate: `const embed = createBatchedEmbedder(...)` becomes\n * `const { embed } = createBatchedEmbedder(...)`.\n *\n * @example\n * ```typescript\n * const batchedEmbedder = createBatchedEmbedder({\n * batchSize: 20,\n * embedBatch: async (texts) => {\n * const response = await openai.embeddings.create({\n * model: 'text-embedding-3-small',\n * input: texts,\n * });\n * return response.data.map(d => d.embedding);\n * },\n * maxWaitMs: 50,\n * });\n *\n * // Use the embedder\n * const embedding = await batchedEmbedder.embed(\"Hello world\");\n *\n * // Clean up when done\n * batchedEmbedder.destroy();\n * ```\n */\nexport function createBatchedEmbedder(config: {\n batchSize?: number;\n embedBatch: (texts: string[]) => Promise<Embedding[]>;\n maxWaitMs?: number;\n}): BatchedEmbedder {\n const { batchSize = 20, embedBatch, maxWaitMs = 50 } = config;\n\n if (batchSize < 1 || !Number.isFinite(batchSize)) {\n throw new Error(\n `[Directive SemanticCache] batchSize must be >= 1, got ${batchSize}`,\n );\n }\n\n let pendingBatch: Array<{\n text: string;\n resolve: (embedding: Embedding) => void;\n reject: (error: Error) => void;\n }> = [];\n let batchTimer: ReturnType<typeof setTimeout> | null = null;\n let isDestroyed = false;\n\n async function flushBatch(): Promise<void> {\n if (pendingBatch.length === 0) return;\n\n const batch = pendingBatch;\n pendingBatch = [];\n\n if (batchTimer) {\n clearTimeout(batchTimer);\n batchTimer = null;\n }\n\n try {\n const texts = batch.map((item) => item.text);\n const embeddings = await embedBatch(texts);\n\n if (embeddings.length !== batch.length) {\n throw new Error(\n `[Directive SemanticCache] embedBatch returned ${embeddings.length} embeddings for ${batch.length} texts. ` +\n \"The embedBatch function must return exactly one embedding per input text.\",\n );\n }\n\n for (let i = 0; i < batch.length; i++) {\n batch[i]!.resolve(embeddings[i]!);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n for (const item of batch) {\n item.reject(err);\n }\n }\n }\n\n return {\n async embed(text: string): Promise<Embedding> {\n if (isDestroyed) {\n throw new Error(\"BatchedEmbedder has been destroyed\");\n }\n\n return new Promise((resolve, reject) => {\n pendingBatch.push({ text, resolve, reject });\n\n if (pendingBatch.length >= batchSize) {\n flushBatch();\n } else if (!batchTimer) {\n batchTimer = setTimeout(flushBatch, maxWaitMs);\n }\n });\n },\n\n async flush(): Promise<void> {\n await flushBatch();\n },\n\n destroy(): void {\n isDestroyed = true;\n\n // Clear timer\n if (batchTimer) {\n clearTimeout(batchTimer);\n batchTimer = null;\n }\n\n // Reject pending requests\n const batch = pendingBatch;\n pendingBatch = [];\n const err = new Error(\"BatchedEmbedder destroyed\");\n for (const item of batch) {\n item.reject(err);\n }\n },\n };\n}\n","/**\n * Approximate Nearest Neighbor (ANN) Index for Semantic Cache\n *\n * Provides pluggable vector search backends for efficient similarity lookups.\n * Includes a brute-force exact search and a VP-tree (Vantage Point Tree) for\n * fast approximate nearest neighbor queries.\n *\n * @example\n * ```typescript\n * import { createSemanticCache } from '@directive-run/ai';\n * import { createVPTreeIndex } from '@directive-run/ai';\n *\n * const index = createVPTreeIndex();\n *\n * const cache = createSemanticCache({\n * embedder: myEmbedder,\n * annIndex: index,\n * });\n * ```\n */\n\nimport type { Embedding } from \"./semantic-cache.js\";\nimport { cosineSimilarity } from \"./semantic-cache.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Search result from an ANN index */\nexport interface ANNSearchResult {\n /** ID of the matched item */\n id: number;\n /** Similarity score (0-1, higher is more similar) */\n similarity: number;\n}\n\n/** ANN Index interface - pluggable vector search backend */\nexport interface ANNIndex {\n /** Add a vector to the index */\n add(id: number, embedding: Embedding): void;\n /** Remove a vector from the index */\n remove(id: number): void;\n /** Search for the k nearest neighbors */\n search(query: Embedding, k: number, threshold?: number): ANNSearchResult[];\n /** Rebuild the index (call after batch additions) */\n rebuild(): void;\n /** Get the number of indexed vectors */\n size(): number;\n /** Clear the index */\n clear(): void;\n /** Check if the index needs to be rebuilt (e.g., after additions/removals) */\n needsRebuild(): boolean;\n}\n\n// ============================================================================\n// Brute Force Index (Exact Search)\n// ============================================================================\n\n/**\n * Create a brute-force exact search index.\n *\n * O(n) search, O(1) add/remove. Best for small collections (< 10,000 vectors).\n *\n * @example\n * ```typescript\n * const index = createBruteForceIndex();\n * index.add(0, [0.1, 0.2, 0.3]);\n * index.add(1, [0.4, 0.5, 0.6]);\n *\n * const results = index.search([0.1, 0.2, 0.3], 1);\n * // [{ id: 0, similarity: 1.0 }]\n * ```\n */\nexport function createBruteForceIndex(): ANNIndex {\n const vectors = new Map<number, Embedding>();\n let expectedDimension: number | null = null;\n\n function validateDimension(embedding: Embedding): void {\n if (expectedDimension === null) {\n expectedDimension = embedding.length;\n } else if (embedding.length !== expectedDimension) {\n throw new Error(\n `[Directive ANNIndex] Dimension mismatch: expected ${expectedDimension}, got ${embedding.length}`,\n );\n }\n }\n\n return {\n add(id: number, embedding: Embedding): void {\n validateDimension(embedding);\n vectors.set(id, embedding);\n },\n\n remove(id: number): void {\n vectors.delete(id);\n },\n\n search(query: Embedding, k: number, threshold = 0): ANNSearchResult[] {\n if (expectedDimension !== null && query.length !== expectedDimension) {\n throw new Error(\n `[Directive ANNIndex] Query dimension mismatch: expected ${expectedDimension}, got ${query.length}`,\n );\n }\n const results: ANNSearchResult[] = [];\n\n for (const [id, embedding] of vectors) {\n const similarity = cosineSimilarity(query, embedding);\n if (similarity >= threshold) {\n results.push({ id, similarity });\n }\n }\n\n // Sort by similarity descending, take top k\n results.sort((a, b) => b.similarity - a.similarity);\n return results.slice(0, k);\n },\n\n rebuild(): void {\n // No-op for brute force\n },\n\n size(): number {\n return vectors.size;\n },\n\n clear(): void {\n vectors.clear();\n expectedDimension = null;\n },\n\n needsRebuild(): boolean {\n return false; // Brute force doesn't need rebuilding\n },\n };\n}\n\n// ============================================================================\n// VP-Tree Index (Approximate Search)\n// ============================================================================\n\ninterface VPNode {\n id: number;\n embedding: Embedding;\n mu: number; // Median distance\n left: VPNode | null;\n right: VPNode | null;\n}\n\nfunction cosineDistance(a: Embedding, b: Embedding): number {\n return 1 - cosineSimilarity(a, b);\n}\n\n/** VP-Tree index configuration */\nexport interface VPTreeIndexConfig {\n /** Optional random number generator for deterministic builds. Returns a number in [0, 1). */\n random?: () => number;\n}\n\nfunction buildVPTree(\n items: Array<{ id: number; embedding: Embedding }>,\n random: () => number,\n): VPNode | null {\n if (items.length === 0) return null;\n\n // Pick a random vantage point\n const vpIdx = Math.floor(random() * items.length);\n const vp = items[vpIdx]!;\n const rest = items.filter((_, i) => i !== vpIdx);\n\n if (rest.length === 0) {\n return {\n id: vp.id,\n embedding: vp.embedding,\n mu: 0,\n left: null,\n right: null,\n };\n }\n\n // Calculate distances from vantage point\n const distances = rest.map((item) => ({\n item,\n distance: cosineDistance(vp.embedding, item.embedding),\n }));\n\n // Find median distance\n distances.sort((a, b) => a.distance - b.distance);\n const medianIdx = Math.floor(distances.length / 2);\n const mu = distances[medianIdx]!.distance;\n\n const leftItems = distances.slice(0, medianIdx).map((d) => d.item);\n const rightItems = distances.slice(medianIdx).map((d) => d.item);\n\n return {\n id: vp.id,\n embedding: vp.embedding,\n mu,\n left: buildVPTree(leftItems, random),\n right: buildVPTree(rightItems, random),\n };\n}\n\nfunction searchVPTree(\n node: VPNode | null,\n query: Embedding,\n k: number,\n threshold: number,\n results: ANNSearchResult[],\n maxDist: { value: number },\n): void {\n if (!node) return;\n\n const dist = cosineDistance(query, node.embedding);\n const similarity = 1 - dist;\n\n if (similarity >= threshold) {\n results.push({ id: node.id, similarity });\n results.sort((a, b) => b.similarity - a.similarity);\n\n if (results.length > k) {\n results.pop();\n }\n\n if (results.length === k) {\n maxDist.value = 1 - results[results.length - 1]!.similarity;\n }\n }\n\n // Determine which subtrees to search\n if (dist < node.mu) {\n // Query is inside the ball: search left (inside) first\n searchVPTree(node.left, query, k, threshold, results, maxDist);\n // Only search right if the distance boundary overlaps\n if (dist + maxDist.value >= node.mu) {\n searchVPTree(node.right, query, k, threshold, results, maxDist);\n }\n } else {\n // Query is outside the ball: search right (outside) first\n searchVPTree(node.right, query, k, threshold, results, maxDist);\n // Only search left if the distance boundary overlaps\n if (dist - maxDist.value <= node.mu) {\n searchVPTree(node.left, query, k, threshold, results, maxDist);\n }\n }\n}\n\n/**\n * Create a VP-Tree (Vantage Point Tree) index for efficient approximate nearest neighbor search.\n *\n * O(log n) search on average, requires rebuild after batch additions.\n * Best for medium collections (1,000 - 100,000 vectors).\n *\n * @example\n * ```typescript\n * const index = createVPTreeIndex();\n *\n * // Add vectors\n * for (let i = 0; i < embeddings.length; i++) {\n * index.add(i, embeddings[i]);\n * }\n *\n * // Build the tree\n * index.rebuild();\n *\n * // Search\n * const results = index.search(queryEmbedding, 5, 0.9);\n * ```\n */\nexport function createVPTreeIndex(vpConfig: VPTreeIndexConfig = {}): ANNIndex {\n const { random = Math.random } = vpConfig;\n const items = new Map<number, Embedding>();\n let root: VPNode | null = null;\n let needsRebuild = false;\n let expectedDimension: number | null = null;\n\n function validateDimension(embedding: Embedding): void {\n if (expectedDimension === null) {\n expectedDimension = embedding.length;\n } else if (embedding.length !== expectedDimension) {\n throw new Error(\n `[Directive ANNIndex] Dimension mismatch: expected ${expectedDimension}, got ${embedding.length}`,\n );\n }\n }\n\n return {\n add(id: number, embedding: Embedding): void {\n validateDimension(embedding);\n items.set(id, embedding);\n needsRebuild = true;\n },\n\n remove(id: number): void {\n items.delete(id);\n needsRebuild = true;\n },\n\n search(query: Embedding, k: number, threshold = 0): ANNSearchResult[] {\n if (expectedDimension !== null && query.length !== expectedDimension) {\n throw new Error(\n `[Directive ANNIndex] Query dimension mismatch: expected ${expectedDimension}, got ${query.length}`,\n );\n }\n if (needsRebuild || !root) {\n // Fall back to brute force if tree is stale\n const results: ANNSearchResult[] = [];\n for (const [id, embedding] of items) {\n const similarity = cosineSimilarity(query, embedding);\n if (similarity >= threshold) {\n results.push({ id, similarity });\n }\n }\n results.sort((a, b) => b.similarity - a.similarity);\n return results.slice(0, k);\n }\n\n const results: ANNSearchResult[] = [];\n const maxDist = { value: Number.POSITIVE_INFINITY };\n searchVPTree(root, query, k, threshold, results, maxDist);\n return results;\n },\n\n rebuild(): void {\n const itemArray = Array.from(items.entries()).map(([id, embedding]) => ({\n id,\n embedding,\n }));\n root = buildVPTree(itemArray, random);\n needsRebuild = false;\n },\n\n size(): number {\n return items.size;\n },\n\n clear(): void {\n items.clear();\n root = null;\n needsRebuild = false;\n expectedDimension = null;\n },\n\n needsRebuild(): boolean {\n return needsRebuild;\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {isPrototypeSafe}from'@directive-run/core/internals';function R(t){if(!isPrototypeSafe(t))throw new Error("[Directive] structured-output: extracted JSON contains unsafe prototype keys")}var O=1048576;function k(t){if(t.length>O)throw new Error(`[Directive] Output too large for JSON extraction (${t.length} chars, max ${O}).`);let n=t.trim();try{let e=JSON.parse(n);return R(e),e}catch(e){if(e instanceof Error&&e.message.startsWith("[Directive] structured-output:"))throw e}let r=n.indexOf("{"),s=n.indexOf("["),i,f,l;if(r===-1&&s===-1)throw new Error("[Directive] No JSON object or array found in output");r===-1?(i=s,f="[",l="]"):s===-1?(i=r,f="{",l="}"):(i=Math.min(r,s),f=i===r?"{":"[",l=i===r?"}":"]");let p=0,d=false,g=false;for(let e=i;e<n.length;e++){let a=n[e];if(g){g=false;continue}if(a==="\\"){g=true;continue}if(a==='"'){d=!d;continue}if(!d){if(a===f)p++;else if(a===l&&(p--,p===0)){let u=n.slice(i,e+1),o;try{o=JSON.parse(u);}catch{let h=u.replace(/"(?:[^"\\]|\\.)*"/g,c=>c.replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t"));o=JSON.parse(h);}return R(o),o}}}throw new Error("[Directive] No valid JSON found in output")}function y(t){return t?t.issues&&t.issues.length>0?t.issues.map(n=>n.message).join("; "):t.message??"Validation failed":"Validation failed"}function J(t,n){let{schema:r,maxRetries:s=2,extractJson:i=k,schemaDescription:f}=n;if(!Number.isFinite(s)||s<0)throw new Error("[Directive] withStructuredOutput: maxRetries must be a non-negative finite number.");let l=f??r.description??"the specified JSON schema";return async(p,d,g)=>{let e={...p,instructions:(p.instructions??"")+`
|
|
2
|
+
|
|
3
|
+
IMPORTANT: Respond with valid JSON matching `+l+". Output ONLY the JSON object, no additional text or markdown formatting."},a,u;for(let o=0;o<=s;o++){let h=o===0?d:`${d}
|
|
4
|
+
|
|
5
|
+
Your previous response was not valid JSON. Error: ${u}
|
|
6
|
+
Please try again with valid JSON only.`,c=await t(e,h,g);a=c;let x=typeof c.output=="string"?c.output:JSON.stringify(c.output);try{let m=i(x),w=r.safeParse(m);if(w.success)return {...c,output:w.data};u=y(w.error);}catch(m){u=m instanceof Error?m.message:String(m);}}throw new S(`[Directive] Failed to get valid structured output after ${s+1} attempts: ${u}`,a)}}var S=class extends Error{lastResult;constructor(n,r){super(n),this.name="StructuredOutputError",this.lastResult=r;}};export{k as a,J as b,S as c};//# sourceMappingURL=chunk-UR4ZGO7V.js.map
|
|
7
|
+
//# sourceMappingURL=chunk-UR4ZGO7V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/structured-output.ts"],"names":["assertPrototypeSafe","value","isPrototypeSafe","MAX_EXTRACT_LENGTH","extractJsonFromOutput","output","trimmed","parsed","err","objectStart","arrayStart","start","openChar","closeChar","depth","inString","escaped","i","char","jsonStr","sanitized","match","formatValidationError","error","issue","withStructuredOutput","runner","config","schema","maxRetries","extractJson","schemaDescription","schemaPrompt","agent","input","options","structuredAgent","lastResult","lastError","attempt","effectiveInput","result","outputStr","extracted","StructuredOutputError","message"],"mappings":"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","file":"chunk-UR4ZGO7V.js","sourcesContent":["/**\n * P6: Structured Outputs — Schema validation with auto-retry for LLM responses.\n *\n * Turns unreliable text output into typed, validated data. Appends JSON schema\n * instructions to the system prompt and retries with error feedback on parse failure.\n *\n * Works with any Zod-compatible schema (any object with a `safeParse` method).\n *\n * @module\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n * import { withStructuredOutput, StructuredOutputError } from '@directive-run/ai';\n *\n * const SentimentSchema = z.object({\n * sentiment: z.enum([\"positive\", \"negative\", \"neutral\"]),\n * confidence: z.number().min(0).max(1),\n * });\n *\n * const runner = withStructuredOutput(baseRunner, {\n * schema: SentimentSchema,\n * maxRetries: 2,\n * });\n *\n * const result = await runner(agent, \"Analyze: I love this product!\");\n * // result.output is typed as { sentiment: string; confidence: number }\n * ```\n */\n\nimport { isPrototypeSafe } from \"@directive-run/core/internals\";\nimport type { AgentLike, AgentRunner, RunOptions, RunResult } from \"./types.js\";\n\n/**\n * Guard against prototype pollution in LLM-extracted JSON. LLM output is\n * attacker-controllable via prompt injection — payloads like\n * `{\"__proto__\":{\"polluted\":true}}` would otherwise seed pollution downstream.\n */\nfunction assertPrototypeSafe(value: unknown): void {\n if (!isPrototypeSafe(value)) {\n throw new Error(\n \"[Directive] structured-output: extracted JSON contains unsafe prototype keys\",\n );\n }\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Zod-compatible schema duck type — any object with a `safeParse` method.\n *\n * This interface allows structured outputs to work with Zod, Valibot,\n * or any validation library that implements this pattern.\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n *\n * // Zod schemas implement SafeParseable automatically\n * const schema = z.object({ name: z.string() });\n *\n * // Custom schema\n * const custom: SafeParseable<{ name: string }> = {\n * safeParse(value) {\n * if (typeof value === \"object\" && value && \"name\" in value) {\n * return { success: true, data: value as { name: string } };\n * }\n * return { success: false, error: { message: \"Missing name field\" } };\n * },\n * };\n * ```\n */\nexport interface SafeParseable<T = unknown> {\n safeParse(value: unknown): SafeParseResult<T>;\n /** Optional: schema description injected into the system prompt. */\n description?: string;\n}\n\nexport interface SafeParseResult<T> {\n success: boolean;\n data?: T;\n error?: { message?: string; issues?: Array<{ message: string }> };\n}\n\nexport interface StructuredOutputConfig<T = unknown> {\n /** Zod-compatible schema with safeParse. */\n schema: SafeParseable<T>;\n /** Max retries on parse/validation failure. @default 2 */\n maxRetries?: number;\n /** Custom JSON extractor. Default: finds first `{...}` or `[...]` in output. */\n extractJson?: (output: string) => unknown;\n /** Schema description to inject into system prompt. Auto-derived from schema.description if available. */\n schemaDescription?: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Maximum output length to process (1MB). */\nconst MAX_EXTRACT_LENGTH = 1_048_576;\n\n/** Default JSON extractor — finds the first `{...}` or `[...]` in output. */\nexport function extractJsonFromOutput(output: string): unknown {\n if (output.length > MAX_EXTRACT_LENGTH) {\n throw new Error(\n `[Directive] Output too large for JSON extraction (${output.length} chars, max ${MAX_EXTRACT_LENGTH}).`,\n );\n }\n\n const trimmed = output.trim();\n\n // Try direct parse first\n try {\n const parsed = JSON.parse(trimmed);\n assertPrototypeSafe(parsed);\n\n return parsed;\n } catch (err) {\n // Re-throw prototype-safety errors immediately — they are NOT parse errors\n if (\n err instanceof Error &&\n err.message.startsWith(\"[Directive] structured-output:\")\n ) {\n throw err;\n }\n // Continue to extraction on plain parse failures\n }\n\n // Try to find JSON object or array\n const objectStart = trimmed.indexOf(\"{\");\n const arrayStart = trimmed.indexOf(\"[\");\n\n let start: number;\n let openChar: string;\n let closeChar: string;\n\n if (objectStart === -1 && arrayStart === -1) {\n throw new Error(\"[Directive] No JSON object or array found in output\");\n }\n\n if (objectStart === -1) {\n start = arrayStart;\n openChar = \"[\";\n closeChar = \"]\";\n } else if (arrayStart === -1) {\n start = objectStart;\n openChar = \"{\";\n closeChar = \"}\";\n } else {\n start = Math.min(objectStart, arrayStart);\n openChar = start === objectStart ? \"{\" : \"[\";\n closeChar = start === objectStart ? \"}\" : \"]\";\n }\n\n // Find matching closing bracket\n let depth = 0;\n let inString = false;\n let escaped = false;\n\n for (let i = start; i < trimmed.length; i++) {\n const char = trimmed[i]!;\n\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n continue;\n }\n\n if (char === '\"') {\n inString = !inString;\n continue;\n }\n\n if (inString) {\n continue;\n }\n\n if (char === openChar) {\n depth++;\n } else if (char === closeChar) {\n depth--;\n if (depth === 0) {\n const jsonStr = trimmed.slice(start, i + 1);\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n // LLMs emit literal newlines inside JSON string values — escape them\n const sanitized = jsonStr.replace(/\"(?:[^\"\\\\]|\\\\.)*\"/g, (match) =>\n match\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\"),\n );\n\n parsed = JSON.parse(sanitized);\n }\n\n assertPrototypeSafe(parsed);\n\n return parsed;\n }\n }\n }\n\n throw new Error(\"[Directive] No valid JSON found in output\");\n}\n\n/** Format validation errors for feedback. */\nfunction formatValidationError(\n error: SafeParseResult<unknown>[\"error\"],\n): string {\n if (!error) {\n return \"Validation failed\";\n }\n\n if (error.issues && error.issues.length > 0) {\n return error.issues.map((issue) => issue.message).join(\"; \");\n }\n\n return error.message ?? \"Validation failed\";\n}\n\n// ============================================================================\n// Wrapper\n// ============================================================================\n\n/**\n * Wrap an AgentRunner with structured output parsing and validation.\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n *\n * const SentimentSchema = z.object({\n * sentiment: z.enum([\"positive\", \"negative\", \"neutral\"]),\n * confidence: z.number().min(0).max(1),\n * });\n *\n * const runner = withStructuredOutput(baseRunner, {\n * schema: SentimentSchema,\n * maxRetries: 2,\n * });\n *\n * const result = await runner(agent, \"Analyze: I love this product!\");\n * // result.output is typed as { sentiment: string; confidence: number }\n * ```\n */\nexport function withStructuredOutput<T = unknown>(\n runner: AgentRunner,\n config: StructuredOutputConfig<T>,\n): AgentRunner {\n const {\n schema,\n maxRetries = 2,\n extractJson = extractJsonFromOutput,\n schemaDescription,\n } = config;\n\n // Validate config\n if (!Number.isFinite(maxRetries) || maxRetries < 0) {\n throw new Error(\n \"[Directive] withStructuredOutput: maxRetries must be a non-negative finite number.\",\n );\n }\n\n const schemaPrompt =\n schemaDescription ?? schema.description ?? \"the specified JSON schema\";\n\n // The returned runner produces `T` from the schema. We cast at the\n // boundary to satisfy the `AgentRunner` generic while keeping output type-safe.\n return async <_T = unknown>(\n agent: AgentLike,\n input: string,\n options?: RunOptions,\n ): Promise<RunResult<_T>> => {\n // Append JSON instruction to agent's system prompt\n const structuredAgent: AgentLike = {\n ...agent,\n instructions:\n (agent.instructions ?? \"\") +\n \"\\n\\nIMPORTANT: Respond with valid JSON matching \" +\n schemaPrompt +\n \". \" +\n \"Output ONLY the JSON object, no additional text or markdown formatting.\",\n };\n\n let lastResult: RunResult<unknown> | undefined;\n let lastError: string | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n // On retries, append error feedback as additional input\n const effectiveInput =\n attempt === 0\n ? input\n : `${input}\\n\\nYour previous response was not valid JSON. Error: ${lastError}\\nPlease try again with valid JSON only.`;\n\n const result = await runner(structuredAgent, effectiveInput, options);\n lastResult = result;\n\n // Try to extract and validate JSON\n const outputStr =\n typeof result.output === \"string\"\n ? result.output\n : JSON.stringify(result.output);\n\n try {\n const extracted = extractJson(outputStr);\n const parsed = schema.safeParse(extracted);\n\n if (parsed.success) {\n return {\n ...result,\n output: parsed.data as _T,\n };\n }\n\n lastError = formatValidationError(parsed.error);\n } catch (err) {\n lastError = err instanceof Error ? err.message : String(err);\n }\n }\n\n // All retries exhausted — throw with context\n throw new StructuredOutputError(\n `[Directive] Failed to get valid structured output after ${maxRetries + 1} attempts: ${lastError}`,\n lastResult,\n );\n };\n}\n\n/** Error thrown when structured output parsing fails after all retries. */\nexport class StructuredOutputError extends Error {\n readonly lastResult: RunResult<unknown> | undefined;\n\n constructor(message: string, lastResult?: RunResult<unknown>) {\n super(message);\n this.name = \"StructuredOutputError\";\n this.lastResult = lastResult;\n }\n}\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {t}from'@directive-run/core';var n=class extends Error{code;guardrailName;guardrailType;userMessage;agentName;constructor(e){super(e.message,{cause:e.cause}),this.name="GuardrailError",this.code=e.code,this.guardrailName=e.guardrailName,this.guardrailType=e.guardrailType,this.userMessage=e.userMessage??e.message,this.agentName=e.agentName,Object.defineProperty(this,"input",{value:e.input,enumerable:false,writable:false,configurable:false}),Object.defineProperty(this,"data",{value:e.data,enumerable:false,writable:false,configurable:false});}toJSON(){return {name:this.name,code:this.code,message:this.message,guardrailName:this.guardrailName,guardrailType:this.guardrailType,userMessage:this.userMessage,agentName:this.agentName}}};function g(r){return r instanceof n}var a="__agent",o="__approval",s="__conversation",i="__toolCalls",u="__breakpoints";var d="__scratchpad",l={facts:{[a]:t.object(),[o]:t.object(),[s]:t.array(),[i]:t.array(),[u]:t.object()},derivations:{},events:{},requirements:{}};export{n as a,g as b,a as c,o as d,s as e,i as f,u as g,d as h,l as i};//# sourceMappingURL=chunk-UR5BMWEN.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-UR5BMWEN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"],"mappings":"oCA8jBO,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,EAAG,CAAA,CAAE,QAAO,CACtB,CAACC,CAAY,EAAG,EAAE,MAAA,EAAO,CACzB,CAACC,CAAgB,EAAG,EAAE,KAAA,EAAM,CAC5B,CAACC,CAAc,EAAG,CAAA,CAAE,KAAA,GACpB,CAACC,CAAc,EAAG,CAAA,CAAE,MAAA,EACtB,CAAA,CACA,WAAA,CAAa,EAAC,CACd,MAAA,CAAQ,EAAC,CACT,YAAA,CAAc,EAChB","file":"chunk-UR5BMWEN.js","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"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var x=new Set(["agent_start","agent_complete","agent_error","agent_retry","guardrail_check","constraint_evaluate","resolver_start","resolver_complete","resolver_error","approval_request","approval_response","handoff_start","handoff_complete","pattern_start","pattern_complete","dag_node_update","breakpoint_hit","breakpoint_resumed","derivation_update","scratchpad_update","reflection_iteration","race_start","race_winner","race_cancelled","debate_round","reroute","checkpoint_save","checkpoint_restore","task_start","task_complete","task_error","task_progress","goal_step"]),A=new Set(["__proto__","constructor","prototype","toString","valueOf","hasOwnProperty"]);function H(l={}){let g=l.maxEvents??2e3,m=l.goToSnapshot;if(!Number.isFinite(g)||g<1)throw new Error("[Directive DebugTimeline] maxEvents must be >= 1");let t=[],o=0,p=new Set;return {record(s){let n={...s,id:o++};t.push(n);let i=t.length-g;i>0&&t.splice(0,i);for(let a of p)try{a(n);}catch(c){typeof process<"u"&&process.env?.NODE_ENV!=="production"&&console.error("[Directive DebugTimeline] Listener threw:",c instanceof Error?c.message:c);}return n},getEvents(){return [...t]},getEventsForAgent(s){return t.filter(n=>n.agentId===s)},getEventsByType(s){return t.filter(n=>n.type===s)},getEventsAtSnapshot(s){return t.filter(n=>n.snapshotId===s)},getEventsInRange(s,n){return t.filter(i=>i.timestamp>=s&&i.timestamp<=n)},forkFrom(s){let n=-1;for(let i=t.length-1;i>=0;i--)if(t[i].snapshotId!==null&&t[i].snapshotId<=s){n=t[i].id;break}if(n>=0){let i=t.length;for(let a=t.length-1;a>=0;a--)if(t[a].id<=n){i=a+1;break}t=t.slice(0,i);}else t=[];m&&m(s);},export(){return JSON.stringify({version:1,events:t,nextId:o})},import(s){let n;try{n=JSON.parse(s);}catch{throw new Error("[Directive DebugTimeline] Invalid JSON")}if(!n||typeof n!="object")throw new Error("[Directive DebugTimeline] Invalid timeline data");for(let c of Object.keys(n))if(A.has(c))throw new Error(`[Directive DebugTimeline] Blocked key in import: ${c}`);let i=n;if(!Array.isArray(i.events))throw new Error("[Directive DebugTimeline] Missing events array");let a=[];for(let c of i.events){if(!c||typeof c!="object")continue;for(let D of Object.keys(c))if(A.has(D))throw new Error(`[Directive DebugTimeline] Blocked key in event: ${D}`);let b=c;typeof b.id=="number"&&typeof b.type=="string"&&x.has(b.type)&&typeof b.timestamp=="number"&&a.push(c);}t=a.length>g?a.slice(-g):a,o=typeof i.nextId=="number"?i.nextId:a.length;},clear(){t=[],o=0;},subscribe(s){return p.add(s),()=>{p.delete(s);}},get length(){return t.length}}}function L(l,g){let m=new Map;return {name:"directive-ai-debug-timeline",onConstraintEvaluate(t,o){l.record({type:"constraint_evaluate",timestamp:Date.now(),snapshotId:g(),constraintId:t,fired:o});},onResolverStart(t,o){m.set(t,Date.now()),l.record({type:"resolver_start",timestamp:Date.now(),snapshotId:g(),resolverId:t,requirementType:o.requirement.type});},onResolverComplete(t){let o=m.get(t);m.delete(t),l.record({type:"resolver_complete",timestamp:Date.now(),snapshotId:g(),resolverId:t,durationMs:o?Date.now()-o:0});},onResolverError(t,o,p){let h=m.get(t);m.delete(t);let s=p instanceof Error?p.message:String(p);l.record({type:"resolver_error",timestamp:Date.now(),snapshotId:g(),resolverId:t,errorMessage:s,durationMs:h?Date.now()-h:0});}}}var T={successRate:.5,latency:.3,circuitState:.2};function I(l={}){let g=l.windowMs??6e4,m=l.maxNormalLatencyMs??5e3,t=l.maxEventsPerAgent??1e3,o={successRate:l.weights?.successRate??T.successRate,latency:l.weights?.latency??T.latency,circuitState:l.weights?.circuitState??T.circuitState};if(!Number.isFinite(g)||g<=0)throw new Error("[Directive HealthMonitor] windowMs must be a positive number");if(!Number.isFinite(m)||m<=0)throw new Error("[Directive HealthMonitor] maxNormalLatencyMs must be a positive number");if(!Number.isFinite(t)||t<1)throw new Error("[Directive HealthMonitor] maxEventsPerAgent must be >= 1");for(let[r,e]of Object.entries(o))if(e<0||e>1)throw new Error(`[Directive HealthMonitor] weight "${r}" must be between 0 and 1 (got ${e})`);let p=o.successRate+o.latency+o.circuitState;if(Math.abs(p-1)>.01)throw new Error(`[Directive HealthMonitor] weights must sum to ~1.0 (tolerance: \xB10.01, got ${p.toFixed(4)})`);let h=new Map,s=new Map,n=0,i=null,a=-1;function c(r){let e=h.get(r);return e||(e=[],h.set(r,e)),e}function b(r,e){let v=e-g,u=0;for(;u<r.length&&r[u].timestamp<v;)u++;let E=r.length-u-t;E>0&&(u+=E),u>0&&r.splice(0,u);}function D(r){let e=h.get(r);if(!e||e.length===0)return 50;let v=Date.now();if(b(e,v),e.length===0)return 50;let E=e.filter(M=>M.success).length/e.length,_=e.reduce((M,R)=>M+R.latencyMs,0)/e.length,y=Math.min(_/m,1),f=s.get(r)??"CLOSED",d=f==="CLOSED"?1:f==="HALF_OPEN"?.5:0,w=E*o.successRate+(1-y)*o.latency+d*o.circuitState;return Math.round(w*100)}function S(r){let e=c(r),v=Date.now();b(e,v);let u=e.filter(d=>d.success).length,E=e.length-u,_=e.length>0?u/e.length:0,y=e.length>0?e.reduce((d,w)=>d+w.latencyMs,0)/e.length:0,f=[];for(let d=e.length-1;d>=0&&f.length<5;d--)e[d].errorMessage&&f.unshift(e[d].errorMessage);return {agentId:r,circuitState:s.get(r)??"CLOSED",successRate:_,avgLatencyMs:y,recentFailures:E,recentSuccesses:u,healthScore:D(r),lastErrors:f}}return {recordSuccess(r,e){let v=c(r);v.push({success:true,latencyMs:e,timestamp:Date.now()}),b(v,Date.now()),n++;},recordFailure(r,e,v){let u=c(r);u.push({success:false,latencyMs:e,timestamp:Date.now(),errorMessage:v?.message}),b(u,Date.now()),n++;},getMetrics(r){return S(r)},getAllMetrics(){if(n===a&&i)return i;let r=Object.create(null);for(let e of h.keys())r[e]=S(e);return i=r,a=n,r},getHealthScore(r){return D(r)},updateCircuitState(r,e){s.set(r,e),n++;},reset(){h.clear(),s.clear(),n++,i=null,a=-1;}}}exports.a=H;exports.b=L;exports.c=I;//# sourceMappingURL=chunk-WOFIBIPW.cjs.map
|
|
2
|
+
//# sourceMappingURL=chunk-WOFIBIPW.cjs.map
|