@arnilo/prism 0.4.0 → 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 +33 -1
- package/README.md +23 -20
- package/dist/agent-run-state.d.ts +1 -2
- package/dist/agent-run-state.js +0 -3
- 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 +49 -43
- package/dist/agent-session/session.js +11 -1177
- package/dist/capture.d.ts +63 -0
- package/dist/capture.js +67 -0
- package/dist/cli-init.d.ts +18 -2
- package/dist/cli-init.js +2 -7
- package/dist/cli-runner.d.ts +2 -2
- package/dist/cli-runner.js +45 -9
- package/dist/content.d.ts +3 -3
- package/dist/content.js +3 -1
- package/dist/contracts-core/agent.d.ts +2 -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/index.d.ts +5 -3
- package/dist/index.js +4 -3
- 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/provider-conformance.d.ts +114 -5
- package/dist/testing/provider-conformance.js +342 -0
- 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/docs/0.1.0-readiness.md +3 -3
- package/docs/a2a.md +2 -2
- 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/cli-rpc.md +20 -9
- package/docs/coding-agent-tools.md +19 -19
- package/docs/coding-review-and-diagnostics.md +2 -2
- package/docs/coding-security.md +4 -4
- package/docs/coding-workspaces.md +2 -2
- package/docs/computer-use-linux.md +13 -2
- package/docs/context-and-skills.md +1 -1
- package/docs/conversations.md +4 -4
- package/docs/credential-storage.md +11 -7
- package/docs/credentials-and-redaction.md +1 -1
- package/docs/data-classification.md +1 -1
- package/docs/database-persistence.md +4 -4
- package/docs/dev-inspector.md +6 -6
- package/docs/device-adapters.md +2 -2
- package/docs/diagrams.md +1 -1
- package/docs/document-reader.md +6 -6
- package/docs/documents.md +5 -4
- package/docs/embeddings.md +112 -0
- package/docs/enterprise-postgres-state.md +7 -7
- package/docs/evaluations.md +8 -8
- package/docs/extensions.md +3 -3
- package/docs/forge-integration.md +3 -3
- package/docs/graft.md +2 -2
- package/docs/guardrails.md +1 -1
- package/docs/host-security.md +15 -15
- package/docs/image-generation.md +129 -0
- package/docs/impeccable.md +5 -3
- package/docs/index.md +60 -33
- 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 +43 -12
- package/docs/middleware-hooks.md +1 -1
- package/docs/migrate-to-0.4.md +3 -3
- package/docs/migrate-to-0.5.md +122 -0
- package/docs/migration.md +29 -1
- package/docs/model-registry.md +38 -0
- package/docs/model-routing.md +5 -5
- package/docs/moderation.md +117 -0
- package/docs/multi-agent-patterns.md +4 -4
- package/docs/multimodal-content.md +26 -2
- package/docs/obscura.md +2 -2
- package/docs/observability.md +32 -7
- package/docs/openapi-tools.md +13 -3
- package/docs/operations.md +11 -0
- package/docs/performance.md +7 -7
- package/docs/persistence-credentials-multimodality-primitives.md +6 -6
- package/docs/policy-and-audit.md +17 -7
- package/docs/ponytail.md +1 -1
- package/docs/postgres-persistence.md +5 -5
- package/docs/process-sessions.md +2 -2
- package/docs/prompt-registry.md +7 -7
- package/docs/provider-caching.md +4 -0
- package/docs/provider-conformance.md +23 -1
- package/docs/provider-packages.md +39 -3
- package/docs/provider-primitives.md +1 -1
- package/docs/provider-request-policies.md +1 -1
- package/docs/providers/ai-sdk.md +15 -3
- package/docs/providers/alibaba.md +5 -1
- package/docs/providers/anthropic.md +4 -0
- package/docs/providers/azure.md +17 -1
- package/docs/providers/bedrock.md +15 -0
- package/docs/providers/clinepass.md +4 -0
- package/docs/providers/commandcode.md +253 -0
- package/docs/providers/deepseek.md +4 -0
- package/docs/providers/google.md +4 -0
- package/docs/providers/hyper.md +284 -0
- package/docs/providers/kimi.md +4 -0
- package/docs/providers/neuralwatt.md +4 -0
- package/docs/providers/ollama.md +15 -0
- package/docs/providers/openai-compatible.md +4 -0
- package/docs/providers/openai.md +4 -0
- package/docs/providers/opencode-go.md +4 -0
- package/docs/providers/openrouter.md +5 -1
- package/docs/providers/vertex.md +16 -0
- package/docs/providers/xai.md +4 -0
- package/docs/providers/zai.md +4 -0
- package/docs/rag.md +26 -4
- package/docs/release-and-install.md +103 -46
- package/docs/resource-loading.md +1 -1
- package/docs/runs-and-usage.md +14 -2
- package/docs/server.md +5 -5
- package/docs/settings-auth-trust-security.md +7 -5
- package/docs/sheets.md +2 -2
- package/docs/speech.md +126 -0
- package/docs/sqlite-persistence.md +4 -4
- package/docs/supervisors.md +3 -3
- package/docs/thinking-and-reasoning.md +93 -60
- package/docs/tool-conformance.md +1 -1
- package/docs/tool-execution-primitives.md +8 -8
- package/docs/tools.md +4 -4
- package/docs/web-tools.md +1 -1
- package/docs/wiki.md +1 -1
- 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 +11 -11
- package/docs/workflows.md +5 -5
- package/package.json +11 -8
- package/templates/init/providers.json +24 -8
- package/docs/antigravity-agent.md +0 -207
package/docs/documents.md
CHANGED
|
@@ -66,6 +66,7 @@ All package operations throw typed exceptions derived from `DocumentsError`:
|
|
|
66
66
|
| `DocumentsCapExceededError` | `ERR_PRISM_DOCUMENTS_CAP_EXCEEDED` | Document exceeds byte size, block count, cell count, or slide count caps. |
|
|
67
67
|
| `DocumentsParseError` | `ERR_PRISM_DOCUMENTS_PARSE_FAILED` | Input buffer lacks PK zip signature, is corrupted, or fails OOXML part parsing. |
|
|
68
68
|
| `DocumentsFormatError` | `ERR_PRISM_DOCUMENTS_UNSUPPORTED_FORMAT` | Format mismatch (e.g. attempting to generate PPTX from a `DocModel`). |
|
|
69
|
+
| `DocumentsPatchError` | `ERR_PRISM_DOCUMENTS_UNSAFE_PATH` | `__proto__`, `prototype`, or `constructor` appears as a `metadata` target or inside a block/slide/sheet `patch` segment (rejected before mutation to prevent `Object.prototype` pollution). |
|
|
69
70
|
| `DocumentsPatchError` | `ERR_PRISM_DOCUMENTS_PATCH_FAILED` | Out-of-bounds index target, unknown patch operation, or invalid patch structure. |
|
|
70
71
|
|
|
71
72
|
## Request/response example
|
|
@@ -207,7 +208,7 @@ Financial worksheets often require exact decimal representations that JavaScript
|
|
|
207
208
|
|
|
208
209
|
## Related APIs
|
|
209
210
|
|
|
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
|
|
212
|
-
- [`@arnilo/prism-coding-agent`](./coding-agent-tools.md): Coding tools and file operations.
|
|
213
|
-
- [`@arnilo/prism-observability
|
|
211
|
+
- [`@arnilo/prism-coding-tools/document-reader`](./document-reader.md): Bounded literal text extraction from PDF and DOCX documents for coding agent tools.
|
|
212
|
+
- [`@arnilo/prism-core/integrations/work`](./work-tools.md): Microsoft 365 and Google Workspace identity-scoped connectors.
|
|
213
|
+
- [`@arnilo/prism-coding-tools/agent`](./coding-agent-tools.md): Coding tools and file operations.
|
|
214
|
+
- [`@arnilo/prism-core/governance/observability`](./observability.md): OpenTelemetry instrumentation and trace adapters.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Embeddings
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`EmbeddingsProvider` is the provider-neutral embeddings contract: one-shot batch
|
|
6
|
+
text→vector generation with usage accounting, per-item error mapping, and
|
|
7
|
+
capability-gated models. First-party adapters ship in
|
|
8
|
+
[`@arnilo/prism-providers/openai`](providers/openai.md) (OpenAI-compatible
|
|
9
|
+
`POST {base}/embeddings`) and [`@arnilo/prism-providers/alibaba`](providers/alibaba.md)
|
|
10
|
+
(DashScope `compatible-mode/v1/embeddings`); offline conformance runs via
|
|
11
|
+
`runEmbeddingsConformance` from `@arnilo/prism/testing/provider-conformance`.
|
|
12
|
+
|
|
13
|
+
## When to use it
|
|
14
|
+
|
|
15
|
+
Use it when a host owns its embedding pipeline (RAG ingestion, memory indexing,
|
|
16
|
+
semantic search) and wants a portable contract instead of per-provider HTTP code.
|
|
17
|
+
Do not use it as a live integration runner: the contract is caller-gated, adapters
|
|
18
|
+
perform no network on construction, and batch caps are enforced with typed errors
|
|
19
|
+
rather than silent auto-chunking — chunk callers themselves (for example,
|
|
20
|
+
`@arnilo/prism-memory`'s `embedBatched`).
|
|
21
|
+
|
|
22
|
+
## Inputs / request
|
|
23
|
+
|
|
24
|
+
| Field | Type | Meaning |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `model` | `string` | Embedding model id, e.g. `text-embedding-3-small` or `text-embedding-v4`. |
|
|
27
|
+
| `inputs` | `readonly string[]` | Texts to embed; order is preserved on `result.vectors`. Non-empty and within the provider batch cap. |
|
|
28
|
+
| `dimensions` | `number?` | Output-dimensions override; only for models that support reduced dimensions (OpenAI `dimensions` param, DashScope 64–2048). |
|
|
29
|
+
| `signal` | `AbortSignal?` | Cancellation; observed by the adapter transport. |
|
|
30
|
+
|
|
31
|
+
Adapter options: `apiKey` (`CredentialValueSource` — the existing credential seam,
|
|
32
|
+
resolved per call and redacted from errors), `baseUrl`/`preset` (Alibaba),
|
|
33
|
+
`fetch` (inject a fake transport for offline tests), `headers`, and default
|
|
34
|
+
`dimensions`/`encodingFormat` where the provider supports them.
|
|
35
|
+
|
|
36
|
+
## Outputs / response / events
|
|
37
|
+
|
|
38
|
+
| Field | Type | Meaning |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `vectors` | `readonly (readonly number[])[]` | Vectors in input order; `vectors[i]` corresponds to `inputs[i]`. |
|
|
41
|
+
| `usage` | `Usage` | Provider-reported token usage (`inputTokens`, `totalTokens`); empty object when the provider omits it. |
|
|
42
|
+
| `dimensions` | `number` | Actual vector dimensionality reported by the response. |
|
|
43
|
+
|
|
44
|
+
Failures throw `EmbeddingsError` with a stable `code`:
|
|
45
|
+
`empty_input` (no inputs), `batch_too_large` (over the provider cap — OpenAI 2048,
|
|
46
|
+
DashScope 10), `request_failed` (non-2xx, secret-redacted message),
|
|
47
|
+
`response_malformed` (missing index, wrong dimensionality), `unsupported_model`
|
|
48
|
+
(via `assertEmbeddingsSupported` when the host checks
|
|
49
|
+
`ModelCapabilities.embeddings`).
|
|
50
|
+
|
|
51
|
+
## Request/response example
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{ "model": "text-embedding-3-small", "input": ["hello", "world"], "dimensions": 256 }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Implementation example
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { createOpenAIEmbeddingsProvider } from "@arnilo/prism-providers/openai";
|
|
61
|
+
import { runEmbeddingsConformance } from "@arnilo/prism/testing/provider-conformance";
|
|
62
|
+
|
|
63
|
+
const embeddings = createOpenAIEmbeddingsProvider({ apiKey: process.env.OPENAI_API_KEY });
|
|
64
|
+
const result = await embeddings.embedMany({
|
|
65
|
+
model: "text-embedding-3-small",
|
|
66
|
+
inputs: ["hello", "world"],
|
|
67
|
+
});
|
|
68
|
+
// result.vectors.length === 2; result.usage.inputTokens reported
|
|
69
|
+
|
|
70
|
+
// Offline conformance (fake transport, no network):
|
|
71
|
+
await runEmbeddingsConformance({
|
|
72
|
+
provider: createOpenAIEmbeddingsProvider({ apiKey: "sk-test", fetch: fakeFetch }),
|
|
73
|
+
model: "text-embedding-3-small",
|
|
74
|
+
maxBatchSize: 2048,
|
|
75
|
+
sample: { inputs: ["a", "b"], dimensions: 2 },
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Extension and configuration notes
|
|
80
|
+
|
|
81
|
+
- Implement `EmbeddingsProvider` (`{ id, embedMany }`) for other vendors; the
|
|
82
|
+
contract is structural — no base class, no registry.
|
|
83
|
+
- Models declare support with `capabilities.embeddings`; hosts gate with
|
|
84
|
+
`modelSupportsEmbeddings(capabilities)` / `assertEmbeddingsSupported(model)`,
|
|
85
|
+
mirroring the structured-output guard pattern.
|
|
86
|
+
- `@arnilo/prism-memory` keeps its dependency-free `Embedder` host seam; adapters
|
|
87
|
+
bridge structurally (`createAlibabaEmbedder` remains assignable to `Embedder`
|
|
88
|
+
without importing it). The contract is a superset: it adds usage and per-item
|
|
89
|
+
error mapping.
|
|
90
|
+
- Adapters never auto-chunk: a batch over the provider cap rejects with
|
|
91
|
+
`batch_too_large`, so `embedBatched`-style callers own batching and preserve
|
|
92
|
+
per-item error attribution.
|
|
93
|
+
|
|
94
|
+
## Security and performance notes
|
|
95
|
+
|
|
96
|
+
- API keys resolve through the existing `CredentialValueSource` seam and are
|
|
97
|
+
redacted from every thrown error (`redactSecrets`); no new secret paths.
|
|
98
|
+
- Responses are read through the bounded transport (`readBoundedResponseJson` /
|
|
99
|
+
`readBoundedResponseText`) — response bodies cannot exhaust memory.
|
|
100
|
+
- Input text is never logged; error messages carry status and redacted body only.
|
|
101
|
+
- One HTTP request per `embedMany` call; response mapping allocates one vector
|
|
102
|
+
copy per input and nothing else. Per-item token caps are server-enforced;
|
|
103
|
+
the local cap is batch count.
|
|
104
|
+
|
|
105
|
+
## Related APIs
|
|
106
|
+
|
|
107
|
+
- [`@arnilo/prism-memory`](working-and-semantic-memory.md): `Embedder` host seam and `embedBatched` —
|
|
108
|
+
consumption side of the structural bridge.
|
|
109
|
+
- [Provider conformance](provider-conformance.md): `runEmbeddingsConformance` and
|
|
110
|
+
the offline conformance matrix this contract joins.
|
|
111
|
+
- [Provider packages](provider-packages.md): subpath import rules for
|
|
112
|
+
`@arnilo/prism-providers/openai` and `@arnilo/prism-providers/alibaba`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-enterprise
|
|
5
|
+
`@arnilo/prism-core/enterprise/postgres` is one optional PostgreSQL composition for existing enterprise state seams:
|
|
6
6
|
|
|
7
7
|
| State | Composition property | Durable behavior |
|
|
8
8
|
| --- | --- | --- |
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| ERP messaging | `erpMessaging` | Transactional outbox/inbox markers plus bounded, tenant-scoped at-least-once dispatch (migration 004). |
|
|
15
15
|
| Multi-party approvals | `createPostgresApprovalStore({ pool, schema, authority })` | Immutable approval requests, role/quorum decisions, revocation, bounded delegation, and atomic grant consumption (migration 005). |
|
|
16
16
|
|
|
17
|
-
`createPostgresEnterpriseState()` opens a host-supplied or adapter-owned `pg` pool, verifies/applies checksum-protected enterprise migrations (`001_enterprise_state`, `002_tool_effects`, `003_router_reservations`, `004_erp_messaging`, `005_erp_approvals`), and returns those stores plus explicit cleanup and close operations. Importing it performs no I/O. It is separate from session/run persistence in [`@arnilo/prism-
|
|
17
|
+
`createPostgresEnterpriseState()` opens a host-supplied or adapter-owned `pg` pool, verifies/applies checksum-protected enterprise migrations (`001_enterprise_state`, `002_tool_effects`, `003_router_reservations`, `004_erp_messaging`, `005_erp_approvals`), and returns those stores plus explicit cleanup and close operations. Importing it performs no I/O. It is separate from session/run persistence in [`@arnilo/prism-core/sessions/postgres`](postgres-persistence.md).
|
|
18
18
|
|
|
19
19
|
## When to use it
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ Use memory/file stores only for tests, demos, or a deliberately single-process h
|
|
|
25
25
|
## Inputs / request
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
import { createPostgresEnterpriseState } from "@arnilo/prism-enterprise
|
|
28
|
+
import { createPostgresEnterpriseState } from "@arnilo/prism-core/enterprise/postgres";
|
|
29
29
|
import { Pool } from "pg";
|
|
30
30
|
|
|
31
31
|
const pool = new Pool({
|
|
@@ -95,7 +95,7 @@ A migration creates `prism_policy_decisions`, `prism_evaluations`, `prism_work_i
|
|
|
95
95
|
## Implementation example
|
|
96
96
|
|
|
97
97
|
```ts
|
|
98
|
-
import { createPostgresErpMessaging } from "@arnilo/prism-enterprise
|
|
98
|
+
import { createPostgresErpMessaging } from "@arnilo/prism-core/enterprise/postgres";
|
|
99
99
|
|
|
100
100
|
const messaging = createPostgresErpMessaging({ pool, schema: "prism" });
|
|
101
101
|
const client = await pool.connect();
|
|
@@ -141,7 +141,7 @@ await messaging.dispatcher.replay({
|
|
|
141
141
|
|
|
142
142
|
```ts
|
|
143
143
|
import type { AgentIdentity } from "@arnilo/prism";
|
|
144
|
-
import { createPostgresEnterpriseState, type PostgresEnterpriseState } from "@arnilo/prism-enterprise
|
|
144
|
+
import { createPostgresEnterpriseState, type PostgresEnterpriseState } from "@arnilo/prism-core/enterprise/postgres";
|
|
145
145
|
|
|
146
146
|
const identity: AgentIdentity = {
|
|
147
147
|
tenantId: "tenant-1",
|
|
@@ -202,13 +202,13 @@ export async function recordEnterpriseState(state: PostgresEnterpriseState) {
|
|
|
202
202
|
|
|
203
203
|
## Extension and configuration notes
|
|
204
204
|
|
|
205
|
-
- `createModelRouter({ resolver, stateStore: state.modelRouter })` keeps allow-list, residency, fallback, and diagnostics behavior in `@arnilo/prism-model-router`; this package only supplies durable state. Router admission reservations (`reserveBudget`/`commitBudget`/`releaseBudget` on `state.modelRouter`) live in the `reservations` JSONB column of `prism_model_router_budgets`: one atomic UPSERT per admission, fencing-token-guarded commit/release in a SERIALIZABLE transaction, and TTL reconciliation as unknown usage; see [Model routing](model-routing.md).
|
|
205
|
+
- `createModelRouter({ resolver, stateStore: state.modelRouter })` keeps allow-list, residency, fallback, and diagnostics behavior in `@arnilo/prism-core/governance/model-router`; this package only supplies durable state. Router admission reservations (`reserveBudget`/`commitBudget`/`releaseBudget` on `state.modelRouter`) live in the `reservations` JSONB column of `prism_model_router_budgets`: one atomic UPSERT per admission, fencing-token-guarded commit/release in a SERIALIZABLE transaction, and TTL reconciliation as unknown usage; see [Model routing](model-routing.md).
|
|
206
206
|
- `createPostgresErpMessaging({ pool, schema? })` is the direct messaging composition. `outbox.append` and `inbox.record` accept a caller-owned `PoolClient`; the host must put them in the same transaction as its local mutation. The dispatcher owns only short claim/transition transactions and never invokes business callbacks or stores executable handlers.
|
|
207
207
|
- `createPostgresApprovalStore({ pool, schema?, authority })` is the direct approval composition (migration 005). `authority.resolveRoles(actor, request)` and `policyRevision` are host-owned; Prism persists only accepted role grants and delegation chains. `decide`/`revoke` lock the request row and revision-check the terminal transition in one transaction. `consume` accepts an optional caller-owned `client`; grant consumption and the protected action commit (or roll back) together.
|
|
208
208
|
- Rate/budget/circuit tables are capped like the memory store: `consumeRate`/`readBudget`/`addUsage`/`reserveBudget` accept `maxRateKeys`/`maxBudgetKeys` (the router passes its resolved limits) and evict the least-recently-used row on new-key insert — never the row just inserted, never a budget row holding an active reservation — else fail closed with `ERR_PRISM_MODEL_ROUTER_STATE`. Cleanup prunes expired reservations within its bounded batch.
|
|
209
209
|
- Policy/evaluation/query public contracts stay in their owning packages. This package exports `createPostgresEnterpriseState`, `createPostgresApprovalStore`, `createPostgresErpMessaging`, their options/result/types, and `EnterprisePostgresError`; it has no SQL, DDL, codec, queryable, or migration subpath.
|
|
210
210
|
- The fixed schema has no generic key/value table and no background cleanup scheduler. Schedule `state.cleanup()` from an authorized host job, size its bounded batch for the deployment, and monitor unknown work rows for reconciliation. Run protected integration checks with `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres`; the command rejects an absent URL instead of silently skipping database coverage.
|
|
211
|
-
- The OPA adapter (`@arnilo/prism-policy/opa`, 0.0.28) records decisions into the same `state.policy` store unchanged via `evaluateAndAppend` — see [Policy and audit](policy-and-audit.md#opa-external-policy-adapter-arniloprism-policyopa-008).
|
|
211
|
+
- The OPA adapter (`@arnilo/prism-core/governance/policy/opa`, 0.0.28) records decisions into the same `state.policy` store unchanged via `evaluateAndAppend` — see [Policy and audit](policy-and-audit.md#opa-external-policy-adapter-arniloprism-policyopa-008).
|
|
212
212
|
- Request-path state SQL uses `SELECT`, `INSERT`, `UPDATE`, and `DELETE` on the eight state tables. The open/migration lifecycle additionally needs schema/catalog/advisory-lock and DDL permissions. Use a deployment migration principal for that lifecycle and a least-privilege request role for request traffic; this release intentionally does not ship a migration CLI or worker.
|
|
213
213
|
|
|
214
214
|
## Security and performance notes
|
package/docs/evaluations.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-evals` adds optional deterministic scorers, immutable datasets, bounded persistence-trace grading, explicit host model judges, pairwise comparisons, CI thresholds, live post-run scoring, and batch experiments over `AgentRunResult`. Scores are finite numbers in `[0, 1]` with optional reason/metadata and linkage to run/session/trace/experiment IDs.
|
|
5
|
+
`@arnilo/prism-core/governance/evals` adds optional deterministic scorers, immutable datasets, bounded persistence-trace grading, explicit host model judges, pairwise comparisons, CI thresholds, live post-run scoring, and batch experiments over `AgentRunResult`. Scores are finite numbers in `[0, 1]` with optional reason/metadata and linkage to run/session/trace/experiment IDs.
|
|
6
6
|
|
|
7
7
|
## When to use it
|
|
8
8
|
|
|
9
|
-
Use this package when a host needs offline quality checks or sampled live scoring without coupling scorers into core agent execution. Install it directly or through `@arnilo/prism-
|
|
9
|
+
Use this package when a host needs offline quality checks or sampled live scoring without coupling scorers into core agent execution. Install it directly or through the `@arnilo/prism-core` family package; installation does not attach scorers to runs.
|
|
10
10
|
|
|
11
11
|
## Inputs / request
|
|
12
12
|
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
defineScorer,
|
|
61
61
|
runExperiment,
|
|
62
62
|
scoreRunLive,
|
|
63
|
-
} from "@arnilo/prism-evals";
|
|
63
|
+
} from "@arnilo/prism-core/governance/evals";
|
|
64
64
|
|
|
65
65
|
const scorer = defineScorer({
|
|
66
66
|
id: "contains-citation",
|
|
@@ -145,7 +145,7 @@ assertEvaluationThreshold(report, { minimumMean: 0.9, maximumFailures: 0 });
|
|
|
145
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
146
|
|
|
147
147
|
```ts
|
|
148
|
-
import { datasetFromRuns, defineDataset } from "@arnilo/prism-evals";
|
|
148
|
+
import { datasetFromRuns, defineDataset } from "@arnilo/prism-core/governance/evals";
|
|
149
149
|
|
|
150
150
|
const result = await datasetFromRuns({
|
|
151
151
|
runIds: ["run_9f2", "run_a71"],
|
|
@@ -169,16 +169,16 @@ Omit `toItem` and the default mapping is used: `input` = first user message, `ex
|
|
|
169
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
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
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.
|
|
172
|
+
Prompt versions can ride the same primitives: [`assertPromptPromotion`](prompt-registry.md#eval-gated-promotion) in `@arnilo/prism-core/governance/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
173
|
|
|
174
174
|
## Coding and browser adversarial evaluations (0.0.9)
|
|
175
175
|
|
|
176
176
|
Release 0.0.9 ships curated network-free adversarial fixtures in package tests:
|
|
177
177
|
|
|
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.
|
|
178
|
+
- `@arnilo/prism-coding-tools/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.
|
|
179
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.
|
|
180
180
|
|
|
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`.
|
|
181
|
+
Fixtures reuse `@arnilo/prism-core/governance/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`.
|
|
182
182
|
|
|
183
183
|
## PostgreSQL enterprise state (0.0.23)
|
|
184
184
|
|
|
@@ -214,7 +214,7 @@ The protected runner (`scripts/phase27-erp-journey.test.mjs`) carries the journe
|
|
|
214
214
|
### Hard-gate usage
|
|
215
215
|
|
|
216
216
|
```ts
|
|
217
|
-
import { createErpInvariantScorers, erpInvariantDataset, scoreRun } from "@arnilo/prism-evals";
|
|
217
|
+
import { createErpInvariantScorers, erpInvariantDataset, scoreRun } from "@arnilo/prism-core/governance/evals";
|
|
218
218
|
|
|
219
219
|
const scorers = createErpInvariantScorers();
|
|
220
220
|
const records = await scoreRun({
|
package/docs/extensions.md
CHANGED
|
@@ -140,9 +140,9 @@ await kernel.middleware.run("provider_request", { metadata: {} });
|
|
|
140
140
|
- [Compaction and retry policies](compaction-and-retry.md): compaction strategy/retry policy contributions and `compaction`/`retry` middleware runtime behavior.
|
|
141
141
|
- [LLM compaction package](compaction-llm.md): optional extension helper that registers a provider-backed compaction strategy.
|
|
142
142
|
- [Observational memory compaction package](compaction-observational-memory.md): optional extension helper that registers an inert fast memory compaction strategy.
|
|
143
|
-
- [Caveman behavior integration](caveman.md): optional `@arnilo/prism-caveman` upstream Caveman skills, commands, level injector, and session `caveman-level` persistence.
|
|
144
|
-
- [Ponytail behavior integration](ponytail.md): optional `@arnilo/prism-ponytail` upstream Ponytail skills, commands, mode injector, and session `ponytail-mode` persistence.
|
|
145
|
-
- [Impeccable behavior integration](impeccable.md): optional `@arnilo/prism-impeccable` upstream Impeccable skill and `load_skill` command.
|
|
143
|
+
- [Caveman behavior integration](caveman.md): optional `@arnilo/prism-coding-tools/caveman` upstream Caveman skills, commands, level injector, and session `caveman-level` persistence.
|
|
144
|
+
- [Ponytail behavior integration](ponytail.md): optional `@arnilo/prism-coding-tools/ponytail` upstream Ponytail skills, commands, mode injector, and session `ponytail-mode` persistence.
|
|
145
|
+
- [Impeccable behavior integration](impeccable.md): optional `@arnilo/prism-coding-tools/impeccable` upstream Impeccable skill and `load_skill` command.
|
|
146
146
|
- [Public contracts](public-contracts.md): `Extension`, `ExtensionAPI`, and contribution contract types.
|
|
147
147
|
- [Credentials and redaction](credentials-and-redaction.md): secret-redaction behavior used for extension errors.
|
|
148
148
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`createGitHubForge` is an optional host-activated adapter in `@arnilo/prism-coding-agent` for the six **proven** GitHub operations: issue context read, authenticated push, pull-request create/update, review comments, and check/status retrieval, plus bounded handoff reconciliation. It is GitHub-first by freeze decision — there is no multi-forge generic abstraction, and no octokit dependency: HTTP uses Node's global `fetch` with a bounded streaming reader, timeout, and rate-limit backoff; push reuses the existing `BoundGitRunner` with the token injected via `GIT_CONFIG_*` environment variables (`http.extraHeader`) — never argv, never persisted, never in logs/events. Every mutation flows through Phase 8 approval (`ExecutionPolicy`) and Phase 7 `ToolEffectStore` idempotency keys; a retry after a completed call returns the existing record instead of duplicating the PR or comment.
|
|
5
|
+
`createGitHubForge` is an optional host-activated adapter in `@arnilo/prism-coding-tools/agent` for the six **proven** GitHub operations: issue context read, authenticated push, pull-request create/update, review comments, and check/status retrieval, plus bounded handoff reconciliation. It is GitHub-first by freeze decision — there is no multi-forge generic abstraction, and no octokit dependency: HTTP uses Node's global `fetch` with a bounded streaming reader, timeout, and rate-limit backoff; push reuses the existing `BoundGitRunner` with the token injected via `GIT_CONFIG_*` environment variables (`http.extraHeader`) — never argv, never persisted, never in logs/events. Every mutation flows through Phase 8 approval (`ExecutionPolicy`) and Phase 7 `ToolEffectStore` idempotency keys; a retry after a completed call returns the existing record instead of duplicating the PR or comment.
|
|
6
6
|
|
|
7
7
|
| Export | Purpose |
|
|
8
8
|
| --- | --- |
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
Use when a coding agent needs to open/update PRs, comment on reviews, push a branch with scoped credentials, or verify handoff state against GitHub before deciding the next step. Do not use as a general GitHub SDK, an auto-merge engine (`reconcileHandoff` never merges), or a replacement for host-owned App installation flows — the adapter resolves credentials through the host's `CredentialResolverSource`-compatible resolver and never stores them.
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
|
-
import { createGitHubForge } from "@arnilo/prism-coding-agent";
|
|
21
|
+
import { createGitHubForge } from "@arnilo/prism-coding-tools/agent";
|
|
22
22
|
|
|
23
23
|
const forge = createGitHubForge({
|
|
24
24
|
credentials: { name: "github", resolver: myCredentialResolver }, // App installation token preferred; PAT allowed
|
|
@@ -75,7 +75,7 @@ Every mutation result is recorded in the `effectStore` with a stable key derived
|
|
|
75
75
|
## Implementation example
|
|
76
76
|
|
|
77
77
|
```ts
|
|
78
|
-
import { createGitHubForge } from "@arnilo/prism-coding-agent";
|
|
78
|
+
import { createGitHubForge } from "@arnilo/prism-coding-tools/agent";
|
|
79
79
|
|
|
80
80
|
const forge = createGitHubForge({
|
|
81
81
|
credentials: { name: "github-app", resolver },
|
package/docs/graft.md
CHANGED
|
@@ -14,7 +14,7 @@ Use it when a host wants agents to locate code by architecture, callers, and cou
|
|
|
14
14
|
- `"push"` — per-turn retrieval pack (pointers only) + first-turn orientation, injected automatically.
|
|
15
15
|
- `"both"` — everything.
|
|
16
16
|
|
|
17
|
-
Install optional peer `@nanonets/graft@^0.
|
|
17
|
+
Install optional peer `@nanonets/graft@^0.16.0` **or** pass `packageRoot`/`cliPath` explicitly. Pair with progressive disclosure: the `graft` skill body stays small; tool schemas carry the details. Graft complements indexed code search (`repository_search`): graph/semantic locators vs literal search — neither replaces the other.
|
|
18
18
|
|
|
19
19
|
Zero-code alternative (L0): hosts can skip this package entirely and let agents call `graft <command> --json` through their shell tool, optionally seeding context with graft's own generated instruction files. This package exists for native-tool ergonomics, budgeted subprocesses, session persistence, and push mode.
|
|
20
20
|
|
|
@@ -105,7 +105,7 @@ await kernel.load([
|
|
|
105
105
|
- Import alone registers nothing (`sideEffects: false`); no timers, watchers, or network. The only child processes are budgeted graft CLI calls.
|
|
106
106
|
- Retrieval happens in-process via Prism primitives (context provider, injector, tool_result middleware) — no external hook shims.
|
|
107
107
|
- Ask result shape is parsed tolerantly (`nodes|results|matches|hits`) because graft is pre-1.0; formatters emit pointers (`title` + `file:line` + `[[wikilink]]`), never source bodies.
|
|
108
|
-
- Not included in `@arnilo/prism-
|
|
108
|
+
- Not included in `@arnilo/prism-coding-tools`, `@arnilo/prism-core`, or the `prism-all` umbrella (deliberate opt-out, like Caveman/Ponytail) — opt-in install only.
|
|
109
109
|
- Multi-repo layouts work as upstream graft defines them (workspaces, submodules with `--follow-submodules`, sibling repos); point `projectDir` at the graft root that owns the target repo.
|
|
110
110
|
|
|
111
111
|
## Security and performance notes
|
package/docs/guardrails.md
CHANGED
|
@@ -76,7 +76,7 @@ Guardrails are callbacks supplied by the host. Prism does not discover, load, re
|
|
|
76
76
|
|
|
77
77
|
## Security and performance notes
|
|
78
78
|
|
|
79
|
-
Optional `@arnilo/prism-policy` can record guardrail outcomes via `recordGuardrailDecision` (evidence refs only; see [Policy and audit](policy-and-audit.md)).
|
|
79
|
+
Optional `@arnilo/prism-core/governance/policy` can record guardrail outcomes via `recordGuardrailDecision` (evidence refs only; see [Policy and audit](policy-and-audit.md)).
|
|
80
80
|
|
|
81
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
|
|
package/docs/host-security.md
CHANGED
|
@@ -26,17 +26,17 @@ Start from explicit host inputs. Do not let runtime code discover security state
|
|
|
26
26
|
| Tool allow-list | active tools for this agent/session/run | `createToolRegistry`, `filterTools()`, `dispatchToolCall()` |
|
|
27
27
|
| Tool argument rules | host validator | `AgentConfig.validator`, `RunOptions.validate`, `ToolValidator` |
|
|
28
28
|
| Guardrail decisions | host callback allow/block/tripwire policy | `Guardrails`, `Guardrail`, `GuardrailError` |
|
|
29
|
-
| Coding execution policy | path/command approval adapter | `ExecutionPolicy`, `@arnilo/prism-coding-security` |
|
|
29
|
+
| Coding execution policy | path/command approval adapter | `ExecutionPolicy`, `@arnilo/prism-coding-tools/security` |
|
|
30
30
|
| Remote media policy | public/default pinned DNS or explicit trusted transport | `SsrfPolicy`, `resolveMediaContentBlock()` |
|
|
31
31
|
| Durable history | host database adapter | `SessionStore`, `assertSessionStoreConforms()` |
|
|
32
32
|
| Durable audit | host ledger adapter | `RunLedger`, `redactRunLedgerRecord()` |
|
|
33
33
|
| Telemetry | host OpenTelemetry SDK/exporter | metadata-only adapter, controlled metric labels, `onTraceReference` |
|
|
34
34
|
| Durable interruption | host checkpoint + session stores, exact ownership | `RunOptions.runState`, `resumeAgentRun()`, `createAgentRunLifecycle()`, `createSecureAgent()` |
|
|
35
35
|
| Extensions | explicit package imports only | `createExtensionKernel`, `ExtensionAPI` |
|
|
36
|
-
| Remote agent/workflow API | host authentication + ownership mapping | `@arnilo/prism-server`, `createPrismHandler()` |
|
|
37
|
-
| Authenticated identity | host `IdentityVerifier` → verified `AgentIdentity`; optional OIDC/JWKS reference adapter (`@arnilo/prism-credentials
|
|
38
|
-
| Policy decision audit | optional redacted ledger + host WORM sink | [Policy and audit](policy-and-audit.md), `@arnilo/prism-policy` |
|
|
39
|
-
| Durable enterprise state | host PostgreSQL pool, TLS, exact owner/principal projection, migration/runtime database roles, backup and explicit cleanup schedule | [Enterprise PostgreSQL state](enterprise-postgres-state.md), `@arnilo/prism-enterprise
|
|
36
|
+
| Remote agent/workflow API | host authentication + ownership mapping | `@arnilo/prism-core/runtime/server`, `createPrismHandler()` |
|
|
37
|
+
| Authenticated identity | host `IdentityVerifier` → verified `AgentIdentity`; optional OIDC/JWKS reference adapter (`@arnilo/prism-core/credentials/node/oidc`, pinned issuer/audience/JWKS, fail closed) | [Agent identity](agent-identity.md), `assertIdentityActive`, `narrowIdentity` |
|
|
38
|
+
| Policy decision audit | optional redacted ledger + host WORM sink | [Policy and audit](policy-and-audit.md), `@arnilo/prism-core/governance/policy` |
|
|
39
|
+
| Durable enterprise state | host PostgreSQL pool, TLS, exact owner/principal projection, migration/runtime database roles, backup and explicit cleanup schedule | [Enterprise PostgreSQL state](enterprise-postgres-state.md), `@arnilo/prism-core/enterprise/postgres` |
|
|
40
40
|
| MCP server exposure | host MCP auth + selected capability list | `createPrismMcpServer()`, `createPrismMcpWebHandler()` |
|
|
41
41
|
|
|
42
42
|
## Outputs / response / events
|
|
@@ -139,7 +139,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
|
|
|
139
139
|
- Redaction is exact known-secret replacement only. It is not arbitrary secret detection, entropy scanning, or DLP.
|
|
140
140
|
- Known secrets must be passed into redactors before data is emitted or persisted. Redact again in host adapters if they transform records after Prism redaction.
|
|
141
141
|
- OpenAI Realtime sessions require a stable host owner identifier, use header-only credentials, and bind to the server `session.created` id. Treat returned audio/transcripts as untrusted; use a `SecretRedactor`, retain finite event/byte/wall caps, and close on disconnect or an identity/budget breach.
|
|
142
|
-
- Tool `parameters` metadata is not validated by default. Add a `ToolValidator`, use `createToolParameterValidator()` with a schema adapter, or install `@arnilo/prism-
|
|
142
|
+
- Tool `parameters` metadata is not validated by default. Add a `ToolValidator`, use `createToolParameterValidator()` with a schema adapter, or install `@arnilo/prism-core/validation/json-schema` before side effects. Its untrusted-schema adapter rejects non-local refs, forbidden keys/cycles/non-finite values and bounds bytes/depth/properties/keywords/refs plus its LRU cache before Ajv compilation; do not raise caps above documented hard limits.
|
|
143
143
|
- RAG `replaceSource()` only accepts a store with scoped `getBySource()` plus a real transaction; it stages bounded embeddings before mutation and otherwise fails closed. `deleteSource()` rechecks returned tenant/resource/corpus/source metadata. `createResourceDocumentLoader()` receives only a host-authorized `ResourceLoader`; `createWebFetchDocumentLoader()` never opens I/O and rejects local/private/IP-literal URLs before delegating to host-configured web-tools. HTML scripts/styles are stripped, PDF parsing has byte/page/time caps and rejects compressed PDFs.
|
|
144
144
|
- RAG retrieval always emits `trust: { untrusted: true, inert: true, injectionCapable: true }` plus attributable citation provenance. Context blocks repeat this metadata and never gain tool authority. Host `Reranker`s see redacted finite candidates, are hard-capped by bytes/time/concurrency, must return only a permutation of candidate IDs, and cannot overwrite provenance/trust. Ingestion status errors are redacted; status storage/listing stays exact-scope and capped.
|
|
145
145
|
- Treat embeddings as untrusted numeric input. `@arnilo/prism-memory` rejects empty, non-number, NaN, and infinite vectors before in-memory similarity, pgvector parameters, export, or rebuild; custom `Embedder`/`VectorStore` implementations must retain the same boundary. Memory entries carry consent/source/visibility; revoked/invisible entries never enter prompts, events, exports, or telemetry. `exportMemory()` additionally excludes consent-less legacy records regardless of recall mode and requires exact host identity equal to its tenant/resource/thread scope. Save rebuild cursors only in host-authorized storage; `rebuildIndex()` is one abortable capped page, never an implicit corpus job. `forget`/`applyRetention` are real bounded deletes.
|
|
@@ -149,19 +149,19 @@ Wire those values where they matter: provider adapters receive the resolved cred
|
|
|
149
149
|
- AG-UI fields stay untrusted after schema validation. `input.project` returns host-selected messages/handoffs only; never merge state/tools/context/props into ownership, identity, permissions, provider options, or media policy. Apply Prism media SSRF/MIME bounds before resolution; output projectors are bounded allow-lists; interrupt edits deny rather than mutate persisted calls.
|
|
150
150
|
- AG-UI MCP Apps requires negotiated `mcpApps`, exact proxy origin/auth, owned-run context, approval, one bridge, separate-origin sandbox (`allow-scripts allow-same-origin`), and no-wider CSP. Never execute HTML in host origin or retry a UI mutation; Task 4 adds recovery.
|
|
151
151
|
- AG-UI A2A requires exact-origin verified client, host-owned task selection/correlation, explicit data/tool/A2UI projection, and reauthorized follow/cancel.
|
|
152
|
-
- `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. The artifact review service (`createArtifactService`) requires authenticated identity + thread ownership on every attach/revise/compare/approve/reject/download, resolves concurrent reviewers via checkpoint CAS (no lost approvals), rejects local filesystem paths in `uri`/citations, redacts records before persist and on response, and serves downloads only through signed expiring links that are reauthorized against the token's ownership per request. When a blob store is wired (`bodies: ArtifactBodyStore`, 0.0.28), delivery links additionally resolve through `bodies.presign`; the reference `createS3ArtifactBodyStore` verifies ownership on every operation, verifies size/SHA-256/MIME on put and get (fail closed), refuses delete under legal hold (host `isHeld` callback), keeps credentials host-resolved, and never discloses bucket/path/key in errors, telemetry, or artifact records. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache. Outbound lifecycle webhooks (`createWebhookNotifier`, 0.3.2) share the same boundary posture: host-registered public HTTPS (or explicitly opted-in loopback HTTP) targets only, private/metadata literals rejected at registration, every attempt DNS-pinned and redirect-free through core `pinnedFetch`, redaction before HMAC signing, and the key held by the host only. Pass a known-secret `SecretRedactor`.
|
|
153
|
-
- Coding tools from `@arnilo/prism-coding-agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. They enforce finite text-scan/image/edit/write/shell limits, repository list/search depth/entry/match/scan/time caps, structured Git path/ref/message/output/patch/worktree caps, named-check concurrency/output caps, a 600-second default shell wall time, and a 64 MiB default total-output ceiling. Opt-in `createGitTools()` uses argument arrays with hooks/credential prompts/external diff disabled, requires host `commitIdentity` for commits, and never pushes or opens PRs. Successful truncated shell output leaves a host-owned exclusive `0600` temp file; delete `metadata.fullOutputPath` after use. Error/abort/timeout/overflow removes unpublished spills. Custom read/edit/shell/repository backends must honor supplied caps/signals. Use `@arnilo/prism-coding-security` for path roots, command rules, identity-scoped approval caching, required `workspaceMode` on `createSandboxCodingComposition()` / `createSandboxCodingTools()`, and the optional `createDockerSandbox()` reference adapter. **Host mode is never contained execution** (every isolation capability false). Sandbox mode reports isolation only from validated adapter capability metadata: `composition.capabilities` carries the frozen `SandboxCapabilities` object (`workspaceCoherent`, `filesystemIsolated`, `networkIsolated`, `processIsolated`, `privilegeIsolated`, `egressRestricted`); the deprecated `containmentClaim` is a conservative projection and must never be used alone. Authorize security-sensitive actions from the individual capabilities the policy actually needs — e.g. require `filesystemIsolated` before hosting untrusted coding tasks, and `egressRestricted` before any network-capable run. Mixed wiring requires `allowMixedWorkspaceWiring` and still reports no isolation. Limits alone are not containment: construct the Docker adapter (absolute CLI, digest-pinned image, network none by default) or an equivalent host sandbox before treating coding execution as production-safe. Docker daemon/image trust, egress firewall/proxy, and artifact retention remain host-owned.
|
|
154
|
-
- Allow-list egress (0.0.26, `@arnilo/prism-coding-security`): `createEgressPolicy()` is deny-all with exact host/port/protocol rules and frozen `npm-registry`/`github` presets; `createAllowListEgressProxy()` is an HTTP forward proxy + CONNECT tunnel that pins DNS answers and verifies the connected address (rebinding defense), denies private/link-local/metadata ranges unless a rule opts in, re-validates every redirect hop against policy, and cuts oversized/slow transfers at frozen byte/time caps. TLS passes through without interception. Every allow/deny writes an audit record with no secrets. The proxy is inert until `start()`; `reloadPolicy()` is the only rule change path. `composeEgressSandboxNetwork(proxy.attestation(), name)` records validated attestation as `prism.egress.*` container labels — evidence, not enforcement: the host must restrict the Docker network so the proxy is the only reachable path, and `denyDirectEgress: true` is a claim the host makes true by topology. The proxy is not a firewall and cannot stop a container whose network reaches the internet directly.
|
|
152
|
+
- `@arnilo/prism-core/runtime/server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. The artifact review service (`createArtifactService`) requires authenticated identity + thread ownership on every attach/revise/compare/approve/reject/download, resolves concurrent reviewers via checkpoint CAS (no lost approvals), rejects local filesystem paths in `uri`/citations, redacts records before persist and on response, and serves downloads only through signed expiring links that are reauthorized against the token's ownership per request. When a blob store is wired (`bodies: ArtifactBodyStore`, 0.0.28), delivery links additionally resolve through `bodies.presign`; the reference `createS3ArtifactBodyStore` verifies ownership on every operation, verifies size/SHA-256/MIME on put and get (fail closed), refuses delete under legal hold (host `isHeld` callback), keeps credentials host-resolved, and never discloses bucket/path/key in errors, telemetry, or artifact records. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache. Outbound lifecycle webhooks (`createWebhookNotifier`, 0.3.2) share the same boundary posture: host-registered public HTTPS (or explicitly opted-in loopback HTTP) targets only, private/metadata literals rejected at registration, every attempt DNS-pinned and redirect-free through core `pinnedFetch`, redaction before HMAC signing, and the key held by the host only. Pass a known-secret `SecretRedactor`.
|
|
153
|
+
- Coding tools from `@arnilo/prism-coding-tools/agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. They enforce finite text-scan/image/edit/write/shell limits, repository list/search depth/entry/match/scan/time caps, structured Git path/ref/message/output/patch/worktree caps, named-check concurrency/output caps, a 600-second default shell wall time, and a 64 MiB default total-output ceiling. Opt-in `createGitTools()` uses argument arrays with hooks/credential prompts/external diff disabled, requires host `commitIdentity` for commits, and never pushes or opens PRs. Successful truncated shell output leaves a host-owned exclusive `0600` temp file; delete `metadata.fullOutputPath` after use. Error/abort/timeout/overflow removes unpublished spills. Custom read/edit/shell/repository backends must honor supplied caps/signals. Use `@arnilo/prism-coding-tools/security` for path roots, command rules, identity-scoped approval caching, required `workspaceMode` on `createSandboxCodingComposition()` / `createSandboxCodingTools()`, and the optional `createDockerSandbox()` reference adapter. **Host mode is never contained execution** (every isolation capability false). Sandbox mode reports isolation only from validated adapter capability metadata: `composition.capabilities` carries the frozen `SandboxCapabilities` object (`workspaceCoherent`, `filesystemIsolated`, `networkIsolated`, `processIsolated`, `privilegeIsolated`, `egressRestricted`); the deprecated `containmentClaim` is a conservative projection and must never be used alone. Authorize security-sensitive actions from the individual capabilities the policy actually needs — e.g. require `filesystemIsolated` before hosting untrusted coding tasks, and `egressRestricted` before any network-capable run. Mixed wiring requires `allowMixedWorkspaceWiring` and still reports no isolation. Limits alone are not containment: construct the Docker adapter (absolute CLI, digest-pinned image, network none by default) or an equivalent host sandbox before treating coding execution as production-safe. Docker daemon/image trust, egress firewall/proxy, and artifact retention remain host-owned.
|
|
154
|
+
- Allow-list egress (0.0.26, `@arnilo/prism-coding-tools/security`): `createEgressPolicy()` is deny-all with exact host/port/protocol rules and frozen `npm-registry`/`github` presets; `createAllowListEgressProxy()` is an HTTP forward proxy + CONNECT tunnel that pins DNS answers and verifies the connected address (rebinding defense), denies private/link-local/metadata ranges unless a rule opts in, re-validates every redirect hop against policy, and cuts oversized/slow transfers at frozen byte/time caps. TLS passes through without interception. Every allow/deny writes an audit record with no secrets. The proxy is inert until `start()`; `reloadPolicy()` is the only rule change path. `composeEgressSandboxNetwork(proxy.attestation(), name)` records validated attestation as `prism.egress.*` container labels — evidence, not enforcement: the host must restrict the Docker network so the proxy is the only reachable path, and `denyDirectEgress: true` is a claim the host makes true by topology. The proxy is not a firewall and cannot stop a container whose network reaches the internet directly.
|
|
155
155
|
- Optional `@arnilo/prism-web-tools/browser` requires a host-supplied Playwright Browser (`playwright-core@1.61.0` peer). Import is inert. One non-persistent context belongs to one run; actions serialize; refs are snapshot-scoped; CSS/evaluate/CDP/persistent profiles are denied. Context routing + `serviceWorkers: "block"` deny file/data/blob/devtools/private/loopback by default and require contained-proxy attestation for external egress (Playwright routing is defense in depth, not DNS containment). Uploads are realpath-rooted; downloads quarantine with hash/MIME until host `approveRelease`; screenshots return bounded `ImageContent`. Observation vs mutation/high-impact actions map to `ExecutionPolicy`. Treat snapshot/page text as untrusted external content. Close contexts with `browser_close` or `manager.closeRun(runId)` on abort/terminal. Browser control endpoint, binary/image pin, and real egress firewall/proxy remain host-owned. Shared sandbox: `createSharedSandboxBrowserOptions()` + `assertBrowserSandboxNetwork()`.
|
|
156
156
|
- Browser verified-state checkpoints (0.0.14, `createBrowserCheckpointLedger()`) store URL + domain-state hash + host data refs only — never serialized browser internals (cookies/storage/contexts). After any resume/interruption the ledger fails closed (`assertVerifiedBeforeSideEffect`) until the host reloads + verifies, so side effects never replay on stale state.
|
|
157
157
|
- Device adapters (0.0.14, `resolveDevicePolicy`/`assertDeviceAdmit`) are deny-by-default: admission fails closed without explicit `enabled`, an explicit sandbox, approval (when required), an under-budget session count, and shared `RunLimits`. Stream chunks over the frozen cap are dropped with a marker; telemetry is redacted before emit/persist. No vendor voice/desktop package ships in 0.0.14 (demand-gated 0.1.x); device adapters cannot broaden consent/memory/network/file/browser/connector/tool permissions (gate 8).
|
|
158
|
-
- Optional `@arnilo/prism-wiki` tools treat agent-supplied input as untrusted at the first-party `.wiki/` filesystem boundary. `wiki_read_page` enforces lexical containment (`path.relative` with separator-aware `..`/absolute checks) plus `fs.realpath` containment for the wiki root and every successfully read file, so sibling-prefix (`.wiki-evil`), `..`, absolute, alternate-separator, and symlink escapes are denied before content is returned; missing contained pages report `found: false` while denied paths throw an access-denied error (never mapped to not-found). `wiki_record_insight` rejects empty titles/content, caps titles at 200 characters and content at 65,536 bytes, and collapses control characters and newlines in titles to single-line display text before any page/frontmatter/index/log write, so titles cannot inject Markdown headings, index entries, or log entries; slugs are allow-listed to `[a-z0-9-_]` with a non-empty fallback. See [LLM Wiki](wiki.md).
|
|
159
|
-
- `@arnilo/prism-credentials
|
|
158
|
+
- Optional `@arnilo/prism-memory/wiki` tools treat agent-supplied input as untrusted at the first-party `.wiki/` filesystem boundary. `wiki_read_page` enforces lexical containment (`path.relative` with separator-aware `..`/absolute checks) plus `fs.realpath` containment for the wiki root and every successfully read file, so sibling-prefix (`.wiki-evil`), `..`, absolute, alternate-separator, and symlink escapes are denied before content is returned; missing contained pages report `found: false` while denied paths throw an access-denied error (never mapped to not-found). `wiki_record_insight` rejects empty titles/content, caps titles at 200 characters and content at 65,536 bytes, and collapses control characters and newlines in titles to single-line display text before any page/frontmatter/index/log write, so titles cannot inject Markdown headings, index entries, or log entries; slugs are allow-listed to `[a-z0-9-_]` with a non-empty fallback. See [LLM Wiki](wiki.md).
|
|
159
|
+
- `@arnilo/prism-core/credentials/node` rejects oversized/malformed envelopes and excessive scrypt work before KDF allocation, uses async scrypt, and requires restrictive existing/new Unix vault modes. Keep vault ownership and parent-directory access host-controlled; review before `chmod 600`, never auto-weaken a file policy. Keychain calls use abort-aware native async work with finite timeout/payload caps and sanitized errors. OS prompts, service availability, and whether a native backend promptly honors cancellation remain host/platform boundaries; no plaintext fallback is attempted.
|
|
160
160
|
- LLM compaction always sends finite summary `maxTokens`, retains bounded deltas/events, and bounds/redacts provider/factory/policy error detail. Observational-memory workers cap turns, calls, arguments, results, transcript, and surfaced errors; unknown tools fail before execution, while invalid results can only be rejected after a host tool returns and may therefore follow side effects. Pass all known provider/credential/tool secrets into compaction/runtime options; exact replacement is not secret discovery.
|
|
161
161
|
- Default remote-media loading resolves every DNS answer, rejects the hostname if any address is non-public, and pins one validated address through the request. Explicit `allowedHostnames` can trust private destinations. A host-supplied `fetch` owns DNS/rebinding/proxy/redirect safety; a custom `requestUrl` must connect to its supplied validated address.
|
|
162
162
|
- Permission checks happen before tool validation and before `tool.execute()`. Middleware cannot grant permission by renaming a tool.
|
|
163
163
|
- Session stores and ledgers receive redacted values when a redactor is active, but durable storage remains host-owned. Enforce tenant/account/user ownership, retention, legal hold, and quotas via `ProductionPersistenceStore.lifecycle` (or host-equivalent DB controls). Hold always blocks delete.
|
|
164
|
-
- `@arnilo/prism-enterprise
|
|
164
|
+
- `@arnilo/prism-core/enterprise/postgres` request paths require exact tenant scope plus principal for work/router state, use bound SQL values, and retain no prompts, connector request bodies, raw provider results, tokens, or credentials. Configure TLS/credential rotation/connection limits with the host `pg` pool. Run checksum/catalog migration setup with a controlled migration principal; keep request-path SQL least-privilege (`USAGE`, `SELECT`, `INSERT`, `UPDATE`, `DELETE` on six state tables) and do not grant request workers `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `GRANT`, or `COPY PROGRAM`. Back up and restore-test the schema; run bounded owner-scoped `state.cleanup()` from an authorized host job. `unknown` connector outcomes require reconciliation and must never auto-replay.
|
|
165
165
|
- Prefer `createExtensionKernel({ loadPolicy })` allow-list/signature checks before loading third-party extension packages.
|
|
166
166
|
- Provider-owned auth/content/session/cache/security headers win over caller headers in adapters that merge headers.
|
|
167
167
|
- Security checks are bounded explicit calls on the active path. Prism adds no hidden global middleware, background workers, watchers, network calls, or filesystem scans.
|
|
@@ -190,7 +190,7 @@ PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy
|
|
|
190
190
|
## Web research boundaries
|
|
191
191
|
|
|
192
192
|
- Construct `@arnilo/prism-web-tools` with one host-selected Brave or Exa adapter; never expose adapter/provider/credential/schema selection to model arguments.
|
|
193
|
-
- Construct `@arnilo/prism-work
|
|
193
|
+
- Construct `@arnilo/prism-core/integrations/work` with host-pinned CLI binary + isolated `configDir` + verified `AgentIdentity` (M365 and/or GWS). Never pass model-built command strings, `login`/`setup`/`auth`/`schema`/`--debug`, or credentials in argv. Mutations require draft approval; external recipients and anonymous/`anyone` shares fail closed.
|
|
194
194
|
- Provider API origins are fixed exact HTTPS origins and redirects fail. Credentials resolve immediately before I/O; remote bodies and secrets are excluded from errors/results/telemetry.
|
|
195
195
|
- Firecrawl targets reject userinfo, non-HTTP(S), private literals, and policy-denied hosts. Supply `validateUrl` for host DNS/rebinding/egress checks. Firecrawl performs remote retrieval, so Prism cannot pin target DNS after handoff.
|
|
196
196
|
- Treat every snippet, highlight, Markdown byte, metadata field, and extracted JSON value as prompt-injection-capable untrusted data. Never elevate it into system instructions or let it modify tools, permissions, trust, credentials, routing, or extraction schema.
|
|
@@ -211,8 +211,8 @@ PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy
|
|
|
211
211
|
### 0.1.0 security evidence (plan 012 Task 6)
|
|
212
212
|
|
|
213
213
|
- **Audit policy.** `npm audit --audit-level=moderate` is enforced in both `security.yml` and the `release.yml` supply-chain job (freeze-manifest `releasePolicy.auditLevelTarget`); recorded 0.1.0 tree: 0 vulnerabilities at every severity (317 locked dependencies, MCP SDK at the 1.30.0 fix baseline).
|
|
214
|
-
- **Named threat-suites leg.** `npm run security:threat-suites` aggregates the Phase 8–11 conformance suites (durable-loop/HITL approval, coding sandbox/egress/forge, ACP protocol, OIDC/OPA/MCP-OAuth/OpenAPI/artifact) into one named 0.1.0 security evidence leg — same scripts as `npm test`, no rewrite; the Phase 7 tenant-isolation suite is its protected counterpart under `npm run test:postgres` (missing `PRISM_TEST_POSTGRES_URL` is a named blocked gate). The dev-inspector leg (`scripts/phase40-security.test.mjs`, plan 040 Task 5) exercises the `@arnilo/prism-dev` local playground through built public entrypoints: D1 non-loopback binds refuse before any listener exists (`ERR_PRISM_DEV_REMOTE_BIND`) and loopback is the only bindable surface; D2 the host redactor scrubs secret literals from server-rendered replay payloads; D3 replay selectors outside the `resolveRun` seam's ownership fail closed 404 and replay without a durable event_source is a documented 404, never a re-execution; D4 unknown decision outcome discriminants reject `400` without consuming a run version or executing the tool, and a valid `allow_once` applies exactly once.
|
|
215
|
-
- **Dev-surface boundary (plan 040 Task 5).** The `@arnilo/prism-dev` inspector is a developer-time tool: loopback-only by default, non-loopback requires an explicit programmatic `remoteAuthorize` callback plus a real authorizer (the CLI/bin offers no remote-bind flag at all), and it must never be the production API boundary (that stays `@arnilo/prism-server` under host authorization). It carries no credential storage — the host agent config owns credentials and the inspector never reads environment secrets; rendered tool args/results pass the host redactor on both the live and replay paths, and HITL decision resume composes the core `createAgentRunLifecycle` validation (fail-closed on unknown discriminants/versions/runs).
|
|
214
|
+
- **Named threat-suites leg.** `npm run security:threat-suites` aggregates the Phase 8–11 conformance suites (durable-loop/HITL approval, coding sandbox/egress/forge, ACP protocol, OIDC/OPA/MCP-OAuth/OpenAPI/artifact) into one named 0.1.0 security evidence leg — same scripts as `npm test`, no rewrite; the Phase 7 tenant-isolation suite is its protected counterpart under `npm run test:postgres` (missing `PRISM_TEST_POSTGRES_URL` is a named blocked gate). The dev-inspector leg (`scripts/phase40-security.test.mjs`, plan 040 Task 5) exercises the `@arnilo/prism-coding-tools/dev` local playground through built public entrypoints: D1 non-loopback binds refuse before any listener exists (`ERR_PRISM_DEV_REMOTE_BIND`) and loopback is the only bindable surface; D2 the host redactor scrubs secret literals from server-rendered replay payloads; D3 replay selectors outside the `resolveRun` seam's ownership fail closed 404 and replay without a durable event_source is a documented 404, never a re-execution; D4 unknown decision outcome discriminants reject `400` without consuming a run version or executing the tool, and a valid `allow_once` applies exactly once.
|
|
215
|
+
- **Dev-surface boundary (plan 040 Task 5).** The `@arnilo/prism-coding-tools/dev` inspector is a developer-time tool: loopback-only by default, non-loopback requires an explicit programmatic `remoteAuthorize` callback plus a real authorizer (the CLI/bin offers no remote-bind flag at all), and it must never be the production API boundary (that stays `@arnilo/prism-core/runtime/server` under host authorization). It carries no credential storage — the host agent config owns credentials and the inspector never reads environment secrets; rendered tool args/results pass the host redactor on both the live and replay paths, and HITL decision resume composes the core `createAgentRunLifecycle` validation (fail-closed on unknown discriminants/versions/runs).
|
|
216
216
|
- **Supply-chain negative fixtures.** `scripts/release-gate.test.mjs` verifies the tarball deny list rejects tampered content (plans/reviews/maps/tests), unexpected file types and credential material (native binaries, `.pem`/`.key`/`.p12`), and that a provenance flag suppressed in CI is detectable in the `release.mjs` publish dry-run arguments (`--provenance` mandatory under `GITHUB_ACTIONS`, never claimed on local OIDC-less publishes).
|
|
217
217
|
- **Mandatory gate stack.** CodeQL/SAST, PR dependency review (fail on high), secret scan (source + unpacked tarballs), SPDX SBOM + license policy, tarball allow/deny content checks, and provenance (npm OIDC + GitHub build attestations on tarballs and SBOM) all run in `security.yml`/`release.yml`; evidence for the 0.1.0 tree is recorded in [0.1.0 readiness](0.1.0-readiness.md).
|
|
218
218
|
- **CodeQL query suite.** `.github/codeql/codeql-config.yml` selects the `security-extended` suite for `javascript-typescript` (with the default suite) on push/PR/schedule in `security.yml` (10-minute job bound; measured runtime ~3m22s on the audited SHA, last successful main run `33059128198`). The ignore list covers only generated `dist`, `node_modules`, and release/security artifact directories — first-party packages, threat suites, and fixtures that ship or execute are always scanned, so new alerts enter the same plan-038 ledger/remediation loop (config + guardrails asserted in `scripts/phase38-codeql-regression.test.mjs`). Local Task 6 gates (typecheck/lint/format/threat suites/audit/secret scan/SBOM) pass on the remediations; GitHub `state=open` stays non-zero until those remediations are the analyzed head. Groups G (`js/insufficient-password-hash` on RFC 7636 S256) and H (`js/incomplete-url-substring-sanitization` on a negative docs assertion) are maintainer-reviewed false positives queued for narrow dismissal after that analyze, not code changes.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Image generation and editing
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`ImageGenerationProvider` is the provider-neutral image contract: `generate`
|
|
6
|
+
(prompt→image[s] with size/format/quality/count options) and `edit`
|
|
7
|
+
(image+mask+prompt, reusing the existing `ImageContent` binary content parts).
|
|
8
|
+
Results are `Uint8Array` bytes plus provenance — hosts own persistence; no
|
|
9
|
+
disk writes, no URL-only contract. Adapters ship in
|
|
10
|
+
[`@arnilo/prism-providers/openai`](providers/openai.md) (`/v1/images/generations`,
|
|
11
|
+
`/v1/images/edits`, always `b64_json`) and
|
|
12
|
+
[`@arnilo/prism-providers/alibaba`](providers/alibaba.md) (DashScope wanx async
|
|
13
|
+
task API); offline conformance runs via `runImageGenerationConformance` from
|
|
14
|
+
`@arnilo/prism/testing/provider-conformance`.
|
|
15
|
+
|
|
16
|
+
## When to use it
|
|
17
|
+
|
|
18
|
+
Use it when the host owns image storage and lifecycle and wants portable
|
|
19
|
+
generate/edit calls with typed errors. Do not use it for image *input* to a chat
|
|
20
|
+
model — that is the existing `ImageContent` content part on
|
|
21
|
+
[`ModelConfig`](public-contracts.md) — and do not use the Alibaba adapter for
|
|
22
|
+
edits (DashScope has no first-party image-edit route; it rejects with
|
|
23
|
+
`unsupported_operation`).
|
|
24
|
+
|
|
25
|
+
## Inputs / request
|
|
26
|
+
|
|
27
|
+
| Field | Type | Meaning |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `model` | `string` | e.g. `gpt-image-1` (OpenAI), `wanx2.1-t2i-turbo` (DashScope). |
|
|
30
|
+
| `prompt` | `string` | Non-empty, within the provider cap (OpenAI 32,000 chars, wanx 800). |
|
|
31
|
+
| `images` / `mask` | `ImageContent[]` / `ImageContent?` (edit) | Base64 `data` parts decode inline; `url` parts resolve through `pinnedFetch` (SSRF-guarded, DNS-pinned, byte-bounded). |
|
|
32
|
+
| `size` / `format` / `quality` / `count` | `string?` / `string?` / `string?` / `number?` | Provider-defined vocabulary (`1024x1024`, `png`, `standard`/`hd`, 1–10 OpenAI / 1–4 wanx). |
|
|
33
|
+
| `signal` | `AbortSignal?` | Cancellation; observed by the adapter transport and the DashScope poll loop. |
|
|
34
|
+
|
|
35
|
+
Adapter options: `apiKey` (`CredentialValueSource` — the existing credential
|
|
36
|
+
seam, resolved per call and redacted from errors), `baseUrl`, `fetch` (inject a
|
|
37
|
+
fake transport for offline tests), `fetchUrl` (inject a result/input-image
|
|
38
|
+
downloader; defaults to `pinnedFetch`), `headers`, and `maxImageBytes`.
|
|
39
|
+
|
|
40
|
+
## Outputs / response / events
|
|
41
|
+
|
|
42
|
+
| Field | Type | Meaning |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `images` | `GeneratedImage[]` | One entry per generated image, in provider order. |
|
|
45
|
+
| `images[].bytes` | `Uint8Array` | Decoded image bytes (one allocation per image; no re-encode loops). |
|
|
46
|
+
| `images[].mimeType` | `string` | e.g. `image/png` (from the provider's `output_format` or the request format). |
|
|
47
|
+
| `images[].provider` / `.model` | `string` | Preserved provenance — hosts can attribute stored output. |
|
|
48
|
+
| `images[].url` / `.revisedPrompt` | `string?` | Provider-native passthrough when returned. |
|
|
49
|
+
| `usage` | `Usage?` | Provider-reported usage when available. |
|
|
50
|
+
|
|
51
|
+
Failures throw `ImageGenerationError` with a stable `code`: `empty_input`
|
|
52
|
+
(no prompt / edit without image parts), `input_too_large` (prompt or count over
|
|
53
|
+
cap, over-ceiling input image), `unsupported_operation` (edit on providers
|
|
54
|
+
without an edit route), `request_failed` (non-2xx, failed task, failed download,
|
|
55
|
+
secret-redacted message), `response_malformed` (missing `b64_json`, invalid
|
|
56
|
+
base64, no result URLs), `unsupported_model` (via `assertImageGenerationSupported`
|
|
57
|
+
when the host checks `ModelCapabilities.imageGeneration`).
|
|
58
|
+
|
|
59
|
+
## Request/response example
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{ "model": "gpt-image-1", "prompt": "a red cube", "size": "1024x1024", "n": 1, "response_format": "b64_json" }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Implementation example
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { createOpenAIImageGenerationProvider } from "@arnilo/prism-providers/openai";
|
|
69
|
+
import { createAlibabaImageGenerationProvider } from "@arnilo/prism-providers/alibaba";
|
|
70
|
+
import { runImageGenerationConformance } from "@arnilo/prism/testing/provider-conformance";
|
|
71
|
+
|
|
72
|
+
const images = createOpenAIImageGenerationProvider({ apiKey: process.env.OPENAI_API_KEY });
|
|
73
|
+
const { images: generated } = await images.generate({ model: "gpt-image-1", prompt: "a red cube", size: "1024x1024" });
|
|
74
|
+
// generated[0] = { bytes: Uint8Array, mimeType: "image/png", provider: "openai", model: "gpt-image-1" }
|
|
75
|
+
|
|
76
|
+
const edited = await images.edit({
|
|
77
|
+
model: "gpt-image-1",
|
|
78
|
+
prompt: "make it blue",
|
|
79
|
+
images: [{ type: "image", data: base64Png, mimeType: "image/png" }],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// DashScope wanx: submit + poll + download, wrapped in one call:
|
|
83
|
+
const alibaba = createAlibabaImageGenerationProvider({ apiKey: process.env.DASHSCOPE_API_KEY });
|
|
84
|
+
const wanx = await alibaba.generate({ model: "wanx2.1-t2i-turbo", prompt: "a red cube" });
|
|
85
|
+
|
|
86
|
+
// Offline conformance (fake transport, no network):
|
|
87
|
+
await runImageGenerationConformance({
|
|
88
|
+
provider: createOpenAIImageGenerationProvider({ apiKey: "sk-test", fetch: fakeFetch }),
|
|
89
|
+
model: "gpt-image-1",
|
|
90
|
+
maxPromptChars: 32000,
|
|
91
|
+
sample: { prompt: "a red cube", count: 1 },
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Extension and configuration notes
|
|
96
|
+
|
|
97
|
+
- Implement `ImageGenerationProvider` for other vendors; the contract is
|
|
98
|
+
structural — no base class, no registry. Providers without an edit route
|
|
99
|
+
reject `edit` with `ImageGenerationError("unsupported_operation")` rather
|
|
100
|
+
than pretending.
|
|
101
|
+
- Models declare support with `capabilities.imageGeneration`; hosts gate with
|
|
102
|
+
`modelSupportsImageGeneration` / `assertImageGenerationSupported`, mirroring
|
|
103
|
+
the embeddings/speech guard pattern.
|
|
104
|
+
- The DashScope adapter owns the async-task lifecycle (submit with
|
|
105
|
+
`X-DashScope-Async: enable`, poll until terminal status, download result
|
|
106
|
+
URLs); `pollIntervalMs` and `timeoutMs` tune the loop, and the abort signal
|
|
107
|
+
is honored between polls.
|
|
108
|
+
|
|
109
|
+
## Security and performance notes
|
|
110
|
+
|
|
111
|
+
- API keys resolve through the existing `CredentialValueSource` seam and are
|
|
112
|
+
redacted from every thrown error (`redactSecrets`); no new secret paths.
|
|
113
|
+
- All URL fetches (edit inputs, DashScope result images) go through
|
|
114
|
+
`pinnedFetch` — DNS-pinned, SSRF-guarded, byte-bounded (`maxImageBytes`,
|
|
115
|
+
25 MiB default); responses over the ceiling reject instead of buffering.
|
|
116
|
+
- Prompts and image bytes are never logged; error messages carry status and a
|
|
117
|
+
redacted body only. The contract never touches local disk — bytes return to
|
|
118
|
+
the host.
|
|
119
|
+
- Base64 payloads decode exactly once per image; response mapping allocates
|
|
120
|
+
per-image and nothing else.
|
|
121
|
+
|
|
122
|
+
## Related APIs
|
|
123
|
+
|
|
124
|
+
- [Multimodal content](public-contracts.md): `ImageContent` parts — the edit
|
|
125
|
+
input vocabulary and the chat image-input path.
|
|
126
|
+
- [Provider conformance](provider-conformance.md): `runImageGenerationConformance`
|
|
127
|
+
and the offline conformance matrix.
|
|
128
|
+
- [Provider packages](provider-packages.md): subpath import rules for
|
|
129
|
+
`@arnilo/prism-providers/openai` and `@arnilo/prism-providers/alibaba`.
|