@promptev/context-engine 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,26 +5,13 @@ import { H as Hooks, R as RedactionPolicy, U as UsageEvent, P as ProgressEvent,
5
5
  export { D as DocumentReport, a as RedactionRule, b as RedactionRuleInit, c as applyRedaction, e as emitError, d as emitProgress, f as emitToolCall, g as emitUsage, h as graphUnits, u as unitsForFile } from './redaction-BqD_DEUQ.js';
6
6
  import { E as Embedder, S as StorageBackend, F as FetchImpl } from './storage-CJrKgJeJ.js';
7
7
  export { C as ChunkRow, a as EmbedKind, P as PostgresBackend, b as SearchScope, c as buildEmbedder } from './storage-CJrKgJeJ.js';
8
+ import { P as Principals, U as Unset, S as ScopeInput, K as KnowledgeComputeFn, T as Trusted } from './mcp-uirRbluA.js';
9
+ export { a as KNOWLEDGE_ACTIONS, b as KNOWLEDGE_TOOL_DESCRIPTION, c as KnowledgeAction, d as Scope, e as TRUSTED, f as UNSCOPED, g as UNSET, h as callKnowledgeTool, i as createMcpApp, k as knowledgeToolDefinition, n as narrowToCeiling, r as resolvePrincipals, j as resolveScope } from './mcp-uirRbluA.js';
8
10
  import { T as ToolEngine, C as CanonicalTool, b as ToolHttpClient, a as ToolConfig } from './governance-BLPK7NMe.js';
9
11
  export { c as ToolKind, d as configSchema } from './governance-BLPK7NMe.js';
10
- export { createMcpApp } from './mcp.js';
11
12
  import 'zod';
12
13
  import 'node:http';
13
14
 
14
- /**
15
- * Sentinels distinguishing omitted arguments from real values, including null.
16
- *
17
- * UNSET: "argument omitted" vs null (e.g. updateDocument acl=null means unrestricted).
18
- * TRUSTED: trusted caller, ACL filtering disabled. Truthy on purpose so
19
- * `if (principals)` does not treat a trusted caller as anonymous.
20
- */
21
- declare const UNSET: unique symbol;
22
- type Unset = typeof UNSET;
23
- declare const TRUSTED: unique symbol;
24
- type Trusted = typeof TRUSTED;
25
- type Principals = string[] | null | typeof TRUSTED | undefined;
26
- declare function resolvePrincipals(value: Principals, method: string): string[] | null;
27
-
28
15
  type Mode$1 = "hybrid" | "graph";
29
16
  interface IngestRequest {
30
17
  content?: Buffer | null;
@@ -79,17 +66,18 @@ declare function getDocumentText(documentId: string, opts: {
79
66
  secretKey?: string | Buffer | null;
80
67
  hooks?: Hooks;
81
68
  }): Promise<string>;
82
- /**
83
- * Page through documents in scope, newest first.
84
- *
85
- * `redaction` masks `documentType` — unconstrained free text an LLM wrote
86
- * after reading the document body. `name`/`description` remain
87
- * intentionally unmasked: both are CALLER-set at ingest time, not text the
88
- * pipeline derived from the document body.
89
- */
90
69
  declare function listDocuments(opts: {
91
70
  pool: Pool;
92
71
  sourceId?: string | null;
72
+ /** OR-of-many, ONE keyset-paged query across all of them; with `sourceId`, their union. */
73
+ sourceIds?: string[] | null;
74
+ /**
75
+ * Narrows to specific documents IN SQL, not after the page is built: three
76
+ * named documents that happen to sit on page four would otherwise come back
77
+ * as an empty page rather than as themselves. An empty array means nothing
78
+ * is in scope and stays empty.
79
+ */
80
+ documentIds?: string[] | null;
93
81
  principals?: string[] | null;
94
82
  cursor?: unknown;
95
83
  limit?: number;
@@ -97,6 +85,167 @@ declare function listDocuments(opts: {
97
85
  secretKey?: string | Buffer | null;
98
86
  hooks?: Hooks;
99
87
  }): Promise<Record<string, unknown>>;
88
+ type SpreadsheetDescription = {
89
+ document_id: string;
90
+ name: unknown;
91
+ source_id: unknown;
92
+ sheets: SheetSchema[] | null;
93
+ schema_unavailable?: string;
94
+ };
95
+ /**
96
+ * Sheet names, column headers and row counts for the named spreadsheets.
97
+ *
98
+ * `documentIds` comes from a listing the caller has already been shown, but
99
+ * the ACL and the source scope are applied AGAIN here: "we already filtered
100
+ * the list" is exactly how a batch read ends up reading one row it should
101
+ * not have. A document that is not visible, is not in scope, or is not
102
+ * tabular simply does not appear in the result.
103
+ *
104
+ * Reading document bodies is the cost, so it is bounded twice: the caller
105
+ * passes only the page it is describing, and `budget` caps the total
106
+ * characters of stored text this will pull. Documents past the budget are
107
+ * still LISTED, with `sheets: null` and a reason — a silently shortened
108
+ * schema would read as "that workbook has no sheets".
109
+ *
110
+ * `redaction` masks sheet names and column headers, which are derived from
111
+ * the document body exactly like `search`'s chunk text. The document `name`
112
+ * is not masked, matching `listDocuments`: it is caller-set at ingest.
113
+ */
114
+ declare function spreadsheetSchema(opts: {
115
+ pool: Pool;
116
+ documentIds: string[];
117
+ sourceIds?: string[] | null;
118
+ principals?: string[] | null;
119
+ budget?: number;
120
+ redaction?: RedactionPolicy | null;
121
+ secretKey?: string | Buffer | null;
122
+ hooks?: Hooks;
123
+ }): Promise<SpreadsheetDescription[]>;
124
+ type DocumentStructure = Record<string, unknown>;
125
+ /**
126
+ * What is INSIDE each of the named documents, whatever its type.
127
+ *
128
+ * Returns `{documentId: structure}`. The shape of `structure` follows the
129
+ * document, because the thing a model needs to know differs by type:
130
+ *
131
+ * | document | structure |
132
+ * |---|---|
133
+ * | CSV / XLSX / TSV | `sheets: [{name, columns, row_count}]` |
134
+ * | markdown, Word, HTML, a transcribed PDF | `sections: [...]`, `last_page` |
135
+ * | JSON | `keys: [...]` |
136
+ * | anything else | just `chunks` |
137
+ *
138
+ * `chunks` is on every one of them, and is the floor: a plain `.txt` has no
139
+ * headings to report, but a model still has to know whether `get_chunks` is
140
+ * worth calling. A document that is present but described by nothing at all
141
+ * reads as an empty document, which is why there is no "no structure" case.
142
+ *
143
+ * Everything but the spreadsheet columns comes from `meta_data` on the chunk
144
+ * rows, which the chunkers already wrote at ingest (`section_title`, `page`,
145
+ * `top_level_key`) — one grouped query over small rows, no document body read
146
+ * and no LLM. Columns are the exception: the header row is not in chunk
147
+ * metadata, so the tabular half still parses stored text, under the same
148
+ * budget (see `spreadsheetSchema`).
149
+ */
150
+ declare function documentStructure(opts: {
151
+ pool: Pool;
152
+ documentIds: string[];
153
+ sourceIds?: string[] | null;
154
+ principals?: string[] | null;
155
+ budget?: number;
156
+ /**
157
+ * Cap every list at `MAX_STRUCTURE_ITEMS` and report the remainder as a
158
+ * count. One rule decides it, and the caller above applies it: **the cap is
159
+ * for the call that did NOT name its documents.** A `discover` describing a
160
+ * whole page has a context budget to keep; a caller that asked about one
161
+ * document asked for all of it, exactly like `spreadsheetSchema`.
162
+ */
163
+ bounded?: boolean;
164
+ redaction?: RedactionPolicy | null;
165
+ secretKey?: string | Buffer | null;
166
+ hooks?: Hooks;
167
+ }): Promise<Record<string, DocumentStructure>>;
168
+ type DocumentTypeCount = {
169
+ kind: "spreadsheet" | "text";
170
+ type: string | null;
171
+ documents: number;
172
+ with_fields: number;
173
+ };
174
+ /**
175
+ * The corpus census: `[{kind, type, documents, with_fields}]`.
176
+ *
177
+ * Keyed by TWO things, because only one of them is always known:
178
+ *
179
+ * - `kind` is derived from the mime (`isTabularMime`, the same predicate
180
+ * `compute` selects on), so it is known for every document ever ingested.
181
+ * - `type` is the document's `document_type`, which is unconstrained free
182
+ * text an LLM wrote during structured extraction — and extraction is
183
+ * opt-in (`extractStructured`, off by default). On a deployment that never
184
+ * enabled it, `type` is null on every row. A census keyed on `type` alone
185
+ * would therefore be a single null bucket, which tells a model nothing
186
+ * about a corpus it is about to query.
187
+ *
188
+ * `with_fields` counts documents whose `structured_data` is a non-empty
189
+ * object. Extraction that ran and legitimately found nothing stores `{}`, and
190
+ * counting that as coverage would point a model at `query_meta` for a type
191
+ * that has nothing to filter on.
192
+ */
193
+ declare function documentTypes(opts: {
194
+ pool: Pool;
195
+ sourceIds?: string[] | null;
196
+ principals?: string[] | null;
197
+ documentIds?: string[] | null;
198
+ limit?: number;
199
+ redaction?: RedactionPolicy | null;
200
+ secretKey?: string | Buffer | null;
201
+ hooks?: Hooks;
202
+ }): Promise<DocumentTypeCount[]>;
203
+ type FieldDescription = {
204
+ field: string;
205
+ type: string;
206
+ documents: number;
207
+ };
208
+ type FieldGroup = {
209
+ kind: "spreadsheet" | "text";
210
+ type: string | null;
211
+ fields: FieldDescription[];
212
+ more_fields?: string[];
213
+ };
214
+ /**
215
+ * Extracted structured field names grouped by document kind AND type.
216
+ *
217
+ * Returns `[{kind, type, fields: [{field, type, documents}], more_fields}]` —
218
+ * one row per group, keyed by the SAME pair `documentTypes` is keyed by. That
219
+ * pairing is the point: `document_type` is a label an LLM wrote, so two
220
+ * different kinds can share one ("invoice" for both a PDF and a CSV of
221
+ * invoice rows). Keyed on the label alone, their fields merge into one group
222
+ * and a model reads a spreadsheet's columns as a PDF's extracted fields.
223
+ *
224
+ * `more_fields` holds the NAMES the per-group detail cap left out, not a
225
+ * count: nothing is dropped silently, and a name is all a caller needs to
226
+ * reach a field through `query_meta`. It is absent when nothing was left out.
227
+ *
228
+ * Counted over the documents the CALLER can see, not over the learned field
229
+ * registry (`context_engine_structured_keys`), which carries no ACL: a
230
+ * registry-wide answer would tell an anonymous caller the field names of
231
+ * every restricted document in the corpus. Counting from `structured_data`
232
+ * also makes `documents` mean what it says — how many in-scope documents
233
+ * actually carry the field.
234
+ *
235
+ * The type is `inferDataType`, the same function that labelled the registry,
236
+ * so the vocabulary a model reads here is the one the rest of the engine
237
+ * uses.
238
+ */
239
+ declare function fieldSummary(opts: {
240
+ pool: Pool;
241
+ sourceIds?: string[] | null;
242
+ principals?: string[] | null;
243
+ documentIds?: string[] | null;
244
+ maxFieldsPerType?: number;
245
+ redaction?: RedactionPolicy | null;
246
+ secretKey?: string | Buffer | null;
247
+ hooks?: Hooks;
248
+ }): Promise<FieldGroup[]>;
100
249
  /**
101
250
  * Answer a natural-language question against documents' `structuredData`.
102
251
  *
@@ -121,6 +270,24 @@ declare function queryStructured(question: string, opts: {
121
270
  secretKey?: string | Buffer | null;
122
271
  hooks?: Hooks;
123
272
  }): Promise<Record<string, unknown>>;
273
+ type SheetSchema = {
274
+ name: string;
275
+ columns: string[];
276
+ row_count: number;
277
+ };
278
+ /**
279
+ * The schema of one stored spreadsheet: `[{name, columns, row_count}]`.
280
+ *
281
+ * Header row and row count per SHEET, not unioned across the workbook — two
282
+ * sheets that both have an `amount` column are two different frames to
283
+ * `compute`, and a union would hide which one has the column a question
284
+ * needs. `row_count` counts DATA rows (the header is not one of them).
285
+ *
286
+ * Needs no danfo: `discover` must stay callable on an install that never
287
+ * enabled code execution, which is exactly the install where a model most
288
+ * needs the columns before it writes a query.
289
+ */
290
+ declare function spreadsheetSchemaFromText(text: string | null | undefined): SheetSchema[];
124
291
  /**
125
292
  * Compute an answer to `instruction` over in-scope spreadsheet documents.
126
293
  *
@@ -315,7 +482,9 @@ interface RunSearchOpts {
315
482
  topK?: number;
316
483
  mode?: Mode;
317
484
  compressToTokens?: number | null;
318
- graphRanked?: string[] | null;
485
+ /** A list, or a promise of one: passing a promise lets the graph leg run
486
+ * BESIDE the hybrid legs instead of ahead of them. */
487
+ graphRanked?: string[] | Promise<string[] | null> | null;
319
488
  redaction?: RedactionPolicy | null;
320
489
  }
321
490
  /**
@@ -466,7 +635,13 @@ declare class ContextEngine implements ToolEngine {
466
635
  documentIds?: string[] | null;
467
636
  principals?: Principals;
468
637
  topK?: number;
469
- mode?: "hybrid" | "graph";
638
+ /**
639
+ * Omit it (or pass null) and the mode is worked out from the documents
640
+ * in scope: the graph leg runs when this deployment has a graph AND
641
+ * something in scope was ingested with `mode: "graph"`. Naming one
642
+ * forces it. The graph leg ADDS to the hybrid legs, never replaces them.
643
+ */
644
+ mode?: "hybrid" | "graph" | null;
470
645
  compressToTokens?: number | null;
471
646
  redaction?: RedactionPolicy | null;
472
647
  }): Promise<SearchResult>;
@@ -476,8 +651,25 @@ declare class ContextEngine implements ToolEngine {
476
651
  * caller can never distinguish "doesn't exist" from "exists but you
477
652
  * can't see it").
478
653
  */
654
+ /**
655
+ * How long a failed graph probe is remembered. One refused connection must
656
+ * not become one refused connection per request, and must not be permanent
657
+ * either — the database may come back.
658
+ */
659
+ private static readonly GRAPH_PROBE_BACKOFF_MS;
660
+ private graphUnreachableUntil;
661
+ /**
662
+ * Is the graph database actually up?
663
+ *
664
+ * `graph.enabled` says the deployment is CONFIGURED, not that Neo4j is
665
+ * answering. Choosing the graph leg when it is unreachable buys a connection
666
+ * timeout on every search and no extra results, so a mode-less search checks
667
+ * first and remembers a failure briefly.
668
+ */
669
+ private graphIsReachable;
479
670
  getDocument(documentId: string, opts?: {
480
671
  principals?: Principals;
672
+ redaction?: RedactionPolicy | null;
481
673
  }): Promise<Record<string, unknown>>;
482
674
  deleteDocument(documentId: string, opts?: {
483
675
  principals?: Principals;
@@ -502,17 +694,133 @@ declare class ContextEngine implements ToolEngine {
502
694
  getDocumentText(documentId: string, opts?: {
503
695
  principals?: Principals;
504
696
  }): Promise<string>;
697
+ /**
698
+ * The ONE knowledge tool, as a library call. See `knowledge-tool.ts`.
699
+ *
700
+ * The same function the MCP server serves — an application driving its own
701
+ * agent loop hands its model this one door to the corpus without speaking
702
+ * MCP at all, and cannot get a different answer, because there is one
703
+ * implementation behind both surfaces.
704
+ */
705
+ searchKnowledgeBase(args: {
706
+ action: string;
707
+ principals?: Principals;
708
+ scope: ScopeInput;
709
+ query?: string | null;
710
+ document_id?: string | null;
711
+ source_ids?: string[] | null;
712
+ document_ids?: string[] | null;
713
+ entity?: string | null;
714
+ depth?: number | null;
715
+ category?: string | null;
716
+ label?: string | null;
717
+ entity_type?: string | null;
718
+ top_k?: number | null;
719
+ mode?: string | null;
720
+ limit?: number | null;
721
+ cursor?: unknown;
722
+ redaction?: RedactionPolicy | null;
723
+ compute?: KnowledgeComputeFn | null;
724
+ map_reduce?: ((instruction: string, opts: Record<string, unknown>) => Promise<Record<string, unknown>>) | null;
725
+ start?: number | null;
726
+ end?: number | null;
727
+ max_chars?: number | null;
728
+ }): Promise<Record<string, unknown>>;
729
+ /** Read one document in order, a range of chunks at a time. */
730
+ getChunks(documentId: string, opts?: {
731
+ principals?: Principals;
732
+ start?: number | null;
733
+ end?: number | null;
734
+ redaction?: RedactionPolicy | null;
735
+ }): Promise<Record<string, unknown>>;
736
+ /**
737
+ * Several whole documents at once, each ACL-checked. An id that is absent OR
738
+ * not visible is simply missing from the result, never an error — the same
739
+ * non-disclosure `getDocument` gives, which a batch read is the classic
740
+ * place to lose.
741
+ */
742
+ getDocuments(documentIds: string[], opts?: {
743
+ principals?: Principals;
744
+ redaction?: RedactionPolicy | null;
745
+ }): Promise<Array<Record<string, unknown>>>;
746
+ /** Ask the same question of every document in scope. */
747
+ mapReduce(instruction: string, opts?: {
748
+ principals?: Principals;
749
+ sourceIds?: string[] | null;
750
+ documentIds?: string[] | null;
751
+ limit?: number | null;
752
+ maxConcurrency?: number | null;
753
+ redaction?: RedactionPolicy | null;
754
+ }): Promise<Record<string, unknown>>;
505
755
  listDocuments(opts?: {
506
756
  sourceId?: string | null;
757
+ sourceIds?: string[] | null;
758
+ documentIds?: string[] | null;
507
759
  principals?: Principals;
508
760
  cursor?: unknown;
509
761
  limit?: number;
762
+ redaction?: RedactionPolicy | null;
510
763
  }): Promise<Record<string, unknown>>;
764
+ /**
765
+ * Sheet names, columns and row counts for the named spreadsheets.
766
+ *
767
+ * See `actions.spreadsheetSchema`. This is the half of `discover` that lets
768
+ * a model write ONE `compute` call: sheet names here are the keys it will
769
+ * index `dfs` by, and columns are the names it will use inside the code it
770
+ * writes.
771
+ */
772
+ spreadsheetSchema(opts: {
773
+ documentIds: string[];
774
+ sourceIds?: string[] | null;
775
+ principals?: Principals;
776
+ redaction?: RedactionPolicy | null;
777
+ }): Promise<SpreadsheetDescription[]>;
778
+ /**
779
+ * What is inside each of the named documents, whatever its type.
780
+ *
781
+ * See `actions.documentStructure`. Sheets and columns for a workbook,
782
+ * sections and the last page for a document with headings, top-level keys
783
+ * for JSON, and a chunk count for everything — so `discover` describes the
784
+ * whole corpus rather than only the spreadsheets in it.
785
+ */
786
+ documentStructure(opts: {
787
+ documentIds: string[];
788
+ sourceIds?: string[] | null;
789
+ principals?: Principals;
790
+ bounded?: boolean;
791
+ redaction?: RedactionPolicy | null;
792
+ }): Promise<Record<string, DocumentStructure>>;
793
+ /**
794
+ * The corpus census — `[{kind, type, documents, with_fields}]`.
795
+ *
796
+ * See `actions.documentTypes`. `kind` comes from the mime and is always
797
+ * known; `type` is the LLM-written document type and exists only where
798
+ * structured extraction was opted into.
799
+ */
800
+ documentTypes(opts?: {
801
+ sourceIds?: string[] | null;
802
+ principals?: Principals;
803
+ documentIds?: string[] | null;
804
+ redaction?: RedactionPolicy | null;
805
+ }): Promise<DocumentTypeCount[]>;
806
+ /**
807
+ * Extracted structured field names grouped by document kind and type.
808
+ *
809
+ * See `actions.fieldSummary`. One row per group, keyed by the same
810
+ * `(kind, type)` pair `documentTypes` uses.
811
+ */
812
+ fieldSummary(opts?: {
813
+ sourceIds?: string[] | null;
814
+ principals?: Principals;
815
+ documentIds?: string[] | null;
816
+ redaction?: RedactionPolicy | null;
817
+ }): Promise<FieldGroup[]>;
511
818
  queryStructured(question: string, opts?: {
512
819
  sourceIds?: string[] | null;
513
820
  principals?: Principals;
514
821
  docType?: string | null;
515
822
  limit?: number;
823
+ redaction?: RedactionPolicy | null;
516
824
  }): Promise<Record<string, unknown>>;
517
825
  compute(instruction: string, opts?: {
518
826
  sourceIds?: string[] | null;
@@ -866,4 +1174,4 @@ declare function functionTool(fn: (...args: never[]) => unknown): CanonicalTool;
866
1174
  /** Bumped by CI on every main merge; 0.0.0 = pre-first-release. */
867
1175
  declare const __version__ = "0.0.0";
868
1176
 
869
- export { ApprovalExpired, ApprovalNotPending, type ApprovalRecord, CeleryRunner, CodeExecutionError, CodeExecutionTimeout, type ComputeDocument, type ComputeFrames, ContextEngine, ContextEngineConfig, DEFAULT_LEG_WEIGHT, DocumentNotFoundError, EXTRACTION_VERSION, Embedder, EngineActionError, ExtraMissingError, Extracted, ExtractionConfig, type ExtractionResult, GraphLegUnavailable, type Hit, Hooks, InProcessRunner, IngestReport, LLMClient, LLMConfig, type Principals, ProgressEvent, RedactionPolicy, RerankerConfig, type SearchResult, StorageBackend, TRUSTED, type TaskRunner, type TaskStatus, ToolConfig, type Trusted, UNSET, type Unset, UsageEvent, __version__, buildLlmClient, callLlm, compute, computeOverFrames, decryptDict, encryptDict, extract, extractStructuredData, functionTool, getDocumentText, getSecretKey, listDocuments, queryStructured, redactHits, rerank, resolveApproval, resolveFields, resolvePrincipals, rrfFuse, runMigrate, runSearch, shouldRequireApproval, upsertRegistry };
1177
+ export { ApprovalExpired, ApprovalNotPending, type ApprovalRecord, CeleryRunner, CodeExecutionError, CodeExecutionTimeout, type ComputeDocument, type ComputeFrames, ContextEngine, ContextEngineConfig, DEFAULT_LEG_WEIGHT, DocumentNotFoundError, EXTRACTION_VERSION, Embedder, EngineActionError, ExtraMissingError, Extracted, ExtractionConfig, type ExtractionResult, GraphLegUnavailable, type Hit, Hooks, InProcessRunner, IngestReport, KnowledgeComputeFn, LLMClient, LLMConfig, Principals, ProgressEvent, RedactionPolicy, RerankerConfig, ScopeInput, type SearchResult, StorageBackend, type TaskRunner, type TaskStatus, ToolConfig, Trusted, Unset, UsageEvent, __version__, buildLlmClient, callLlm, compute, computeOverFrames, decryptDict, documentStructure, documentTypes, encryptDict, extract, extractStructuredData, fieldSummary, functionTool, getDocumentText, getSecretKey, listDocuments, queryStructured, redactHits, rerank, resolveApproval, resolveFields, rrfFuse, runMigrate, runSearch, shouldRequireApproval, spreadsheetSchema, spreadsheetSchemaFromText, upsertRegistry };