@promptev/context-engine 0.0.0 → 0.0.1

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 (58) hide show
  1. package/README.md +93 -5
  2. package/dist/cli.js +1761 -501
  3. package/dist/cli.js.map +1 -1
  4. package/dist/{config-Bt9bUQqU.d.ts → config-CNnASw5X.d.cts} +42 -5
  5. package/dist/{config-Bl9U789m.d.cts → config-CdlSkKgV.d.ts} +42 -5
  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-BDkcv4qZ.d.cts → governance-D8g6Wyvb.d.cts} +8 -2
  19. package/dist/{governance-XIScatRO.d.ts → governance-XFVgtEdV.d.ts} +8 -2
  20. package/dist/graph/index.cjs +122 -43
  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 +122 -43
  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 +2186 -910
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +70 -107
  35. package/dist/index.d.ts +70 -107
  36. package/dist/index.js +2186 -908
  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-B_DTkQgU.d.ts} +17 -2
  51. package/dist/{router-OPgSoYAB.d.cts → router-Dsv3fv0R.d.cts} +17 -2
  52. package/dist/storage-DU1JRno5.d.cts +164 -0
  53. package/dist/storage-Dvt2ZxsV.d.ts +164 -0
  54. package/package.json +61 -23
  55. package/src/migrations/sql/0003_tools.sql +2 -0
  56. package/src/migrations/sql/0004_acl_indexes.sql +23 -2
  57. package/dist/embeddings-B-jZ42mk.d.cts +0 -67
  58. package/dist/embeddings-DaSdAZN3.d.ts +0 -67
@@ -1,6 +1,6 @@
1
1
  import { Pool } from 'pg';
2
- import { C as ContextEngineConfig } from './config-Bl9U789m.cjs';
3
- import { H as Hooks } from './redaction-BmDSWJ7h.cjs';
2
+ import { C as ContextEngineConfig } from './config-CNnASw5X.cjs';
3
+ import { H as Hooks } from './redaction-BqD_DEUQ.cjs';
4
4
 
5
5
  type ToolKind = "http" | "db" | "mcp" | "function";
6
6
  interface ToolConfigInit {
@@ -17,6 +17,8 @@ interface ToolConfigInit {
17
17
  approvalPolicy?: Record<string, unknown>;
18
18
  approval_policy?: Record<string, unknown>;
19
19
  enabled?: boolean;
20
+ metaData?: Record<string, unknown>;
21
+ meta_data?: Record<string, unknown>;
20
22
  }
21
23
  /**
22
24
  * Caller-facing shape for registering a tool. Kind-specific `config` is
@@ -33,6 +35,10 @@ declare class ToolConfig {
33
35
  requiresApproval: boolean;
34
36
  approvalPolicy: Record<string, unknown>;
35
37
  enabled: boolean;
38
+ /** Engine-opaque user metadata (documents have the same column). Stored
39
+ * and returned in CLEAR on the admin surface only — secrets go in
40
+ * `config`, which is encrypted. */
41
+ metaData: Record<string, unknown>;
36
42
  constructor(init: ToolConfigInit);
37
43
  static fromUnknown(body: unknown): ToolConfig;
38
44
  }
@@ -1,6 +1,6 @@
1
1
  import { Pool } from 'pg';
2
- import { C as ContextEngineConfig } from './config-Bt9bUQqU.js';
3
- import { H as Hooks } from './redaction-BmDSWJ7h.js';
2
+ import { C as ContextEngineConfig } from './config-CdlSkKgV.js';
3
+ import { H as Hooks } from './redaction-BqD_DEUQ.js';
4
4
 
5
5
  type ToolKind = "http" | "db" | "mcp" | "function";
6
6
  interface ToolConfigInit {
@@ -17,6 +17,8 @@ interface ToolConfigInit {
17
17
  approvalPolicy?: Record<string, unknown>;
18
18
  approval_policy?: Record<string, unknown>;
19
19
  enabled?: boolean;
20
+ metaData?: Record<string, unknown>;
21
+ meta_data?: Record<string, unknown>;
20
22
  }
21
23
  /**
22
24
  * Caller-facing shape for registering a tool. Kind-specific `config` is
@@ -33,6 +35,10 @@ declare class ToolConfig {
33
35
  requiresApproval: boolean;
34
36
  approvalPolicy: Record<string, unknown>;
35
37
  enabled: boolean;
38
+ /** Engine-opaque user metadata (documents have the same column). Stored
39
+ * and returned in CLEAR on the admin surface only — secrets go in
40
+ * `config`, which is encrypted. */
41
+ metaData: Record<string, unknown>;
36
42
  constructor(init: ToolConfigInit);
37
43
  static fromUnknown(body: unknown): ToolConfig;
38
44
  }
