@arnilo/prism 0.0.1 → 0.0.2

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 (120) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/README.md +17 -7
  3. package/dist/agent-definitions.d.ts +12 -0
  4. package/dist/agent-definitions.js +131 -0
  5. package/dist/agent-loops.d.ts +14 -0
  6. package/dist/agent-loops.js +161 -0
  7. package/dist/agents.js +263 -76
  8. package/dist/cache-helpers.d.ts +28 -0
  9. package/dist/cache-helpers.js +73 -0
  10. package/dist/cli-runner.d.ts +38 -2
  11. package/dist/cli-runner.js +167 -5
  12. package/dist/compaction.js +2 -0
  13. package/dist/config.js +47 -12
  14. package/dist/contracts.d.ts +581 -6
  15. package/dist/contracts.js +41 -1
  16. package/dist/contribution-parsing.d.ts +19 -0
  17. package/dist/contribution-parsing.js +124 -0
  18. package/dist/contributions.d.ts +13 -3
  19. package/dist/contributions.js +96 -20
  20. package/dist/extensions.js +3 -0
  21. package/dist/index.d.ts +19 -9
  22. package/dist/index.js +10 -4
  23. package/dist/input.d.ts +7 -1
  24. package/dist/input.js +52 -11
  25. package/dist/instruction-injection.d.ts +28 -0
  26. package/dist/instruction-injection.js +55 -0
  27. package/dist/manifests.d.ts +1 -1
  28. package/dist/manifests.js +3 -3
  29. package/dist/models.d.ts +4 -1
  30. package/dist/models.js +5 -2
  31. package/dist/node/agent-definitions.d.ts +98 -0
  32. package/dist/node/agent-definitions.js +389 -0
  33. package/dist/node/contribution-discovery.d.ts +17 -0
  34. package/dist/node/contribution-discovery.js +163 -0
  35. package/dist/node/instruction-injectors.d.ts +32 -0
  36. package/dist/node/instruction-injectors.js +72 -0
  37. package/dist/node/session-store-jsonl.d.ts +1 -1
  38. package/dist/node/session-store-jsonl.js +42 -4
  39. package/dist/node/system-project-prompts.d.ts +30 -0
  40. package/dist/node/system-project-prompts.js +53 -0
  41. package/dist/provider-events.d.ts +3 -1
  42. package/dist/provider-events.js +34 -0
  43. package/dist/provider-request-policy.js +15 -1
  44. package/dist/providers/openai-compatible.js +1 -1
  45. package/dist/providers.d.ts +6 -2
  46. package/dist/providers.js +15 -1
  47. package/dist/redaction.d.ts +2 -1
  48. package/dist/redaction.js +3 -0
  49. package/dist/registry-options.d.ts +5 -0
  50. package/dist/registry-options.js +5 -0
  51. package/dist/rpc.d.ts +6 -2
  52. package/dist/rpc.js +71 -13
  53. package/dist/session-stores.d.ts +3 -1
  54. package/dist/session-stores.js +67 -6
  55. package/dist/skills.d.ts +4 -1
  56. package/dist/skills.js +3 -1
  57. package/dist/system-prompts.js +6 -2
  58. package/dist/testing/compaction-conformance.d.ts +17 -0
  59. package/dist/testing/compaction-conformance.js +61 -0
  60. package/dist/testing/extension-conformance.d.ts +26 -0
  61. package/dist/testing/extension-conformance.js +55 -0
  62. package/dist/testing/provider-conformance.d.ts +7 -0
  63. package/dist/testing/provider-conformance.js +18 -31
  64. package/dist/testing/session-store-conformance.d.ts +20 -0
  65. package/dist/testing/session-store-conformance.js +92 -0
  66. package/dist/testing/tool-conformance.d.ts +39 -0
  67. package/dist/testing/tool-conformance.js +79 -0
  68. package/dist/tools.d.ts +7 -2
  69. package/dist/tools.js +50 -13
  70. package/docs/agent-definitions.md +251 -0
  71. package/docs/agent-events.md +199 -0
  72. package/docs/agent-loops.md +217 -0
  73. package/docs/agent-session-runtime.md +20 -8
  74. package/docs/cli-rpc.md +39 -4
  75. package/docs/compaction-and-retry.md +2 -2
  76. package/docs/compaction-conformance.md +76 -0
  77. package/docs/compaction-llm.md +6 -3
  78. package/docs/compaction-observational-memory.md +4 -4
  79. package/docs/configuration-and-manifests.md +6 -1
  80. package/docs/context-and-skills.md +79 -6
  81. package/docs/contribution-discovery.md +149 -0
  82. package/docs/contribution-registries.md +9 -6
  83. package/docs/credentials-and-redaction.md +2 -0
  84. package/docs/customization.md +191 -0
  85. package/docs/database-persistence.md +407 -0
  86. package/docs/extension-authoring.md +193 -0
  87. package/docs/extension-conformance.md +80 -0
  88. package/docs/extensions.md +6 -0
  89. package/docs/host-security.md +141 -0
  90. package/docs/index.md +40 -19
  91. package/docs/input-and-prompt-assembly.md +19 -3
  92. package/docs/instruction-injection.md +183 -0
  93. package/docs/migration.md +201 -0
  94. package/docs/model-registry.md +122 -0
  95. package/docs/node-jsonl-session-store.md +5 -4
  96. package/docs/performance.md +127 -0
  97. package/docs/provider-caching.md +206 -0
  98. package/docs/provider-conformance.md +32 -5
  99. package/docs/provider-layer.md +51 -11
  100. package/docs/provider-packages.md +65 -5
  101. package/docs/provider-request-policies.md +113 -0
  102. package/docs/providers/kimi.md +22 -0
  103. package/docs/providers/neuralwatt.md +388 -0
  104. package/docs/providers/openai-compatible.md +1 -0
  105. package/docs/providers/openai.md +21 -0
  106. package/docs/providers/opencode-go.md +31 -3
  107. package/docs/providers/openrouter.md +29 -0
  108. package/docs/providers/zai.md +17 -0
  109. package/docs/public-contracts.md +87 -12
  110. package/docs/release-and-install.md +76 -26
  111. package/docs/runs-and-usage.md +236 -0
  112. package/docs/session-store-conformance.md +78 -0
  113. package/docs/session-stores-and-branching.md +10 -6
  114. package/docs/session-stores.md +126 -0
  115. package/docs/settings-auth-trust-security.md +18 -4
  116. package/docs/structured-output.md +247 -0
  117. package/docs/system-prompts.md +104 -2
  118. package/docs/tool-conformance.md +87 -0
  119. package/docs/tools.md +64 -8
  120. package/package.json +35 -2
