@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.
Files changed (123) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +34 -57
  3. package/dist/agent-definitions.js +4 -1
  4. package/dist/agent-run-lifecycle.js +4 -0
  5. package/dist/agent-run-state.d.ts +4 -0
  6. package/dist/agent-run-state.js +18 -5
  7. package/dist/agent-session/session.d.ts +7 -0
  8. package/dist/agent-session/session.js +59 -2
  9. package/dist/cli-dev.d.ts +29 -0
  10. package/dist/cli-dev.js +52 -0
  11. package/dist/cli-init.d.ts +17 -2
  12. package/dist/cli-init.js +194 -21
  13. package/dist/cli-runner.d.ts +5 -1
  14. package/dist/cli-runner.js +12 -1
  15. package/dist/contracts-core/agent.d.ts +29 -2
  16. package/dist/contracts-protocol.d.ts +18 -0
  17. package/dist/contracts-run-state.d.ts +1 -2
  18. package/dist/index.d.ts +3 -1
  19. package/dist/index.js +2 -1
  20. package/dist/input.d.ts +8 -0
  21. package/dist/input.js +4 -0
  22. package/dist/rpc.d.ts +4 -1
  23. package/dist/rpc.js +5 -1
  24. package/dist/testing/persistence-schema.d.ts +1 -1
  25. package/dist/testing/persistence-schema.js +32 -28
  26. package/dist/testing/tool-conformance.d.ts +25 -0
  27. package/dist/testing/tool-conformance.js +128 -1
  28. package/dist/tool-search.d.ts +76 -0
  29. package/dist/tool-search.js +199 -0
  30. package/docs/0.1.0-readiness.md +2 -2
  31. package/docs/acp-agent.md +1 -1
  32. package/docs/agent-definitions.md +1 -1
  33. package/docs/antigravity-agent.md +1 -1
  34. package/docs/browser-automation.md +5 -5
  35. package/docs/caveman.md +2 -2
  36. package/docs/cli-rpc.md +26 -3
  37. package/docs/coding-agent-tools.md +7 -1
  38. package/docs/coding-security.md +1 -1
  39. package/docs/coding-tools.md +82 -0
  40. package/docs/compaction-and-retry.md +5 -2
  41. package/docs/compaction-llm.md +4 -4
  42. package/docs/compaction-observational-memory.md +49 -2
  43. package/docs/context-and-skills.md +2 -0
  44. package/docs/core.md +85 -0
  45. package/docs/credential-storage.md +1 -1
  46. package/docs/database-persistence.md +4 -0
  47. package/docs/dev-inspector.md +103 -0
  48. package/docs/diagrams.md +247 -0
  49. package/docs/documents.md +213 -0
  50. package/docs/evaluations.md +35 -1
  51. package/docs/extension-authoring.md +42 -0
  52. package/docs/graft.md +3 -3
  53. package/docs/guardrails.md +1 -1
  54. package/docs/host-security.md +4 -3
  55. package/docs/impeccable.md +2 -2
  56. package/docs/index.md +34 -23
  57. package/docs/mcp-tools.md +1 -1
  58. package/docs/migrate-to-0.4.md +312 -0
  59. package/docs/migration.md +22 -0
  60. package/docs/model-routing.md +1 -1
  61. package/docs/multi-agent-patterns.md +177 -0
  62. package/docs/multimodal-content.md +1 -1
  63. package/docs/obscura.md +10 -10
  64. package/docs/openapi-tools.md +1 -1
  65. package/docs/performance.md +23 -3
  66. package/docs/persistence-credentials-multimodality-primitives.md +1 -1
  67. package/docs/policy-and-audit.md +1 -1
  68. package/docs/ponytail.md +2 -2
  69. package/docs/prompt-registry.md +106 -0
  70. package/docs/provider-caching.md +32 -32
  71. package/docs/provider-conformance.md +1 -1
  72. package/docs/provider-packages.md +19 -19
  73. package/docs/provider-primitives.md +4 -4
  74. package/docs/providers/ai-sdk.md +3 -3
  75. package/docs/providers/alibaba.md +5 -5
  76. package/docs/providers/anthropic.md +6 -6
  77. package/docs/providers/azure.md +3 -3
  78. package/docs/providers/bedrock.md +3 -3
  79. package/docs/providers/clinepass.md +3 -3
  80. package/docs/providers/deepseek.md +3 -3
  81. package/docs/providers/google.md +4 -4
  82. package/docs/providers/kimi.md +3 -3
  83. package/docs/providers/neuralwatt.md +8 -8
  84. package/docs/providers/ollama.md +3 -3
  85. package/docs/providers/openai-compatible.md +1 -1
  86. package/docs/providers/openai.md +5 -5
  87. package/docs/providers/opencode-go.md +4 -4
  88. package/docs/providers/openrouter.md +3 -3
  89. package/docs/providers/vertex.md +5 -5
  90. package/docs/providers/xai.md +3 -3
  91. package/docs/providers/zai.md +3 -3
  92. package/docs/public-contracts.md +1 -1
  93. package/docs/rag.md +5 -5
  94. package/docs/release-and-install.md +116 -50
  95. package/docs/runs-and-usage.md +14 -1
  96. package/docs/server.md +90 -1
  97. package/docs/sheets.md +229 -0
  98. package/docs/supervisors.md +9 -1
  99. package/docs/thinking-and-reasoning.md +10 -10
  100. package/docs/tool-conformance.md +27 -2
  101. package/docs/tools.md +29 -2
  102. package/docs/web-tools.md +2 -2
  103. package/docs/wiki.md +24 -10
  104. package/docs/workflow-orchestration-primitives.md +24 -0
  105. package/docs/workflows.md +102 -8
  106. package/docs/working-and-semantic-memory.md +53 -5
  107. package/package.json +10 -30
  108. package/templates/README.md +23 -0
  109. package/templates/deep-research/README.md.tmpl +47 -0
  110. package/templates/deep-research/env.example.tmpl +12 -0
  111. package/templates/deep-research/gitignore.tmpl +7 -0
  112. package/templates/deep-research/manifest.json +12 -0
  113. package/templates/deep-research/package.json.tmpl +23 -0
  114. package/templates/deep-research/src/agent.ts.tmpl +81 -0
  115. package/templates/deep-research/src/index.ts.tmpl +53 -0
  116. package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
  117. package/templates/deep-research/src/tools.ts.tmpl +86 -0
  118. package/templates/deep-research/src/types.ts.tmpl +45 -0
  119. package/templates/deep-research/src/workflow.ts.tmpl +156 -0
  120. package/templates/deep-research/tsconfig.json.tmpl +15 -0
  121. package/templates/init/manifest.json +5 -0
  122. package/templates/init/package.json.tmpl +2 -1
  123. package/templates/init/providers.json +16 -16
