@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,11 @@
|
|
|
1
|
+
function O(i,a=false){let c=false,g=[],s=[],P=a?(m,...v)=>console.debug(`[MCP Stub] ${m}`,...v):()=>{};return {async connect(){P(`Connecting to ${i.name} (${i.transport})`),c=true;},async disconnect(){c=false;},isConnected(){return c},getCapabilities(){return {tools:true,resources:true,prompts:true}},async listTools(){return g},async callTool(m,v){return P(`Calling tool ${m}`,v),{content:[{type:"text",text:`Stub result for ${m}`}]}},async listResources(){return s},async readResource(m){return P(`Reading resource ${m}`),{contents:[{uri:m,text:`Stub content for ${m}`}]}},async listPrompts(){return []},async getPrompt(m){return {messages:[{role:"user",content:{type:"text",text:`Stub prompt ${m}`}}]}}}}function _(i,a,c){let g=Date.now(),s=i.get(a);return !s||g>s.resetTime?(i.set(a,{count:1,resetTime:g+6e4}),true):s.count>=c?false:(s.count++,true)}function F(i){let{servers:a,toolConstraints:c={},resourceMappings:g=[],events:s={},autoConnect:P=false,autoReconnect:m=true,debug:v=false,allowDirectCalls:h=false}=i;!i.clientFactory&&(typeof process<"u"&&process.env?.NODE_ENV==="production"?console.warn(`[Directive MCP] WARNING: Using stub MCP client in production!
|
|
2
|
+
The stub client returns mock data and does not connect to real MCP servers.
|
|
3
|
+
Provide a real 'clientFactory' option to connect to actual MCP servers:
|
|
4
|
+
|
|
5
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
6
|
+
|
|
7
|
+
const adapter = createMCPAdapter({
|
|
8
|
+
servers: [...],
|
|
9
|
+
clientFactory: (config) => new Client(config),
|
|
10
|
+
});`):v&&console.debug("[Directive MCP] Using stub client for development. Provide 'clientFactory' for production use."));let b=i.clientFactory??(e=>O(e,v)),A=i.approvalTimeoutMs??3e5,n={servers:new Map,toolConstraints:new Map(Object.entries(c)),rateLimiters:new Map,pendingApprovals:new Map,approvedRequests:new Set,rejectedRequests:new Set},E=0,d=new Map,M=new Map;function D(e){return new Promise((t,r)=>{if(n.approvedRequests.has(e)){n.approvedRequests.delete(e),n.pendingApprovals.delete(e),s.onApprovalResolved?.(e,true),t();return}if(n.rejectedRequests.has(e)){n.rejectedRequests.delete(e),n.pendingApprovals.delete(e);let l=M.get(e);M.delete(e),s.onApprovalResolved?.(e,false),r(new Error(`[Directive MCP] Tool call request ${e} was rejected${l?`: ${l}`:""}`));return}let o=setTimeout(()=>{d.delete(e),n.pendingApprovals.delete(e),r(new Error(`[Directive MCP] Approval timeout: Request ${e} was not approved or rejected within ${A}ms. Call adapter.approve("${e}") or adapter.reject("${e}") to resolve.`));},A);d.set(e,{resolve:t,reject:r,timeoutId:o});})}function $(e,t,r){let o=d.get(e);o?(clearTimeout(o.timeoutId),d.delete(e),n.pendingApprovals.delete(e),s.onApprovalResolved?.(e,t),t?o.resolve():o.reject(new Error(`[Directive MCP] Tool call request ${e} was rejected${r?`: ${r}`:""}`))):(t?n.approvedRequests.add(e):(n.rejectedRequests.add(e),r&&M.set(e,r)),setTimeout(()=>{n.approvedRequests.delete(e),n.rejectedRequests.delete(e),M.delete(e),n.pendingApprovals.delete(e);},A));}let w=new Map;for(let e of a)n.servers.set(e.name,{config:e,client:null,tools:[],resources:[],status:"disconnected"}),w.set(e.name,{timer:null,attempts:0,maxAttempts:e.retry?.maxAttempts??10,baseDelay:e.retry?.backoffMs??5e3});function x(e){let t=/[;|&$`><]/;if(e.command&&t.test(e.command))throw new Error(`[Directive MCP] Stdio command for server '${e.name}' contains shell metacharacters: '${e.command}'. This may indicate a command injection vulnerability. Use 'args' for command arguments instead.`);if(e.args){for(let r of e.args)if(t.test(r))throw new Error(`[Directive MCP] Stdio argument for server '${e.name}' contains shell metacharacters: '${r}'. This may indicate a command injection vulnerability.`)}}async function S(e){let t=n.servers.get(e);if(!t)throw new Error(`Unknown MCP server: ${e}`);if(t.status!=="connected"){t.config.transport==="stdio"&&x(t.config),t.status="connecting";try{let r=b(t.config);await r.connect(),t.client=r,t.status="connected";let o=w.get(e);o&&(o.attempts=0,o.timer&&(clearTimeout(o.timer),o.timer=null)),r.getCapabilities().tools&&(t.tools=await r.listTools()),r.getCapabilities().resources&&(t.resources=await r.listResources()),t.lastSync=Date.now(),s.onConnect?.(e);}catch(r){if(t.status="error",t.error=r instanceof Error?r:new Error(String(r)),s.onError?.(e,t.error),m){let o=w.get(e);if(o&&o.attempts<o.maxAttempts){o.attempts++;let l=Math.min(o.baseDelay*2**(o.attempts-1)+Math.random()*1e3,6e4);o.timer=setTimeout(()=>{o.timer=null,S(e).catch(()=>{});},l);}else o&&console.error(`[Directive MCP] Max reconnect attempts (${o.maxAttempts}) reached for server '${e}'. Call adapter.connectServer("${e}") to retry manually.`);}throw t.error}}}async function T(e){let t=w.get(e);t?.timer&&(clearTimeout(t.timer),t.timer=null,t.attempts=0);let r=n.servers.get(e);if(!(!r||!r.client))try{await r.client.disconnect();}finally{r.status="disconnected",r.client=null,s.onDisconnect?.(e);}}async function k(e,t,r,o){let l=n.servers.get(e);if(!l)throw new Error(`[Directive MCP] Unknown server '${e}'. Available servers: ${Array.from(n.servers.keys()).join(", ")||"(none)"}`);if(!l.client)throw new Error(`[Directive MCP] Server '${e}' is not connected. Call 'adapter.connect()' or 'adapter.connectServer("${e}")' first.`);let f=`${e}.${t}`,u=n.toolConstraints.get(f);if(u){if(u.rateLimit){let p=n.rateLimiters.get(f);if(!_(n.rateLimiters,f,u.rateLimit)){let C=p?.resetTime?new Date(p.resetTime).toISOString():"unknown";throw new Error(`[Directive MCP] Rate limit exceeded for '${f}': ${p?.count??0}/${u.rateLimit} requests per minute. Resets at ${C}.`)}}if(u.maxArgSize){let p=JSON.stringify(r).length;if(p>u.maxArgSize)throw new Error(`Arguments exceed max size (${p} > ${u.maxArgSize})`)}if(u.when&&!await u.when(o,r))throw new Error(`Constraint not satisfied for ${f}`);if(u.requireApproval){let p=`approval-${++E}-${Date.now()}`,C={id:p,server:e,tool:t,args:r,requestedAt:Date.now()};n.pendingApprovals.set(p,C),s.onApprovalRequest?.(C),await D(p);}}s.onToolCall?.(e,t,r);let R=await Promise.race([l.client.callTool(t,r),new Promise((p,C)=>setTimeout(()=>C(new Error(`Tool call timeout: ${f}`)),u?.timeout??3e4))]);return s.onToolResult?.(e,t,R),R}let j={name:"mcp-adapter",onInit:async()=>{P&&await Promise.all(Array.from(n.servers.keys()).map(e=>S(e).catch(t=>console.error(`Failed to connect to ${e}:`,t))));},onDestroy:async()=>{for(let e of w.values())e.timer&&(clearTimeout(e.timer),e.timer=null);for(let[,e]of d)clearTimeout(e.timeoutId),e.reject(new Error("[Directive MCP] Adapter destroyed while awaiting approval"));d.clear(),await Promise.all(Array.from(n.servers.keys()).map(e=>T(e).catch(t=>console.error(`Failed to disconnect from ${e}:`,t))));}};async function L(e){for(let t of g)for(let[r,o]of n.servers)if(o.client){for(let l of o.resources)if(typeof t.pattern=="string"?U(l.uri,t.pattern):t.pattern.test(l.uri))try{let u=await o.client.readResource(l.uri),R=u.contents[0]?.text??"",p=t.transform?t.transform(R):R;e[t.factKey]=p,s.onResourceUpdate?.(r,l.uri,u);}catch(u){console.error(`Failed to sync resource ${l.uri}:`,u);}}}return {plugin:j,async connect(){await Promise.all(Array.from(n.servers.keys()).map(S));},connectServer:S,async disconnect(){await Promise.all(Array.from(n.servers.keys()).map(T));},disconnectServer:T,getTools(){let e=new Map;for(let[t,r]of n.servers)e.set(t,r.tools);return e},getResources(){let e=new Map;for(let[t,r]of n.servers)e.set(t,r.resources);return e},async callTool(e,t,r,o){return k(e,t,r,o)},async callToolDirect(e,t,r){if(!h)throw new Error("[Directive] callToolDirect is disabled by default. Pass { allowDirectCalls: true } to enable unconstrained tool calls.");process.env.NODE_ENV!=="production"&&console.warn("[Directive] callToolDirect bypasses all constraints (rate limits, approvals, timeouts).");let o=n.servers.get(e);if(!o)throw new Error(`[Directive MCP] Unknown server '${e}'. Available servers: ${Array.from(n.servers.keys()).join(", ")||"(none)"}`);if(!o.client)throw new Error(`[Directive MCP] Server '${e}' is not connected. Call 'adapter.connect()' or 'adapter.connectServer("${e}")' first.`);s.onToolCall?.(e,t,r);let l=await o.client.callTool(t,r);return s.onToolResult?.(e,t,l),l},async readResource(e,t){let r=n.servers.get(e);if(!r)throw new Error(`[Directive MCP] Unknown server '${e}'. Available servers: ${Array.from(n.servers.keys()).join(", ")||"(none)"}`);if(!r.client)throw new Error(`[Directive MCP] Server '${e}' is not connected. Call 'adapter.connect()' or 'adapter.connectServer("${e}")' first.`);let o=await r.client.readResource(t);return s.onResourceUpdate?.(e,t,o),o},syncResources:L,getServerStatus(e){return n.servers.get(e)},getAllServerStatuses(){return new Map(n.servers)},approve(e){if(!n.pendingApprovals.get(e)&&!d.has(e))throw new Error(`[Directive MCP] No pending approval request with ID '${e}'. Pending requests: ${Array.from(n.pendingApprovals.keys()).join(", ")||"(none)"}`);$(e,true);},reject(e,t){if(!n.pendingApprovals.get(e)&&!d.has(e))throw new Error(`[Directive MCP] No pending approval request with ID '${e}'. Pending requests: ${Array.from(n.pendingApprovals.keys()).join(", ")||"(none)"}`);$(e,false,t);},getPendingApprovals(){return Array.from(n.pendingApprovals.values())},getRejectionReason(e){return M.get(e)}}}var y=new Map,N=200;function U(i,a){let c=y.get(a);if(!c){let g=a.replace(/\*\*/g,"\0GLOBSTAR\0").replace(/\*/g,"\0STAR\0").replace(/\?/g,"\0QUESTION\0").replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\0GLOBSTAR\0/g,".*").replace(/\0STAR\0/g,"[^/]*").replace(/\0QUESTION\0/g,".");if(c=new RegExp(`^${g}$`),y.size>=N){let s=y.keys().next().value;s!==void 0&&y.delete(s);}y.set(a,c);}return c.test(i)}function G(i){let a=[];for(let[c,g]of i)for(let s of g)a.push({type:"function",function:{name:`${c}.${s.name}`,description:s.description??`Tool: ${s.name}`,parameters:s.inputSchema}});return a}function z(i,a,c){return {type:"MCP_CALL_TOOL",server:i,tool:a,args:c}}function B(i,a){return {type:"MCP_READ_RESOURCE",server:i,uri:a}}function K(i,a,c){return {type:"MCP_GET_PROMPT",server:i,prompt:a,args:c}}function W(i,a){return {type:"MCP_SYNC_RESOURCES",server:i,pattern:a}}export{F as a,G as b,z as c,B as d,K as e,W as f};//# sourceMappingURL=chunk-NNAQ4ZH2.js.map
|
|
11
|
+
//# sourceMappingURL=chunk-NNAQ4ZH2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts"],"names":["createStubClient","config","debug","connected","tools","resources","log","msg","args","name","uri","checkRateLimit","rateLimiters","key","limit","now","limiter","createMCPAdapter","servers","toolConstraints","resourceMappings","events","autoConnect","autoReconnect","allowDirectCalls","clientFactory","serverConfig","approvalTimeoutMs","state","approvalCounter","approvalWaiters","rejectionReasons","waitForApproval","requestId","resolve","reject","reason","timeoutId","resolveApproval","approved","waiter","reconnectState","validateStdioCommand","shellMetachars","arg","connectServer","serverState","client","rState","error","delay","disconnectServer","callToolWithConstraints","server","tool","facts","constraintKey","constraint","resetAt","argSize","approvalRequest","result","_","plugin","e","syncResources","mapping","serverName","resource","matchGlob","content","value","globCache","MAX_GLOB_CACHE_SIZE","str","pattern","regex","regexPattern","firstKey","convertToolsForLLM","serverTools","mcpCallTool","mcpReadResource","mcpGetPrompt","prompt","mcpSyncResources"],"mappings":"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","file":"chunk-NNAQ4ZH2.js","sourcesContent":["/**\n * MCP Adapter - Model Context Protocol Integration for Directive\n *\n * Provides seamless integration between Directive's constraint system and MCP servers:\n * - MCP tools become Directive resolvers with constraint-driven access control\n * - MCP resources sync to Directive facts\n * - MCP prompts available through requirements\n *\n * @example\n * ```typescript\n * import { createMCPAdapter } from '@directive-run/ai';\n *\n * const mcpAdapter = createMCPAdapter({\n * servers: [\n * { name: 'filesystem', transport: 'stdio', command: 'mcp-server-filesystem' },\n * { name: 'github', transport: 'sse', url: 'https://mcp.github.com' }\n * ],\n * toolConstraints: {\n * 'filesystem.write': { requireApproval: true },\n * 'github.create_pr': { when: (facts) => facts.reviewComplete }\n * }\n * });\n *\n * const system = createSystem({\n * module: myModule,\n * plugins: [mcpAdapter.plugin]\n * });\n * ```\n */\n\nimport type { Plugin } from \"@directive-run/core\";\nimport type {\n MCPAdapterConfig,\n MCPApprovalRequest,\n MCPCallToolRequirement,\n MCPClient,\n MCPGetPromptRequirement,\n MCPReadResourceRequirement,\n MCPResource,\n MCPResourceMapping,\n MCPResourceResult,\n MCPServerConfig,\n MCPSyncResourcesRequirement,\n MCPTool,\n MCPToolConstraint,\n MCPToolResult,\n} from \"./mcp-types.js\";\n\n// ============================================================================\n// MCP Adapter State\n// ============================================================================\n\n/** State of an MCP server connection */\ninterface MCPServerState {\n config: MCPServerConfig;\n client: MCPClient | null;\n tools: MCPTool[];\n resources: MCPResource[];\n status: \"disconnected\" | \"connecting\" | \"connected\" | \"error\";\n error?: Error;\n lastSync?: number;\n}\n\n/** Internal state for the adapter */\ninterface MCPAdapterState {\n servers: Map<string, MCPServerState>;\n toolConstraints: Map<string, MCPToolConstraint>;\n resourceMappings: MCPResourceMapping[];\n rateLimiters: Map<string, { count: number; resetTime: number }>;\n /** Pending approval requests */\n pendingApprovals: Map<string, MCPApprovalRequest>;\n /** Approved request IDs */\n approvedRequests: Set<string>;\n /** Rejected request IDs */\n rejectedRequests: Set<string>;\n}\n\n// ============================================================================\n// MCP Adapter Instance\n// ============================================================================\n\n/** MCP Adapter instance */\nexport interface MCPAdapter {\n /** Plugin to add to Directive system */\n plugin: Plugin;\n /** Connect to all configured servers */\n connect(): Promise<void>;\n /** Connect to a specific server */\n connectServer(name: string): Promise<void>;\n /** Disconnect from all servers */\n disconnect(): Promise<void>;\n /** Disconnect from a specific server */\n disconnectServer(name: string): Promise<void>;\n /** Get all available tools across all servers */\n getTools(): Map<string, MCPTool[]>;\n /** Get all available resources across all servers */\n getResources(): Map<string, MCPResource[]>;\n /**\n * Call a tool with constraint checking (recommended).\n * Applies rate limits, argument size limits, approval workflow, and custom constraints.\n * @param server - Server name\n * @param tool - Tool name\n * @param args - Tool arguments\n * @param facts - Current facts for constraint evaluation\n */\n callTool(\n server: string,\n tool: string,\n args: Record<string, unknown>,\n facts: Record<string, unknown>,\n ): Promise<MCPToolResult>;\n /**\n * Call a tool directly, bypassing all constraints (rate limits, approvals, etc.).\n * Use only for trusted internal calls where constraint checking is not needed.\n */\n callToolDirect(\n server: string,\n tool: string,\n args: Record<string, unknown>,\n ): Promise<MCPToolResult>;\n /** Read a resource directly */\n readResource(server: string, uri: string): Promise<MCPResourceResult>;\n /** Sync resources to facts */\n syncResources(facts: Record<string, unknown>): Promise<void>;\n /** Get server status */\n getServerStatus(name: string): MCPServerState | undefined;\n /** Get all server statuses */\n getAllServerStatuses(): Map<string, MCPServerState>;\n /** Approve a pending tool call request */\n approve(requestId: string): void;\n /** Reject a pending tool call request */\n reject(requestId: string, reason?: string): void;\n /** Get pending approval requests */\n getPendingApprovals(): MCPApprovalRequest[];\n /** Get the rejection reason for a request (if available) */\n getRejectionReason(requestId: string): string | undefined;\n}\n\n// ============================================================================\n// Default MCP Client (Stub)\n// ============================================================================\n\n/**\n * Create a stub MCP client for development/testing.\n *\n * **Important:** This stub is for development only. In production, provide\n * a real MCP client via the `clientFactory` option:\n *\n * @example\n * ```typescript\n * import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\n *\n * const adapter = createMCPAdapter({\n * servers: [...],\n * clientFactory: (config) => new Client(config),\n * });\n * ```\n *\n * @param config - Server configuration\n * @param debug - Enable debug logging (default: false)\n */\nfunction createStubClient(config: MCPServerConfig, debug = false): MCPClient {\n let connected = false;\n const tools: MCPTool[] = [];\n const resources: MCPResource[] = [];\n\n const log = debug\n ? (msg: string, ...args: unknown[]) =>\n console.debug(`[MCP Stub] ${msg}`, ...args)\n : () => {};\n\n return {\n async connect() {\n log(`Connecting to ${config.name} (${config.transport})`);\n connected = true;\n },\n async disconnect() {\n connected = false;\n },\n isConnected() {\n return connected;\n },\n getCapabilities() {\n return { tools: true, resources: true, prompts: true };\n },\n async listTools() {\n return tools;\n },\n async callTool(name: string, args: Record<string, unknown>) {\n log(`Calling tool ${name}`, args);\n return {\n content: [{ type: \"text\" as const, text: `Stub result for ${name}` }],\n };\n },\n async listResources() {\n return resources;\n },\n async readResource(uri: string) {\n log(`Reading resource ${uri}`);\n return {\n contents: [{ uri, text: `Stub content for ${uri}` }],\n };\n },\n async listPrompts() {\n return [];\n },\n async getPrompt(name: string) {\n return {\n messages: [\n {\n role: \"user\" as const,\n content: { type: \"text\" as const, text: `Stub prompt ${name}` },\n },\n ],\n };\n },\n };\n}\n\n// ============================================================================\n// Rate Limiter\n// ============================================================================\n\nfunction checkRateLimit(\n rateLimiters: Map<string, { count: number; resetTime: number }>,\n key: string,\n limit: number,\n): boolean {\n const now = Date.now();\n const limiter = rateLimiters.get(key);\n\n if (!limiter || now > limiter.resetTime) {\n rateLimiters.set(key, { count: 1, resetTime: now + 60000 });\n return true;\n }\n\n if (limiter.count >= limit) {\n return false;\n }\n\n limiter.count++;\n return true;\n}\n\n// ============================================================================\n// MCP Adapter Factory\n// ============================================================================\n\n/**\n * Create an MCP adapter for Directive integration.\n *\n * @example\n * ```typescript\n * const adapter = createMCPAdapter({\n * servers: [\n * { name: 'fs', transport: 'stdio', command: 'mcp-server-filesystem' },\n * ],\n * toolConstraints: {\n * 'fs.write_file': {\n * requireApproval: true,\n * maxArgSize: 10000,\n * timeout: 30000,\n * },\n * },\n * resourceMappings: [\n * {\n * pattern: 'file://*.json',\n * factKey: 'jsonFiles',\n * mode: 'poll',\n * pollInterval: 5000,\n * },\n * ],\n * });\n *\n * // Add to system\n * const system = createSystem({\n * module: myModule,\n * plugins: [adapter.plugin],\n * });\n *\n * // Connect to servers\n * await adapter.connect();\n * ```\n */\nexport function createMCPAdapter(config: MCPAdapterConfig): MCPAdapter {\n const {\n servers,\n toolConstraints = {},\n resourceMappings = [],\n events = {},\n autoConnect = false,\n autoReconnect = true,\n debug = false,\n allowDirectCalls = false,\n } = config;\n\n // Warn if using stub client in production\n const usingStubClient = !config.clientFactory;\n if (usingStubClient) {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n if (isProduction) {\n console.warn(\n \"[Directive MCP] WARNING: Using stub MCP client in production!\\n\" +\n \"The stub client returns mock data and does not connect to real MCP servers.\\n\" +\n \"Provide a real 'clientFactory' option to connect to actual MCP servers:\\n\\n\" +\n \" import { Client } from '@modelcontextprotocol/sdk/client/index.js';\\n\\n\" +\n \" const adapter = createMCPAdapter({\\n\" +\n \" servers: [...],\\n\" +\n \" clientFactory: (config) => new Client(config),\\n\" +\n \" });\",\n );\n } else if (debug) {\n console.debug(\n \"[Directive MCP] Using stub client for development. \" +\n \"Provide 'clientFactory' for production use.\",\n );\n }\n }\n\n const clientFactory =\n config.clientFactory ??\n ((serverConfig: MCPServerConfig) => createStubClient(serverConfig, debug));\n const approvalTimeoutMs = config.approvalTimeoutMs ?? 300000;\n\n // Initialize state\n const state: MCPAdapterState = {\n servers: new Map(),\n toolConstraints: new Map(Object.entries(toolConstraints)),\n resourceMappings,\n rateLimiters: new Map(),\n pendingApprovals: new Map(),\n approvedRequests: new Set(),\n rejectedRequests: new Set(),\n };\n\n // Approval ID counter\n let approvalCounter = 0;\n\n // Promise-based approval waiting (no polling)\n const approvalWaiters = new Map<\n string,\n {\n resolve: () => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n }\n >();\n\n // Rejection reasons storage\n const rejectionReasons = new Map<string, string>();\n\n // Wait for approval with timeout - Promise-based, no polling\n function waitForApproval(requestId: string): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if already resolved\n if (state.approvedRequests.has(requestId)) {\n state.approvedRequests.delete(requestId);\n state.pendingApprovals.delete(requestId);\n events.onApprovalResolved?.(requestId, true);\n resolve();\n return;\n }\n if (state.rejectedRequests.has(requestId)) {\n state.rejectedRequests.delete(requestId);\n state.pendingApprovals.delete(requestId);\n const reason = rejectionReasons.get(requestId);\n rejectionReasons.delete(requestId);\n events.onApprovalResolved?.(requestId, false);\n reject(\n new Error(\n `[Directive MCP] Tool call request ${requestId} was rejected${reason ? `: ${reason}` : \"\"}`,\n ),\n );\n return;\n }\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n approvalWaiters.delete(requestId);\n state.pendingApprovals.delete(requestId);\n reject(\n new Error(\n `[Directive MCP] Approval timeout: Request ${requestId} was not approved or rejected within ${approvalTimeoutMs}ms. ` +\n `Call adapter.approve(\"${requestId}\") or adapter.reject(\"${requestId}\") to resolve.`,\n ),\n );\n }, approvalTimeoutMs);\n\n // Store waiter for later resolution\n approvalWaiters.set(requestId, { resolve, reject, timeoutId });\n });\n }\n\n // Resolve an approval (called by approve/reject)\n function resolveApproval(\n requestId: string,\n approved: boolean,\n reason?: string,\n ): void {\n const waiter = approvalWaiters.get(requestId);\n if (waiter) {\n clearTimeout(waiter.timeoutId);\n approvalWaiters.delete(requestId);\n state.pendingApprovals.delete(requestId);\n events.onApprovalResolved?.(requestId, approved);\n\n if (approved) {\n waiter.resolve();\n } else {\n waiter.reject(\n new Error(\n `[Directive MCP] Tool call request ${requestId} was rejected${reason ? `: ${reason}` : \"\"}`,\n ),\n );\n }\n } else {\n // Waiter not yet created, store for immediate resolution with TTL cleanup\n if (approved) {\n state.approvedRequests.add(requestId);\n } else {\n state.rejectedRequests.add(requestId);\n if (reason) {\n rejectionReasons.set(requestId, reason);\n }\n }\n // Auto-cleanup pre-resolved state after approval timeout to prevent memory leaks\n setTimeout(() => {\n state.approvedRequests.delete(requestId);\n state.rejectedRequests.delete(requestId);\n rejectionReasons.delete(requestId);\n state.pendingApprovals.delete(requestId);\n }, approvalTimeoutMs);\n }\n }\n\n // Track reconnect state per server\n const reconnectState = new Map<\n string,\n {\n timer: ReturnType<typeof setTimeout> | null;\n attempts: number;\n maxAttempts: number;\n baseDelay: number;\n }\n >();\n\n // Initialize server states\n for (const serverConfig of servers) {\n state.servers.set(serverConfig.name, {\n config: serverConfig,\n client: null,\n tools: [],\n resources: [],\n status: \"disconnected\",\n });\n reconnectState.set(serverConfig.name, {\n timer: null,\n attempts: 0,\n maxAttempts: serverConfig.retry?.maxAttempts ?? 10,\n baseDelay: serverConfig.retry?.backoffMs ?? 5000,\n });\n }\n\n // Validate stdio command to prevent shell injection\n function validateStdioCommand(serverConfig: MCPServerConfig): void {\n const shellMetachars = /[;|&$`><]/;\n\n if (serverConfig.command) {\n if (shellMetachars.test(serverConfig.command)) {\n throw new Error(\n `[Directive MCP] Stdio command for server '${serverConfig.name}' contains shell metacharacters: '${serverConfig.command}'. ` +\n `This may indicate a command injection vulnerability. Use 'args' for command arguments instead.`,\n );\n }\n }\n\n if (serverConfig.args) {\n for (const arg of serverConfig.args) {\n if (shellMetachars.test(arg)) {\n throw new Error(\n `[Directive MCP] Stdio argument for server '${serverConfig.name}' contains shell metacharacters: '${arg}'. ` +\n `This may indicate a command injection vulnerability.`,\n );\n }\n }\n }\n }\n\n // Connect to a server\n async function connectServer(name: string): Promise<void> {\n const serverState = state.servers.get(name);\n if (!serverState) {\n throw new Error(`Unknown MCP server: ${name}`);\n }\n\n if (serverState.status === \"connected\") {\n return;\n }\n\n // Validate stdio commands before connecting\n if (serverState.config.transport === \"stdio\") {\n validateStdioCommand(serverState.config);\n }\n\n serverState.status = \"connecting\";\n\n try {\n const client = clientFactory(serverState.config);\n await client.connect();\n\n serverState.client = client;\n serverState.status = \"connected\";\n\n // Reset reconnect state on successful connection\n const rState = reconnectState.get(name);\n if (rState) {\n rState.attempts = 0;\n if (rState.timer) {\n clearTimeout(rState.timer);\n rState.timer = null;\n }\n }\n\n // Fetch available tools and resources\n if (client.getCapabilities().tools) {\n serverState.tools = await client.listTools();\n }\n if (client.getCapabilities().resources) {\n serverState.resources = await client.listResources();\n }\n\n serverState.lastSync = Date.now();\n events.onConnect?.(name);\n } catch (error) {\n serverState.status = \"error\";\n serverState.error =\n error instanceof Error ? error : new Error(String(error));\n events.onError?.(name, serverState.error);\n\n if (autoReconnect) {\n const rState = reconnectState.get(name);\n if (rState && rState.attempts < rState.maxAttempts) {\n rState.attempts++;\n // Exponential backoff with jitter, capped at 60s\n const delay = Math.min(\n rState.baseDelay * 2 ** (rState.attempts - 1) +\n Math.random() * 1000,\n 60000,\n );\n rState.timer = setTimeout(() => {\n rState.timer = null;\n connectServer(name).catch(() => {}); // Error handled in next iteration\n }, delay);\n } else if (rState) {\n console.error(\n `[Directive MCP] Max reconnect attempts (${rState.maxAttempts}) reached for server '${name}'. ` +\n `Call adapter.connectServer(\"${name}\") to retry manually.`,\n );\n }\n }\n\n throw serverState.error;\n }\n }\n\n // Disconnect from a server\n async function disconnectServer(name: string): Promise<void> {\n // Clear any pending reconnect timer\n const rState = reconnectState.get(name);\n if (rState?.timer) {\n clearTimeout(rState.timer);\n rState.timer = null;\n rState.attempts = 0;\n }\n\n const serverState = state.servers.get(name);\n if (!serverState || !serverState.client) {\n return;\n }\n\n try {\n await serverState.client.disconnect();\n } finally {\n serverState.status = \"disconnected\";\n serverState.client = null;\n events.onDisconnect?.(name);\n }\n }\n\n // Call a tool with constraint checking\n async function callToolWithConstraints(\n server: string,\n tool: string,\n args: Record<string, unknown>,\n facts: Record<string, unknown>,\n ): Promise<MCPToolResult> {\n const serverState = state.servers.get(server);\n if (!serverState) {\n throw new Error(\n `[Directive MCP] Unknown server '${server}'. ` +\n `Available servers: ${Array.from(state.servers.keys()).join(\", \") || \"(none)\"}`,\n );\n }\n if (!serverState.client) {\n throw new Error(\n `[Directive MCP] Server '${server}' is not connected. ` +\n `Call 'adapter.connect()' or 'adapter.connectServer(\"${server}\")' first.`,\n );\n }\n\n const constraintKey = `${server}.${tool}`;\n const constraint = state.toolConstraints.get(constraintKey);\n\n // Check constraints\n if (constraint) {\n // Check rate limit\n if (constraint.rateLimit) {\n const limiter = state.rateLimiters.get(constraintKey);\n if (\n !checkRateLimit(\n state.rateLimiters,\n constraintKey,\n constraint.rateLimit,\n )\n ) {\n const resetAt = limiter?.resetTime\n ? new Date(limiter.resetTime).toISOString()\n : \"unknown\";\n throw new Error(\n `[Directive MCP] Rate limit exceeded for '${constraintKey}': ` +\n `${limiter?.count ?? 0}/${constraint.rateLimit} requests per minute. ` +\n `Resets at ${resetAt}.`,\n );\n }\n }\n\n // Check max arg size\n if (constraint.maxArgSize) {\n const argSize = JSON.stringify(args).length;\n if (argSize > constraint.maxArgSize) {\n throw new Error(\n `Arguments exceed max size (${argSize} > ${constraint.maxArgSize})`,\n );\n }\n }\n\n // Check custom constraint\n if (constraint.when) {\n const allowed = await constraint.when(facts, args);\n if (!allowed) {\n throw new Error(`Constraint not satisfied for ${constraintKey}`);\n }\n }\n\n // Check if approval is required\n if (constraint.requireApproval) {\n const requestId = `approval-${++approvalCounter}-${Date.now()}`;\n const approvalRequest: MCPApprovalRequest = {\n id: requestId,\n server,\n tool,\n args,\n requestedAt: Date.now(),\n };\n\n state.pendingApprovals.set(requestId, approvalRequest);\n events.onApprovalRequest?.(approvalRequest);\n\n // Wait for approval or rejection\n await waitForApproval(requestId);\n }\n }\n\n events.onToolCall?.(server, tool, args);\n\n // Call the tool\n const result = await Promise.race([\n serverState.client.callTool(tool, args),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`Tool call timeout: ${constraintKey}`)),\n constraint?.timeout ?? 30000,\n ),\n ),\n ]);\n\n events.onToolResult?.(server, tool, result);\n\n return result;\n }\n\n // Create plugin\n const plugin: Plugin = {\n name: \"mcp-adapter\",\n\n onInit: async () => {\n if (autoConnect) {\n await Promise.all(\n Array.from(state.servers.keys()).map((name) =>\n connectServer(name).catch((e) =>\n console.error(`Failed to connect to ${name}:`, e),\n ),\n ),\n );\n }\n },\n\n onDestroy: async () => {\n // Clear all reconnect timers\n for (const rState of reconnectState.values()) {\n if (rState.timer) {\n clearTimeout(rState.timer);\n rState.timer = null;\n }\n }\n\n // Reject all pending approval waiters\n for (const [, waiter] of approvalWaiters) {\n clearTimeout(waiter.timeoutId);\n waiter.reject(\n new Error(\n \"[Directive MCP] Adapter destroyed while awaiting approval\",\n ),\n );\n }\n approvalWaiters.clear();\n\n await Promise.all(\n Array.from(state.servers.keys()).map((name) =>\n disconnectServer(name).catch((e) =>\n console.error(`Failed to disconnect from ${name}:`, e),\n ),\n ),\n );\n },\n };\n\n // Sync resources to facts\n async function syncResources(facts: Record<string, unknown>): Promise<void> {\n for (const mapping of resourceMappings) {\n for (const [serverName, serverState] of state.servers) {\n if (!serverState.client) continue;\n\n for (const resource of serverState.resources) {\n // Check if resource matches pattern\n const matches =\n typeof mapping.pattern === \"string\"\n ? matchGlob(resource.uri, mapping.pattern)\n : mapping.pattern.test(resource.uri);\n\n if (matches) {\n try {\n const result = await serverState.client.readResource(\n resource.uri,\n );\n const content = result.contents[0]?.text ?? \"\";\n const value = mapping.transform\n ? mapping.transform(content)\n : content;\n\n facts[mapping.factKey] = value;\n events.onResourceUpdate?.(serverName, resource.uri, result);\n } catch (error) {\n console.error(`Failed to sync resource ${resource.uri}:`, error);\n }\n }\n }\n }\n }\n }\n\n return {\n plugin,\n\n async connect() {\n await Promise.all(Array.from(state.servers.keys()).map(connectServer));\n },\n\n connectServer,\n\n async disconnect() {\n await Promise.all(Array.from(state.servers.keys()).map(disconnectServer));\n },\n\n disconnectServer,\n\n getTools() {\n const tools = new Map<string, MCPTool[]>();\n for (const [name, serverState] of state.servers) {\n tools.set(name, serverState.tools);\n }\n return tools;\n },\n\n getResources() {\n const resources = new Map<string, MCPResource[]>();\n for (const [name, serverState] of state.servers) {\n resources.set(name, serverState.resources);\n }\n return resources;\n },\n\n async callTool(server, tool, args, facts) {\n return callToolWithConstraints(server, tool, args, facts);\n },\n\n async callToolDirect(server, tool, args) {\n if (!allowDirectCalls) {\n throw new Error(\n \"[Directive] callToolDirect is disabled by default. Pass { allowDirectCalls: true } to enable unconstrained tool calls.\",\n );\n }\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[Directive] callToolDirect bypasses all constraints (rate limits, approvals, timeouts).\",\n );\n }\n const serverState = state.servers.get(server);\n if (!serverState) {\n throw new Error(\n `[Directive MCP] Unknown server '${server}'. ` +\n `Available servers: ${Array.from(state.servers.keys()).join(\", \") || \"(none)\"}`,\n );\n }\n if (!serverState.client) {\n throw new Error(\n `[Directive MCP] Server '${server}' is not connected. ` +\n `Call 'adapter.connect()' or 'adapter.connectServer(\"${server}\")' first.`,\n );\n }\n events.onToolCall?.(server, tool, args);\n const result = await serverState.client.callTool(tool, args);\n events.onToolResult?.(server, tool, result);\n return result;\n },\n\n async readResource(server, uri) {\n const serverState = state.servers.get(server);\n if (!serverState) {\n throw new Error(\n `[Directive MCP] Unknown server '${server}'. ` +\n `Available servers: ${Array.from(state.servers.keys()).join(\", \") || \"(none)\"}`,\n );\n }\n if (!serverState.client) {\n throw new Error(\n `[Directive MCP] Server '${server}' is not connected. ` +\n `Call 'adapter.connect()' or 'adapter.connectServer(\"${server}\")' first.`,\n );\n }\n const result = await serverState.client.readResource(uri);\n events.onResourceUpdate?.(server, uri, result);\n return result;\n },\n\n syncResources,\n\n getServerStatus(name) {\n return state.servers.get(name);\n },\n\n getAllServerStatuses() {\n return new Map(state.servers);\n },\n\n approve(requestId: string) {\n const request = state.pendingApprovals.get(requestId);\n if (!request && !approvalWaiters.has(requestId)) {\n throw new Error(\n `[Directive MCP] No pending approval request with ID '${requestId}'. ` +\n `Pending requests: ${Array.from(state.pendingApprovals.keys()).join(\", \") || \"(none)\"}`,\n );\n }\n resolveApproval(requestId, true);\n },\n\n reject(requestId: string, reason?: string) {\n const request = state.pendingApprovals.get(requestId);\n if (!request && !approvalWaiters.has(requestId)) {\n throw new Error(\n `[Directive MCP] No pending approval request with ID '${requestId}'. ` +\n `Pending requests: ${Array.from(state.pendingApprovals.keys()).join(\", \") || \"(none)\"}`,\n );\n }\n resolveApproval(requestId, false, reason);\n },\n\n getPendingApprovals() {\n return Array.from(state.pendingApprovals.values());\n },\n\n getRejectionReason(requestId: string): string | undefined {\n return rejectionReasons.get(requestId);\n },\n };\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/** Cache for compiled glob patterns to avoid repeated regex compilation */\nconst globCache = new Map<string, RegExp>();\nconst MAX_GLOB_CACHE_SIZE = 200;\n\n/** Simple glob matching (supports * and **) with caching */\nfunction matchGlob(str: string, pattern: string): boolean {\n let regex = globCache.get(pattern);\n if (!regex) {\n // Escape all regex metacharacters first, then convert glob wildcards\n const regexPattern = pattern\n .replace(/\\*\\*/g, \"\\0GLOBSTAR\\0\")\n .replace(/\\*/g, \"\\0STAR\\0\")\n .replace(/\\?/g, \"\\0QUESTION\\0\")\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\0GLOBSTAR\\0/g, \".*\")\n .replace(/\\0STAR\\0/g, \"[^/]*\")\n .replace(/\\0QUESTION\\0/g, \".\");\n regex = new RegExp(`^${regexPattern}$`);\n\n // LRU eviction: delete oldest entry when cache is full\n if (globCache.size >= MAX_GLOB_CACHE_SIZE) {\n const firstKey = globCache.keys().next().value;\n if (firstKey !== undefined) globCache.delete(firstKey);\n }\n globCache.set(pattern, regex);\n }\n return regex.test(str);\n}\n\n/**\n * Convert MCP tools to a format suitable for LLM tool calling.\n *\n * @example\n * ```typescript\n * const adapter = createMCPAdapter({ servers: [...] });\n * await adapter.connect();\n *\n * const tools = adapter.getTools();\n * const llmTools = convertToolsForLLM(tools);\n * // Use with OpenAI/Anthropic/etc.\n * ```\n */\nexport function convertToolsForLLM(tools: Map<string, MCPTool[]>): Array<{\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}> {\n const result: Array<{\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n }> = [];\n\n for (const [server, serverTools] of tools) {\n for (const tool of serverTools) {\n result.push({\n type: \"function\",\n function: {\n name: `${server}.${tool.name}`,\n description: tool.description ?? `Tool: ${tool.name}`,\n parameters: tool.inputSchema,\n },\n });\n }\n }\n\n return result;\n}\n\n/**\n * Create a requirement to call an MCP tool.\n *\n * @example\n * ```typescript\n * const req = mcpCallTool('filesystem', 'read_file', { path: '/etc/hosts' });\n * // { type: 'MCP_CALL_TOOL', server: 'filesystem', tool: 'read_file', args: { path: '/etc/hosts' } }\n * ```\n */\nexport function mcpCallTool(\n server: string,\n tool: string,\n args: Record<string, unknown>,\n): MCPCallToolRequirement {\n return { type: \"MCP_CALL_TOOL\", server, tool, args };\n}\n\n/**\n * Create a requirement to read an MCP resource.\n */\nexport function mcpReadResource(\n server: string,\n uri: string,\n): MCPReadResourceRequirement {\n return { type: \"MCP_READ_RESOURCE\", server, uri };\n}\n\n/**\n * Create a requirement to get an MCP prompt.\n */\nexport function mcpGetPrompt(\n server: string,\n prompt: string,\n args?: Record<string, string>,\n): MCPGetPromptRequirement {\n return { type: \"MCP_GET_PROMPT\", server, prompt, args };\n}\n\n/**\n * Create a requirement to sync MCP resources.\n */\nexport function mcpSyncResources(\n server?: string,\n pattern?: string | RegExp,\n): MCPSyncResourcesRequirement {\n return { type: \"MCP_SYNC_RESOURCES\", server, pattern };\n}\n\n// Re-export types\nexport * from \"./mcp-types.js\";\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';var chunkFFRWQNK7_cjs=require('./chunk-FFRWQNK7.cjs'),core=require('@directive-run/core');function D(t){let e=5381;for(let n=0;n<t.length;n++)e=(e<<5)+e^t.charCodeAt(n);return (e>>>0).toString(16)}async function C(t){try{let e=globalThis.crypto?.subtle;if(e&&typeof e.digest=="function"){let n=new TextEncoder,r=await e.digest("SHA-256",n.encode(t)),o=new Uint8Array(r),a="";for(let i of o)a+=i.toString(16).padStart(2,"0");return a}}catch{}return D(t)}var f=class extends Error{constructor(n,r,o,a){super(n);this.attempts=r;this.errors=o;this.lastRawOutput=a;}name="PredicateFromIntentError"},H=`You emit ONLY a JSON object describing a Directive FactPredicate \u2014 no prose, no markdown fences, no explanation.
|
|
2
|
+
|
|
3
|
+
A FactPredicate is a JSON tree of fact paths and operators:
|
|
4
|
+
- Object form (preferred): { "factName": { "$op": operand }, "otherFact": { "$op": operand } }
|
|
5
|
+
- Combinators: { "$all": [predicateA, predicateB] }, { "$any": [...] }, { "$not": predicate }
|
|
6
|
+
- Bare value (equality shortcut): { "factName": value }
|
|
7
|
+
|
|
8
|
+
Operator set (CLOSED \u2014 only these are valid):
|
|
9
|
+
$eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $between,
|
|
10
|
+
$matches, $startsWith, $endsWith, $contains, $changed
|
|
11
|
+
Combinators: $all, $any, $not
|
|
12
|
+
|
|
13
|
+
Each operator is only valid for certain kinds (see below). Emit ONLY operators valid for the fact's kind.
|
|
14
|
+
`;function s(t){let e=t.nullable?" (nullable)":"";switch(t.kind){case "literal":return `literal ${JSON.stringify(t.value)} (${t.primitive})${e}`;case "enum":return `enum ${JSON.stringify(t.values)} (${t.primitive})${e}`;case "array":return `array of ${s(t.element)}${e}`;case "tuple":return `tuple [${t.elements.map(s).join(", ")}]${e}`;case "object":return `object { ${Object.entries(t.shape).map(([n,r])=>`${n}: ${s(r)}`).join(", ")} }${e}`;case "record":return `record<string, ${s(t.value)}>${e}`;case "union":return `union (${t.members.map(s).join(" | ")})${e}`;case "branded":return `branded(${s(t.inner)})${e}`;default:return `${t.kind}${e}`}}function J(t,e){let n=[H];n.push(`
|
|
15
|
+
Facts in this schema (path \u2192 kind \u2192 allowed operators):`);for(let[r,o]of t.entries()){if(e&&!r.startsWith(e))continue;let a=core.getOperatorsForKind(o);n.push(` ${r}: ${s(o)} \u2014 allowed: ${a.join(", ")}`);}return e&&n.push(`
|
|
16
|
+
The user intent will be over the namespace "${e}". Use only facts at or below that path.`),n.push(`
|
|
17
|
+
Respond with ONLY the JSON predicate object. No prose. No markdown fences. No "Here is...".`),n.join(`
|
|
18
|
+
`)}function M(t,e,n){let r=[];r.push("Your previous response was rejected. Original intent (still applies):"),r.push(` ${t}`);let o=null;if(typeof n=="string")r.push(`
|
|
19
|
+
Reason: ${n}`);else {r.push(`
|
|
20
|
+
Validation errors (fix every one):`),o=new Set;for(let a of n)r.push(` - path "${a.path}", op "${a.op}": ${a.reason}`),a.allowedOps&&a.allowedOps.length>0&&r.push(` \u2192 allowed operators for this fact: ${a.allowedOps.join(", ")}`),o.add(a.path);}if(r.push(`
|
|
21
|
+
Schema reminder:`),o&&o.size>0){let a=0;for(let p of o){let l=e.get(p);if(l){let y=core.getOperatorsForKind(l);r.push(` ${p}: ${s(l)} \u2014 allowed: ${y.join(", ")}`),a++;}else r.push(` ${p}: (not in schema \u2014 pick from the available facts below)`);}let i=e.size-a;i>0&&r.push(` \u2026and ${i} more fact(s) available \u2014 ask if you need the full list.`);}else for(let[a,i]of e.entries()){let p=core.getOperatorsForKind(i);r.push(` ${a}: ${s(i)} \u2014 allowed: ${p.join(", ")}`);}return r.push(`
|
|
22
|
+
Emit ONLY a corrected JSON FactPredicate object. No prose.`),r.join(`
|
|
23
|
+
`)}function B(t,e,n){if(t.length>n.maxPredicateBytes)return {ok:false,reason:`Output exceeded maxPredicateBytes=${n.maxPredicateBytes} (got ${t.length}). Emit a smaller predicate.`};let r;try{r=chunkFFRWQNK7_cjs.a(t);}catch(a){return {ok:false,reason:`Could not extract JSON from output: ${a instanceof Error?a.message:String(a)}`}}try{core.validatePredicate(r);}catch(a){return {ok:false,reason:`Structural validation failed: ${a instanceof Error?a.message:String(a)}`}}let o=core.validatePredicateAgainstSchema(r,e,{maxOperatorCount:n.maxOperatorCount,maxArrayOperandLength:n.maxArrayOperandLength});return o.ok?{ok:true,predicate:r}:{ok:false,reason:`Predicate has ${o.errors.length} schema-validation error(s).`,details:o.errors}}var Y=3,K=65536,V=256,W=1e3;async function X(t){let e=await k(t);if(e.predicate===null)throw new f(`[Directive] predicateFromIntent: failed after ${e.attempts} attempt(s). Last error: ${e.errors[e.errors.length-1]?.reason??"unknown"}`,e.attempts,e.errors,e.lastRawOutput);return e.predicate}async function k(t){let{intent:e,schema:n,runner:r,agent:o,factPath:a,maxRetries:i=Y,maxPredicateBytes:p=K,maxOperatorCount:l=V,maxArrayOperandLength:y=W,redact:w,signal:$}=t;if(typeof e!="string"||e.length===0)throw new Error("[Directive] predicateFromIntent: `intent` must be a non-empty string.");let P=w?w(e):e,u=core.getSchemaFieldKinds(n);if(u.size===0)throw new Error("[Directive] predicateFromIntent: schema has no introspectable facts. Pass a module schema or a bare facts record.");let R=J(u,a),O=o??{name:"predicate-emitter"},T={...O,instructions:`${O.instructions??""}
|
|
24
|
+
|
|
25
|
+
${R}`.trim()},c=[],b,d=0,I={maxPredicateBytes:p,maxOperatorCount:l,maxArrayOperandLength:y};for(;d<i+1;){if($?.aborted)throw new Error("aborted");d++;let j=d===1?`Intent: ${P}
|
|
26
|
+
|
|
27
|
+
Emit the predicate now.`:M(P,u,c[c.length-1].details??c[c.length-1].reason),m;try{m=await r(T,j,{signal:$});}catch(S){if($?.aborted)throw new Error("aborted");c.push({attempt:d,reason:`LLM runner threw: ${S instanceof Error?S.message:String(S)}`});continue}let F=typeof m.output=="string"?m.output:JSON.stringify(m.output);b=F;let h=B(F,u,I);if(h.ok)return {predicate:h.predicate,attempts:d,errors:c,lastRawOutput:b};c.push({attempt:d,reason:h.reason,details:h.details});}return {predicate:null,attempts:d,errors:c,lastRawOutput:b}}function v(t,e){let n=core.getSchemaFieldKinds(t),r=[];for(let[o,a]of n.entries()){if(e&&!o.startsWith(e))continue;let i=core.getOperatorsForKind(a);r.push(`${o}: ${s(a)} \u2014 ops: ${i.join(", ")}`);}return r.join(`
|
|
28
|
+
`)}function E(t,e){return e??`Emit a Directive FactPredicate (JSON tree of facts and operators) matching the user's intent. Schema:
|
|
29
|
+
${t}`}function G(t,e={}){let n=v(t,e.factPath),r=e.name??"emit_predicate",o=E(n,e.description);return {type:"function",function:{name:r,description:o,parameters:{type:"object",properties:{predicate:{type:"object"}},required:["predicate"]}},schemaSummary:n}}function U(t,e={}){let n=v(t,e.factPath),r=e.name??"emit_predicate",o=E(n,e.description);return {name:r,description:o,input_schema:{type:"object",properties:{predicate:{type:"object"}},required:["predicate"]},schemaSummary:n}}function Q(t,e={}){return U(t,e)}async function Z(t){let e=await k(t);if(e.predicate===null)throw new f(`[Directive] predicateFromIntentWithProvenance: failed after ${e.attempts} attempt(s). Last error: ${e.errors[e.errors.length-1]?.reason??"unknown"}`,e.attempts,e.errors,e.lastRawOutput);let n=t.redact?t.redact(t.intent):t.intent,r=t.agent?.model??"unknown",o=core.predicateHash(e.predicate),a=await C(n),i=t.redactIntent?{model:r,intentHash:a,attemptCount:e.attempts,emittedAt:new Date().toISOString(),predicateHash:o}:{model:r,intent:n,intentHash:a,attemptCount:e.attempts,emittedAt:new Date().toISOString(),predicateHash:o};return {predicate:e.predicate,provenance:i}}exports.a=f;exports.b=X;exports.c=k;exports.d=G;exports.e=U;exports.f=Q;exports.g=Z;//# sourceMappingURL=chunk-PD772MSE.cjs.map
|
|
30
|
+
//# sourceMappingURL=chunk-PD772MSE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/predicate-from-intent.ts"],"names":["djb2Hash","str","hash","i","hashStringSha256","raw","subtle","enc","buf","bytes","hex","b","PredicateFromIntentError","message","attempts","errors","lastRawOutput","SYSTEM_PROMPT_HEADER","renderKindForPrompt","node","nullableTag","k","v","buildSystemPrompt","kindMap","factPath","lines","path","ops","getOperatorsForKind","buildErrorFeedback","intent","pathsToShow","e","shown","remaining","validateOneAttempt","rawOutput","opts","parsed","extractJsonFromOutput","err","validatePredicate","schemaResult","validatePredicateAgainstSchema","DEFAULT_MAX_RETRIES","DEFAULT_MAX_PREDICATE_BYTES","DEFAULT_MAX_OPERATOR_COUNT","DEFAULT_MAX_ARRAY_OPERAND_LENGTH","predicateFromIntent","result","predicateFromIntentRaw","rawIntent","schema","runner","agent","maxRetries","maxPredicateBytes","maxOperatorCount","maxArrayOperandLength","redact","signal","getSchemaFieldKinds","systemPrompt","baseAgent","promptAgent","attempt","validateOpts","input","runResult","validated","buildSchemaSummary","buildDescription","summary","override","predicateToolSpecOpenAI","name","description","predicateToolSpecAnthropic","predicateToolSpec","predicateFromIntentWithProvenance","sanitizedIntent","model","predicateHashValue","predicateHash","intentHash","provenance"],"mappings":"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","file":"chunk-PD772MSE.cjs","sourcesContent":["/**\n * predicateFromIntent — let an LLM emit a typed FactPredicate as JSON,\n * structurally + semantically validated before it ever reaches your\n * constraint engine.\n *\n * Pipeline per call attempt:\n *\n * 1. Output-size check (reject before JSON.parse for DoS guard)\n * 2. JSON.parse via extractJsonFromOutput (handles surrounding prose)\n * 3. validatePredicate (structural: closed operator set, depth, JSON safety)\n * 4. Operator-count check\n * 5. validatePredicateAgainstSchema (semantic: operator-on-kind matrix)\n *\n * On any failure: a structured error message — including the offending\n * clause's path, the allowed operators for that fact's kind, and the\n * original schema kinds — is fed back to the LLM in the next attempt.\n *\n * Returns the validated FactPredicate. Throws PredicateFromIntentError\n * on retry exhaustion. NEVER returns a partial / unvalidated predicate.\n */\n\nimport {\n getOperatorsForKind,\n getSchemaFieldKinds,\n predicateHash,\n validatePredicate,\n validatePredicateAgainstSchema,\n type FactPredicate,\n type SchemaKindNode,\n type SchemaValidationError,\n} from \"@directive-run/core\";\n\nimport { extractJsonFromOutput } from \"./structured-output.js\";\nimport type { AgentLike, AgentRunner } from \"./types.js\";\n\n// ============================================================================\n// Hashing helpers\n// ============================================================================\n//\n// Provenance hashing has two flavors:\n//\n// - `predicateHash(spec)` — synchronous djb2 of a stable-stringified\n// predicate. Imported from `@directive-run/core` (the supported,\n// semver-stable surface). Two semantically-identical predicates emitted\n// with different whitespace / key-order produce the same hash. (N3)\n//\n// - `hashStringSha256(str)` — async SHA-256 via crypto.subtle when\n// available, djb2 fallback otherwise. Used for `intentHash` —\n// intents are free-form strings, no canonicalization to do.\n//\n\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\n }\n\n return (hash >>> 0).toString(16);\n}\n\nasync function hashStringSha256(raw: string): Promise<string> {\n // Prefer crypto.subtle SHA-256 when available (browsers, Node 19+, workers).\n // Fall back to a sync djb2 — collision-prone, but adequate for telemetry\n // alongside the persisted predicate.\n try {\n const subtle = (globalThis as { crypto?: { subtle?: SubtleCrypto } })\n .crypto?.subtle;\n if (subtle && typeof subtle.digest === \"function\") {\n const enc = new TextEncoder();\n const buf = await subtle.digest(\"SHA-256\", enc.encode(raw));\n const bytes = new Uint8Array(buf);\n let hex = \"\";\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\");\n }\n\n return hex;\n }\n } catch {\n // fall through to djb2\n }\n\n return djb2Hash(raw);\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PredicateFromIntentOptions<_F = Record<string, unknown>> {\n /** Natural-language intent (untrusted user input — sanitize via `redact`). */\n intent: string;\n /**\n * Module schema (must expose builders with `_typeName` or `_kind`).\n * Pass either `{ facts: {...} }` or a bare `Record<string, builder>`.\n */\n schema: unknown;\n /** AgentRunner from `@directive-run/ai` adapters (createOpenAIRunner, etc.). */\n runner: AgentRunner;\n /**\n * Optional agent override. Default is `{ name: \"predicate-emitter\" }`\n * with our system prompt; pass `instructions` to append additional\n * context.\n */\n agent?: AgentLike;\n /**\n * Optional dotted-path namespace; useful for cross-module systems\n * where the LLM should emit a predicate over `auth.token` (default:\n * the schema's root facts).\n */\n factPath?: string;\n /** Max retries on validation failure. Default 3. */\n maxRetries?: number;\n /**\n * Hard byte cap on the LLM's raw output, BEFORE JSON.parse. Defaults\n * to 64 KiB. A larger predicate is rejected outright; protects\n * against multi-MB-payload DoS where the predicate is technically\n * structurally valid.\n */\n maxPredicateBytes?: number;\n /**\n * Hard cap on the number of operator clauses in the predicate.\n * Defaults to 256. Protects against `{ $any: [{ x: 1 }, … x100,000 ] }`\n * style operator-count exhaustion.\n */\n maxOperatorCount?: number;\n /**\n * Optional sanitizer applied to `intent` BEFORE it lands in the\n * system prompt. Useful for stripping or redacting user-controlled\n * content that looks like prompt-injection.\n */\n redact?: (intent: string) => string;\n /**\n * Hard cap on the length of each `$in` / `$nin` array operand the LLM\n * may emit. Defaults to 1000. Forwarded to\n * `validatePredicateAgainstSchema`'s `maxArrayOperandLength`.\n */\n maxArrayOperandLength?: number;\n /**\n * Optional `AbortSignal` for cooperative cancellation. (N6)\n *\n * The retry loop checks `signal.aborted` between attempts AND forwards\n * the signal into the runner call itself (`runner(agent, input, { signal })`).\n * Whether the in-flight LLM call honors the signal depends on the runner:\n * fetch-based adapters (the bundled OpenAI / Anthropic / Ollama runners)\n * thread it through to `fetch`, so the network call aborts mid-stream.\n * A custom runner that ignores the signal still delivers cancellation\n * at the next retry boundary.\n *\n * On abort: throws `Error(\"aborted\")`.\n *\n * NOTE: `predicateFromIntent` does NOT limit in-flight calls — callers\n * MUST wrap with a concurrency limiter (e.g. `p-limit`) to bound\n * fan-out under load.\n */\n signal?: AbortSignal;\n /**\n * When `true`, the {@link PredicateFromIntentProvenance} returned by\n * `predicateFromIntentWithProvenance` omits the raw `intent` string and\n * stores only the SHA-256 `intentHash`. Use this in PII-sensitive\n * contexts where the original intent must not be persisted. (M6)\n *\n * **Default `false` for back-compat.** For PII-sensitive deployments,\n * ALWAYS set `redactIntent: true` — the raw intent may contain\n * user-supplied content (names, emails, medical or financial details,\n * customer messages) that becomes a permanent record in\n * `provenance.intent`. The default is opt-in only because flipping it\n * now would silently strip diagnostic data from existing callers; v2\n * may flip this default (tracked in IDEAS.md).\n *\n * Pair with a `redact:` sanitizer when the intent itself must be\n * scrubbed BEFORE it lands in the LLM prompt — `redactIntent` controls\n * only what enters the provenance record, not what the LLM sees.\n */\n redactIntent?: boolean;\n}\n\nexport interface PredicateFromIntentDiagnostics<F = Record<string, unknown>> {\n /** The validated predicate (`null` if all retries failed). */\n predicate: FactPredicate<F> | null;\n /** Number of LLM calls actually made. */\n attempts: number;\n /** Errors encountered across all attempts (most recent last). */\n errors: ReadonlyArray<{ attempt: number; reason: string; details?: readonly SchemaValidationError[] }>;\n /** The raw LLM output from the final attempt — useful for debugging. */\n lastRawOutput?: string;\n}\n\n/** Thrown by `predicateFromIntent` on retry exhaustion. `predicateFromIntentRaw` returns these as a diagnostics payload instead. */\nexport class PredicateFromIntentError extends Error {\n override readonly name = \"PredicateFromIntentError\";\n constructor(\n message: string,\n public readonly attempts: number,\n public readonly errors: ReadonlyArray<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }>,\n public readonly lastRawOutput: string | undefined,\n ) {\n super(message);\n }\n}\n\n// ============================================================================\n// Prompt builder\n// ============================================================================\n\nconst SYSTEM_PROMPT_HEADER = `You emit ONLY a JSON object describing a Directive FactPredicate — no prose, no markdown fences, no explanation.\n\nA FactPredicate is a JSON tree of fact paths and operators:\n- Object form (preferred): { \"factName\": { \"$op\": operand }, \"otherFact\": { \"$op\": operand } }\n- Combinators: { \"$all\": [predicateA, predicateB] }, { \"$any\": [...] }, { \"$not\": predicate }\n- Bare value (equality shortcut): { \"factName\": value }\n\nOperator set (CLOSED — only these are valid):\n $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $between,\n $matches, $startsWith, $endsWith, $contains, $changed\nCombinators: $all, $any, $not\n\nEach operator is only valid for certain kinds (see below). Emit ONLY operators valid for the fact's kind.\n`;\n\nfunction renderKindForPrompt(node: SchemaKindNode): string {\n const nullableTag = node.nullable ? \" (nullable)\" : \"\";\n switch (node.kind) {\n case \"literal\":\n return `literal ${JSON.stringify(node.value)} (${node.primitive})${nullableTag}`;\n case \"enum\":\n return `enum ${JSON.stringify(node.values)} (${node.primitive})${nullableTag}`;\n case \"array\":\n return `array of ${renderKindForPrompt(node.element)}${nullableTag}`;\n case \"tuple\":\n return `tuple [${node.elements.map(renderKindForPrompt).join(\", \")}]${nullableTag}`;\n case \"object\":\n return `object { ${Object.entries(node.shape)\n .map(([k, v]) => `${k}: ${renderKindForPrompt(v)}`)\n .join(\", \")} }${nullableTag}`;\n case \"record\":\n return `record<string, ${renderKindForPrompt(node.value)}>${nullableTag}`;\n case \"union\":\n return `union (${node.members.map(renderKindForPrompt).join(\" | \")})${nullableTag}`;\n case \"branded\":\n return `branded(${renderKindForPrompt(node.inner)})${nullableTag}`;\n default:\n return `${node.kind}${nullableTag}`;\n }\n}\n\nfunction buildSystemPrompt(\n kindMap: Map<string, SchemaKindNode>,\n factPath?: string,\n): string {\n const lines: string[] = [SYSTEM_PROMPT_HEADER];\n\n lines.push(\"\\nFacts in this schema (path → kind → allowed operators):\");\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(\n ` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`,\n );\n }\n if (factPath) {\n lines.push(\n `\\nThe user intent will be over the namespace \"${factPath}\". Use only facts at or below that path.`,\n );\n }\n\n lines.push(\n \"\\nRespond with ONLY the JSON predicate object. No prose. No markdown fences. No \\\"Here is...\\\".\",\n );\n\n return lines.join(\"\\n\");\n}\n\nfunction buildErrorFeedback(\n intent: string,\n kindMap: Map<string, SchemaKindNode>,\n errors: readonly SchemaValidationError[] | string,\n): string {\n const lines: string[] = [];\n lines.push(\"Your previous response was rejected. Original intent (still applies):\");\n lines.push(` ${intent}`);\n\n // M16: When we have structured errors, scope the schema reminder to only\n // the offending fact paths instead of dumping the full schema. Falls back\n // to the full schema for non-structural failures (string errors).\n let pathsToShow: Set<string> | null = null;\n\n if (typeof errors === \"string\") {\n lines.push(`\\nReason: ${errors}`);\n } else {\n lines.push(\"\\nValidation errors (fix every one):\");\n pathsToShow = new Set();\n for (const e of errors) {\n lines.push(` - path \"${e.path}\", op \"${e.op}\": ${e.reason}`);\n if (e.allowedOps && e.allowedOps.length > 0) {\n lines.push(` → allowed operators for this fact: ${e.allowedOps.join(\", \")}`);\n }\n // Collect every path mentioned by an error. If a path isn't in the\n // kindMap (unknown fact), the offending key may be a dotted prefix of\n // a real fact — include the closest known ancestor too.\n pathsToShow.add(e.path);\n }\n }\n\n lines.push(\"\\nSchema reminder:\");\n if (pathsToShow && pathsToShow.size > 0) {\n let shown = 0;\n for (const path of pathsToShow) {\n const node = kindMap.get(path);\n if (node) {\n const ops = getOperatorsForKind(node);\n lines.push(` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`);\n shown++;\n } else {\n lines.push(\n ` ${path}: (not in schema — pick from the available facts below)`,\n );\n }\n }\n const remaining = kindMap.size - shown;\n if (remaining > 0) {\n lines.push(` …and ${remaining} more fact(s) available — ask if you need the full list.`);\n }\n } else {\n for (const [path, node] of kindMap.entries()) {\n const ops = getOperatorsForKind(node);\n lines.push(` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`);\n }\n }\n\n lines.push(\"\\nEmit ONLY a corrected JSON FactPredicate object. No prose.\");\n\n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Validation pipeline (one attempt)\n// ============================================================================\n\nfunction validateOneAttempt(\n rawOutput: string,\n kindMap: Map<string, SchemaKindNode>,\n opts: {\n maxPredicateBytes: number;\n maxOperatorCount: number;\n maxArrayOperandLength: number;\n },\n):\n | { ok: true; predicate: unknown }\n | { ok: false; reason: string; details?: readonly SchemaValidationError[] } {\n // 1. Byte cap (pre-parse — kills 10MB-payload DoS)\n if (rawOutput.length > opts.maxPredicateBytes) {\n return {\n ok: false,\n reason: `Output exceeded maxPredicateBytes=${opts.maxPredicateBytes} (got ${rawOutput.length}). Emit a smaller predicate.`,\n };\n }\n\n // 2. JSON parse (handles surrounding prose)\n let parsed: unknown;\n try {\n parsed = extractJsonFromOutput(rawOutput);\n } catch (err) {\n return {\n ok: false,\n reason: `Could not extract JSON from output: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 3. Structural validation (closed operator set, depth, JSON-safety)\n try {\n validatePredicate(parsed);\n } catch (err) {\n return {\n ok: false,\n reason: `Structural validation failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 4 + 5. Operator-count cap + array-operand cap + schema validation\n const schemaResult = validatePredicateAgainstSchema(parsed, kindMap, {\n maxOperatorCount: opts.maxOperatorCount,\n maxArrayOperandLength: opts.maxArrayOperandLength,\n });\n\n if (!schemaResult.ok) {\n return {\n ok: false,\n reason: `Predicate has ${schemaResult.errors.length} schema-validation error(s).`,\n details: schemaResult.errors,\n };\n }\n\n return { ok: true, predicate: parsed };\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_MAX_PREDICATE_BYTES = 65_536; // 64 KiB\nconst DEFAULT_MAX_OPERATOR_COUNT = 256;\nconst DEFAULT_MAX_ARRAY_OPERAND_LENGTH = 1000;\n\n/**\n * Ask an LLM to emit a FactPredicate matching the user's intent, then\n * validate it structurally + semantically before returning. On validation\n * failure, retries with structured error feedback in the next prompt.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion. NEVER\n * returns a partial / unvalidated predicate.\n *\n * **Rate limiting:** this function does NOT limit in-flight calls. Wrap\n * with a concurrency limiter (e.g. `p-limit` / `Bottleneck`) before\n * exposing it to user-driven traffic. Pass an `AbortSignal` via `opts.signal`\n * for cooperative cancellation between retry attempts.\n *\n * @example\n * ```ts\n * import { createOpenAIRunner } from \"@directive-run/ai/openai\";\n * import { predicateFromIntent } from \"@directive-run/ai\";\n *\n * const runner = createOpenAIRunner({ apiKey, model: \"gpt-4o-mini\" });\n *\n * const predicate = await predicateFromIntent({\n * intent: \"checkout is unblocked when the cart total is at least 50\",\n * schema: myModule.schema,\n * runner,\n * });\n * // → { cartTotal: { $gte: 50 } }\n * ```\n */\nexport async function predicateFromIntent<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<FactPredicate<F>> {\n const result = await predicateFromIntentRaw(opts);\n if (result.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntent: failed after ${result.attempts} attempt(s). Last error: ${\n result.errors[result.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n result.attempts,\n result.errors,\n result.lastRawOutput,\n );\n }\n\n return result.predicate;\n}\n\n/**\n * Lower-level variant — returns the validated predicate (or null) plus\n * full diagnostics. Use when you want to surface validation telemetry,\n * preview the LLM's last raw output, or display per-attempt errors in\n * a UI.\n */\nexport async function predicateFromIntentRaw<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentDiagnostics<F>> {\n const {\n intent: rawIntent,\n schema,\n runner,\n agent,\n factPath,\n maxRetries = DEFAULT_MAX_RETRIES,\n maxPredicateBytes = DEFAULT_MAX_PREDICATE_BYTES,\n maxOperatorCount = DEFAULT_MAX_OPERATOR_COUNT,\n maxArrayOperandLength = DEFAULT_MAX_ARRAY_OPERAND_LENGTH,\n redact,\n signal,\n } = opts;\n\n if (typeof rawIntent !== \"string\" || rawIntent.length === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: `intent` must be a non-empty string.\",\n );\n }\n\n const intent = redact ? redact(rawIntent) : rawIntent;\n const kindMap = getSchemaFieldKinds(schema);\n\n if (kindMap.size === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: schema has no introspectable facts. Pass a module schema or a bare facts record.\",\n );\n }\n\n const systemPrompt = buildSystemPrompt(kindMap, factPath);\n const baseAgent: AgentLike = agent ?? { name: \"predicate-emitter\" };\n const promptAgent: AgentLike = {\n ...baseAgent,\n instructions: `${baseAgent.instructions ?? \"\"}\\n\\n${systemPrompt}`.trim(),\n };\n\n const errors: Array<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }> = [];\n\n let lastRawOutput: string | undefined;\n let attempt = 0;\n const validateOpts = {\n maxPredicateBytes,\n maxOperatorCount,\n maxArrayOperandLength,\n };\n\n while (attempt < maxRetries + 1) {\n // M7: cooperative cancellation — bail between attempts when aborted.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n attempt++;\n const input =\n attempt === 1\n ? `Intent: ${intent}\\n\\nEmit the predicate now.`\n : buildErrorFeedback(intent, kindMap, errors[errors.length - 1]!.details ?? errors[errors.length - 1]!.reason);\n\n let runResult;\n try {\n // (N6) Forward the abort signal to the runner so in-flight LLM\n // calls can be cancelled mid-fetch. fetch-based adapters honor\n // this via the underlying fetch's `signal` option. Custom runners\n // that ignore the third arg fall back to between-retry cancellation.\n runResult = await runner(promptAgent, input, { signal });\n } catch (err) {\n // If the abort happened during the in-flight call (and the runner\n // honored it), surface that as a plain `Error(\"aborted\")` rather\n // than burning a retry attempt on a cancellation error.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n errors.push({\n attempt,\n reason: `LLM runner threw: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n\n const rawOutput =\n typeof runResult.output === \"string\"\n ? runResult.output\n : JSON.stringify(runResult.output);\n lastRawOutput = rawOutput;\n\n const validated = validateOneAttempt(rawOutput, kindMap, validateOpts);\n\n if (validated.ok) {\n return {\n predicate: validated.predicate as FactPredicate<F>,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n }\n\n errors.push({\n attempt,\n reason: validated.reason,\n details: validated.details,\n });\n }\n\n return {\n predicate: null,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n}\n\n// ============================================================================\n// Tool-spec presets (OpenAI + Anthropic function-calling)\n// ============================================================================\n\nexport interface PredicateToolSpecOptions {\n /** Tool name. Default `\"emit_predicate\"`. */\n name?: string;\n /** Tool description. Default: a one-liner describing predicate emission. */\n description?: string;\n /** Optional dotted-path namespace to restrict the tool's scope. */\n factPath?: string;\n}\n\n/**\n * Anthropic Messages API tool shape. Drop into the `tools: [...]` array.\n * Anthropic's API expects `input_schema` at the top level of the tool.\n */\nexport interface PredicateToolSpecAnthropic {\n name: string;\n description: string;\n input_schema: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool shape. Drop into the\n * `tools: [...]` array. OpenAI nests the function payload under\n * `function: { name, description, parameters }`.\n */\nexport interface PredicateToolSpecOpenAI {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * @deprecated Use {@link PredicateToolSpecAnthropic} (or\n * {@link PredicateToolSpecOpenAI}) directly. Kept as an alias for the\n * pre-split shape that v1.12.x callers depend on; identical to\n * `PredicateToolSpecAnthropic`.\n */\nexport type PredicateToolSpec = PredicateToolSpecAnthropic;\n\nfunction buildSchemaSummary(\n schema: unknown,\n factPath: string | undefined,\n): string {\n const kindMap = getSchemaFieldKinds(schema);\n const lines: string[] = [];\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(`${path}: ${renderKindForPrompt(node)} — ops: ${ops.join(\", \")}`);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction buildDescription(summary: string, override?: string): string {\n return (\n override ??\n `Emit a Directive FactPredicate (JSON tree of facts and operators) matching the user's intent. Schema:\\n${summary}`\n );\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool spec for predicate\n * emission. Drop the result into your `tools: [...]` array; the model\n * will be told to emit a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecOpenAI(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await openai.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecOpenAI(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecOpenAI {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n type: \"function\",\n function: {\n name,\n description,\n parameters: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * Anthropic Messages API tool spec for predicate emission. Drop the\n * result into your `tools: [...]` array; the model will be told to emit\n * a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecAnthropic(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await anthropic.messages.create({\n * model: \"claude-3-5-sonnet-latest\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecAnthropic(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecAnthropic {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n name,\n description,\n input_schema: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * @deprecated Use {@link predicateToolSpecAnthropic} (or\n * {@link predicateToolSpecOpenAI}) directly. Back-compat alias for\n * v1.12.x callers — emits the Anthropic shape, unchanged.\n */\nexport function predicateToolSpec(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpec {\n return predicateToolSpecAnthropic(schema, opts);\n}\n\n// ============================================================================\n// Provenance (M24)\n// ============================================================================\n\nexport interface PredicateFromIntentProvenance {\n /**\n * Resolved model name when the caller passes `agent: { model }`,\n * otherwise `\"unknown\"`.\n *\n * NOTE: most callers omit `agent` (the default `predicate-emitter`\n * agent has no model field set), so `model` is `\"unknown\"` by default.\n * v1 does NOT read provider-detected model strings from `RunResult` —\n * that requires every adapter to surface `runResult.model`, which the\n * current `AgentRunner` contract does not. Tracked for v2; callers who\n * need provider attribution today should pass `agent: { name, model: \"...\" }`.\n */\n readonly model: string;\n /**\n * Sanitized intent string actually sent to the LLM (post-redact). When\n * `redactIntent: true` was passed, this field is omitted entirely — only\n * `intentHash` is populated.\n */\n readonly intent?: string;\n /**\n * SHA-256 hex hash of the sanitized intent string (or djb2 fallback\n * when `crypto.subtle` is unavailable). Always present — even when\n * `intent` is omitted via `redactIntent`. (M6)\n */\n readonly intentHash: string;\n /** Number of LLM calls that ran before the final predicate was accepted. */\n readonly attemptCount: number;\n /** ISO timestamp when the predicate was returned. */\n readonly emittedAt: string;\n /**\n * Hash of the VALIDATED predicate (canonicalized via stableStringify\n * before hashing). Two semantically-identical predicates emitted with\n * different whitespace or key order produce the SAME `predicateHash`.\n * Sufficient as a tamper-evident pointer alongside the persisted\n * predicate. (N3)\n *\n * Renamed from `rawOutputHash` in v1.13.x — the old name hashed the\n * raw LLM output string, which made two whitespace-different responses\n * for the same logical predicate hash differently. Callers persisting\n * the old `rawOutputHash` value should re-derive it from the stored\n * predicate using `hashObject(predicate)` from `@directive-run/core/internals`.\n */\n readonly predicateHash: string;\n}\n\nexport interface PredicateFromIntentWithProvenanceResult<F = Record<string, unknown>> {\n readonly predicate: FactPredicate<F>;\n readonly provenance: PredicateFromIntentProvenance;\n}\n\n/**\n * Like {@link predicateFromIntent} but additionally returns a structured\n * provenance record — the model name, sanitized intent (or its hash),\n * attempt count, timestamp, and a canonical hash of the validated\n * predicate.\n *\n * **Production deployments MUST persist the provenance record alongside\n * the predicate.** Without it, auditing \"where did this rule come from?\"\n * becomes guesswork.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion — same\n * semantics as the un-provenanced variant.\n *\n * **PII guidance (M6):** pass `redactIntent: true` to omit the raw\n * intent from the provenance record and persist only the `intentHash`.\n * Useful when the intent itself is sensitive (medical, financial,\n * customer messages, etc.).\n *\n * **Hash semantics (N3):**\n * - `predicateHash` hashes the VALIDATED predicate object via stable\n * stringification — two whitespace-different LLM outputs that parse to\n * the same predicate produce the same hash.\n * - `intentHash` hashes the sanitized intent STRING (SHA-256 when\n * available, djb2 fallback).\n *\n * @example\n * ```ts\n * const { predicate, provenance } = await predicateFromIntentWithProvenance({\n * intent: \"block checkout when cart > 10k\",\n * schema: checkoutModule.schema,\n * runner,\n * agent: { name: \"predicate-emitter\", model: \"gpt-4o-mini\" },\n * redactIntent: false, // default: store both intent + intentHash\n * });\n *\n * await db.predicates.insert({\n * predicate,\n * model: provenance.model,\n * intent: provenance.intent, // omitted when redactIntent: true\n * intentHash: provenance.intentHash,\n * emittedAt: provenance.emittedAt,\n * predicateHash: provenance.predicateHash,\n * attempts: provenance.attemptCount,\n * });\n * ```\n */\nexport async function predicateFromIntentWithProvenance<\n F = Record<string, unknown>,\n>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentWithProvenanceResult<F>> {\n const raw = await predicateFromIntentRaw(opts);\n if (raw.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntentWithProvenance: failed after ${raw.attempts} attempt(s). Last error: ${\n raw.errors[raw.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n raw.attempts,\n raw.errors,\n raw.lastRawOutput,\n );\n }\n\n const sanitizedIntent = opts.redact ? opts.redact(opts.intent) : opts.intent;\n const model = opts.agent?.model ?? \"unknown\";\n // (N3) Hash the VALIDATED predicate (stable canonical form), not the\n // raw LLM output — two semantically-identical responses with different\n // whitespace / key order produce the same hash. Uses the supported\n // public `predicateHash` helper from `@directive-run/core`.\n const predicateHashValue = predicateHash(raw.predicate);\n // (M6) Always hash the intent; raw intent string is included only when\n // `redactIntent` is not set.\n const intentHash = await hashStringSha256(sanitizedIntent);\n\n const provenance: PredicateFromIntentProvenance = opts.redactIntent\n ? {\n model,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n }\n : {\n model,\n intent: sanitizedIntent,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n };\n\n return {\n predicate: raw.predicate,\n provenance,\n };\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {a}from'./chunk-UR4ZGO7V.js';import {getSchemaFieldKinds,predicateHash,getOperatorsForKind,validatePredicate,validatePredicateAgainstSchema}from'@directive-run/core';function D(t){let e=5381;for(let n=0;n<t.length;n++)e=(e<<5)+e^t.charCodeAt(n);return (e>>>0).toString(16)}async function C(t){try{let e=globalThis.crypto?.subtle;if(e&&typeof e.digest=="function"){let n=new TextEncoder,r=await e.digest("SHA-256",n.encode(t)),o=new Uint8Array(r),a="";for(let i of o)a+=i.toString(16).padStart(2,"0");return a}}catch{}return D(t)}var f=class extends Error{constructor(n,r,o,a){super(n);this.attempts=r;this.errors=o;this.lastRawOutput=a;}name="PredicateFromIntentError"},H=`You emit ONLY a JSON object describing a Directive FactPredicate \u2014 no prose, no markdown fences, no explanation.
|
|
2
|
+
|
|
3
|
+
A FactPredicate is a JSON tree of fact paths and operators:
|
|
4
|
+
- Object form (preferred): { "factName": { "$op": operand }, "otherFact": { "$op": operand } }
|
|
5
|
+
- Combinators: { "$all": [predicateA, predicateB] }, { "$any": [...] }, { "$not": predicate }
|
|
6
|
+
- Bare value (equality shortcut): { "factName": value }
|
|
7
|
+
|
|
8
|
+
Operator set (CLOSED \u2014 only these are valid):
|
|
9
|
+
$eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $between,
|
|
10
|
+
$matches, $startsWith, $endsWith, $contains, $changed
|
|
11
|
+
Combinators: $all, $any, $not
|
|
12
|
+
|
|
13
|
+
Each operator is only valid for certain kinds (see below). Emit ONLY operators valid for the fact's kind.
|
|
14
|
+
`;function s(t){let e=t.nullable?" (nullable)":"";switch(t.kind){case "literal":return `literal ${JSON.stringify(t.value)} (${t.primitive})${e}`;case "enum":return `enum ${JSON.stringify(t.values)} (${t.primitive})${e}`;case "array":return `array of ${s(t.element)}${e}`;case "tuple":return `tuple [${t.elements.map(s).join(", ")}]${e}`;case "object":return `object { ${Object.entries(t.shape).map(([n,r])=>`${n}: ${s(r)}`).join(", ")} }${e}`;case "record":return `record<string, ${s(t.value)}>${e}`;case "union":return `union (${t.members.map(s).join(" | ")})${e}`;case "branded":return `branded(${s(t.inner)})${e}`;default:return `${t.kind}${e}`}}function J(t,e){let n=[H];n.push(`
|
|
15
|
+
Facts in this schema (path \u2192 kind \u2192 allowed operators):`);for(let[r,o]of t.entries()){if(e&&!r.startsWith(e))continue;let a=getOperatorsForKind(o);n.push(` ${r}: ${s(o)} \u2014 allowed: ${a.join(", ")}`);}return e&&n.push(`
|
|
16
|
+
The user intent will be over the namespace "${e}". Use only facts at or below that path.`),n.push(`
|
|
17
|
+
Respond with ONLY the JSON predicate object. No prose. No markdown fences. No "Here is...".`),n.join(`
|
|
18
|
+
`)}function M(t,e,n){let r=[];r.push("Your previous response was rejected. Original intent (still applies):"),r.push(` ${t}`);let o=null;if(typeof n=="string")r.push(`
|
|
19
|
+
Reason: ${n}`);else {r.push(`
|
|
20
|
+
Validation errors (fix every one):`),o=new Set;for(let a of n)r.push(` - path "${a.path}", op "${a.op}": ${a.reason}`),a.allowedOps&&a.allowedOps.length>0&&r.push(` \u2192 allowed operators for this fact: ${a.allowedOps.join(", ")}`),o.add(a.path);}if(r.push(`
|
|
21
|
+
Schema reminder:`),o&&o.size>0){let a=0;for(let p of o){let l=e.get(p);if(l){let y=getOperatorsForKind(l);r.push(` ${p}: ${s(l)} \u2014 allowed: ${y.join(", ")}`),a++;}else r.push(` ${p}: (not in schema \u2014 pick from the available facts below)`);}let i=e.size-a;i>0&&r.push(` \u2026and ${i} more fact(s) available \u2014 ask if you need the full list.`);}else for(let[a,i]of e.entries()){let p=getOperatorsForKind(i);r.push(` ${a}: ${s(i)} \u2014 allowed: ${p.join(", ")}`);}return r.push(`
|
|
22
|
+
Emit ONLY a corrected JSON FactPredicate object. No prose.`),r.join(`
|
|
23
|
+
`)}function B(t,e,n){if(t.length>n.maxPredicateBytes)return {ok:false,reason:`Output exceeded maxPredicateBytes=${n.maxPredicateBytes} (got ${t.length}). Emit a smaller predicate.`};let r;try{r=a(t);}catch(a){return {ok:false,reason:`Could not extract JSON from output: ${a instanceof Error?a.message:String(a)}`}}try{validatePredicate(r);}catch(a){return {ok:false,reason:`Structural validation failed: ${a instanceof Error?a.message:String(a)}`}}let o=validatePredicateAgainstSchema(r,e,{maxOperatorCount:n.maxOperatorCount,maxArrayOperandLength:n.maxArrayOperandLength});return o.ok?{ok:true,predicate:r}:{ok:false,reason:`Predicate has ${o.errors.length} schema-validation error(s).`,details:o.errors}}var Y=3,K=65536,V=256,W=1e3;async function X(t){let e=await k(t);if(e.predicate===null)throw new f(`[Directive] predicateFromIntent: failed after ${e.attempts} attempt(s). Last error: ${e.errors[e.errors.length-1]?.reason??"unknown"}`,e.attempts,e.errors,e.lastRawOutput);return e.predicate}async function k(t){let{intent:e,schema:n,runner:r,agent:o,factPath:a,maxRetries:i=Y,maxPredicateBytes:p=K,maxOperatorCount:l=V,maxArrayOperandLength:y=W,redact:w,signal:$}=t;if(typeof e!="string"||e.length===0)throw new Error("[Directive] predicateFromIntent: `intent` must be a non-empty string.");let P=w?w(e):e,u=getSchemaFieldKinds(n);if(u.size===0)throw new Error("[Directive] predicateFromIntent: schema has no introspectable facts. Pass a module schema or a bare facts record.");let R=J(u,a),O=o??{name:"predicate-emitter"},T={...O,instructions:`${O.instructions??""}
|
|
24
|
+
|
|
25
|
+
${R}`.trim()},c=[],b,d=0,I={maxPredicateBytes:p,maxOperatorCount:l,maxArrayOperandLength:y};for(;d<i+1;){if($?.aborted)throw new Error("aborted");d++;let j=d===1?`Intent: ${P}
|
|
26
|
+
|
|
27
|
+
Emit the predicate now.`:M(P,u,c[c.length-1].details??c[c.length-1].reason),m;try{m=await r(T,j,{signal:$});}catch(S){if($?.aborted)throw new Error("aborted");c.push({attempt:d,reason:`LLM runner threw: ${S instanceof Error?S.message:String(S)}`});continue}let F=typeof m.output=="string"?m.output:JSON.stringify(m.output);b=F;let h=B(F,u,I);if(h.ok)return {predicate:h.predicate,attempts:d,errors:c,lastRawOutput:b};c.push({attempt:d,reason:h.reason,details:h.details});}return {predicate:null,attempts:d,errors:c,lastRawOutput:b}}function v(t,e){let n=getSchemaFieldKinds(t),r=[];for(let[o,a]of n.entries()){if(e&&!o.startsWith(e))continue;let i=getOperatorsForKind(a);r.push(`${o}: ${s(a)} \u2014 ops: ${i.join(", ")}`);}return r.join(`
|
|
28
|
+
`)}function E(t,e){return e??`Emit a Directive FactPredicate (JSON tree of facts and operators) matching the user's intent. Schema:
|
|
29
|
+
${t}`}function G(t,e={}){let n=v(t,e.factPath),r=e.name??"emit_predicate",o=E(n,e.description);return {type:"function",function:{name:r,description:o,parameters:{type:"object",properties:{predicate:{type:"object"}},required:["predicate"]}},schemaSummary:n}}function U(t,e={}){let n=v(t,e.factPath),r=e.name??"emit_predicate",o=E(n,e.description);return {name:r,description:o,input_schema:{type:"object",properties:{predicate:{type:"object"}},required:["predicate"]},schemaSummary:n}}function Q(t,e={}){return U(t,e)}async function Z(t){let e=await k(t);if(e.predicate===null)throw new f(`[Directive] predicateFromIntentWithProvenance: failed after ${e.attempts} attempt(s). Last error: ${e.errors[e.errors.length-1]?.reason??"unknown"}`,e.attempts,e.errors,e.lastRawOutput);let n=t.redact?t.redact(t.intent):t.intent,r=t.agent?.model??"unknown",o=predicateHash(e.predicate),a=await C(n),i=t.redactIntent?{model:r,intentHash:a,attemptCount:e.attempts,emittedAt:new Date().toISOString(),predicateHash:o}:{model:r,intent:n,intentHash:a,attemptCount:e.attempts,emittedAt:new Date().toISOString(),predicateHash:o};return {predicate:e.predicate,provenance:i}}export{f as a,X as b,k as c,G as d,U as e,Q as f,Z as g};//# sourceMappingURL=chunk-POBEEJR6.js.map
|
|
30
|
+
//# sourceMappingURL=chunk-POBEEJR6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/predicate-from-intent.ts"],"names":["djb2Hash","str","hash","i","hashStringSha256","raw","subtle","enc","buf","bytes","hex","b","PredicateFromIntentError","message","attempts","errors","lastRawOutput","SYSTEM_PROMPT_HEADER","renderKindForPrompt","node","nullableTag","k","v","buildSystemPrompt","kindMap","factPath","lines","path","ops","getOperatorsForKind","buildErrorFeedback","intent","pathsToShow","e","shown","remaining","validateOneAttempt","rawOutput","opts","parsed","extractJsonFromOutput","err","validatePredicate","schemaResult","validatePredicateAgainstSchema","DEFAULT_MAX_RETRIES","DEFAULT_MAX_PREDICATE_BYTES","DEFAULT_MAX_OPERATOR_COUNT","DEFAULT_MAX_ARRAY_OPERAND_LENGTH","predicateFromIntent","result","predicateFromIntentRaw","rawIntent","schema","runner","agent","maxRetries","maxPredicateBytes","maxOperatorCount","maxArrayOperandLength","redact","signal","getSchemaFieldKinds","systemPrompt","baseAgent","promptAgent","attempt","validateOpts","input","runResult","validated","buildSchemaSummary","buildDescription","summary","override","predicateToolSpecOpenAI","name","description","predicateToolSpecAnthropic","predicateToolSpec","predicateFromIntentWithProvenance","sanitizedIntent","model","predicateHashValue","predicateHash","intentHash","provenance"],"mappings":"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","file":"chunk-POBEEJR6.js","sourcesContent":["/**\n * predicateFromIntent — let an LLM emit a typed FactPredicate as JSON,\n * structurally + semantically validated before it ever reaches your\n * constraint engine.\n *\n * Pipeline per call attempt:\n *\n * 1. Output-size check (reject before JSON.parse for DoS guard)\n * 2. JSON.parse via extractJsonFromOutput (handles surrounding prose)\n * 3. validatePredicate (structural: closed operator set, depth, JSON safety)\n * 4. Operator-count check\n * 5. validatePredicateAgainstSchema (semantic: operator-on-kind matrix)\n *\n * On any failure: a structured error message — including the offending\n * clause's path, the allowed operators for that fact's kind, and the\n * original schema kinds — is fed back to the LLM in the next attempt.\n *\n * Returns the validated FactPredicate. Throws PredicateFromIntentError\n * on retry exhaustion. NEVER returns a partial / unvalidated predicate.\n */\n\nimport {\n getOperatorsForKind,\n getSchemaFieldKinds,\n predicateHash,\n validatePredicate,\n validatePredicateAgainstSchema,\n type FactPredicate,\n type SchemaKindNode,\n type SchemaValidationError,\n} from \"@directive-run/core\";\n\nimport { extractJsonFromOutput } from \"./structured-output.js\";\nimport type { AgentLike, AgentRunner } from \"./types.js\";\n\n// ============================================================================\n// Hashing helpers\n// ============================================================================\n//\n// Provenance hashing has two flavors:\n//\n// - `predicateHash(spec)` — synchronous djb2 of a stable-stringified\n// predicate. Imported from `@directive-run/core` (the supported,\n// semver-stable surface). Two semantically-identical predicates emitted\n// with different whitespace / key-order produce the same hash. (N3)\n//\n// - `hashStringSha256(str)` — async SHA-256 via crypto.subtle when\n// available, djb2 fallback otherwise. Used for `intentHash` —\n// intents are free-form strings, no canonicalization to do.\n//\n\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\n }\n\n return (hash >>> 0).toString(16);\n}\n\nasync function hashStringSha256(raw: string): Promise<string> {\n // Prefer crypto.subtle SHA-256 when available (browsers, Node 19+, workers).\n // Fall back to a sync djb2 — collision-prone, but adequate for telemetry\n // alongside the persisted predicate.\n try {\n const subtle = (globalThis as { crypto?: { subtle?: SubtleCrypto } })\n .crypto?.subtle;\n if (subtle && typeof subtle.digest === \"function\") {\n const enc = new TextEncoder();\n const buf = await subtle.digest(\"SHA-256\", enc.encode(raw));\n const bytes = new Uint8Array(buf);\n let hex = \"\";\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\");\n }\n\n return hex;\n }\n } catch {\n // fall through to djb2\n }\n\n return djb2Hash(raw);\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PredicateFromIntentOptions<_F = Record<string, unknown>> {\n /** Natural-language intent (untrusted user input — sanitize via `redact`). */\n intent: string;\n /**\n * Module schema (must expose builders with `_typeName` or `_kind`).\n * Pass either `{ facts: {...} }` or a bare `Record<string, builder>`.\n */\n schema: unknown;\n /** AgentRunner from `@directive-run/ai` adapters (createOpenAIRunner, etc.). */\n runner: AgentRunner;\n /**\n * Optional agent override. Default is `{ name: \"predicate-emitter\" }`\n * with our system prompt; pass `instructions` to append additional\n * context.\n */\n agent?: AgentLike;\n /**\n * Optional dotted-path namespace; useful for cross-module systems\n * where the LLM should emit a predicate over `auth.token` (default:\n * the schema's root facts).\n */\n factPath?: string;\n /** Max retries on validation failure. Default 3. */\n maxRetries?: number;\n /**\n * Hard byte cap on the LLM's raw output, BEFORE JSON.parse. Defaults\n * to 64 KiB. A larger predicate is rejected outright; protects\n * against multi-MB-payload DoS where the predicate is technically\n * structurally valid.\n */\n maxPredicateBytes?: number;\n /**\n * Hard cap on the number of operator clauses in the predicate.\n * Defaults to 256. Protects against `{ $any: [{ x: 1 }, … x100,000 ] }`\n * style operator-count exhaustion.\n */\n maxOperatorCount?: number;\n /**\n * Optional sanitizer applied to `intent` BEFORE it lands in the\n * system prompt. Useful for stripping or redacting user-controlled\n * content that looks like prompt-injection.\n */\n redact?: (intent: string) => string;\n /**\n * Hard cap on the length of each `$in` / `$nin` array operand the LLM\n * may emit. Defaults to 1000. Forwarded to\n * `validatePredicateAgainstSchema`'s `maxArrayOperandLength`.\n */\n maxArrayOperandLength?: number;\n /**\n * Optional `AbortSignal` for cooperative cancellation. (N6)\n *\n * The retry loop checks `signal.aborted` between attempts AND forwards\n * the signal into the runner call itself (`runner(agent, input, { signal })`).\n * Whether the in-flight LLM call honors the signal depends on the runner:\n * fetch-based adapters (the bundled OpenAI / Anthropic / Ollama runners)\n * thread it through to `fetch`, so the network call aborts mid-stream.\n * A custom runner that ignores the signal still delivers cancellation\n * at the next retry boundary.\n *\n * On abort: throws `Error(\"aborted\")`.\n *\n * NOTE: `predicateFromIntent` does NOT limit in-flight calls — callers\n * MUST wrap with a concurrency limiter (e.g. `p-limit`) to bound\n * fan-out under load.\n */\n signal?: AbortSignal;\n /**\n * When `true`, the {@link PredicateFromIntentProvenance} returned by\n * `predicateFromIntentWithProvenance` omits the raw `intent` string and\n * stores only the SHA-256 `intentHash`. Use this in PII-sensitive\n * contexts where the original intent must not be persisted. (M6)\n *\n * **Default `false` for back-compat.** For PII-sensitive deployments,\n * ALWAYS set `redactIntent: true` — the raw intent may contain\n * user-supplied content (names, emails, medical or financial details,\n * customer messages) that becomes a permanent record in\n * `provenance.intent`. The default is opt-in only because flipping it\n * now would silently strip diagnostic data from existing callers; v2\n * may flip this default (tracked in IDEAS.md).\n *\n * Pair with a `redact:` sanitizer when the intent itself must be\n * scrubbed BEFORE it lands in the LLM prompt — `redactIntent` controls\n * only what enters the provenance record, not what the LLM sees.\n */\n redactIntent?: boolean;\n}\n\nexport interface PredicateFromIntentDiagnostics<F = Record<string, unknown>> {\n /** The validated predicate (`null` if all retries failed). */\n predicate: FactPredicate<F> | null;\n /** Number of LLM calls actually made. */\n attempts: number;\n /** Errors encountered across all attempts (most recent last). */\n errors: ReadonlyArray<{ attempt: number; reason: string; details?: readonly SchemaValidationError[] }>;\n /** The raw LLM output from the final attempt — useful for debugging. */\n lastRawOutput?: string;\n}\n\n/** Thrown by `predicateFromIntent` on retry exhaustion. `predicateFromIntentRaw` returns these as a diagnostics payload instead. */\nexport class PredicateFromIntentError extends Error {\n override readonly name = \"PredicateFromIntentError\";\n constructor(\n message: string,\n public readonly attempts: number,\n public readonly errors: ReadonlyArray<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }>,\n public readonly lastRawOutput: string | undefined,\n ) {\n super(message);\n }\n}\n\n// ============================================================================\n// Prompt builder\n// ============================================================================\n\nconst SYSTEM_PROMPT_HEADER = `You emit ONLY a JSON object describing a Directive FactPredicate — no prose, no markdown fences, no explanation.\n\nA FactPredicate is a JSON tree of fact paths and operators:\n- Object form (preferred): { \"factName\": { \"$op\": operand }, \"otherFact\": { \"$op\": operand } }\n- Combinators: { \"$all\": [predicateA, predicateB] }, { \"$any\": [...] }, { \"$not\": predicate }\n- Bare value (equality shortcut): { \"factName\": value }\n\nOperator set (CLOSED — only these are valid):\n $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $between,\n $matches, $startsWith, $endsWith, $contains, $changed\nCombinators: $all, $any, $not\n\nEach operator is only valid for certain kinds (see below). Emit ONLY operators valid for the fact's kind.\n`;\n\nfunction renderKindForPrompt(node: SchemaKindNode): string {\n const nullableTag = node.nullable ? \" (nullable)\" : \"\";\n switch (node.kind) {\n case \"literal\":\n return `literal ${JSON.stringify(node.value)} (${node.primitive})${nullableTag}`;\n case \"enum\":\n return `enum ${JSON.stringify(node.values)} (${node.primitive})${nullableTag}`;\n case \"array\":\n return `array of ${renderKindForPrompt(node.element)}${nullableTag}`;\n case \"tuple\":\n return `tuple [${node.elements.map(renderKindForPrompt).join(\", \")}]${nullableTag}`;\n case \"object\":\n return `object { ${Object.entries(node.shape)\n .map(([k, v]) => `${k}: ${renderKindForPrompt(v)}`)\n .join(\", \")} }${nullableTag}`;\n case \"record\":\n return `record<string, ${renderKindForPrompt(node.value)}>${nullableTag}`;\n case \"union\":\n return `union (${node.members.map(renderKindForPrompt).join(\" | \")})${nullableTag}`;\n case \"branded\":\n return `branded(${renderKindForPrompt(node.inner)})${nullableTag}`;\n default:\n return `${node.kind}${nullableTag}`;\n }\n}\n\nfunction buildSystemPrompt(\n kindMap: Map<string, SchemaKindNode>,\n factPath?: string,\n): string {\n const lines: string[] = [SYSTEM_PROMPT_HEADER];\n\n lines.push(\"\\nFacts in this schema (path → kind → allowed operators):\");\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(\n ` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`,\n );\n }\n if (factPath) {\n lines.push(\n `\\nThe user intent will be over the namespace \"${factPath}\". Use only facts at or below that path.`,\n );\n }\n\n lines.push(\n \"\\nRespond with ONLY the JSON predicate object. No prose. No markdown fences. No \\\"Here is...\\\".\",\n );\n\n return lines.join(\"\\n\");\n}\n\nfunction buildErrorFeedback(\n intent: string,\n kindMap: Map<string, SchemaKindNode>,\n errors: readonly SchemaValidationError[] | string,\n): string {\n const lines: string[] = [];\n lines.push(\"Your previous response was rejected. Original intent (still applies):\");\n lines.push(` ${intent}`);\n\n // M16: When we have structured errors, scope the schema reminder to only\n // the offending fact paths instead of dumping the full schema. Falls back\n // to the full schema for non-structural failures (string errors).\n let pathsToShow: Set<string> | null = null;\n\n if (typeof errors === \"string\") {\n lines.push(`\\nReason: ${errors}`);\n } else {\n lines.push(\"\\nValidation errors (fix every one):\");\n pathsToShow = new Set();\n for (const e of errors) {\n lines.push(` - path \"${e.path}\", op \"${e.op}\": ${e.reason}`);\n if (e.allowedOps && e.allowedOps.length > 0) {\n lines.push(` → allowed operators for this fact: ${e.allowedOps.join(\", \")}`);\n }\n // Collect every path mentioned by an error. If a path isn't in the\n // kindMap (unknown fact), the offending key may be a dotted prefix of\n // a real fact — include the closest known ancestor too.\n pathsToShow.add(e.path);\n }\n }\n\n lines.push(\"\\nSchema reminder:\");\n if (pathsToShow && pathsToShow.size > 0) {\n let shown = 0;\n for (const path of pathsToShow) {\n const node = kindMap.get(path);\n if (node) {\n const ops = getOperatorsForKind(node);\n lines.push(` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`);\n shown++;\n } else {\n lines.push(\n ` ${path}: (not in schema — pick from the available facts below)`,\n );\n }\n }\n const remaining = kindMap.size - shown;\n if (remaining > 0) {\n lines.push(` …and ${remaining} more fact(s) available — ask if you need the full list.`);\n }\n } else {\n for (const [path, node] of kindMap.entries()) {\n const ops = getOperatorsForKind(node);\n lines.push(` ${path}: ${renderKindForPrompt(node)} — allowed: ${ops.join(\", \")}`);\n }\n }\n\n lines.push(\"\\nEmit ONLY a corrected JSON FactPredicate object. No prose.\");\n\n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Validation pipeline (one attempt)\n// ============================================================================\n\nfunction validateOneAttempt(\n rawOutput: string,\n kindMap: Map<string, SchemaKindNode>,\n opts: {\n maxPredicateBytes: number;\n maxOperatorCount: number;\n maxArrayOperandLength: number;\n },\n):\n | { ok: true; predicate: unknown }\n | { ok: false; reason: string; details?: readonly SchemaValidationError[] } {\n // 1. Byte cap (pre-parse — kills 10MB-payload DoS)\n if (rawOutput.length > opts.maxPredicateBytes) {\n return {\n ok: false,\n reason: `Output exceeded maxPredicateBytes=${opts.maxPredicateBytes} (got ${rawOutput.length}). Emit a smaller predicate.`,\n };\n }\n\n // 2. JSON parse (handles surrounding prose)\n let parsed: unknown;\n try {\n parsed = extractJsonFromOutput(rawOutput);\n } catch (err) {\n return {\n ok: false,\n reason: `Could not extract JSON from output: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 3. Structural validation (closed operator set, depth, JSON-safety)\n try {\n validatePredicate(parsed);\n } catch (err) {\n return {\n ok: false,\n reason: `Structural validation failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n\n // 4 + 5. Operator-count cap + array-operand cap + schema validation\n const schemaResult = validatePredicateAgainstSchema(parsed, kindMap, {\n maxOperatorCount: opts.maxOperatorCount,\n maxArrayOperandLength: opts.maxArrayOperandLength,\n });\n\n if (!schemaResult.ok) {\n return {\n ok: false,\n reason: `Predicate has ${schemaResult.errors.length} schema-validation error(s).`,\n details: schemaResult.errors,\n };\n }\n\n return { ok: true, predicate: parsed };\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_MAX_PREDICATE_BYTES = 65_536; // 64 KiB\nconst DEFAULT_MAX_OPERATOR_COUNT = 256;\nconst DEFAULT_MAX_ARRAY_OPERAND_LENGTH = 1000;\n\n/**\n * Ask an LLM to emit a FactPredicate matching the user's intent, then\n * validate it structurally + semantically before returning. On validation\n * failure, retries with structured error feedback in the next prompt.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion. NEVER\n * returns a partial / unvalidated predicate.\n *\n * **Rate limiting:** this function does NOT limit in-flight calls. Wrap\n * with a concurrency limiter (e.g. `p-limit` / `Bottleneck`) before\n * exposing it to user-driven traffic. Pass an `AbortSignal` via `opts.signal`\n * for cooperative cancellation between retry attempts.\n *\n * @example\n * ```ts\n * import { createOpenAIRunner } from \"@directive-run/ai/openai\";\n * import { predicateFromIntent } from \"@directive-run/ai\";\n *\n * const runner = createOpenAIRunner({ apiKey, model: \"gpt-4o-mini\" });\n *\n * const predicate = await predicateFromIntent({\n * intent: \"checkout is unblocked when the cart total is at least 50\",\n * schema: myModule.schema,\n * runner,\n * });\n * // → { cartTotal: { $gte: 50 } }\n * ```\n */\nexport async function predicateFromIntent<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<FactPredicate<F>> {\n const result = await predicateFromIntentRaw(opts);\n if (result.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntent: failed after ${result.attempts} attempt(s). Last error: ${\n result.errors[result.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n result.attempts,\n result.errors,\n result.lastRawOutput,\n );\n }\n\n return result.predicate;\n}\n\n/**\n * Lower-level variant — returns the validated predicate (or null) plus\n * full diagnostics. Use when you want to surface validation telemetry,\n * preview the LLM's last raw output, or display per-attempt errors in\n * a UI.\n */\nexport async function predicateFromIntentRaw<F = Record<string, unknown>>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentDiagnostics<F>> {\n const {\n intent: rawIntent,\n schema,\n runner,\n agent,\n factPath,\n maxRetries = DEFAULT_MAX_RETRIES,\n maxPredicateBytes = DEFAULT_MAX_PREDICATE_BYTES,\n maxOperatorCount = DEFAULT_MAX_OPERATOR_COUNT,\n maxArrayOperandLength = DEFAULT_MAX_ARRAY_OPERAND_LENGTH,\n redact,\n signal,\n } = opts;\n\n if (typeof rawIntent !== \"string\" || rawIntent.length === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: `intent` must be a non-empty string.\",\n );\n }\n\n const intent = redact ? redact(rawIntent) : rawIntent;\n const kindMap = getSchemaFieldKinds(schema);\n\n if (kindMap.size === 0) {\n throw new Error(\n \"[Directive] predicateFromIntent: schema has no introspectable facts. Pass a module schema or a bare facts record.\",\n );\n }\n\n const systemPrompt = buildSystemPrompt(kindMap, factPath);\n const baseAgent: AgentLike = agent ?? { name: \"predicate-emitter\" };\n const promptAgent: AgentLike = {\n ...baseAgent,\n instructions: `${baseAgent.instructions ?? \"\"}\\n\\n${systemPrompt}`.trim(),\n };\n\n const errors: Array<{\n attempt: number;\n reason: string;\n details?: readonly SchemaValidationError[];\n }> = [];\n\n let lastRawOutput: string | undefined;\n let attempt = 0;\n const validateOpts = {\n maxPredicateBytes,\n maxOperatorCount,\n maxArrayOperandLength,\n };\n\n while (attempt < maxRetries + 1) {\n // M7: cooperative cancellation — bail between attempts when aborted.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n attempt++;\n const input =\n attempt === 1\n ? `Intent: ${intent}\\n\\nEmit the predicate now.`\n : buildErrorFeedback(intent, kindMap, errors[errors.length - 1]!.details ?? errors[errors.length - 1]!.reason);\n\n let runResult;\n try {\n // (N6) Forward the abort signal to the runner so in-flight LLM\n // calls can be cancelled mid-fetch. fetch-based adapters honor\n // this via the underlying fetch's `signal` option. Custom runners\n // that ignore the third arg fall back to between-retry cancellation.\n runResult = await runner(promptAgent, input, { signal });\n } catch (err) {\n // If the abort happened during the in-flight call (and the runner\n // honored it), surface that as a plain `Error(\"aborted\")` rather\n // than burning a retry attempt on a cancellation error.\n if (signal?.aborted) {\n throw new Error(\"aborted\");\n }\n errors.push({\n attempt,\n reason: `LLM runner threw: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n\n const rawOutput =\n typeof runResult.output === \"string\"\n ? runResult.output\n : JSON.stringify(runResult.output);\n lastRawOutput = rawOutput;\n\n const validated = validateOneAttempt(rawOutput, kindMap, validateOpts);\n\n if (validated.ok) {\n return {\n predicate: validated.predicate as FactPredicate<F>,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n }\n\n errors.push({\n attempt,\n reason: validated.reason,\n details: validated.details,\n });\n }\n\n return {\n predicate: null,\n attempts: attempt,\n errors,\n lastRawOutput,\n };\n}\n\n// ============================================================================\n// Tool-spec presets (OpenAI + Anthropic function-calling)\n// ============================================================================\n\nexport interface PredicateToolSpecOptions {\n /** Tool name. Default `\"emit_predicate\"`. */\n name?: string;\n /** Tool description. Default: a one-liner describing predicate emission. */\n description?: string;\n /** Optional dotted-path namespace to restrict the tool's scope. */\n factPath?: string;\n}\n\n/**\n * Anthropic Messages API tool shape. Drop into the `tools: [...]` array.\n * Anthropic's API expects `input_schema` at the top level of the tool.\n */\nexport interface PredicateToolSpecAnthropic {\n name: string;\n description: string;\n input_schema: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool shape. Drop into the\n * `tools: [...]` array. OpenAI nests the function payload under\n * `function: { name, description, parameters }`.\n */\nexport interface PredicateToolSpecOpenAI {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: { predicate: { type: \"object\" } };\n required: [\"predicate\"];\n };\n };\n /** Human-readable schema description — embed in your tool's \"description\" if your provider concatenates them. */\n schemaSummary: string;\n}\n\n/**\n * @deprecated Use {@link PredicateToolSpecAnthropic} (or\n * {@link PredicateToolSpecOpenAI}) directly. Kept as an alias for the\n * pre-split shape that v1.12.x callers depend on; identical to\n * `PredicateToolSpecAnthropic`.\n */\nexport type PredicateToolSpec = PredicateToolSpecAnthropic;\n\nfunction buildSchemaSummary(\n schema: unknown,\n factPath: string | undefined,\n): string {\n const kindMap = getSchemaFieldKinds(schema);\n const lines: string[] = [];\n for (const [path, node] of kindMap.entries()) {\n if (factPath && !path.startsWith(factPath)) continue;\n const ops = getOperatorsForKind(node);\n lines.push(`${path}: ${renderKindForPrompt(node)} — ops: ${ops.join(\", \")}`);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction buildDescription(summary: string, override?: string): string {\n return (\n override ??\n `Emit a Directive FactPredicate (JSON tree of facts and operators) matching the user's intent. Schema:\\n${summary}`\n );\n}\n\n/**\n * OpenAI Chat Completions / Responses API tool spec for predicate\n * emission. Drop the result into your `tools: [...]` array; the model\n * will be told to emit a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecOpenAI(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await openai.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecOpenAI(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecOpenAI {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n type: \"function\",\n function: {\n name,\n description,\n parameters: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * Anthropic Messages API tool spec for predicate emission. Drop the\n * result into your `tools: [...]` array; the model will be told to emit\n * a predicate matching this schema.\n *\n * @example\n * ```ts\n * const tool = predicateToolSpecAnthropic(myModule.schema, { name: \"set_checkout_rule\" });\n *\n * await anthropic.messages.create({\n * model: \"claude-3-5-sonnet-latest\",\n * tools: [tool],\n * messages: [...],\n * });\n * ```\n */\nexport function predicateToolSpecAnthropic(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpecAnthropic {\n const summary = buildSchemaSummary(schema, opts.factPath);\n const name = opts.name ?? \"emit_predicate\";\n const description = buildDescription(summary, opts.description);\n\n return {\n name,\n description,\n input_schema: {\n type: \"object\",\n properties: { predicate: { type: \"object\" } },\n required: [\"predicate\"],\n },\n schemaSummary: summary,\n };\n}\n\n/**\n * @deprecated Use {@link predicateToolSpecAnthropic} (or\n * {@link predicateToolSpecOpenAI}) directly. Back-compat alias for\n * v1.12.x callers — emits the Anthropic shape, unchanged.\n */\nexport function predicateToolSpec(\n schema: unknown,\n opts: PredicateToolSpecOptions = {},\n): PredicateToolSpec {\n return predicateToolSpecAnthropic(schema, opts);\n}\n\n// ============================================================================\n// Provenance (M24)\n// ============================================================================\n\nexport interface PredicateFromIntentProvenance {\n /**\n * Resolved model name when the caller passes `agent: { model }`,\n * otherwise `\"unknown\"`.\n *\n * NOTE: most callers omit `agent` (the default `predicate-emitter`\n * agent has no model field set), so `model` is `\"unknown\"` by default.\n * v1 does NOT read provider-detected model strings from `RunResult` —\n * that requires every adapter to surface `runResult.model`, which the\n * current `AgentRunner` contract does not. Tracked for v2; callers who\n * need provider attribution today should pass `agent: { name, model: \"...\" }`.\n */\n readonly model: string;\n /**\n * Sanitized intent string actually sent to the LLM (post-redact). When\n * `redactIntent: true` was passed, this field is omitted entirely — only\n * `intentHash` is populated.\n */\n readonly intent?: string;\n /**\n * SHA-256 hex hash of the sanitized intent string (or djb2 fallback\n * when `crypto.subtle` is unavailable). Always present — even when\n * `intent` is omitted via `redactIntent`. (M6)\n */\n readonly intentHash: string;\n /** Number of LLM calls that ran before the final predicate was accepted. */\n readonly attemptCount: number;\n /** ISO timestamp when the predicate was returned. */\n readonly emittedAt: string;\n /**\n * Hash of the VALIDATED predicate (canonicalized via stableStringify\n * before hashing). Two semantically-identical predicates emitted with\n * different whitespace or key order produce the SAME `predicateHash`.\n * Sufficient as a tamper-evident pointer alongside the persisted\n * predicate. (N3)\n *\n * Renamed from `rawOutputHash` in v1.13.x — the old name hashed the\n * raw LLM output string, which made two whitespace-different responses\n * for the same logical predicate hash differently. Callers persisting\n * the old `rawOutputHash` value should re-derive it from the stored\n * predicate using `hashObject(predicate)` from `@directive-run/core/internals`.\n */\n readonly predicateHash: string;\n}\n\nexport interface PredicateFromIntentWithProvenanceResult<F = Record<string, unknown>> {\n readonly predicate: FactPredicate<F>;\n readonly provenance: PredicateFromIntentProvenance;\n}\n\n/**\n * Like {@link predicateFromIntent} but additionally returns a structured\n * provenance record — the model name, sanitized intent (or its hash),\n * attempt count, timestamp, and a canonical hash of the validated\n * predicate.\n *\n * **Production deployments MUST persist the provenance record alongside\n * the predicate.** Without it, auditing \"where did this rule come from?\"\n * becomes guesswork.\n *\n * Throws {@link PredicateFromIntentError} on retry exhaustion — same\n * semantics as the un-provenanced variant.\n *\n * **PII guidance (M6):** pass `redactIntent: true` to omit the raw\n * intent from the provenance record and persist only the `intentHash`.\n * Useful when the intent itself is sensitive (medical, financial,\n * customer messages, etc.).\n *\n * **Hash semantics (N3):**\n * - `predicateHash` hashes the VALIDATED predicate object via stable\n * stringification — two whitespace-different LLM outputs that parse to\n * the same predicate produce the same hash.\n * - `intentHash` hashes the sanitized intent STRING (SHA-256 when\n * available, djb2 fallback).\n *\n * @example\n * ```ts\n * const { predicate, provenance } = await predicateFromIntentWithProvenance({\n * intent: \"block checkout when cart > 10k\",\n * schema: checkoutModule.schema,\n * runner,\n * agent: { name: \"predicate-emitter\", model: \"gpt-4o-mini\" },\n * redactIntent: false, // default: store both intent + intentHash\n * });\n *\n * await db.predicates.insert({\n * predicate,\n * model: provenance.model,\n * intent: provenance.intent, // omitted when redactIntent: true\n * intentHash: provenance.intentHash,\n * emittedAt: provenance.emittedAt,\n * predicateHash: provenance.predicateHash,\n * attempts: provenance.attemptCount,\n * });\n * ```\n */\nexport async function predicateFromIntentWithProvenance<\n F = Record<string, unknown>,\n>(\n opts: PredicateFromIntentOptions<F>,\n): Promise<PredicateFromIntentWithProvenanceResult<F>> {\n const raw = await predicateFromIntentRaw(opts);\n if (raw.predicate === null) {\n throw new PredicateFromIntentError(\n `[Directive] predicateFromIntentWithProvenance: failed after ${raw.attempts} attempt(s). Last error: ${\n raw.errors[raw.errors.length - 1]?.reason ?? \"unknown\"\n }`,\n raw.attempts,\n raw.errors,\n raw.lastRawOutput,\n );\n }\n\n const sanitizedIntent = opts.redact ? opts.redact(opts.intent) : opts.intent;\n const model = opts.agent?.model ?? \"unknown\";\n // (N3) Hash the VALIDATED predicate (stable canonical form), not the\n // raw LLM output — two semantically-identical responses with different\n // whitespace / key order produce the same hash. Uses the supported\n // public `predicateHash` helper from `@directive-run/core`.\n const predicateHashValue = predicateHash(raw.predicate);\n // (M6) Always hash the intent; raw intent string is included only when\n // `redactIntent` is not set.\n const intentHash = await hashStringSha256(sanitizedIntent);\n\n const provenance: PredicateFromIntentProvenance = opts.redactIntent\n ? {\n model,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n }\n : {\n model,\n intent: sanitizedIntent,\n intentHash,\n attemptCount: raw.attempts,\n emittedAt: new Date().toISOString(),\n predicateHash: predicateHashValue,\n };\n\n return {\n predicate: raw.predicate,\n provenance,\n };\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import {c}from'./chunk-UR5BMWEN.js';import {safeStringify}from'@directive-run/core/internals';function K(i){let{patterns:a=[/\b\d{3}-\d{2}-\d{4}\b/g,/\b\d{16}\b/g,/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi],redact:r=false,redactReplacement:t="[REDACTED]"}=i;return e=>{let n=e.input,s=false;for(let c of a)c.lastIndex=0,c.test(n)&&(s=true,r&&(c.lastIndex=0,n=n.replace(c,t)));return s&&!r?{passed:false,reason:"Input contains PII"}:{passed:true,transformed:r&&s?n:void 0}}}function ee(i){let{checkFn:a,message:r="Content flagged by moderation"}=i;return async t=>{let e="output"in t?typeof t.output=="string"?t.output:JSON.stringify(t.output):t.input,n=await a(e);return {passed:!n,reason:n?r:void 0}}}function te(i){let{maxTokensPerMinute:a=1e5,maxRequestsPerMinute:r=60}=i,t=Math.max(r,1e3),e=[],n=[],s=6e4;function c$1(d,u){let l=0,g=d.length;for(;l<g;){let p=l+g>>>1;(d[p]??0)<u?l=p+1:g=p;}return l}let o=(d,u)=>{let l=Date.now(),g=l-s,p=c$1(e,g);p>0&&(e=e.slice(p));let b=c$1(n,g);b>0&&(n=n.slice(b));let h=u.facts[c]?.tokenUsage??0,y=e.length,I=n.length;return y+h>a?{passed:false,reason:"Token rate limit exceeded"}:I>=r?{passed:false,reason:"Request rate limit exceeded"}:(n.length<t&&n.push(l),e.length<t&&e.push(l),{passed:true})};return o.reset=()=>{e=[],n=[];},o}function ne(i){let{allowlist:a,denylist:r,caseSensitive:t=false}=i,e=a?.map(s=>t?s:s.toLowerCase()),n=r?.map(s=>t?s:s.toLowerCase());return s=>{let c=t?s.toolCall.name:s.toolCall.name.toLowerCase();return e&&!e.includes(c)?{passed:false,reason:`Tool "${s.toolCall.name}" not in allowlist`}:n?.includes(c)?{passed:false,reason:`Tool "${s.toolCall.name}" is blocked`}:{passed:true}}}function re(i){let{validate:a,errorPrefix:r="Output schema validation failed"}=i;return t=>{let e=a(t.output);return typeof e=="boolean"?{passed:e,reason:e?void 0:r}:e.valid?{passed:true}:{passed:false,reason:e.errors?.length?`${r}: ${e.errors.join("; ")}`:r}}}function ie(i){let{type:a,requiredFields:r=[],minLength:t,maxLength:e,minStringLength:n,maxStringLength:s}=i;return c=>{let o=c.output;switch(a){case "string":return typeof o!="string"?{passed:false,reason:`Expected string, got ${typeof o}`}:n!==void 0&&o.length<n?{passed:false,reason:`String too short: ${o.length} < ${n}`}:s!==void 0&&o.length>s?{passed:false,reason:`String too long: ${o.length} > ${s}`}:{passed:true};case "number":return typeof o!="number"||Number.isNaN(o)?{passed:false,reason:`Expected number, got ${typeof o}`}:{passed:true};case "boolean":return typeof o!="boolean"?{passed:false,reason:`Expected boolean, got ${typeof o}`}:{passed:true};case "object":if(typeof o!="object"||o===null||Array.isArray(o))return {passed:false,reason:`Expected object, got ${Array.isArray(o)?"array":typeof o}`};for(let d of r)if(!(d in o))return {passed:false,reason:`Missing required field: ${d}`};return {passed:true};case "array":return Array.isArray(o)?t!==void 0&&o.length<t?{passed:false,reason:`Array too short: ${o.length} < ${t}`}:e!==void 0&&o.length>e?{passed:false,reason:`Array too long: ${o.length} > ${e}`}:{passed:true}:{passed:false,reason:`Expected array, got ${typeof o}`};default:return {passed:false,reason:`Unknown type: ${a}`}}}}function ae(i){let{maxCharacters:a,maxTokens:r,estimateTokens:t=e=>Math.ceil(e.length/4)}=i;return e=>{let n=safeStringify(e.output);if(a!==void 0&&n.length>a)return {passed:false,reason:`Output too long: ${n.length} characters (max: ${a})`};if(r!==void 0){let s=t(n);if(s>r)return {passed:false,reason:`Output too long: ~${s} tokens (max: ${r})`}}return {passed:true}}}function se(i){let{blockedPatterns:a,caseSensitive:r=false}=i;a.length===0&&console.warn("[Directive] createContentFilterGuardrail: blockedPatterns is empty \u2014 no content will be filtered");let t=a.map(e=>{if(e instanceof RegExp)return e;let n=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(n,r?"g":"gi")});return e=>{let n=safeStringify(e.output);for(let s of t)if(s.lastIndex=0,s.test(n))return {passed:false,reason:`Output contains blocked content matching: ${s.source}`};return {passed:true}}}var M=[{type:"ssn",pattern:/\b(\d{3}[-\s]?\d{2}[-\s]?\d{4})\b/g,validate:i=>{let a=i.replace(/[-\s]/g,"");return !(a.startsWith("000")||a.startsWith("666")||a.startsWith("9")||a.slice(3,5)==="00"||a.slice(5)==="0000")},confidence:.95},{type:"credit_card",pattern:/\b((?:\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4})|\d{13,19})\b/g,validate:i=>{let a=i.replace(/[-\s]/g,"");if(a.length<13||a.length>19)return false;let r=0,t=false;for(let e=a.length-1;e>=0;e--){let n=a[e];if(!n)continue;let s=Number.parseInt(n,10);t&&(s*=2,s>9&&(s-=9)),r+=s,t=!t;}return r%10===0},confidence:.95},{type:"email",pattern:/\b([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,})\b/gi,confidence:.9},{type:"phone",pattern:/\b(\+?1?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4})\b/g,validate:i=>{let a=i.replace(/\D/g,"");return a.length>=10&&a.length<=11},confidence:.8},{type:"date_of_birth",pattern:/\b(born|dob|birth.?date|date.?of.?birth)[:.\s]+(\d{1,4}[-/]\d{1,2}[-/]\d{1,4})\b/gi,valueGroup:2,confidence:.85},{type:"ip_address",pattern:/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/g,validate:i=>{let r=i.split(".").map(n=>Number.parseInt(n,10));if(r.some(n=>Number.isNaN(n)||n<0||n>255))return false;let[t,e]=r;return !(t===10||t===172&&e>=16&&e<=31||t===192&&e===168||t===127||t===169&&e===254||i==="0.0.0.0"||i==="255.255.255.255")},confidence:.9},{type:"bank_account",pattern:/\b(account|acct)[\s#:]+(\d{8,17})\b/gi,valueGroup:2,confidence:.7},{type:"passport",pattern:/\b(passport)[\s#:]+([A-Z0-9]{6,9})\b/gi,valueGroup:2,confidence:.75},{type:"driver_license",pattern:/\b(driver'?s?\s*licen[cs]e|dl)[\s#:]+([A-Z0-9]{5,15})\b/gi,valueGroup:2,confidence:.7},{type:"medical_id",pattern:/\b(mrn|medical.?record|patient.?id)[\s#:]+([A-Z0-9-]{6,15})\b/gi,valueGroup:2,confidence:.7},{type:"national_id",pattern:/\b(national.?id|nin|identity.?number|identity.?card|id.?number)[\s#:]+([A-Z0-9-]{6,20})\b/gi,valueGroup:2,confidence:.85}];function F(i){let a=[],r="street|st|avenue|ave|road|rd|drive|dr|lane|ln|court|ct|way|boulevard|blvd|circle|cir|place|pl",t=new RegExp(`\\b(\\d{1,5}\\s+(?:\\w+\\s+){1,4}(?:${r})\\b[^\\n]{0,50}\\b[A-Z]{2}\\s+\\d{5}(?:-\\d{4})?)\\b`,"gi"),e;for(;(e=t.exec(i))!==null;)a.push({type:"address",value:e[0],position:{start:e.index,end:e.index+e[0].length},confidence:.7});return a}var D=["mr","mrs","ms","miss","dr","prof","sir","madam","name is","called","known as","signed by","from","dear","hi","hello","contact","recipient"];function O(i){let a=[],r=D.join("|"),t=new RegExp(`\\b(${r})[.,:]?\\s+([A-Z][a-z]{1,20}(?:\\s[A-Z][a-z]{1,20}){0,2})\\b`,"gi"),e;for(;(e=t.exec(i))!==null;){let n=e[2],s=e[1];n&&(n.split(/\s+/).length>=2||s&&D.some(c=>s.toLowerCase().includes(c)))&&a.push({type:"name",value:n,position:{start:e.index,end:e.index+e[0].length},confidence:.6,context:e[0]});}return a}var N=1e5;function L(i,a){let r=[],t=new RegExp(i.pattern.source,i.pattern.flags),e=i.valueGroup??1,n;for(;(n=t.exec(a))!==null;){let s=n[e]??n[0],c=n.index,o=n.index+n[0].length,d=a.slice(Math.max(0,c-20),o+20);i.validate&&!i.validate(s,d)||r.push({type:i.type,value:s,position:{start:c,end:o},confidence:i.confidence,context:d});}return r}var P={name:"regex",async detect(i,a){if(i.length>N)throw new Error(`[Directive] Input exceeds maximum length of ${N} characters for PII detection. Truncate input or process in chunks.`);let r=[],t=new Set(a);for(let e of M)t.has(e.type)&&r.push(...L(e,i));return t.has("address")&&r.push(...F(i)),t.has("name")&&r.push(...O(i)),r}},z=new Set(["ssn","credit_card","date_of_birth","medical_id","national_id","passport","driver_license","bank_account"]);function H(i,a){let{start:r,end:t}=i.position;return Number.isInteger(r)&&Number.isInteger(t)&&r>=0&&r<t&&t<=a}function U(i,a){switch(a){case "placeholder":return "[REDACTED]";case "typed":return z.has(i.type)?"[REDACTED]":`[${i.type.toUpperCase()}]`;case "masked":{if(i.type!=="credit_card")return "****";let r=i.value.replace(/\D/g,"");return `****${r.length>4?r.slice(-4):""}`}case "hashed":return `[HASH:${V(i.value)}]`}}function _(i,a,r="typed"){let e=[...a.filter(o=>H(o,i.length))].sort((o,d)=>{if(d.confidence!==o.confidence)return d.confidence-o.confidence;let u=o.position.end-o.position.start,l=d.position.end-d.position.start;return l!==u?l-u:o.position.start-d.position.start}),n=[];for(let o of e)n.some(u=>o.position.start<u.position.end&&u.position.start<o.position.end)||n.push(o);let s=n.sort((o,d)=>d.position.start-o.position.start),c=i;for(let o of s){let d=U(o,r);c=c.slice(0,o.position.start)+d+c.slice(o.position.end);}return c}function V(i){let t=2166136261;for(let e=0;e<i.length;e++)t^=i.charCodeAt(e),t=Math.imul(t,16777619);return (t>>>0).toString(16).padStart(8,"0")}var G=["ssn","credit_card","email","phone","date_of_birth","bank_account"];function B(i={}){let{types:a=G,detector:r="regex",redact:t=false,redactionStyle:e="typed",minConfidence:n=.7,onDetected:s,allowlist:c=[],minItemsToBlock:o=1,detectorTimeout:d=5e3}=i,u=r==="regex"?P:r,l=new Set(c.map(p=>p.toLowerCase().trim()));async function g(p,b){if(u===P)return u.detect(p,b);let m,f=u.detect(p,b),h=new Promise((y,I)=>{m=setTimeout(()=>I(new Error(`[Directive] PII detector '${u.name}' timed out after ${d}ms`)),d);});f.catch(()=>{}),h.catch(()=>{});try{return await Promise.race([f,h])}finally{clearTimeout(m);}}return async p=>{let m=(await g(p.input,a)).filter(f=>!(f.confidence<n||l.has(f.value.toLowerCase().trim())));if(m.length>0&&s?.(m),m.length>=o){if(t)return {passed:true,transformed:_(p.input,m,e)};let f={};for(let y of m)f[y.type]=(f[y.type]||0)+1;return {passed:false,reason:`PII detected (${Object.entries(f).map(([y,I])=>`${y}: ${I}`).join(", ")})`}}return {passed:true}}}function ce(i={}){let a=B(i);return async(r,t)=>{let e=typeof r.output=="string"?r.output:JSON.stringify(r.output);return a({input:e,agentName:r.agentName},t)}}async function Z(i,a={}){let{types:r=G,detector:t="regex",minConfidence:e=.7,timeout:n=5e3}=a,s=t==="regex"?P:t,c;if(s===P)c=await s.detect(i,r);else {let u,l=s.detect(i,r),g=new Promise((p,b)=>{u=setTimeout(()=>b(new Error(`[Directive] PII detector '${s.name}' timed out after ${n}ms`)),n);});l.catch(()=>{}),g.catch(()=>{});try{c=await Promise.race([l,g]);}finally{clearTimeout(u);}}let o=c.filter(u=>u.confidence>=e),d={};for(let u of o)d[u.type]=(d[u.type]||0)+1;return {detected:o.length>0,items:o,typeCounts:d}}async function de(i,a={}){let r=await Z(i,a);return r.detected?{...r,redactedText:_(i,r.items,a.style??"typed")}:{...r}}var w=[{pattern:/ignore\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|prompts?|rules?|guidelines?)/i,name:"ignore-previous",severity:"critical",category:"instruction_override"},{pattern:/disregard\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|prompts?)/i,name:"disregard-previous",severity:"critical",category:"instruction_override"},{pattern:/forget\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|prompts?)/i,name:"forget-previous",severity:"critical",category:"instruction_override"},{pattern:/override\s+(the\s+)?(system|base)\s+(prompt|instructions?)/i,name:"override-system",severity:"critical",category:"instruction_override"},{pattern:/\bDAN\s+(mode|jailbreak)\b/i,name:"dan-mode",severity:"critical",category:"jailbreak"},{pattern:/\bjailbreak(ed)?\s*(mode)?\b/i,name:"jailbreak-keyword",severity:"high",category:"jailbreak"},{pattern:/developer\s+mode\s+(enabled|activated|on)/i,name:"developer-mode",severity:"critical",category:"jailbreak"},{pattern:/pretend\s+(you\s+)?(are|can|have)\s+(no\s+)?(restrictions?|limits?|boundaries?|ethics)/i,name:"pretend-no-restrictions",severity:"high",category:"jailbreak"},{pattern:/you\s+(now\s+)?have\s+no\s+(ethical\s+)?(restrictions?|guidelines?|boundaries?)/i,name:"no-restrictions",severity:"high",category:"jailbreak"},{pattern:/you\s+are\s+now\s+(a|an)\s+\w+\s+(that|who)\s+(can|will|must)/i,name:"role-assignment",severity:"medium",category:"role_manipulation"},{pattern:/from\s+now\s+on,?\s+(you\s+)?(will|must|should)\s+(only\s+)?/i,name:"from-now-on",severity:"medium",category:"role_manipulation"},{pattern:/^(system|assistant|user):\s*/im,name:"fake-role-marker",severity:"high",category:"context_manipulation"},{pattern:/<\|?(system|endofprompt|im_start|im_end)\|?>/i,name:"special-token-injection",severity:"critical",category:"context_manipulation"},{pattern:/```(system|assistant|instructions?)\n/i,name:"markdown-code-injection",severity:"medium",category:"delimiter_injection"},{pattern:/<system>|<\/system>|<instructions?>|<\/instructions?>/i,name:"xml-tag-injection",severity:"high",category:"delimiter_injection"},{pattern:/fetch\s+(content\s+)?(from|at)\s+(the\s+)?url/i,name:"url-fetch-instruction",severity:"medium",category:"indirect_injection"},{pattern:/execute\s+(the\s+)?(code|script|command)\s+(from|in|at)/i,name:"execute-from-source",severity:"high",category:"indirect_injection"}],k=[...w,{pattern:/act\s+as\s+(if\s+)?(you\s+)?(were|are|can)/i,name:"act-as",severity:"low",category:"role_manipulation"},{pattern:/new\s+instructions?:/i,name:"new-instructions",severity:"medium",category:"instruction_override"},{pattern:/\[system\]|\[admin\]|\[developer\]/i,name:"bracket-role-marker",severity:"medium",category:"context_manipulation"},{pattern:/base64|rot13|decode\s+(this|the)/i,name:"encoding-reference",severity:"low",category:"encoding_evasion"},{pattern:/\u200b|\u200c|\u200d|\u2060|\ufeff/,name:"zero-width-chars",severity:"medium",category:"encoding_evasion"}],A=1e5;function $(i,a=w){if(i.length>A)throw new Error(`[Directive] Input exceeds maximum length of ${A} characters for injection detection. Truncate input or process in chunks.`);let r=[];for(let{pattern:s,name:c,severity:o,category:d}of a){let l=new RegExp(s.source,s.flags).exec(i);l&&r.push({name:c,category:d,severity:o,match:l[0],position:l.index});}let t={low:10,medium:25,high:50,critical:100},e=r.reduce((s,c)=>s+t[c.severity],0),n=Math.min(100,e);return {detected:r.length>0,patterns:r,riskScore:n}}function q(i,a=w){let r=i.replace(/\u200b|\u200c|\u200d|\u2060|\ufeff/g,""),t=a.map(d=>`(${d.pattern.source})`);if(t.length===0)return r;let e=a.some(d=>d.pattern.flags.includes("g")),n=a.some(d=>d.pattern.flags.includes("i")),s=a.some(d=>d.pattern.flags.includes("m")),c=`${e?"g":""}${n?"i":""}${s?"m":""}`,o=new RegExp(t.join("|"),c||"gi");return r=r.replace(o,"[REDACTED]"),r}function W(i={}){let{additionalPatterns:a=[],replacePatterns:r,strictMode:t=false,blockThreshold:e=50,sanitize:n=false,onBlocked:s,ignoreCategories:c=[]}=i,o;if(r?o=r:o=t?[...k]:[...w],o=[...o,...a],c.length>0){let d=new Set(c);o=o.filter(u=>!d.has(u.category));}return d=>{let u=$(d.input,o);if(u.detected&&u.riskScore>=e){if(s?.(d.input,u),n)return {passed:true,transformed:q(d.input,o)};let l=u.patterns.sort((g,p)=>{let b={critical:0,high:1,medium:2,low:3};return b[g.severity]-b[p.severity]}).slice(0,3).map(g=>g.name).join(", ");return {passed:false,reason:`Prompt injection detected (risk: ${u.riskScore}%, patterns: ${l})`}}return {passed:true}}}function ue(i,a){return `[UNTRUSTED_CONTENT source="${a}"]
|
|
2
|
+
${i}
|
|
3
|
+
[/UNTRUSTED_CONTENT]`}function me(i){let{baseGuardrail:a=W({strictMode:true,blockThreshold:25}),additionalPatterns:r=[]}=i,t=/\[UNTRUSTED_CONTENT source="([^"]+)"\]([\s\S]*?)\[\/UNTRUSTED_CONTENT\]/g;return async(e,n)=>{let s=await a(e,n);if(!s.passed)return s;let c=e.input.matchAll(t);for(let o of c){let[,d,u]=o;if(!u)continue;let l=$(u,[...k,...r]);if(l.detected&&l.riskScore>=25)return {passed:false,reason:`Untrusted content from "${d}" contains potential injection (risk: ${l.riskScore}%)`}}return {passed:true}}}function v(i,a){if(i.length!==a.length)throw new Error(`Vector dimensions must match: ${i.length} vs ${a.length}`);let r=0,t=0,e=0;for(let n=0;n<i.length;n++){let s=i[n],c=a[n];r+=s*c,t+=s*s,e+=c*c;}return t=Math.sqrt(t),e=Math.sqrt(e),t===0||e===0?0:r/(t*e)}function J(i,a,r,t){let e=null;for(let n of a){if(t&&n.agentName&&n.agentName!==t)continue;let s=v(i,n.queryEmbedding);s>=r&&(!e||s>e.similarity)&&(e={entry:n,similarity:s});}return e}function Y(){let i=new Map;function a(r){let t=i.get(r);return t||(t=new Map,i.set(r,t)),t}return {async getEntries(r){return Array.from(a(r).values())},async addEntry(r,t){a(r).set(t.id,t);},async updateEntry(r,t,e){let n=a(r),s=n.get(t);s&&n.set(t,{...s,...e});},async removeEntry(r,t){a(r).delete(t);},async clear(r){i.delete(r);}}}function ge(i){let{embedder:a,similarityThreshold:r=.9,maxCacheSize:t=1e3,ttlMs:e=36e5,namespace:n="default",storage:s=Y(),onHit:c,onMiss:o,onError:d,perAgent:u=false}=i,l={totalEntries:0,totalHits:0,totalMisses:0,hitRate:0,avgSimilarityOnHit:0,oldestEntry:null,newestEntry:null},g=0;function p(m){if(l.totalEntries=m.length,l.hitRate=l.totalHits+l.totalMisses>0?l.totalHits/(l.totalHits+l.totalMisses):0,l.avgSimilarityOnHit=l.totalHits>0?g/l.totalHits:0,m.length>0){let f=m.map(h=>h.createdAt);l.oldestEntry=Math.min(...f),l.newestEntry=Math.max(...f);}else l.oldestEntry=null,l.newestEntry=null;}async function b(){let m=await s.getEntries(n),f=Date.now();for(let y of m)f-y.createdAt>e&&await s.removeEntry(n,y.id);let h=await s.getEntries(n);if(h.length>t){let I=h.sort((E,S)=>E.accessedAt-S.accessedAt).slice(0,h.length-t);for(let E of I)await s.removeEntry(n,E.id);}}return {async lookup(m,f){let h=Date.now();try{let y=await a(m),I=await s.getEntries(n),E=J(y,I,r,u?f:void 0);return E?(await s.updateEntry(n,E.entry.id,{accessedAt:Date.now(),accessCount:E.entry.accessCount+1}),l.totalHits++,g+=E.similarity,p(I),c?.(E.entry,E.similarity),{hit:!0,entry:E.entry,similarity:E.similarity,latencyMs:Date.now()-h}):(l.totalMisses++,p(I),o?.(m),{hit:!1,latencyMs:Date.now()-h})}catch(y){return l.totalMisses++,d?.(y instanceof Error?y:new Error(String(y))),{hit:false,latencyMs:Date.now()-h}}},async store(m,f,h,y={}){let I=await a(m),E={id:globalThis.crypto?.randomUUID?.()??`${Date.now()}-${Math.random().toString(36).slice(2,11)}`,query:m,queryEmbedding:I,response:f,metadata:y,createdAt:Date.now(),accessedAt:Date.now(),accessCount:0,agentName:u?h:void 0};await s.addEntry(n,E),await b();let S=await s.getEntries(n);p(S);},async invalidate(m){let f=await s.getEntries(n),h=0;for(let I of f)m(I)&&(await s.removeEntry(n,I.id),h++);let y=await s.getEntries(n);return p(y),h},async clear(){await s.clear(n),l={totalEntries:0,totalHits:0,totalMisses:0,hitRate:0,avgSimilarityOnHit:0,oldestEntry:null,newestEntry:null},g=0;},getStats(){return {...l}},async export(){return s.getEntries(n)},async import(m){for(let h of m)await s.addEntry(n,h);await b();let f=await s.getEntries(n);p(f);}}}function fe(i){let{cache:a}=i;return async r=>{let t=await a.lookup(r.input,r.agentName);return t.hit&&t.entry?{passed:false,cacheHit:true,reason:`Cache hit (similarity: ${(t.similarity*100).toFixed(1)}%)`,cachedResponse:t.entry.response,similarity:t.similarity}:{passed:true,cacheHit:false}}}function he(i=128){return async a=>{let r=new Array(i).fill(0);for(let e=0;e<a.length;e++){let n=a.charCodeAt(e);r[e%i]+=n/256;}let t=Math.sqrt(r.reduce((e,n)=>e+n*n,0));if(t>0)for(let e=0;e<i;e++)r[e]/=t;return r}}function ye(i){let{batchSize:a=20,embedBatch:r,maxWaitMs:t=50}=i;if(a<1||!Number.isFinite(a))throw new Error(`[Directive SemanticCache] batchSize must be >= 1, got ${a}`);let e=[],n=null,s=false;async function c(){if(e.length===0)return;let o=e;e=[],n&&(clearTimeout(n),n=null);try{let d=o.map(l=>l.text),u=await r(d);if(u.length!==o.length)throw new Error(`[Directive SemanticCache] embedBatch returned ${u.length} embeddings for ${o.length} texts. The embedBatch function must return exactly one embedding per input text.`);for(let l=0;l<o.length;l++)o[l].resolve(u[l]);}catch(d){let u=d instanceof Error?d:new Error(String(d));for(let l of o)l.reject(u);}}return {async embed(o){if(s)throw new Error("BatchedEmbedder has been destroyed");return new Promise((d,u)=>{e.push({text:o,resolve:d,reject:u}),e.length>=a?c():n||(n=setTimeout(c,t));})},async flush(){await c();},destroy(){s=true,n&&(clearTimeout(n),n=null);let o=e;e=[];let d=new Error("BatchedEmbedder destroyed");for(let u of o)u.reject(d);}}}function Ee(){let i=new Map,a=null;function r(t){if(a===null)a=t.length;else if(t.length!==a)throw new Error(`[Directive ANNIndex] Dimension mismatch: expected ${a}, got ${t.length}`)}return {add(t,e){r(e),i.set(t,e);},remove(t){i.delete(t);},search(t,e,n=0){if(a!==null&&t.length!==a)throw new Error(`[Directive ANNIndex] Query dimension mismatch: expected ${a}, got ${t.length}`);let s=[];for(let[c,o]of i){let d=v(t,o);d>=n&&s.push({id:c,similarity:d});}return s.sort((c,o)=>o.similarity-c.similarity),s.slice(0,e)},rebuild(){},size(){return i.size},clear(){i.clear(),a=null;},needsRebuild(){return false}}}function j(i,a){return 1-v(i,a)}function T(i,a){if(i.length===0)return null;let r=Math.floor(a()*i.length),t=i[r],e=i.filter((u,l)=>l!==r);if(e.length===0)return {id:t.id,embedding:t.embedding,mu:0,left:null,right:null};let n=e.map(u=>({item:u,distance:j(t.embedding,u.embedding)}));n.sort((u,l)=>u.distance-l.distance);let s=Math.floor(n.length/2),c=n[s].distance,o=n.slice(0,s).map(u=>u.item),d=n.slice(s).map(u=>u.item);return {id:t.id,embedding:t.embedding,mu:c,left:T(o,a),right:T(d,a)}}function x(i,a,r,t,e,n){if(!i)return;let s=j(a,i.embedding),c=1-s;c>=t&&(e.push({id:i.id,similarity:c}),e.sort((o,d)=>d.similarity-o.similarity),e.length>r&&e.pop(),e.length===r&&(n.value=1-e[e.length-1].similarity)),s<i.mu?(x(i.left,a,r,t,e,n),s+n.value>=i.mu&&x(i.right,a,r,t,e,n)):(x(i.right,a,r,t,e,n),s-n.value<=i.mu&&x(i.left,a,r,t,e,n));}function ve(i={}){let{random:a=Math.random}=i,r=new Map,t=null,e=false,n=null;function s(c){if(n===null)n=c.length;else if(c.length!==n)throw new Error(`[Directive ANNIndex] Dimension mismatch: expected ${n}, got ${c.length}`)}return {add(c,o){s(o),r.set(c,o),e=true;},remove(c){r.delete(c),e=true;},search(c,o,d=0){if(n!==null&&c.length!==n)throw new Error(`[Directive ANNIndex] Query dimension mismatch: expected ${n}, got ${c.length}`);if(e||!t){let g=[];for(let[p,b]of r){let m=v(c,b);m>=d&&g.push({id:p,similarity:m});}return g.sort((p,b)=>b.similarity-p.similarity),g.slice(0,o)}let u=[],l={value:Number.POSITIVE_INFINITY};return x(t,c,o,d,u,l),u},rebuild(){let c=Array.from(r.entries()).map(([o,d])=>({id:o,embedding:d}));t=T(c,a),e=false;},size(){return r.size},clear(){r.clear(),t=null,e=false,n=null;},needsRebuild(){return e}}}export{Ee as A,ve as B,K as a,ee as b,te as c,ne as d,re as e,ie as f,ae as g,se as h,_ as i,B as j,ce as k,Z as l,de as m,w as n,k as o,$ as p,q,W as r,ue as s,me as t,v as u,Y as v,ge as w,fe as x,he as y,ye as z};//# sourceMappingURL=chunk-QRXWLD6H.js.map
|
|
4
|
+
//# sourceMappingURL=chunk-QRXWLD6H.js.map
|