@promptev/context-engine 0.0.0 → 0.0.2

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.
Files changed (60) hide show
  1. package/README.md +116 -5
  2. package/dist/cli.js +1896 -552
  3. package/dist/cli.js.map +1 -1
  4. package/dist/{config-Bl9U789m.d.cts → config-BODDdXJ7.d.ts} +75 -16
  5. package/dist/{config-Bt9bUQqU.d.ts → config-C5RZ00W6.d.cts} +75 -16
  6. package/dist/express.cjs +925 -151
  7. package/dist/express.cjs.map +1 -1
  8. package/dist/express.d.cts +11 -4
  9. package/dist/express.d.ts +11 -4
  10. package/dist/express.js +926 -152
  11. package/dist/express.js.map +1 -1
  12. package/dist/fastify.cjs +923 -151
  13. package/dist/fastify.cjs.map +1 -1
  14. package/dist/fastify.d.cts +8 -4
  15. package/dist/fastify.d.ts +8 -4
  16. package/dist/fastify.js +924 -152
  17. package/dist/fastify.js.map +1 -1
  18. package/dist/{governance-XIScatRO.d.ts → governance-BLPK7NMe.d.ts} +8 -2
  19. package/dist/{governance-BDkcv4qZ.d.cts → governance-P9pRb4Ol.d.cts} +8 -2
  20. package/dist/graph/index.cjs +171 -59
  21. package/dist/graph/index.cjs.map +1 -1
  22. package/dist/graph/index.d.cts +5 -3
  23. package/dist/graph/index.d.ts +5 -3
  24. package/dist/graph/index.js +171 -59
  25. package/dist/graph/index.js.map +1 -1
  26. package/dist/hono.cjs +923 -151
  27. package/dist/hono.cjs.map +1 -1
  28. package/dist/hono.d.cts +8 -4
  29. package/dist/hono.d.ts +8 -4
  30. package/dist/hono.js +924 -152
  31. package/dist/hono.js.map +1 -1
  32. package/dist/index.cjs +2413 -1052
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +125 -107
  35. package/dist/index.d.ts +125 -107
  36. package/dist/index.js +2412 -1050
  37. package/dist/index.js.map +1 -1
  38. package/dist/mcp.cjs +100 -14
  39. package/dist/mcp.cjs.map +1 -1
  40. package/dist/mcp.d.cts +5 -0
  41. package/dist/mcp.d.ts +5 -0
  42. package/dist/mcp.js +100 -14
  43. package/dist/mcp.js.map +1 -1
  44. package/dist/migrations/sql/0003_tools.sql +2 -0
  45. package/dist/migrations/sql/0004_acl_indexes.sql +23 -2
  46. package/dist/{redaction-BmDSWJ7h.d.cts → redaction-BqD_DEUQ.d.cts} +22 -1
  47. package/dist/{redaction-BmDSWJ7h.d.ts → redaction-BqD_DEUQ.d.ts} +22 -1
  48. package/dist/redaction-presidio.d.cts +1 -1
  49. package/dist/redaction-presidio.d.ts +1 -1
  50. package/dist/{router-CrxZ2y_Z.d.ts → router-CiFwC-EN.d.cts} +17 -2
  51. package/dist/{router-OPgSoYAB.d.cts → router-D8gBzwLd.d.ts} +17 -2
  52. package/dist/skills/context-engine/SKILL.md +5 -1
  53. package/dist/storage-CJrKgJeJ.d.ts +167 -0
  54. package/dist/storage-Dvpq2xAC.d.cts +167 -0
  55. package/package.json +61 -23
  56. package/src/migrations/sql/0003_tools.sql +2 -0
  57. package/src/migrations/sql/0004_acl_indexes.sql +23 -2
  58. package/src/skills/context-engine/SKILL.md +5 -1
  59. package/dist/embeddings-B-jZ42mk.d.cts +0 -67
  60. package/dist/embeddings-DaSdAZN3.d.ts +0 -67
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/extras.ts","../src/tools/mcp-tools.ts","../src/version.ts","../src/mcp.ts"],"names":["handler"],"mappings":"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","file":"mcp.js","sourcesContent":["/** Action-surface errors — user-facing / data-dependent failures (not found, ACL, bad input).\n * Config/programming errors stay as TypeError / RangeError / Error.\n */\nexport class EngineActionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EngineActionError\";\n }\n}\n\n/** Missing vs forbidden document: identical message so callers cannot distinguish. */\nexport class DocumentNotFoundError extends Error {\n constructor(documentId: string) {\n super(`document not found: ${documentId}`);\n this.name = \"DocumentNotFoundError\";\n }\n}\n\nexport class GraphLegUnavailable extends Error {\n constructor(message = \"graph ranked list was not supplied\") {\n super(message);\n this.name = \"GraphLegUnavailable\";\n }\n}\n\nexport class ApprovalNotPending extends Error {\n constructor(message = \"approval is not pending\") {\n super(message);\n this.name = \"ApprovalNotPending\";\n }\n}\n\nexport class ApprovalExpired extends Error {\n constructor(message = \"approval has expired\") {\n super(message);\n this.name = \"ApprovalExpired\";\n }\n}\n\nexport class CodeExecutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CodeExecutionError\";\n }\n}\n\nexport class CodeExecutionTimeout extends Error {\n constructor(message = \"code execution timed out\") {\n super(message);\n this.name = \"CodeExecutionTimeout\";\n }\n}\n\nexport class ExtraMissingError extends Error {\n constructor(extra: string, pkg: string, what: string) {\n super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);\n this.name = \"ExtraMissingError\";\n }\n}\n","import { ExtraMissingError } from \"./errors.js\";\n\nexport async function tryImport<T = unknown>(specifier: string): Promise<T | null> {\n try {\n return (await import(specifier)) as T;\n } catch {\n return null;\n }\n}\n\nexport async function requireExtra<T = unknown>(specifier: string, extra: string, what: string): Promise<T> {\n try {\n return (await import(specifier)) as T;\n } catch (_err) {\n throw new ExtraMissingError(extra, specifier, what);\n }\n}\n","export type PrincipalsFn = () => unknown | Promise<unknown>;\n\nexport const SCOPE_NOTE =\n \" Results are scoped to the caller's permissions (resolved by the server's \" +\n \"injected principals dependency — never a caller-supplied argument) and to \" +\n \"the given source_ids, if any.\";\n\nexport async function resolvePrincipalsFn(principals: PrincipalsFn): Promise<string[] | null> {\n const result = await Promise.resolve(principals());\n return result as string[] | null;\n}\n\nexport type McpToolHost = {\n tool(\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (...args: never[]) => Promise<unknown>,\n ): unknown;\n};\n\nexport function registerToolGateway(\n mcp: McpToolHost,\n engine: {\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n },\n principals: PrincipalsFn,\n): void {\n mcp.tool(\n \"search_tools\",\n \"Keyword search over the tools this deployment has registered \" +\n \"(http/db/mcp/function) — the ACL-visible name, kind, description, \" +\n \"and JSON Schema params of each match, so a caller can discover what \" +\n \"it can then invoke with `execute_tool`.\" +\n SCOPE_NOTE,\n { query: { type: \"string\" }, limit: { type: \"number\" } },\n async (...raw: never[]) => {\n const args = (raw[0] ?? {}) as { query?: string; limit?: number };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n const tools = await engine.searchTools(String(args.query ?? \"\"), {\n principals: callerPrincipals,\n limit: args.limit ?? 10,\n });\n return { tools };\n },\n );\n\n mcp.tool(\n \"execute_tool\",\n \"Governed execution of a tool previously discovered via \" +\n \"`search_tools` (ACL check, approval gate, audit). Returns \" +\n \"`{result, usage}` on success, or an `approval_required` payload \" +\n \"when the call needs a human approval that isn't already granted — \" +\n \"the caller must not retry until that approval resolves.\" +\n SCOPE_NOTE,\n { name: { type: \"string\" }, args: { type: \"object\" } },\n async (...raw: never[]) => {\n const body = (raw[0] ?? {}) as { name?: string; args?: Record<string, unknown> };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n return engine.executeTool(String(body.name), body.args ?? null, {\n principals: callerPrincipals,\n source: \"mcp\",\n });\n },\n );\n}\n","/** Bumped by CI on every main merge; 0.0.0 = pre-first-release. */\nexport const __version__ = \"0.0.0\";\n","import { ExtraMissingError } from \"./errors.js\";\nimport { requireExtra } from \"./extras.js\";\nimport {\n type PrincipalsFn,\n registerToolGateway,\n resolvePrincipalsFn,\n SCOPE_NOTE,\n} from \"./tools/mcp-tools.js\";\nimport { __version__ } from \"./version.js\";\n\ntype Engine = {\n config: { llm?: unknown; enableCodeExecution?: boolean };\n search: (query: string, opts?: Record<string, unknown>) => Promise<{ hits: unknown[]; usage?: unknown }>;\n getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;\n compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n};\n\nfunction asMcpResult(data: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(data) }] };\n}\n\nexport async function createMcpApp(\n engine: Engine,\n opts: { principals: PrincipalsFn },\n): Promise<\n ((req: import(\"node:http\").IncomingMessage, res: import(\"node:http\").ServerResponse) => Promise<void>) & {\n mcp: unknown;\n }\n> {\n if (!opts?.principals) {\n throw new TypeError(\"createMcpApp requires principals\");\n }\n\n let McpServer: new (info: {\n name: string;\n version: string;\n }) => {\n tool: (...args: unknown[]) => unknown;\n connect: (t: unknown) => Promise<void>;\n };\n let StreamableHTTPServerTransport: new (opts: {\n sessionIdGenerator?: undefined;\n }) => {\n handleRequest: (req: unknown, res: unknown, body?: unknown) => Promise<void>;\n };\n try {\n const serverMod = await requireExtra<{ McpServer: typeof McpServer }>(\n \"@modelcontextprotocol/sdk/server/mcp.js\",\n \"mcp\",\n \"MCP server\",\n );\n const httpMod = await requireExtra<{\n StreamableHTTPServerTransport: typeof StreamableHTTPServerTransport;\n }>(\"@modelcontextprotocol/sdk/server/streamableHttp.js\", \"mcp\", \"MCP server\");\n McpServer = serverMod.McpServer;\n StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;\n } catch (exc) {\n if (exc instanceof ExtraMissingError) throw exc;\n throw new ExtraMissingError(\"mcp\", \"@modelcontextprotocol/sdk\", \"MCP server\");\n }\n\n const mcp = new McpServer({ name: \"context-engine\", version: __version__ });\n\n const tool = (\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (args: Record<string, unknown>) => Promise<unknown>,\n ) => {\n mcp.tool(name, description, schema, async (args: Record<string, unknown>) =>\n asMcpResult(await handler(args)),\n );\n };\n\n tool(\n \"search_knowledge_base\",\n `Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,\n {\n query: { type: \"string\" },\n source_ids: { type: \"array\", items: { type: \"string\" } },\n top_k: { type: \"number\" },\n mode: { type: \"string\", enum: [\"hybrid\", \"graph\"] },\n },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n const result = await engine.search(String(args.query ?? \"\"), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n topK: args.top_k ?? 10,\n mode: args.mode ?? \"hybrid\",\n });\n return {\n hits: (result.hits ?? []).map((hit) => {\n const h = hit as Record<string, unknown>;\n return {\n document_name: h.document_name ?? h.documentName,\n chunk_text: h.chunk_text ?? h.chunkText,\n score: h.score,\n source_id: h.source_id ?? h.sourceId,\n };\n }),\n usage: result.usage,\n };\n },\n );\n\n tool(\n \"get_document\",\n `Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,\n { document_id: { type: \"string\" } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n return engine.getDocument(String(args.document_id), { principals: callerPrincipals });\n },\n );\n\n if (engine.config.llm != null) {\n tool(\n \"query_structured\",\n `Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,\n { question: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.queryStructured) throw new Error(\"queryStructured is not available on this engine\");\n return engine.queryStructured(String(args.question), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n if (engine.config.enableCodeExecution) {\n tool(\n \"compute\",\n `Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,\n { instruction: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.compute) throw new Error(\"compute is not available on this engine\");\n return engine.compute(String(args.instruction), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n }\n }\n\n registerToolGateway(\n {\n tool: (name, description, schema, handler) => {\n tool(name, description, schema, async (args) => handler(args as never));\n },\n },\n engine,\n opts.principals,\n );\n\n const handler = (async (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => {\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });\n await mcp.connect(transport);\n await transport.handleRequest(req, res);\n }) as ((\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => Promise<void>) & { mcp: unknown };\n handler.mcp = mcp;\n return handler;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/extras.ts","../src/sentinels.ts","../src/routing-core.ts","../src/tools/mcp-tools.ts","../src/version.ts","../src/mcp.ts"],"names":["z","handler"],"mappings":"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","file":"mcp.js","sourcesContent":["/** Action-surface errors — user-facing / data-dependent failures (not found, ACL, bad input).\n * Config/programming errors stay as TypeError / RangeError / Error.\n */\nexport class EngineActionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EngineActionError\";\n }\n}\n\n/** Missing vs forbidden document: identical message so callers cannot distinguish. */\nexport class DocumentNotFoundError extends Error {\n constructor(documentId: string) {\n super(`document not found: ${documentId}`);\n this.name = \"DocumentNotFoundError\";\n }\n}\n\nexport class GraphLegUnavailable extends Error {\n constructor(message = \"graph ranked list was not supplied\") {\n super(message);\n this.name = \"GraphLegUnavailable\";\n }\n}\n\nexport class ApprovalNotPending extends Error {\n constructor(message = \"approval is not pending\") {\n super(message);\n this.name = \"ApprovalNotPending\";\n }\n}\n\nexport class ApprovalExpired extends Error {\n constructor(message = \"approval has expired\") {\n super(message);\n this.name = \"ApprovalExpired\";\n }\n}\n\nexport class CodeExecutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CodeExecutionError\";\n }\n}\n\nexport class CodeExecutionTimeout extends Error {\n constructor(message = \"code execution timed out\") {\n super(message);\n this.name = \"CodeExecutionTimeout\";\n }\n}\n\nexport class ExtraMissingError extends Error {\n constructor(extra: string, pkg: string, what: string) {\n super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);\n this.name = \"ExtraMissingError\";\n }\n}\n","import { ExtraMissingError } from \"./errors.js\";\n\nexport async function tryImport<T = unknown>(specifier: string): Promise<T | null> {\n try {\n return (await import(specifier)) as T;\n } catch {\n return null;\n }\n}\n\nexport async function requireExtra<T = unknown>(specifier: string, extra: string, what: string): Promise<T> {\n try {\n return (await import(specifier)) as T;\n } catch (_err) {\n throw new ExtraMissingError(extra, specifier, what);\n }\n}\n","/**\n * Sentinels distinguishing omitted arguments from real values, including null.\n *\n * UNSET: \"argument omitted\" vs null (e.g. updateDocument acl=null means unrestricted).\n * TRUSTED: trusted caller, ACL filtering disabled. Truthy on purpose so\n * `if (principals)` does not treat a trusted caller as anonymous.\n */\n\nexport const UNSET: unique symbol = Symbol.for(\"context_engine.UNSET\");\nexport type Unset = typeof UNSET;\n\n// Symbol.for (the process-global registry), NEVER a class instance: the\n// package ships per-entry bundles (tsup splitting:false), so dist/index.js\n// and dist/mcp.js each carry their own copy of this module. A class instance\n// is a different object per copy, and `result === TRUSTED` then fails for an\n// app importing TRUSTED from one entry while mounting another — every tool\n// call on a correctly configured trusted mount errors. UNSET above survives\n// bundle duplication for exactly this reason; TRUSTED must too.\nexport const TRUSTED: unique symbol = Symbol.for(\"context_engine.TRUSTED\");\nexport type Trusted = typeof TRUSTED;\n\nexport type Principals = string[] | null | typeof TRUSTED | undefined;\n\n// Once per method, matching Python's default warnings filter — before the\n// dedup, a legacy caller re-triggered the warning on EVERY request.\nconst warnedMethods = new Set<string>();\n\nexport function resolvePrincipals(value: Principals, method: string): string[] | null {\n if (value === TRUSTED) return null;\n if (value === undefined || value === null) {\n // `undefined` (omitted) is the same legacy trusted spelling as `null` —\n // Python's omitted `principals` defaults to None and warns identically.\n if (!warnedMethods.has(method)) {\n warnedMethods.add(method);\n process.emitWarning(\n `${method}(principals=${value === null ? \"null\" : \"undefined\"}) means TRUSTED CALLER — ` +\n `access control is disabled and every document is returned. If that is what ` +\n `you want, pass principals=TRUSTED (from @promptev/context-engine) to say so ` +\n `explicitly. If you meant 'no authenticated user', pass principals=[] instead. ` +\n `Passing null/omitting will raise in 1.0.`,\n { type: \"DeprecationWarning\", code: \"CE_PRINCIPALS_NULL\" },\n );\n }\n return null;\n }\n if (!Array.isArray(value)) {\n // NEVER coerce: a bare string (or any other object) coercing to null\n // used to mean full-corpus TRUSTED — an ACL bypass a caller could hit\n // with one wrong type. Fail loudly instead.\n throw new TypeError(\n `${method}(principals=...) must be an array of principal strings, [] for an ` +\n `anonymous caller, or TRUSTED — got ${typeof value}. A non-array value must ` +\n `never silently disable ACL filtering.`,\n );\n }\n return value;\n}\n\nexport function isTrusted(principals: string[] | null | undefined): boolean {\n return principals === null || principals === undefined;\n}\n","import { z } from \"zod\";\nimport { TRUSTED, type Trusted } from \"./sentinels.js\";\n\nexport class HandlerError extends Error {\n status: number;\n detail: unknown;\n constructor(status: number, detail: unknown) {\n super(typeof detail === \"string\" ? detail : JSON.stringify(detail));\n this.name = \"HandlerError\";\n this.status = status;\n this.detail = detail;\n }\n}\n\nexport const ingestJsonRequestSchema = z\n .object({\n text: z.string(),\n name: z.string(),\n source_id: z.string().nullable().optional(),\n external_id: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n meta_data: z.record(z.unknown()).nullable().optional(),\n acl: z.array(z.string()).nullable().optional(),\n mode: z.enum([\"hybrid\", \"graph\"]).nullable().optional(),\n extract_structured: z.boolean().optional().default(false),\n batch: z.boolean().optional().default(false),\n })\n .strip();\n\nexport const documentPatchSchema = z\n .object({\n acl: z.array(z.string()).nullable().optional(),\n name: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n meta_data: z.record(z.unknown()).nullable().optional(),\n })\n .strict();\n\nexport const searchRequestSchema = z\n .object({\n query: z.string(),\n source_ids: z.array(z.string()).nullable().optional(),\n // Narrows WITHIN a source and INTERSECTS with source_ids — it can only\n // shrink the result set (the ACL predicate still applies in the same SQL\n // conjunction), so exposing it needs no authorizeAcl-style grant check.\n document_ids: z.array(z.string()).nullable().optional(),\n top_k: z.number().int().optional().default(10),\n mode: z.enum([\"hybrid\", \"graph\"]).optional().default(\"hybrid\"),\n compress_to_tokens: z.number().int().nullable().optional(),\n })\n .strip();\n\nexport type IngestJSONRequest = z.infer<typeof ingestJsonRequestSchema>;\nexport type DocumentPatch = z.infer<typeof documentPatchSchema>;\nexport type SearchRequest = z.infer<typeof searchRequestSchema>;\n\nexport type ContextEngineLike = {\n ingest: (args: Record<string, unknown>) => Promise<unknown>;\n search: (query: string, opts?: Record<string, unknown>) => Promise<{ hits?: unknown[]; usage?: unknown }>;\n listDocuments: (opts: Record<string, unknown>) => Promise<unknown>;\n getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n deleteDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n updateDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n stats: (sourceId?: string | null) => Promise<unknown>;\n};\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function requireValidUuid(documentId: string): void {\n if (!UUID_RE.test(String(documentId))) {\n throw new HandlerError(400, `invalid document id: ${JSON.stringify(documentId)}`);\n }\n}\n\nexport function formBool(value: unknown): boolean {\n if (typeof value === \"boolean\") return value;\n if (value == null) return false;\n return [\"1\", \"true\", \"yes\", \"on\"].includes(String(value).trim().toLowerCase());\n}\n\nexport function formJson(value: unknown): unknown {\n if (value === undefined || value === null || value === \"\") return null;\n if (typeof value === \"object\") return value;\n try {\n return JSON.parse(String(value));\n } catch {\n throw new HandlerError(400, `invalid JSON in field: ${JSON.stringify(value)}`);\n }\n}\n\nexport function formStr(value: unknown): string | null {\n return value === undefined || value === null || value === \"\" ? null : String(value);\n}\n\nexport function resolveRequestPrincipals(value: unknown, opts: { surface: string }): string[] | Trusted {\n // Hand the SENTINEL through, not null: every engine method resolves TRUSTED\n // silently, while `principals=null` triggers the deprecation warning aimed\n // at legacy in-process callers — collapsing here made a correctly\n // configured trusted mount re-trigger that warning on every request.\n if (value === TRUSTED) return TRUSTED;\n if (value == null) {\n throw new HandlerError(\n 500,\n `${opts.surface}: the \\`principals\\` dependency returned null, which means ` +\n `TRUSTED CALLER — it disables ACL filtering and skips the check that ` +\n `stops a caller filing documents under groups it does not hold. This ` +\n `mount is misconfigured: return [] for an unauthenticated caller, or ` +\n `pass TRUSTED explicitly (from @promptev/context-engine) if the surface really ` +\n `is trusted.`,\n );\n }\n // A runtime check, not a cast: `as string[]` let a plain-JS dependency\n // return a bare string that flowed into resolvePrincipals and (before its\n // own guard) coerced to full-corpus TRUSTED.\n if (!Array.isArray(value) || value.some((p) => typeof p !== \"string\")) {\n throw new HandlerError(\n 500,\n `${opts.surface}: the \\`principals\\` dependency must return a list of ` +\n `principal strings, [] for an anonymous caller, or TRUSTED — got ${typeof value}.`,\n );\n }\n return value;\n}\n\nexport function authorizeAcl(requested: unknown, principals: string[] | null | Trusted): void {\n if (requested == null || principals == null || principals === TRUSTED) return;\n if (!Array.isArray(requested)) {\n throw new HandlerError(422, \"acl must be a list of principal strings\");\n }\n // TRUSTED was excluded above, so what remains is the plain list.\n const held = new Set(principals as string[]);\n const ungranted = [...new Set(requested.map(String))].filter((p) => !held.has(p)).sort();\n if (ungranted.length) {\n throw new HandlerError(403, `cannot grant access to principals you do not hold: ${ungranted}`);\n }\n}\n\nfunction asDict(obj: unknown): unknown {\n if (obj == null) return obj;\n if (typeof obj === \"object\" && typeof (obj as { toJSON?: () => unknown }).toJSON === \"function\") {\n return (obj as { toJSON: () => unknown }).toJSON();\n }\n return obj;\n}\n\nfunction zodError(err: z.ZodError): HandlerError {\n return new HandlerError(\n 422,\n err.issues.map((i) => ({ loc: i.path, msg: i.message, type: i.code })),\n );\n}\n\nasync function runIngest(engine: ContextEngineLike, kwargs: Record<string, unknown>): Promise<unknown> {\n try {\n return asDict(await engine.ingest(kwargs));\n } catch (exc) {\n if (exc instanceof TypeError || (exc instanceof Error && exc.name === \"TypeError\")) {\n throw new HandlerError(400, String(exc));\n }\n if (exc instanceof Error && exc.name === \"Error\" && /invalid|required/i.test(exc.message)) {\n throw new HandlerError(400, String(exc));\n }\n throw exc;\n }\n}\n\nexport async function handleIngestJson(\n engine: ContextEngineLike,\n payload: unknown,\n principals: unknown,\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(principals, { surface: \"handle_ingest_json\" });\n const parsed = ingestJsonRequestSchema.safeParse(payload);\n if (!parsed.success) throw zodError(parsed.error);\n const body = parsed.data;\n authorizeAcl(body.acl, resolved);\n return runIngest(engine, {\n text: body.text,\n name: body.name,\n description: body.description,\n sourceId: body.source_id,\n externalId: body.external_id,\n metaData: body.meta_data,\n acl: body.acl,\n mode: body.mode,\n extractStructured: body.extract_structured,\n batch: body.batch,\n });\n}\n\nexport async function handleIngestFile(\n engine: ContextEngineLike,\n opts: {\n content: Buffer | Uint8Array;\n filename: string | null | undefined;\n form: Record<string, unknown> | Map<string, unknown>;\n principals: unknown;\n },\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(opts.principals, { surface: \"handle_ingest_file\" });\n const form = opts.form instanceof Map ? Object.fromEntries(opts.form) : opts.form;\n const acl = formJson(form.acl);\n authorizeAcl(acl, resolved);\n return runIngest(engine, {\n content: opts.content,\n filename: opts.filename,\n name: formStr(form.name) || opts.filename,\n description: formStr(form.description),\n sourceId: formStr(form.source_id),\n externalId: formStr(form.external_id),\n metaData: formJson(form.meta_data),\n acl,\n mode: formStr(form.mode),\n extractStructured: formBool(form.extract_structured),\n batch: formBool(form.batch),\n });\n}\n\nexport async function handleListDocuments(\n engine: ContextEngineLike,\n opts: {\n sourceId: string | null | undefined;\n limit: number;\n cursor: string | null | undefined;\n principals: unknown;\n },\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(opts.principals, { surface: \"handle_list_documents\" });\n let parsedCursor: unknown = null;\n if (opts.cursor) {\n try {\n parsedCursor = JSON.parse(opts.cursor);\n } catch {\n throw new HandlerError(400, `invalid cursor: ${JSON.stringify(opts.cursor)}`);\n }\n }\n return engine.listDocuments({\n sourceId: opts.sourceId ?? null,\n principals: resolved,\n cursor: parsedCursor,\n limit: opts.limit,\n });\n}\n\nexport async function handleGetDocument(\n engine: ContextEngineLike,\n documentId: string,\n principals: unknown,\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(principals, { surface: \"handle_get_document\" });\n requireValidUuid(documentId);\n try {\n return await engine.getDocument(documentId, { principals: resolved });\n } catch (exc) {\n if (\n exc instanceof Error &&\n (exc.name === \"DocumentNotFoundError\" || exc instanceof TypeError === false)\n ) {\n const msg = String(exc);\n if (/not found/i.test(msg) || exc.name === \"DocumentNotFoundError\") {\n throw new HandlerError(404, msg.replace(/^Error:\\s*/, \"\"));\n }\n }\n throw exc;\n }\n}\n\nexport async function handleDeleteDocument(\n engine: ContextEngineLike,\n documentId: string,\n principals: unknown,\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(principals, { surface: \"handle_delete_document\" });\n requireValidUuid(documentId);\n try {\n await engine.deleteDocument(documentId, { principals: resolved });\n } catch (exc) {\n const msg = String(exc);\n if (/not found/i.test(msg) || (exc instanceof Error && exc.name === \"DocumentNotFoundError\")) {\n throw new HandlerError(404, msg.replace(/^Error:\\s*/, \"\"));\n }\n throw exc;\n }\n return { deleted: documentId };\n}\n\nexport async function handleUpdateDocument(\n engine: ContextEngineLike,\n documentId: string,\n payload: unknown,\n principals: unknown,\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(principals, { surface: \"handle_update_document\" });\n requireValidUuid(documentId);\n const parsed = documentPatchSchema.safeParse(payload);\n if (!parsed.success) throw zodError(parsed.error);\n const provided: Record<string, unknown> = {};\n const raw = payload as Record<string, unknown>;\n for (const key of [\"acl\", \"name\", \"description\", \"meta_data\"] as const) {\n if (Object.hasOwn(raw, key)) {\n provided[key === \"meta_data\" ? \"metaData\" : key] = raw[key];\n }\n }\n if (\"acl\" in provided) authorizeAcl(provided.acl, resolved);\n try {\n const changed = await engine.updateDocument(documentId, { principals: resolved, ...provided });\n return { changed };\n } catch (exc) {\n const msg = String(exc);\n if (/not found/i.test(msg) || (exc instanceof Error && exc.name === \"DocumentNotFoundError\")) {\n throw new HandlerError(404, msg.replace(/^Error:\\s*/, \"\"));\n }\n throw exc;\n }\n}\n\nexport async function handleSearch(\n engine: ContextEngineLike,\n payload: unknown,\n principals: unknown,\n): Promise<unknown> {\n const resolved = resolveRequestPrincipals(principals, { surface: \"handle_search\" });\n const parsed = searchRequestSchema.safeParse(payload);\n if (!parsed.success) throw zodError(parsed.error);\n const body = parsed.data;\n // Early, like every sibling document endpoint: a malformed id must be a\n // clean 400 here, not a Postgres 22P02 raised inside every search leg —\n // whose 400-vs-500 mapping would otherwise hang on the ENGLISH pg error\n // text, with the raw DatabaseError echoed to the caller.\n for (const did of body.document_ids ?? []) requireValidUuid(did);\n try {\n const result = await engine.search(body.query, {\n sourceIds: body.source_ids,\n documentIds: body.document_ids,\n principals: resolved,\n topK: body.top_k,\n mode: body.mode,\n compressToTokens: body.compress_to_tokens,\n });\n const hits = (result.hits ?? []).map((hit) => asDict(hit));\n return { hits, usage: result.usage };\n } catch (exc) {\n if (exc instanceof Error && /invalid|required|graph/i.test(exc.message)) {\n throw new HandlerError(400, String(exc));\n }\n throw exc;\n }\n}\n\nexport async function handleStats(\n engine: ContextEngineLike,\n sourceId: string | null | undefined,\n): Promise<unknown> {\n return engine.stats(sourceId ?? null);\n}\n","import { z } from \"zod\";\nimport { HandlerError, resolveRequestPrincipals } from \"../routing-core.js\";\nimport type { Trusted } from \"../sentinels.js\";\n\nexport type PrincipalsFn = () => unknown | Promise<unknown>;\n/** Zero-argument, sync or async, resolved fresh per execution — the same\n * contract as `PrincipalsFn`. Returns the opaque approval scope (a run id is\n * the expected shape) or `null` for the unscoped legacy path. */\nexport type ApprovalScopeFn = () => unknown | Promise<unknown>;\n\nexport const SCOPE_NOTE =\n \" Results are scoped to the caller's permissions (resolved by the server's \" +\n \"injected principals dependency — never a caller-supplied argument) and to \" +\n \"the given source_ids, if any.\";\n\nexport async function resolvePrincipalsFn(principals: PrincipalsFn): Promise<string[] | Trusted> {\n const result = await Promise.resolve(principals());\n // Validation DELEGATES to routing-core's resolveRequestPrincipals — the\n // single canonical remote-surface validator (TRUSTED passes through, null\n // and non-arrays are rejected) — rather than hand-copying its rules: a\n // rule added to the canonical validator must not silently miss the MCP\n // surface. Its HandlerError is an HTTP shape, so it is re-raised as a\n // plain Error with the same detail — the MCP host converts that to the\n // isError=true result this surface's contract promises.\n try {\n return resolveRequestPrincipals(result, { surface: \"the MCP `principals` dependency\" });\n } catch (exc) {\n if (exc instanceof HandlerError) throw new Error(exc.message, { cause: exc });\n throw exc;\n }\n}\n\nexport type McpToolHost = {\n tool(\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (...args: never[]) => Promise<unknown>,\n ): unknown;\n};\n\nexport function registerToolGateway(\n mcp: McpToolHost,\n engine: {\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n },\n principals: PrincipalsFn,\n /** Optional server-side resolver for the approval claim scope (see\n * governance `executeTool`). Like `principals`, NEVER a tool argument: a\n * model that could name its own scope could claim another run's\n * approvals. Validation is the library's, so a wrong type surfaces as the\n * same isError=true result any other host-side wiring bug does. */\n approvalScope: ApprovalScopeFn | null = null,\n): void {\n mcp.tool(\n \"search_tools\",\n \"Keyword search over the tools this deployment has registered \" +\n \"(http/db/mcp/function) — the ACL-visible name, kind, description, \" +\n \"and JSON Schema params of each match, so a caller can discover what \" +\n \"it can then invoke with `execute_tool`.\" +\n SCOPE_NOTE,\n // Zod raw shape — see the note on the search tool in mcp.ts.\n { query: z.string(), limit: z.number().int().optional() },\n async (...raw: never[]) => {\n const args = (raw[0] ?? {}) as { query?: string; limit?: number };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n const tools = await engine.searchTools(String(args.query ?? \"\"), {\n principals: callerPrincipals,\n limit: args.limit ?? 10,\n });\n return { tools };\n },\n );\n\n mcp.tool(\n \"execute_tool\",\n \"Governed execution of a tool previously discovered via \" +\n \"`search_tools` (ACL check, approval gate, audit). Returns \" +\n \"`{result, usage}` on success, or an `approval_required` payload \" +\n \"when the call needs a human approval that isn't already granted — \" +\n \"the caller must not retry until that approval resolves.\" +\n SCOPE_NOTE,\n { name: z.string(), args: z.record(z.unknown()).optional() },\n async (...raw: never[]) => {\n const body = (raw[0] ?? {}) as { name?: string; args?: Record<string, unknown> };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n const scope = approvalScope ? await Promise.resolve(approvalScope()) : null;\n return engine.executeTool(String(body.name), body.args ?? null, {\n principals: callerPrincipals,\n source: \"mcp\",\n approvalScope: scope,\n });\n },\n );\n}\n","/** Bumped by CI on every main merge; 0.0.0 = pre-first-release. */\nexport const __version__ = \"0.0.0\";\n","import { z } from \"zod\";\nimport { ExtraMissingError } from \"./errors.js\";\nimport { requireExtra } from \"./extras.js\";\nimport { requireValidUuid } from \"./routing-core.js\";\nimport {\n type ApprovalScopeFn,\n type PrincipalsFn,\n registerToolGateway,\n resolvePrincipalsFn,\n SCOPE_NOTE,\n} from \"./tools/mcp-tools.js\";\nimport { __version__ } from \"./version.js\";\n\ntype Engine = {\n config: { llm?: unknown; enableCodeExecution?: boolean };\n search: (query: string, opts?: Record<string, unknown>) => Promise<{ hits: unknown[]; usage?: unknown }>;\n getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;\n compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n};\n\nfunction asMcpResult(data: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(data) }] };\n}\n\nexport async function createMcpApp(\n engine: Engine,\n opts: { principals: PrincipalsFn; approvalScope?: ApprovalScopeFn | null },\n): Promise<\n ((req: import(\"node:http\").IncomingMessage, res: import(\"node:http\").ServerResponse) => Promise<void>) & {\n mcp: unknown;\n }\n> {\n if (!opts?.principals) {\n throw new TypeError(\"createMcpApp requires principals\");\n }\n\n let McpServer: new (info: {\n name: string;\n version: string;\n }) => {\n tool: (...args: unknown[]) => unknown;\n connect: (t: unknown) => Promise<void>;\n };\n let StreamableHTTPServerTransport: new (opts: {\n sessionIdGenerator?: undefined;\n }) => {\n handleRequest: (req: unknown, res: unknown, body?: unknown) => Promise<void>;\n };\n try {\n const serverMod = await requireExtra<{ McpServer: typeof McpServer }>(\n \"@modelcontextprotocol/sdk/server/mcp.js\",\n \"mcp\",\n \"MCP server\",\n );\n const httpMod = await requireExtra<{\n StreamableHTTPServerTransport: typeof StreamableHTTPServerTransport;\n }>(\"@modelcontextprotocol/sdk/server/streamableHttp.js\", \"mcp\", \"MCP server\");\n McpServer = serverMod.McpServer;\n StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;\n } catch (exc) {\n if (exc instanceof ExtraMissingError) throw exc;\n throw new ExtraMissingError(\"mcp\", \"@modelcontextprotocol/sdk\", \"MCP server\");\n }\n\n const mcp = new McpServer({ name: \"context-engine\", version: __version__ });\n\n const tool = (\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (args: Record<string, unknown>) => Promise<unknown>,\n ) => {\n mcp.tool(name, description, schema, async (args: Record<string, unknown>) =>\n asMcpResult(await handler(args)),\n );\n };\n\n tool(\n \"search_knowledge_base\",\n `Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,\n {\n // Zod RAW SHAPES, not JSON schema: the SDK's isZodRawShape test\n // rejects a plain schema object — on current SDK versions that made\n // registration THROW at startup, and on 1.12.0 the object was consumed\n // as annotations and every handler ran with NO arguments.\n query: z.string(),\n source_ids: z.array(z.string()).optional(),\n document_ids: z.array(z.string()).optional(),\n top_k: z.number().int().optional(),\n mode: z.enum([\"hybrid\", \"graph\"]).optional(),\n },\n async (args) => {\n // Early, mirroring the HTTP handler: a malformed id must surface as a\n // clean tool error, not a Postgres 22P02 from inside every leg.\n for (const did of (args.document_ids as string[] | undefined) ?? []) {\n requireValidUuid(did);\n }\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n const result = await engine.search(String(args.query ?? \"\"), {\n sourceIds: args.source_ids,\n documentIds: args.document_ids,\n principals: callerPrincipals,\n topK: args.top_k ?? 10,\n mode: args.mode ?? \"hybrid\",\n });\n return {\n hits: (result.hits ?? []).map((hit) => {\n const h = hit as Record<string, unknown>;\n return {\n document_name: h.document_name ?? h.documentName,\n chunk_text: h.chunk_text ?? h.chunkText,\n score: h.score,\n source_id: h.source_id ?? h.sourceId,\n };\n }),\n usage: result.usage,\n };\n },\n );\n\n tool(\n \"get_document\",\n `Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,\n { document_id: z.string() },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n return engine.getDocument(String(args.document_id), { principals: callerPrincipals });\n },\n );\n\n if (engine.config.llm != null) {\n tool(\n \"query_structured\",\n `Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,\n { question: z.string(), source_ids: z.array(z.string()).optional() },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.queryStructured) throw new Error(\"queryStructured is not available on this engine\");\n return engine.queryStructured(String(args.question), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n if (engine.config.enableCodeExecution) {\n tool(\n \"compute\",\n `Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,\n { instruction: z.string(), source_ids: z.array(z.string()).optional() },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.compute) throw new Error(\"compute is not available on this engine\");\n return engine.compute(String(args.instruction), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n }\n }\n\n registerToolGateway(\n {\n tool: (name, description, schema, handler) => {\n tool(name, description, schema, async (args) => handler(args as never));\n },\n },\n engine,\n opts.principals,\n opts.approvalScope ?? null,\n );\n\n const handler = (async (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => {\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });\n await mcp.connect(transport);\n await transport.handleRequest(req, res);\n }) as ((\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => Promise<void>) & { mcp: unknown };\n handler.mcp = mcp;\n return handler;\n}\n"]}
@@ -11,6 +11,7 @@ CREATE TABLE context_engine_tools (
11
11
  requires_approval BOOLEAN NOT NULL DEFAULT false,
12
12
  approval_policy JSONB NOT NULL DEFAULT '{}'::jsonb,
13
13
  enabled BOOLEAN NOT NULL DEFAULT true,
14
+ meta_data JSONB NOT NULL DEFAULT '{}'::jsonb,
14
15
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
15
16
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
16
17
  );
