@arnilo/prism 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +42 -62
  3. package/dist/agent-run-lifecycle.js +4 -0
  4. package/dist/agent-run-state.d.ts +5 -2
  5. package/dist/agent-run-state.js +18 -8
  6. package/dist/agent-session/session/assemble.d.ts +6 -0
  7. package/dist/agent-session/session/assemble.js +391 -0
  8. package/dist/agent-session/session/persist.d.ts +28 -0
  9. package/dist/agent-session/session/persist.js +166 -0
  10. package/dist/agent-session/session/provider-round.d.ts +6 -0
  11. package/dist/agent-session/session/provider-round.js +231 -0
  12. package/dist/agent-session/session/tool-round.d.ts +31 -0
  13. package/dist/agent-session/session/tool-round.js +473 -0
  14. package/dist/agent-session/session/types.d.ts +115 -0
  15. package/dist/agent-session/session/types.js +5 -0
  16. package/dist/agent-session/session.d.ts +54 -41
  17. package/dist/agent-session/session.js +23 -1132
  18. package/dist/capture.d.ts +63 -0
  19. package/dist/capture.js +67 -0
  20. package/dist/cli-dev.d.ts +29 -0
  21. package/dist/cli-dev.js +52 -0
  22. package/dist/cli-init.d.ts +34 -3
  23. package/dist/cli-init.js +192 -24
  24. package/dist/cli-runner.d.ts +6 -2
  25. package/dist/cli-runner.js +57 -10
  26. package/dist/content.d.ts +3 -3
  27. package/dist/content.js +3 -1
  28. package/dist/contracts-core/agent.d.ts +8 -0
  29. package/dist/contracts-core/batch.d.ts +97 -0
  30. package/dist/contracts-core/batch.js +65 -0
  31. package/dist/contracts-core/content.d.ts +72 -1
  32. package/dist/contracts-core/embeddings.d.ts +30 -0
  33. package/dist/contracts-core/embeddings.js +17 -0
  34. package/dist/contracts-core/images.d.ts +60 -0
  35. package/dist/contracts-core/images.js +17 -0
  36. package/dist/contracts-core/moderation.d.ts +46 -0
  37. package/dist/contracts-core/moderation.js +34 -0
  38. package/dist/contracts-core/speech.d.ts +39 -0
  39. package/dist/contracts-core/speech.js +17 -0
  40. package/dist/contracts-core/transcription.d.ts +48 -0
  41. package/dist/contracts-core/transcription.js +17 -0
  42. package/dist/contracts-core/video.d.ts +61 -0
  43. package/dist/contracts-core/video.js +17 -0
  44. package/dist/contracts-core.d.ts +7 -0
  45. package/dist/contracts-core.js +7 -0
  46. package/dist/contracts-protocol.d.ts +18 -0
  47. package/dist/contracts-run-state.d.ts +1 -2
  48. package/dist/index.d.ts +7 -3
  49. package/dist/index.js +5 -3
  50. package/dist/input.d.ts +8 -0
  51. package/dist/input.js +4 -0
  52. package/dist/node/agent-definitions.d.ts +1 -8
  53. package/dist/node/agent-definitions.js +0 -34
  54. package/dist/node/settings.d.ts +0 -1
  55. package/dist/node/settings.js +0 -5
  56. package/dist/pinned-fetch.js +29 -3
  57. package/dist/provider-events.js +3 -4
  58. package/dist/providers/media.d.ts +1 -2
  59. package/dist/providers/media.js +1 -4
  60. package/dist/rpc.d.ts +1 -1
  61. package/dist/rpc.js +4 -4
  62. package/dist/testing/persistence-schema.d.ts +1 -1
  63. package/dist/testing/persistence-schema.js +32 -28
  64. package/dist/testing/provider-conformance.d.ts +114 -5
  65. package/dist/testing/provider-conformance.js +342 -0
  66. package/dist/testing/tool-conformance.d.ts +25 -0
  67. package/dist/testing/tool-conformance.js +128 -1
  68. package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
  69. package/dist/testing/tool-effect-store-conformance.js +0 -3
  70. package/dist/thinking.d.ts +48 -9
  71. package/dist/thinking.js +134 -8
  72. package/dist/tool-search.d.ts +76 -0
  73. package/dist/tool-search.js +199 -0
  74. package/docs/0.1.0-readiness.md +3 -3
  75. package/docs/a2a.md +2 -2
  76. package/docs/acp-agent.md +1 -1
  77. package/docs/acp.md +3 -3
  78. package/docs/ag-ui-adoption.md +1 -1
  79. package/docs/ag-ui.md +1 -2
  80. package/docs/agent-definitions.md +1 -1
  81. package/docs/agent-events.md +5 -5
  82. package/docs/agent-identity.md +13 -2
  83. package/docs/audit-export.md +3 -3
  84. package/docs/batch-jobs.md +120 -0
  85. package/docs/browser-automation.md +5 -5
  86. package/docs/caveman.md +2 -2
  87. package/docs/cli-rpc.md +43 -9
  88. package/docs/coding-agent-tools.md +19 -19
  89. package/docs/coding-review-and-diagnostics.md +2 -2
  90. package/docs/coding-security.md +5 -5
  91. package/docs/coding-tools.md +82 -0
  92. package/docs/coding-workspaces.md +2 -2
  93. package/docs/compaction-and-retry.md +2 -2
  94. package/docs/compaction-llm.md +4 -4
  95. package/docs/compaction-observational-memory.md +3 -3
  96. package/docs/computer-use-linux.md +13 -2
  97. package/docs/context-and-skills.md +3 -1
  98. package/docs/conversations.md +4 -4
  99. package/docs/core.md +85 -0
  100. package/docs/credential-storage.md +12 -8
  101. package/docs/credentials-and-redaction.md +1 -1
  102. package/docs/data-classification.md +1 -1
  103. package/docs/database-persistence.md +7 -3
  104. package/docs/dev-inspector.md +103 -0
  105. package/docs/device-adapters.md +2 -2
  106. package/docs/diagrams.md +247 -0
  107. package/docs/document-reader.md +6 -6
  108. package/docs/documents.md +214 -0
  109. package/docs/embeddings.md +112 -0
  110. package/docs/enterprise-postgres-state.md +7 -7
  111. package/docs/evaluations.md +41 -7
  112. package/docs/extensions.md +3 -3
  113. package/docs/forge-integration.md +3 -3
  114. package/docs/graft.md +5 -5
  115. package/docs/guardrails.md +2 -2
  116. package/docs/host-security.md +16 -15
  117. package/docs/image-generation.md +129 -0
  118. package/docs/impeccable.md +7 -5
  119. package/docs/index.md +84 -46
  120. package/docs/indexed-code-search.md +2 -2
  121. package/docs/language-intelligence.md +4 -4
  122. package/docs/live-testing.md +126 -0
  123. package/docs/mcp-tools.md +44 -13
  124. package/docs/middleware-hooks.md +1 -1
  125. package/docs/migrate-to-0.4.md +312 -0
  126. package/docs/migrate-to-0.5.md +122 -0
  127. package/docs/migration.md +51 -1
  128. package/docs/model-registry.md +38 -0
  129. package/docs/model-routing.md +6 -6
  130. package/docs/moderation.md +117 -0
  131. package/docs/multi-agent-patterns.md +177 -0
  132. package/docs/multimodal-content.md +27 -3
  133. package/docs/obscura.md +12 -12
  134. package/docs/observability.md +32 -7
  135. package/docs/openapi-tools.md +14 -4
  136. package/docs/operations.md +11 -0
  137. package/docs/performance.md +30 -10
  138. package/docs/persistence-credentials-multimodality-primitives.md +7 -7
  139. package/docs/policy-and-audit.md +18 -8
  140. package/docs/ponytail.md +3 -3
  141. package/docs/postgres-persistence.md +5 -5
  142. package/docs/process-sessions.md +2 -2
  143. package/docs/prompt-registry.md +106 -0
  144. package/docs/provider-caching.md +36 -32
  145. package/docs/provider-conformance.md +24 -2
  146. package/docs/provider-packages.md +58 -22
  147. package/docs/provider-primitives.md +5 -5
  148. package/docs/provider-request-policies.md +1 -1
  149. package/docs/providers/ai-sdk.md +18 -6
  150. package/docs/providers/alibaba.md +10 -6
  151. package/docs/providers/anthropic.md +10 -6
  152. package/docs/providers/azure.md +20 -4
  153. package/docs/providers/bedrock.md +18 -3
  154. package/docs/providers/clinepass.md +7 -3
  155. package/docs/providers/commandcode.md +253 -0
  156. package/docs/providers/deepseek.md +7 -3
  157. package/docs/providers/google.md +8 -4
  158. package/docs/providers/hyper.md +284 -0
  159. package/docs/providers/kimi.md +7 -3
  160. package/docs/providers/neuralwatt.md +12 -8
  161. package/docs/providers/ollama.md +18 -3
  162. package/docs/providers/openai-compatible.md +5 -1
  163. package/docs/providers/openai.md +9 -5
  164. package/docs/providers/opencode-go.md +8 -4
  165. package/docs/providers/openrouter.md +8 -4
  166. package/docs/providers/vertex.md +21 -5
  167. package/docs/providers/xai.md +7 -3
  168. package/docs/providers/zai.md +7 -3
  169. package/docs/rag.md +31 -9
  170. package/docs/release-and-install.md +181 -76
  171. package/docs/resource-loading.md +1 -1
  172. package/docs/runs-and-usage.md +28 -3
  173. package/docs/server.md +94 -5
  174. package/docs/settings-auth-trust-security.md +7 -5
  175. package/docs/sheets.md +229 -0
  176. package/docs/speech.md +126 -0
  177. package/docs/sqlite-persistence.md +4 -4
  178. package/docs/supervisors.md +4 -3
  179. package/docs/thinking-and-reasoning.md +93 -60
  180. package/docs/tool-conformance.md +28 -3
  181. package/docs/tool-execution-primitives.md +8 -8
  182. package/docs/tools.md +32 -5
  183. package/docs/web-tools.md +3 -3
  184. package/docs/wiki.md +7 -7
  185. package/docs/work-artifacts-and-review.md +17 -6
  186. package/docs/work-connectors.md +4 -4
  187. package/docs/work-tools.md +5 -5
  188. package/docs/workflow-orchestration-primitives.md +35 -11
  189. package/docs/workflows.md +74 -13
  190. package/docs/working-and-semantic-memory.md +53 -5
  191. package/package.json +14 -31
  192. package/templates/README.md +23 -0
  193. package/templates/deep-research/README.md.tmpl +47 -0
  194. package/templates/deep-research/env.example.tmpl +12 -0
  195. package/templates/deep-research/gitignore.tmpl +7 -0
  196. package/templates/deep-research/manifest.json +12 -0
  197. package/templates/deep-research/package.json.tmpl +23 -0
  198. package/templates/deep-research/src/agent.ts.tmpl +81 -0
  199. package/templates/deep-research/src/index.ts.tmpl +53 -0
  200. package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
  201. package/templates/deep-research/src/tools.ts.tmpl +86 -0
  202. package/templates/deep-research/src/types.ts.tmpl +45 -0
  203. package/templates/deep-research/src/workflow.ts.tmpl +156 -0
  204. package/templates/deep-research/tsconfig.json.tmpl +15 -0
  205. package/templates/init/manifest.json +5 -0
  206. package/templates/init/package.json.tmpl +2 -1
  207. package/templates/init/providers.json +40 -24
  208. package/docs/antigravity-agent.md +0 -207
