@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/README.md CHANGED
@@ -9,9 +9,15 @@
9
9
  as a TypeScript library, on your own Postgres.</b>
10
10
  </p>
11
11
 
12
- > TypeScript client in this repo (Python lives at the root). Same Postgres
13
- > schema a corpus migrated or ingested by either client is searchable by
14
- > the other. Apache-2.0.
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/@promptev/context-engine"><img src="https://img.shields.io/npm/v/@promptev/context-engine?label=npm&color=CB3837" alt="npm"></a>
14
+ <a href="https://pypi.org/project/promptev-context-engine/"><img src="https://img.shields.io/pypi/v/promptev-context-engine?label=PyPI%20(python)&color=3775A9" alt="PyPI"></a>
15
+ <a href="https://github.com/promptev/context-engine/actions/workflows/js.yml"><img src="https://github.com/promptev/context-engine/actions/workflows/js.yml/badge.svg" alt="CI"></a>
16
+ <img src="https://img.shields.io/badge/node-22%2B-339933" alt="Node 22+">
17
+ <img src="https://img.shields.io/badge/types-included-3178C6" alt="TypeScript types included">
18
+ <a href="../LICENSE.md"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="Apache-2.0"></a>
19
+ </p>
20
+
15
21
 
16
22
  It is a **library, not a server**. BYO database, embedding provider, and LLM.
17
23
  `npm install`, point it at Postgres you already run, call `engine.search()`.
@@ -22,16 +28,52 @@ optional graph). PII redaction runs **before** a hosted reranker sees hits and
22
28
 
23
29
  📖 **Docs:** https://promptev.ai/documentation/context-engine/ · **[access control](../docs/access-control.md)**
24
30
 