@@ -0,0 +1,247 @@
1
+ # Diagramming, draw.io embed client, and mxGraph XML validation (`@arnilo/prism-office/diagrams`)
2
+
3
+ ## What it does
4
+
5
+ The `@arnilo/prism-office/diagrams` package provides an origin-enforced draw.io / diagrams.net iframe embed client, XXE-safe mxGraph XML validation, and byte-stable deterministic XML canonicalization for content hashing and visual artifact workflows in Prism applications and agent runtimes.
6
+
7
+ ### Core Capabilities
8
+
9
+ - **Origin-Enforced Embed Client**: `createDrawioEmbed({ iframe, origin })` establishes a typed, secure postMessage bridge between host applications and embedded draw.io editor iframes adhering to the diagrams.net `proto=json` embed protocol.
10
+ - **Dual Inbound Verification Boundary**: Inbound `message` events are verified against **both** the configured origin and `iframe.contentWindow` prior to JSON parsing. Foreign origins, rogue windows, and malformed frames are dropped immediately at the boundary.
11
+ - **Strict Outbound Target Enforcement**: Prohibits wildcard `targetOrigin: "*"` on all outbound actions. Every postMessage transmits exclusively to the exact validated origin.
12
+ - **No Public SaaS Default**: Construction requires an explicit, validated origin string (`https://` or `http://`). No default fallback to public SaaS endpoints (`embed.diagrams.net`) exists; self-hosting is the documented deployment.
13
+ - **XXE & Billion-Laughs Defenses**: `validateDrawioXml` rejects DOCTYPE and ENTITY declarations up-front (`UNSAFE_XML_DECLARATION_PATTERN = /<!\s*(?:DOCTYPE|ENTITY)/i`) with `ERR_PRISM_DIAGRAMS_XXE`, and operates with XML parser entity and HTML entity expansion disabled under strict element, attribute, and byte caps.
14
+ - **Deterministic XML Canonicalization**: `canonicalizeDrawioXml` sorts element attributes lexicographically (`a-z`), standardizes double quotes and entity escaping, and normalizes insignificant whitespace while preserving document sequence, producing byte-identical outputs for SHA-256 content hashing.
15
+ - **Visio Format Exclusion (P12 Guard)**: Detects and rejects Microsoft Visio binary (`.vsd`) and OpenXML (`.vsdx`) inputs across all entrypoints with `ERR_PRISM_DIAGRAMS_UNSUPPORTED_FORMAT`.
16
+ - **Dependency-Free Telemetry Seam (P15)**: Pluggable `DiagramsTelemetry` interface emits `diagrams.validate` and `diagrams.canonicalize` spans tracking byte sizes, element/cell counts, and durations without leaking diagram contents or node text.
17
+
18
+ ## When to use it
19
+
20
+ Use `@arnilo/prism-office/diagrams` when applications, host workspaces, or autonomous agents need to:
21
+ 1. Embed an interactive, self-hosted draw.io / diagrams.net editor inside a web or Electron iframe with strictly enforced cross-origin security.
22
+ 2. Coordinate diagram editing lifecycles (`init` handshake, `load`, `save`, `autosave`, `merge`, and `export`).
23
+ 3. Execute save-with-preview workflows generating SVG (`xmlsvg`) or PNG (`xmlpng`) visual snapshots from the active editor session.
24
+ 4. Validate untrusted agent-generated or user-uploaded mxGraph XML models against structural and memory boundaries before persistence.
25
+ 5. Compute deterministic content hashes (`sha256(canonicalizeDrawioXml(xml))`) for version control, caching, and change detection.
26
+
27
+ Do **not** use this package for:
28
+ - Microsoft Visio format conversion (`.vsd` / `.vsdx` files are explicitly excluded and rejected per P12).
29
+ - Server-side headless diagram rendering without an editor instance (use headless browser automation or containerized export services).
30
+
31
+ ## Inputs / request
32
+
33
+ ### Primary Functions
34
+
35
+ | Function | Signature | Description |
36
+ | --- | --- | --- |
37
+ | `createDrawioEmbed` | `(options: DrawioEmbedOptions) => DrawioEmbed` | Creates an origin-enforced embed client bound to an iframe element or structural frame. |
38
+ | `validateDrawioXml` | `(xml: string \| Uint8Array, options?: DrawioXmlOptions) => DrawioModelSummary` | Validates mxGraph XML well-formedness, caps, and structure, extracting page/cell/edge metrics. |
39
+ | `canonicalizeDrawioXml` | `(xml: string \| Uint8Array, options?: DrawioCanonicalizeOptions) => string` | Produces byte-stable, attribute-sorted, whitespace-normalized XML for content hashing. |
40
+ | `validateDiagramsOrigin` | `(origin: unknown) => string` | Validates that an origin string is a valid `https:` or `http:` URL origin without paths, queries, hashes, or wildcards. |
41
+ | `assertNotVisio` | `(input: string \| Uint8Array) => void` | Asserts that input is not a Microsoft Visio file, throwing `DiagramsFormatError` if Visio signatures are detected. |
42
+
43
+ ### Message & Options Types
44
+
45
+ ```ts
46
+ export interface DrawioEmbedOptions {
47
+ readonly iframe: DrawioEmbedFrame;
48
+ readonly origin: string;
49
+ readonly messageSource?: DrawioMessageSource;
50
+ readonly onProtocolError?: (error: DiagramsProtocolError) => void;
51
+ readonly defaultExportTimeoutMs?: number;
52
+ }
53
+
54
+ export interface DrawioLoadOptions {
55
+ readonly xml: string;
56
+ readonly autosave?: boolean;
57
+ readonly saveAndExit?: boolean;
58
+ readonly noSaveBtn?: boolean;
59
+ readonly noExitBtn?: boolean;
60
+ readonly title?: string;
61
+ }
62
+
63
+ export interface DrawioExportOptions {
64
+ readonly format: "xml" | "xmlsvg" | "xmlpng" | "json" | "png" | "svg";
65
+ readonly scale?: number;
66
+ readonly border?: number;
67
+ readonly xml?: string;
68
+ readonly embedImages?: boolean;
69
+ readonly timeoutMs?: number;
70
+ }
71
+
72
+ export interface DrawioXmlCaps {
73
+ readonly maxBytes?: number;
74
+ readonly maxElements?: number;
75
+ readonly maxAttributes?: number;
76
+ }
77
+ ```
78
+
79
+ ### Capacity Limits and Defaults
80
+
81
+ | Cap | Default | Hard Ceiling | Description |
82
+ | --- | --- | --- | --- |
83
+ | `maxBytes` | 32 MiB (`33,554,432`) | 512 MiB (`536,870,912`) | Maximum input XML string or byte length. |
84
+ | `maxElements` | 100,000 | 500,000 | Maximum total XML element count in diagram tree. |
85
+ | `maxAttributes` | 500,000 | 2,000,000 | Maximum total XML attribute count across elements. |
86
+ | `defaultExportTimeoutMs` | 30,000 ms | Unlimited | Timeout waiting for editor export responses. |
87
+
88
+ ## Outputs / response / events
89
+
90
+ ### Error Hierarchy
91
+
92
+ All error classes extend `DiagramsError` and carry structured `ERR_PRISM_DIAGRAMS_*` error codes:
93
+
94
+ | Error Class | Code | Cause / Trigger |
95
+ | --- | --- | --- |
96
+ | `DiagramsOriginError` | `ERR_PRISM_DIAGRAMS_ORIGIN_INVALID` | Origin is empty, wildcard (`*`), malformed URL, or contains forbidden path/query/hash components. |
97
+ | `DiagramsProtocolError` | `ERR_PRISM_DIAGRAMS_PROTOCOL` | Inbound message failed JSON parsing, missing event discriminator, or postMessage issued without contentWindow. |
98
+ | `DiagramsXxeError` | `ERR_PRISM_DIAGRAMS_XXE` | XML input contains forbidden DOCTYPE or ENTITY declaration. |
99
+ | `DiagramsCapError` | `ERR_PRISM_DIAGRAMS_XML_CAP` | XML input exceeds byte length, total element count, or total attribute count caps. |
100
+ | `DiagramsXmlMalformedError` | `ERR_PRISM_DIAGRAMS_XML_MALFORMED` | XML input is truncated or violates XML well-formedness rules. |
101
+ | `DiagramsModelInvalidError` | `ERR_PRISM_DIAGRAMS_XML_INVALID_MODEL` | XML root is neither `<mxfile>` nor `<mxGraphModel>`. |
102
+ | `DiagramsFormatError` | `ERR_PRISM_DIAGRAMS_UNSUPPORTED_FORMAT` | Visio format (.vsd/.vsdx) detected in input (P12). |
103
+ | `DiagramsTimeoutError` | `ERR_PRISM_DIAGRAMS_TIMEOUT` | Export operation timed out waiting for editor response. |
104
+
105
+ ### Output Types
106
+
107
+ ```ts
108
+ export interface DrawioModelSummary {
109
+ readonly pages: number;
110
+ readonly cells: number;
111
+ readonly edges: number;
112
+ readonly width?: number;
113
+ readonly height?: number;
114
+ readonly compressed?: boolean;
115
+ }
116
+
117
+ export interface DrawioExportResult {
118
+ readonly format: string;
119
+ readonly data: string;
120
+ readonly xml?: string;
121
+ readonly bounds?: DrawioExportBounds;
122
+ }
123
+ ```
124
+
125
+ ## Request/response example
126
+
127
+ ### Protocol Envelope (`proto=json`)
128
+
129
+ Inbound editor-to-host `message` event:
130
+ ```json
131
+ {
132
+ "event": "save",
133
+ "xml": "<mxfile host=\"drawio.internal\"><diagram id=\"1\">...</diagram></mxfile>",
134
+ "exit": false
135
+ }
136
+ ```
137
+
138
+ Outbound host-to-editor action postMessage:
139
+ ```json
140
+ {
141
+ "action": "load",
142
+ "xml": "<mxfile host=\"drawio.internal\"><diagram id=\"1\">...</diagram></mxfile>",
143
+ "autosave": 1,
144
+ "title": "System Architecture"
145
+ }
146
+ ```
147
+
148
+ ## Implementation example
149
+
150
+ ```ts
151
+ import { createDrawioEmbed, validateDrawioXml, canonicalizeDrawioXml } from "@arnilo/prism-office/diagrams";
152
+
153
+ // 1. Initialize embed client with strict origin binding
154
+ const embed = createDrawioEmbed({
155
+ iframe: document.getElementById("drawio-frame") as HTMLIFrameElement,
156
+ origin: "https://drawio.internal.example",
157
+ onProtocolError(error) {
158
+ console.error("Protocol error:", error.message);
159
+ },
160
+ });
161
+
162
+ // 2. Register typed event listeners
163
+ embed.on("init", () => {
164
+ const initialXml = `<mxfile host="drawio.internal"><diagram id="d1" name="Architecture"><mxGraphModel dx="800" dy="600"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="Core Agent" vertex="1" parent="1"><mxGeometry x="100" y="100" width="120" height="60" as="geometry"/></mxCell></root></mxGraphModel></diagram></mxfile>`;
165
+ embed.load({ xml: initialXml, autosave: true });
166
+ });
167
+
168
+ embed.on("save", async ({ xml, exit }) => {
169
+ // Validate model before persisting
170
+ const summary = validateDrawioXml(xml);
171
+ console.log(`Validated diagram with ${summary.cells} cells and ${summary.edges} edges`);
172
+
173
+ // Compute canonical hash for content-addressed storage
174
+ const canonical = canonicalizeDrawioXml(xml);
175
+ console.log("Canonical XML ready for persistence");
176
+
177
+ if (exit) {
178
+ console.log("Editor exit requested by user");
179
+ }
180
+ });
181
+
182
+ embed.on("autosave", ({ xml }) => {
183
+ console.log("Draft autosaved:", xml.length, "bytes");
184
+ });
185
+
186
+ // 3. Save-with-preview flow: export SVG snapshot
187
+ const preview = await embed.export({ format: "xmlsvg" });
188
+ console.log("Exported preview format:", preview.format, "data:", preview.data.slice(0, 40));
189
+ ```
190
+
191
+ ## Extension and configuration notes
192
+
193
+ ### Self-Hosted draw.io Deployment
194
+
195
+ The recommended and supported deployment is a self-hosted instance of the Apache-2.0 `jgraph/drawio` container:
196
+
197
+ ```bash
198
+ docker run -d -p 8080:8080 -e DRAWIO_SERVER_URL="http://localhost:8080" jgraph/drawio
199
+ ```
200
+
201
+ Iframe embed URLs are formed with query parameters configuring json protocol mode:
202
+ ```text
203
+ http://localhost:8080/?embed=1&proto=json&spin=1
204
+ ```
205
+
206
+ ### Decoupled Structural DOM Interface
207
+
208
+ `DrawioEmbedFrame` is typed structurally:
209
+ ```ts
210
+ export interface DrawioEmbedFrame {
211
+ readonly contentWindow: {
212
+ postMessage(message: unknown, targetOrigin: string): void;
213
+ } | null;
214
+ }
215
+ ```
216
+ This enables use with vanilla DOM elements, React/Svelte/Vue refs, Electron webviews, and headless test doubles without requiring browser globals or `@types/dom`.
217
+
218
+ ### OpenTelemetry Telemetry Seam
219
+
220
+ Pass an optional `DiagramsTelemetry` implementation to record spans without runtime overhead:
221
+ ```ts
222
+ const summary = validateDrawioXml(xml, {
223
+ telemetry: {
224
+ startSpan(name, attributes) {
225
+ // Maps to OTel tracer.startSpan("diagrams.validate", { attributes })
226
+ // Diagram text and labels are NEVER passed to spans.
227
+ return activeSpan;
228
+ },
229
+ },
230
+ });
231
+ ```
232
+
233
+ ## Security and performance notes
234
+
235
+ - **Trust Boundary Placement**: Origin and `event.source` checks execute inside the embed client before JSON parsing. Rogue cross-origin messages and foreign window messages are dropped without triggering listeners or error handlers.
236
+ - **Wildcard Prohibition**: `targetOrigin: "*"` is blocked at construction and runtime. Outbound messages are posted exclusively to the verified origin.
237
+ - **XXE Prevention**: DOCTYPE and ENTITY declarations are rejected up-front by regex pre-checks; `fast-xml-parser` is configured with entity expansion disabled.
238
+ - **Memory Caps**: Progressive limits on byte size, element counts, and attribute counts prevent XML decompression bombs and heap exhaustion.
239
+ - **Single-Pass Performance**: Canonicalization and validation process 1 MB XML models in under 10 ms.
240
+
241
+ ## Related APIs
242
+
243
+ - [`@arnilo/prism-office/documents`](./documents.md): Specification-compliant OpenXML document generation and preview rendering for DOCX, XLSX, and PPTX.
244
+ - [`@arnilo/prism-office/sheets`](./sheets.md): Spreadsheet and CSV parsing engine with strict financial decimal safety guarantees.
245
+ - [`@arnilo/prism-web-tools/browser`](./browser-automation.md): Browser automation tools and quarantine lifecycle.
246
+ - [`@arnilo/prism-ag-ui`](./ag-ui.md): Agent-User Interface projection and timeline components.
247
+ - [`@arnilo/prism-observability-opentelemetry`](./observability.md): OpenTelemetry instrumentation and trace adapters.
@@ -0,0 +1,213 @@
1
+ # Documents, spreadsheets, and presentations (`@arnilo/prism-office/documents`)
2
+
3
+ ## What it does
4
+
5
+ The `@arnilo/prism-office/documents` package provides specification-compliant, AI-native OpenXML document generation, parsing, patching, and bounded preview rendering for Microsoft Word (`.docx`), Microsoft Excel (`.xlsx`), and Microsoft PowerPoint (`.pptx`) artifacts.
6
+
7
+ It operates on a canonical, typed abstract syntax tree (AST) called the **Prism Document Model** (`DocModel`, `SheetModel`, `DeckModel`):
8
+ - **Pure in-memory doctrine**: Functions accept `Uint8Array` container buffers or typed model objects and emit `Uint8Array` buffers or JSON models. Zero filesystem reads, zero network I/O, zero `process.env` lookups, and zero child process spawns.
9
+ - **Draft-07 JSON Schema validation & slicing**: Full runtime structural validation with transitive closure slicing (`getDocumentModelSchema`) allowing LLM tools and agent prompts to extract minimal, self-contained sub-schemas (e.g. `doc.paragraph`, `doc.table`).
10
+ - **Bidirectional round-trip fidelity**: Prism-generated documents parse back into structurally equivalent models verified against a per-kind equality specification.
11
+ - **Typed model patch engine**: Immutably applies `set`, `insert`, `remove`, and `move` operations to document blocks, worksheet cells, and presentation slides with schema re-validation and an interactive `createPatchHistory` undo/redo stack.
12
+ - **Framework-neutral preview blocks & bounded HTML**: Generates structured snapshots (`PreviewBlock[]`) for native desktop/web UI grids and outline trees, as well as safe, sanitize-by-construction HTML fragments (`renderPreviewHtml`) guaranteed to contain no executable scripts, no active pseudo-protocols, and no external hyperlinks.
13
+ - **Boundary text redaction**: Pluggable `SecretRedactor` hook to sanitize extracted text content (paragraphs, cells, notes, tables) at the parse boundary before models are returned.
14
+ - **Dependency-free telemetry seam**: Zero-overhead `DocumentsTelemetry` hook for OpenTelemetry-compatible span tracing without leaking document or chunk text into telemetry collectors.
15
+
16
+ ## When to use it
17
+
18
+ Use `@arnilo/prism-office/documents` whenever autonomous agents, coding assistants, workflow orchestrators, or enterprise applications need to:
19
+ 1. Synthesize professional DOCX reports, financial XLSX spreadsheets, or PPTX presentation decks from structured LLM outputs.
20
+ 2. Ingest existing OOXML artifacts into a structured, validated document model for analysis or automated summarization.
21
+ 3. Perform atomic, validated updates or localized edits to documents using typed patch operations.
22
+ 4. Render safe, bounded HTML previews or framework-neutral outline and grid snapshots in web and desktop hosts.
23
+
24
+ Do **not** use this package for collaborative real-time editing (OT/CRDT), macro execution, or in-memory spreadsheet formula evaluation (formulas are preserved verbatim as `{ formula, cachedValue? }` read-only pairs).
25
+
26
+ ## Inputs / request
27
+
28
+ ### Generation & Parsing Functions
29
+
30
+ | Function | Signature | Description |
31
+ | --- | --- | --- |
32
+ | `generateDocument` | `(model: DocumentModel, options: GenerateDocumentOptions) => Promise<GenerateDocumentResult>` | Translates a typed model into spec-compliant OOXML binary bytes (PK zip container) with a SHA-256 content hash. |
33
+ | `parseDocument` | `(bytes: Uint8Array, options: ParseDocumentOptions) => Promise<DocumentModel>` | Verifies PK zip signature, enforces caps, translates OOXML parts, applies optional redaction, and returns a validated model. |
34
+ | `patchDocument` | `(model: DocumentModel, patches: readonly DocumentPatch[], options?: PatchDocumentOptions) => DocumentModel` | Clones the model, applies typed structural patch operations, and validates the resulting model against Draft-07 schemas. |
35
+ | `createPatchHistory` | `(initialModel: DocumentModel) => PatchHistory` | Creates an interactive undo/redo history manager for host editing workflows. |
36
+ | `renderPreviewBlocks` | `(model: DocumentModel, options?: PreviewBlocksOptions) => PreviewBlock[]` | Emits framework-neutral structured blocks (document outlines, bounded sheet grid chunks, slide summaries). |
37
+ | `renderPreviewHtml` | `(model: DocumentModel, options?: PreviewHtmlOptions) => string` | Emits safe, bounded HTML fragments with all entities escaped and external URLs neutralized. |
38
+ | `getDocumentModelSchema`| `(options: GetDocumentModelSchemaOptions) => Record<string, unknown>` | Retrieves full Draft-07 JSON Schema or a self-contained sliced sub-schema with resolved `$defs`. |
39
+ | `validateDocumentModel`| `(model: unknown) => asserts model is DocumentModel` | Validates arbitrary JSON objects against Draft-07 document schemas and structural invariants. |
40
+
41
+ ### Capacity Limits and Defaults
42
+
43
+ Caps are strictly enforced in memory before compute-intensive translation or parsing:
44
+
45
+ | Cap | Default | Hard Ceiling | Target |
46
+ | --- | --- | --- | --- |
47
+ | `maxBytes` | 32 MiB (`33,554,432`) | 512 MiB (`536,870,912`) | Binary input buffer & generated OOXML bytes |
48
+ | `maxBlocks` | 10,000 | 50,000 | Total blocks in a `DocModel` |
49
+ | `maxSheets` | 50 | 250 | Worksheets in a `SheetModel` |
50
+ | `maxRows` | 100,000 | 1,000,000 | Rows per worksheet |
51
+ | `maxColumns` | 1,000 | 16,384 | Columns per worksheet |
52
+ | `maxCells` | 1,000,000 | 10,000,000 | Total cells across all worksheets |
53
+ | `maxSlides` | 500 | 2,000 | Total slides in a `DeckModel` |
54
+ | `maxParagraphs` | 10,000 | 50,000 | Total paragraphs in a document |
55
+ | `maxRuns` | 50,000 | 250,000 | Total formatted text runs in a document |
56
+
57
+ ## Outputs / response / events
58
+
59
+ ### Error Hierarchy
60
+
61
+ All package operations throw typed exceptions derived from `DocumentsError`:
62
+
63
+ | Error Class | Error Code | Trigger Condition |
64
+ | --- | --- | --- |
65
+ | `DocumentsValidationError` | `ERR_PRISM_DOCUMENTS_INVALID_MODEL` | Input JSON fails Draft-07 schema validation, has dimension mismatches, or invalid decimal string syntax. |
66
+ | `DocumentsCapExceededError` | `ERR_PRISM_DOCUMENTS_CAP_EXCEEDED` | Document exceeds byte size, block count, cell count, or slide count caps. |
67
+ | `DocumentsParseError` | `ERR_PRISM_DOCUMENTS_PARSE_FAILED` | Input buffer lacks PK zip signature, is corrupted, or fails OOXML part parsing. |
68
+ | `DocumentsFormatError` | `ERR_PRISM_DOCUMENTS_UNSUPPORTED_FORMAT` | Format mismatch (e.g. attempting to generate PPTX from a `DocModel`). |
69
+ | `DocumentsPatchError` | `ERR_PRISM_DOCUMENTS_PATCH_FAILED` | Out-of-bounds index target, unknown patch operation, or invalid patch structure. |
70
+
71
+ ## Request/response example
72
+
73
+ ### JSON Schema Document Models
74
+
75
+ ```json
76
+ {
77
+ "kind": "sheet",
78
+ "modelVersion": 1,
79
+ "title": "Q3 Financial Summary",
80
+ "sheets": [
81
+ {
82
+ "name": "Revenue",
83
+ "columnWidths": [{ "column": 0, "width": 25 }, { "column": 1, "width": 15 }],
84
+ "frozenPanes": { "rows": 1, "columns": 0 },
85
+ "cells": [
86
+ ["Department", "Operating Budget", "Actual Expense"],
87
+ ["Engineering", { "type": "decimal", "value": "1500000.00" }, { "type": "decimal", "value": "1420000.50" }],
88
+ ["Operations", { "type": "decimal", "value": "450000.00" }, { "type": "decimal", "value": "435000.00" }],
89
+ ["Total", { "formula": "=SUM(B2:B3)", "cachedValue": 1950000 }, { "formula": "=SUM(C2:C3)", "cachedValue": 1855000.5 }]
90
+ ]
91
+ }
92
+ ]
93
+ }
94
+ ```
95
+
96
+ ## Implementation example
97
+
98
+ ```ts
99
+ import {
100
+ generateDocument,
101
+ parseDocument,
102
+ patchDocument,
103
+ createPatchHistory,
104
+ renderPreviewBlocks,
105
+ renderPreviewHtml,
106
+ type DocModel,
107
+ } from "@arnilo/prism-office/documents";
108
+
109
+ // 1. Define typed document model
110
+ const doc: DocModel = {
111
+ kind: "doc",
112
+ modelVersion: 1,
113
+ title: "Architecture Review",
114
+ blocks: [
115
+ { type: "heading", level: 1, text: "System Architecture" },
116
+ {
117
+ type: "paragraph",
118
+ runs: [
119
+ { text: "Prism operates purely in memory with ", bold: false },
120
+ { text: "zero-trust security boundaries.", bold: true, italic: true },
121
+ ],
122
+ },
123
+ {
124
+ type: "table",
125
+ rows: 2,
126
+ columns: 2,
127
+ cells: [
128
+ ["Module", "Latency"],
129
+ ["Parser", "12ms"],
130
+ ],
131
+ },
132
+ ],
133
+ };
134
+
135
+ // 2. Generate in-memory DOCX binary with SHA-256 contentHash
136
+ const { bytes, contentHash } = await generateDocument(doc, { format: "docx" });
137
+ console.log(`Generated DOCX (${bytes.byteLength} bytes, SHA-256: ${contentHash})`);
138
+
139
+ // 3. Parse OOXML bytes back to a validated model
140
+ const parsed = await parseDocument(bytes, { kind: "doc" });
141
+
142
+ // 4. Apply typed model patches
143
+ const patched = patchDocument(parsed, [
144
+ { op: "set", target: { block: 0 }, block: { type: "heading", level: 1, text: "Executive Summary" } },
145
+ { op: "insert", target: { afterBlock: 0 }, block: { type: "paragraph", text: "New introduction." } },
146
+ ]);
147
+
148
+ // 5. Interactive Undo/Redo editing
149
+ const history = createPatchHistory(patched);
150
+ history.apply([{ op: "set", target: { title: true }, value: "Updated Review" }]);
151
+ console.log(history.canUndo()); // true
152
+ const restored = history.undo(); // restored to "Executive Summary" state
153
+
154
+ // 6. Generate structured preview blocks & safe HTML
155
+ const blocks = renderPreviewBlocks(restored);
156
+ const htmlSnippet = renderPreviewHtml(restored, { maxHtmlBytes: 256 * 1024 });
157
+ ```
158
+
159
+ ## Extension and configuration notes
160
+
161
+ ### Sub-package Pinning
162
+ To avoid pulling in CLI frameworks or extraneous dependencies, `@arnilo/prism-office/documents` directly pins the exact underlying modular packages:
163
+ - `@office-open/docx@0.12.3`
164
+ - `@office-open/xlsx@0.12.3`
165
+ - `@office-open/pptx@0.12.3`
166
+
167
+ ### Draft-07 JSON Schema Slicing
168
+ For AI agent tool generation where token budgets are constrained, `getDocumentModelSchema` provides closure slicing:
169
+ ```ts
170
+ // Returns only TableBlock, CellValue, and their transitively required definitions in $defs
171
+ const tableSchema = getDocumentModelSchema({ kind: "doc", slice: "table" });
172
+ ```
173
+
174
+ ### Text Redaction Hook (`SecretRedactor`)
175
+ When parsing untrusted or sensitive OOXML containers, hosts can inject a redaction hook to scrub PII or secrets before the document model enters memory:
176
+ ```ts
177
+ const sanitizedModel = await parseDocument(rawBytes, {
178
+ kind: "doc",
179
+ redactor: {
180
+ redact: (text: string) => text.replace(/\b\d{3}-\d{2}-\d{4}\b/g, "[REDACTED-SSN]"),
181
+ },
182
+ });
183
+ ```
184
+
185
+ ### Telemetry Seam
186
+ The dependency-free `DocumentsTelemetry` seam allows optional OpenTelemetry instrumentation without adding runtime telemetry dependencies:
187
+ ```ts
188
+ const telemetry: DocumentsTelemetry = {
189
+ startSpan(name, attributes) {
190
+ // Maps to tracer.startSpan with allow-listed metadata (kind, format, bytes, counts)
191
+ // Model content and document text are NEVER passed to telemetry spans.
192
+ return activeSpan;
193
+ },
194
+ };
195
+ ```
196
+
197
+ ### Decimal Fidelity Ceiling
198
+ Financial worksheets often require exact decimal representations that JavaScript 64-bit binary floating-point numbers cannot represent without precision loss. `@arnilo/prism-office/documents` supports canonical string decimals (`{ type: "decimal", value: "1500000.00" }`), preserving exact numerical formatting without IEEE 754 precision artifacts.
199
+
200
+ ## Security and performance notes
201
+
202
+ - **Pure In-Memory Operation**: No temporary files, no shell execution, no binary spawning, and zero network sockets.
203
+ - **ZIP Signature Gating**: Buffers must begin with PK zip container signatures (`0x50, 0x4B, 0x03, 0x04`). Extension-based type inference is strictly prohibited.
204
+ - **Fail-Closed Caps**: Input size and element count caps are evaluated before entering XML translation passes, preventing zip-bomb and decompression amplification attacks.
205
+ - **Sanitize-by-Construction HTML**: `renderPreviewHtml` strictly entity-encodes all text fields, neutralizes dangerous protocols (`javascript:`, `http://`, `https://`), strips raw script/image tags, and caps output size to prevent DOM-based XSS and memory exhaustion.
206
+ - **Performance Budget**: Warm generation of 200-block documents completes in under 15 ms; parse and round-trip equality checks complete in under 100 ms.
207
+
208
+ ## Related APIs
209
+
210
+ - [`@arnilo/prism-document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
211
+ - [`@arnilo/prism-work-tools`](./work-tools.md): Microsoft 365 and Google Workspace identity-scoped connectors.
212
+ - [`@arnilo/prism-coding-agent`](./coding-agent-tools.md): Coding tools and file operations.
213
+ - [`@arnilo/prism-observability-opentelemetry`](./observability.md): OpenTelemetry instrumentation and trace adapters.
@@ -19,6 +19,7 @@ Use this package when a host needs offline quality checks or sampled live scorin
19
19
  | `createMemoryEvaluationStore` | optional seed records |
20
20
  | `appendEvaluationFeedback` | `RunFeedbackStore`, `EvaluationStore`, feedback fields, and 1–64 known evaluation IDs |
21
21
  | `createPersistenceTraceResolver` | explicit `ProductionPersistenceStore`, exact session/run/ownership, page/byte bounds |
22
+ | `datasetFromRuns` | `runIds` and/or `sessionIds`, existing dataset, `ProductionPersistenceStore`, ownership, redactor/secrets, optional `toItem` |
22
23
  | `createModelJudge` | host judge callback, stable rubric/version, timeout/attempt/output bounds |
23
24
  | `runComparison` | immutable dataset, 2–8 named candidates by default, pairwise scorers |
24
25
  | `assertEvaluationThreshold` / `serializeEvaluationReport` | mean/failure/per-scorer gates and bounded redacted JSON |
@@ -32,6 +33,7 @@ Use this package when a host needs offline quality checks or sampled live scorin
32
33
  | `runExperiment` | `ExperimentReport` with stable item order, evaluations, and aggregates |
33
34
  | `EvaluationStore.query` | cursor-paginated, ownership-filtered page |
34
35
  | `appendEvaluationFeedback` | immutable `RunFeedbackRecord` containing only evaluation/scorer IDs |
36
+ | `datasetFromRuns` | `{ dataset, version, added, skipped }` — new immutable dataset version with one item per added run; skips carry reasons (missing run, ownership mismatch, empty output) |
35
37
 
36
38
  ## Request/response example
37
39
 
@@ -121,6 +123,7 @@ console.log(report.aggregate.meanScore, linked.evaluationIds);
121
123
  - Model judges are host callbacks, not providers: Prism passes rubric/version plus bounded target only—never credential resolvers, tools, or workspace. Defaults are one attempt, 30 seconds, and 16 KiB output; failures become redacted evaluation records.
122
124
  - Pairwise candidates are sorted by name, executed once per item, compared in stable item/pair/scorer order, and record ties/failures without choosing a winner. Candidate and scorer outputs have byte caps.
123
125
  - `assertEvaluationThreshold()` throws `ERR_PRISM_EVAL_THRESHOLD`; an uncaught error gives CI a non-zero exit. Keep model-judge/live gates credential-gated and outside the network-free default suite. `serializeEvaluationReport()` bounds/redacts checked-in artifacts.
126
+ - `datasetFromRuns` redacts before item construction and never stores an unredactable item; curated items are byte-capped (`ERR_PRISM_EVAL_CURATE`), ownership is verified exactly per run, and a failed append leaves the prior dataset version untouched.
124
127
 
125
128
  ## Trace, judge, comparison, and CI example
126
129
 
@@ -137,12 +140,43 @@ assertEvaluationThreshold(report, { minimumMean: 0.9, maximumFailures: 0 });
137
140
 
138
141
  `traceResolver` is explicit; no arbitrary run search occurs. `baseline`/`candidate` are host functions returning `AgentRunResult`. See `examples/evaluation-gate.ts` for a network-free gate and `examples/coding-browser-evaluation.ts` for coding/browser adversarial fixtures.
139
142
 
143
+ ## Curating datasets from production runs
144
+
145
+ Plan 043 adds `datasetFromRuns`: it turns recorded runs (production incident transcripts included) into dataset items in one call — resolve through `createPersistenceTraceResolver`, redact, map through an optional host `toItem`, and append as a **new immutable dataset version**. The prior version object is never mutated.
146
+
147
+ ```ts
148
+ import { datasetFromRuns, defineDataset } from "@arnilo/prism-evals";
149
+
150
+ const result = await datasetFromRuns({
151
+ runIds: ["run_9f2", "run_a71"],
152
+ dataset: defineDataset({ id: "support-regressions", items: [] }),
153
+ store: persistence,
154
+ ownership: { tenantId: "t1", userId: "u1" },
155
+ redactor,
156
+ toItem: (run) => ({
157
+ input: run.input,
158
+ expected: run.feedback?.metadata?.expected, // human-graded gold from the feedback seam
159
+ metadata: { graded: run.feedback?.rating },
160
+ }),
161
+ });
162
+ // result.added === 2, result.dataset.version === "2"
163
+ ```
164
+
165
+ Omit `toItem` and the default mapping is used: `input` = first user message, `expected` = the recorded feedback's `metadata.expected` when present, `output` = final assistant text under `metadata.output`.
166
+
167
+ - Session ids (`sessionIds`) expand to every run recorded under the session; bare `runIds` are located by one ownership-bounded scan of the run ledger (page/byte caps apply).
168
+ - Each resolved run maps to one item keyed by the run id. The default `toItem` carries the first user message as `input`; `expected` comes **only from the feedback seam** (`metadata.expected` of the latest human-graded `RunFeedbackRecord`) — never re-derived from untrusted outputs, and omitted entirely (not fabricated) when a run has no feedback. The recorded output rides `metadata.output` for provenance. A host `toItem` always wins and may return `undefined` to drop a run (`host filter` skip).
169
+ - Feedback costs one bounded, owner-scoped query per curation batch (`store.feedback`); records are read id-only per the feedback linkage contract — scorer payloads are never copied. A feedback query failure (e.g. scope contract mismatch) omits `expected` instead of aborting the batch.
170
+ - Every item field passes the host `redactor` after host mapping — fail closed: a redactor failure or an item over the frozen 4 MiB cap (`ERR_PRISM_EVAL_CURATE`) skips the run or aborts the append before anything is persisted. Cross-tenant runs are never readable (resolver ownership check → `ownership mismatch` skip).
171
+
172
+ Prompt versions can ride the same primitives: [`assertPromptPromotion`](prompt-registry.md#eval-gated-promotion) in `@arnilo/prism-prompts` resolves two prompt versions, runs them through `runComparison`, and returns a `promote`/`hold` verdict with per-scorer aggregates and a bounded report — never applying the change itself.
173
+
140
174
  ## Coding and browser adversarial evaluations (0.0.9)
141
175
 
142
176
  Release 0.0.9 ships curated network-free adversarial fixtures in package tests:
143
177
 
144
178
  - `@arnilo/prism-coding-agent` `eval-fixtures.test.ts`: safe native list vs shell, Git path/ref injection, dirty-tree rollback, unknown named-check failure, PR-handoff artifact completeness, and prompt-injection file content under read-only tools.
145
- - `@arnilo/prism-browser` `eval-fixtures.test.ts`: stale snapshot refs, side-effect approval, private/loopback/file deny, upload/download/screenshot policy, CSS/evaluate target rejection, and hostile accessible-name text.
179
+ - `browser` `eval-fixtures.test.ts`: stale snapshot refs, side-effect approval, private/loopback/file deny, upload/download/screenshot policy, CSS/evaluate target rejection, and hostile accessible-name text.
146
180
 
147
181
  Fixtures reuse `@arnilo/prism-evals` (`defineDataset` / `defineScorer` / `scoreRun` / `assertEvaluationThreshold` / `serializeEvaluationReport`). Optional SWE-bench-compatible or live-browser harnesses remain host adapters — they are not default dependencies or quality claims. Protected real Docker/Playwright gates stay env-gated (`PRISM_TEST_DOCKER_SANDBOX`, `PRISM_LIVE_PLAYWRIGHT`) and never enter `sdk:ready`.
148
182
 
@@ -168,6 +168,48 @@ await agent.createSession().run("Use the Acme extension.", { activeSkills: ["acm
168
168
  - Middleware from `api.use()` runs only when the host passes `kernel.middleware` into runtime configuration.
169
169
  - Provider packages, provider request policies, system prompt contributions, instruction injectors, builders, strategies, commands, store factories, resource loaders, settings providers, and credential resolvers are all inert until host code selects or invokes them.
170
170
 
171
+ ### Host driver hooks (opt-in)
172
+
173
+ A contributed command can act — start a session run, start a workflow, steer
174
+ an active run — only when the **host** injects driver capabilities into the
175
+ execution context. Drivers are never package-supplied: a command that wants
176
+ them guards on `context.drivers` and degrades gracefully when the host
177
+ supplies none. Commands stay inert data in hosts without drivers, and the
178
+ context shape is unchanged (no `drivers` key at all).
179
+
180
+ ```ts
181
+ // Host opt-in (e.g. RPC session factory):
182
+ await runRpcServer({
183
+ stdin,
184
+ stdout,
185
+ createSession,
186
+ commands,
187
+ drivers: {
188
+ startRun: (input, options) => session.run(input, options),
189
+ startWorkflow: (workflow, input, options) => runWorkflow(workflow, input, options),
190
+ steer: (runId, input) => session.steer(runId, input),
191
+ },
192
+ });
193
+
194
+ // Contributed command (host-opt-in capability use):
195
+ registerCommand({
196
+ name: "acme.start",
197
+ async execute(args, context) {
198
+ if (!context.drivers?.startWorkflow) {
199
+ return { name: "acme.start", error: { message: "host did not supply workflow drivers" } };
200
+ }
201
+ const run = await context.drivers.startWorkflow(workflowFor(args), args.input);
202
+ return { name: "acme.start", value: { runId: run.runId, status: run.status } };
203
+ },
204
+ });
205
+ ```
206
+
207
+ `CommandDrivers` is typed (`startRun` / `startWorkflow` / `steer`) and exported
208
+ from the core contracts surface. Driver errors surface through the command's
209
+ normal error path — commands map failures to `CommandResult.error`
210
+ (`ErrorInfo`) or let the host error envelope carry them. Driver presence does
211
+ not affect command `metadata.trust` labeling.
212
+
171
213
  ## Security and performance notes
172
214
 
173
215
  - Prism does not sandbox extension code. Hosts should load only trusted packages or run untrusted packages in their own sandbox/process before calling Prism APIs.
package/docs/graft.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-graft` is an optional package that wires [nanonets/graft](https://github.com/nanonets/graft) — a repository context-graph CLI (`graft/` directory, INDEX.md orientation, symbol-level wiring graph) — into Prism contribution contracts.
5
+ `@arnilo/prism-memory/graft` is an optional subpath that wires [nanonets/graft](https://github.com/nanonets/graft) — a repository context-graph CLI (`graft/` directory, INDEX.md orientation, symbol-level wiring graph) — into Prism contribution contracts.
6
6
 
7
7
  It registers six pull tools backed by the graft CLI (`--json`, argv-safe), a push-mode retrieval-pack context provider plus first-turn orientation injector carried on the `graft` skill, commands (`graft`, `graft-build`, `graft-check`, `graft-viz`), and an edit-watch middleware that computes blast radius after mutating tool calls. Import is inert; a missing graft CLI fails closed at `setup` with a bounded redacted error.
8
8
 
@@ -74,7 +74,7 @@ Tool call (pull):
74
74
  Status event:
75
75
 
76
76
  ```json
77
- { "type": "graft:status", "extension": "@arnilo/prism-graft", "metadata": { "fresh": true, "missing": 0, "stale": 2 } }
77
+ { "type": "graft:status", "extension": "@arnilo/prism-memory/graft", "metadata": { "fresh": true, "missing": 0, "stale": 2 } }
78
78
  ```
79
79
 
80
80
  ## Implementation example
@@ -83,7 +83,7 @@ See [`examples/graft-extension.ts`](../examples/graft-extension.ts) — network-
83
83
 
84
84
  ```ts
85
85
  import { createExtensionKernel, createMemorySessionStore } from "@arnilo/prism";
86
- import { createGraftExtension } from "@arnilo/prism-graft";
86
+ import { createGraftExtension } from "@arnilo/prism-memory/graft";
87
87
 
88
88
  const store = createMemorySessionStore();
89
89
  const kernel = createExtensionKernel({ errorPolicy: "throw" });
@@ -78,7 +78,7 @@ Guardrails are callbacks supplied by the host. Prism does not discover, load, re
78
78
 
79
79
  Optional `@arnilo/prism-policy` can record guardrail outcomes via `recordGuardrailDecision` (evidence refs only; see [Policy and audit](policy-and-audit.md)).
80
80
 
81
- Output buffering prevents blocked provider content from reaching subscribers, session entries, ledgers, parsers, delegation, or tools. Tool-output checks receive raw results but Prism discards blocked raw output before event, ledger, transcript, or MCP exposure. Redaction replaces exact known values only; it is not general secret detection. Parallel checks receive an abort signal, but callback code must honor it to stop in-flight work. Browser snapshots and page text from `@arnilo/prism-browser` are untrusted external content: never allow them to modify tools, permissions, credentials, or policy. Browser mutations still require host `ExecutionPolicy`/approval; prompt-injection text in a page cannot grant upload/download release.
81
+ Output buffering prevents blocked provider content from reaching subscribers, session entries, ledgers, parsers, delegation, or tools. Tool-output checks receive raw results but Prism discards blocked raw output before event, ledger, transcript, or MCP exposure. Redaction replaces exact known values only; it is not general secret detection. Parallel checks receive an abort signal, but callback code must honor it to stop in-flight work. Browser snapshots and page text from the `browser` subpath are untrusted external content: never allow them to modify tools, permissions, credentials, or policy. Browser mutations still require host `ExecutionPolicy`/approval; prompt-injection text in a page cannot grant upload/download release.
82
82
 
83
83
  ## Related APIs
84
84