@@ -2,100 +2,133 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism keeps thinking/reasoning **provider-owned on the wire** while giving hosts one portable way to set effort per turn. Model defaults live on `ModelConfig.compat` (and `capabilities.reasoning` where declared). Per-turn overrides live on `ProviderRequestOptions.compat` and win through existing `mergeProviderRequestOptions`. Shared helpers map a portable `ThinkingLevel` into the official compat fields each family already reads — they do **not** invent a second options tree.
5
+ Prism gives hosts one portable way to set thinking/reasoning effort per model and per turn, and guarantees the level actually reaches the wire on every provider Prism ships. The single entry point is **`applyThinkingLevelForModel`**: it resolves the model's compat family, snaps the requested level to the model's **declared levels** (`capabilities.thinkingLevels`), and merges the family's compat patch into your base options. Every first-party provider catalog stamps the family and declares the per-model level set; provider resolvers translate the patch into official wire fields. Model defaults live on `ModelConfig.compat`; per-turn overrides live on `ProviderRequestOptions.compat` and win through the existing `mergeProviderRequestOptions` merge.
6
6
 
7
7
  ## When to use it
8
8
 
9
- - Session runs: pass `providerOptions.compat` (or `applyThinkingLevel`) on `RunOptions`.
10
- - Use-case workers (LLM compaction, observational memory): pass `thinkingLevel`; packages map it into `compat` via the shared helpers.
11
- - Provider authors: keep reading official fields from `options.compat` / `model.compat`; add package-local escape hatches only when the official API has unique knobs.
9
+ - Session runs: pass `providerOptions` from `applyThinkingLevelForModel` on `RunOptions` — one call, no per-provider branching.
10
+ - Use-case workers (LLM compaction, observational memory): pass `thinkingLevel`; workers call `applyThinkingLevelForModel` with the bound model.
11
+ - Hosts building UI: read `model.capabilities.thinkingLevels` (when declared) to render a legal level picker; `isSupportedThinkingLevel` tells you whether a value is declared before sending.
12
+ - Provider authors: read official wire fields from the compat patches below; keep unique knobs package-local.
12
13
 
13
- ## Contract
14
+ ## Inputs / request
14
15
 
15
- | Layer | Surface |
16
- | --- | --- |
17
- | Model default | `ModelConfig.compat` (+ `capabilities.reasoning` when the model can reason) |
18
- | Per-turn override | `ProviderRequestOptions.compat` (request wins over model via merge) |
19
- | Portable level | `ThinkingLevel`: `none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max` |
20
- | Helpers | `thinkingCompatFor`, `applyThinkingLevel`, `thinkingFamilyForModel`, `isThinkingLevel`, `normalizeThinkingLevel`, `THINKING_LEVELS` |
21
- | Not used | Inert `options.extra.thinkingLevel` — providers do not read `extra` for effort |
16
+ | Input | Type | Notes |
17
+ | --- | --- | --- |
18
+ | `base` | `ProviderRequestOptions \| undefined` | Existing options; the patch is merged on top |
19
+ | `level` | `string \| undefined` | Portable `ThinkingLevel` (`none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max`) or an opaque provider-specific string (forward-compat passthrough) |
20
+ | `model` | `Pick<ModelConfig, "provider" \| "compat" \| "capabilities">` | Model view used for family resolution, declared levels, and reasoning gating |
22
21
 
23
- ```ts
24
- import { applyThinkingLevel, thinkingCompatFor, thinkingFamilyForModel } from "@arnilo/prism";
22
+ ## Outputs / response / events
25
23
 
26
- // Per-turn override on a session run (OpenAI / OpenRouter family)
27
- await session.run(input, {
28
- providerOptions: applyThinkingLevel(undefined, "low", "openai_reasoning"),
29
- });
24
+ Returns the merged `ProviderRequestOptions` (a new object when a patch applies; `base` unchanged when there is nothing to do — non-reasoning model, `noop` family, or `level` undefined).
25
+
26
+ ## Request/response example
27
+
28
+ ```json
29
+ { "compat": { "reasoning_effort": "high" } }
30
+ ```
31
+
32
+ ## Implementation example
33
+
34
+ ```ts
35
+ import { applyThinkingLevelForModel } from "@arnilo/prism";
30
36
 
31
- // Equivalent explicit compat
37
+ // Per-turn override on a session run
32
38
  await session.run(input, {
33
- providerOptions: { compat: thinkingCompatFor("openai_reasoning", "low") },
34
- // → { reasoning: { effort: "low" } }
39
+ providerOptions: applyThinkingLevelForModel(base, "high", model),
35
40
  });
36
41
 
37
- // Use-case worker: family from model metadata (or pass an explicit family)
38
- const family = thinkingFamilyForModel(model);
39
- await runObserver({
40
- ...,
41
- providerOptions: applyThinkingLevel(base, "low", family === "noop" ? "reasoning_effort" : family),
42
- });
42
+ // Declared-level-aware UI
43
+ const levels = model.capabilities?.thinkingLevels; // e.g. ["low","medium","high","xhigh","max"]
43
44
  ```
44
45
 
46
+ ## Contract
47
+
48
+ | Layer | Surface |
49
+ | --- | --- |
50
+ | Adapter (use this) | `applyThinkingLevelForModel(base, level, model)` — family resolution + snap + merge in one call |
51
+ | Model default | `ModelConfig.compat` (+ `capabilities.reasoning`, `capabilities.thinkingLevels` when declared) |
52
+ | Per-turn override | `ProviderRequestOptions.compat` (request wins over model via merge) |
53
+ | Portable level | `ThinkingLevel`: `none` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max` |
54
+ | Parse / validate | `parseThinkingLevel` (known level → canonical; other non-empty string → opaque passthrough; empty/non-string → `undefined`), `isSupportedThinkingLevel(model, level)`, `thinkingLevelsForModel(model)`, `snapThinkingLevel(model, level)` |
55
+ | Legacy helpers | `thinkingCompatFor`, `applyThinkingLevel`, `thinkingFamilyForModel`, `isThinkingLevel`, `normalizeThinkingLevel`, `THINKING_LEVELS` (still exported; prefer the adapter) |
56
+ | Not used | Inert `options.extra.thinkingLevel` — providers do not read `extra` for effort |
57
+
45
58
  ## Compat families
