@arnilo/prism 0.0.14 → 0.0.15
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 +11 -2
- package/README.md +5 -4
- package/dist/agent-loops.d.ts +4 -0
- package/dist/agent-loops.js +16 -3
- package/dist/contracts.d.ts +76 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/provider-events.d.ts +1 -0
- package/dist/provider-events.js +3 -0
- package/docs/host-security.md +4 -1
- package/docs/index.md +12 -11
- package/docs/migration.md +29 -1
- package/docs/multimodal-content.md +8 -5
- package/docs/performance.md +34 -0
- package/docs/provider-caching.md +8 -0
- package/docs/provider-conformance.md +29 -5
- package/docs/provider-packages.md +22 -1
- package/docs/providers/ai-sdk.md +23 -7
- package/docs/providers/openai.md +22 -3
- package/docs/rag.md +41 -12
- package/docs/release-and-install.md +62 -14
- package/docs/resource-loading.md +3 -0
- package/docs/review-coverage-2026-07-26-phase-10.md +132 -0
- package/docs/working-and-semantic-memory.md +22 -4
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Phase 10 Review Coverage — 0.0.15 Provider, Memory, and RAG Ecosystem Parity
|
|
2
|
+
|
|
3
|
+
Frozen: 2026-07-26 at Prism `73aec95` (Release 0.0.14). This document is the Task 0 primitive-inventory, scope freeze, limit freeze, and threat/authority matrix for Plan 078. It constrains Tasks 1–9; later tasks may refine API shapes but may not widen permissions or package scope beyond what this matrix authorizes.
|
|
4
|
+
|
|
5
|
+
## 1. Capability traceability (every Phase 10 roadmap criterion → Task owner)
|
|
6
|
+
|
|
7
|
+
| Roadmap acceptance criterion | Existing primitive(s) | Minimum gap | Owner task | Test owner | Docs owner |
|
|
8
|
+
| --- | --- | --- | --- | --- | --- |
|
|
9
|
+
| OpenAI hosted tools / response continuation / realtime without hosted-tool semantics in core | `AIProvider.generate()` (`src/contracts.ts:297`), `ProviderEvent` union (`src/contracts.ts:288`), `ProviderRequest`, `src/providers/openai-compatible.ts`, `packages/provider-openai/src/{responses,codex}.ts` | `ProviderEvent` has no continuation/realtime variant; `ToolCallContent` has no `authority` field; no realtime/continuation/hosted-tool code anywhere | Task 1 | Task 1 | Task 1 + Task 8 |
|
|
10
|
+
| AI SDK tested supported-version matrix + complete content/tool/metadata mapping | `packages/provider-ai-sdk/src/{provider,stream,prompt,errors,types}.ts` | no supported-version matrix; mapping is not table-driven; unsupported fields drop silently | Task 2 | Task 2 | Task 2 + Task 8 |
|
|
11
|
+
| Kimi/ZAI/OpenRouter/OpenCode Go/Alibaba/Ollama/NeuralWatt attributable discovery/cache/reasoning/routing metadata; shared serializers only where wire-identical | per-provider `provider.ts`/`models.ts`; shared `serializeOpenAITool` (`src/providers/openai-primitives.ts:62`); per-provider message serializers (`serializeMoonshotMessage`, `serializeAlibabaMessage`, …) already diverge on `cache_control`/`reasoning_content` | audit each wire; surface routing metadata (OpenRouter) without core leak; confirm shared-serializer extractions on exact match only | Task 3 | Task 3 | Task 3 + Task 8 |
|
|
12
|
+
| Anthropic/Google native (0.0.11) remain under shared offline conformance + restricted live canaries | `packages/provider-{anthropic,google}/src`; `src/testing/provider-conformance.ts` | no re-open; re-confirm conformance + canary wiring | Task 3 (audit only) + Task 7 | Task 3/7 | Task 8 |
|
|
13
|
+
| RAG atomic source replacement, deletion | `indexChunks()` (`packages/rag/src/indexing.ts`) — `ponytail:` comment explicitly defers stale-source replacement to the host; `VectorStore.delete()` exists (`packages/memory/src/types.ts:91`) | add `replaceSource` (tx) + `deleteSource` scoped to `RagScope` | Task 4 | Task 4 | Task 4 + Task 8 |
|
|
14
|
+
| RAG document-loader/parser seams + text/Markdown/HTML/PDF reference adapters | `ResourceLoader` (`src/contracts.ts`), `loadTextResource`/`loadBinaryResource` (`src/resources.ts`); `chunkText`/`chunkMarkdown` (`packages/rag/src/chunk.ts`) | no `DocumentLoader`/`Parser` seam; no format adapters | Task 4 | Task 4 | Task 4 + Task 8 |
|
|
15
|
+
| Public web ingestion reuses bounded web-tools fetch/citations (no second crawler) | `web_fetch`/`web_extract` (`packages/web-tools/src/{exa,firecrawl}.ts`); `WebDocument`/`WebExtraction` with `untrusted: true` + `WebCitation.citationId` (`packages/web-tools/src/types.ts`); `canonicalUrl` SSRF guard (`packages/web-tools/src/normalize.ts:5`) | add a `WebFetchDocumentLoader` wrapper; no new crawler | Task 4 | Task 4 | Task 4 + Task 8 |
|
|
16
|
+
| RAG reranking | `retrieveContext()` (`packages/rag/src/retrieve.ts`), `RagHit`/`RetrieveContextOptions` (`packages/rag/src/types.ts`) | no `Reranker` seam; `RetrieveContextOptions` has no `reranker` | Task 5 | Task 5 | Task 5 + Task 8 |
|
|
17
|
+
| RAG citation provenance + content-trust metadata | `RagCitation`/`RagContextResult` (`packages/rag/src/types.ts:50,77`); web-tools `untrusted: true` precedent | `RagHit` has no provenance/trust fields; assembled context not marked untrusted/inert | Task 5 | Task 5 | Task 5 + Task 8 |
|
|
18
|
+
| RAG ingestion status | `indexChunks` returns `IndexChunksResult` only | no per-source pending/indexed/failed/partial status | Task 5 | Task 5 | Task 5 + Task 8 |
|
|
19
|
+
| Memory finite-vector validation | `assertFiniteVector` (`packages/memory/src/util.ts`); already enforced at embedder, in-memory store, and PostgreSQL/pgvector | add export/rebuild boundary validation; semantic SQLite adapter is not shipped | Task 6 | Task 6 | Task 6 + Task 8 |
|
|
20
|
+
| Memory retention/deletion/export | `applyRetention` + `forget` + `correct` + `grantConsent`/`revokeConsent` already shipped in 0.0.14 (`packages/memory/src/memory.ts:261,249,223,205`) | `exportMemory` (bounded+redacted) and `rebuildIndex` are absent; retention/forget/correct are DONE — do not rebuild | Task 6 | Task 6 | Task 6 + Task 8 |
|
|
21
|
+
| Memory source/consent metadata | `MemoryConsent`/`MemoryConsentInput`/`MemoryConsentScope`/`MemoryConsentSource` shipped 0.0.14 (`packages/memory/src/types.ts`, exported `index.ts:61-64`); `isInjectable` honors consent (`memory.ts:439`) | DONE in 0.0.14 — Task 6 only adds export/rebuild conformance, not new consent shapes | Task 6 | Task 6 | Task 6 + Task 8 |
|
|
22
|
+
| Memory index rebuild | `VectorStore.upsert`/`delete`/`getByThread` | no `rebuildIndex` (bounded, abortable, resumable) | Task 6 | Task 6 | Task 6 + Task 8 |
|
|
23
|
+
| Memory production adapter conformance | `runMemoryConformance` (`packages/memory/src/conformance.ts`); in-memory suite + PostgreSQL/pgvector integration call it | extend conformance to export/rebuild + cross-tenant/thread; confirm PostgreSQL/pgvector parity (semantic SQLite is demand-gated) | Task 6 + Task 7 | Task 6/7 | Task 8 |
|
|
24
|
+
| Additional vector stores demand-gated | none | no new vector-store package this phase | Task 0 (out of scope) | Task 0 guard | Task 8 |
|
|
25
|
+
| Performance: finite byte/token/time/concurrency limits + benchmarks | per-package `limits.ts`; `RagLimits` (`packages/rag/src/limits.ts`) already capped; `MemoryLimits` (`packages/memory/src/limits.ts`) | freeze Phase 10 caps for hosted-tool/realtime/continuation/parse/rerank/rebuild/export; `scripts/benchmark-0.0.15.mjs` | Task 7 | Task 7 | Task 7 + Task 8 |
|
|
26
|
+
| Code Quality: shared transport/serialization primitives; RAG/memory reuse existing contracts | `src/providers/openai-compatible.ts`, `openai-primitives.ts`, `Embedder`/`VectorStore`/`MemoryStore` (`packages/memory/src/types.ts`), `ResourceLoader` | share serializers only on exact wire match; parsers/rerankers are thin seams, not a framework | Task 3/4/5 | per task | Task 8 |
|
|
27
|
+
| Security: credentials host-owned; remote docs SSRF-bounded; retrieved content untrusted inert; source replace/delete scoped | `resolveCredentialValue`, `readBoundedResponseText`, `canonicalUrl`, `isInjectable`, `RagScope`, `MemoryScope` | enforce scope ownership on replace/delete; content-trust metadata on every assembled block | Task 1/4/5/6 | per task | Task 8 |
|
|
28
|
+
|
|
29
|
+
## 2. Package ownership and manifest count
|
|
30
|
+
|
|
31
|
+
- Baseline (0.0.14): **43 publishable manifests** = 42 workspace `packages/*/package.json` + root `@arnilo/prism`. Confirmed all 42 workspace packages `private !== true`.
|
|
32
|
+
- Phase 10 decision: **43 → 43**. No new package authorized. Every Phase 10 capability extends an existing package in place:
|
|
33
|
+
- `@arnilo/prism-provider-openai` ← hosted tools, response continuation, realtime seam (Task 1).
|
|
34
|
+
- `@arnilo/prism-provider-ai-sdk` ← supported-version matrix + typed mapping (Task 2).
|
|
35
|
+
- `@arnilo/prism-provider-{kimi,zai,openrouter,opencode-go,alibaba,ollama,neuralwatt}` ← attributable metadata + justified shared serializers (Task 3).
|
|
36
|
+
- `@arnilo/prism-provider-{anthropic,google}` ← conformance/canary re-confirm only (Task 3 audit + Task 7); no primary-adapter re-open.
|
|
37
|
+
- `@arnilo/prism-rag` ← replaceSource/deleteSource, DocumentLoader/Parser seam + text/Markdown/HTML/PDF + web-fetch loader, Reranker, provenance/trust, ingestion status (Tasks 4–5).
|
|
38
|
+
- `@arnilo/prism-memory` ← exportMemory, rebuildIndex, conformance parity (Task 6). Consent/retention/forget/correct are DONE (0.0.14) — not rebuilt.
|
|
39
|
+
- `@arnilo/prism-web-tools` ← no change; RAG web ingestion consumes its normalized results/citations.
|
|
40
|
+
- Core `@arnilo/prism` (`src/contracts.ts`, `src/providers/*`) ← minimum neutral continuation/realtime `ProviderEvent` variant + `ToolCallContent.authority` only (Task 1). No OpenAI-specific field enters core.
|
|
41
|
+
- Out of scope (recorded so the Task 0 scope guard rejects them): Studio/control plane; remote-browser vendors (Playwright reference remains 0.0.9); Office runtime; additional vector-store packages; Slack/Teams/voice/desktop vendor packages; GraphRAG/advanced semantic chunking (0.1.x demand-gated).
|
|
42
|
+
- New package split is authorized only if a later task records measured size/cohesion need in this doc; none is recorded at freeze.
|
|
43
|
+
|
|
44
|
+
## 3. Primitive inventory (reused, not duplicated)
|
|
45
|
+
|
|
46
|
+
Core (`src/`):
|
|
47
|
+
- `AIProvider.generate(request): AsyncIterable<ProviderEvent>` — the single provider stream contract.
|
|
48
|
+
- `ProviderRequest` / `ProviderRequestOptions` (cache, headers, structuredOutput, compat, extra, signal) — neutral knobs.
|
|
49
|
+
- `ProviderEvent` union: `message_start | content_delta | tool_call_delta | tool_call | usage | done | error`. **Gap:** no continuation cursor, no realtime audio/session event, no hosted-tool authority.
|
|
50
|
+
- `ToolCallContent` (`src/contracts.ts:65`). **Gap:** no `authority: "host" | "provider-hosted"` discriminator.
|
|
51
|
+
- `ResourceLoader` + `loadTextResource`/`loadBinaryResource`/`loadManifestResource` (`src/resources.ts`) — authorized host artifact loader; RAG `DocumentLoader` composes over this.
|
|
52
|
+
- `src/providers/openai-compatible.ts` (shared OpenAI-compatible transport), `openai-primitives.ts` (`serializeOpenAITool`, `serializeOpenAIChatMessage`, structured-output serializers) — provider serializer sharing candidates.
|
|
53
|
+
- `src/provider-request-policy.ts`, `src/provider-events.ts`, `src/redaction.ts`, `src/run-limits.ts` — reused for hosted-tool/continuation/realtime limits, redaction, and shared `RunLimits`.
|
|
54
|
+
- `src/testing/provider-conformance.ts` — shared offline conformance (`assertProviderStreamConforms`, `assertAbortIsObserved`, `assertNoSecretLeak`, `assertProviderOwnedHeadersWin`, …); reused by Tasks 1–3.
|
|
55
|
+
|
|
56
|
+
Memory (`packages/memory/src/`):
|
|
57
|
+
- `Embedder` (`types.ts:48`), `VectorStore` (`types.ts:85`: upsert/query/delete/getByThread?), `MemoryVectorRecord`/`MemoryVectorHit`.
|
|
58
|
+
- `createMemory()` (`memory.ts:46`) → `remember`/`recall`/`forget`/`correct`/`grantConsent`/`revokeConsent`/`applyRetention`/`createContextProvider` — **0.0.14 shipped consent + retention + forget + correct**.
|
|
59
|
+
- `MemoryConsent`/`MemoryConsentInput`/`MemoryConsentScope`/`MemoryConsentSource` (`types.ts`, exported `index.ts:61-64`); `isInjectable` (`memory.ts:439`) honors consent/visibility.
|
|
60
|
+
- `assertFiniteVector` (`util.ts`) — enforced at embedder, memory-vector, and PostgreSQL/pgvector. **Gap:** add export/rebuild path validation; no semantic SQLite adapter exists.
|
|
61
|
+
- `runMemoryConformance` (`conformance.ts`) — offline conformance; called by `memory.test.ts` + PostgreSQL/pgvector integration. **Gap:** extend to export/rebuild + cross-thread/tenant.
|
|
62
|
+
|
|
63
|
+
RAG (`packages/rag/src/`):
|
|
64
|
+
- `indexChunks` (`indexing.ts`) — embeds + upserts; `ponytail:` comment explicitly defers stale-source replacement to host. **Gap:** `replaceSource` (transactional) + `deleteSource` (scoped).
|
|
65
|
+
- `retrieveContext` (`retrieve.ts`), `createRagContextProvider` (`context.ts`).
|
|
66
|
+
- `RagScope` (tenantId/resourceId/corpusId), `RagChunk`/`RagHit`/`RagCitation`/`RagContextResult` (`types.ts`). **Gap:** `RagHit` provenance/trust; `RetrieveContextOptions.reranker`; ingestion status.
|
|
67
|
+
- `chunkText`/`chunkMarkdown` (`chunk.ts`); `RagLimits` (`limits.ts`) — already hard-capped (chunkSize 16 384, maxChunks 8 192, topK 32, queryCandidates 128, resultBytes 512 KiB, contextTokens 8 000, metadataBytes 64 KiB, vectorDim 4 096).
|
|
68
|
+
|
|
69
|
+
Web-tools (`packages/web-tools/src/`):
|
|
70
|
+
- `WebDocument`/`WebExtraction` carry `untrusted: true` + `WebCitation.citationId` (`types.ts:9,10`); `canonicalUrl` SSRF guard rejects non-http(s)/userinfo URLs (`normalize.ts:5`); `citation()` builds `web:<provider>:<sourceId|hash>` IDs (`normalize.ts:6`). RAG web ingestion wraps these — no new crawler.
|
|
71
|
+
|
|
72
|
+
## 4. Frozen finite limits (Phase 10)
|
|
73
|
+
|
|
74
|
+
RAG (existing caps retained; new caps added):
|
|
75
|
+
- `replaceSource`: transactional window = maxChunks (8 192); on failure prior index intact; cross-scope rejected.
|
|
76
|
+
- `deleteSource`: scoped to `RagScope`; cross-scope rejected; bounded by existing `VectorStore.delete`.
|
|
77
|
+
- `DocumentLoader`/`Parser`: per-document byte cap = `HARD_MAX_DOCUMENT_CHARS_CAP` (8 MiB); parse time cap = 30 s (abortable); page cap (PDF) = 256; concurrency cap = 4 per scope; HTML strips script/style.
|
|
78
|
+
- `Reranker`: query cap = 8 KiB; hits cap = `HARD_QUERY_CANDIDATES_CAP` (128); time cap = 30 s; concurrency = 4 per scope; original retrieval order recoverable.
|
|
79
|
+
- Ingestion status: per-source record (pending/indexed/failed/partial + byte/chunk/error counts); status query O(scope), page cap = 100.
|
|
80
|
+
- Provenance/trust: present on every `RagHit`; assembled context marked `untrusted: true, inert: true`; injection-capable flag set on web/loader-sourced blocks.
|
|
81
|
+
|
|
82
|
+
Memory (existing caps retained; new caps added):
|
|
83
|
+
- `exportMemory`: page cap = 200; byte cap = 32 MiB; time cap = 60 s; redacted via active redactor; cross-tenant rejected.
|
|
84
|
+
- `rebuildIndex`: bounded batch stream (batchSize = `HARD_EMBED_BATCH_SIZE_CAP` 128); abortable + resumable via scope cursor; no full-corpus scan per run.
|
|
85
|
+
- `assertFiniteVector` at every boundary (embedder, memory-vector, PostgreSQL/pgvector, export, rebuild); semantic SQLite remains demand-gated.
|
|
86
|
+
|
|
87
|
+
OpenAI hosted tools / continuation / realtime (new):
|
|
88
|
+
- Hosted-tool result bytes = 1 MiB per call; authority = `"provider-hosted"`; marked untrusted; redacted.
|
|
89
|
+
- Continuation window = 8 hops; cursor opaque, ≤ 4 KiB; bounded by run's `RunLimits`; abort propagates; duplicate/stale cursor rejected.
|
|
90
|
+
- Realtime session: audio event cap = 256/s; byte cap = 1 MiB/s; wall-time cap = 600 s; concurrent sessions cap = host-owned (default 1 per run); disconnect/budget breach fails closed; credentials never in events.
|
|
91
|
+
|
|
92
|
+
Provider discovery (existing caller-gated; retained):
|
|
93
|
+
- Discovery page cap = 200; byte cap = 1 MiB; time cap = 30 s; abortable; no setup-time network unless host opts in.
|
|
94
|
+
|
|
95
|
+
All new loops consume the shared turn/tool/token/cost `RunLimits` (no second budget engine).
|
|
96
|
+
|
|
97
|
+
## 5. Threat / authority matrix
|
|
98
|
+
|
|
99
|
+
| Threat | Boundary | Control | Task |
|
|
100
|
+
| --- | --- | --- | --- |
|
|
101
|
+
| Hosted tool masquerading as host-owned tool (gains host permissions) | `ToolCallContent.authority` | new `authority: "provider-hosted"` discriminator; guardrails/permissions treat provider-hosted calls as provider-side, not host-side | Task 1 |
|
|
102
|
+
| Unbounded continuation loop | continuation cursor | opaque cursor, ≤ 4 KiB; 8-hop window; bounded by `RunLimits`; stale/duplicate cursor rejected | Task 1 |
|
|
103
|
+
| Realtime audio/credential leak | realtime session | credentials never in events; audio/transcripts untrusted + redacted; disconnect/budget fail-closed; exact origin/session/ownership binding | Task 1 |
|
|
104
|
+
| AI SDK silent field drop | mapping | typed table-driven mapping; unsupported required field raises `ERR_PRISM_PROVIDER_MAPPING`; version-skew setup error | Task 2 |
|
|
105
|
+
| Serializer sharing drops provider-specific cache/reasoning markers | shared serializer extraction | extract only on recorded exact wire match; per-provider serializer retained otherwise (Kimi/Moonshot vs Alibaba already diverge on `cache_control`/`reasoning_content`) | Task 3 |
|
|
106
|
+
| Remote document SSRF / private origin | `DocumentLoader`/`web_fetch` | `canonicalUrl` rejects non-http(s)/userinfo/private/local/file origins; parser bombs fail closed on byte/page/time cap | Task 4 |
|
|
107
|
+
| Retrieved content gains tool authority | assembled context | every retrieved block marked `untrusted: true, inert: true`; injection-capable flag; never executed | Task 4/5 |
|
|
108
|
+
| Source replacement/deletion crosses ownership/corpus | `RagScope`/`MemoryScope` | scope ownership verified on replace/delete; cross-scope rejected | Task 4/6 |
|
|
109
|
+
| Revoked/invisible memory injected/exported/telemetered | `isInjectable`/consent | reuse 0.0.14 consent enforcement; export redacted + scoped; retention real-delete where policy allows | Task 6 |
|
|
110
|
+
| Non-finite vector corrupts store | `assertFiniteVector` | enforced at every store boundary (add sqlite/query/export/rebuild) | Task 6 |
|
|
111
|
+
| Reranker exfiltration | reranker I/O | redacted via active redactor; original order recoverable; concurrency capped | Task 5 |
|
|
112
|
+
| Permission broadening (roadmap gate 9) | whole phase | no broadening of consent/memory/network/file/browser/connector/tool permissions; Task 9 regression guard | Task 9 |
|
|
113
|
+
|
|
114
|
+
## 6. Task 0 validation matrix (scope guards)
|
|
115
|
+
|
|
116
|
+
- `src/__tests__/docs.test.ts` Phase 10 evidence test asserts: review doc headings, Task 1–9 owners, frozen tokens (hosted-tool authority, continuation cursor ≤ 4 KiB, realtime audio cap 256/s, Reranker, DocumentLoader, replaceSource, exportMemory, rebuildIndex), roadmap criteria coverage, and the scope guard rejecting `packages/{realtime,document-loaders,reranker,vector-store-*,studio,voice,desktop}`.
|
|
117
|
+
- Scope guard: no new package directory beyond the existing 42; `@arnilo/prism-realtime` / `@arnilo/prism-document-loaders` / `@arnilo/prism-reranker` / additional `@arnilo/prism-provider-vector-*` must not appear in the package graph or `docs/index.md`.
|
|
118
|
+
- Non-broadening guard: gate 9 carried into Task 9 release validation.
|
|
119
|
+
- Manifest count guard: 43 publishable; `release:check --version 0.0.15` validates the exact graph.
|
|
120
|
+
|
|
121
|
+
## 7. Frozen decisions (binding on Tasks 1–9)
|
|
122
|
+
|
|
123
|
+
- `43 → 43` manifests; no new package (extend in place). A split requires a recorded amendment to §2 of this doc with measured size/cohesion evidence.
|
|
124
|
+
- Hosted-tool authority = `"provider-hosted"` (string literal); lives on `ToolCallContent` in core (one neutral field); OpenAI-specific behavior stays in the provider package.
|
|
125
|
+
- Continuation cursor is an opaque provider string ≤ 4 KiB; no core field beyond the neutral `ProviderEvent` variant + `ProviderRequestOptions` hook.
|
|
126
|
+
- Realtime session binds to exact origin/session/ownership; audio events untrusted + redacted; no realtime field leaks into core beyond the neutral event variant.
|
|
127
|
+
- `DocumentLoader` composes over `ResourceLoader` for authorized host artifacts; web ingestion wraps `web_fetch`/`web_extract` (no second crawler).
|
|
128
|
+
- `Reranker` is a seam over `RagHit[]`; `retrieveContext({ reranker })` keeps original order recoverable.
|
|
129
|
+
- Memory consent/retention/forget/correct are DONE (0.0.14); Task 6 only adds `exportMemory` + `rebuildIndex` + conformance parity + remaining finite-vector boundaries — do not rebuild consent.
|
|
130
|
+
- No additional vector-store package; demand-gated to 0.1.x.
|
|
131
|
+
- Shared serializer extraction requires a recorded exact wire match in this doc §2/§5; the Kimi/Moonshot vs Alibaba divergence on `cache_control`/`reasoning_content` is the precedent for keeping per-provider serializers.
|
|
132
|
+
- `npm test` stays network-free; credentialed live canaries stay operator-gated and are documented in the Task 7 matrix.
|
|
@@ -23,11 +23,18 @@ Ordinary Prism sessions do not require this package or any vector backend.
|
|
|
23
23
|
| `vectorStore` / `workingStore` | no | Defaults to in-memory adapters |
|
|
24
24
|
| `schema` / `validateWorkingMemory` | no | Working-memory shape checks (JSON Schema subset or host hook) |
|
|
25
25
|
| `workingMemoryTemplate` | no | `{{path}}` template for context injection |
|
|
26
|
-
| `limits` | no | top-K, adjacent range, batch, payload, injected-token caps |
|
|
26
|
+
| `limits` | no | top-K, adjacent range, batch, payload, injected-token, export, and rebuild caps |
|
|
27
27
|
| `redactor` / `secrets` | no | Redact text/metadata before persist/inject |
|
|
28
28
|
| `requireConsent` | no | Strict mode: recall/injection excludes entries lacking explicit consent |
|
|
29
29
|
|
|
30
|
-
Semantic indexing (entries carry
|
|
30
|
+
Semantic indexing (entries carry `MemoryConsent` source/visibility; unset defaults to `{ source: "user", scope: "thread", visible: true }`):
|
|
31
|
+
|
|
32
|
+
| `MemoryConsent` field | Meaning |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| `source` | `"user"`, `"agent"`, or `"system"` provenance. |
|
|
35
|
+
| `scope` | `"thread"`, `"profile"`, or `"user"` control scope. |
|
|
36
|
+
| `visible` | `false` immediately excludes the record from recall, injection, export, and telemetry. |
|
|
37
|
+
| `grantedAt` / `revokedAt` | Optional host/audit timestamps; a revocation excludes the record. |
|
|
31
38
|
|
|
32
39
|
```ts
|
|
33
40
|
await memory.remember({ entries: [{ id, text, metadata?, consent?, sequence? }] }, { wait?: boolean })
|
|
@@ -46,6 +53,14 @@ await memory.setConsent(entryId, { visible?: boolean, source?, scope? }) // gran
|
|
|
46
53
|
await memory.correct(entryId, text) // re-embeds, preserves consent
|
|
47
54
|
await memory.forget({ ids? }) // real delete (whole thread if no ids)
|
|
48
55
|
await memory.applyRetention({ maxAgeDays?, maxEntries?, batchSize? }) // bounded real-delete sweep
|
|
56
|
+
|
|
57
|
+
const page = await memory.exportMemory({
|
|
58
|
+
identity: { tenantId, resourceId, threadId }, // exact host-verified owner
|
|
59
|
+
cursor?, limit?, maxBytes?, maxMs?, signal?,
|
|
60
|
+
}); // visible, explicitly consented, redacted records only
|
|
61
|
+
|
|
62
|
+
const rebuilt = await memory.rebuildIndex({ cursor?, batchSize?, maxMs?, signal? });
|
|
63
|
+
// re-embeds one page; save rebuilt.nextCursor and call again to resume
|
|
49
64
|
```
|
|
50
65
|
|
|
51
66
|
## Outputs / response / events
|
|
@@ -58,6 +73,8 @@ await memory.applyRetention({ maxAgeDays?, maxEntries?, batchSize? }) // bou
|
|
|
58
73
|
| `setConsent` / `correct` | Updated `MemoryVectorRecord` with stamped grant/revoke times |
|
|
59
74
|
| `forget` | Removed count (real delete) |
|
|
60
75
|
| `applyRetention` | `{ deleted, scanned }` bounded real-delete sweep |
|
|
76
|
+
| `exportMemory` | `{ entries, bytes, nextCursor? }` redacted, explicitly consented, identity-bound page |
|
|
77
|
+
| `rebuildIndex` | `{ rebuilt, nextCursor? }` re-embedded bounded page; caller owns resume scheduling |
|
|
61
78
|
| `createContextProvider()` | Inert `ContextProvider` blocks for working and/or semantic text |
|
|
62
79
|
| `createWorkingMemoryProcessor({ extract })` | Explicit host-invoked updater; never auto-runs |
|
|
63
80
|
|
|
@@ -144,7 +161,8 @@ const memory = createMemory({
|
|
|
144
161
|
- The working-memory processor is opt-in and host-invoked; middleware is not required.
|
|
145
162
|
- `createHashEmbedder()` is for tests/demos only; production hosts supply a real `Embedder`.
|
|
146
163
|
- Observational memory (`@arnilo/prism-compaction-observational-memory`) remains unchanged and composable.
|
|
147
|
-
- Consent is enforced at the single `recall()` gate, so both direct recall and `createContextProvider()` injection honor it; `visible: false` (or a revoked grant) keeps an entry out of prompts, events, exports, and telemetry. `setConsent`/`correct` re-upsert in place (consent change does not re-embed); `forget`/`applyRetention` are real deletes, not tombstones. Retention
|
|
164
|
+
- Consent is enforced at the single `recall()` gate, so both direct recall and `createContextProvider()` injection honor it; `visible: false` (or a revoked grant) keeps an entry out of prompts, events, exports, and telemetry. `setConsent`/`correct` re-upsert in place (consent change does not re-embed); `forget`/`applyRetention` are real deletes, not tombstones. Retention uses indexed oldest-first pages plus a scoped count, deleting one default-500/hard-5000 batch without reading a corpus into memory. The PostgreSQL adapter persists consent in a `consent JSONB` column added by `buildMemoryDdl`.
|
|
165
|
+
- `exportMemory()` requires an exact `{ tenantId, resourceId, threadId }` identity equal to its `createMemory()` scope. It excludes legacy consent-less, invisible, and revoked records even when normal recall allows legacy entries. It returns a stable sequence cursor page, redacted before response, with defaults/hard caps of 100/200 entries, 4/32 MiB, and 10/60 seconds. `rebuildIndex()` uses the same stable cursor shape to re-embed one 32/128-record page under a 10/60-second cap; save the cursor durably to resume. Both APIs require a store implementing bounded `listByThread()`; retention also requires `countByThread()`. PostgreSQL/pgvector and the in-memory reference adapter conform; SQLite persistence stores sessions, not semantic vectors.
|
|
148
166
|
- Profile bundles do not include this package yet.
|
|
149
167
|
|
|
150
168
|
Shared conformance:
|
|
@@ -167,7 +185,7 @@ await runMemoryConformance(() => ({
|
|
|
167
185
|
- Configure `secrets` / `redactor` so memory text and metadata cannot persist or inject raw canaries.
|
|
168
186
|
- Injected context is inert text — it cannot grant tools or permissions.
|
|
169
187
|
- Hard caps: top-K ≤ 32, messageRange ≤ 4, embed batch ≤ 128, injected tokens ≤ 8000, payload/working-memory byte limits enforced.
|
|
170
|
-
- Every embedding is a non-empty finite number vector. `embedBatched()`, in-memory `VectorStore` upserts/queries,
|
|
188
|
+
- Every embedding is a non-empty finite number vector. `embedBatched()`, in-memory `VectorStore` upserts/queries, PostgreSQL/pgvector parameters, and export/rebuild page boundaries reject NaN, ±Infinity, non-numbers, and wrong configured dimensions before similarity scoring, SQL, response, or re-indexing. Custom adapters can call `assertFiniteVector(vector, label, expectedLength?)` at their trust boundary.
|
|
171
189
|
- Default `remember()` does not block agent completion; pass `{ wait: true }` when indexing must finish first.
|
|
172
190
|
- PostgreSQL live suite is gated by `PRISM_TEST_POSTGRES_URL` and requires the `vector` extension.
|
|
173
191
|
|