@@ -68,6 +68,8 @@ var init_hooks = __esm({
68
68
  // src/providers/llm.ts
69
69
  var llm_exports = {};
70
70
  __export(llm_exports, {
71
+ CALL_TIMEOUT_MS: () => CALL_TIMEOUT_MS,
72
+ GEMINI_CALL_TIMEOUT_MS: () => GEMINI_CALL_TIMEOUT_MS,
71
73
  LLMClient: () => LLMClient,
72
74
  TIMEOUT_MS: () => TIMEOUT_MS,
73
75
  buildLlmClient: () => buildLlmClient,
@@ -110,7 +112,7 @@ async function loadGeminiChatClient(apiKey) {
110
112
  if (!Ctor) {
111
113
  throw new ExtraMissingError("gemini", specifier, "gemini llm");
112
114
  }
113
- return new Ctor({ apiKey: apiKey ?? null });
115
+ return new Ctor({ apiKey: apiKey ?? null, httpOptions: { timeout: GEMINI_CALL_TIMEOUT_MS } });
114
116
  }
115
117
  async function loadBedrockSdk() {
116
118
  const specifier = "@aws-sdk/client-bedrock-runtime";
@@ -147,11 +149,13 @@ async function callLlm(cfg, opts) {
147
149
  await owned.aclose();
148
150
  }
149
151
  }
150
- var TIMEOUT_MS, ANTHROPIC_VERSION, ANTHROPIC_MAX_TOKENS, OPENAI_FAMILY, LLMClient;
152
+ var CALL_TIMEOUT_MS, TIMEOUT_MS, GEMINI_CALL_TIMEOUT_MS, ANTHROPIC_VERSION, ANTHROPIC_MAX_TOKENS, OPENAI_FAMILY, LLMClient;
151
153
  var init_llm = __esm({
152
154
  "src/providers/llm.ts"() {
153
155
  init_errors();
154
- TIMEOUT_MS = 3e4;
156
+ CALL_TIMEOUT_MS = 24e4;
157
+ TIMEOUT_MS = CALL_TIMEOUT_MS;
158
+ GEMINI_CALL_TIMEOUT_MS = CALL_TIMEOUT_MS;
155
159
  ANTHROPIC_VERSION = "2023-06-01";
156
160
  ANTHROPIC_MAX_TOKENS = 4096;
157
161
  OPENAI_FAMILY = /* @__PURE__ */ new Set(["openai", "azure_openai", "custom"]);
@@ -179,22 +183,30 @@ var init_llm = __esm({
179
183
  await this.aclose();
180
184
  }
181
185
  async call(opts) {
182
- const { system, user, jsonMode = false, images = null } = opts;
186
+ const {
187
+ system,
188
+ user,
189
+ jsonMode = false,
190
+ images = null,
191
+ maxTokens = null,
192
+ thinkingBudget = null,
193
+ temperature = null
194
+ } = opts;
183
195
  if (this.provider === "anthropic") {
184
- return this.callAnthropic(system, user, jsonMode, images);
196
+ return this.callAnthropic(system, user, jsonMode, images, maxTokens, thinkingBudget, temperature);
185
197
  }
186
198
  if (OPENAI_FAMILY.has(this.provider)) {
187
- return this.callOpenAI(system, user, jsonMode, images);
199
+ return this.callOpenAI(system, user, jsonMode, images, maxTokens, temperature);
188
200
  }
189
201
  if (this.provider === "gemini") {
190
- return this.callGemini(system, user, jsonMode, images);
202
+ return this.callGemini(system, user, jsonMode, images, maxTokens, thinkingBudget, temperature);
191
203
  }
192
204
  if (this.provider === "bedrock") {
193
- return this.callBedrock(system, user, jsonMode, images);
205
+ return this.callBedrock(system, user, jsonMode, images, maxTokens, thinkingBudget, temperature);
194
206
  }
195
207
  throw new Error(`unknown llm provider: ${JSON.stringify(this.provider)}`);
196
208
  }
197
- async callAnthropic(system, user, jsonMode, images) {
209
+ async callAnthropic(system, user, jsonMode, images, maxTokens, thinkingBudget = null, temperature = null) {
198
210
  if (!this.fetchImpl) {
199
211
  throw new Error("anthropic llm client has no fetch implementation");
200
212
  }
@@ -215,26 +227,27 @@ Respond with valid JSON only.`;
215
227
  });
216
228
  }
217
229
  content.push({ type: "text", text: user });
218
- const data = await postJson(
219
- this.fetchImpl,
220
- "https://api.anthropic.com/v1/messages",
221
- {
222
- model: this.model,
223
- max_tokens: ANTHROPIC_MAX_TOKENS,
224
- system,
225
- messages: [{ role: "user", content }]
226
- },
227
- {
228
- "x-api-key": this.cfg.apiKey ?? "",
229
- "anthropic-version": ANTHROPIC_VERSION,
230
- "content-type": "application/json"
231
- }
232
- );
230
+ const body = {
231
+ model: this.model,
232
+ max_tokens: maxTokens ?? ANTHROPIC_MAX_TOKENS,
233
+ system,
234
+ messages: [{ role: "user", content }]
235
+ };
236
+ if (thinkingBudget) {
237
+ body.thinking = { type: "enabled", budget_tokens: thinkingBudget };
238
+ } else if (temperature !== null) {
239
+ body.temperature = temperature;
240
+ }
241
+ const data = await postJson(this.fetchImpl, "https://api.anthropic.com/v1/messages", body, {
242
+ "x-api-key": this.cfg.apiKey ?? "",
243
+ "anthropic-version": ANTHROPIC_VERSION,
244
+ "content-type": "application/json"
245
+ });
233
246
  const text = data.content[0].text;
234
247
  const usage = data.usage ?? {};
235
248
  return [text, { input: usage.input_tokens ?? 0, output: usage.output_tokens ?? 0 }];
236
249
  }
237
- async callOpenAI(system, user, jsonMode, images) {
250
+ async callOpenAI(system, user, jsonMode, images, maxTokens, temperature = null) {
238
251
  if (!this.client) {
239
252
  throw new Error("openai-family llm client has no client");
240
253
  }
@@ -255,12 +268,18 @@ Respond with valid JSON only.`;
255
268
  if (jsonMode) {
256
269
  body.response_format = { type: "json_object" };
257
270
  }
271
+ if (maxTokens) {
272
+ body.max_completion_tokens = maxTokens;
273
+ }
274
+ if (temperature !== null) {
275
+ body.temperature = temperature;
276
+ }
258
277
  const resp = await this.client.chat.completions.create(body);
259
278
  const text = resp.choices[0]?.message?.content ?? "";
260
279
  const usage = resp.usage;
261
280
  return [text, { input: usage?.prompt_tokens ?? 0, output: usage?.completion_tokens ?? 0 }];
262
281
  }
263
- async callGemini(system, user, jsonMode, images) {
282
+ async callGemini(system, user, jsonMode, images, maxTokens, thinkingBudget = null, temperature = null) {
264
283
  if (!this.genaiClient) {
265
284
  this.genaiClient = await loadGeminiChatClient(this.cfg.apiKey);
266
285
  }
@@ -269,10 +288,30 @@ Respond with valid JSON only.`;
269
288
  parts.push({ inlineData: { mimeType: "image/png", data: toBase64(img) } });
270
289
  }
271
290
  parts.push({ text: user });
272
- const config = { systemInstruction: system };
291
+ const config = {
292
+ systemInstruction: system,
293
+ // ALWAYS off, and not as a preference. Automatic function calling means
294
+ // the SDK itself EXECUTES a callable it was handed as a tool and loops
295
+ // on the result — up to ten round trips — before returning anything.
296
+ // This package passes declarations only, so today nothing is executable;
297
+ // but that depends on every future caller continuing to do the same, and
298
+ // an application that gates tool execution behind human approval would
299
+ // have that gate bypassed silently, by a library, with the loop already
300
+ // run before it could object.
301
+ automaticFunctionCalling: { disable: true }
302
+ };
273
303
  if (jsonMode) {
274
304
  config.responseMimeType = "application/json";
275
305
  }
306
+ if (maxTokens) {
307
+ config.maxOutputTokens = maxTokens;
308
+ }
309
+ if (temperature !== null) {
310
+ config.temperature = temperature;
311
+ }
312
+ if (thinkingBudget !== null) {
313
+ config.thinkingConfig = { thinkingBudget };
314
+ }
276
315
  const resp = await this.genaiClient.models.generateContent({
277
316
  model: this.model,
278
317
  contents: parts,
@@ -284,7 +323,7 @@ Respond with valid JSON only.`;
284
323
  const outputTokens = usageMeta?.candidatesTokenCount ?? usageMeta?.candidates_token_count ?? 0;
285
324
  return [text, { input: inputTokens || 0, output: outputTokens || 0 }];
286
325
  }
287
- async callBedrock(system, user, jsonMode, images) {
326
+ async callBedrock(system, user, jsonMode, images, maxTokens, thinkingBudget = null, temperature = null) {
288
327
  const { BedrockRuntimeClient, ConverseCommand } = await loadBedrockSdk();
289
328
  if (jsonMode) {
290
329
  system = `${system}
@@ -308,7 +347,21 @@ Respond with valid JSON only.`;
308
347
  new ConverseCommand({
309
348
  modelId: this.model,
310
349
  system: [{ text: system }],
311
- messages: [{ role: "user", content }]
350
+ messages: [{ role: "user", content }],
351
+ ...maxTokens || temperature !== null ? {
352
+ inferenceConfig: {
353
+ ...maxTokens ? { maxTokens } : {},
354
+ ...temperature !== null ? { temperature } : {}
355
+ }
356
+ } : {},
357
+ // Anthropic-style passthrough — Converse forwards it to the model.
358
+ // Zero (the vision transcription contract) sends nothing: thinking
359
+ // is opt-in for the anthropic models bedrock hosts.
360
+ ...thinkingBudget ? {
361
+ additionalModelRequestFields: {
362
+ thinking: { type: "enabled", budget_tokens: thinkingBudget }
363
+ }
364
+ } : {}
312
365
  })
313
366
  );
314
367
  const text = result.output?.message?.content?.[0]?.text ?? "";
@@ -1150,7 +1203,8 @@ var retrieval_exports = {};
1150
1203
  __export(retrieval_exports, {
1151
1204
  buildGraphRanked: () => buildGraphRanked,
1152
1205
  corpusIsAclUniform: () => corpusIsAclUniform,
1153
- shouldUseCommunitySummaries: () => shouldUseCommunitySummaries
1206
+ shouldUseCommunitySummaries: () => shouldUseCommunitySummaries,
1207
+ vectorSeedIds: () => vectorSeedIds
1154
1208
  });
1155
1209
  function vecLiteral(vector) {
1156
1210
  return `[${vector.map((x) => Number(x)).join(",")}]`;
@@ -1176,8 +1230,8 @@ async function deriveQueryEntities(pool, chunkIds, opts) {
1176
1230
  JOIN context_engine_chunks c ON c.id = ce.chunk_id
1177
1231
  WHERE ce.chunk_id = ANY($1::uuid[]) ${SCOPE}
1178
1232
  GROUP BY e.normalized_name, e.name, e.type
1179
- ORDER BY freq DESC LIMIT $4`,
1180
- [chunkIds, opts.sourceIds, opts.principals, ENTITY_LIMIT]
1233
+ ORDER BY freq DESC LIMIT $5`,
1234
+ [chunkIds, opts.sourceIds, opts.documentIds ?? null, opts.principals, ENTITY_LIMIT]
1181
1235
  );
1182
1236
  return result.rows.map((r) => ({
1183
1237
  normalized_name: r.normalized_name,
@@ -1242,8 +1296,8 @@ async function computeCommunityScores(pool, chunkIds, vector, opts) {
1242
1296
  `SELECT ce.chunk_id::text, ce.entity_id::text
1243
1297
  FROM context_engine_chunk_entities ce
1244
1298
  JOIN context_engine_chunks c ON c.id = ce.chunk_id
1245
- WHERE ce.chunk_id = ANY($1::uuid[]) AND ce.entity_id = ANY($4::uuid[]) ${SCOPE}`,
1246
- [chunkIds, opts.sourceIds, opts.principals, Object.keys(entityScore)]
1299
+ WHERE ce.chunk_id = ANY($1::uuid[]) AND ce.entity_id = ANY($5::uuid[]) ${SCOPE}`,
1300
+ [chunkIds, opts.sourceIds, opts.documentIds ?? null, opts.principals, Object.keys(entityScore)]
1247
1301
  );
1248
1302
  const chunkScores = {};
1249
1303
  for (const row of result.rows) {
@@ -1252,13 +1306,29 @@ async function computeCommunityScores(pool, chunkIds, vector, opts) {
1252
1306
  return chunkScores;
1253
1307
  }
1254
1308
  async function vectorSeedIds(pool, vector, opts) {
1255
- const result = await pool.query(
1256
- `SELECT c.id::text FROM context_engine_chunks c
1257
- WHERE c.embedding IS NOT NULL ${SCOPE}
1258
- ORDER BY c.embedding <=> CAST($1 AS vector) LIMIT $4`,
1259
- [vecLiteral(vector), opts.sourceIds, opts.principals, SEED_LIMIT]
1260
- );
1261
- return result.rows.map((r) => String(r.id));
1309
+ const binds = [opts.sourceIds, opts.documentIds ?? null, opts.principals];
1310
+ const scoped = binds.some((v) => v !== null);
1311
+ const client = await pool.connect();
1312
+ try {
1313
+ await client.query("BEGIN");
1314
+ await opts.backend?.tuneAnnScan?.(client, SEED_LIMIT, scoped);
1315
+ const result = await client.query(
1316
+ `SELECT c.id::text FROM context_engine_chunks c
1317
+ WHERE c.embedding IS NOT NULL ${SCOPE}
1318
+ ORDER BY c.embedding <=> CAST($1 AS vector) LIMIT $5`,
1319
+ [vecLiteral(vector), ...binds, SEED_LIMIT]
1320
+ );
1321
+ await client.query("COMMIT");
1322
+ return result.rows.map((r) => String(r.id));
1323
+ } catch (err) {
1324
+ try {
1325
+ await client.query("ROLLBACK");
1326
+ } catch {
1327
+ }
1328
+ throw err;
1329
+ } finally {
1330
+ client.release();
1331
+ }
1262
1332
  }
1263
1333
  async function buildGraphRanked(query, opts) {
1264
1334
  try {
@@ -1267,11 +1337,18 @@ async function buildGraphRanked(query, opts) {
1267
1337
  const vector = vectors[0] ? [...vectors[0]] : null;
1268
1338
  if (!vector) return [];
1269
1339
  const sourceIds = opts.sourceIds ?? null;
1340
+ const documentIds = opts.documentIds ?? null;
1270
1341
  const principals = opts.principals ?? null;
1271
- const seeds = await vectorSeedIds(opts.pool, vector, { sourceIds, principals });
1342
+ const seeds = await vectorSeedIds(opts.pool, vector, {
1343
+ sourceIds,
1344
+ documentIds,
1345
+ principals,
1346
+ backend: opts.backend
1347
+ });
1272
1348
  if (!seeds.length) return [];
1273
1349
  const queryEntities = await deriveQueryEntities(opts.pool, seeds.slice(0, TOP_SEEDS_FOR_ENTITIES), {
1274
1350
  sourceIds,
1351
+ documentIds,
1275
1352
  principals
1276
1353
  });
1277
1354
  const entityNorms = queryEntities.map((e) => String(e.normalized_name));
@@ -1293,6 +1370,7 @@ async function buildGraphRanked(query, opts) {
1293
1370
  const relScores = await computeRelationshipScores(opts.pool, allIds, entityNorms);
1294
1371
  const commScores = await computeCommunityScores(opts.pool, allIds, vector, {
1295
1372
  sourceIds,
1373
+ documentIds,
1296
1374
  principals,
1297
1375
  useSummaries
1298
1376
  });
@@ -1344,7 +1422,8 @@ var init_retrieval = __esm({
1344
1422
  TOP_SEEDS_FOR_ENTITIES = 20;
1345
1423
  SCOPE = `
1346
1424
  AND ($2::text[] IS NULL OR c.source_id = ANY($2::text[]))
1347
- AND ($3::text[] IS NULL OR c.acl IS NULL OR c.acl && $3::text[])
1425
+ AND ($3::uuid[] IS NULL OR c.document_id = ANY($3::uuid[]))
1426
+ AND ($4::text[] IS NULL OR c.acl IS NULL OR c.acl && $4::text[])
1348
1427
  `;
1349
1428
  }
1350
1429
  });