46
59
 
47
- Core maps only shapes shared by ≥2 packages (or an explicit no-op). Unique knobs stay package-local.
60
+ Core maps only shapes shared by ≥2 packages (or an explicit no-op). Unique knobs stay package-local. Family inference is **stamp-first**: `compat.thinkingFamily` set by the catalog wins, then compat-shape heuristics, then provider-id heuristics, then `capabilities.reasoning`.
48
61
 
49
- | Family | Compat patch | Used by (official fields) |
62
+ | Family | Compat patch | Used by (official wire fields) |
50
63
  | --- | --- | --- |
51
64
  | `openai_reasoning` | `{ reasoning: { effort } }` | OpenAI Responses `reasoning.effort`; OpenRouter `reasoning.effort` |
52
- | `reasoning_effort` | `{ reasoning_effort }` | Z.AI `reasoning_effort`; NeuralWatt `reasoning_effort`; Kimi K3 `reasoning_effort`; DeepSeek `reasoning_effort`; ClinePass `reasoning_effort` |
53
- | `thinking_type` | `{ thinking: { type: "enabled" \| "disabled" } }` | Z.AI `thinking.type`; Kimi K2.x `thinking.type` (`none` → `disabled`); DeepSeek `thinking.type` |
65
+ | `reasoning_effort` | `{ reasoning_effort }` | Z.AI, NeuralWatt, Kimi K3, DeepSeek, xAI, ClinePass, Hyper, Ollama, gateways (OpenAI routes) |
66
+ | `thinking_type` | `{ thinking: { type: "enabled" \| "disabled" } }` | Z.AI `thinking.type`; Kimi K2.x; DeepSeek toggle; Qwen `enable_thinking` (via `alibabaEnableThinking`) |
67
+ | `google` | `{ thinkingLevel }` | Google `generationConfig.thinkingConfig.thinkingLevel` (3.x) / `thinkingBudget` (2.5) |
68
+ | `output_config_effort` | `{ output_config: { effort } }` | Anthropic Messages `output_config.effort`; DeepSeek anthropic-format endpoint |
54
69
  | `noop` | `{}` | AI SDK / host-owned adapters — effort is host-model settings |
55
70
 
56
- `applyThinkingLevel` defaults `family` to `reasoning_effort` when omitted. For `openai_reasoning`, an existing `compat.reasoning.summary` (or other reasoning keys) is preserved when merging `effort`.
71
+ **Removed guidance:** do not use the `thinking_type` family to carry effort on Anthropic-routed providers — `thinking.type` is a toggle, and `enabled` without `budget_tokens` is rejected by current Anthropic APIs. Anthropic effort travels in `output_config.effort` (`output_config_effort` family).
57
72
 
58
- ### Recommended family by first-party package
73
+ ### First-party packages
59
74
 
60
- | Package | Recommended family | Notes |
61
- | --- | --- | --- |
62
- | `@arnilo/prism-provider-openai` | `openai_reasoning` | First-class body `reasoning` from model + per-turn compat merge; `summary`/`mode`/`context` via compat |
63
- | `@arnilo/prism-provider-openrouter` | `openai_reasoning` | First-class `resolveOpenRouterReasoning` merge; prefer `reasoning` object over legacy `reasoning_effort` shorthand; `preserveThinking` replays as body `reasoning` |
64
- | `@arnilo/prism-provider-zai` | `reasoning_effort` (+ optional `thinking_type`) | Official `thinking` / `reasoning_effort` / `tool_stream` / `clear_thinking`; Preserved Thinking via `reasoning_content` |
65
- | `@arnilo/prism-provider-neuralwatt` | `reasoning_effort` | Budgets / `preserve_thinking` / `clear_thinking` / `chat_template_kwargs` stay package-local on `compat` |
66
- | `@arnilo/prism-provider-kimi` | K3: `reasoning_effort`; K2.x: `thinking_type` | K2.7-code thinking is always on; do not send conflicting `thinking` + `reasoning_effort` |
67
- | `@arnilo/prism-provider-opencode-go` | Anthropic route: thinking blocks (`thinking_type` family); OpenAI route: `reasoning_content` preserve + optional `thinking`/`reasoning_effort`/`reasoning` passthrough | Official dual endpoints; MiniMax/Qwen → Anthropic, others → OpenAI |
68
- | `@arnilo/prism-provider-ai-sdk` | `noop` | Host `LanguageModelV4` owns reasoning settings |
69
- | `@arnilo/prism-provider-deepseek` | `thinking_type` + `reasoning_effort` | Thinking on by default (`high`). `cacheRetention: "none"` or `thinking: false` disables. Tool turns must replay `reasoning_content` or the API returns 400. |
70
- | `@arnilo/prism-provider-xai` | replay only | Featured Completions do not send `reasoning_effort`. Reasoning models must replay `reasoning_content` or the prefix cache breaks. Do not flatten thinking into text. |
71
- | `@arnilo/prism-provider-clinepass` | `reasoning_effort` | Per-model `compat.thinkingLevelMap`. GLM `xhigh` passthrough (never send `max`). K3 `high` → `max`. Unsupported slots omit the field. |
75
+ | Package | Family / behavior |
76
+ | --- | --- |
77
+ | `@arnilo/prism-providers/openai` | `openai_reasoning`; per-family effort tables, Responses-side clamp, `summary` preserved |
78
+ | `@arnilo/prism-providers/openrouter` | `openai_reasoning`; API-derived `supported_efforts` levels; `preserveThinking` replays as body `reasoning` / `reasoning_content` |
79
+ | `@arnilo/prism-providers/anthropic` | `output_config_effort`; generation-aware `adaptive`/legacy thinking |
80
+ | `@arnilo/prism-providers/google` | `google`; 3.x `thinkingLevel` sets, 2.5 budget ranges |
81
+ | `@arnilo/prism-providers/zai` | `reasoning_effort` (GLM-5.2/5.3 snap tables) + `thinking_type` toggle; Preserved Thinking via `reasoning_content` |
82
+ | `@arnilo/prism-providers/kimi` | K3: `reasoning_effort` (`low/high/max`); K2.x: `thinking_type` |
83
+ | `@arnilo/prism-providers/deepseek` | `reasoning_effort` (`low/high/max`) + `thinking_type` toggle; thinking on by default; tool turns must replay `reasoning_content` or the API returns 400 |
84
+ | `@arnilo/prism-providers/xai` | `reasoning_effort` with declared per-model ladders; `reasoning_content` replay still required |
85
+ | `@arnilo/prism-providers/clinepass` | `reasoning_effort` through per-model slot maps (`compat.thinkingLevelMap`); GLM `xhigh` passthrough, never `max` |
86
+ | `@arnilo/prism-providers/neuralwatt` | `reasoning_effort` (`low/medium/high/max`); budgets + preserve/clear thinking stay package-local |
87
+ | `@arnilo/prism-providers/hyper` | `reasoning_effort` derived from live `effort_levels`; snap instead of drop; Anthropic route emits `output_config.effort` |
88
+ | `@arnilo/prism-providers/commandcode` / `@arnilo/prism-providers/opencode-go` | Gateway level tables (`claude-*` → `output_config_effort`, `gpt-5.6*` → `openai_reasoning`, K3/DeepSeek/GLM → `reasoning_effort`, K2.x/MiniMax/Qwen → `thinking_type`) |
89
+ | `@arnilo/prism-providers/alibaba` | `thinking_type` mapped onto Qwen `enable_thinking` (toggle, no effort levels) |
90
+ | `@arnilo/prism-providers/ollama` | `reasoning_effort`; `gpt-oss*` declares `low/medium/high`; native `think` field never mixed in |
91
+ | `@arnilo/prism-providers/azure` / `.../vertex` / `.../bedrock` | OpenAI-compat sanitized forwarder (`reasoning_effort` / `reasoning` object), snapped to declared levels |
92
+ | `@arnilo/prism-providers/ai-sdk` | `noop` — host `LanguageModelV4` owns reasoning settings |
93
+
94
+ ## Declared levels and snapping
72
95
 
