@arnilo/prism 0.3.2 → 0.5.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 +50 -1
- package/README.md +42 -62
- package/dist/agent-run-lifecycle.js +4 -0
- package/dist/agent-run-state.d.ts +5 -2
- package/dist/agent-run-state.js +18 -8
- package/dist/agent-session/session/assemble.d.ts +6 -0
- package/dist/agent-session/session/assemble.js +391 -0
- package/dist/agent-session/session/persist.d.ts +28 -0
- package/dist/agent-session/session/persist.js +166 -0
- package/dist/agent-session/session/provider-round.d.ts +6 -0
- package/dist/agent-session/session/provider-round.js +231 -0
- package/dist/agent-session/session/tool-round.d.ts +31 -0
- package/dist/agent-session/session/tool-round.js +473 -0
- package/dist/agent-session/session/types.d.ts +115 -0
- package/dist/agent-session/session/types.js +5 -0
- package/dist/agent-session/session.d.ts +54 -41
- package/dist/agent-session/session.js +23 -1132
- package/dist/capture.d.ts +63 -0
- package/dist/capture.js +67 -0
- package/dist/cli-dev.d.ts +29 -0
- package/dist/cli-dev.js +52 -0
- package/dist/cli-init.d.ts +34 -3
- package/dist/cli-init.js +192 -24
- package/dist/cli-runner.d.ts +6 -2
- package/dist/cli-runner.js +57 -10
- package/dist/content.d.ts +3 -3
- package/dist/content.js +3 -1
- package/dist/contracts-core/agent.d.ts +8 -0
- package/dist/contracts-core/batch.d.ts +97 -0
- package/dist/contracts-core/batch.js +65 -0
- package/dist/contracts-core/content.d.ts +72 -1
- package/dist/contracts-core/embeddings.d.ts +30 -0
- package/dist/contracts-core/embeddings.js +17 -0
- package/dist/contracts-core/images.d.ts +60 -0
- package/dist/contracts-core/images.js +17 -0
- package/dist/contracts-core/moderation.d.ts +46 -0
- package/dist/contracts-core/moderation.js +34 -0
- package/dist/contracts-core/speech.d.ts +39 -0
- package/dist/contracts-core/speech.js +17 -0
- package/dist/contracts-core/transcription.d.ts +48 -0
- package/dist/contracts-core/transcription.js +17 -0
- package/dist/contracts-core/video.d.ts +61 -0
- package/dist/contracts-core/video.js +17 -0
- package/dist/contracts-core.d.ts +7 -0
- package/dist/contracts-core.js +7 -0
- package/dist/contracts-protocol.d.ts +18 -0
- package/dist/contracts-run-state.d.ts +1 -2
- package/dist/index.d.ts +7 -3
- package/dist/index.js +5 -3
- package/dist/input.d.ts +8 -0
- package/dist/input.js +4 -0
- package/dist/node/agent-definitions.d.ts +1 -8
- package/dist/node/agent-definitions.js +0 -34
- package/dist/node/settings.d.ts +0 -1
- package/dist/node/settings.js +0 -5
- package/dist/pinned-fetch.js +29 -3
- package/dist/provider-events.js +3 -4
- package/dist/providers/media.d.ts +1 -2
- package/dist/providers/media.js +1 -4
- package/dist/rpc.d.ts +1 -1
- package/dist/rpc.js +4 -4
- package/dist/testing/persistence-schema.d.ts +1 -1
- package/dist/testing/persistence-schema.js +32 -28
- package/dist/testing/provider-conformance.d.ts +114 -5
- package/dist/testing/provider-conformance.js +342 -0
- package/dist/testing/tool-conformance.d.ts +25 -0
- package/dist/testing/tool-conformance.js +128 -1
- package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
- package/dist/testing/tool-effect-store-conformance.js +0 -3
- package/dist/thinking.d.ts +48 -9
- package/dist/thinking.js +134 -8
- package/dist/tool-search.d.ts +76 -0
- package/dist/tool-search.js +199 -0
- package/docs/0.1.0-readiness.md +3 -3
- package/docs/a2a.md +2 -2
- package/docs/acp-agent.md +1 -1
- package/docs/acp.md +3 -3
- package/docs/ag-ui-adoption.md +1 -1
- package/docs/ag-ui.md +1 -2
- package/docs/agent-definitions.md +1 -1
- package/docs/agent-events.md +5 -5
- package/docs/agent-identity.md +13 -2
- package/docs/audit-export.md +3 -3
- package/docs/batch-jobs.md +120 -0
- package/docs/browser-automation.md +5 -5
- package/docs/caveman.md +2 -2
- package/docs/cli-rpc.md +43 -9
- package/docs/coding-agent-tools.md +19 -19
- package/docs/coding-review-and-diagnostics.md +2 -2
- package/docs/coding-security.md +5 -5
- package/docs/coding-tools.md +82 -0
- package/docs/coding-workspaces.md +2 -2
- package/docs/compaction-and-retry.md +2 -2
- package/docs/compaction-llm.md +4 -4
- package/docs/compaction-observational-memory.md +3 -3
- package/docs/computer-use-linux.md +13 -2
- package/docs/context-and-skills.md +3 -1
- package/docs/conversations.md +4 -4
- package/docs/core.md +85 -0
- package/docs/credential-storage.md +12 -8
- package/docs/credentials-and-redaction.md +1 -1
- package/docs/data-classification.md +1 -1
- package/docs/database-persistence.md +7 -3
- package/docs/dev-inspector.md +103 -0
- package/docs/device-adapters.md +2 -2
- package/docs/diagrams.md +247 -0
- package/docs/document-reader.md +6 -6
- package/docs/documents.md +214 -0
- package/docs/embeddings.md +112 -0
- package/docs/enterprise-postgres-state.md +7 -7
- package/docs/evaluations.md +41 -7
- package/docs/extensions.md +3 -3
- package/docs/forge-integration.md +3 -3
- package/docs/graft.md +5 -5
- package/docs/guardrails.md +2 -2
- package/docs/host-security.md +16 -15
- package/docs/image-generation.md +129 -0
- package/docs/impeccable.md +7 -5
- package/docs/index.md +84 -46
- package/docs/indexed-code-search.md +2 -2
- package/docs/language-intelligence.md +4 -4
- package/docs/live-testing.md +126 -0
- package/docs/mcp-tools.md +44 -13
- package/docs/middleware-hooks.md +1 -1
- package/docs/migrate-to-0.4.md +312 -0
- package/docs/migrate-to-0.5.md +122 -0
- package/docs/migration.md +51 -1
- package/docs/model-registry.md +38 -0
- package/docs/model-routing.md +6 -6
- package/docs/moderation.md +117 -0
- package/docs/multi-agent-patterns.md +177 -0
- package/docs/multimodal-content.md +27 -3
- package/docs/obscura.md +12 -12
- package/docs/observability.md +32 -7
- package/docs/openapi-tools.md +14 -4
- package/docs/operations.md +11 -0
- package/docs/performance.md +30 -10
- package/docs/persistence-credentials-multimodality-primitives.md +7 -7
- package/docs/policy-and-audit.md +18 -8
- package/docs/ponytail.md +3 -3
- package/docs/postgres-persistence.md +5 -5
- package/docs/process-sessions.md +2 -2
- package/docs/prompt-registry.md +106 -0
- package/docs/provider-caching.md +36 -32
- package/docs/provider-conformance.md +24 -2
- package/docs/provider-packages.md +58 -22
- package/docs/provider-primitives.md +5 -5
- package/docs/provider-request-policies.md +1 -1
- package/docs/providers/ai-sdk.md +18 -6
- package/docs/providers/alibaba.md +10 -6
- package/docs/providers/anthropic.md +10 -6
- package/docs/providers/azure.md +20 -4
- package/docs/providers/bedrock.md +18 -3
- package/docs/providers/clinepass.md +7 -3
- package/docs/providers/commandcode.md +253 -0
- package/docs/providers/deepseek.md +7 -3
- package/docs/providers/google.md +8 -4
- package/docs/providers/hyper.md +284 -0
- package/docs/providers/kimi.md +7 -3
- package/docs/providers/neuralwatt.md +12 -8
- package/docs/providers/ollama.md +18 -3
- package/docs/providers/openai-compatible.md +5 -1
- package/docs/providers/openai.md +9 -5
- package/docs/providers/opencode-go.md +8 -4
- package/docs/providers/openrouter.md +8 -4
- package/docs/providers/vertex.md +21 -5
- package/docs/providers/xai.md +7 -3
- package/docs/providers/zai.md +7 -3
- package/docs/rag.md +31 -9
- package/docs/release-and-install.md +181 -76
- package/docs/resource-loading.md +1 -1
- package/docs/runs-and-usage.md +28 -3
- package/docs/server.md +94 -5
- package/docs/settings-auth-trust-security.md +7 -5
- package/docs/sheets.md +229 -0
- package/docs/speech.md +126 -0
- package/docs/sqlite-persistence.md +4 -4
- package/docs/supervisors.md +4 -3
- package/docs/thinking-and-reasoning.md +93 -60
- package/docs/tool-conformance.md +28 -3
- package/docs/tool-execution-primitives.md +8 -8
- package/docs/tools.md +32 -5
- package/docs/web-tools.md +3 -3
- package/docs/wiki.md +7 -7
- package/docs/work-artifacts-and-review.md +17 -6
- package/docs/work-connectors.md +4 -4
- package/docs/work-tools.md +5 -5
- package/docs/workflow-orchestration-primitives.md +35 -11
- package/docs/workflows.md +74 -13
- package/docs/working-and-semantic-memory.md +53 -5
- package/package.json +14 -31
- 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 +40 -24
- package/docs/antigravity-agent.md +0 -207
package/docs/core.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Core Runtime, Sessions, and Governance (@arnilo/prism-core)
|
|
2
|
+
|
|
3
|
+
The `@arnilo/prism-core` family package unifies Prism's privileged runtime, sessions, governance, credentials, enterprise persistence, and work integrations into explicit, import-isolated subpaths.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @arnilo/prism @arnilo/prism-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For database persistence and distributed event streams, install the required optional peer dependencies:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# SQLite sessions & prompt storage
|
|
15
|
+
npm install better-sqlite3
|
|
16
|
+
|
|
17
|
+
# PostgreSQL sessions, enterprise persistence & prompt storage
|
|
18
|
+
npm install pg
|
|
19
|
+
|
|
20
|
+
# NATS JetStream distributed event source
|
|
21
|
+
npm install @nats-io/jetstream @nats-io/transport-node
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Subpaths Map
|
|
25
|
+
|
|
26
|
+
| Subpath | Description | Optional Peers |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `@arnilo/prism-core/runtime/server` | HTTP server handler, SSE streaming, artifact delivery, replay, webhook delivery | — |
|
|
29
|
+
| `@arnilo/prism-core/runtime/supervisor` | Agent-to-Agent (A2A) protocol server, client, event source, and multi-agent supervisor | — |
|
|
30
|
+
| `@arnilo/prism-core/runtime/workflows` | Multi-step DAG workflow coordinator, saga recovery, checkpoints, and loop nodes | — |
|
|
31
|
+
| `@arnilo/prism-core/sessions/codecs` | Checkpoint, cursor, feedback, and search serialization codecs | — |
|
|
32
|
+
| `@arnilo/prism-core/sessions/sqlite` | SQLite session store, leases, lifecycle, and schema migrations | `better-sqlite3` |
|
|
33
|
+
| `@arnilo/prism-core/sessions/postgres` | PostgreSQL session store, event source, and migrations | `pg` |
|
|
34
|
+
| `@arnilo/prism-core/sessions/nats` | NATS JetStream distributed event source | `@nats-io/jetstream`, `@nats-io/transport-node` |
|
|
35
|
+
| `@arnilo/prism-core/governance/policy` | Capability admission, tool execution approvals, audit log exporter, and OPA evaluator | — |
|
|
36
|
+
| `@arnilo/prism-core/governance/evals` | Offline evaluation runs, scorers, judges, threshold assertions, and trace curation | — |
|
|
37
|
+
| `@arnilo/prism-core/governance/prompts` | Versioned prompt registry, promotion gating, rollback, and storage | `better-sqlite3`, `pg` |
|
|
38
|
+
| `@arnilo/prism-core/governance/model-router` | Cost- and latency-aware model routing, token reservations, and failover | — |
|
|
39
|
+
| `@arnilo/prism-core/governance/observability` | OpenTelemetry instrumentation and event tracing | `@opentelemetry/api` |
|
|
40
|
+
| `@arnilo/prism-core/credentials/node` | Keyring-backed encrypted credential store, scrypt envelope encryption, OAuth2 PKCE providers, and OIDC identity verification | `@napi-rs/keyring` (bundled) |
|
|
41
|
+
| `@arnilo/prism-core/enterprise/postgres` | Unified multi-tenant enterprise PostgreSQL state (approvals, evaluations, model-router, policy, tool effects, work idempotency) | `pg` |
|
|
42
|
+
| `@arnilo/prism-core/integrations/work` | Microsoft 365 and Google Workspace CLI tool adapters with approval gates and idempotency | — |
|
|
43
|
+
| `@arnilo/prism-core/validation/json-schema` | Ajv-backed JSON Schema tool argument validation | `ajv` (bundled) |
|
|
44
|
+
|
|
45
|
+
## Usage Examples
|
|
46
|
+
|
|
47
|
+
### Workflow Runtime
|
|
48
|
+
```ts
|
|
49
|
+
import { createWorkflowCoordinator, defineWorkflow, functionNode } from "@arnilo/prism-core/runtime/workflows";
|
|
50
|
+
|
|
51
|
+
const wf = defineWorkflow({
|
|
52
|
+
name: "order-processing",
|
|
53
|
+
initial: "validate",
|
|
54
|
+
nodes: {
|
|
55
|
+
validate: functionNode(async ({ input }) => ({ next: "process", output: input })),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Policy & Approvals
|
|
61
|
+
```ts
|
|
62
|
+
import { createMemoryApprovalStore, evaluateApproval } from "@arnilo/prism-core/governance/policy";
|
|
63
|
+
|
|
64
|
+
const approvals = createMemoryApprovalStore();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### SQLite Sessions
|
|
68
|
+
```ts
|
|
69
|
+
import { createSqlitePersistence } from "@arnilo/prism-core/sessions/sqlite";
|
|
70
|
+
|
|
71
|
+
const persistence = createSqlitePersistence({ filename: "./prism.db" });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### JSON Schema Validation
|
|
75
|
+
```ts
|
|
76
|
+
import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
|
|
77
|
+
|
|
78
|
+
const validator = createJsonSchemaToolArgumentValidator();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Security & Import Isolation
|
|
82
|
+
|
|
83
|
+
- Subpaths never load database drivers (`pg`, `better-sqlite3`) unless the specific database subpath is imported.
|
|
84
|
+
- All database and network drivers fail closed with clear actionable error messages when peers are omitted.
|
|
85
|
+
- Root `@arnilo/prism` remains dependency-free contracts and CLI runner.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
The optional `@arnilo/prism-credentials
|
|
5
|
+
The optional `@arnilo/prism-core/credentials/node` package ships host-owned credential persistence for Node.js CLI and desktop apps:
|
|
6
6
|
|
|
7
7
|
- **Encrypted file store** — AES-256-GCM envelope with scrypt KDF, atomic rename writes, versioned on-disk format
|
|
8
8
|
- **System keychain store** — cross-platform secret service via `@napi-rs/keyring@^1.3.0`
|
|
@@ -17,7 +17,7 @@ Factories:
|
|
|
17
17
|
- `createOAuthCredentialStoreAdapter(store)`
|
|
18
18
|
- `rotateEncryptedCredentialStorePassphrase(options)`
|
|
19
19
|
|
|
20
|
-
The `@arnilo/prism-credentials
|
|
20
|
+
The `@arnilo/prism-core/credentials/node/oidc` subpath adds the optional OIDC/JWKS identity verifier (`createOidcIdentityVerifier`) — pinned issuer/audience/JWKS verification over native `fetch` + WebCrypto (see [Agent identity](agent-identity.md)).
|
|
21
21
|
|
|
22
22
|
Core `@arnilo/prism` remains storage-free. Hosts choose a backend explicitly at startup; there is no global credential singleton and no silent fallback from keychain to plaintext file storage.
|
|
23
23
|
|
|
@@ -37,7 +37,7 @@ Do **not** use it when credentials should live in a remote vault, HSM, or cloud
|
|
|
37
37
|
import {
|
|
38
38
|
openEncryptedCredentialStore,
|
|
39
39
|
createKeychainCredentialStore,
|
|
40
|
-
} from "@arnilo/prism-credentials
|
|
40
|
+
} from "@arnilo/prism-core/credentials/node";
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
### Encrypted file
|
|
@@ -79,6 +79,10 @@ Encrypted file stores also expose:
|
|
|
79
79
|
|
|
80
80
|
`encryptBytes()` and `decryptBytes()` are Promise-based because they use asynchronous `node:crypto.scrypt`.
|
|
81
81
|
|
|
82
|
+
### MCP OAuth records (plan 063)
|
|
83
|
+
|
|
84
|
+
When backing `McpClientAuthState` from `@arnilo/prism-mcp` with one of these stores, key OAuth rows by the validated authorization-server `issuer` the SDK stamps onto every `StoredOAuthTokens`/`StoredOAuthClientInformation` record (the credential methods receive it). Credentials must never cross issuers: a store that cannot partition by issuer stays single-slot-safe (the MCP provider re-validates the stamp), but partitioning is the preferred shape for hosts talking to more than one MCP server. Refresh tokens belong only in the encrypted file or keychain backends — never the plaintext memory store in production.
|
|
85
|
+
|
|
82
86
|
Errors are explicit and fail closed:
|
|
83
87
|
|
|
84
88
|
| Error | Code | When |
|
|
@@ -126,7 +130,7 @@ import {
|
|
|
126
130
|
createOAuthCredentialStoreAdapter,
|
|
127
131
|
createStoredCredentialResolver,
|
|
128
132
|
openEncryptedCredentialStore,
|
|
129
|
-
} from "@arnilo/prism-credentials
|
|
133
|
+
} from "@arnilo/prism-core/credentials/node";
|
|
130
134
|
|
|
131
135
|
const store = await openEncryptedCredentialStore({
|
|
132
136
|
path: "./credentials.vault",
|
|
@@ -157,7 +161,7 @@ import {
|
|
|
157
161
|
createGoogleWorkspaceOAuthProvider,
|
|
158
162
|
createOAuthWorkTokenProvider,
|
|
159
163
|
createOAuthCredentialStoreAdapter,
|
|
160
|
-
} from "@arnilo/prism-credentials
|
|
164
|
+
} from "@arnilo/prism-core/credentials/node";
|
|
161
165
|
|
|
162
166
|
// Read-only mail/calendar (no mutation scopes requested).
|
|
163
167
|
const m365 = createMicrosoft365OAuthProvider({ clientId: "<app-id>", capabilities: ["mail", "calendar"], access: "read" });
|
|
@@ -178,7 +182,7 @@ await revokeOAuthCredential({ provider: m365, credentials: creds, store: createO
|
|
|
178
182
|
Passphrase rotation:
|
|
179
183
|
|
|
180
184
|
```ts
|
|
181
|
-
import { rotateEncryptedCredentialStorePassphrase } from "@arnilo/prism-credentials
|
|
185
|
+
import { rotateEncryptedCredentialStorePassphrase } from "@arnilo/prism-core/credentials/node";
|
|
182
186
|
|
|
183
187
|
await rotateEncryptedCredentialStorePassphrase({
|
|
184
188
|
path: "./credentials.vault",
|
|
@@ -198,8 +202,8 @@ import {
|
|
|
198
202
|
import {
|
|
199
203
|
createKeychainCredentialStore,
|
|
200
204
|
createStoredCredentialResolver,
|
|
201
|
-
} from "@arnilo/prism-credentials
|
|
202
|
-
import { createOpenAIProviderPackage } from "@arnilo/prism-
|
|
205
|
+
} from "@arnilo/prism-core/credentials/node";
|
|
206
|
+
import { createOpenAIProviderPackage } from "@arnilo/prism-providers/openai";
|
|
203
207
|
|
|
204
208
|
const keychain = createKeychainCredentialStore({
|
|
205
209
|
service: "com.example.my-app",
|
|
@@ -133,4 +133,4 @@ A future provider-local OAuth adapter needs published permission for third-party
|
|
|
133
133
|
- [LLM compaction package](compaction-llm.md): resolves optional summary-provider credentials per compaction call and redacts exact known values.
|
|
134
134
|
- [OpenAI-compatible provider](providers/openai-compatible.md): resolves API keys per request and redacts known values from adapter errors.
|
|
135
135
|
|
|
136
|
-
Phase 10 added `createMemoryCredentialStore()`, `createChainedCredentialResolver()`, and `createSecretRedactor()` for opt-in in-memory auth and runtime redaction. By default the memory store serves a providerless record for a provider-scoped request of the same name — that record is then shared across every provider; pass `{ allowProviderFallback: false }` for exact-match-only resolution (strict provider scoping). Phase 11 adds OAuth/API-key contracts plus explicit resolver order helpers. Core still has no persistent secret store and does not read environment variables or files for credentials. For durable storage, use [`@arnilo/prism-credentials
|
|
136
|
+
Phase 10 added `createMemoryCredentialStore()`, `createChainedCredentialResolver()`, and `createSecretRedactor()` for opt-in in-memory auth and runtime redaction. By default the memory store serves a providerless record for a provider-scoped request of the same name — that record is then shared across every provider; pass `{ allowProviderFallback: false }` for exact-match-only resolution (strict provider scoping). Phase 11 adds OAuth/API-key contracts plus explicit resolver order helpers. Core still has no persistent secret store and does not read environment variables or files for credentials. For durable storage, use [`@arnilo/prism-core/credentials/node`](credential-storage.md) encrypted-file or keychain backends. See [Security/auth/trust](settings-auth-trust-security.md).
|
|
@@ -77,6 +77,6 @@ const redactor = createAuditFieldRedactor(fieldPolicy, { labelFor });
|
|
|
77
77
|
|
|
78
78
|
- `redactMessage` / `redactProviderRequest` / `redactAgentEvent` / `redactSessionEntry` / `redactRunLedgerRecord` — the egress seams that take the optional policy (secret redaction first, then classification).
|
|
79
79
|
- `createAuditFieldRedactor` → the audit-export `redact` hook; see [Signed, hash-chained audit export](audit-export.md).
|
|
80
|
-
- `createOpenTelemetryInstrumentation` in `@arnilo/prism-observability
|
|
80
|
+
- `createOpenTelemetryInstrumentation` in `@arnilo/prism-core/governance/observability` — the telemetry `fieldPolicy` option.
|
|
81
81
|
- `createProtectedFieldPolicy`, `ALLOW_FIELD_POLICY`, `FieldPolicyError`, `FIELD_POLICY_LIMITS` — the protected default and limits.
|
|
82
82
|
- The ERP-T9 threat matrix (`src/__tests__/field-policy.test.ts`) and the boundary-drill scripts cover the enforcement evidence.
|
|
@@ -6,9 +6,11 @@ The production persistence contracts describe database-neutral types for durable
|
|
|
6
6
|
|
|
7
7
|
Prism itself does not ship a production database adapter. The built-in `SessionStore` contract (`append` / `list` / optional `get`) remains the runtime seam; `ProductionPersistenceStore` is the optional adapter-facing contract for hosts that need paginated reads, tenant isolation, audit tables, retention, and optional generic `CheckpointStore` / `LeaseStore` capabilities.
|
|
8
8
|
|
|
9
|
-
Plan 056 Task 1 adds dialect-neutral shared primitives under `@arnilo/prism/testing/persistence-schema`, `@arnilo/prism/testing/session-store-conformance`, and `@arnilo/prism/testing/run-ledger-conformance`. Task 2 ships `@arnilo/prism-
|
|
9
|
+
Plan 056 Task 1 adds dialect-neutral shared primitives under `@arnilo/prism/testing/persistence-schema`, `@arnilo/prism/testing/session-store-conformance`, and `@arnilo/prism/testing/run-ledger-conformance`. Task 2 ships `@arnilo/prism-core/sessions/sqlite` (see [SQLite persistence](sqlite-persistence.md)); Task 3 ships `@arnilo/prism-core/sessions/postgres` (see [PostgreSQL persistence](postgres-persistence.md)). Both implement dialect-local SQL against the shared model; Prism core still ships no ORM, driver, or migration runner.
|
|
10
10
|
|
|
11
|
-
Release 0.0.23 additionally ships [`@arnilo/prism-enterprise
|
|
11
|
+
Release 0.0.23 additionally ships [`@arnilo/prism-core/enterprise/postgres`](enterprise-postgres-state.md), a separate PostgreSQL composition for policy decisions, evaluations, work-mutation claims, and model-router state. It is not a `ProductionPersistenceStore` replacement and does not store sessions/runs. Its fixed `prism_enterprise_migrations` history is independent of `prism_migrations`; hosts may use both compositions against the same validated schema.
|
|
12
|
+
|
|
13
|
+
The optional [`@arnilo/prism-core/governance/prompts`](prompt-registry.md) package is another independent persistence surface: its SQLite/PostgreSQL adapters own `prism_prompts`, `prism_prompt_labels`, and `prism_prompt_migrations`, apply a checked `001_init` history, and filter every read/write by exact prompt ownership. It does not extend the shared session schema or place prompt bodies in run/session metadata.
|
|
12
14
|
|
|
13
15
|
## When to use it
|
|
14
16
|
|
|
@@ -80,6 +82,8 @@ Metadata CAS (0.2.2): the write seam accepts an additive `expectedVersion` guard
|
|
|
80
82
|
|
|
81
83
|
Artifact co-work review (0.0.14) reuses the generic `CheckpointStore` rather than adding a dedicated table: the [artifact service](work-artifacts-and-review.md) stores each artifact as a versioned checkpoint value (namespace `prism.artifact`, key `threadId:artifactId`, category `artifact`). The checkpoint `version` is the compare-and-swap counter that resolves concurrent reviewers; revision numbers, approvals, and `lastValidatedVersion` live inside the JSON value. SQLite/Postgres already persist checkpoints durably, so there is no separate artifact schema or migration, and records carry metadata/hashes/refs only — never file bodies.
|
|
82
84
|
|
|
85
|
+
Run prompt provenance (plan 042): `RunRecord` gains an optional typed `promptVersion` ref (`{ name, version, hash }`) that the first-party adapters persist as a nullable `prompt_version` JSON column on run rows (schema migration `009_run_prompt_version`, shared schema version 9). Rows written before the migration stay `NULL` and read back without the field; a host that never sets `RunOptions.promptVersion` sees byte-identical rows. The ref is an opaque identity (`sha256:` body hash), never prompt content, and flows through the same ledger redaction as every other run field. Prompt bodies themselves live only in the separate [prompt registry tables](prompt-registry.md) — never in run rows or run metadata.
|
|
86
|
+
|
|
83
87
|
## Outputs / response / events
|
|
84
88
|
|
|
85
89
|
Each `query*` method returns a `PersistencePage<T>`:
|
|
@@ -453,7 +457,7 @@ const dbStore: ProductionPersistenceStore = {
|
|
|
453
457
|
- `SessionStore` (`append`/`list`/`get`/optional `readBranchPath`) can be implemented on top of `ProductionPersistenceStore` or kept separate.
|
|
454
458
|
- **State-concurrency conformance (0.2.2):** durable adapters must pass `assertStateConcurrencyConforms` from `@arnilo/prism/testing/state-concurrency-conformance` against both the memory stores and their own implementation (approval determinism, checkpoint CAS, replay-cursor resume, idempotency retry, router reservation, conversation metadata CAS, unknown-outcome recovery). The harness uses deterministic barriers only — no timing-only sleeps — and runs the memory leg in the default `npm test` and the durable legs in `test:postgres`/`test:nats`; `scripts/phase22-conformance.test.mjs` asserts every store leg executed (missing protected environment records a named BLOCKED GATE, never a green skip).
|
|
455
459
|
- Cursor values and idempotency keys are host-defined and opaque to Prism.
|
|
456
|
-
- First-party SQLite/PostgreSQL adapters expose `persistence.checkpoints` and `persistence.leases`, backed by package-owned `prism_checkpoints` / `prism_leases` tables. `@arnilo/prism-workflows` consumes them for durable resume, human suspension, multi-process coordination, Phase 11 schedule records/fire leases, shared state, and replay lineage; workflow code owns no SQL table. `suspended`/`denied`, schedules, state history, and replay lineage remain namespaces/categories plus bounded checkpoint JSON values, so Phases 8 and 11 need no database migration.
|
|
460
|
+
- First-party SQLite/PostgreSQL adapters expose `persistence.checkpoints` and `persistence.leases`, backed by package-owned `prism_checkpoints` / `prism_leases` tables. `@arnilo/prism-core/runtime/workflows` consumes them for durable resume, human suspension, multi-process coordination, Phase 11 schedule records/fire leases, shared state, and replay lineage; workflow code owns no SQL table. `suspended`/`denied`, schedules, state history, and replay lineage remain namespaces/categories plus bounded checkpoint JSON values, so Phases 8 and 11 need no database migration.
|
|
457
461
|
|
|
458
462
|
Schema version **7** adds the exact-owner durable event retention index (`prism_agent_events_owner_timestamp_sequence_idx`). Distributed subscribe/LISTEN remains PostgreSQL-only via `persistence.events`.
|
|
459
463
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Dev inspector
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`@arnilo/prism-coding-tools/dev` is a **loopback-only local dev inspector** over a host's already-configured Prism agent — the `prism dev` playground server (plan 040). It is a **composition-only consumer**: it adds zero core primitives and imports no core internals. Every capability is an existing public seam consumed verbatim:
|
|
6
|
+
|
|
7
|
+
- `@arnilo/prism-core/runtime/server` `createPrismHandler` — direct `POST /prism/agents/:id/runs` and SSE `POST /prism/agents/:id/stream` agent routes, authorization, ownership propagation, and the durable `Last-Event-ID` event route when an exposure carries `events` + `resolveRun`.
|
|
8
|
+
- Core durable `AgentEventSource` contract (`page`/`subscribe`) — replay and reconnect without re-execution.
|
|
9
|
+
- `@arnilo/prism-ag-ui/renderer` — event projection for the served UI page (plan 040 Task 3).
|
|
10
|
+
- Run-ledger records (`RunRecord`/`AgentEventRecord`/`ToolCallRecord`/`UsageRecord`) surfaced only through the seams above — the package never touches a ledger.
|
|
11
|
+
- Pending-decision resume through the server's fail-closed decision validation (plan 040 Task 2) — the inspector adds none.
|
|
12
|
+
|
|
13
|
+
## When to use it
|
|
14
|
+
|
|
15
|
+
Use it when iterating on prompts in a local Prism host and you want a inspectable timeline (events, tool calls, usage, HITL decisions, run replay) instead of building your own trace viewer. Do not deploy it: it is a developer-time surface, deliberately excluded from production dependency use, and it must never be the production API boundary — that stays `@arnilo/prism-core/runtime/server` under host authorization.
|
|
16
|
+
|
|
17
|
+
### Quickstart — `prism dev` (plan 040 Task 4)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install --save-dev @arnilo/prism-coding-tools/dev
|
|
21
|
+
cd my-agent && npm run dev # → prism dev → http://127.0.0.1:4311
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`prism dev` (and the standalone `prism-dev` bin, plus the programmatic `runDevCli` from `@arnilo/prism-coding-tools/dev/cli`) boots the inspector over the current `prism init` scaffold: it imports `dist/agent.js` and calls its `createAppAgent()` export — the scaffold's own agent, with its own credentials. It defaults to `127.0.0.1:4311`, prints the loopback URL once listening (start-to-listen under 1s excluding provider network), and `Ctrl+C` drains and closes. A non-loopback `--host` is refused before binding (`ERR_PRISM_DEV_REMOTE_BIND`); the CLI never reads environment secrets itself. See `docs/cli-rpc.md` for the flag table.
|
|
25
|
+
|
|
26
|
+
## Inputs / request
|
|
27
|
+
|
|
28
|
+
`createPrismDevInspector(options)`:
|
|
29
|
+
|
|
30
|
+
| Field | Purpose |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `agent` | Required host-built `Agent` (mock or provider-backed). The inspector never constructs the agent or reads credentials. |
|
|
33
|
+
| `eventSource` | Optional durable `AgentEventSource`; opts the server exposure into durable event routes, SSE reconnect, and the paged replay endpoint. Requires `resolveRun`. |
|
|
34
|
+
| `resolveRun` | Required with `eventSource`: resolves a public run selector to exact internal session/run IDs. Refusing a selector (foreign/unknown run) fails closed with `404`. |
|
|
35
|
+
| `checkpoints` | Optional host checkpoint store backing the agent's `runState`; wiring it enables the durable status/resume capability behind the decision endpoint. Host-owned — the inspector only composes the core lifecycle seam (`createAgentRunLifecycle`) over the host's own agent. |
|
|
36
|
+
| `definitionRevision` | Definition revision declared for the lifecycle resolve; default `"1"`. |
|
|
37
|
+
| `authorize` | Optional per-operation authorizer. Loopback default: single synthetic local user (`local`, ownership `tenantId`/`userId` both `local` so durable event scoping passes); request JSON can never widen ownership (server seam enforces). |
|
|
38
|
+
| `host` | Bind host, default `127.0.0.1`. **Non-loopback fails closed** unless `remoteAuthorize` resolves `true` and a real `authorize` callback is supplied. |
|
|
39
|
+
| `port` | Default `4311`; `0` picks an ephemeral port. |
|
|
40
|
+
| `remoteAuthorize` | Explicit opt-in callback for a non-loopback bind, consulted by `listen()`. |
|
|
41
|
+
| `redactor` | Host `SecretRedactor` passed through to the server handler and the replay pager; rendered tool args/results stay host-redacted on both the SSE and replay paths. |
|
|
42
|
+
| `limits` / `basePath` | Server limits and route base path passthrough. |
|
|
43
|
+
|
|
44
|
+
## Outputs / response / events
|
|
45
|
+
|
|
46
|
+
The inspector exposes `handler` (the composed `PrismRequestHandler`), `listen()`, `close()`, and once listening `url`/`host`/`port`. Boot (create + bind, excluding host model calls) stays under the 1s envelope. Configuration refusals throw `DevInspectorError` (`ERR_PRISM_DEV_INSPECTOR`, or `ERR_PRISM_DEV_REMOTE_BIND` for bind-policy failures).
|
|
47
|
+
|
|
48
|
+
Per-task surface (plan 040): Task 1 wires agent routes + bind policy; Task 2 (shipped) adds the data-defined inspector routes below; Task 3 serves the static UI page; Task 4 ships the `prism dev` CLI composition.
|
|
49
|
+
|
|
50
|
+
## HTTP surface (plan 040 Task 2)
|
|
51
|
+
|
|
52
|
+
Data-defined route table over the server seam — each route either rewrites the URL into the already conformance-tested `PrismRequestHandler` or pages the durable event source. Unmatched requests forward unchanged to the raw `/{basePath}/*` server surface on the same listener.
|
|
53
|
+
|
|
54
|
+
| Route | Purpose | Adapts to |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `POST /prompt` | Runs the agent (direct run). | server handler direct agent run. |
|
|
57
|
+
| `GET /events?runId=<id>` | Durable SSE stream of normalized events. `Last-Event-ID` header reconnect and `?cursor=` are honored by the server seam; missing `runId` → `400 ERR_PRISM_DEV_ROUTE`. |
|
|
58
|
+
| `GET /runs/:id/replay?cursor=…` | Paged replay of a stored run from the durable `AgentEventSource` — **no session, no provider, no re-execution** (`createPrismAgentEventReplay` page). Returns `{ items, nextCursor?, terminal }`; unknown/foreign run ids → `404`. |
|
|
59
|
+
| `POST /runs/:runId/decisions/:decisionId` | Resumes/denies one suspended approval. Body `{ outcome: "allow_once" \| "allow_always" \| "deny", expectedVersion? }` → forwarded as a single-entry core decision batch; unknown discriminants and stale versions fail closed (`400`) at the core boundary **before any state write**. |
|
|
60
|
+
|
|
61
|
+
Reconnect semantics: every SSE frame carries `id: <cursor>`; a reconnecting client sends `Last-Event-ID: <cursor>` and receives exactly the post-cursor events — no duplicates, no loss (server conformance-tested). Replay pages are bounded by the deployment limits (`maxReplayEvents`, `maxReplayCursorBytes`) and ownership-scoped by the source seam itself.
|
|
62
|
+
|
|
63
|
+
## UI walkthrough (plan 040 Task 3)
|
|
64
|
+
|
|
65
|
+
Opening the inspector URL serves one static page (`GET /` → `page` + `GET /assets/inspector.js`; bootstrap via same-origin `GET /config` → `{ basePath, agentId }`). No external fetches — the bundle is offline-capable, served with a strict CSP (`default-src 'none'; script-src 'self'; connect-src 'self'`, `nosniff`, `no-store`), and every dynamic payload reaches the DOM through text nodes only (redacted strings render as-is, never parsed as markup).
|
|
66
|
+
|
|
67
|
+
Panels:
|
|
68
|
+
|
|
69
|
+
- **Prompt box** — `POST {basePath}/agents/{id}/stream` (server SSE seam); frames arrive as redacted `AgentEvent` JSON and fold into the timeline live.
|
|
70
|
+
- **Event timeline** — message deltas merged into per-stream text items, thinking separately, turn boundaries as separators. Rows render incrementally through a **windowed list** (last `MAX_RENDERED_WINDOW` = 400 rows; older rows collapse into a counter line) so 1k+ event runs never lock the page. Tool calls are expandable `<details>`: streamed args, finished results, blocked/error state.
|
|
71
|
+
- **Usage** — per-run totals summed from `provider_turn_finished.usage` and the terminal `agent_finished.usage` (input/output/total tokens, cost when the model reports it).
|
|
72
|
+
- **Decisions** — `agent_suspended` renders one card per pending decision (`PendingDecision.approvalId`, tool name, redacted reason, `expectedVersion` from the event's run version). Buttons post `POST /runs/:runId/decisions/:approvalId` ({ outcome: `allow_once` | `allow_always` | `deny`, expectedVersion }); rejections show the seam's fail-closed error verbatim, and a remaining-multi-decision suspension re-renders from the response's `runState.interruption`.
|
|
73
|
+
- **Run selector** — session runs (live + loaded) with status; a durable view of any past run loads via `GET {basePath}/events?runId=…` over `EventSource` — the seam's own `Last-Event-ID` reconnect applies. Without a durable event source wired, loading by runId surfaces that fact instead of pretending to replay.
|
|
74
|
+
|
|
75
|
+
## Request/response example
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
POST /prompt
|
|
79
|
+
{ "input": "Summarize the release notes" }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Suspended approval surfaced by that response (`runState.interruption.pendingDecisions`) resumes via:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
POST /runs/<runId>/decisions/<approvalId>
|
|
86
|
+
{ "outcome": "allow_once", "expectedVersion": 1 }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Implementation example
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { createPrismDevInspector } from "@arnilo/prism-coding-tools/dev";
|
|
93
|
+
|
|
94
|
+
const inspector = createPrismDevInspector({
|
|
95
|
+
agent, // host-built agent (mock or provider-backed)
|
|
96
|
+
eventSource, // optional durable AgentEventSource for replay
|
|
97
|
+
host: "127.0.0.1",
|
|
98
|
+
port: 4311,
|
|
99
|
+
});
|
|
100
|
+
await inspector.listen(); // http://127.0.0.1:4311 — loopback only
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Loopback policy: default bind is `127.0.0.1:4311`; a non-loopback bind is refused unless an explicit `remoteAuthorize` callback opts in and a real `authorize` callback is supplied; loopback default authorization is one synthetic local user; the inspector stores no secrets and never reads `process.env` for credentials.
|
package/docs/device-adapters.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
Optional realtime voice and desktop OS / computer-control surface for Prism agents, shipped in 0.0.14 as a **contract + deny-by-default policy** in `@arnilo/prism` (`src/devices.ts`). The first vendor adapter, `@arnilo/prism-computer-use-linux`, wraps the host-owned `computer-use-linux` MCP binary without changing this generic contract. The contract composes over the existing `PermissionPolicy`, `RunLimits`, approval (`tool_approval`), and redactor seams; it adds no second approval runtime and no device framework.
|
|
5
|
+
Optional realtime voice and desktop OS / computer-control surface for Prism agents, shipped in 0.0.14 as a **contract + deny-by-default policy** in `@arnilo/prism` (`src/devices.ts`). The first vendor adapter, `@arnilo/prism-coding-tools/computer-use-linux`, wraps the host-owned `computer-use-linux` MCP binary without changing this generic contract. The contract composes over the existing `PermissionPolicy`, `RunLimits`, approval (`tool_approval`), and redactor seams; it adds no second approval runtime and no device framework.
|
|
6
6
|
|
|
7
7
|
## When to use it
|
|
8
8
|
|
|
@@ -79,7 +79,7 @@ if (chunk.accepted) emit(redactDeviceTelemetry(createSecretRedactor([token]), fr
|
|
|
79
79
|
|
|
80
80
|
- Frozen caps: audio/screenshot/stream chunk **1 MiB / 8 MiB**; concurrent device sessions per identity **1 / 4**. Device wall time / turns / tool calls consume the shared `RunLimits` (admission fails closed without run accounting).
|
|
81
81
|
- `enabled` resolves to `true` only on an explicit `true`; any other value is disabled. `requireApproval` stays `true` unless the host explicitly sets `false` (it should not).
|
|
82
|
-
- `@arnilo/prism-computer-use-linux` is the first vendor package. It remains optional, Linux-only, host-binary-owned, and outside umbrella profiles; this page stays generic so future voice or desktop vendors can satisfy the same contract via `runDevicePolicyConformance`.
|
|
82
|
+
- `@arnilo/prism-coding-tools/computer-use-linux` is the first vendor package. It remains optional, Linux-only, host-binary-owned, and outside umbrella profiles; this page stays generic so future voice or desktop vendors can satisfy the same contract via `runDevicePolicyConformance`.
|
|
83
83
|
|
|
84
84
|
## Security and performance notes
|
|
85
85
|
|
package/docs/diagrams.md
ADDED
|
@@ -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-core/governance/observability`](./observability.md): OpenTelemetry instrumentation and trace adapters.
|
package/docs/document-reader.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Document reader (`@arnilo/prism-document-reader`)
|
|
1
|
+
# Document reader (`@arnilo/prism-coding-tools/document-reader`)
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ Optional bounded literal-text extraction for PDF and DOCX files, consumed by the
|
|
|
6
6
|
|
|
7
7
|
## When to use it
|
|
8
8
|
|
|
9
|
-
Use when coding agents must read PDF/Office files (specs, requirements docs, reports) as literal text. Do **not** use it when embedded content execution, macro evaluation, or external resource fetching is required — this adapter never does any of those by construction, and the optional peer parsers (`pdf-parse`, `mammoth`) are the only parsing code involved. Docker-less hosts that need document reads pair this with the network-free native sandbox backend (`@arnilo/prism-coding-security` `createNativeSandbox`) for the surrounding tool execution.
|
|
9
|
+
Use when coding agents must read PDF/Office files (specs, requirements docs, reports) as literal text. Do **not** use it when embedded content execution, macro evaluation, or external resource fetching is required — this adapter never does any of those by construction, and the optional peer parsers (`pdf-parse`, `mammoth`) are the only parsing code involved. Docker-less hosts that need document reads pair this with the network-free native sandbox backend (`@arnilo/prism-coding-tools/security` `createNativeSandbox`) for the surrounding tool execution.
|
|
10
10
|
|
|
11
11
|
Activation is explicit: no file-extension sniffing anywhere enables parsing. Absent `documentReader` option = exactly the 0.1.5 read behavior.
|
|
12
12
|
|
|
@@ -33,8 +33,8 @@ Errors: `DocumentReaderError` with code `ERR_PRISM_DOCUMENT_READER` for missing
|
|
|
33
33
|
## Request/response example
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
|
-
import { createReadTool } from "@arnilo/prism-coding-agent";
|
|
37
|
-
import { createDocumentReader } from "@arnilo/prism-document-reader";
|
|
36
|
+
import { createReadTool } from "@arnilo/prism-coding-tools/agent";
|
|
37
|
+
import { createDocumentReader } from "@arnilo/prism-coding-tools/document-reader";
|
|
38
38
|
|
|
39
39
|
const documentReader = await createDocumentReader({
|
|
40
40
|
maxBytes: 32 * 1024 * 1024,
|
|
@@ -49,7 +49,7 @@ A `read` of `spec.pdf` yields text content extracted from the PDF (up to 2 MiB o
|
|
|
49
49
|
## Implementation example
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
|
-
import { createDocumentReader, createPdfParser, type DocumentParser } from "@arnilo/prism-document-reader";
|
|
52
|
+
import { createDocumentReader, createPdfParser, type DocumentParser } from "@arnilo/prism-coding-tools/document-reader";
|
|
53
53
|
|
|
54
54
|
// Host-selected parser wiring: swap in a different PDF backend without touching bounds.
|
|
55
55
|
const myPdfParser: DocumentParser = {
|
|
@@ -79,7 +79,7 @@ const reader = await createDocumentReader({ parsers: [myPdfParser, await createP
|
|
|
79
79
|
|
|
80
80
|
## Related APIs
|
|
81
81
|
|
|
82
|
-
- `createReadTool` / `DocumentReader` / `DocumentReaderResult` (`@arnilo/prism-coding-agent`)
|
|
82
|
+
- `createReadTool` / `DocumentReader` / `DocumentReaderResult` (`@arnilo/prism-coding-tools/agent`)
|
|
83
83
|
- `SecretRedactor` (`@arnilo/prism` redaction)
|
|
84
84
|
- `docs/_evidence/phase18-primitive-review.md` (doc-reader threat model D1–D8)
|
|
85
85
|
- `docs/coding-security.md` (native sandbox backend for surrounding execution containment)
|