@@ -22,6 +23,7 @@ CREATE TABLE context_engine_tool_approvals (
22
23
  tool_args_frozen JSONB NOT NULL DEFAULT '{}'::jsonb,
23
24
  source_id TEXT,
24
25
  principals JSONB,
26
+ approval_scope TEXT,
25
27
  status TEXT NOT NULL DEFAULT 'pending',
26
28
  approver TEXT,
27
29
  approver_meta JSONB,
@@ -1,4 +1,25 @@
1
1
  -- 0004_acl_indexes
2
+ -- IF NOT EXISTS: this file doubles as the HEAL step runMigrate applies after
3
+ -- every chain walk — see the comment in db.ts.
2
4
 
3
- CREATE INDEX ix_context_engine_chunks_acl_gin ON context_engine_chunks USING gin (acl);
4
- CREATE INDEX ix_context_engine_documents_acl_gin ON context_engine_documents USING gin (acl);
5
+ CREATE INDEX IF NOT EXISTS ix_context_engine_chunks_acl_gin ON context_engine_chunks USING gin (acl);
6
+ CREATE INDEX IF NOT EXISTS ix_context_engine_documents_acl_gin ON context_engine_documents USING gin (acl);
7
+
8
+ -- tools.meta_data (2026-08-18) — engine-opaque user metadata, added after
9
+ -- the tools chain revision shipped. Riding the heal step (this file re-runs
10
+ -- after every chain walk) converges every existing database without
11
+ -- re-parenting the chain; fresh databases also get it from 0003's CREATE.
12
+ -- The Python port does the same in cli.py `_heal_schema`.
13
+ ALTER TABLE context_engine_tools ADD COLUMN IF NOT EXISTS meta_data JSONB NOT NULL DEFAULT '{}'::jsonb;
14
+
15
+ -- tool_approvals.approval_scope (2026-09-04) — the claim scope, separate from
16
+ -- the tool-lookup source_id. The partial UNIQUE index is what makes
17
+ -- findOrCreatePending race-safe: two identical calls in one scope can only
18
+ -- ever leave one pending row. md5(jsonb::text) is stable because jsonb text
19
+ -- output is canonical. The Python port does the same in cli.py _heal_schema.
20
+ ALTER TABLE context_engine_tool_approvals ADD COLUMN IF NOT EXISTS approval_scope TEXT;
21
+ CREATE INDEX IF NOT EXISTS ix_context_engine_tool_approvals_claim
22
+ ON context_engine_tool_approvals (tool_name, approval_scope, status);
23
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_context_engine_tool_approvals_pending_scope
24
+ ON context_engine_tool_approvals (tool_name, approval_scope, md5(tool_args_frozen::text))
25
+ WHERE status = 'pending' AND approval_scope IS NOT NULL;
@@ -16,6 +16,8 @@ interface DocumentReport {
16
16
  providerTokens: Record<string, number>;
17
17
  error: string | null;
18
18
  redactionFailed: string[];
19
+ unreadableReason?: string | null;
20
+ unreadablePages?: number;
19
21
  }
20
22
  interface IngestReport {
21
23
  documents: DocumentReport[];
@@ -34,13 +36,32 @@ declare function unitsForFile(mime: string, opts: {
34
36
  }): number;
35
37
  declare function graphUnits(chunkCount: number, primaryCommunityCount: number): number;
36
38
 
39
+ /**
40
+ * One ingest stage boundary. `documentId` is null until the row is claimed
41
+ * (extraction runs before that, so dedup can decide from the extracted
42
+ * text); `sourceId` + `externalId` are the caller's own identity and exist
43
+ * on every event. `detail` is per stage and always JSON-serialisable.
44
+ */
45
+ interface ProgressEvent {
46
+ sourceId: string | null;
47
+ externalId: string | null;
48
+ documentId: string | null;
49
+ name: string;
50
+ stage: "extract" | "redact" | "chunk" | "embed" | "structured" | "graph";
51
+ state: "started" | "done";
52
+ detail: Record<string, unknown>;
53
+ }
37
54
  interface Hooks {
38
55
  onUsage?: ((event: UsageEvent) => void) | null;
39
56
  onError?: ((exc: unknown, ctx: Record<string, unknown>) => void) | null;
40
57
  onToolCall?: ((event: Record<string, unknown>) => void) | null;
58
+ /** Ingest stage boundaries, for live progress UIs. Never raises outward. */
59
+ onProgress?: ((event: ProgressEvent) => void) | null;
41
60
  }
42
61
  declare function emitUsage(hooks: Hooks | null | undefined, event: UsageEvent): void;
43
62
  declare function emitError(hooks: Hooks | null | undefined, exc: unknown, ctx: Record<string, unknown>): void;
63
+ /** Report an ingest stage boundary to `hooks.onProgress`, if set. Never raises. */
64
+ declare function emitProgress(hooks: Hooks | null | undefined, event: ProgressEvent): void;
44
65
  declare function emitToolCall(hooks: Hooks | null | undefined, event: Record<string, unknown>): void;
45
66
 
46
67
  type Span = [number, number];
@@ -95,4 +116,4 @@ declare function applyRedaction(text: string, policy: RedactionPolicy, opts: {
95
116
  hooks?: Hooks | null;
96
117
  }): [string, RedactionNote];
97
118
 
98
- export { type DocumentReport as D, type Hooks as H, type IngestReport as I, RedactionPolicy as R, type UsageEvent as U, RedactionRule as a, type RedactionRuleInit as b, applyRedaction as c, emitToolCall as d, emitError as e, emitUsage as f, graphUnits as g, type DetectorFn as h, unitsForFile as u };
119
+ export { type DocumentReport as D, type Hooks as H, type IngestReport as I, type ProgressEvent as P, RedactionPolicy as R, type UsageEvent as U, RedactionRule as a, type RedactionRuleInit as b, applyRedaction as c, emitProgress as d, emitError as e, emitToolCall as f, emitUsage as g, graphUnits as h, type DetectorFn as i, unitsForFile as u };
@@ -16,6 +16,8 @@ interface DocumentReport {
16
16
  providerTokens: Record<string, number>;
17
17
  error: string | null;
18
18
  redactionFailed: string[];
19
+ unreadableReason?: string | null;
20
+ unreadablePages?: number;
19
21
  }
20
22
  interface IngestReport {
21
23
  documents: DocumentReport[];
@@ -34,13 +36,32 @@ declare function unitsForFile(mime: string, opts: {
34
36
  }): number;
35
37
  declare function graphUnits(chunkCount: number, primaryCommunityCount: number): number;
36
38
 
39
+ /**
40
+ * One ingest stage boundary. `documentId` is null until the row is claimed
41
+ * (extraction runs before that, so dedup can decide from the extracted
42
+ * text); `sourceId` + `externalId` are the caller's own identity and exist
43
+ * on every event. `detail` is per stage and always JSON-serialisable.
44
+ */
45
+ interface ProgressEvent {
46
+ sourceId: string | null;
47
+ externalId: string | null;
48
+ documentId: string | null;
49
+ name: string;
50
+ stage: "extract" | "redact" | "chunk" | "embed" | "structured" | "graph";
51
+ state: "started" | "done";
52
+ detail: Record<string, unknown>;
53
+ }
37
54
  interface Hooks {
38
55
  onUsage?: ((event: UsageEvent) => void) | null;
39
56
  onError?: ((exc: unknown, ctx: Record<string, unknown>) => void) | null;
40
57
  onToolCall?: ((event: Record<string, unknown>) => void) | null;
58
+ /** Ingest stage boundaries, for live progress UIs. Never raises outward. */
59
+ onProgress?: ((event: ProgressEvent) => void) | null;
41
60
  }
42
61
  declare function emitUsage(hooks: Hooks | null | undefined, event: UsageEvent): void;
43
62
  declare function emitError(hooks: Hooks | null | undefined, exc: unknown, ctx: Record<string, unknown>): void;
63
+ /** Report an ingest stage boundary to `hooks.onProgress`, if set. Never raises. */
64
+ declare function emitProgress(hooks: Hooks | null | undefined, event: ProgressEvent): void;
44
65
  declare function emitToolCall(hooks: Hooks | null | undefined, event: Record<string, unknown>): void;
45
66
 
46
67
  type Span = [number, number];
@@ -95,4 +116,4 @@ declare function applyRedaction(text: string, policy: RedactionPolicy, opts: {
95
116
  hooks?: Hooks | null;
96
117
  }): [string, RedactionNote];
97
118
 
98
- export { type DocumentReport as D, type Hooks as H, type IngestReport as I, RedactionPolicy as R, type UsageEvent as U, RedactionRule as a, type RedactionRuleInit as b, applyRedaction as c, emitToolCall as d, emitError as e, emitUsage as f, graphUnits as g, type DetectorFn as h, unitsForFile as u };
119
+ export { type DocumentReport as D, type Hooks as H, type IngestReport as I, type ProgressEvent as P, RedactionPolicy as R, type UsageEvent as U, RedactionRule as a, type RedactionRuleInit as b, applyRedaction as c, emitProgress as d, emitError as e, emitToolCall as f, emitUsage as g, graphUnits as h, type DetectorFn as i, unitsForFile as u };
@@ -1,4 +1,4 @@
1
- import { h as DetectorFn } from './redaction-BmDSWJ7h.cjs';
1
+ import { i as DetectorFn } from './redaction-BqD_DEUQ.cjs';
2
2
 
3
3
  /**
4
4
  * Microsoft Presidio has no JavaScript port. This adapter talks to a
@@ -1,4 +1,4 @@
1
- import { h as DetectorFn } from './redaction-BmDSWJ7h.js';
1
+ import { i as DetectorFn } from './redaction-BqD_DEUQ.js';
2
2
 
3
3
  /**
4
4
  * Microsoft Presidio has no JavaScript port. This adapter talks to a
@@ -1,4 +1,4 @@
1
- import { T as ToolEngine, a as ToolConfig } from './governance-XIScatRO.js';
1
+ import { T as ToolEngine, a as ToolConfig } from './governance-P9pRb4Ol.cjs';
2
2
 
3
3
  type ContextEngineLike = {
4
4
  ingest: (args: Record<string, unknown>) => Promise<unknown>;
@@ -30,6 +30,12 @@ type ToolsHandlerEngine = ToolEngine & {
30
30
  declare function createToolsHandlers(engine: ToolsHandlerEngine, opts?: {
31
31
  redirectBaseUrl?: string;
32
32
  pendingStore?: PendingStore | null;
33
+ /** Serve `config_redacted` (the masked request template) on the GET
34
+ * routes. Defaults OFF: those routes serve the same ACL-visible
35
+ * population that may EXECUTE a tool, and even the redacted template is
36
+ * editor-facing metadata an agent caller has no business reading. Enable
37
+ * only on a mount that genuinely fronts an editor/admin UI. */
38
+ configTemplate?: boolean;
33
39
  }): {
34
40
  createTool(body: unknown, principals: unknown): Promise<Record<string, unknown>>;
35
41
  listToolsAdmin(query: {
@@ -40,11 +46,20 @@ declare function createToolsHandlers(engine: ToolsHandlerEngine, opts?: {
40
46
  deleteToolRoute(toolId: string, principals: unknown): Promise<Record<string, unknown>>;
41
47
  testToolRoute(body: unknown): Promise<Record<string, unknown>>;
42
48
  toolSchemaRoute(kind: string): Record<string, unknown>;
49
+ /**
50
+ * `approvalScope` is resolved by the adapter's `approvalScope` option —
51
+ * SERVER-SIDE, never from the body. A body key of the same name is
52
+ * ignored exactly like a body `principals`: a client that could name
53
+ * its own scope could claim another scope's approvals. Absent, the
54
+ * execution runs unscoped (the deprecated legacy path). A malformed
55
+ * scope is the host's wiring bug, so it surfaces as a 500, never a 4xx
56
+ * the client might "fix" by changing its body.
57
+ */
43
58
  executeToolRoute(body: {
44
59
  call_name?: string;
45
60
  args?: Record<string, unknown> | null;
46
61
  source_id?: string | null;
47
- }, principals: unknown): Promise<Record<string, unknown>>;
62
+ }, principals: unknown, approvalScope?: unknown): Promise<Record<string, unknown>>;
48
63
  mcpConnectAndList(body: {
49
64
  server_name: string;
50
65
  url: string;
@@ -1,4 +1,4 @@
1
- import { T as ToolEngine, a as ToolConfig } from './governance-BDkcv4qZ.cjs';
1
+ import { T as ToolEngine, a as ToolConfig } from './governance-BLPK7NMe.js';
2
2
 
3
3
  type ContextEngineLike = {
4
4
  ingest: (args: Record<string, unknown>) => Promise<unknown>;
@@ -30,6 +30,12 @@ type ToolsHandlerEngine = ToolEngine & {
30
30
  declare function createToolsHandlers(engine: ToolsHandlerEngine, opts?: {
31
31
  redirectBaseUrl?: string;
32
32
  pendingStore?: PendingStore | null;
33
+ /** Serve `config_redacted` (the masked request template) on the GET
34
+ * routes. Defaults OFF: those routes serve the same ACL-visible
35
+ * population that may EXECUTE a tool, and even the redacted template is
36
+ * editor-facing metadata an agent caller has no business reading. Enable
37
+ * only on a mount that genuinely fronts an editor/admin UI. */
38
+ configTemplate?: boolean;
33
39
  }): {
34
40
  createTool(body: unknown, principals: unknown): Promise<Record<string, unknown>>;
35
41
  listToolsAdmin(query: {
@@ -40,11 +46,20 @@ declare function createToolsHandlers(engine: ToolsHandlerEngine, opts?: {
40
46
  deleteToolRoute(toolId: string, principals: unknown): Promise<Record<string, unknown>>;
41
47
  testToolRoute(body: unknown): Promise<Record<string, unknown>>;
42
48
  toolSchemaRoute(kind: string): Record<string, unknown>;
49
+ /**
50
+ * `approvalScope` is resolved by the adapter's `approvalScope` option —
51
+ * SERVER-SIDE, never from the body. A body key of the same name is
52
+ * ignored exactly like a body `principals`: a client that could name
53
+ * its own scope could claim another scope's approvals. Absent, the
54
+ * execution runs unscoped (the deprecated legacy path). A malformed
55
+ * scope is the host's wiring bug, so it surfaces as a 500, never a 4xx
56
+ * the client might "fix" by changing its body.
57
+ */
43
58
  executeToolRoute(body: {
44
59
  call_name?: string;
45
60
  args?: Record<string, unknown> | null;
46
61
  source_id?: string | null;
47
- }, principals: unknown): Promise<Record<string, unknown>>;
62
+ }, principals: unknown, approvalScope?: unknown): Promise<Record<string, unknown>>;
48
63
  mcpConnectAndList(body: {
49
64
  server_name: string;
50
65
  url: string;
@@ -70,7 +70,11 @@ await engine.search(q, { principals: user.groups }); // scoped
70
70
  silently loses recall — queries return fewer rows than match, or none, with
71
71
  no error. The library cannot compensate.
72
72
  - **`config.enableCodeExecution` is `false` on purpose.** `engine.compute()`
73
- executes generated code. Turn it on only deliberately.
73
+ and `computeOverFrames()` execute generated code. Turn it on only
74
+ deliberately. `computeOverFrames({ sheet: rows }, instruction, { config:
75
+ engine.config })` is the same guarded path for tables the host already holds
76
+ (no document to point at); redaction masks every string cell AND every column
77
+ header before the LLM sees a schema, and sweeps the result.
74
78
  - Filing a document under an ACL the caller does not hold returns **403**, on
75
79
  ingest and on PATCH alike.
76
80
 
@@ -0,0 +1,167 @@
1
+ import { b as EmbeddingConfig } from './config-BODDdXJ7.js';
2
+ import { PoolClient, Pool } from 'pg';
3
+
4
+ /**
5
+ * Pluggable embeddings provider.
6
+ *
7
+ * openai / azure_openai / custom → OpenAI SDK (OpenAI-compatible, including TEI/vLLM).
8
+ * gemini / vertex_ai → lazy `@google/genai` (optional extra "gemini"). One
9
+ * code path: same SDK and models, differing only in how the client
10
+ * authenticates (API key vs ADC against a GCP project) — see
11
+ * `providers/google.ts`.
12
+ * voyage / cohere → fetch against their public REST APIs.
13
+ *
14
+ * `kind` is accepted everywhere but only voyage/cohere act on it.
15
+ * 30s timeout, no retries. Injectable `client` / `fetch` for tests.
16
+ */
17
+
18
+ type EmbedKind = "document" | "query";
19
+ type FetchImpl = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
20
+ type EmbeddingsClient = {
21
+ embeddings: {
22
+ create(body: {
23
+ model: string;
24
+ input: string[];
25
+ }): Promise<{
26
+ data: Array<{
27
+ embedding: number[];
28
+ }>;
29
+ usage?: {
30
+ total_tokens?: number;
31
+ } | null;
32
+ }>;
33
+ };
34
+ close?: () => void | Promise<void>;
35
+ timeout?: number;
36
+ baseURL?: string;
37
+ };
38
+ type EmbedderOpts = {
39
+ client?: EmbeddingsClient | null;
40
+ fetch?: FetchImpl | null;
41
+ fetchImpl?: FetchImpl | null;
42
+ };
43
+ declare class Embedder {
44
+ cfg: EmbeddingConfig;
45
+ provider: EmbeddingConfig["provider"];
46
+ model: string;
47
+ dim: number | null;
48
+ client: EmbeddingsClient | null;
49
+ fetchImpl: FetchImpl | null;
50
+ private genaiClient;
51
+ constructor(cfg: EmbeddingConfig, opts?: EmbedderOpts);
52
+ aclose(): Promise<void>;
53
+ [Symbol.asyncDispose](): Promise<void>;
54
+ /**
55
+ * Embed `texts`, returning `[vectors, tokenCount]`.
56
+ * Auto-detects `this.dim` on first success; raises on mismatch.
57
+ */
58
+ embed(texts: string[], opts?: {
59
+ kind?: EmbedKind;
60
+ }): Promise<[number[][], number]>;
61
+ /** Provider dispatch. Overridable per-instance (tests stub this). */
62
+ rawEmbed(texts: string[], kind?: EmbedKind): Promise<[number[][], number]>;
63
+ private embedOpenAI;
64
+ private embedGemini;
65
+ private embedVoyage;
66
+ private embedCohere;
67
+ private requireFetch;
68
+ }
69
+ declare function buildEmbedder(cfg: EmbeddingConfig, opts?: EmbedderOpts): Embedder;
70
+
71
+ interface ChunkRow {
72
+ idx: number;
73
+ text: string;
74
+ lang?: string | null;
75
+ embedding?: number[] | null;
76
+ meta?: Record<string, unknown>;
77
+ }
78
+ interface SearchScope {
79
+ sourceIds?: string[] | null;
80
+ /** Narrows WITHIN a source and INTERSECTS with `sourceIds` rather than
81
+ * widening it: a consumer that binds an agent to three of a source's
82
+ * documents needs a filter `sourceIds` cannot express, since every one of
83
+ * those documents shares the same source. */
84
+ documentIds?: string[] | null;
85
+ principals?: string[] | null;
86
+ limit?: number;
87
+ }
88
+ /** The ANN scan tuning the vector leg and the graph leg's seed query share.
89
+ * Named separately from `StorageBackend`, which carries it as an OPTIONAL
90
+ * member: a backend with no approximate index has no such knobs. */
91
+ interface AnnTunable {
92
+ tuneAnnScan(client: PoolClient, limit: number, scoped: boolean): Promise<void>;
93
+ }
94
+ interface StorageBackend {
95
+ supportsFts: boolean;
96
+ supportsTrgm: boolean;
97
+ supportsAnn: boolean;
98
+ upsertChunks(documentId: string, sourceId: string | null, acl: string[] | null, chunks: readonly ChunkRow[]): Promise<number>;
99
+ deleteChunks(documentId: string): Promise<void>;
100
+ updateChunkEmbeddings(documentId: string, vectors: readonly number[][]): Promise<number>;
101
+ updateChunkAcl(documentId: string, acl: string[] | null): Promise<number>;
102
+ filterIds(chunkIds: readonly string[], scope: SearchScope): Promise<string[]>;
103
+ ftsSearch(query: string, scope: SearchScope): Promise<string[]>;
104
+ trgmSearch(query: string, scope: SearchScope): Promise<string[]>;
105
+ annSearch(vector: readonly number[], scope: SearchScope): Promise<string[]>;
106
+ /** Optional: only a backend with an approximate index has a scan to tune.
107
+ * The graph leg's seed query is the second caller — see `AnnTunable`. */
108
+ tuneAnnScan?: AnnTunable["tuneAnnScan"];
109
+ }
110
+ declare class PostgresBackend implements StorageBackend {
111
+ supportsFts: boolean;
112
+ supportsTrgm: boolean;
113
+ supportsAnn: boolean;
114
+ private readonly pool;
115
+ private readonly exactThresholdOverride;
116
+ /** Tri-state: null = not yet checked. */
117
+ private iterativeScan;
118
+ constructor(pool: Pool, exactThreshold?: number | null);
119
+ private get exactThreshold();
120
+ /**
121
+ * Bind values for SCOPE + the row limit.
122
+ * `principals` is passed through UNCHANGED: null (trusted) and [] (anonymous)
123
+ * mean different things.
124
+ */
125
+ private scopeParams;
126
+ upsertChunks(documentId: string, sourceId: string | null, acl: string[] | null, chunks: readonly ChunkRow[]): Promise<number>;
127
+ deleteChunks(documentId: string): Promise<void>;
128
+ updateChunkEmbeddings(documentId: string, vectors: readonly number[][]): Promise<number>;
129
+ updateChunkAcl(documentId: string, acl: string[] | null): Promise<number>;
130
+ filterIds(chunkIds: readonly string[], scope: SearchScope): Promise<string[]>;
131
+ ftsSearch(query: string, scope: SearchScope): Promise<string[]>;
132
+ trgmSearch(query: string, scope: SearchScope): Promise<string[]>;
133
+ /**
134
+ * Set pg_trgm's similarity threshold for this query via the `set_limit()` /
135
+ * `show_limit()` FUNCTIONS — never the GUC `pg_trgm.similarity_threshold`.
136
+ *
137
+ * The GUC is registered lazily, only once pg_trgm's shared library is loaded
138
+ * into the backend process. On a fresh pooled connection that has not yet
139
+ * run any pg_trgm operation, `SHOW pg_trgm.similarity_threshold` raises
140
+ * "unrecognized configuration parameter" — and because that error aborts the
141
+ * surrounding transaction, a fallback issued on the same connection then
142
+ * fails with "current transaction is aborted". Every connection a pool hands
143
+ * out is fresh, so this is the common case, not an edge case. Calling
144
+ * `set_limit()` loads the library and does not depend on the GUC. This
145
+ * mirrors the Python backend, which was hardened against exactly this.
146
+ *
147
+ * `set_limit()` is connection-scoped and survives COMMIT and the return to
148
+ * the pool, so the previous value is captured here and restored by the
149
+ * caller.
150
+ */
151
+ private applyTrgmThreshold;
152
+ private restoreTrgmLimit;
153
+ annSearch(vector: readonly number[], scope: SearchScope): Promise<string[]>;
154
+ private eligibleIsSmall;
155
+ /** Size the HNSW candidate budget, and make it iterative when filtered.
156
+ *
157
+ * Public because the graph leg's seed query (`graph/retrieval.ts`) is the
158
+ * same shape — an ANN walk with the scope predicate as a POST-filter — and
159
+ * must not carry a second copy of this. Call it inside a transaction on the
160
+ * client the query itself will run on: every setting here is `SET LOCAL`. */
161
+ tuneAnnScan(client: PoolClient, limit: number, scoped: boolean): Promise<void>;
162
+ private scanBudget;
163
+ private enableIterativeScan;
164
+ private supportsIterativeScan;
165
+ }
166
+
167
+ export { type AnnTunable as A, type ChunkRow as C, Embedder as E, type FetchImpl as F, PostgresBackend as P, type StorageBackend as S, type EmbedKind as a, type SearchScope as b, buildEmbedder as c };