@@ -0,0 +1,247 @@
1
+ # Structured output
2
+
3
+ ## What it does
4
+
5
+ Structured output in Prism is the `Artifact*` contract seam: a host-defined type `T` threaded through host-supplied `parser` → `validator` → `repairer` callbacks inside the `generateValidateReviseLoop` agent loop. Prism never instantiates `T`. The only way to get typed output from a loop is `ArtifactParser<T>`; Prism has no `WorkflowStep`/`NodeSchema`/`synapta*` types and no domain control-flow vocabulary — the seam is generic over an opaque host `T`.
6
+
7
+ An artifact loop generates provider text, parses it to `T`, validates `T` against a host schema, and on validation failure runs a repairer to build a follow-up input that asks the model to fix the artifact — repeating up to `maxRevisions` times. The result of every validation and the terminal `artifact_finished`/`artifact_failed` outcomes are observable through `AgentEvent` artifact variants.
8
+
9
+ ## When to use it
10
+
11
+ Use `generateValidateReviseLoop` (with host `parser`/`validator`/`repairer`) when a run should produce an artifact that must satisfy a host-owned schema before it is considered complete: structured JSON output, a generated file passing lint, a typed response conforming to a Synapta-defined model. Wrap your existing schema/validation library behind the `Artifact*` callbacks.
12
+
13
+ Do not use it to re-implement provider calls, retry, abort, store, or event emission — those stay runtime-owned and are exposed to the loop only through `LoopContext`. Do not use it for runs that need tool calls during revision turns — use `singleShotLoop` or a custom `AgentLoopStrategy` instead. Do not put Synapta domain types into Prism; map them to `ArtifactValidation` in your callbacks.
14
+
15
+ ## Inputs / request
16
+
17
+ ```ts
18
+ import {
19
+ createAgent,
20
+ type ArtifactParser,
21
+ type ArtifactValidator,
22
+ type ArtifactRepairer,
23
+ type ArtifactValidation,
24
+ type ArtifactContext,
25
+ type ArtifactParseResult,
26
+ } from "@arnilo/prism";
27
+ ```
28
+
29
+ Host callback contracts (all generic over host `T`; Prism never instantiates `T`):
30
+
31
+ | Contract | Shape |
32
+ | --- | --- |
33
+ | `ArtifactParser<T>` | `(text: string, ctx: ArtifactContext) => ArtifactParseResult<T> \| Promise<...>` — parse assistant text to a typed value. |
34
+ | `ArtifactValidator<T>` | `(value: T, ctx: ArtifactContext) => ArtifactValidation \| Promise<...>` — return `{ ok: true }` or `{ ok: false, errors }`. |
35
+ | `ArtifactRepairer<T>` | `(value: T \| undefined, failure: ArtifactValidation, ctx: ArtifactContext) => AgentInput \| Promise<...>` — build the revision follow-up input. |
36
+ | `ArtifactValidation` | `{ ok: boolean; errors?: readonly { path?: string; message: string }[]; metadata?: Readonly<Record<string, unknown>> }`. |
37
+ | `ArtifactContext` | `{ sessionId, runId, turn, signal, metadata }` — passed to every callback. |
38
+ | `ArtifactParseResult<T>` | `{ ok: boolean; value?: T; error?: string }`. |
39
+
40
+ Loop selection (RunOptions wins over AgentConfig):
41
+
42
+ ```ts
43
+ await session.run(input, {
44
+ loop: {
45
+ strategy: "generate-validate-revise",
46
+ validator, // required
47
+ parser, // optional; default treats assistant text as the value
48
+ repairer, // optional; default stringifies validation.errors[].message
49
+ maxRevisions: 3, // optional; default 3
50
+ },
51
+ });
52
+ ```
53
+
54
+ ## Outputs / response / events
55
+
56
+ `generateValidateReviseLoop.run(ctx)` returns `Promise<Usage | undefined>`. Observable behavior is emitted through `AgentEvent` artifact variants (zero emitted by `singleShotLoop`):
57
+
58
+ ```
59
+ artifact_validation_started
60
+ → artifact_validation_finished
61
+ → (artifact_revision_started)*
62
+ → artifact_finished | artifact_failed
63
+ ```
64
+
65
+ See [Agent events § Artifact event ordering](agent-events.md#artifact-event-ordering). Validation-failure-triggering-a-revision is recoverable and never an `error`; only terminal budget exhaustion emits `artifact_failed`; real failures stay on `error`.
66
+
67
+ `ArtifactValidation.errors[].message` may echo model text — every `artifact_*` payload is redacted through `redactAgentEvent` / the active `SecretRedactor` before subscribers observe it.
68
+
69
+ ## Request/response example
70
+
71
+ ```json
72
+ {
73
+ "ok": false,
74
+ "errors": [{ "path": "title", "message": "missing required field" }],
75
+ "metadata": { "schema": "release-note/v1" }
76
+ }
77
+ ```
78
+
79
+ ## Implementation example
80
+
81
+ A Synapta-style host maps its own schema to `ArtifactValidation` via the callbacks — no Synapta type is imported by Prism:
82
+
83
+ ```ts
84
+ import {
85
+ createAgent,
86
+ createMockProvider,
87
+ providerTextDelta,
88
+ providerDone,
89
+ createSecretRedactor,
90
+ type ArtifactParser,
91
+ type ArtifactValidator,
92
+ type ArtifactRepairer,
93
+ } from "@arnilo/prism";
94
+
95
+ // Host owns this schema (Synapta's own type). Prism never imports it.
96
+ interface ReleaseNote { readonly title: string; readonly body: string }
97
+
98
+ const parser: ArtifactParser<ReleaseNote> = (text) => {
99
+ try {
100
+ const value = JSON.parse(text) as ReleaseNote;
101
+ return { ok: true, value };
102
+ } catch (error) {
103
+ return { ok: false, error: error instanceof Error ? error.message : "parse failed" };
104
+ }
105
+ };
106
+
107
+ const validator: ArtifactValidator<ReleaseNote> = (value) =>
108
+ value.title && value.body
109
+ ? { ok: true }
110
+ : { ok: false, errors: [{ path: value.title ? "body" : "title", message: "missing field" }] };
111
+
112
+ const repairer: ArtifactRepairer<ReleaseNote> = (_value, failure) => ({
113
+ role: "user",
114
+ content: [{ type: "text", text: `Fix these: ${failure.errors?.map((e) => e.path ? `${e.path}: ${e.message}` : e.message).join("; ")}` }],
115
+ });
116
+
117
+ const agent = createAgent({
118
+ model: { provider: "mock", model: "demo" },
119
+ provider: createMockProvider([
120
+ providerTextDelta(JSON.stringify({ title: "ok", body: "v1" })),
121
+ providerDone(),
122
+ ]),
123
+ // Redact any leaked secrets from model text echoed in errors[].message/metadata.
124
+ redactor: createSecretRedactor([process.env.APP_KEY]),
125
+ });
126
+
127
+ await agent.createSession().run("Produce the JSON release note.", {
128
+ loop: { strategy: "generate-validate-revise", validator, parser, repairer, maxRevisions: 3 },
129
+ });
130
+ ```
131
+
132
+ ## End-to-end third-party integration
133
+
134
+ A third-party host (for example, Synapta) can mix first-party and own providers, register tools, select skills, load `AGENTS.md`/`SYSTEM.md`, and opt a run into the artifact loop — all without importing any `synapta*` types into Prism and without any `workflow`/`node`/`step` vocabulary in the core contracts.
135
+
136
+ ```ts
137
+ import {
138
+ createAgent,
139
+ createProviderResolver,
140
+ createToolRegistry,
141
+ createSkillRegistry,
142
+ createSecretRedactor,
143
+ type ArtifactParser,
144
+ type ArtifactValidator,
145
+ type ArtifactRepairer,
146
+ type ToolDefinition,
147
+ type Skill,
148
+ } from "@arnilo/prism";
149
+ import { loadSystemPromptFiles } from "@arnilo/prism/node/system-prompts";
150
+
151
+ // Host-owned schema (Synapta's own type). Prism never imports it.
152
+ interface ReleaseNote { readonly title: string; readonly body: string }
153
+
154
+ // Map the host schema to ArtifactValidation. The callbacks are generic at the
155
+ // loop boundary; cast to the host schema inside the callback body.
156
+ const validator: ArtifactValidator<unknown> = (value) => {
157
+ const note = value as ReleaseNote;
158
+ const errors: { readonly path?: string; readonly message: string }[] = [];
159
+ if (!note.title) errors.push({ path: "title", message: "missing title" });
160
+ if (!note.body) errors.push({ path: "body", message: "missing body" });
161
+ return errors.length === 0 ? { ok: true } : { ok: false, errors };
162
+ };
163
+
164
+ const parser: ArtifactParser<unknown> = (text) => {
165
+ try { return { ok: true, value: JSON.parse(text) as ReleaseNote }; }
166
+ catch (error) { return { ok: false, error: error instanceof Error ? error.message : "parse failed" }; }
167
+ };
168
+
169
+ const repairer: ArtifactRepairer<unknown> = (_value, failure) => ({
170
+ role: "user",
171
+ content: [{
172
+ type: "text",
173
+ text: `Fix these issues: ${failure.errors?.map((e) => e.path ? `${e.path}: ${e.message}` : e.message).join("; ")}`,
174
+ }],
175
+ });
176
+
177
+ // Mix a first-party provider with a host-owned one.
178
+ const resolver = createProviderResolver([
179
+ firstPartyMockProvider, // e.g. from a Prism provider package
180
+ createOwnMockProvider(), // host-implemented AIProvider
181
+ ]);
182
+
183
+ const tools = createToolRegistry([
184
+ firstPartyEchoTool,
185
+ { name: "acme/fetch-schema", /* ...host tool definition... */ } as ToolDefinition,
186
+ ]);
187
+
188
+ const skills = createSkillRegistry([
189
+ {
190
+ name: "schema-skill",
191
+ instructions: "Use the release-note schema and the acme/fetch-schema tool when needed.",
192
+ toolNames: ["acme/fetch-schema"],
193
+ // context: [schemaContextProvider],
194
+ } as Skill,
195
+ ]);
196
+
197
+ const agent = createAgent({
198
+ model: { provider: "acme", model: "artifact-v1" },
199
+ providerSource: resolver,
200
+ tools,
201
+ skills,
202
+ instructions: "You are a release-note writer.",
203
+ systemPrompt: await loadSystemPromptFiles({ workspaceRoot, globalRoot }),
204
+ redactor: createSecretRedactor([process.env.ACME_API_KEY ?? ""]),
205
+ });
206
+
207
+ await agent.createSession().run("Write the release note.", {
208
+ activeSkills: ["schema-skill"],
209
+ loop: { strategy: "generate-validate-revise", validator, parser, repairer, maxRevisions: 3 },
210
+ });
211
+ ```
212
+
213
+ Key cross-seam points:
214
+
215
+ - `providerSource` is a resolver, so the host can supply its own `AIProvider` alongside first-party ones. See [Provider packages](provider-packages.md) and [Provider layer](provider-layer.md).
216
+ - `tools` and `skills` are host-owned registries; a skill's `toolNames` and `context` are selected only when the skill is active. See [Tools](tools.md) and [Context and skills](context-and-skills.md).
217
+ - `systemPrompt` is loaded from `AGENTS.md`/`SYSTEM.md` via the Node loader; the runtime itself is file-name agnostic. See [System prompts](system-prompts.md).
218
+ - The `validator`/`parser`/`repairer` callbacks are typed as `Artifact*<unknown>` at the loop boundary; the host's `ReleaseNote` type is cast inside the callback body. Prism threads an opaque value and never instantiates it.
219
+ - Every `artifact_*` event payload is redacted through the active `SecretRedactor`, so secrets echoed in `errors[].message` or `metadata` are scrubbed before subscribers see them. See [Credentials and redaction](credentials-and-redaction.md).
220
+ - For a runnable, network-free version that also demonstrates tool dispatch and redaction, see [`examples/synapta-style-artifact-loop.ts`](../examples/synapta-style-artifact-loop.ts).
221
+
222
+ ## Extension and configuration notes
223
+
224
+ - `generate-validate-revise` is selected via `AgentConfig.loop` / `RunOptions.loop` (`RunOptions.loop` wins). See [Agent loops](agent-loops.md). `resolveLoop()` maps the options form to the factory; an unknown `strategy` throws before the first turn; a custom `AgentLoopStrategy` instance bypasses the options form.
225
+ - The default parser treats assistant text as the value (`{ ok: true, value: text }`); supply a host parser whenever `T` is not `string`.
226
+ - The default repairer builds a user message from `validation.errors[].message`; supply a host repairer for schema-specific guidance.
227
+ - `maxRevisions` (default 3) bounds revision turns; budget exhaustion ends the loop and emits `artifact_failed` (it does not throw).
228
+ - Tools are not dispatched in revision turns. Hosts needing tools in artifact turns use `singleShotLoop` or a custom loop.
229
+
230
+ ## Security and performance notes
231
+
232
+ - Prism never instantiates `T`; it only threads the host-supplied value through parser→validator→repairer. No Synapta type is imported by `src/`.
233
+ - Boundary lock: `src/` imports no `synapta*` package, and the `Artifact*` / `AgentLoop*` / `LoopContext` contract field names contain no `workflow`/`node`/`step` domain vocabulary. Hosts map their own schema names to `ArtifactValidation.errors[].path`.
234
+ - `ArtifactValidation.errors[].message` and `metadata` may echo model text; every `artifact_*` event payload is redacted through `redactAgentEvent` / the active `SecretRedactor`. The generic walker handles nested objects/arrays and replaces cyclic references with `"[Circular]"` without throwing.
235
+ - A run makes at most `maxRevisions + 1` provider turns; it cannot loop forever on an always-failing validator. Each revision costs one provider turn plus one store append.
236
+ - No new dependency is required to use structured output — host callbacks wrap whatever schema/validation library the host already uses.
237
+
238
+ ## Related APIs
239
+ - [Agent loops](agent-loops.md): `generateValidateReviseLoop` factory and `LoopContext`.
240
+ - [Agent events](agent-events.md): `artifact_validation_started` / `artifact_validation_finished` / `artifact_revision_started` / `artifact_finished` / `artifact_failed` variants.
241
+ - [Public contracts](public-contracts.md): `ArtifactValidation`, `ArtifactContext`, `ArtifactParseResult<T>`, `ArtifactParser<T>`, `ArtifactValidator<T>`, `ArtifactRepairer<T>`.
242
+ - [Credentials and redaction](credentials-and-redaction.md): `createSecretRedactor` and `redactAgentEvent`.
243
+ - [Agent/session runtime](agent-session-runtime.md): `session.run(input, options)` and `RunOptions.loop`.
244
+ - [Tools](tools.md): host-owned tool registries and dispatch.
245
+ - [Context and skills](context-and-skills.md): skill selection, `toolNames`, and context providers.
246
+ - [System prompts](system-prompts.md): composing layers and loading `AGENTS.md`/`SYSTEM.md`.
247
+ - [Provider packages](provider-packages.md) and [Provider layer](provider-layer.md): mixing first-party and host-owned providers.
@@ -28,7 +28,9 @@ composeSystemPrompt([
28
28
  ], { base: "Base instruction." });
29
29
  ```
30
30
 
31
- `source` order is deterministic for known sources: `package`, `app`, `user`, then `run`. Unknown sources keep input order after known sources.
31
+ Known `source` order is deterministic: `user`, `package`, `app`, then `run`. Unknown custom sources sort between `package` and `app`. Multiple unknown sources keep their relative input order. Unknown sources intentionally rank below host/app and run layers, so a custom `replace` or `disable` cannot override `RunOptions.systemPrompt` by sorting after it.
32
+
33
+ > **Behavior change (Phase 31):** `source: "user"` is now the global base layer (rank 0), not a high-priority caller override. Without unknown custom sources, the file/host layering arrow remains `SYSTEM.md` (user) → package → `AGENTS.md` (app) → host `AgentConfig.systemPrompt` → `RunOptions.systemPrompt` (run). With unknown custom sources, the full layering arrow is `SYSTEM.md` (user) → package → unknown custom sources → `AGENTS.md` (app) → host `AgentConfig.systemPrompt` → `RunOptions.systemPrompt` (run). Earlier phases ranked `user` above `package`/`app`; Phase 37 moved unknown custom sources below app/run after discovering they could otherwise sort after `run` and override run-level prompt policy. `RunOptions.systemPrompt: false` still disables every configured layer for the run and keeps `AgentConfig.instructions` as the base prompt.
32
34
 
33
35
  `mode` behavior:
34
36
 
@@ -99,18 +101,118 @@ export default definePrismManifest({
99
101
 
100
102
  The manifest entry does not load or apply the prompt. The host must still select it and pass the `SystemPromptContribution` to the runtime.
101
103
 
102
- No `SYSTEM.md`, `APPEND_SYSTEM.md`, prompt template, settings, or manifest discovery happens in core.
104
+ No `APPEND_SYSTEM.md`, prompt template, settings, or manifest discovery happens in core. `SYSTEM.md` / `AGENTS.md` walk-up loading is a Node/CLI concern — see [AGENTS.md and SYSTEM.md files](#agentsmd-and-systemmd-files) below.
103
105
 
104
106
  ## Security and performance notes
105
107
 
106
108
  - Composition is a single in-memory pass plus deterministic ordering; no dependency, watcher, filesystem read, provider call, or tokenizer is added.
107
109
  - Prompt text is caller-supplied content. Do not put secrets in prompts, settings, manifests, session entries, package metadata, or docs examples.
110
+ - Unknown custom sources rank before app/run layers; prefer `source: "package"` for package defaults and `source: "run"` only for host-selected run overrides.
108
111
  - `replace`/`disable` make prompt policy explicit; they are not permission or sandbox controls.
109
112
 
113
+ ## AGENTS.md and SYSTEM.md files
114
+
115
+ ### What it does
116
+
117
+ The Node loader `loadSystemPromptFiles` reads two standard prompt files and returns them as `SystemPromptContribution` layers that feed `composeSystemPrompt` — the same pipeline as explicit `AgentConfig.systemPrompt` layers. There is no parallel mechanism and no hidden global: the loader is a sibling of `src/node/instruction-injectors.ts`, opt-in by passing roots.
118
+
119
+ - `SYSTEM.md` at `<globalRoot>/.prism/agent/SYSTEM.md` — the user-owned global prompt, tagged `source: "user"` (the Phase 31 base layer). No trust gate; its presence is the user's explicit choice.
120
+ - `AGENTS.md` at `<workspaceRoot>/AGENTS.md` — the project prompt, tagged `source: "app"`. Trust-gated via `createPathTrustPolicy`; an untrusted workspace contributes nothing (fail-closed, silent skip).
121
+
122
+ The `prism` CLI auto-loads both in print/json modes (see [CLI/RPC](cli-rpc.md)); RPC mode does **not** auto-read them (the host owns the session factory).
123
+
124
+ ### When to use it
125
+
126
+ Use `loadSystemPromptFiles` when a Node host or the CLI wants to honor the standard `AGENTS.md` / `SYSTEM.md` layout without wiring prompt text by hand. Hosts pass `workspaceRoot` (defaults to `process.cwd()` on the CLI) and `globalRoot` (host-controlled; the CLI no longer defaults it to the user's home directory — pass it explicitly from a host adapter or use `--system-md-file`).
127
+
128
+ Do not use it to load arbitrary prompt templates, settings, or manifests — it reads exactly two filenames and nothing else. Do not use it from the SDK entrypoint (`@arnilo/prism`) — it lives in the Node subpath `@arnilo/prism/node/system-prompts` and performs real filesystem I/O.
129
+
130
+ ### Inputs / request
131
+
132
+ `loadSystemPromptFiles(options)`:
133
+
134
+ | Field | Meaning |
135
+ | --- | --- |
136
+ | `workspaceRoot?` | Reads `<workspaceRoot>/AGENTS.md` (trust-gated, `source: "app"`). |
137
+ | `globalRoot?` | Reads `<globalRoot>/.prism/agent/SYSTEM.md` (user-owned, `source: "user"`). |
138
+ | `agentsMdPath?` | Override the AGENTS.md path (still `source: "app"`, still trust-gated). |
139
+ | `systemMdPath?` | Override the SYSTEM.md path (still `source: "user"`, no trust gate). |
140
+ | `trust?` | `TrustPolicy` (e.g. `createPathTrustPolicy`) fail-closed against the workspace. |
141
+ | `permission?` | `PermissionPolicy` asserting each read (`assertPermission`). |
142
+
143
+ Passing no roots returns `[]` and performs no filesystem I/O — the SDK escape hatch. `AgentConfig.instructions` / `AgentConfig.systemPrompt` keep working unchanged.
144
+
145
+ CLI flags:
146
+
147
+ | Flag | Meaning |
148
+ | --- | --- |
149
+ | `--no-agents-md` | Skip auto-loading `<workspaceRoot>/AGENTS.md`. |
150
+ | `--no-system-md` | Skip auto-loading the global `SYSTEM.md` layer. The CLI does not default to the user's home directory; pass `globalRoot` from a host adapter or use `--system-md-file` to opt in. |
151
+ | `--agents-md-file <path>` | Read AGENTS.md from `<path>` instead (trust-gated, `source: "app"`). |
152
+ | `--system-md-file <path>` | Read SYSTEM.md from `<path>` instead (user-owned, `source: "user"`). |
153
+
154
+ `--system <text>` stays as `AgentConfig.instructions` (the base prompt) and is composed below the file layers. `RunOptions.systemPrompt` is not surfaced as a CLI flag (the `--system` base + the two file layers cover the CLI surface).
155
+
156
+ ### Outputs / response / events
157
+
158
+ `loadSystemPromptFiles()` returns `readonly SystemPromptContribution[]` — `SYSTEM.md` first (`source: "user"`), then `AGENTS.md` (`source: "app"`). Input order here only matters for the stable tie-break when sources collide; rank order (`user` → `package` → `app` → `run`) is enforced inside `composeSystemPrompt`. The CLI passes a non-empty result as `AgentConfig.systemPrompt`; the runtime composes it with `instructions` (base) and emits no separate event.
159
+
160
+ ### Request/response example
161
+
162
+ ```json
163
+ {
164
+ "base": "You are helpful.",
165
+ "layers": [
166
+ { "id": "system-md", "source": "user", "mode": "append", "text": "Global system policy." },
167
+ { "id": "agents-md", "source": "app", "mode": "append", "text": "Project rule." }
168
+ ],
169
+ "composed": "You are helpful.\n\nGlobal system policy.\n\nProject rule."
170
+ }
171
+ ```
172
+
173
+ ### Implementation example
174
+
175
+ ```ts
176
+ import { composeSystemPrompt } from "@arnilo/prism";
177
+ import { loadSystemPromptFiles } from "@arnilo/prism/node/system-prompts";
178
+ import { createPathTrustPolicy } from "@arnilo/prism/node/trust";
179
+
180
+ // Trust gate mirrors discoverContributions — untrusted AGENTS.md is skipped silently.
181
+ const trust = createPathTrustPolicy({ trustedRoots: [workspaceRoot] });
182
+ const layers = await loadSystemPromptFiles({ workspaceRoot, globalRoot, trust });
183
+ const composed = composeSystemPrompt(layers, { base: "You are helpful." });
184
+ ```
185
+
186
+ A complete runnable example lives at `examples/system-project-prompts.ts`.
187
+
188
+ ### Agent bundle prompt layers (Phase 34)
189
+
190
+ `resolveAgentBundle()` (from `@arnilo/prism/node/agent-definitions`) appends up to three prompt sources for a discovered agent bundle, in this fixed order, all reusing `composeSystemPrompt`'s `source` rank (`user` → `package` → `app` → `run`):
191
+
192
+ 1. `<configRoot>/agents/SYSTEM.md` — app-global prompt, `source: "user"`.
193
+ 2. `<configRoot>/agents/<agentName>/AGENT.md` — the per-agent bundle's markdown body (below the front fence), `source: "package"`.
194
+ 3. `<workspaceRoot>/AGENTS.md` — the repo-level project prompt, `source: "app"`.
195
+
196
+ Each layer is independently toggled via `ResolveAgentBundleOptions.include` (`systemPrompt`, `agentPrompt`, `repoPrompt`); all default to `true`. The app-config root and workspace root are trust-gated **independently** — an untrusted root contributes nothing (fail-closed, no throw). `RunOptions.systemPrompt` (`source: "run"`) still wins and is appended last at run time. Missing files are skipped silently.
197
+
198
+ ### Extension and configuration notes
199
+
200
+ The loader reads text only with two `readFile` calls max — no `readdir`, no scan, no `import()`. It does not fit `discoverContributions`' named-subdir scanner (these are root-level single files), so it is a sibling adapter over the shared `readOptionalFile` helper rather than another scanner kind. Override paths (`agentsMdPath` / `systemMdPath`) reuse the same trust gate, so a `--agents-md-file` opt-in still fails closed outside trusted roots.
201
+
202
+ ### Security and performance notes
203
+
204
+ - **Trust gating**: `AGENTS.md` (and `--agents-md-file`) pass through `createPathTrustPolicy` + `isPathInsideReal`, which resolve symlinks and fail closed. Untrusted workspaces contribute nothing — the run still works with base instructions. `SYSTEM.md` (whether from a host-supplied `globalRoot` or an explicit `--system-md-file`) is user-owned and is not trust-gated.
205
+ - **No code execution**: the loader never `import()`s or `eval()`s a discovered file — it reads prompt text only.
206
+ - **Redaction**: loaded prompt text is caller/host-supplied content subject to `redactProviderRequest` like any system instruction. Do not put secrets in `AGENTS.md` / `SYSTEM.md`, settings, manifests, or docs examples.
207
+ - **Performance**: two `readFile` calls per CLI print/json run; missing files are ENOENT-skipped. Default SDK use (no roots) performs no I/O. RPC mode does not auto-read these files.
208
+
110
209
  ## Related APIs
111
210
 
112
211
  - [Input and prompt assembly](input-and-prompt-assembly.md): default input builder receives the composed system instruction string.
113
212
  - [Agent/session runtime](agent-session-runtime.md): runtime fields `AgentConfig.systemPrompt` and `RunOptions.systemPrompt`.
213
+ - [Contribution discovery (workspace)](contribution-discovery.md): the scanner for `.agents/<kind>/<name>/` contributions; `AGENTS.md`/`SYSTEM.md` loading is a sibling loader, not a scanner kind.
114
214
  - [Contribution registries](contribution-registries.md): inert system prompt contribution registry.
115
215
  - [Extensions](extensions.md): `registerSystemPromptContribution()`.
216
+ - [CLI/RPC](cli-rpc.md): the `--no-agents-md` / `--no-system-md` / `--agents-md-file` / `--system-md-file` flags, and the `--agents-config <path>` app-config bundle flag.
217
+ - [Agent definitions](agent-definitions.md): `resolveAgentBundle` appends `SYSTEM.md` → `AGENT.md` body → repo `AGENTS.md` as a three-layer prompt model on top of this loader.
116
218
  - [Public contracts](public-contracts.md): exported prompt contribution contracts.
@@ -0,0 +1,87 @@
1
+ # Tool conformance
2
+
3
+ ## What it does
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.
6
+
7
+ Exported from `@arnilo/prism/testing/tool-conformance`:
8
+
9
+ - `assertToolDispatchConforms(registry, options)`
10
+ - `assertToolBlocked(probe, expectedReason)`
11
+ - `dispatchAndCollect(probe)`
12
+ - `ToolConformanceOptions`, `ToolDispatchProbeOptions`
13
+
14
+ ## When to use it
15
+
16
+ Use this helper when configuring a `ToolRegistry` with allow/deny filters, permission policies, and validators. It asserts the canonical blocked reasons and that blocked calls never execute:
17
+
18
+ - unknown tool → `tool_execution_blocked` with reason `unknown_tool`
19
+ - denied tool (filter) → `tool_denied`
20
+ - non-object arguments → `invalid_arguments`
21
+ - permission denial → `permission_denied`
22
+ - validator failure → `validation_failed`
23
+ - a valid call emits `tool_execution_started` and returns a result with no error
24
+
25
+ ## Inputs / request
26
+
27
+ ```ts
28
+ import { assertToolDispatchConforms } from "@arnilo/prism/testing/tool-conformance";
29
+ import { createToolRegistry } from "@arnilo/prism";
30
+
31
+ await assertToolDispatchConforms(createToolRegistry(), {
32
+ tool: { name: "echo", execute: (args, ctx) => ({ toolCallId: ctx.toolCallId, name: "echo", value: args }) },
33
+ validArgs: { msg: "hi" },
34
+ permission: myPermissionPolicy,
35
+ });
36
+ ```
37
+
38
+ `ToolConformanceOptions`:
39
+ - `tool: ToolDefinition` — registered as the success-path target
40
+ - `validArgs: JsonObject` — arguments for the success probe
41
+ - `permission?: PermissionPolicy` — applied to every probe (default allow-all)
42
+ - `validate?: ToolValidator`, `filter?: ToolFilterInput`, `secrets?: readonly (string | undefined)[]`
43
+
44
+ ## Outputs / response / events
45
+
46
+ `assertToolDispatchConforms` returns `Promise<void>` and throws on the first violation. `dispatchAndCollect` returns `{ result, events }` capturing the emitted `AgentEvent`s for custom assertions.
47
+
48
+ ## Request/response example
49
+
50
+ ```ts
51
+ import { assertToolBlocked } from "@arnilo/prism/testing/tool-conformance";
52
+
53
+ await assertToolBlocked(
54
+ { call: { type: "tool_call", id: "c", name: "missing", arguments: {} }, registry: createToolRegistry() },
55
+ "unknown_tool",
56
+ );
57
+ ```
58
+
59
+ ## Implementation example
60
+
61
+ ```ts
62
+ import { assertToolDispatchConforms } from "@arnilo/prism/testing/tool-conformance";
63
+ import { createToolRegistry } from "@arnilo/prism";
64
+
65
+ await assertToolDispatchConforms(createToolRegistry(), {
66
+ tool: { name: "echo", execute: (args, ctx) => ({ toolCallId: ctx.toolCallId, name: "echo", value: args }) },
67
+ validArgs: {},
68
+ });
69
+ ```
70
+
71
+ ## Extension and configuration notes
72
+
73
+ - The helper registers `options.tool` into the supplied registry; pass a fresh registry to avoid duplicate-name errors.
74
+ - Execution is observed via the `tool_execution_started`/`tool_execution_blocked` events the runtime emits — the helper does not mutate the caller's tool.
75
+ - Use `dispatchAndCollect` directly for custom probes (e.g. middleware ordering) beyond the standard matrix.
76
+
77
+ ## Security and performance notes
78
+
79
+ - No credentials, no network required.
80
+ - The helper uses an allow-all permission policy by default; supply `permission` to validate your fail-closed policy.
81
+ - Blocked calls are proven not to execute by the absence of `tool_execution_started`.
82
+
83
+ ## Related APIs
84
+
85
+ - [Tools](tools.md)
86
+ - [Settings, auth, trust, security](settings-auth-trust-security.md)
87
+ - [Provider conformance](provider-conformance.md)
package/docs/tools.md CHANGED
@@ -20,7 +20,7 @@ Do not use the harness as a sandbox, package loader, app-tool pack, permission p
20
20
  ## Inputs / request
21
21
 
22
22
  ```ts
23
- createToolRegistry(tools?: readonly ToolDefinition[]): ToolRegistry
23
+ createToolRegistry(tools?: readonly ToolDefinition[], options?: { duplicate?: "replace" | "error" }): ToolRegistry
24
24
  filterTools(tools: readonly ToolDefinition[], filter?: ToolFilter | readonly ToolFilter[]): readonly ToolDefinition[]
25
25
  dispatchToolCall(options: DispatchToolCallOptions): Promise<ToolResult>
26
26
  ```
@@ -29,7 +29,7 @@ dispatchToolCall(options: DispatchToolCallOptions): Promise<ToolResult>
29
29
 
30
30
  | Method | Input | Result |
31
31
  | --- | --- | --- |
32
- | `register(tool)` | `ToolDefinition` | Stores or replaces by `tool.name`. |
32
+ | `register(tool)` | `ToolDefinition` | Stores/replaces by `tool.name`; throws `Duplicate tool: <name>` when `duplicate: "error"`. |
33
33
  | `get(name)` | tool name | Returns the tool or `undefined`. |
34
34
  | `resolve(name)` | tool name | Returns the tool or throws `Unknown tool: <name>`. |
35
35
  | `list()` | none | Returns tools in insertion order. |
@@ -52,13 +52,16 @@ When multiple filters are provided, each non-empty allow list must include the t
52
52
  | `context` | `ToolExecutionContext` with session/run/tool call ids, signal, metadata, and optional progress callback. |
53
53
  | `filter` | Optional exact allow/deny filter or ordered filters. |
54
54
  | `middleware` | Optional `MiddlewareRegistry`; `tool_call` runs before validation/execution and `tool_result` runs after execution. |
55
- | `validate` | Optional host validator returning `void`, a message string, or `ErrorInfo`. |
55
+ | `validate` | Optional host validator returning `void`, a message string, or `ErrorInfo`. A non-`void` return blocks dispatch with reason `validation_failed` (redacted). Runs after the permission assertion and before `tool.execute()`. |
56
56
  | `emit` | Optional `AgentEvent` callback for lifecycle events. |
57
57
  | `secrets` | Known secret values to redact from thrown tool errors. |
58
+ | `redactor` | Optional `SecretRedactor` used to redact tool-call ledger records. |
59
+ | `ledger` | Optional `RunLedger` adapter; when set, `dispatchToolCall` appends `ToolCallRecord` rows. |
60
+ | `ownership` | Optional `OwnershipScope` copied into each `ToolCallRecord`. |
58
61
 
59
62
  ## Outputs / response / events
60
63
 
61
- Registry calls return plain `ToolDefinition` objects. `resolve()` fails closed for unknown names before any tool can execute. Filtering returns only tools already present in the input list; it never creates or enables new tools.
64
+ Registry calls return plain `ToolDefinition` objects. `resolve()` fails closed for unknown names before any tool can execute. Duplicate registrations replace deterministically by default for compatibility; `createToolRegistry([], { duplicate: "error" })` rejects silent shadowing with `Duplicate tool: <name>`. Filtering returns only tools already present in the input list; it never creates or enables new tools.
62
65
 
63
66
  `dispatchToolCall()` returns a `ToolResult`. Unknown tools, denied tools, invalid arguments, validator failures, and thrown tool errors return a result with `error` and do not throw by default.
64
67
 
@@ -72,6 +75,20 @@ Dispatch can emit these `AgentEvent` types:
72
75
  | `tool_execution_finished` | After successful execution and `tool_result` middleware. |
73
76
  | `tool_execution_error` | When `tool.execute()` throws. |
74
77
 
78
+ ### Tool-call ledger rows
79
+
80
+ When `options.ledger` is set, `dispatchToolCall()` also appends a `ToolCallRecord` for each lifecycle transition. The runtime passes each record through `redactRunLedgerRecord(record, options.redactor)` before handing it to the adapter. Rows are written for:
81
+
82
+ | Status | When | Extra fields |
83
+ | --- | --- | --- |
84
+ | `started` | After `tool_execution_started` | `startedAt`, `arguments` |
85
+ | `started` (progress snapshot) | On each `context.progress()` call | `progress`, `progressMetadata`, `progressAt` |
86
+ | `finished` | After `tool_execution_finished` | `finishedAt`, `result` |
87
+ | `error` | After `tool_execution_error` | `finishedAt`, `result` with `error` |
88
+ | `blocked` | On any blocked path | `finishedAt`, `reason`, `result` with `error` |
89
+
90
+ Blocked reasons are `unknown_tool`, `tool_denied`, `invalid_arguments`, `permission_denied`, and `validation_failed`. Progress snapshots reuse status `started` because the tool call is still in flight.
91
+
75
92
  ## Request/response example
76
93
 
77
94
  ```json
@@ -124,13 +141,52 @@ const activeTools = createToolRegistry([contributions.tools.resolve("echo")]);
124
141
 
125
142
  Middleware can transform `tool_call` and `tool_result` payloads, but dispatch re-checks active registry lookup, filters, and object arguments after `tool_call` middleware. Middleware cannot grant permission by changing a tool name.
126
143
 
127
- Configuration can carry allow/deny names, but Prism does not define a policy class or hidden global active tool set. Skills may reference `toolNames`, but `resolveActiveSkills()` only checks those names against the host-active tool list; it does not register, allow, or execute tools.
144
+ Configuration can carry allow/deny names, but Prism does not define a policy class or hidden global active tool set. Skills may reference `toolNames`, but `resolveActiveSkills()` only checks those names against the host-active tool list; it does not register, allow, permit, or execute tools. A missing `toolNames` dependency fails before the provider turn and writes no tool result.
145
+
146
+ ### Per-run tool scoping
147
+
148
+ `session.run()` intentionally has no `RunOptions.tools` or `RunOptions.toolFilter`. Scope tools by building the active `ToolRegistry` for the agent/session, by resolving declarative `AgentDefinition.tools`, or by using `PermissionPolicy` / `ToolValidator` to fail closed at dispatch time. Skills do not grant tool access; `toolNames` only validates that host-active tools exist.
149
+
150
+ ```ts
151
+ const activeTools = createToolRegistry([searchTool]);
152
+ const agent = createAgent({ model, provider, tools: activeTools, permission, validator });
153
+ ```
154
+
155
+ Need different tools for one request? Build a short-lived agent/session with a narrower registry, or block extra calls with `PermissionPolicy` / `RunOptions.validate`. No extra per-run tool API exists yet; add one only when host apps need it.
156
+
157
+ ### Runtime-supplied validators
158
+
159
+ `AgentConfig.validator?` and `RunOptions.validate?` expose the same `ToolValidator` seam that `DispatchToolCallOptions.validate` already uses. The runtime threads `validate: RunOptions.validate ?? AgentConfig.validator` into every `dispatchToolCall` it issues during the tool loop, so an app can supply argument validation without taking ownership of dispatch itself. `RunOptions.validate` overrides `AgentConfig.validator` on a per-run basis (RunOptions wins). When neither is set, dispatch runs unmodified.
160
+
161
+ The validator runs after the permission assertion and before `tool.execute()`. A `void` return lets the tool run. A non-`void` return (a string message or `ErrorInfo`) blocks the call: `dispatchToolCall` emits `tool_execution_blocked` with reason `validation_failed` and a redacted error, and the tool is not executed. This is the same redaction path as thrown tool errors, so a validator that echoes a secret is scrubbed through the active `SecretRedactor`. Composition of multiple validators is deferred (YAGNI); wrap or call both in a host-supplied function if needed.
162
+
163
+ ```ts
164
+ import { createAgent, createSecretRedactor, type ToolValidator } from "@arnilo/prism";
165
+
166
+ const validator: ToolValidator = (_tool, args) =>
167
+ typeof args.query === "string" && args.query.length <= 1000
168
+ ? undefined
169
+ : "query too long";
170
+
171
+ const agent = createAgent({
172
+ model,
173
+ provider,
174
+ tools,
175
+ // applied to every run of this agent
176
+ validator,
177
+ // redacts validator output (and tool errors) the same way as secrets
178
+ redactor: createSecretRedactor([process.env.APP_KEY!]),
179
+ });
180
+
181
+ // override per run only
182
+ await session.run(input, { validate: (_t, args) => args.dry ? "dry-run blocked" : undefined });
183
+ ```
128
184
 
129
185
  ## Security and performance notes
130
186
 
131
- - Tool lookup uses a `Map` for O(1) name lookup.
187
+ - Tool lookup uses a `Map` for O(1) name lookup. Strict duplicate mode adds one O(1) `Map.has()` check during registration only.
132
188
  - Filtering is exact-name matching over the provided tools and rules.
133
- - Unknown, denied, malformed, and validator-blocked calls fail closed.
189
+ - Unknown, denied, malformed, duplicate-in-strict-mode, and validator-blocked calls fail closed.
134
190
  - Tool arguments must be JSON object-shaped before validation or execution.
135
191
  - `parameters` is pass-through metadata; hosts own schema interpretation and validation.
136
192
  - Prism does not sandbox host tools and does not include built-in app tools.
@@ -148,4 +204,4 @@ Configuration can carry allow/deny names, but Prism does not define a policy cla
148
204
  - [Credentials and redaction](credentials-and-redaction.md): redaction helpers used for tool execution errors.
149
205
  - [Observational memory compaction package](compaction-observational-memory.md): optional exact-id recall tool factory.
150
206
 
151
- `DispatchToolCallOptions.permission` can provide a `PermissionPolicy`; denial emits `tool_execution_blocked` before validation or `execute()`. Middleware cannot bypass this guard. Prism does not sandbox tools. See [Security/auth/trust](settings-auth-trust-security.md).
207
+ `DispatchToolCallOptions.permission` can provide a `PermissionPolicy`; denial emits `tool_execution_blocked` before validation or `execute()`. Middleware cannot bypass this guard. `AgentConfig.validator`/`RunOptions.validate` run after this guard; their output is redacted through the active `SecretRedactor`. Prism does not sandbox tools. See [Security/auth/trust](settings-auth-trust-security.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,6 +18,22 @@
18
18
  "types": "./dist/testing/provider-conformance.d.ts",
19
19
  "default": "./dist/testing/provider-conformance.js"
20
20
  },
21
+ "./testing/session-store-conformance": {
22
+ "types": "./dist/testing/session-store-conformance.d.ts",
23
+ "default": "./dist/testing/session-store-conformance.js"
24
+ },
25
+ "./testing/compaction-conformance": {
26
+ "types": "./dist/testing/compaction-conformance.d.ts",
27
+ "default": "./dist/testing/compaction-conformance.js"
28
+ },
29
+ "./testing/tool-conformance": {
30
+ "types": "./dist/testing/tool-conformance.d.ts",
31
+ "default": "./dist/testing/tool-conformance.js"
32
+ },
33
+ "./testing/extension-conformance": {
34
+ "types": "./dist/testing/extension-conformance.d.ts",
35
+ "default": "./dist/testing/extension-conformance.js"
36
+ },
21
37
  "./node/config": {
22
38
  "types": "./dist/node/config.d.ts",
23
39
  "default": "./dist/node/config.js"
@@ -33,6 +49,22 @@
33
49
  "./node/session-store-jsonl": {
34
50
  "types": "./dist/node/session-store-jsonl.d.ts",
35
51
  "default": "./dist/node/session-store-jsonl.js"
52
+ },
53
+ "./node/contribution-discovery": {
54
+ "types": "./dist/node/contribution-discovery.d.ts",
55
+ "default": "./dist/node/contribution-discovery.js"
56
+ },
57
+ "./node/instruction-injectors": {
58
+ "types": "./dist/node/instruction-injectors.d.ts",
59
+ "default": "./dist/node/instruction-injectors.js"
60
+ },
61
+ "./node/system-prompts": {
62
+ "types": "./dist/node/system-project-prompts.d.ts",
63
+ "default": "./dist/node/system-project-prompts.js"
64
+ },
65
+ "./node/agent-definitions": {
66
+ "types": "./dist/node/agent-definitions.d.ts",
67
+ "default": "./dist/node/agent-definitions.js"
36
68
  }
37
69
  },
38
70
  "bin": {
@@ -58,7 +90,8 @@
58
90
  "typecheck": "npm run build:core && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
59
91
  "test": "npm run build && node --test dist/__tests__/*.test.js && npm run test --workspaces --if-present",
60
92
  "pack:dry-run": "npm pack --dry-run && npm run pack:dry-run --workspaces --if-present",
61
- "release:dry-run": "npm test && npm run pack:dry-run"
93
+ "release:dry-run": "npm run sdk:ready",
94
+ "sdk:ready": "npm run typecheck && npm test && npm run pack:dry-run"
62
95
  },
63
96
  "devDependencies": {
64
97
  "typescript": "^5.7.0",