73
- `thinkingFamilyForModel` infers family from existing `compat` shape, then safe provider heuristics (`openai*` → `openai_reasoning`, `neuralwatt` → `reasoning_effort`), then `capabilities.reasoning` → `reasoning_effort`, else `noop`. Docs and packages may map other provider ids explicitly; core avoids provider-specific literals beyond those heuristics.
96
+ Every reasoning-capable model in a first-party catalog declares its legal level set (`capabilities.thinkingLevels`) and, where meaningful, a `compat.thinkingFamily` stamp. The source of truth is the [thinking coverage evidence matrix](_evidence/thinking-coverage-2026-09-05.md) — generated from the compiled catalogs, with per-model source (API-derived vs doc-pinned) and the wire/live test that pins each row.
74
97
 
75
- ## Merge order
98
+ Snap semantics (`snapThinkingLevel`, applied by the adapter and by provider resolvers when the model declares a set):
76
99
 
77
- 1. `ModelConfig.compat` / model defaults inside the provider
78
- 2. `ProviderRequestOptions.compat` from agent / session policies
79
- 3. Per-turn `RunOptions.providerOptions` or use-case `applyThinkingLevel` patch (wins)
100
+ 1. The requested level is in the declared set → forwarded unchanged.
101
+ 2. Below the declared minimum (typically `none`/`minimal` on a set without them) → snaps **up** to the minimum.
102
+ 3. Otherwise → nearest declared level by ladder distance, **ties breaking up**.
103
+ 4. Provider-documented tables (DeepSeek, Z.AI GLM-5.2/5.3, ClinePass slot maps, Kimi K3) are wire authority and take precedence over the generic rule.
104
+ 5. Undeclared levels (opaque strings) on a reasoning-capable model → passthrough (forward compat); a non-reasoning model → options unchanged.
80
105
 
81
- Providers already prefer `request.options.compat.*` over `request.model.compat.*`.
106
+ OpenRouter and Hyper derive their sets from each provider's models API (`supported_efforts` / `effort_levels`); all other catalogs are doc-pinned because those upstreams expose no enumeration API.
82
107
 
83
- ## Use-case workers
108
+ ## Extension and configuration notes
84
109
 
85
- LLM compaction and observational memory accept `thinkingLevel?: string`. They call `applyThinkingLevel` into `compat` (not `extra.thinkingLevel`). When model inference returns `noop`, an explicit `thinkingLevel` still falls back to `reasoning_effort` so the host setting is never inert. Model selection for those workers (including session-model fallback) is documented in [Use-case model selection](use-case-model-selection.md).
110
+ - `thinkingFamilyForModel(model)` resolves a family without applying it; hosts that build their own options can use `thinkingCompatFor(family, level)` directly. `compat.thinkingFamily` on a model or request overrides all heuristics.
111
+ - For `openai_reasoning`, an existing `compat.reasoning.summary` (or other reasoning keys) is preserved when merging `effort`.
112
+ - Package-local knobs (`thinking_budget`, `thinking_token_budget`, `chat_template_kwargs`, `cacheRetention`-coupled switches) remain on `compat` — see each provider page.
113
+
114
+ ## Security and performance notes
115
+
116
+ - Declared levels prevent 400s from illegal effort values on strict upstreams; snapping is deterministic and ladder-based, never a silent drop.
117
+ - `none` semantics are provider-specific (off, or minimum effort where off is unsupported — e.g. Anthropic Opus 5 cannot disable thinking at `xhigh`/`max`, GLM-5.3 cannot disable thinking at all); the per-provider pages call these out.
118
+ - No secrets or credentials flow through any helper here; patches are plain compat objects.
86
119
 
87
120
  ## Non-reasoning models
88
121
 
89
- - Helper with `noop`: returns options unchanged — no invented body fields.
90
- - Helper with a real family on a model that rejects the field: provider/API error — hosts should gate on `capabilities.reasoning` or package docs.
122
+ - The adapter returns options unchanged — no invented body fields.
91
123
  - `thinking_type` + `none` sets `{ type: "disabled" }`; other levels set `{ type: "enabled" }` without encoding effort (compose with `reasoning_effort` when the API supports both).
92
124
 
93
- ## Related pages
125
+ ## Related APIs
94
126
 
95
- - [Use-case model selection](use-case-model-selection.md) — session vs worker/summary model binding
96
- - [Provider packages](provider-packages.md) — package boundaries and discovery
97
127
  - [Provider caching](provider-caching.md) — cache retention can disable thinking on some providers (e.g. Z.AI / DeepSeek when `cacheRetention: "none"`)
98
128
  - [Provider request policies](provider-request-policies.md) — `mergeProviderRequestOptions`
129
+ - [Use-case model selection](use-case-model-selection.md) — session vs worker/summary model binding (workers take `thinkingLevel`)
99
130
  - [Agent/session runtime](agent-session-runtime.md) — prior-reasoning preservation across turns
100
- - Per-provider pages under [docs/providers](providers/)
101
- - Evidence matrix: [Review coverage (2026-07-17 provider validation)](_evidence/review-coverage-2026-07-17-provider-validation.md)
131
+ - [Provider packages](provider-packages.md) — package boundaries and discovery
132
+ - Per-provider pages under [docs/providers](providers/) — declared levels, wire field, and snapping per provider
133
+ - [Thinking coverage evidence matrix](_evidence/thinking-coverage-2026-09-05.md) — per-model legality, source, and test pins
134
+ - [Review coverage (2026-07-17 provider validation)](_evidence/review-coverage-2026-07-17-provider-validation.md)
@@ -2,14 +2,15 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Tool conformance helpers are dependency-free assertions for tool-dispatch configuration tests. They exercise the blocked-reason matrix and the success path of `dispatchToolCall` without network or credentials.
5
+ Tool conformance helpers are dependency-free assertions for tool-dispatch configuration tests. They exercise the blocked-reason matrix and the success path of `dispatchToolCall` without network or credentials, and the tool-disclosure contract (progressive tool loading, plan 041) without any provider call.
6
6
 
7
7
  Exported from `@arnilo/prism/testing/tool-conformance`:
8
8
 
9
9
  - `assertToolDispatchConforms(registry, options)`
10
+ - `assertToolDisclosureConforms(options)`
10
11
  - `assertToolBlocked(probe, expectedReason)`
11
12
  - `dispatchAndCollect(probe)`
12
- - `ToolConformanceOptions`, `ToolDispatchProbeOptions`
13
+ - `ToolConformanceOptions`, `ToolDispatchProbeOptions`, `ToolDisclosureConformanceOptions`
13
14
 
14
15
  ## When to use it
15
16
 