31
+ ## Why you'd choose this
32
+
33
+ **1. Access control that survives the vector index.** Filtering an approximate
34
+ index with a `WHERE` clause is a *post-filter* — the index picks candidates
35
+ first, your ACL discards them second, and the query returns short. We measured
36
+ it on 200k public documents at production embedding width, and because real
37
+ permissions are topically clustered rather than random, the loss is about
38
+ twice what a conventional benchmark reports: **recall 0.473 against 0.980 at
39
+ identical visibility, a quarter of queries empty, no error raised.** Tuning
40
+ does not fully close it, so this library decides between an exact and an
41
+ approximate scan per query instead. [Method](../benchmarks/acl_recall/).
42
+
43
+ **2. Redaction that runs in the right place.** Not more detectors — better
44
+ *placement*. Hits are masked **before** a hosted reranker sees them and
45
+ **before** the audit row is written, so the masked value is the only one that
46
+ leaves the process.
47
+
48
+ **3. It's a library, so the data never moves.** No server, no corpus handed
49
+ over. It only ever calls the Postgres, embedding endpoint, and LLM you
50
+ configure.
51
+
52
+ **4. Governed tool execution in the same place as retrieval.** ACL-scoped
53
+ tools, encrypted credentials, a fail-closed approval gate, and an audit row
54
+ per call — see [Tools](#tools) below.
55
+
56
+ **Prove it on your own data** — one read-only command, offline, no embedding
57
+ provider called:
58
+
59
+ ```bash
60
+ npx context-engine check-acl-exposure --database-url postgresql://...
61
+ ```
62
+
63
+ It reports, for the ACL values that actually occur in your corpus, what a bare
64
+ scoped query returns versus what this library returns — both scored against an
65
+ exact oracle computed inside Postgres.
66
+
25
67
  ## Install
26
68
 
27
69
  ```bash
28
70
  npm install @promptev/context-engine pg
29
71
  ```
30
72
 
31
- Needs **Node.js 20+** and **Postgres** with `vector`, `pg_trgm`, and `unaccent`
73
+ Needs **Node.js 22+** and **Postgres** with `vector`, `pg_trgm`, and `unaccent`
32
74
  (created by `context-engine migrate` if the role has `CREATE EXTENSION`).
33
75
 
34
- `pg` is a peer dependency (LGPL) so a bare install pulls no copyleft.
76
+ `pg` is a peer dependency, and it — like everything else here — is MIT/BSD/Apache, so a bare install pulls **no copyleft at all**.
35
77
 
36
78
  Optional peers — install only what you use:
37
79
 
@@ -65,6 +107,13 @@ const engine = new ContextEngine(config);
65
107
 
66
108
  Or from `CE_`-prefixed env vars (`CE_EMBEDDING__PROVIDER`, nested with `__`).
67
109
 
110
+ `storage` holds the deployment knobs: `annExactThreshold` (the vector leg's
111
+ exact/approximate crossover) and the `pg.Pool` settings — `poolMax` (10),
112
+ `poolIdleTimeoutMs` (10000) and `poolConnectionTimeoutMs` (30000). Reachable
113
+ as env vars too, e.g. `CE_STORAGE__POOL_MAX`. (`pg` has no pre-ping, so unlike
114
+ the Python client there is nothing to turn on: a connection the database has
115
+ dropped fails once and is replaced.)
116
+
68
117
  ## Provision
69
118
 
70
119
  ```bash
@@ -85,6 +134,7 @@ await engine.ingest({
85
134
 
86
135
  const result = await engine.search("how much annual leave do I get", {
87
136
  sourceIds: ["hr-handbook"],
137
+ documentIds: null, // optionally pin to specific documents WITHIN the sources
88
138
  principals: ["group:hr"], // TRUSTED = skip ACL; [] = anonymous
89
139
  topK: 10,
90
140
  });
@@ -97,6 +147,29 @@ trusted caller and returns the entire corpus. Use `[]` or `TRUSTED` explicitly.
97
147
  npx context-engine install-skill
98
148
  ```
99
149
 
150
+ ## Compute over tables
151
+
152
+ `engine.compute()` turns the in-scope CSV/XLSX documents into row tables and has
153
+ the LLM write code against them. `computeOverFrames()` is the same path for
154
+ tables you already hold — an uploaded workbook, a connector's sheet, a query
155
+ result — with no document to point at:
156
+
157
+ ```ts
158
+ import { computeOverFrames } from "@promptev/context-engine";
159
+
160
+ const out = await computeOverFrames(
161
+ { expenses: rows }, // { sheetName: Array<Record<string, unknown>> }
162
+ "total the amount column",
163
+ { config: engine.config },
164
+ );
165
+ out.result;
166
+ ```
167
+
168
+ Both are **off by default** (`enableCodeExecution: true` turns them on — only
169
+ behind real OS-level isolation) and both apply `config.redaction` before the LLM
170
+ sees anything: every string cell *and* every column header is masked, and the
171
+ returned object — generated code included — is swept on the way out.
172
+
100
173
  ## Serve
101
174
 
102
175
  ```ts
@@ -107,6 +180,44 @@ const router = createHonoRouter(engine, { auth: myAuth, principals: myPrincipals
107
180
 
108
181
  `auth` and `principals` are required. Identical routes exist for Express and Fastify.
109
182
 
183
+ ## Tools
184
+
185
+ Register a governed tool — HTTP, SQL, MCP, or a plain function — and every call
186
+ is ACL-scoped, credential-encrypted, optionally approval-gated, and audited.
187
+
188
+ ```ts
189
+ import { ToolConfig, resolveApproval } from "@promptev/context-engine";
190
+
191
+ await engine.registerTool(new ToolConfig({
192
+ name: "get_weather",
193
+ kind: "http",
194
+ description: "Fetch the current weather for a city",
195
+ config: { method: "GET", url: "https://api.example.com/weather" },
196
+ acl: ["group:ops"],
197
+ requiresApproval: true, // pauses for a human before it runs
198
+ }));
199
+
200
+ const out = await engine.executeTool("http_get_weather", { city: "Lahore" }, {
201
+ principals: ["group:ops"],
202
+ approvalScope: "run-42", // opaque, chosen by you — a run id is the usual shape
203
+ });
204
+ // -> { approval_required: { approval_id: "...", expires_at: "...", ... } } (not executed yet)
205
+
206
+ await resolveApproval(engine, approvalId, "approved", "boss");
207
+ // the same call, same approvalScope, runs for real — exactly once
208
+ ```
209
+
210
+ `approvalScope` is the claim scope: an approved record is consumed only by the
211
+ same call in the same scope (and, when the record carries principals, by a
212
+ caller who overlaps them). Within a scope, identical pending requests share one
213
+ record. Resolve it server-side — on the adapters and the MCP gateway it is an
214
+ `approvalScope` resolver beside `principals`, never a request field. Omitting it
215
+ still works this release, unscoped and with a `DeprecationWarning`; the next
216
+ release refuses a gated call with no scope.
217
+
218
+ A caller may only register or relabel a tool under principals it holds — filing
219
+ one under another group's ACL is a 403.
220
+
110
221
  ## License
111
222
 
112
223
  Apache-2.0. See `LICENSE.md` and `NOTICE`.