@arnilo/prism 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +34 -57
- package/dist/agent-definitions.js +4 -1
- package/dist/agent-run-lifecycle.js +4 -0
- package/dist/agent-run-state.d.ts +4 -0
- package/dist/agent-run-state.js +18 -5
- package/dist/agent-session/session.d.ts +7 -0
- package/dist/agent-session/session.js +59 -2
- package/dist/cli-dev.d.ts +29 -0
- package/dist/cli-dev.js +52 -0
- package/dist/cli-init.d.ts +17 -2
- package/dist/cli-init.js +194 -21
- package/dist/cli-runner.d.ts +5 -1
- package/dist/cli-runner.js +12 -1
- package/dist/contracts-core/agent.d.ts +29 -2
- package/dist/contracts-protocol.d.ts +18 -0
- package/dist/contracts-run-state.d.ts +1 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/input.d.ts +8 -0
- package/dist/input.js +4 -0
- package/dist/rpc.d.ts +4 -1
- package/dist/rpc.js +5 -1
- package/dist/testing/persistence-schema.d.ts +1 -1
- package/dist/testing/persistence-schema.js +32 -28
- package/dist/testing/tool-conformance.d.ts +25 -0
- package/dist/testing/tool-conformance.js +128 -1
- package/dist/tool-search.d.ts +76 -0
- package/dist/tool-search.js +199 -0
- package/docs/0.1.0-readiness.md +2 -2
- package/docs/acp-agent.md +1 -1
- package/docs/agent-definitions.md +1 -1
- package/docs/antigravity-agent.md +1 -1
- package/docs/browser-automation.md +5 -5
- package/docs/caveman.md +2 -2
- package/docs/cli-rpc.md +26 -3
- package/docs/coding-agent-tools.md +7 -1
- package/docs/coding-security.md +1 -1
- package/docs/coding-tools.md +82 -0
- package/docs/compaction-and-retry.md +5 -2
- package/docs/compaction-llm.md +4 -4
- package/docs/compaction-observational-memory.md +49 -2
- package/docs/context-and-skills.md +2 -0
- package/docs/core.md +85 -0
- package/docs/credential-storage.md +1 -1
- package/docs/database-persistence.md +4 -0
- package/docs/dev-inspector.md +103 -0
- package/docs/diagrams.md +247 -0
- package/docs/documents.md +213 -0
- package/docs/evaluations.md +35 -1
- package/docs/extension-authoring.md +42 -0
- package/docs/graft.md +3 -3
- package/docs/guardrails.md +1 -1
- package/docs/host-security.md +4 -3
- package/docs/impeccable.md +2 -2
- package/docs/index.md +34 -23
- package/docs/mcp-tools.md +1 -1
- package/docs/migrate-to-0.4.md +312 -0
- package/docs/migration.md +22 -0
- package/docs/model-routing.md +1 -1
- package/docs/multi-agent-patterns.md +177 -0
- package/docs/multimodal-content.md +1 -1
- package/docs/obscura.md +10 -10
- package/docs/openapi-tools.md +1 -1
- package/docs/performance.md +23 -3
- package/docs/persistence-credentials-multimodality-primitives.md +1 -1
- package/docs/policy-and-audit.md +1 -1
- package/docs/ponytail.md +2 -2
- package/docs/prompt-registry.md +106 -0
- package/docs/provider-caching.md +32 -32
- package/docs/provider-conformance.md +1 -1
- package/docs/provider-packages.md +19 -19
- package/docs/provider-primitives.md +4 -4
- package/docs/providers/ai-sdk.md +3 -3
- package/docs/providers/alibaba.md +5 -5
- package/docs/providers/anthropic.md +6 -6
- package/docs/providers/azure.md +3 -3
- package/docs/providers/bedrock.md +3 -3
- package/docs/providers/clinepass.md +3 -3
- package/docs/providers/deepseek.md +3 -3
- package/docs/providers/google.md +4 -4
- package/docs/providers/kimi.md +3 -3
- package/docs/providers/neuralwatt.md +8 -8
- package/docs/providers/ollama.md +3 -3
- package/docs/providers/openai-compatible.md +1 -1
- package/docs/providers/openai.md +5 -5
- package/docs/providers/opencode-go.md +4 -4
- package/docs/providers/openrouter.md +3 -3
- package/docs/providers/vertex.md +5 -5
- package/docs/providers/xai.md +3 -3
- package/docs/providers/zai.md +3 -3
- package/docs/public-contracts.md +1 -1
- package/docs/rag.md +5 -5
- package/docs/release-and-install.md +116 -50
- package/docs/runs-and-usage.md +14 -1
- package/docs/server.md +90 -1
- package/docs/sheets.md +229 -0
- package/docs/supervisors.md +9 -1
- package/docs/thinking-and-reasoning.md +10 -10
- package/docs/tool-conformance.md +27 -2
- package/docs/tools.md +29 -2
- package/docs/web-tools.md +2 -2
- package/docs/wiki.md +24 -10
- package/docs/workflow-orchestration-primitives.md +24 -0
- package/docs/workflows.md +102 -8
- package/docs/working-and-semantic-memory.md +53 -5
- package/package.json +10 -30
- package/templates/README.md +23 -0
- package/templates/deep-research/README.md.tmpl +47 -0
- package/templates/deep-research/env.example.tmpl +12 -0
- package/templates/deep-research/gitignore.tmpl +7 -0
- package/templates/deep-research/manifest.json +12 -0
- package/templates/deep-research/package.json.tmpl +23 -0
- package/templates/deep-research/src/agent.ts.tmpl +81 -0
- package/templates/deep-research/src/index.ts.tmpl +53 -0
- package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
- package/templates/deep-research/src/tools.ts.tmpl +86 -0
- package/templates/deep-research/src/types.ts.tmpl +45 -0
- package/templates/deep-research/src/workflow.ts.tmpl +156 -0
- package/templates/deep-research/tsconfig.json.tmpl +15 -0
- package/templates/init/manifest.json +5 -0
- package/templates/init/package.json.tmpl +2 -1
- package/templates/init/providers.json +16 -16
package/docs/sheets.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Spreadsheets, CSV parsing, and typed schema inference (`@arnilo/prism-office/sheets`)
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
The `@arnilo/prism-office/sheets` package provides fail-closed, high-fidelity spreadsheet (XLSX) and delimiter-separated (CSV/TSV/PSV) data ingestion with automatic dialect sniffing, typed column schema inference, and **strict financial decimal safety**.
|
|
6
|
+
|
|
7
|
+
### Headline Guarantee: Strict Financial Decimal Safety
|
|
8
|
+
|
|
9
|
+
> [!IMPORTANT]
|
|
10
|
+
> **Zero Float Coercion on Decimal Paths**:
|
|
11
|
+
> In financial and enterprise data processing, floating-point rounding errors (IEEE-754 `double`) silently distort monetary totals, balance ledgers, and transaction reconciliations.
|
|
12
|
+
>
|
|
13
|
+
> In `@arnilo/prism-office/sheets`:
|
|
14
|
+
> - Money-like and decimal values are **never converted to JavaScript numbers (`Number()`, `parseFloat()`, or unary `+`)**.
|
|
15
|
+
> - All decimal and currency values are parsed, normalized, and emitted as exact canonical decimal strings: `{ type: "decimal", value: "1234.56" }`.
|
|
16
|
+
> - Currency markers (`$`, `€`, `£`, `¥`, `₹`, `CHF`, `USD`, `EUR`, etc.) and accounting parentheses `($1,234.56)` are normalized safely into canonical strings (`"-1234.56"`).
|
|
17
|
+
> - Ambiguous numbers (e.g. scientific notation `1.23e5` or inconsistent locale separators) are preserved as raw strings with `flags: ["numeric-ambiguous"]` rather than guessed.
|
|
18
|
+
> - An automated source-scan test in the regression suite enforces that no floating-point conversions exist on decimal paths across the codebase.
|
|
19
|
+
|
|
20
|
+
### Core Capabilities
|
|
21
|
+
|
|
22
|
+
- **Pure In-Memory Operation**: Accepts `Uint8Array` binary archives or `string | Uint8Array` CSV text. Zero filesystem access, zero network I/O, zero `process.env` lookups, and zero background worker threads.
|
|
23
|
+
- **Fail-Closed Container Gating**: XLSX archives must begin with the standard ZIP container magic signature (`PK\x03\x04`). CSV inputs support UTF-8 (with automatic BOM stripping); UTF-16 encoded buffers are refused fail-closed with `ERR_PRISM_SHEETS_UNSUPPORTED_FORMAT`.
|
|
24
|
+
- **Automatic CSV Dialect Sniffing**: Analyzes the first 4 KiB / 50 lines to detect candidate delimiters (`,`, `;`, `\t`, `|`) using variance-based scoring outside quoted regions, correctly distinguishing delimiters from commas within quoted addresses or company names.
|
|
25
|
+
- **RFC 4180 State Machine**: Handles embedded newlines in quoted fields, doubled-quote escaping (`""`), and CRLF / LF line endings in a single, non-backtracking linear pass (<60 ms for 1 MB CSVs).
|
|
26
|
+
- **Read-Only Formula Preservation**: OpenXML formula cells are extracted as `{ type: "formula", formula: "=SUM(A1:A10)", cachedValue: "100" }` and are **never evaluated or executed**.
|
|
27
|
+
- **Bounded Sampling Window + Full Validation**: Infers column types across an initial window (default 500 rows) and validates all subsequent records against the inferred schema, reporting structured `type-mismatch` warnings without silent coercion.
|
|
28
|
+
- **Privacy-Guaranteed Telemetry Seam**: Optional, dependency-free `SheetsTelemetry` hook emits `sheets.parse` spans carrying byte, row, column, and duration metrics with zero cell text or confidential payload leakage.
|
|
29
|
+
|
|
30
|
+
## When to use it
|
|
31
|
+
|
|
32
|
+
Use `@arnilo/prism-office/sheets` when autonomous agents, data pipelines, or enterprise workflows need to:
|
|
33
|
+
1. Ingest untrusted customer XLSX or CSV files with strict, unbypassable byte, row, column, and sheet caps.
|
|
34
|
+
2. Parse tabular financial records, invoices, ledgers, or pricing sheets with mathematical decimal precision guarantees.
|
|
35
|
+
3. Automatically determine CSV delimiters, quotes, and headers without manual dialect configuration.
|
|
36
|
+
4. Extract structural column schemas (`name`, `type`, `nullRate`, `sample`, `flags`) for automated data cataloging, SQL generation, or tool routing.
|
|
37
|
+
|
|
38
|
+
Do **not** use this package for interactive spreadsheet calculation/formula engines, macro execution, chart generation, or real-time collaborative editing.
|
|
39
|
+
|
|
40
|
+
## Inputs / request
|
|
41
|
+
|
|
42
|
+
### Primary Parsing Functions
|
|
43
|
+
|
|
44
|
+
| Function | Signature | Description |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `parseWorkbook` | `(bytes: Uint8Array, options?: ParseWorkbookOptions) => Promise<WorkbookParse>` | Parses an XLSX workbook binary buffer, enforces caps and ZIP signature gating, extracts raw cells, resolves shared strings and styles, and infers schemas per worksheet. |
|
|
47
|
+
| `parseCsv` | `(input: string \| Uint8Array, options?: ParseCsvOptions) => Promise<CsvParse>` | Parses CSV/TSV/PSV input with automatic dialect sniffing, BOM stripping, RFC 4180 state machine processing, and schema inference. |
|
|
48
|
+
| `inferAndTransformRows` | `(rows: readonly (readonly CellValue[])[], caps: ResolvedSheetsCaps) => InferAndTransformResult` | Pure function that infers column types over a sampling window and validates full rows against the inferred schema. |
|
|
49
|
+
|
|
50
|
+
### Decimal & Normalization Utilities
|
|
51
|
+
|
|
52
|
+
| Function | Signature | Description |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `normalizeDecimal` | `(input: string) => NormalizedDecimalResult \| null` | Normalizes currency strings, accounting negatives, and thousands separators into canonical decimal strings (`^-?\d+(\.\d+)?$`). Returns `null` if ambiguous or invalid. |
|
|
55
|
+
| `isCanonicalDecimal` | `(str: string) => boolean` | Checks if a string is already in canonical decimal format (e.g. `"1234.56"`, `"-0.05"`, `"42"`). |
|
|
56
|
+
| `isCurrencyString` | `(str: string) => boolean` | Checks if a string contains explicit currency symbols or currency codes (`$`, `€`, `USD`, etc.). |
|
|
57
|
+
| `isScientificNotation` | `(str: string) => boolean` | Checks if a string represents scientific notation (e.g. `"1.23e5"`, `"4.56E-3"`). |
|
|
58
|
+
|
|
59
|
+
### Cap Validation Utilities
|
|
60
|
+
|
|
61
|
+
| Function | Signature | Description |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `resolveSheetsCaps` | `(caps?: SheetsCaps) => ResolvedSheetsCaps` | Resolves user-configured limits against safe defaults and hard ceilings. |
|
|
64
|
+
| `validateByteCap` | `(byteLength: number, caps: ResolvedSheetsCaps) => void` | Validates input size against `caps.maxBytes`, throwing `SheetsCapError` if exceeded. |
|
|
65
|
+
| `validateZipSignature` | `(bytes: Uint8Array) => void` | Validates standard PKZIP magic bytes (`0x50, 0x4b, 0x03, 0x04`), throwing `SheetsFormatError` if missing. |
|
|
66
|
+
|
|
67
|
+
### Capacity Limits and Defaults
|
|
68
|
+
|
|
69
|
+
Limits are verified upfront and enforced progressively to prevent memory exhaustion and denial-of-service from adversarial inputs:
|
|
70
|
+
|
|
71
|
+
| Cap | Default | Hard Ceiling | Description |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| `maxBytes` | 32 MiB (`33,554,432`) | 512 MiB (`536,870,912`) | Maximum input buffer or string byte length. |
|
|
74
|
+
| `maxSheets` | 100 | 1,000 | Maximum worksheets in a workbook archive. |
|
|
75
|
+
| `maxRows` | 100,000 | 1,000,000 | Maximum rows per worksheet or CSV document. |
|
|
76
|
+
| `maxColumns` | 1,000 | 16,384 | Maximum columns per worksheet or CSV document. |
|
|
77
|
+
| `inferenceWindowRows` | 500 | 5,000 | Number of rows sampled for column schema inference. |
|
|
78
|
+
| `maxWarnings` | 100 | 1,000 | Maximum validation and dialect warnings recorded. |
|
|
79
|
+
|
|
80
|
+
## Outputs / response / events
|
|
81
|
+
|
|
82
|
+
### Error Hierarchy
|
|
83
|
+
|
|
84
|
+
All error classes inherit from `SheetsError` and carry structured error codes:
|
|
85
|
+
|
|
86
|
+
| Error Class | Code | Cause / Trigger |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| `SheetsCapError` | `ERR_PRISM_SHEETS_CAP` | Input size, sheet count, row count, or column count exceeds configured caps. |
|
|
89
|
+
| `SheetsValidationError` | `ERR_PRISM_SHEETS_VALIDATION` | Invalid cap configuration (e.g. non-integer or exceeding hard ceiling). |
|
|
90
|
+
| `SheetsFormatError` | `ERR_PRISM_SHEETS_UNSUPPORTED_FORMAT` | Missing ZIP container signature on XLSX input or unsupported encoding (UTF-16) on CSV input. |
|
|
91
|
+
| `SheetsParseError` | `ERR_PRISM_SHEETS_PARSE_FAILED` | Corrupt archive structure or malformed XML parts. |
|
|
92
|
+
|
|
93
|
+
### Schema & Warnings Output Shape
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
export interface ColumnSchema {
|
|
97
|
+
readonly name: string;
|
|
98
|
+
readonly type: "string" | "integer" | "number" | "decimal" | "date" | "datetime" | "boolean";
|
|
99
|
+
readonly nullRate: number;
|
|
100
|
+
readonly sample?: string;
|
|
101
|
+
readonly flags?: readonly ("numeric-ambiguous" | "mixed-types")[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface InferenceWarning {
|
|
105
|
+
readonly row: number;
|
|
106
|
+
readonly column: number;
|
|
107
|
+
readonly columnName?: string;
|
|
108
|
+
readonly expectedType: string;
|
|
109
|
+
readonly actualValue: string;
|
|
110
|
+
readonly message: string;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Request/response example
|
|
115
|
+
|
|
116
|
+
### Input CSV
|
|
117
|
+
|
|
118
|
+
```csv
|
|
119
|
+
transaction_id,item_description,total_amount,unit_price,refund_fee
|
|
120
|
+
TXN-1001,"Software Consulting","$1,234.56",1234.56,"($ 50.00)"
|
|
121
|
+
TXN-1002,"Cloud Server Hosting","€ 450.00",450.00,"-$ 10.00"
|
|
122
|
+
TXN-1003,"Hardware Device","£ 2,500.00",2500.00,"$ 0.00"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Parsed Output (`CsvParse`)
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"dialect": {
|
|
130
|
+
"delimiter": ",",
|
|
131
|
+
"quote": "\"",
|
|
132
|
+
"hasHeader": true
|
|
133
|
+
},
|
|
134
|
+
"schema": [
|
|
135
|
+
{ "name": "transaction_id", "type": "string", "nullRate": 0, "sample": "TXN-1001", "flags": [] },
|
|
136
|
+
{ "name": "item_description", "type": "string", "nullRate": 0, "sample": "Software Consulting", "flags": [] },
|
|
137
|
+
{ "name": "total_amount", "type": "decimal", "nullRate": 0, "sample": "$1,234.56", "flags": [] },
|
|
138
|
+
{ "name": "unit_price", "type": "decimal", "nullRate": 0, "sample": "1234.56", "flags": [] },
|
|
139
|
+
{ "name": "refund_fee", "type": "decimal", "nullRate": 0, "sample": "($ 50.00)", "flags": [] }
|
|
140
|
+
],
|
|
141
|
+
"rows": [
|
|
142
|
+
["transaction_id", "item_description", "total_amount", "unit_price", "refund_fee"],
|
|
143
|
+
["TXN-1001", "Software Consulting", { "type": "decimal", "value": "1234.56" }, { "type": "decimal", "value": "1234.56" }, { "type": "decimal", "value": "-50.00" }],
|
|
144
|
+
["TXN-1002", "Cloud Server Hosting", { "type": "decimal", "value": "450.00" }, { "type": "decimal", "value": "450.00" }, { "type": "decimal", "value": "-10.00" }],
|
|
145
|
+
["TXN-1003", "Hardware Device", { "type": "decimal", "value": "2500.00" }, { "type": "decimal", "value": "2500.00" }, { "type": "decimal", "value": "0.00" }]
|
|
146
|
+
],
|
|
147
|
+
"warnings": []
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Implementation example
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { parseWorkbook, parseCsv, type SheetsTelemetry } from "@arnilo/prism-office/sheets";
|
|
155
|
+
|
|
156
|
+
// 1. Parse XLSX workbook with custom caps
|
|
157
|
+
const xlsxBytes = new Uint8Array([...]); // Untrusted file bytes
|
|
158
|
+
const workbook = await parseWorkbook(xlsxBytes, {
|
|
159
|
+
caps: {
|
|
160
|
+
maxRows: 50_000,
|
|
161
|
+
maxColumns: 500,
|
|
162
|
+
maxBytes: 16 * 1024 * 1024,
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
for (const sheet of workbook.sheets) {
|
|
167
|
+
console.log(`Sheet: ${sheet.name} (${sheet.rows.length} rows)`);
|
|
168
|
+
for (const col of sheet.schema) {
|
|
169
|
+
console.log(` Column [${col.name}] inferred as ${col.type} (nullRate: ${col.nullRate})`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 2. Parse CSV with automatic dialect sniffing and telemetry
|
|
174
|
+
const csvText = `id;name;revenue\n1;"Acme, Corp";1000000.00\n2;"Global, Inc";500000.50\n`;
|
|
175
|
+
|
|
176
|
+
const telemetry: SheetsTelemetry = {
|
|
177
|
+
startSpan(name, attributes) {
|
|
178
|
+
console.log(`Span started: ${name}`, attributes);
|
|
179
|
+
return {
|
|
180
|
+
setAttribute() {},
|
|
181
|
+
addEvent() {},
|
|
182
|
+
recordError() {},
|
|
183
|
+
end() {},
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const csvResult = await parseCsv(csvText, { telemetry });
|
|
189
|
+
console.log(`Detected delimiter: "${csvResult.dialect.delimiter}"`);
|
|
190
|
+
console.log(`Revenue value:`, csvResult.rows[1][2]);
|
|
191
|
+
// Output: { type: "decimal", value: "1000000.00" }
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Extension and configuration notes
|
|
195
|
+
|
|
196
|
+
### Sub-package Pinning
|
|
197
|
+
To avoid pulling in CLI frameworks or extraneous dependencies, `@arnilo/prism-office/sheets` directly pins the exact underlying modular packages:
|
|
198
|
+
- `@office-open/xlsx@0.12.3`
|
|
199
|
+
- `@office-open/xml@0.12.3`
|
|
200
|
+
|
|
201
|
+
### Custom Telemetry Hook
|
|
202
|
+
The `SheetsTelemetry` seam allows optional OpenTelemetry instrumentation without adding runtime telemetry dependencies:
|
|
203
|
+
```ts
|
|
204
|
+
const telemetry: SheetsTelemetry = {
|
|
205
|
+
startSpan(name, attributes) {
|
|
206
|
+
// Maps to tracer.startSpan with allow-listed metadata (bytes, rows, columns, sheetCount)
|
|
207
|
+
// Cell contents and user data are NEVER passed to telemetry spans.
|
|
208
|
+
return activeSpan;
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Self-Hosting & Operational Notes
|
|
214
|
+
- **Zero Network & Storage Dependencies**: `@arnilo/prism-office/sheets` does not write files or contact network services. Host engines own persistence, storage buckets, and lake datasets.
|
|
215
|
+
- **Fail-Closed Container Gating**: Malicious or non-standard files are rejected before allocation or XML decompression occurs.
|
|
216
|
+
|
|
217
|
+
## Security and performance notes
|
|
218
|
+
|
|
219
|
+
- **Pure In-Memory Operation**: No temporary files, no shell execution, no binary spawning, and zero network sockets.
|
|
220
|
+
- **ZIP Signature Gating**: Buffers must begin with standard PKZIP container signatures (`0x50, 0x4B, 0x03, 0x04`). Extension-based type inference is strictly prohibited.
|
|
221
|
+
- **Fail-Closed Caps**: Input size and element count caps are evaluated before entering XML translation passes, preventing zip-bomb and decompression amplification attacks.
|
|
222
|
+
- **Strict Anti-Corruption Invariant**: Zero floating-point conversions on decimal paths guarantee exact financial calculations and ledger balances.
|
|
223
|
+
- **Performance Budget**: Warm parsing of 1 MB CSV files completes in under 60 ms; workbook parsing completes in under 100 ms.
|
|
224
|
+
|
|
225
|
+
## Related APIs
|
|
226
|
+
|
|
227
|
+
- [`@arnilo/prism-office/documents`](./documents.md): Specification-compliant OpenXML document generation, parsing, patching, and preview rendering for DOCX, XLSX, and PPTX.
|
|
228
|
+
- [`@arnilo/prism-document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
|
|
229
|
+
- [`@arnilo/prism-observability-opentelemetry`](./observability.md): OpenTelemetry instrumentation and trace adapters.
|
package/docs/supervisors.md
CHANGED
|
@@ -17,12 +17,16 @@ Use a supervisor when a host or agent must choose a child dynamically. Use `@arn
|
|
|
17
17
|
| `delegate({ childId, input, threadId?, limits?, signal? })` | Invokes one allow-listed child. Input is text and byte-bounded. |
|
|
18
18
|
| `hooks.before` | May reject, modify redacted input, or narrow limits/policy. |
|
|
19
19
|
| `hooks.after` | Observes redacted terminal summary; failures cannot alter settled result. |
|
|
20
|
-
| `limits` | Depth 4/16, active children 4/32, input 64 KiB/1 MiB, steps 8/64, tools 32/256, tokens 20k/1m, timeout 60s/30m, event queue 128/4096 default/hard. Over-cap `delegate()` throws `SupervisorLimitError` before incrementing `activeChildren`. Hook rejection and timeout decrement the count exactly once (no leaked timers). |
|
|
20
|
+
| `limits` | Depth 4/16, active children 4/32, input 64 KiB/1 MiB, steps 8/64, tools 32/256, tokens 20k/1m, timeout 60s/30m, event queue 128/4096, child events/delegation 256/4096, child-event bytes 32 KiB/256 KiB default/hard. Over-cap `delegate()` throws `SupervisorLimitError` before incrementing `activeChildren`. Hook rejection and timeout decrement the count exactly once (no leaked timers). |
|
|
21
21
|
|
|
22
22
|
## Outputs / response / events
|
|
23
23
|
|
|
24
24
|
`delegate()` returns the child's `AgentRunResult` or throws its `AgentRunError`/a supervisor denial or limit error. `subscribe()` emits bounded `delegation_started`, `delegation_finished`, `delegation_rejected`, and `delegation_error` metadata events. Graceful close drains already-queued terminal events before the iterator completes (same core multiplexer contract). Hosts may project those events through observability `handleDelegation()` using the parent Prism run ID; no OpenTelemetry dependency enters this package.
|
|
25
25
|
|
|
26
|
+
### Child event passthrough (opt-in)
|
|
27
|
+
|
|
28
|
+
`createSupervisor({ childEvents: true })` projects a redacted, size-capped **milestone** subset of child `AgentEvent`s onto the same stream as `delegation_child_event` (tagged `childId`, `delegationId`, `depth`). v1 covers run start/finish/`suspended`/`denied` and tool-execution started/finished/error/blocked — not per-token `message_delta`. Default off: the stream is byte-identical to today (no subscribe, no allocation). Caps: `limits.maxChildEventsPerDelegation` (256/4096) and `limits.maxChildEventBytes` (32 KiB/256 KiB); exceeding either drops further child events and emits one `delegation_child_events_capped` marker (never throws). Events pass through the supervisor `redactor` before emission. Children never receive supervisor internals or store/subscription access. Resume-path rebuilds (`resumeNestedRun`) do not currently project child events — live passthrough is the initial `delegate()` session only.
|
|
29
|
+
|
|
26
30
|
## Request/response example
|
|
27
31
|
|
|
28
32
|
```json
|
|
@@ -50,6 +54,8 @@ const supervisor = createSupervisor({
|
|
|
50
54
|
const result = await supervisor.delegate({ childId: "research", input: "Check sources" });
|
|
51
55
|
```
|
|
52
56
|
|
|
57
|
+
> **Contract — child factories return `Agent`.** `createAgent` must return an `Agent`, not an `AgentSession` (or a plain object). Wrong type throws `SupervisorError: child "<id>" factory must return an Agent, got <type>` on both initial `delegate()` and nested resume. Nested approvals also need a **stable config** plus a **durable (or rebuild-stable) store** — calling `createSession()` inside the factory and returning that session loses the child's checkpointed leaf. Live demo: [`examples/autonomous-coding-loop.ts`](../examples/autonomous-coding-loop.ts) (`childAgent` returns `createAgent(...)`).
|
|
58
|
+
|
|
53
59
|
## Durable child approvals
|
|
54
60
|
|
|
55
61
|
With `checkpoints` + `definitionRevision`, every child run is durable with `interruptBeforeTool: true`. A child that suspends on pending decisions throws `AgentDelegationSuspendedError` out of `delegate()`; when the delegation runs inside a root agent's tool, core converts it into a root suspension whose `interruption.pendingDecisions` carry hashed root-visible approval ids (`sub_<sha256(runId:childApprovalId)>`) and `attribution.path` (redacted child ids, root first, at most 8 deep). Root decisions route back through the same CAS rules: pass `supervisor.resumeNestedRun` as `resumeNestedRun` in the root run's `runState` and in every `resumeAgentRun` options object. The supervisor rebuilds the child from a bounded delegation mapping stored in the same checkpoint store (child id, delegation/thread ids, redacted input, version), re-runs the `before` hook so its narrowing applies to the resumed run (hooks must be idempotent), and re-attributes re-suspensions recursively, so grandchild decisions surface with the full path. A delegating child's own `interruptBeforeTool` also gates its delegate tool, so hosts approve delegation and the child's own side effects as separate stages. Root `*_for_run` stickies record the attribution path and only match the same delegation path; child stickies live on the child run and expire with it. A root approval never widens the child: the child's narrowed permission re-runs at dispatch. Unknown or foreign nested run ids fail closed with one non-enumerating error. Child factories must return stable configs and a durable (or rebuild-stable) session store for resume to work.
|
|
@@ -72,9 +78,11 @@ Supervisors propagate parent `identity` and `effectStore` to every child agent/r
|
|
|
72
78
|
|
|
73
79
|
## Related APIs
|
|
74
80
|
|
|
81
|
+
- [Multi-agent patterns](multi-agent-patterns.md): the decision table comparing this delegation pattern with in-session handoff (swarm) and A2A; handoff keeps one transcript, delegation keeps separate child runs — choose by boundary, budget, and telemetry needs.
|
|
75
82
|
- [Agent identity](agent-identity.md): host-verified identity and narrow delegation.
|
|
76
83
|
- [A2A interoperability](a2a.md): separate remote protocol boundary. `A2ATaskLifecycle` adapts host durable agent/workflow state directly; it does not route A2A execution through local supervisor child planning.
|
|
77
84
|
- [Workflows](workflows.md): preferred deterministic orchestration.
|
|
85
|
+
- Example: [`examples/autonomous-coding-loop.ts`](../examples/autonomous-coding-loop.ts) — per-child models, factory returns `Agent`.
|
|
78
86
|
- [Working and semantic memory](working-and-semantic-memory.md): child scope construction.
|
|
79
87
|
- [Host security](host-security.md): permission and credential boundaries.
|
|
80
88
|
- [Obscura browser engine](obscura.md): optional binary-backed generic tools for child agents.
|
|
@@ -59,16 +59,16 @@ Core maps only shapes shared by ≥2 packages (or an explicit no-op). Unique kno
|
|
|
59
59
|
|
|
60
60
|
| Package | Recommended family | Notes |
|
|
61
61
|
| --- | --- | --- |
|
|
62
|
-
| `@arnilo/prism-
|
|
63
|
-
| `@arnilo/prism-
|
|
64
|
-
| `@arnilo/prism-
|
|
65
|
-
| `@arnilo/prism-
|
|
66
|
-
| `@arnilo/prism-
|
|
67
|
-
| `@arnilo/prism-
|
|
68
|
-
| `@arnilo/prism-
|
|
69
|
-
| `@arnilo/prism-
|
|
70
|
-
| `@arnilo/prism-
|
|
71
|
-
| `@arnilo/prism-
|
|
62
|
+
| `@arnilo/prism-providers/openai` | `openai_reasoning` | First-class body `reasoning` from model + per-turn compat merge; `summary`/`mode`/`context` via compat |
|
|
63
|
+
| `@arnilo/prism-providers/openrouter` | `openai_reasoning` | First-class `resolveOpenRouterReasoning` merge; prefer `reasoning` object over legacy `reasoning_effort` shorthand; `preserveThinking` replays as body `reasoning` |
|
|
64
|
+
| `@arnilo/prism-providers/zai` | `reasoning_effort` (+ optional `thinking_type`) | Official `thinking` / `reasoning_effort` / `tool_stream` / `clear_thinking`; Preserved Thinking via `reasoning_content` |
|
|
65
|
+
| `@arnilo/prism-providers/neuralwatt` | `reasoning_effort` | Budgets / `preserve_thinking` / `clear_thinking` / `chat_template_kwargs` stay package-local on `compat` |
|
|
66
|
+
| `@arnilo/prism-providers/kimi` | K3: `reasoning_effort`; K2.x: `thinking_type` | K2.7-code thinking is always on; do not send conflicting `thinking` + `reasoning_effort` |
|
|
67
|
+
| `@arnilo/prism-providers/opencode-go` | Anthropic route: thinking blocks (`thinking_type` family); OpenAI route: `reasoning_content` preserve + optional `thinking`/`reasoning_effort`/`reasoning` passthrough | Official dual endpoints; MiniMax/Qwen → Anthropic, others → OpenAI |
|
|
68
|
+
| `@arnilo/prism-providers/ai-sdk` | `noop` | Host `LanguageModelV4` owns reasoning settings |
|
|
69
|
+
| `@arnilo/prism-providers/deepseek` | `thinking_type` + `reasoning_effort` | Thinking on by default (`high`). `cacheRetention: "none"` or `thinking: false` disables. Tool turns must replay `reasoning_content` or the API returns 400. |
|
|
70
|
+
| `@arnilo/prism-providers/xai` | replay only | Featured Completions do not send `reasoning_effort`. Reasoning models must replay `reasoning_content` or the prefix cache breaks. Do not flatten thinking into text. |
|
|
71
|
+
| `@arnilo/prism-providers/clinepass` | `reasoning_effort` | Per-model `compat.thinkingLevelMap`. GLM `xhigh` passthrough (never send `max`). K3 `high` → `max`. Unsupported slots omit the field. |
|
|
72
72
|
|
|
73
73
|
`thinkingFamilyForModel` infers family from existing `compat` shape, then safe provider heuristics (`openai*` → `openai_reasoning`, `neuralwatt` → `reasoning_effort`), then `capabilities.reasoning` → `reasoning_effort`, else `noop`. Docs and packages may map other provider ids explicitly; core avoids provider-specific literals beyond those heuristics.
|
|
74
74
|
|
package/docs/tool-conformance.md
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
Tool conformance helpers are dependency-free assertions for tool-dispatch configuration tests. They exercise the blocked-reason matrix and the success path of `dispatchToolCall` without network or credentials.
|
|
5
|
+
Tool conformance helpers are dependency-free assertions for tool-dispatch configuration tests. They exercise the blocked-reason matrix and the success path of `dispatchToolCall` without network or credentials, and the tool-disclosure contract (progressive tool loading, plan 041) without any provider call.
|
|
6
6
|
|
|
7
7
|
Exported from `@arnilo/prism/testing/tool-conformance`:
|
|
8
8
|
|
|
9
9
|
- `assertToolDispatchConforms(registry, options)`
|
|
10
|
+
- `assertToolDisclosureConforms(options)`
|
|
10
11
|
- `assertToolBlocked(probe, expectedReason)`
|
|
11
12
|
- `dispatchAndCollect(probe)`
|
|
12
|
-
- `ToolConformanceOptions`, `ToolDispatchProbeOptions`
|
|
13
|
+
- `ToolConformanceOptions`, `ToolDispatchProbeOptions`, `ToolDisclosureConformanceOptions`
|
|
13
14
|
|
|
14
15
|
## When to use it
|
|
15
16
|
|
|
@@ -45,6 +46,29 @@ await assertToolDispatchConforms(createToolRegistry(), {
|
|
|
45
46
|
|
|
46
47
|
`assertToolDispatchConforms` returns `Promise<void>` and throws on the first violation. `dispatchAndCollect` returns `{ result, events }` capturing the emitted `AgentEvent`s for custom assertions.
|
|
47
48
|
|
|
49
|
+
`assertToolDispatchConforms` returns `Promise<void>` and throws on the first violation. `dispatchAndCollect` returns `{ result, events }` capturing the emitted `AgentEvent`s for custom assertions.
|
|
50
|
+
|
|
51
|
+
### Disclosure leg (toolsDisclosure "search")
|
|
52
|
+
|
|
53
|
+
`assertToolDisclosureConforms(options)` asserts the progressive tool-loading contract against the same narrowing the runtime applies (`filterTools` allow/deny bounds, then `selectDisclosedTools`):
|
|
54
|
+
|
|
55
|
+
- search mode only narrows: the disclosed set is a subset of the allow/deny-filtered input, never wider, never zero, deterministic order for identical turns; a deny-listed tool is never described to the provider
|
|
56
|
+
- the generated `search_tools` tool is always kept in the disclosed set
|
|
57
|
+
- fail closed: an index over the frozen 1024-tool cap discloses the full eligible list
|
|
58
|
+
- `search_tools` output is inert: names plus byte-truncated (512-char) descriptions only — no JSON structure, no tool schemas — oversized hosts descriptions are truncated, never executed, and configured `secrets` never surface even when a description carries one
|
|
59
|
+
- activation is bounded to topK and only ever selects from the eligible set; activated tools stay disclosed on the next turn
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { assertToolDisclosureConforms } from "@arnilo/prism/testing/tool-conformance";
|
|
63
|
+
|
|
64
|
+
assertToolDisclosureConforms({
|
|
65
|
+
tools: hostTools, // incl. schema-bearing and oversized-description tools
|
|
66
|
+
filter: { deny: ["legacy_tool"] }, // host allow/deny bounds
|
|
67
|
+
search: { topK: 16 },
|
|
68
|
+
secrets: [hostSecret], // secret-scan of model-facing search output
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
48
72
|
## Request/response example
|
|
49
73
|
|
|
50
74
|
```ts
|
|
@@ -84,5 +108,6 @@ await assertToolDispatchConforms(createToolRegistry(), {
|
|
|
84
108
|
## Related APIs
|
|
85
109
|
|
|
86
110
|
- [Tools](tools.md)
|
|
111
|
+
- [Tool effects](tool-effects.md)
|
|
87
112
|
- [Settings, auth, trust, security](settings-auth-trust-security.md)
|
|
88
113
|
- [Provider conformance](provider-conformance.md)
|
package/docs/tools.md
CHANGED
|
@@ -251,13 +251,40 @@ createJsonSchemaToolArgumentValidator({
|
|
|
251
251
|
});
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
+
## Tool disclosure (progressive tool loading)
|
|
255
|
+
|
|
256
|
+
`toolsDisclosure` on `AgentConfig` / `RunOptions` (run wins; default `"all"`) controls how active tools reach the provider request. Default `"all"` sends every active tool schema — byte-identical to releases before the option existed. Opt-in `"search"` surfaces a bounded top-k subset per turn (scored lexically against the turn input over name and description) plus the generated `search_tools` tool; the model requests more by calling it.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const agent = createAgent({
|
|
260
|
+
model, provider,
|
|
261
|
+
tools, // host-active ToolDefinitions (or registry)
|
|
262
|
+
toolsDisclosure: "search", // default "all"
|
|
263
|
+
toolsSearch: { topK: 16 }, // optional; clamped to the hard cap
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Limits (mirroring the skill-disclosure DEFAULT/HARD cap pattern):
|
|
268
|
+
|
|
269
|
+
| Limit | Default | Hard cap |
|
|
270
|
+
| --- | --- | --- |
|
|
271
|
+
| Disclosed tools per turn (`topK`) | 16 | 64 |
|
|
272
|
+
| Indexed tools | — | 1024 (fail closed to full disclosure) |
|
|
273
|
+
| Search query bytes | 4096 | 65536 |
|
|
274
|
+
|
|
275
|
+
- `search_tools({ query, k? })` returns inert `name: short description [matched: …]` lines — no schemas or tool bodies — and marks returned tools active for the session. Activation is names-only in run persistence (`sessionState.activatedToolNames`, capped at 128 names) and inert for tools absent from the current registry; a host can reset it with `session.clearActivatedTools()`.
|
|
276
|
+
- Fail closed: any index or scoring error discloses the full input list — never zero tools, never wider than the input list. Exhausting the frozen 1024-tool index cap is surfaced the same way.
|
|
277
|
+
- Disclosure never grants access: dispatch re-checks registry membership and allow/deny (`unknown_tool` / `tool_denied`) on every call regardless of what was described. Search results are intersected with the disclosed list structurally — searched tools are only ever selected from that list, never widened.
|
|
278
|
+
- Scoring is BM25-lite lexical (name tokens weigh ×3, IDF from the registry): bounded, dependency-free, deterministic tie-breaks. ponytail ceiling: embedder-backed scoring via `@arnilo/prism-rag` if accuracy fixtures fall short.
|
|
279
|
+
- Cross-link: skills apply the same discipline to prompt text — see [Context and skills](context-and-skills.md).
|
|
280
|
+
|
|
254
281
|
## Guardrails
|
|
255
282
|
|
|
256
283
|
`DispatchToolCallOptions.guardrails` evaluates `tool_input` after `tool_call` middleware normalization and before lookup, permission, validation, execution policy, or side effect. `tool_output` evaluates raw completed results before redaction, event emission, ledger rows, and transcript append. A block returns a blocked result; tripwire fails the enclosing run. See [Guardrails](guardrails.md).
|
|
257
284
|
|
|
258
285
|
## Related APIs
|
|
259
286
|
|
|
260
|
-
- [OpenAPI tools adapter](openapi-tools.md): optional `@arnilo/prism-
|
|
287
|
+
- [OpenAPI tools adapter](openapi-tools.md): optional `@arnilo/prism-coding-tools/openapi` `createOpenApiTools` — compile host-selected OpenAPI 3.1 operationIds into bounded `ToolDefinition`s (allow-list only, pinned origin, resolved/bounded schemas, approval + effect-store idempotency on mutations, bounded body/response/retries/pagination, host credential resolver, untrusted output).
|
|
261
288
|
- [Agent/session runtime](agent-session-runtime.md): dispatches complete provider tool calls through the host-active tool harness and returns tool results on the next provider turn.
|
|
262
289
|
- [Public contracts](public-contracts.md): `ToolDefinition`, `ToolRegistry`, `ToolExecutionContext`, `ToolResult`, and tool `AgentEvent` contracts.
|
|
263
290
|
- [Contribution registries](contribution-registries.md): inert extension/package tool contribution storage.
|
|
@@ -270,6 +297,6 @@ createJsonSchemaToolArgumentValidator({
|
|
|
270
297
|
- [MCP client bridge](mcp-tools.md): optional remote tool mapping plus separate bounded resource/prompt facades; non-tool MCP capabilities never bypass tool dispatch by masquerading as `ToolDefinition`.
|
|
271
298
|
- [Recoverable tool effects](tool-effects.md): optional `tool.effect` + `effectStore` claim/CAS recovery around dispatch.
|
|
272
299
|
- [Recoverable tool effects](tool-effects.md): optional `tool.effect` + `effectStore` claim/CAS recovery around dispatch.
|
|
273
|
-
- [Coding agent tools](coding-agent-tools.md): optional first-party `@arnilo/prism-coding-agent` `shell`/`read`/`write`/`edit` tools a host registers into this harness.
|
|
300
|
+
- [Coding agent tools](coding-agent-tools.md): optional first-party `@arnilo/prism-coding-tools/agent` `shell`/`read`/`write`/`edit` tools a host registers into this harness.
|
|
274
301
|
|
|
275
302
|
`DispatchToolCallOptions.trust` and `.permission` run before validation or `execute()`; denial emits `tool_execution_blocked`. Middleware cannot bypass either guard. `AgentConfig.validator`/`RunOptions.validate` run after these guards; their output is redacted through the active `SecretRedactor`. `createSecureAgent()` requires all three seams plus non-empty schemas and durable pre-tool approval. Prism does not sandbox tools. See [Security/auth/trust](settings-auth-trust-security.md).
|
package/docs/web-tools.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Use when agent needs explicit public-web discovery or host-approved document retrieval/extraction. Keep search separate from fetch/extract so model cannot select provider, credential, API origin, extraction schema, or cost path.
|
|
10
10
|
|
|
11
|
-
**Obscura-backed alternative**: the optional
|
|
11
|
+
**Obscura-backed alternative**: the optional `@arnilo/prism-web-tools/obscura` subpath ([Obscura](obscura.md)) provides `web_search`/`web_fetch` behavior backed by a host-installed Obscura headless browser through its CLI (one replaceable HTML search profile instead of an API key), plus explicit native `obscura_fetch`/`obscura_scrape` batch tools. It reuses this package's normalized citation/untrusted shapes (`provider: "obscura"`) but does not require credentials; the API-backed Brave/Exa/Firecrawl adapters here remain the preferred path when an API key is available.
|
|
12
12
|
|
|
13
13
|
## Inputs / request
|
|
14
14
|
|
|
@@ -69,7 +69,7 @@ Default/hard limits: query 4/16 KiB; results 10/20; URLs 5/20; request 256 KiB/1
|
|
|
69
69
|
|
|
70
70
|
Provider credentials never enter tool schemas/results, prompts, telemetry, URLs, or errors. Error text excludes remote bodies. Search snippets, Markdown, and extracted JSON are prompt-injection-capable data: never concatenate them into system instructions or use them to modify tools, permissions, credentials, trust, routing, or schemas. Firecrawl fetches target URLs remotely; Prism cannot claim target DNS pinning after handoff. Use controlled host fetch when that guarantee is required.
|
|
71
71
|
|
|
72
|
-
Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Prefer
|
|
72
|
+
Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Prefer the [`browser`](browser-automation.md) subpath over ordinary public retrieval; use browser automation only for interactive/authenticated/JavaScript-heavy work behind a host egress proxy. Arbitrary HTML execution, model-selected providers, automatic OAuth forwarding, and generic web/MCP passthrough are unsupported.
|
|
73
73
|
|
|
74
74
|
## Related APIs
|
|
75
75
|
|
package/docs/wiki.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# LLM Wiki (@arnilo/prism-wiki)
|
|
1
|
+
# LLM Wiki (@arnilo/prism-memory/wiki)
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-wiki` implements Andrej Karpathy's **LLM Wiki Pattern** for the Prism agent ecosystem. It acts as a knowledge compiler that transforms raw, immutable sources (source code, AST symbols, notes, markdown clips, transcripts, journal entries) into a persistent, compounding, cross-linked Markdown knowledge base (`.wiki/`).
|
|
5
|
+
The `@arnilo/prism-memory/wiki` subpath implements Andrej Karpathy's **LLM Wiki Pattern** for the Prism agent ecosystem. It acts as a knowledge compiler that transforms raw, immutable sources (source code, AST symbols, notes, markdown clips, transcripts, journal entries) into a persistent, compounding, cross-linked Markdown knowledge base (`.wiki/`).
|
|
6
6
|
|
|
7
7
|
It integrates Tobias Lütke's [`qmd`](https://github.com/tobi/qmd) on-device hybrid search engine (BM25, vector search, and LLM reranking) and hydrates search results with Context7-inspired hierarchical breadcrumbs (`# Category > ## Topic`) and live clickable source line anchors (`file:///path/to/file#Lxx-Lyy` format), enabling agents and humans to navigate code and notes directly without blind regex loops (`grep`/`rg`).
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ The Karpathy LLM Wiki pattern is structured into 3 distinct tiers:
|
|
|
19
19
|
|
|
20
20
|
1. **Raw Sources (Immutable)**: Source code files, design docs, transcripts, journals, and Markdown notes. Raw sources are strictly read-only and never mutated.
|
|
21
21
|
2. **Compiled Wiki (`.wiki/`)**: Persistent, cross-linked Markdown documents containing synthesized architecture models, entity descriptions, decision records, and line-anchored claims.
|
|
22
|
-
3. **Schema & Protocols (`SCHEMA.md`)**: Operational guidelines governing
|
|
22
|
+
3. **Schema & Protocols (`SCHEMA.md`)**: Operational guidelines governing OKF v0.2 emission, entity categorization, citation rules (`file:///path#Lxx-Lyy`), catalog indexing (`index.md`), and chronological change logging (`log.md`).
|
|
23
23
|
|
|
24
24
|
## Inputs / request
|
|
25
25
|
|
|
@@ -44,7 +44,7 @@ The Karpathy LLM Wiki pattern is structured into 3 distinct tiers:
|
|
|
44
44
|
|
|
45
45
|
- `/wiki-init`: Scaffolds `.wiki/`, instantiates `SCHEMA.md`, `index.md`, and `log.md`, deploys skills, and adds the `qmd` collection.
|
|
46
46
|
- `/wiki-refresh`: Detects modified source files via SHA-256 Merkle diffing, compiles updates to affected entity pages, reconciles contradictions in `log.md`, and runs `qmd update`.
|
|
47
|
-
- `/wiki-lint`: Checks
|
|
47
|
+
- `/wiki-lint`: Checks OKF frontmatter (`type`, ISO `generated.at`), leftover `[[wikilinks]]`, unresolved relative markdown links, dead line anchors, and orphan pages.
|
|
48
48
|
|
|
49
49
|
### Standalone CLI Commands
|
|
50
50
|
|
|
@@ -81,7 +81,7 @@ npx prism-wiki search "How does authentication work?" --mode query
|
|
|
81
81
|
### Response Content:
|
|
82
82
|
```markdown
|
|
83
83
|
### Match 1: Authentication Architecture > Token Verification
|
|
84
|
-
- **Wiki Page:**
|
|
84
|
+
- **Wiki Page:** `entities/authentication.md`
|
|
85
85
|
- **Category:** Core Module
|
|
86
86
|
- **Freshness:** Current (Source hash matches manifest)
|
|
87
87
|
|
|
@@ -91,14 +91,14 @@ The authentication layer uses asymmetric Ed25519 JWT verification in middleware,
|
|
|
91
91
|
**Code & Source Anchors (Clickable):**
|
|
92
92
|
- Token verification: `verifyToken()` (`file:///src/auth/jwt.ts#L45-L89`)
|
|
93
93
|
- Revocation check: `assertNotRevoked()` (`file:///src/auth/session-store.ts#L112-L138`)
|
|
94
|
-
- Architecture Decision:
|
|
94
|
+
- Architecture Decision: `decisions/ADR-004-ed25519-migration.md`
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
## Implementation example
|
|
98
98
|
|
|
99
99
|
```ts
|
|
100
100
|
import { createExtensionKernel } from "@arnilo/prism";
|
|
101
|
-
import { createWikiExtension, initWiki, refreshWiki, lintWiki } from "@arnilo/prism-wiki";
|
|
101
|
+
import { createWikiExtension, initWiki, refreshWiki, lintWiki } from "@arnilo/prism-memory/wiki";
|
|
102
102
|
|
|
103
103
|
const kernel = createExtensionKernel();
|
|
104
104
|
|
|
@@ -112,16 +112,30 @@ await kernel.load([wiki]);
|
|
|
112
112
|
|
|
113
113
|
## Skills and Auto-Deployment
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
The wiki subpath includes two specialized skills formatted according to `.agents/skills/skill-creator`:
|
|
116
116
|
|
|
117
117
|
1. **`wiki-maintainer`**: Ingestion, compilation, line-anchor validation, and contradiction reconciliation rules.
|
|
118
118
|
2. **`wiki-searcher`**: Context7 hierarchical breadcrumb query resolution, zero-grep instructions, and compounding insight recording.
|
|
119
119
|
|
|
120
120
|
When initialized (`wiki-init` or `createWikiExtension`), these skills are automatically deployed to the host workspace's `.agents/skills/` folder so any compatible agent can leverage them immediately.
|
|
121
121
|
|
|
122
|
+
## OKF v0.2 bundle format
|
|
123
|
+
|
|
124
|
+
Emitted `.wiki/` trees are [OKF v0.2](https://github.com/GoogleCloudPlatform/open-knowledge-format) bundles. Karpathy compilation (synthesize, don't copy; precise `file:///` anchors; contradiction reconciliation; synchronized catalog/ledger) is unchanged.
|
|
125
|
+
|
|
126
|
+
| Artifact | OKF rule |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| Root `index.md` | Only `okf_version: "0.2"` frontmatter; sectioned bullet listings per OKF §8 |
|
|
129
|
+
| `entities/index.md`, `decisions/index.md`, `concepts/index.md` | No frontmatter (progressive disclosure) |
|
|
130
|
+
| Concept pages | `type` required (Module / Concept / Decision Record / Entity / Person / Tool), plus `title`, `description`, `tags`, `sources[].resource`, `generated: { by: prism-wiki/<version>, at: <ISO 8601 UTC> }` |
|
|
131
|
+
| `log.md` | `# Directory Update Log`, `## YYYY-MM-DD` newest first, `* **Verb**: …` |
|
|
132
|
+
| Links | Standard relative markdown. `[[wikilinks]]` are lint errors |
|
|
133
|
+
|
|
134
|
+
`.manifest.json` remains the compilation ledger (`id`, `category`, `rawSources`, `lastCompiledAt`). Those keys are not copied into page frontmatter. Trust families (`verified`, `status`) are omitted in v1 (unverified). `wiki-refresh` upgrades pages it touches; leftover legacy pages can be re-scaffolded — the format is regenerable from raw sources.
|
|
135
|
+
|
|
122
136
|
## Extension and configuration notes
|
|
123
137
|
|
|
124
|
-
-
|
|
138
|
+
- The wiki subpath registers tools (`wiki_search`, `wiki_read_page`, `wiki_record_insight`), commands (`wiki-init`, `wiki-refresh`, `wiki-lint`), skills (`wiki-maintainer`, `wiki-searcher`), and instruction injectors (`wiki-guidance`) into Prism registries.
|
|
125
139
|
- It operates with zero core modifications and can be used with any `@arnilo/prism` agent.
|
|
126
140
|
- `qmd` is optional but recommended. When `@tobilu/qmd` is not installed, the search engine falls back to catalog matching against `index.md`.
|
|
127
141
|
|
|
@@ -134,7 +148,7 @@ When initialized (`wiki-init` or `createWikiExtension`), these skills are automa
|
|
|
134
148
|
|
|
135
149
|
## Related APIs
|
|
136
150
|
|
|
137
|
-
- [`@arnilo/prism-rag`](rag.md): Bounded document chunking and vector context injection.
|
|
151
|
+
- [`@arnilo/prism-memory/rag`](rag.md): Bounded document chunking and vector context injection.
|
|
138
152
|
- [`@arnilo/prism-memory`](working-and-semantic-memory.md): Embedder and VectorStore primitives.
|
|
139
153
|
- [`@arnilo/prism-coding-agent`](coding-agent-tools.md): Code manipulation and reading tools.
|
|
140
154
|
- [`Contribution registries`](contribution-registries.md): Extension contribution model.
|
|
@@ -12,6 +12,8 @@ Interactive TUI (**C-012**) is **out of scope** for Plan 057 and deferred. Workf
|
|
|
12
12
|
|
|
13
13
|
**Phase 11 addendum (2026-07-16):** schedules use a separate generic checkpoint namespace plus per-fire `LeaseStore` claims and deterministic queued-run IDs; SQLite/PostgreSQL need no workflow-specific table or migration. Background execution remains `enqueueWorkflow` + the existing coordinator. Nested workflow nodes call the same runner with inherited policy/ownership/checkpoint/event seams. Shared JSON state is validated, redacted, byte/history bounded, and checkpointed by version. Replay creates a new checkpoint with immutable source lineage and copied terminal evidence; approval-bearing prior paths cannot be copied.
|
|
14
14
|
|
|
15
|
+
**Plan 045 Task 2 addendum (2026-08-31):** loop nodes keep one acyclic graph node while durable checkpoints append bounded, versioned iteration records. A tool sub-step can suspend before side effects; approved resume re-enters only the incomplete iteration. `node_iteration_started` / `node_iteration_finished` expose stable iteration IDs and bounded/redacted outputs. Replay starts a fresh cursor and emits new iteration events. A host saga treats the loop as one aggregate step and compensates its iteration IDs in reverse order; no workflow-specific SQL or implicit saga coupling is added.
|
|
16
|
+
|
|
15
17
|
## When to use it
|
|
16
18
|
|
|
17
19
|
- **Workflow package authors** should start here, then follow [Agent/session runtime](agent-session-runtime.md), [Agent loops](agent-loops.md), [Runs and usage ledger](runs-and-usage.md), [CLI/RPC](cli-rpc.md), and [Database persistence](database-persistence.md).
|
|
@@ -139,6 +141,7 @@ import type { OwnershipScope, SecretRedactor } from "@arnilo/prism";
|
|
|
139
141
|
|
|
140
142
|
/** Schema version for checkpoint payload layout (package-owned). */
|
|
141
143
|
export const WORKFLOW_CHECKPOINT_SCHEMA_VERSION = 1 as const;
|
|
144
|
+
export const WORKFLOW_LOOP_ITERATION_SCHEMA_VERSION = 1 as const;
|
|
142
145
|
|
|
143
146
|
export type WorkflowRunStatus =
|
|
144
147
|
| "queued"
|
|
@@ -158,6 +161,16 @@ export interface WorkflowNodeCheckpoint {
|
|
|
158
161
|
readonly sessionId?: string;
|
|
159
162
|
readonly leafId?: string;
|
|
160
163
|
readonly runId?: string;
|
|
164
|
+
/** Optional additive loop cursor/ledger; absent on legacy checkpoints. */
|
|
165
|
+
readonly iteration?: number;
|
|
166
|
+
readonly lastOutput?: unknown;
|
|
167
|
+
readonly iterations?: readonly {
|
|
168
|
+
readonly schemaVersion: typeof WORKFLOW_LOOP_ITERATION_SCHEMA_VERSION;
|
|
169
|
+
readonly iteration: number;
|
|
170
|
+
readonly iterationId: string;
|
|
171
|
+
readonly done: boolean;
|
|
172
|
+
readonly output?: unknown;
|
|
173
|
+
}[];
|
|
161
174
|
}
|
|
162
175
|
|
|
163
176
|
export interface WorkflowCheckpointValue {
|
|
@@ -259,6 +272,17 @@ export type WorkflowEvent =
|
|
|
259
272
|
| { readonly type: "workflow_finished"; readonly workflowId: string; readonly runId: string; readonly status: WorkflowRunStatus; readonly timestamp: string }
|
|
260
273
|
| { readonly type: "node_started"; readonly workflowId: string; readonly runId: string; readonly nodeId: string; readonly timestamp: string }
|
|
261
274
|
| { readonly type: "node_finished"; readonly workflowId: string; readonly runId: string; readonly nodeId: string; readonly timestamp: string }
|
|
275
|
+
| {
|
|
276
|
+
readonly type: "node_iteration_started" | "node_iteration_finished";
|
|
277
|
+
readonly workflowId: string;
|
|
278
|
+
readonly runId: string;
|
|
279
|
+
readonly nodeId: string;
|
|
280
|
+
readonly iteration: number;
|
|
281
|
+
readonly iterationId: string;
|
|
282
|
+
readonly done?: boolean;
|
|
283
|
+
readonly output?: unknown;
|
|
284
|
+
readonly timestamp: string;
|
|
285
|
+
}
|
|
262
286
|
| { readonly type: "node_failed"; readonly workflowId: string; readonly runId: string; readonly nodeId: string; readonly error: { readonly message: string; readonly code?: string | number }; readonly timestamp: string }
|
|
263
287
|
| { readonly type: "node_skipped"; readonly workflowId: string; readonly runId: string; readonly nodeId: string; readonly reason?: string; readonly timestamp: string }
|
|
264
288
|
| { readonly type: "checkpoint_saved"; readonly workflowId: string; readonly runId: string; readonly version: number; readonly timestamp: string }
|