@@ -45,6 +46,29 @@ await assertToolDispatchConforms(createToolRegistry(), {
45
46
 
46
47
  `assertToolDispatchConforms` returns `Promise<void>` and throws on the first violation. `dispatchAndCollect` returns `{ result, events }` capturing the emitted `AgentEvent`s for custom assertions.
47
48
 
49
+ `assertToolDispatchConforms` returns `Promise<void>` and throws on the first violation. `dispatchAndCollect` returns `{ result, events }` capturing the emitted `AgentEvent`s for custom assertions.
50
+
51
+ ### Disclosure leg (toolsDisclosure "search")
52
+
53
+ `assertToolDisclosureConforms(options)` asserts the progressive tool-loading contract against the same narrowing the runtime applies (`filterTools` allow/deny bounds, then `selectDisclosedTools`):
54
+
55
+ - search mode only narrows: the disclosed set is a subset of the allow/deny-filtered input, never wider, never zero, deterministic order for identical turns; a deny-listed tool is never described to the provider
56
+ - the generated `search_tools` tool is always kept in the disclosed set
57
+ - fail closed: an index over the frozen 1024-tool cap discloses the full eligible list
58
+ - `search_tools` output is inert: names plus byte-truncated (512-char) descriptions only — no JSON structure, no tool schemas — oversized hosts descriptions are truncated, never executed, and configured `secrets` never surface even when a description carries one
59
+ - activation is bounded to topK and only ever selects from the eligible set; activated tools stay disclosed on the next turn
60
+
61
+ ```ts
62
+ import { assertToolDisclosureConforms } from "@arnilo/prism/testing/tool-conformance";
63
+
64
+ assertToolDisclosureConforms({
65
+ tools: hostTools, // incl. schema-bearing and oversized-description tools
66
+ filter: { deny: ["legacy_tool"] }, // host allow/deny bounds
67
+ search: { topK: 16 },
68
+ secrets: [hostSecret], // secret-scan of model-facing search output
69
+ });
70
+ ```
71
+
48
72
  ## Request/response example
49
73
 
50
74
  ```ts
@@ -77,12 +101,13 @@ await assertToolDispatchConforms(createToolRegistry(), {
77
101
  ## Security and performance notes
78
102
 
79
103
  - No credentials, no network required.
80
- - Supply `validate` to exercise your policy; use `createJsonSchemaToolArgumentValidator()` from `@arnilo/prism-tool-validator-json-schema` for standards-based `parameters` validation.
104
+ - Supply `validate` to exercise your policy; use `createJsonSchemaToolArgumentValidator()` from `@arnilo/prism-core/validation/json-schema` for standards-based `parameters` validation.
81
105
  - The helper uses an allow-all permission policy by default; supply `permission` to validate your fail-closed policy.
82
106
  - Blocked calls are proven not to execute by the absence of `tool_execution_started`.
83
107
 
84
108
  ## Related APIs
85
109
 
86
110
  - [Tools](tools.md)
111
+ - [Tool effects](tool-effects.md)
87
112
  - [Settings, auth, trust, security](settings-auth-trust-security.md)
88
113
  - [Provider conformance](provider-conformance.md)
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- This page freezes the reusable tool validation, parallel dispatch, MCP bridge, and coding execution-policy designs for Plan 055. It inventories existing `@arnilo/prism` tool harness seams, `@arnilo/prism-coding-agent` behavior, extension/contribution boundaries, and the MCP mapping surface Tasks 1–6 will implement against.
5
+ This page freezes the reusable tool validation, parallel dispatch, MCP bridge, and coding execution-policy designs for Plan 055. It inventories existing `@arnilo/prism` tool harness seams, `@arnilo/prism-coding-tools/agent` behavior, extension/contribution boundaries, and the MCP mapping surface Tasks 1–6 will implement against.
6
6
 
7
7
  Implementation is **shipped** for JSON Schema tool argument validation (Plan 055 Task 1), parallel single-shot tool dispatch (Task 2), the MCP client bridge (Task 3), coding execution policy (Task 4), and bounded image reads (Task 5). Task 6 verification evidence is recorded in [review coverage](_evidence/review-coverage-2026-07-14.md).
8
8
 
@@ -40,7 +40,7 @@ All paths converge on normal `ToolResult` values and `tool_execution_*` events.
40
40
 
41
41
  ```ts
42
42
  import { createAgent } from "@arnilo/prism";
43
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
43
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
44
44
 
45
45
  const agent = createAgent({
46
46
  model,
@@ -123,7 +123,7 @@ Package performs **no** `PermissionPolicy`, `ToolValidator`, or trust checks of
123
123
  | --- | --- |
124
124
  | `ToolDefinition.parameters` | Stored and forwarded to providers; **not validated** by core |
125
125
  | `ToolValidator` | Host function hook; Phase 25 threads through agent runtime |
126
- | Standards-based schema validation | Optional `@arnilo/prism-tool-validator-json-schema`; host wires it through `ToolValidator` |
126
+ | Standards-based schema validation | Optional `@arnilo/prism-core/validation/json-schema`; host wires it through `ToolValidator` |
127
127
  | Schema compile cache | Adapter-owned finite LRU; core never compiles schemas |
128
128
 
129
129
  ### MCP mapping (shipped — Task 3)
@@ -178,10 +178,10 @@ export function createToolParameterValidator(
178
178
  ): ToolValidator;
179
179
  ```
180
180
 
181
- Optional package `@arnilo/prism-tool-validator-json-schema`:
181
+ Optional package `@arnilo/prism-core/validation/json-schema`:
182
182
 
183
183
  ```ts
184
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
184
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
185
185
 
186
186
  createAgent({ model, validator: createJsonSchemaToolArgumentValidator() });
187
187
  ```
@@ -271,7 +271,7 @@ export async function assertExecutionAllowed(
271
271
  ): Promise<ExecutionAction>;
272
272
  ```
273
273
 
274
- `@arnilo/prism-coding-agent` tools call `executionPolicy.check()` **inside** `execute` before side effects (after dispatch permission + argument validation). Optional `@arnilo/prism-coding-security` supplies `createCodingApprovalPolicy({ roots, approve, readOnly, commandRules })` with realpath containment, default deny patterns, metacharacter approval, approval caching, and `createSandboxBashOperations()` for pluggable sandbox backends.
274
+ `@arnilo/prism-coding-tools/agent` tools call `executionPolicy.check()` **inside** `execute` before side effects (after dispatch permission + argument validation). Optional `@arnilo/prism-coding-tools/security` supplies `createCodingApprovalPolicy({ roots, approve, readOnly, commandRules })` with realpath containment, default deny patterns, metacharacter approval, approval caching, and `createSandboxBashOperations()` for pluggable sandbox backends.
275
275
 
276
276
  **Permission vs execution policy:** `PermissionPolicy` remains `tool:<name>:execute` at dispatch. `ExecutionPolicy` adds command/path context for coding tools only — no MCP-specific branches in core.
277
277
 
@@ -366,9 +366,9 @@ Core remains dependency-free: validators, MCP bridges, coding policy, sandboxes,
366
366
 
367
367
  | Finding / capability | Plan 055 task | Primitive / doc |
368
368
  | --- | --- | --- |
369
- | C-001 JSON Schema tool validation | 1 | **shipped** — `ToolArgumentValidator`, `createToolParameterValidator`, `@arnilo/prism-tool-validator-json-schema` |
369
+ | C-001 JSON Schema tool validation | 1 | **shipped** — `ToolArgumentValidator`, `createToolParameterValidator`, `@arnilo/prism-core/validation/json-schema` |
370
370
  | C-003 MCP client bridge | 3 | **shipped** — `@arnilo/prism-mcp` |
371
- | C-006 Approval/sandbox for coding tools | 4 | **shipped** — `ExecutionPolicy`, `@arnilo/prism-coding-security` |
371
+ | C-006 Approval/sandbox for coding tools | 4 | **shipped** — `ExecutionPolicy`, `@arnilo/prism-coding-tools/security` |
372
372
  | C-007 Parallel tool execution | 2 | **shipped** — `toolConcurrency`, `dispatchToolCallsInOrder`, `resolveToolConcurrency` |
373
373
  | R-011 Image size / resize option | 5 | **shipped** — `maxImageBytes`, `transformImage`, `DEFAULT_MAX_IMAGE_BYTES` on read tool |
374
374
  | Phase verification | 6 | **verified** — `npm run sdk:ready` + audit + threat-model fixtures; evidence in review coverage |
package/docs/tools.md CHANGED
@@ -198,11 +198,11 @@ Core exposes schema-agnostic adapters that wrap into the same `ToolValidator` se
198
198
  - `ToolArgumentValidator` — `validate(schema, value)` with structured errors
199
199
  - `createToolParameterValidator(adapter, { missingSchema?: "allow" | "reject" })` — maps `tool.parameters` through the adapter
200
200
 
201
- For standards-based validation install `@arnilo/prism-tool-validator-json-schema`:
201
+ For standards-based validation install `@arnilo/prism-core/validation/json-schema`:
202
202
 
203
203
  ```ts
204
204
  import { createAgent } from "@arnilo/prism";
205
- import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
205
+ import { createJsonSchemaToolArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
206
206
 
207
207
  const agent = createAgent({
208
208
  model,
@@ -242,7 +242,7 @@ await session.run(input, {
242
242
 
243
243
  ## JSON Schema validator limits
244
244
 
245
- Core stores `ToolDefinition.parameters` but does not compile schemas. Hosts that install `@arnilo/prism-tool-validator-json-schema` receive pre-Ajv schema limits: 256 KiB bytes, depth 64, 10,000 properties/keywords, 128 refs, and a 256-entry LRU compiled cache by default. All reject invalid values and have finite hard ceilings. Only fragment-local `$ref` values are accepted; non-local refs, cycles, forbidden keys, and non-finite schema numbers fail before tool execution.
245
+ Core stores `ToolDefinition.parameters` but does not compile schemas. Hosts that install `@arnilo/prism-core/validation/json-schema` receive pre-Ajv schema limits: 256 KiB bytes, depth 64, 10,000 properties/keywords, 128 refs, and a 256-entry LRU compiled cache by default. All reject invalid values and have finite hard ceilings. Only fragment-local `$ref` values are accepted; non-local refs, cycles, forbidden keys, and non-finite schema numbers fail before tool execution.
246
246
 
247
247
  ```ts
248
248
  createJsonSchemaToolArgumentValidator({
@@ -251,13 +251,40 @@ createJsonSchemaToolArgumentValidator({
251
251
  });
252
252
  ```
253
253
 
254
+ ## Tool disclosure (progressive tool loading)
255
+
256
+ `toolsDisclosure` on `AgentConfig` / `RunOptions` (run wins; default `"all"`) controls how active tools reach the provider request. Default `"all"` sends every active tool schema — byte-identical to releases before the option existed. Opt-in `"search"` surfaces a bounded top-k subset per turn (scored lexically against the turn input over name and description) plus the generated `search_tools` tool; the model requests more by calling it.
257
+
258
+ ```ts
259
+ const agent = createAgent({
260
+ model, provider,
261
+ tools, // host-active ToolDefinitions (or registry)
262
+ toolsDisclosure: "search", // default "all"
263
+ toolsSearch: { topK: 16 }, // optional; clamped to the hard cap
264
+ });
265
+ ```
266
+
267
+ Limits (mirroring the skill-disclosure DEFAULT/HARD cap pattern):
268
+
269
+ | Limit | Default | Hard cap |
270
+ | --- | --- | --- |
271
+ | Disclosed tools per turn (`topK`) | 16 | 64 |
272
+ | Indexed tools | — | 1024 (fail closed to full disclosure) |
273
+ | Search query bytes | 4096 | 65536 |
274
+
275
+ - `search_tools({ query, k? })` returns inert `name: short description [matched: …]` lines — no schemas or tool bodies — and marks returned tools active for the session. Activation is names-only in run persistence (`sessionState.activatedToolNames`, capped at 128 names) and inert for tools absent from the current registry; a host can reset it with `session.clearActivatedTools()`.
276
+ - Fail closed: any index or scoring error discloses the full input list — never zero tools, never wider than the input list. Exhausting the frozen 1024-tool index cap is surfaced the same way.
277
+ - Disclosure never grants access: dispatch re-checks registry membership and allow/deny (`unknown_tool` / `tool_denied`) on every call regardless of what was described. Search results are intersected with the disclosed list structurally — searched tools are only ever selected from that list, never widened.
278
+ - Scoring is BM25-lite lexical (name tokens weigh ×3, IDF from the registry): bounded, dependency-free, deterministic tie-breaks. ponytail ceiling: embedder-backed scoring via `@arnilo/prism-memory/rag` if accuracy fixtures fall short.
279
+ - Cross-link: skills apply the same discipline to prompt text — see [Context and skills](context-and-skills.md).
280
+
254
281
  ## Guardrails
255
282
 
256
283
  `DispatchToolCallOptions.guardrails` evaluates `tool_input` after `tool_call` middleware normalization and before lookup, permission, validation, execution policy, or side effect. `tool_output` evaluates raw completed results before redaction, event emission, ledger rows, and transcript append. A block returns a blocked result; tripwire fails the enclosing run. See [Guardrails](guardrails.md).
257
284
 
258
285
  ## Related APIs
259
286
 
260
- - [OpenAPI tools adapter](openapi-tools.md): optional `@arnilo/prism-openapi-tools` `createOpenApiTools` — compile host-selected OpenAPI 3.1 operationIds into bounded `ToolDefinition`s (allow-list only, pinned origin, resolved/bounded schemas, approval + effect-store idempotency on mutations, bounded body/response/retries/pagination, host credential resolver, untrusted output).
287
+ - [OpenAPI tools adapter](openapi-tools.md): optional `@arnilo/prism-coding-tools/openapi` `createOpenApiTools` — compile host-selected OpenAPI 3.1 operationIds into bounded `ToolDefinition`s (allow-list only, pinned origin, resolved/bounded schemas, approval + effect-store idempotency on mutations, bounded body/response/retries/pagination, host credential resolver, untrusted output).
261
288
  - [Agent/session runtime](agent-session-runtime.md): dispatches complete provider tool calls through the host-active tool harness and returns tool results on the next provider turn.
262
289
  - [Public contracts](public-contracts.md): `ToolDefinition`, `ToolRegistry`, `ToolExecutionContext`, `ToolResult`, and tool `AgentEvent` contracts.
263
290
  - [Contribution registries](contribution-registries.md): inert extension/package tool contribution storage.
@@ -270,6 +297,6 @@ createJsonSchemaToolArgumentValidator({
270
297
  - [MCP client bridge](mcp-tools.md): optional remote tool mapping plus separate bounded resource/prompt facades; non-tool MCP capabilities never bypass tool dispatch by masquerading as `ToolDefinition`.
271
298
  - [Recoverable tool effects](tool-effects.md): optional `tool.effect` + `effectStore` claim/CAS recovery around dispatch.
272
299
  - [Recoverable tool effects](tool-effects.md): optional `tool.effect` + `effectStore` claim/CAS recovery around dispatch.
273
- - [Coding agent tools](coding-agent-tools.md): optional first-party `@arnilo/prism-coding-agent` `shell`/`read`/`write`/`edit` tools a host registers into this harness.
300
+ - [Coding agent tools](coding-agent-tools.md): optional first-party `@arnilo/prism-coding-tools/agent` `shell`/`read`/`write`/`edit` tools a host registers into this harness.
274
301
 
275
302
  `DispatchToolCallOptions.trust` and `.permission` run before validation or `execute()`; denial emits `tool_execution_blocked`. Middleware cannot bypass either guard. `AgentConfig.validator`/`RunOptions.validate` run after these guards; their output is redacted through the active `SecretRedactor`. `createSecureAgent()` requires all three seams plus non-empty schemas and durable pre-tool approval. Prism does not sandbox tools. See [Security/auth/trust](settings-auth-trust-security.md).
package/docs/web-tools.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  Use when agent needs explicit public-web discovery or host-approved document retrieval/extraction. Keep search separate from fetch/extract so model cannot select provider, credential, API origin, extraction schema, or cost path.
10
10
 
11
- **Obscura-backed alternative**: the optional [`@arnilo/prism-obscura`](obscura.md) package provides `web_search`/`web_fetch` behavior backed by a host-installed Obscura headless browser through its CLI (one replaceable HTML search profile instead of an API key), plus explicit native `obscura_fetch`/`obscura_scrape` batch tools. It reuses this package's normalized citation/untrusted shapes (`provider: "obscura"`) but does not require credentials; the API-backed Brave/Exa/Firecrawl adapters here remain the preferred path when an API key is available.
11
+ **Obscura-backed alternative**: the optional `@arnilo/prism-web-tools/obscura` subpath ([Obscura](obscura.md)) provides `web_search`/`web_fetch` behavior backed by a host-installed Obscura headless browser through its CLI (one replaceable HTML search profile instead of an API key), plus explicit native `obscura_fetch`/`obscura_scrape` batch tools. It reuses this package's normalized citation/untrusted shapes (`provider: "obscura"`) but does not require credentials; the API-backed Brave/Exa/Firecrawl adapters here remain the preferred path when an API key is available.
12
12
 
13
13
  ## Inputs / request
14
14
 
@@ -44,7 +44,7 @@ Fetch returns bounded Markdown and selected attribution. Extract validates host
44
44
 
45
45
  ```ts
46
46
  import { createEnvCredentialResolver } from "@arnilo/prism";
47
- import { createJsonSchemaArgumentValidator } from "@arnilo/prism-tool-validator-json-schema";
47
+ import { createJsonSchemaArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
48
48
  import { createBraveSearch, createFirecrawlExtractor, createFirecrawlFetch, createWebTools } from "@arnilo/prism-web-tools";
49
49
 
50
50
  const credentials = createEnvCredentialResolver(process.env, {
@@ -69,7 +69,7 @@ Default/hard limits: query 4/16 KiB; results 10/20; URLs 5/20; request 256 KiB/1
69
69
 
70
70
  Provider credentials never enter tool schemas/results, prompts, telemetry, URLs, or errors. Error text excludes remote bodies. Search snippets, Markdown, and extracted JSON are prompt-injection-capable data: never concatenate them into system instructions or use them to modify tools, permissions, credentials, trust, routing, or schemas. Firecrawl fetches target URLs remotely; Prism cannot claim target DNS pinning after handoff. Use controlled host fetch when that guarantee is required.
71
71
 
72
- Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Prefer these tools over `@arnilo/prism-browser` for ordinary public retrieval; use browser automation only for interactive/authenticated/JavaScript-heavy work behind a host egress proxy. Arbitrary HTML execution, model-selected providers, automatic OAuth forwarding, and generic web/MCP passthrough are unsupported.
72
+ Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Prefer the [`browser`](browser-automation.md) subpath over ordinary public retrieval; use browser automation only for interactive/authenticated/JavaScript-heavy work behind a host egress proxy. Arbitrary HTML execution, model-selected providers, automatic OAuth forwarding, and generic web/MCP passthrough are unsupported.
73
73
 
74
74
  ## Related APIs
75
75
 
package/docs/wiki.md CHANGED
@@ -1,8 +1,8 @@
1
- # LLM Wiki (@arnilo/prism-wiki)
1
+ # LLM Wiki (@arnilo/prism-memory/wiki)
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-wiki` implements Andrej Karpathy's **LLM Wiki Pattern** for the Prism agent ecosystem. It acts as a knowledge compiler that transforms raw, immutable sources (source code, AST symbols, notes, markdown clips, transcripts, journal entries) into a persistent, compounding, cross-linked Markdown knowledge base (`.wiki/`).
5
+ The `@arnilo/prism-memory/wiki` subpath implements Andrej Karpathy's **LLM Wiki Pattern** for the Prism agent ecosystem. It acts as a knowledge compiler that transforms raw, immutable sources (source code, AST symbols, notes, markdown clips, transcripts, journal entries) into a persistent, compounding, cross-linked Markdown knowledge base (`.wiki/`).
6
6
 
7
7
  It integrates Tobias Lütke's [`qmd`](https://github.com/tobi/qmd) on-device hybrid search engine (BM25, vector search, and LLM reranking) and hydrates search results with Context7-inspired hierarchical breadcrumbs (`# Category > ## Topic`) and live clickable source line anchors (`file:///path/to/file#Lxx-Lyy` format), enabling agents and humans to navigate code and notes directly without blind regex loops (`grep`/`rg`).
8
8
 
@@ -98,7 +98,7 @@ The authentication layer uses asymmetric Ed25519 JWT verification in middleware,
98
98
 
99
99
  ```ts
100
100
  import { createExtensionKernel } from "@arnilo/prism";
101
- import { createWikiExtension, initWiki, refreshWiki, lintWiki } from "@arnilo/prism-wiki";
101
+ import { createWikiExtension, initWiki, refreshWiki, lintWiki } from "@arnilo/prism-memory/wiki";
102
102
 
103
103
  const kernel = createExtensionKernel();
104
104
 
@@ -112,7 +112,7 @@ await kernel.load([wiki]);
112
112
 
113
113
  ## Skills and Auto-Deployment
114
114
 
115
- `@arnilo/prism-wiki` includes two specialized skills formatted according to `.agents/skills/skill-creator`:
115
+ The wiki subpath includes two specialized skills formatted according to `.agents/skills/skill-creator`:
116
116
 
117
117
  1. **`wiki-maintainer`**: Ingestion, compilation, line-anchor validation, and contradiction reconciliation rules.
118
118
  2. **`wiki-searcher`**: Context7 hierarchical breadcrumb query resolution, zero-grep instructions, and compounding insight recording.
@@ -135,7 +135,7 @@ Emitted `.wiki/` trees are [OKF v0.2](https://github.com/GoogleCloudPlatform/ope
135
135
 
136
136
  ## Extension and configuration notes
137
137
 
138
- - `@arnilo/prism-wiki` registers tools (`wiki_search`, `wiki_read_page`, `wiki_record_insight`), commands (`wiki-init`, `wiki-refresh`, `wiki-lint`), skills (`wiki-maintainer`, `wiki-searcher`), and instruction injectors (`wiki-guidance`) into Prism registries.
138
+ - The wiki subpath registers tools (`wiki_search`, `wiki_read_page`, `wiki_record_insight`), commands (`wiki-init`, `wiki-refresh`, `wiki-lint`), skills (`wiki-maintainer`, `wiki-searcher`), and instruction injectors (`wiki-guidance`) into Prism registries.
139
139
  - It operates with zero core modifications and can be used with any `@arnilo/prism` agent.
140
140
  - `qmd` is optional but recommended. When `@tobilu/qmd` is not installed, the search engine falls back to catalog matching against `index.md`.
141
141
 
@@ -148,7 +148,7 @@ Emitted `.wiki/` trees are [OKF v0.2](https://github.com/GoogleCloudPlatform/ope
148
148
 
149
149
  ## Related APIs
150
150
 
151
- - [`@arnilo/prism-rag`](rag.md): Bounded document chunking and vector context injection.
151
+ - [`@arnilo/prism-memory/rag`](rag.md): Bounded document chunking and vector context injection.
152
152
  - [`@arnilo/prism-memory`](working-and-semantic-memory.md): Embedder and VectorStore primitives.
153
- - [`@arnilo/prism-coding-agent`](coding-agent-tools.md): Code manipulation and reading tools.
153
+ - [`@arnilo/prism-coding-tools/agent`](coding-agent-tools.md): Code manipulation and reading tools.
154
154
  - [`Contribution registries`](contribution-registries.md): Extension contribution model.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-server` ships a durable artifact co-work review service (Phase 9 / 0.0.14): authorized attach of source/output references with MIME/hash/version, producer-run attribution, citations/data sources, and preview metadata; revision comparison; reviewer approve/reject (request-changes) with last-validated recovery; and authorized, expiring delivery links. Core (`@arnilo/prism`) exports artifact **types only** (`ArtifactRecord`, `ArtifactRevision`, `ArtifactApproval`, `ArtifactDeliveryToken`, approval state `pending | approved | rejected`). Prism persists bounded metadata, revisions, approvals, and delivery references over the existing versioned checkpoint store — **never file bodies**; hosts own blob storage and rendering.
5
+ `@arnilo/prism-core/runtime/server` ships a durable artifact co-work review service (Phase 9 / 0.0.14): authorized attach of source/output references with MIME/hash/version, producer-run attribution, citations/data sources, and preview metadata; revision comparison; reviewer approve/reject (request-changes) with last-validated recovery; and authorized, expiring delivery links. Core (`@arnilo/prism`) exports artifact **types only** (`ArtifactRecord`, `ArtifactRevision`, `ArtifactApproval`, `ArtifactDeliveryToken`, approval state `pending | approved | rejected`). Prism persists bounded metadata, revisions, approvals, and delivery references over the existing versioned checkpoint store — **never file bodies**; hosts own blob storage and rendering.
6
6
 
7
7
  ## When to use it
8
8
 
@@ -22,7 +22,7 @@ Not for: storing file content (use host blob storage), local Office preview/rend
22
22
  | `options.redactor` | yes | `SecretRedactor`; records are redacted before persist and on every response |
23
23
  | `options.linkSecret` | yes | Host HMAC key material for signing/verifying delivery links |
24
24
  | `options.limits` | no | Frozen caps (below); each clamped to a hard maximum |
25
- | `options.onDecision` | no | Audit seam (redacted refs) for attach/revise/approve/reject; bridge to `@arnilo/prism-policy` |
25
+ | `options.onDecision` | no | Audit seam (redacted refs) for attach/revise/approve/reject; bridge to `@arnilo/prism-core/governance/policy` |
26
26
 
27
27
  Every operation input carries `ownership` (from host `authorize`, never request JSON) plus optional verified `identity`. `attach` requires `threadId`, `uri`, `mime`, `hash`; `revise` requires `uri`, `hash` (mime defaults to the previous revision); `compare` requires two distinct revision numbers; `approve`/`reject` require a `version`; `deliveryLink` accepts optional `version` (defaults to last validated, else latest) and `ttlSeconds`.
28
28
 
@@ -56,8 +56,8 @@ No package-owned agent events are emitted; `onDecision` is the audit seam (redac
56
56
 
57
57
  ```ts
58
58
  import { createSecretRedactor } from "@arnilo/prism";
59
- import { createSqlitePersistence } from "@arnilo/prism-session-store-sqlite";
60
- import { createArtifactService, createArtifactHandler } from "@arnilo/prism-server";
59
+ import { createSqlitePersistence } from "@arnilo/prism-core/sessions/sqlite";
60
+ import { createArtifactService, createArtifactHandler } from "@arnilo/prism-core/runtime/server";
61
61
 
62
62
  const persistence = createSqlitePersistence({ filename: "prism.db" });
63
63
  const artifacts = createArtifactService(persistence.checkpoints, {
@@ -79,7 +79,7 @@ export const handler = createArtifactHandler({ service: artifacts, authorize: ho
79
79
  - Artifact records are versioned checkpoint values (namespace `prism.artifact`, key `threadId:artifactId`). The checkpoint `version` is the CAS counter for concurrent reviewers, distinct from revision numbers. Any `CheckpointStore` works; sqlite/postgres persistence already expose `.checkpoints`, so there is no separate artifact schema or migration.
80
80
  - `createArtifactHandler` mounts attach/list/get/revise/compare/approve/reject/last-validated/delivery-link plus `GET /prism/artifacts/download?link=…`. Download verifies the link signature + expiry, then **reauthorizes** against the token's ownership (mismatch fails closed), and returns the authorized revision reference only — the host fetches the body.
81
81
  - Delivery links are `base64url(payload).base64url(HMAC-SHA256)` over `{ artifactId, threadId, version, ownership, issuedAt, expiresAt }`; they are reauthorized per download and are not bearer secrets.
82
- - **Blob storage (0.0.28)**: `createArtifactService` accepts an optional `bodies: ArtifactBodyStore` (core contract in `src/artifacts.ts`: `put`/`get`/`delete`/`presign` by opaque, ownership-scoped `ArtifactBodyRef`). When wired, `deliveryLink` resolves through `bodies.presign` and returns an additional `url` (bounded-TTL, single-object presigned URL) beside the signed link/token; revisions must carry a recorded `size` (optional on attach/revise) or delivery fails closed. The reference adapter is `@arnilo/prism-server/artifact-bodies` `createS3ArtifactBodyStore` (hand-rolled SigV4 over native fetch + WebCrypto, path-style, single-chunk PUT with verified `x-amz-content-sha256`; works with AWS S3, MinIO, Cloudflare R2). Hosts may substitute any store; the contract is storage-free in core.
82
+ - **Blob storage (0.0.28)**: `createArtifactService` accepts an optional `bodies: ArtifactBodyStore` (core contract in `src/artifacts.ts`: `put`/`get`/`delete`/`presign` by opaque, ownership-scoped `ArtifactBodyRef`). When wired, `deliveryLink` resolves through `bodies.presign` and returns an additional `url` (bounded-TTL, single-object presigned URL) beside the signed link/token; revisions must carry a recorded `size` (optional on attach/revise) or delivery fails closed. The reference adapter is `@arnilo/prism-core/runtime/server/artifact-bodies` `createS3ArtifactBodyStore` (hand-rolled SigV4 over native fetch + WebCrypto, path-style, single-chunk PUT with verified `x-amz-content-sha256`; works with AWS S3, MinIO, Cloudflare R2). Hosts may substitute any store; the contract is storage-free in core.
83
83
  - Body stores verify ownership on every operation, verify size/SHA-256/MIME on put and get (fail closed), refuse delete under legal hold (host `isHeld` callback), and are idempotent on delete (retention sweeps delete bodies with metadata). Credentials come only from the host resolver; bucket/path/key never appear in errors, telemetry, or artifact records (the object key is derived from the ref).
84
84
  - Review loops driven by an agent consume the shared `RunLimits` at the host's agent layer; the artifact service itself is a passive, bounded record store.
85
85
 
@@ -93,7 +93,18 @@ export const handler = createArtifactHandler({ service: artifacts, authorize: ho
93
93
 
94
94
  ## Coding patch review composition (0.2.6, plan 026)
95
95
 
96
- `@arnilo/prism-coding-agent` composes over this service for the coding patch review workflow: `createCodingPatchReviewManifest` builds a bounded manifest (repository/worktree identity, base/head, patch digest, changed paths, diffstat, check and diagnostic summaries) and returns a structural `ArtifactAttachInput` whose `preview.review` embeds the manifest and whose `hash` is the patch SHA-256; `assertCodingPatchAccepted` derives `pending|accepted|rejected|superseded` from the returned `ArtifactRecord` by binding to the exact artifact revision, digest, and identity — any patch/repository/worktree/base/head change supersedes a prior acceptance (a newer revision attached after approval makes the old acceptance stale and refused). Decisions never apply/commit/push/merge; the manifest never embeds a raw patch body. Full contract: [Coding review and diagnostics](coding-review-and-diagnostics.md).
96
+ `@arnilo/prism-coding-tools/agent` composes over this service for the coding patch review workflow: `createCodingPatchReviewManifest` builds a bounded manifest (repository/worktree identity, base/head, patch digest, changed paths, diffstat, check and diagnostic summaries) and returns a structural `ArtifactAttachInput` whose `preview.review` embeds the manifest and whose `hash` is the patch SHA-256; `assertCodingPatchAccepted` derives `pending|accepted|rejected|superseded` from the returned `ArtifactRecord` by binding to the exact artifact revision, digest, and identity — any patch/repository/worktree/base/head change supersedes a prior acceptance (a newer revision attached after approval makes the old acceptance stale and refused). Decisions never apply/commit/push/merge; the manifest never embeds a raw patch body. Full contract: [Coding review and diagnostics](coding-review-and-diagnostics.md).
97
+
98
+ ## Live probe (plans/064 Task 9)
99
+
100
+ The S3 artifact-body store has an operator-gated live probe against a real S3-compatible endpoint (use a throwaway bucket):
101
+
102
+ ```bash
103
+ PRISM_TEST_S3_ENDPOINT=https://s3.us-east-1.amazonaws.com PRISM_TEST_S3_KEY=<key> \
104
+ PRISM_TEST_S3_SECRET=<secret> PRISM_TEST_S3_BUCKET=prism-throwaway npm test -w @arnilo/prism-core -- artifact-bodies-live
105
+ ```
106
+
107
+ Probes: put → get (hash + size verified), presigned delivery URL with `X-Amz-Signature`, and an idempotent double delete. Bounded to ≤ 3 real requests. Registered in `scripts/live-matrix.json` as `core/artifact-bodies-s3-live`.
97
108
 
98
109
  ## Related APIs
99
110
 
@@ -1,6 +1,6 @@
1
1
  # Work connectors
2
2
 
3
- Least-privilege Microsoft 365 and Google Workspace connectors live in `@arnilo/prism-work-tools`.
3
+ Least-privilege Microsoft 365 and Google Workspace connectors live in `@arnilo/prism-core/integrations/work`.
4
4
 
5
5
  ## Principles
6
6
 
@@ -13,19 +13,19 @@ Least-privilege Microsoft 365 and Google Workspace connectors live in `@arnilo/p
13
13
 
14
14
  ## Microsoft 365
15
15
 
16
- See [Work tools](work-tools.md). Adapter: `createMicrosoft365CliAdapter` / subpath `@arnilo/prism-work-tools/microsoft365`.
16
+ See [Work tools](work-tools.md). Adapter: `createMicrosoft365CliAdapter` / subpath `@arnilo/prism-core/integrations/work/microsoft365`.
17
17
 
18
18
  Uses [@pnp/cli-microsoft365](https://pnp.github.io/cli-microsoft365/) commands such as `outlook message list|get`, `outlook mail send`, `outlook event list|add`, `file list|add`, `spo file sharinglink add`. To Do / Planner / Teams remain capability-gated.
19
19
 
20
20
  ## Google Workspace
21
21
 
22
- See [Work tools](work-tools.md). Adapter: `createGoogleWorkspaceCliAdapter` / subpath `@arnilo/prism-work-tools/google-workspace`.
22
+ See [Work tools](work-tools.md). Adapter: `createGoogleWorkspaceCliAdapter` / subpath `@arnilo/prism-core/integrations/work/google-workspace`.
23
23
 
24
24
  Uses [`@googleworkspace/cli` (`gws`)](https://github.com/googleworkspace/cli): `gmail users messages list|get`, `gmail +send`, `calendar events list|insert`, `drive files list|create`, `drive permissions create`, `tasks tasks *`. Docs/Sheets/Slides create remain capability-gated. Discovery `schema` and `auth`/`login`/`setup` are forbidden from Prism argv.
25
25
 
26
26
  ## Scoped OAuth establishment (0.0.14)
27
27
 
28
- Hosts establish, refresh, and revoke scoped OAuth credentials for these workloads through the existing `OAuthProvider` / credential-store seams (`@arnilo/prism-credentials-node`): `createMicrosoft365OAuthProvider` / `createGoogleWorkspaceOAuthProvider` (PKCE + device code), least-privilege scope bundles per capability (`resolveMicrosoft365Scopes` / `resolveGoogleWorkspaceScopes`, read vs mutation). Connectors consume a per-identity token via a late-bound `tokenProvider` injected as an env var — never argv, never model context; revocation fails closed. See [Credential storage](credential-storage.md) and [Work tools](work-tools.md).
28
+ Hosts establish, refresh, and revoke scoped OAuth credentials for these workloads through the existing `OAuthProvider` / credential-store seams (`@arnilo/prism-core/credentials/node`): `createMicrosoft365OAuthProvider` / `createGoogleWorkspaceOAuthProvider` (PKCE + device code), least-privilege scope bundles per capability (`resolveMicrosoft365Scopes` / `resolveGoogleWorkspaceScopes`, read vs mutation). Connectors consume a per-identity token via a late-bound `tokenProvider` injected as an env var — never argv, never model context; revocation fails closed. See [Credential storage](credential-storage.md) and [Work tools](work-tools.md).
29
29
 
30
30
  ## Out of scope
31
31