@arnilo/prism 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.5.4] - 2026-09-08 (plan 067)
2
+
3
+ ### Changed
4
+ - **Run limits: process-safety HARD split from host policy.** `DEFAULT_RUN_LIMITS` stays the unconfigured fence (turns 16, attempts 24, tool rounds 8, calls 32, wall 120s, bytes 8 MiB, tokens 40k/10k/50k), but `HARD_RUN_LIMITS` shrinks to the two process-integrity axes (`maxRequestBytes`/`maxResponseBytes`, 64 MiB) so a bug cannot OOM the host through a giant provider frame — and hosts can legally raise or disable everything else. Policy axes accept `number | null`: omit for the default, set a positive safe integer, or set `null` to disable the axis (disabled wall still honors `RunOptions.signal`). Resolution stays narrowing-only with `null` as +Infinity (agent 16 + run `null` → 16); an omitted `maxProviderAttempts` lifts to at least a raised/disabled `maxTurns` so attempts cannot undercut turns. Byte axes reject `null` and >64 MiB. The former `$10k` `maxCost` ceiling is removed (any finite non-negative amount). Documented ceiling: vendors that omit usage charge zero to token counters; a configured `maxCost` remains fail-closed. Durable checkpoints omit `deadlineAt` on no-wall runs; older checkpoints with a deadline still resume. New `ResolvedRunLimits` type; `resolveRunLimits` returns it.
5
+
6
+ ### Removed
7
+ - **`HARD_MAX_RUN_COST` export** (was a `$10k` validation ceiling; `maxCost` now accepts any finite non-negative amount plus one currency).
8
+
1
9
  ## [0.5.3] - 2026-09-08
2
10
 
3
11
  ### Fixed
package/README.md CHANGED
@@ -162,16 +162,16 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
162
162
 
163
163
  | package | version | notes |
164
164
  | --- | --- | --- |
165
- | `@arnilo/prism` | 0.5.3 | core — runtime, CLI/RPC, templates, docs |
166
- | `@arnilo/prism-coding-tools` | 0.5.3 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
167
- | `@arnilo/prism-core` | 0.5.3 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
168
- | `@arnilo/prism-providers` | 0.5.3 | family — all provider adapters as `/<adapter>` subpaths |
169
- | `@arnilo/prism-acp-agent` | 0.5.3 | capability — ACP adapter |
170
- | `@arnilo/prism-ag-ui` | 0.5.3 | capability — AG-UI/A2A/A2UI adapter |
171
- | `@arnilo/prism-mcp` | 0.5.3 | capability — MCP client/server/OAuth interop |
172
- | `@arnilo/prism-memory` | 0.5.3 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
173
- | `@arnilo/prism-office` | 0.5.3 | capability — /documents, /sheets, /diagrams subpaths |
174
- | `@arnilo/prism-web-tools` | 0.5.3 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
165
+ | `@arnilo/prism` | 0.5.4 | core — runtime, CLI/RPC, templates, docs |
166
+ | `@arnilo/prism-coding-tools` | 0.5.4 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
167
+ | `@arnilo/prism-core` | 0.5.4 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
168
+ | `@arnilo/prism-providers` | 0.5.4 | family — all provider adapters as `/<adapter>` subpaths |
169
+ | `@arnilo/prism-acp-agent` | 0.5.4 | capability — ACP adapter |
170
+ | `@arnilo/prism-ag-ui` | 0.5.4 | capability — AG-UI/A2A/A2UI adapter |
171
+ | `@arnilo/prism-mcp` | 0.5.4 | capability — MCP client/server/OAuth interop |
172
+ | `@arnilo/prism-memory` | 0.5.4 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
173
+ | `@arnilo/prism-office` | 0.5.4 | capability — /documents, /sheets, /diagrams subpaths |
174
+ | `@arnilo/prism-web-tools` | 0.5.4 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
175
175
  <!-- generated:package-truth:inventory end -->
176
176
 
177
177
  ## Scripts
@@ -28,7 +28,8 @@ export interface StoredAgentRunState extends AgentRunState {
28
28
  readonly stickyDecisions?: readonly StickyDecision[];
29
29
  readonly interruptBeforeTool?: boolean;
30
30
  readonly counters: RunLimitCounters;
31
- readonly deadlineAt: string;
31
+ /** Wall deadline; absent when the run has no wall limit. Old snapshots with a deadline still parse. */
32
+ readonly deadlineAt?: string;
32
33
  /** Loop-local durable state captured by the strategy's snapshot hook at suspension. */
33
34
  readonly loopState?: {
34
35
  readonly name: string;
@@ -84,7 +85,7 @@ export declare function initialAgentRunState(input: {
84
85
  readonly leafId?: string;
85
86
  readonly model: ModelConfig;
86
87
  readonly counters: RunLimitCounters;
87
- readonly deadlineAt: string;
88
+ readonly deadlineAt?: string;
88
89
  readonly status: "suspended" | "running";
89
90
  readonly interruption?: AgentRunInterruption;
90
91
  readonly messages?: readonly Message[];
@@ -165,8 +165,7 @@ export function parseAgentRunState(value, version) {
165
165
  !state.sessionId ||
166
166
  !state.model ||
167
167
  !state.status ||
168
- !state.counters ||
169
- !state.deadlineAt) {
168
+ !state.counters) {
170
169
  throw new AgentRunStateError("Malformed agent run state");
171
170
  }
172
171
  if (state.pendingCalls !== undefined &&
@@ -106,7 +106,8 @@ async function assembleRoundContext(params) {
106
106
  for (const message of inputMessages)
107
107
  await session.appendMessage(message, runId);
108
108
  await session.autoCompact(runId, options, controller.signal, inputMessages);
109
- const maxToolRounds = resolveRunLimits(session.agent.config.limits, options.limits).maxToolRounds;
109
+ // Disabled cap (`null`) maps to +Infinity so loop comparisons never trip (`n >= null` would be true).
110
+ const maxToolRounds = resolveRunLimits(session.agent.config.limits, options.limits).maxToolRounds ?? Number.POSITIVE_INFINITY;
110
111
  const systemInstructions = composeSystemPrompt(mergeSystemPromptConfig(session.agent.config.systemPrompt, options.systemPrompt), {
111
112
  base: session.agent.config.instructions,
112
113
  });
@@ -317,7 +318,8 @@ export async function executeRun(session, input, options, runId, resumed) {
317
318
  deadlineAt: resumed?.state?.deadlineAt,
318
319
  });
319
320
  session.activeLimits = limits;
320
- session.activeLimitOutputBuffer = [session.agent.config.limits, requestedLimits].some((value) => value?.maxOutputTokens !== undefined || value?.maxTotalTokens !== undefined || value?.maxCost !== undefined);
321
+ const hasFiniteTokenCap = (value) => typeof value === "number" && Number.isFinite(value);
322
+ session.activeLimitOutputBuffer = [session.agent.config.limits, requestedLimits].some((value) => hasFiniteTokenCap(value?.maxOutputTokens) || hasFiniteTokenCap(value?.maxTotalTokens) || value?.maxCost !== undefined);
321
323
  try {
322
324
  const ctx = await assembleRoundContext({
323
325
  session,
@@ -2,17 +2,39 @@
2
2
  * Moved verbatim from contracts-core.ts; public surface unchanged behind the barrel. */
3
3
  import type { ProviderTurnResult, ToolResult } from "../contracts-protocol.js";
4
4
  import type { Message, ToolCallContent } from "./content.js";
5
+ /**
6
+ * Host-authored run limits. Policy axes accept `null` to explicitly disable the cap
7
+ * (process safety still caps request/response bytes, which reject `null`). Omitted keys
8
+ * resolve to `DEFAULT_RUN_LIMITS`.
9
+ */
5
10
  export interface RunLimits {
6
- readonly maxTurns?: number;
7
- readonly maxProviderAttempts?: number;
8
- readonly maxToolRounds?: number;
9
- readonly maxToolCalls?: number;
10
- readonly maxWallTimeMs?: number;
11
+ readonly maxTurns?: number | null;
12
+ readonly maxProviderAttempts?: number | null;
13
+ readonly maxToolRounds?: number | null;
14
+ readonly maxToolCalls?: number | null;
15
+ readonly maxWallTimeMs?: number | null;
11
16
  readonly maxRequestBytes?: number;
12
17
  readonly maxResponseBytes?: number;
13
- readonly maxInputTokens?: number;
14
- readonly maxOutputTokens?: number;
15
- readonly maxTotalTokens?: number;
18
+ readonly maxInputTokens?: number | null;
19
+ readonly maxOutputTokens?: number | null;
20
+ readonly maxTotalTokens?: number | null;
21
+ readonly maxCost?: {
22
+ readonly amount: number;
23
+ readonly currency: string;
24
+ };
25
+ }
26
+ /** Fully resolved limits after `resolveRunLimits`: every policy axis is a finite cap or `null` (disabled). */
27
+ export interface ResolvedRunLimits {
28
+ readonly maxTurns: number | null;
29
+ readonly maxProviderAttempts: number | null;
30
+ readonly maxToolRounds: number | null;
31
+ readonly maxToolCalls: number | null;
32
+ readonly maxWallTimeMs: number | null;
33
+ readonly maxRequestBytes: number;
34
+ readonly maxResponseBytes: number;
35
+ readonly maxInputTokens: number | null;
36
+ readonly maxOutputTokens: number | null;
37
+ readonly maxTotalTokens: number | null;
16
38
  readonly maxCost?: {
17
39
  readonly amount: number;
18
40
  readonly currency: string;
package/dist/index.d.ts CHANGED
@@ -88,7 +88,7 @@ export { createDefaultRetryPolicy, isTransientErrorInfo, waitForRetry } from "./
88
88
  export type { BatchedRunLedgerOptions } from "./run-ledger.js";
89
89
  export { createBatchedRunLedger, DEFAULT_LEDGER_BATCH_BYTES, DEFAULT_LEDGER_BATCH_DELAY_MS, DEFAULT_LEDGER_BATCH_ENTRIES, HARD_LEDGER_BATCH_BYTES, HARD_LEDGER_BATCH_DELAY_MS, HARD_LEDGER_BATCH_ENTRIES, isFlushableRunLedger, } from "./run-ledger.js";
90
90
  export type { RunLimitTrackerOptions } from "./run-limits.js";
91
- export { createRunLimitTracker, DEFAULT_RUN_LIMITS, HARD_MAX_RUN_COST, HARD_RUN_LIMITS, RunLimitError, RunLimitTracker, resolveRunLimits, } from "./run-limits.js";
91
+ export { createRunLimitTracker, DEFAULT_RUN_LIMITS, HARD_RUN_LIMITS, RunLimitError, RunLimitTracker, resolveRunLimits, } from "./run-limits.js";
92
92
  export { createSecureAgent } from "./secure-agent.js";
93
93
  export type { PermissionDecision, PermissionPolicy, PermissionRequest, TrustDecision, TrustPolicy, TrustRequest } from "./security.js";
94
94
  export { assertPermission, assertTrusted, checkPermission, createStaticPermissionPolicy, createStaticTrustPolicy, denialToErrorInfo, isTrusted, PermissionDeniedError, TrustDeniedError, } from "./security.js";
@@ -119,5 +119,5 @@ export { trimTrailingSlashes } from "./trim-trailing-slashes.js";
119
119
  export type { ResolvedUseCaseModel, ResolveUseCaseModelInput, UseCaseModelBinding, } from "./use-case-model.js";
120
120
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
121
121
  export declare const name = "prism";
122
- export declare const version = "0.5.3";
122
+ export declare const version = "0.5.4";
123
123
  export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ export { createSecretRedactor, errorToErrorInfo, redactAgentEvent, redactMessage
47
47
  export { loadBinaryResource, loadJsonResource, loadManifestResource, loadTextResource } from "./resources.js";
48
48
  export { createDefaultRetryPolicy, isTransientErrorInfo, waitForRetry } from "./retry.js";
49
49
  export { createBatchedRunLedger, DEFAULT_LEDGER_BATCH_BYTES, DEFAULT_LEDGER_BATCH_DELAY_MS, DEFAULT_LEDGER_BATCH_ENTRIES, HARD_LEDGER_BATCH_BYTES, HARD_LEDGER_BATCH_DELAY_MS, HARD_LEDGER_BATCH_ENTRIES, isFlushableRunLedger, } from "./run-ledger.js";
50
- export { createRunLimitTracker, DEFAULT_RUN_LIMITS, HARD_MAX_RUN_COST, HARD_RUN_LIMITS, RunLimitError, RunLimitTracker, resolveRunLimits, } from "./run-limits.js";
50
+ export { createRunLimitTracker, DEFAULT_RUN_LIMITS, HARD_RUN_LIMITS, RunLimitError, RunLimitTracker, resolveRunLimits, } from "./run-limits.js";
51
51
  export { createSecureAgent } from "./secure-agent.js";
52
52
  export { assertPermission, assertTrusted, checkPermission, createStaticPermissionPolicy, createStaticTrustPolicy, denialToErrorInfo, isTrusted, PermissionDeniedError, TrustDeniedError, } from "./security.js";
53
53
  export { createMemorySessionStore, createSessionEntry, getSessionBranchEntries, listSessionBranches, rebuildSessionContext, } from "./session-stores.js";
@@ -66,6 +66,6 @@ export { createToolParameterValidator, createToolRegistry, dispatchToolCall, fil
66
66
  export { trimTrailingSlashes } from "./trim-trailing-slashes.js";
67
67
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
68
68
  export const name = "prism";
69
- export const version = "0.5.3";
69
+ export const version = "0.5.4";
70
70
  export const description = "Agent harness for AI providers, agents, sessions, and tools.";
71
71
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,25 @@
1
- import type { RunLimitBreach, RunLimitCounters, RunLimitName, RunLimits, Usage } from "./contracts.js";
2
- export declare const DEFAULT_RUN_LIMITS: Required<Omit<RunLimits, "maxCost">>;
3
- export declare const HARD_MAX_RUN_COST = 10000;
4
- export declare const HARD_RUN_LIMITS: Required<Omit<RunLimits, "maxCost">>;
1
+ import type { ResolvedRunLimits, RunLimitBreach, RunLimitCounters, RunLimitName, RunLimits, Usage } from "./contracts.js";
2
+ export declare const DEFAULT_RUN_LIMITS: Readonly<{
3
+ maxTurns: 16;
4
+ maxProviderAttempts: 24;
5
+ maxToolRounds: 8;
6
+ maxToolCalls: 32;
7
+ maxWallTimeMs: 120000;
8
+ maxRequestBytes: number;
9
+ maxResponseBytes: number;
10
+ maxInputTokens: 40000;
11
+ maxOutputTokens: 10000;
12
+ maxTotalTokens: 50000;
13
+ }>;
14
+ /**
15
+ * Process-safety ceilings that exist so a bug cannot OOM the host via JSON.parse of giant
16
+ * provider frames. Product axes (turns, wall time, tokens, …) have no hard cap: hosts set
17
+ * them per workload, and `null` explicitly disables an axis.
18
+ */
19
+ export declare const HARD_RUN_LIMITS: Readonly<{
20
+ maxRequestBytes: number;
21
+ maxResponseBytes: number;
22
+ }>;
5
23
  export declare class RunLimitError extends Error {
6
24
  readonly breach: RunLimitBreach;
7
25
  readonly code = "ERR_PRISM_RUN_LIMIT";
@@ -14,16 +32,17 @@ export interface RunLimitTrackerOptions {
14
32
  readonly deadlineAt?: string;
15
33
  }
16
34
  /** Validate one host-authored layer. Defaults are applied only after inheritance is resolved. */
17
- export declare function resolveRunLimits(agent?: RunLimits, run?: RunLimits): Readonly<Required<Omit<RunLimits, "maxCost">> & Pick<RunLimits, "maxCost">>;
35
+ export declare function resolveRunLimits(agent?: RunLimits, run?: RunLimits): Readonly<ResolvedRunLimits>;
18
36
  export declare class RunLimitTracker {
19
37
  private readonly options;
20
- readonly limits: Readonly<Required<Omit<RunLimits, "maxCost">> & Pick<RunLimits, "maxCost">>;
38
+ readonly limits: Readonly<ResolvedRunLimits>;
21
39
  private readonly startedAt;
22
- readonly deadlineAt: string;
40
+ /** Wall deadline ISO string; absent when the run has no wall limit. */
41
+ readonly deadlineAt: string | undefined;
23
42
  private readonly counters;
24
43
  private timer?;
25
44
  private exceeded?;
26
- constructor(limits: Readonly<Required<Omit<RunLimits, "maxCost">> & Pick<RunLimits, "maxCost">>, options?: RunLimitTrackerOptions);
45
+ constructor(limits: Readonly<ResolvedRunLimits>, options?: RunLimitTrackerOptions);
27
46
  get breach(): RunLimitBreach | undefined;
28
47
  snapshot(): RunLimitCounters;
29
48
  dispose(): void;
@@ -10,20 +10,17 @@ export const DEFAULT_RUN_LIMITS = Object.freeze({
10
10
  maxOutputTokens: 10_000,
11
11
  maxTotalTokens: 50_000,
12
12
  });
13
- export const HARD_MAX_RUN_COST = 10_000;
13
+ /**
14
+ * Process-safety ceilings that exist so a bug cannot OOM the host via JSON.parse of giant
15
+ * provider frames. Product axes (turns, wall time, tokens, …) have no hard cap: hosts set
16
+ * them per workload, and `null` explicitly disables an axis.
17
+ */
14
18
  export const HARD_RUN_LIMITS = Object.freeze({
15
- maxTurns: 64,
16
- maxProviderAttempts: 256,
17
- maxToolRounds: 64,
18
- maxToolCalls: 256,
19
- maxWallTimeMs: 30 * 60_000,
20
19
  maxRequestBytes: 64 * 1024 * 1024,
21
20
  maxResponseBytes: 64 * 1024 * 1024,
22
- maxInputTokens: 1_000_000,
23
- maxOutputTokens: 250_000,
24
- maxTotalTokens: 1_000_000,
25
21
  });
26
22
  const LIMIT_NAMES = Object.keys(DEFAULT_RUN_LIMITS);
23
+ const POLICY_NAMES = LIMIT_NAMES.filter((name) => name !== "maxRequestBytes" && name !== "maxResponseBytes");
27
24
  const COUNTER_FOR = {
28
25
  maxTurns: "turns",
29
26
  maxProviderAttempts: "providerAttempts",
@@ -46,16 +43,44 @@ export class RunLimitError extends Error {
46
43
  this.name = "RunLimitError";
47
44
  }
48
45
  }
46
+ /** `null` means "no cap" and behaves as +Infinity when narrowing against a finite layer. */
47
+ function minCap(a, b) {
48
+ if (a === undefined)
49
+ return b;
50
+ if (b === undefined)
51
+ return a;
52
+ if (a === null)
53
+ return b;
54
+ if (b === null)
55
+ return a;
56
+ return Math.min(a, b);
57
+ }
49
58
  /** Validate one host-authored layer. Defaults are applied only after inheritance is resolved. */
50
59
  export function resolveRunLimits(agent, run) {
51
60
  const base = agent ? validateLimits(agent) : undefined;
52
61
  const override = run ? validateLimits(run) : undefined;
53
62
  const resolved = { ...DEFAULT_RUN_LIMITS };
54
- for (const name of LIMIT_NAMES) {
63
+ for (const name of POLICY_NAMES) {
64
+ const narrowed = minCap(base?.[name], override?.[name]);
65
+ resolved[name] = narrowed !== undefined ? narrowed : DEFAULT_RUN_LIMITS[name];
66
+ }
67
+ for (const name of ["maxRequestBytes", "maxResponseBytes"]) {
55
68
  if (base?.[name] !== undefined)
56
- resolved[name] = base[name];
69
+ resolved[name] = Math.min(resolved[name], base[name]);
57
70
  if (override?.[name] !== undefined)
58
- resolved[name] = base ? Math.min(resolved[name], override[name]) : override[name];
71
+ resolved[name] = Math.min(resolved[name], override[name]);
72
+ }
73
+ // A raised/disabled maxTurns must not be silently undercut by the attempts default:
74
+ // generate-then-tool-loop needs at least one attempt per turn (plus retries).
75
+ if (base?.maxProviderAttempts === undefined && override?.maxProviderAttempts === undefined) {
76
+ const turns = resolved.maxTurns;
77
+ resolved.maxProviderAttempts = turns === null ? null : Math.max(DEFAULT_RUN_LIMITS.maxProviderAttempts, turns);
78
+ }
79
+ else {
80
+ const attempts = resolved.maxProviderAttempts;
81
+ const turns = resolved.maxTurns;
82
+ if (attempts !== null && turns !== null && attempts < turns)
83
+ resolved.maxProviderAttempts = turns;
59
84
  }
60
85
  const maxCost = override?.maxCost ?? base?.maxCost;
61
86
  return Object.freeze({
@@ -80,14 +105,21 @@ function validateLimits(input) {
80
105
  const value = input[name];
81
106
  if (value === undefined)
82
107
  continue;
83
- if (!Number.isSafeInteger(value) || value < 1 || value > HARD_RUN_LIMITS[name]) {
84
- throw new TypeError(`${name} must be a positive safe integer at most ${HARD_RUN_LIMITS[name]}`);
108
+ if (name === "maxRequestBytes" || name === "maxResponseBytes") {
109
+ // Process-safety axes: a giant frame cannot be host-approved away, so `null` is rejected.
110
+ if (value === null || !Number.isSafeInteger(value) || value < 1 || value > HARD_RUN_LIMITS[name])
111
+ throw new TypeError(`${name} must be a positive safe integer at most ${HARD_RUN_LIMITS[name]}`);
112
+ continue;
85
113
  }
114
+ if (value === null)
115
+ continue;
116
+ if (!Number.isSafeInteger(value) || value < 1)
117
+ throw new TypeError(`${name} must be a positive safe integer or null to disable`);
86
118
  }
87
119
  if (input.maxCost) {
88
120
  const { amount, currency } = input.maxCost;
89
- if (!Number.isFinite(amount) || amount < 0 || amount > HARD_MAX_RUN_COST || !currency.trim())
90
- throw new TypeError(`maxCost requires a finite amount from 0 through ${HARD_MAX_RUN_COST} and currency`);
121
+ if (!Number.isFinite(amount) || amount < 0 || !currency.trim())
122
+ throw new TypeError("maxCost requires a finite non-negative amount and currency");
91
123
  }
92
124
  return input;
93
125
  }
@@ -95,6 +127,7 @@ export class RunLimitTracker {
95
127
  options;
96
128
  limits;
97
129
  startedAt = performance.now();
130
+ /** Wall deadline ISO string; absent when the run has no wall limit. */
98
131
  deadlineAt;
99
132
  counters;
100
133
  timer;
@@ -121,21 +154,46 @@ export class RunLimitTracker {
121
154
  throw new TypeError("Run limit snapshot must contain finite non-negative counters");
122
155
  }
123
156
  }
124
- const deadline = options.deadlineAt ? Date.parse(options.deadlineAt) : Date.now() + limits.maxWallTimeMs;
125
- if (!Number.isFinite(deadline))
126
- throw new TypeError("Run limit deadlineAt is invalid");
127
- this.deadlineAt = new Date(deadline).toISOString();
128
- const remaining = Math.max(0, deadline - Date.now());
129
- this.timer = setTimeout(() => this.exceed("maxWallTimeMs", limits.maxWallTimeMs), remaining);
130
- this.timer.unref?.();
131
- if (remaining === 0)
132
- this.exceed("maxWallTimeMs", limits.maxWallTimeMs);
157
+ // A restored durable deadline wins even when the wall limit is now disabled (never drop an existing wall).
158
+ const deadline = options.deadlineAt
159
+ ? Date.parse(options.deadlineAt)
160
+ : limits.maxWallTimeMs === null
161
+ ? undefined
162
+ : Date.now() + limits.maxWallTimeMs;
163
+ if (deadline === undefined) {
164
+ this.deadlineAt = undefined;
165
+ }
166
+ else {
167
+ if (!Number.isFinite(deadline))
168
+ throw new TypeError("Run limit deadlineAt is invalid");
169
+ this.deadlineAt = new Date(deadline).toISOString();
170
+ const remaining = Math.max(0, deadline - Date.now());
171
+ // Node clamps setTimeout delays above 2^31-1 (~24.8 days) to 1ms, which would breach early;
172
+ // arm capped and re-check the real clock before exceeding.
173
+ const arm = (delay) => {
174
+ this.timer = setTimeout(() => {
175
+ const left = deadline - Date.now();
176
+ if (left > 0)
177
+ arm(Math.min(left, 2_147_483_647));
178
+ else
179
+ this.exceed("maxWallTimeMs", limits.maxWallTimeMs ?? 0);
180
+ }, delay);
181
+ this.timer.unref?.();
182
+ };
183
+ arm(Math.min(remaining, 2_147_483_647));
184
+ if (remaining === 0)
185
+ this.exceed("maxWallTimeMs", limits.maxWallTimeMs ?? 0);
186
+ }
133
187
  }
134
188
  get breach() {
135
189
  return this.exceeded;
136
190
  }
137
191
  snapshot() {
138
- return { ...this.counters, wallTimeMs: Math.min(this.limits.maxWallTimeMs, Math.ceil(performance.now() - this.startedAt)) };
192
+ const elapsed = Math.ceil(performance.now() - this.startedAt);
193
+ return {
194
+ ...this.counters,
195
+ wallTimeMs: this.limits.maxWallTimeMs === null ? elapsed : Math.min(this.limits.maxWallTimeMs, elapsed),
196
+ };
139
197
  }
140
198
  dispose() {
141
199
  if (this.timer)
@@ -150,7 +208,8 @@ export class RunLimitTracker {
150
208
  if (!Number.isSafeInteger(observed))
151
209
  this.exceed(limit, Number.MAX_SAFE_INTEGER + 1);
152
210
  this.counters[counter] = observed;
153
- if (observed > this.limits[limit])
211
+ const cap = this.limits[limit];
212
+ if (cap !== null && observed > cap)
154
213
  this.exceed(limit, observed);
155
214
  }
156
215
  recordUsage(usage) {
@@ -183,7 +242,7 @@ export class RunLimitTracker {
183
242
  }
184
243
  exceed(limit, observed) {
185
244
  if (!this.exceeded) {
186
- const maximum = limit === "maxCost" ? (this.limits.maxCost?.amount ?? 0) : this.limits[limit];
245
+ const maximum = limit === "maxCost" ? (this.limits.maxCost?.amount ?? 0) : (this.limits[limit] ?? 0);
187
246
  this.exceeded = {
188
247
  limit,
189
248
  maximum,
@@ -1,6 +1,6 @@
1
1
  # 0.1.0 / 1.0 Readiness Gates
2
2
 
3
- Status: **0.5.3** is the current release line (10 active packages, family subpaths, `^0.5.3` peers); **0.3.3** was the terminal 0.3.x cut; **0.1.7** was the terminal 0.1.x baseline; **1.0** readiness remains operator-gated, not automatic.
3
+ Status: **0.5.4** is the current release line (10 active packages, family subpaths, `^0.5.4` peers); **0.3.3** was the terminal 0.3.x cut; **0.1.7** was the terminal 0.1.x baseline; **1.0** readiness remains operator-gated, not automatic.
4
4
 
5
5
  This page distills runnable readiness gates into one command-per-gate table.
6
6
  The **Last evidence** column records the 0.1.0-tree snapshot (plan 012 Tasks
@@ -20,7 +20,7 @@ Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0
20
20
  keep their per-phase evidence in the pages above; this page records the 0.2.6
21
21
  snapshot (plan 026) with the 0.1.x tables below as the historical record.
22
22
 
23
- ## Current line (0.5.3)
23
+ ## Current line (0.5.4)
24
24
 
25
25
  | Item | Status |
26
26
  |---|---|
@@ -47,7 +47,7 @@ string | Message | readonly Message[]
47
47
 
48
48
  `AgentSessionConfig.store` overrides `AgentConfig.store`; otherwise the session gets a private memory store. `AgentSessionConfig.leafId` selects the branch leaf to resume from.
49
49
 
50
- `AgentConfig.limits` sets run ceilings; `RunOptions.limits` may only narrow configured agent values. Limits cover turns, provider attempts, tool rounds/calls, wall time, request/response bytes, tokens, and optional single-currency cost. A breach emits one `run_limit_exceeded` event and throws `AgentRunError` with `result.limit`; see [Runs and usage ledger](runs-and-usage.md#run-limits).
50
+ `AgentConfig.limits` sets run ceilings; `RunOptions.limits` may only narrow configured agent values (`null` counts as no cap, so a configured finite ceiling still wins). Limits cover turns, provider attempts, tool rounds/calls, wall time, request/response bytes, tokens, and optional single-currency cost. Policy axes accept `null` (0.5.4) to disable the axis; request/response bytes reject `null` and stay process-hard at 64 MiB. A breach emits one `run_limit_exceeded` event and throws `AgentRunError` with `result.limit`; see [Runs and usage ledger](runs-and-usage.md#run-limits).
51
51
 
52
52
  `RunOptions.model` can override the request model for a run. Model overrides append a `model_change` entry. `AgentConfig.inputLayout` selects the default input assembly layout (`"cache_aware"` by default, or opt-in `"legacy"`); `RunOptions.inputLayout` wins for one run. `AgentConfig.thinkingLevel` / `RunOptions.thinkingLevel` (run wins) is the session thinking intent — Prism snaps it onto the request after host `providerOptions`. `AgentConfig.providerOptions`/`RunOptions.providerOptions` supply generic provider request options (session/cache/header/compat/extra hints only — provider-level timeout/retry hints were removed in 0.1.5). Kernel construction always stamps `options.sessionId`/`cacheKey` from `session.id` when missing; `createSessionCachePolicy` is an overlay, not required. Use `RunOptions.signal`/host abort controllers for timeouts and `AgentConfig.retry`/`RunOptions.retry` for retry. `AgentConfig.providerRequestPolicies`/`RunOptions.providerRequestPolicies` run before `AIProvider.generate()` and before `provider_request` middleware. `AgentConfig.systemPrompt` and `RunOptions.systemPrompt` add explicit layered system prompt contributions; `RunOptions.systemPrompt: false` disables configured prompt layers for that run while keeping `AgentConfig.instructions` as the base path. `RunOptions.compaction` can enable auto-compaction for that run or use `false` to disable configured auto-compaction. `RunOptions.retry` can enable provider-turn retry for that run or use `false` to disable configured retry. `RunOptions.metadata` is merged with agent/session metadata for assembly, provider requests, and tool contexts. Run tool-round limits via `RunOptions.limits.maxToolRounds`. `RunOptions.signal` is bridged into the per-run abort signal passed to assembly, providers, tools, auto-compaction, and retry backoff.
53
53
 
package/docs/index.md CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  Prism is a TypeScript/Node.js agent harness. Host apps and extension packages own providers, tools, resources, credentials, storage, UI, and business behavior. Prism supplies contracts, registries, streaming events, and replaceable runtime primitives.
4
4
 
5
- ## Current line (0.5.3)
5
+ ## Current line (0.5.4)
6
6
 
7
7
  - **Tool result content on the wire**: content-only `ToolResult`s fold into `tool_result.result`; adapters join sibling text so the model sees tool output instead of JSON `"null"`.
8
8
  - **Stream token coalesce**: adjacent `text`/`thinking` deltas merge on persist; replay serializers join with `""` so multi-turn tool loops do not grow interstitial newlines.
9
9
  - **Provider request construction**: Prism stamps `sessionId`/`cacheKey` on every owned generate site, default cache breakpoints on `cache_control` / explicit-breakpoint models, and `thinkingLevel` on `AgentConfig` / `RunOptions`. Host policies are overlays. OpenCode Go missing session fails closed with `ProviderRequirementError` before fetch.
10
- - **10 publishable packages**: lockstep `0.5.3` (plans 055–066); family packages use explicit subpaths.
10
+ - **10 publishable packages**: lockstep `0.5.4` (plans 055–067); family packages use explicit subpaths.
11
11
  - **Linux desktop control**: optional `@arnilo/prism-coding-tools/computer-use-linux` wraps a host-owned `computer-use-linux` MCP binary; DeviceAdapter admission is deny-by-default and the package is omitted from umbrellas.
12
12
  - **Coding/ACP closeouts**: `read.findText`, visible fuzzy edit outcomes and miss context, ACP editor-buffer operations, per-session spawnable coding registries, and delete/move projections.
13
13
 
@@ -33,7 +33,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
33
33
  - [Disaster recovery and backup operations](disaster-recovery.md): the plan 027 Task 7 runbook — standard-tool backup/restore/migration-rollback/PITR/DR drill (`scripts/phase27-dr.test.mjs`), guarded commands, app-level verification, the rollback decision tree, and measured RPO/RTO in `docs/_evidence/phase27-dr-evidence.json`.
34
34
  - [Data classification and field-level redaction](data-classification.md): the plan 027 Task 8 contract — `applyFieldPolicy` walking JSON-like values with allow/redact/tokenize/deny decisions, the fail-closed protected default, per-boundary `labelFor` hints (no auto-discovery), sparse-copy overhead, and the ERP-T9 leak matrix incl. egress/audit/telemetry seams.
35
35
  - [Evaluations](evaluations.md): deterministic and bounded trace/model-judge/pairwise scoring, CI thresholds, OTel trace-reference linkage, coding/browser adversarial fixtures, ID-only linkage to immutable owned run feedback, optional durable PostgreSQL records, and trace-to-dataset curation of production runs.
36
- - [Runs and usage ledger](runs-and-usage.md): durable run/event/tool/usage persistence, optional bounded FIFO durability policies, session snapshot caching, immutable run/trace feedback, and the host-supplied `CostCatalog` pricing adapter (usage-only without one).
36
+ - [Runs and usage ledger](runs-and-usage.md): durable run/event/tool/usage persistence, optional bounded FIFO durability policies, session snapshot caching, immutable run/trace feedback, host-raisable `RunLimits` with `null` per-axis disable (bytes stay process-HARD), and the host-supplied `CostCatalog` pricing adapter (usage-only without one).
37
37
  - [Performance limits](performance.md): **0.1.0 capacity envelopes** (frozen performance contract, 24 network-free + 16 protected p95 rows, startup/pack rows), 0.0.26 coding-intelligence/process/forge/egress network-free evidence, 0.0.25 durable-loop/HITL/A2UI network-free evidence, 0.0.24 distributed event/effect PostgreSQL evidence, 0.0.23 enterprise state evidence, 0.0.15 network-free provider/RAG/memory benchmark evidence and frozen caps, bounded evaluation traces/judges/reports, and production sizing assumptions.
38
38
  - [Structured output](structured-output.md): the `Artifact*` seam plus provider-native `StructuredOutputOptions` / `structuredOutputMode` for capable models.
39
39
 
@@ -164,7 +164,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
164
164
  - [Impeccable behavior integration](impeccable.md): optional `@arnilo/prism-coding-tools/impeccable` — host `upstreamPath` to compiled Impeccable `SKILL.md`, skill + `/impeccable` → `load_skill`; no detector CLI, no live browser, not in code/sdk/all.
165
165
 
166
166
  ## Release and install
167
- - [Release and install](release-and-install.md): current **0.5.3** package graph — generated inventory in the [package-inventory section](#package-inventory) and the release page — plan 041-044 changed-package cut (progressive tool loading with `search_tools` disclosure, `@arnilo/prism-prompts` initial cut with run-ledger `promptVersion` provenance (persistence schema 9), trace-to-dataset curation in `@arnilo/prism-evals`, and composite memory-recall scoring in `@arnilo/prism-memory@0.3.2`) and independent `^0.3.0` publication; plan 050 changed-package cut (clay-integration-findings fixes + OKF v0.2 wiki bundles) and independent `^0.3.0` publication; plan 030 last-lockstep cut and independent `^0.3.0` publication; plan 029 **0.2.9** provider adoption (DeepSeek, xAI SuperGrok OAuth, ClinePass), `@arnilo/prism-impeccable`, Ponytail 4.9.0, Caveman v2.1 extras; then plan 028 **0.2.8** ACP adoption fixes; then plan 026 the fully-featured coding-agent-readiness cut: **host-selected PTY** (`pty: true` delegates only to the host `ptyBackend`, fails closed as unsupported when absent, bounded resize/TERM/attach caps), **indexed code search** (host-owned incremental index seam with explicit `indexed_literal`/`semantic` modes, literal remains the default, stale/failed/untrusted indexes fail closed `ERR_PRISM_INDEX_*`, results labeled `untrusted_index`), **coding workspaces** (`createCodingWorkspaceLifecycle`: durable CheckpointStore CAS records + LeaseStore fencing, locked worktrees, credential-free fingerprints, cleanup refusal matrix), **durable recovery** (process intent/ACP `activeRun` refs over Postgres/SQLite stores with attach-if-attested `recover()` and durable fence-checked cancellation, never fabricated exits), **patch review and diagnostics** (`createCodingPatchReviewManifest` + `assertCodingPatchAccepted` with pending/accepted/rejected/superseded bound to digest + revision + identity, opt-in LSP `syncDocument`/`diagnosticDelta`), and the **protected real coding journey** (packed consumer through real provider/Docker/Postgres/GitHub/Playwright/PTY services with retained evidence report; forge breadth GitLab/Bitbucket stays demand-gated); then plan 025 the maintainability-and-bounded-performance cut: **god-module splits** (the six remaining implementation monoliths — `src/contracts-core.ts` 1,719 L, `src/agent-session.ts` 2,049 L, `workflows/src/run.ts` 1,227 L, `server/src/handler.ts` 1,005 L, `coding-agent/src/repository.ts` 974 L, `ag-ui/src/acp/agent.ts` 836 L — split into cohesive family files behind preserved barrels, compat-preserving with zero breaking deltas, no `exports`-map subpath, `RuntimeAgentSession` kept as one class with a recorded reason), **persistence-mechanics dedup** (21 pure ownership/cursor/checkpoint/lifecycle/search helpers moved into the dependency-free `session-store-codecs`; postgres/sqlite adapters shrank 273 lines; SQL dialect stays per-adapter; no schema/shape change; cross-store conformance green), **bounded accumulation removed** (per-push `Buffer.concat` in language framing + tar parsing → chunk-array readers; framing ~100–200× faster at 4,000 chunks, tar linear at 8 MiB, caps fail-closed byte-identical; CLI `collectOutput` audited already linear), **dead-code cleanup internal-only** (62 candidates triaged: 2 internal removals + 60 allow-listed in `docs/_evidence/phase25-dead-exports-triage.md`), and **coverage close** (76 behavior-backed regressions; core 90.53/84.20/90.54 → 91.43/84.80/91.60); additive-only compat (105 helper exports), no migration; then plan 024 the package-documentation-and-compatibility-truth cut: **umbrella wording matches manifests** (`@arnilo/prism-providers` installs 11 of 14 provider adapters — Azure/Bedrock/Vertex are added separately by `prism-all`; `prism-all` installs 20 direct / 43 transitive packages and omits document-reader, OpenAPI tools, NATS, Caveman, Ponytail; membership unchanged in 0.2.x), **manifest-derived package truth** (`scripts/package-truth.mjs` → `scripts/package-truth.json` is the single source for counts, provider membership, and closures; docs literals regenerate from it and drift fails the gates), **peer-version policy Decision A** (exact `@arnilo/prism: 0.2.4` pins, atomic-upgrade rule, ERESOLVE refusal for partial upgrades, `^1.0.0` widening at 1.x), and **current-line truth** (`docs/0.1.0-readiness.md` at the 0.2.x line with 0.1.7 as the terminal 0.1.x baseline); no runtime contract delta (compat gate at 0.2.4: version literal only), no migration; then plan 023 the build-coverage-and-release-evidence-integrity cut: **build serialization** (dependency-free `scripts/with-build-lock.mjs` — one O_EXCL lockfile at `node_modules/.prism-build.lock` serializing every emit/test leaf so concurrent compilers can never expose a partial live `dist/`, stale-PID reclaim, env-overridable `PRISM_BUILD_LOCK_TIMEOUT_MS`, fail-closed; documented direct-`tsc` caveat), **corrected workspace coverage denominators** (package-local `--test-coverage-include=dist/**` so imported core `dist` no longer pollutes workspace rows — `mcp` 45.47→90.25, `rag` 19.70→94.82; evidence-based per-package thresholds in `scripts/coverage-thresholds.json` with `protectedException` for durable-leg packages shown separately, machine-readable `scripts/coverage-summary.json`), **machine-auditable release skip manifest** (`scripts/release-skip-manifest.mjs` → `scripts/release-evidence.json`: every surface recorded `pass`/`skip`/`blocked`/`protected` with reason and required env; the 33 protected/live skips named; a required surface without evidence records `blocked` and fails the release gate fail-closed — missing credentials/services can never convert into a green release), and **stabilized quality gates** (Biome 2.x `preset` config migration with zero lint diagnostics, the racy 150ms MCP bridge timing assert replaced by a deterministic barrier, load-sensitive guards carry documented `ponytail:` ceilings, machine-readable `lint-report.sarif` + `unused-report.json` retained by CI); no runtime contract delta (compat gate at 0.2.3: version literal only), no migration; then plan 022 the concurrent-state-and-durability-integrity cut: atomic model-budget reservation (`ModelRouterStateStore.reserveBudget`/`commitBudget`/`releaseBudget` with fencing tokens, `reservationTtlMs` expiry and unknown-usage reconciliation, rate/budget key-map caps with LRU eviction that never drops a held reservation), atomic conversation metadata (`SessionRecord.version` + `appendSession` `expectedVersion` CAS across Postgres/SQLite — create-only `0`, exact-version `N>0`, legacy last-write-wins when omitted; `SessionMetadataConflictError` `metadata_conflict` with versions only, HTTP 409; concurrent create/branch/archive single-statement with branch caps inside the CAS, archive wins, deleted rows never resurrect), single-consumer `EventMultiplexer` (`EventMultiplexerError` `ERR_PRISM_EVENT_MULTIPLEXER_SINGLE_CONSUMER` instead of silent queue sharing), restart-stable NATS durable consumer identity (`prism_<hmac16>` with no random suffix — crash-resumed subscribe continues from the last ack, orphaned 0.2.1 consumers reclaimed on clean stop), and bounded non-durable active-run registries (sweep + fail-closed 512 cap `ERR_PRISM_WORKFLOW_RUN_REGISTRY_OVERFLOW`); new regression surface `scripts/phase22-security.test.mjs` (4 blockers + gate accounting over built public entrypoints) + packed plain-JS `security22.mjs` consumer + the `@arnilo/prism/testing/state-concurrency-conformance` harness (7 probes across memory/Postgres/SQLite/NATS legs, no timing-only sleeps) + the `scripts/phase22-conformance.test.mjs` gate; additive-only compat (new exports only, no removals); forward-only migrations 008 (`prism_sessions.version`) and 003 (`prism_model_router_budgets.reservations`); migration `0.2.1 → 0.2.2`; then plan 021 the provider-completion-and-outbound-trust-boundaries cut: strict stream completion is the shared OpenAI-compatible default (truncated streams fail `incomplete_delta`, explicit `strictCompletion: false` opt-out), bounded success bodies via `readBoundedResponseJson` on all discovery/quota/embeddings/upload/OAuth JSON endpoints (65,536-byte ceiling, depth/property/shape caps), DNS-pinned OIDC JWKS/OPA/content fetches through the core `pinnedFetch` primitive with 3xx redirects rejected outright (private/metadata answers fail closed `ssrf_denied`), shared bounded OAuth device/token polling (`pollDeviceCodeToken`) across provider-openai and credentials-node, and the four edge fixes (Azure/Vertex credential-once, Bedrock duplicate-case/repeated-query SigV4 canonicalization, OpenAI upload failed-DELETE retention, cache `__overflow__` tokens-only); public-entrypoint threat-suite `scripts/phase21-security.test.mjs` + packed plain-JS consumer; additive-only compat (MCP transport helpers re-exported from core, no removals); migration `0.2.0 → 0.2.1`; then plan 020 the fail-closed runtime-and-sandbox-security cut on the 0.2.x review-remediation line: durable-resume decision validation in core (`assertValidAgentRunResume` — unknown decisions/malformed batches fail closed with `ERR_PRISM_DECISION_*` before any state claim, checkpoint write, or tool execution; server parser remains defense in depth), isolated work-tool subprocess environments (`@arnilo/prism-work-tools` — fixed base allow-list + explicit env + forced HOME/telemetry + late-bound per-identity tokens, 64-name/64-KiB caps, absolute binary/configDir, linear output capture), and explicit sandbox capabilities (`@arnilo/prism-coding-security` — `SandboxAdapter.capabilities` with omission-is-false fail-closed resolution, `SandboxCodingComposition.capabilities` from verified wiring, `containmentClaim` deprecated as the conservative projection; Docker reports only verified controls, native reports filesystem/process/privilege `false`); public-entrypoint security conformance (`scripts/phase20-security.test.mjs`, wired into `security:threat-suites`), packed plain-JS consumer regressions, and the sandbox-browser workflow's fail-loud Docker/native capability evidence gate — 0.2.0 never ships while a blocker is skipped; migration and rollback notes in `docs/migration.md` `0.1.7 → 0.2.0`, store-compatible with 0.1.7 in both directions; 0.1.7 was the performance-and-DX patch — dependency-free `createCacheTelemetry()` per-provider/model cache hit/miss aggregator (bounded cardinality with `__overflow__`, token counters/rates only, host-activated), host-configurable `ModelRouterSelectionPolicy` on `createModelRouter` with the reference `createCostLatencySelection` (ModelCost rank then in-memory latency EMA, default ordered behavior byte-identical), `prism providers add <name>` OpenAI-compatible provider scaffold (manifest/provider/models/cache/conformance test/docs stub, npm-name + traversal + symlink-escape validation, placeholders only), and the async `AgUiProjection` verification closeout (plan 009 Task 15 evidence recorded, no new code); plan 017 the documented breaking cut — deprecated-option removal with `docs/migration.md` `0.1.4 → 0.1.5` section and reviewed compat-baseline regeneration via `--allow-break` then `--update-baseline`: the inert provider request knobs, `RunOptions.maxToolRounds`, observational-memory flat settings keys + top-level worker aliases, `ReadToolOptions.autoResizeImages`, `INIT_PROVIDERS`; all removals fail closed naming their replacement; plan 016 internal god-module split — `agents.ts`/`contracts.ts` reorganized behind barrel re-exports with a byte-identical public entry surface, measured tree-shaking improvement in `scripts/phase16-baseline.json`, and additive `@arnilo/prism-browser` Chrome DevTools Protocol capabilities — `browser_evaluate`/`browser_observe` and `block_urls`/`unblock_urls`/`throttle`/`emulate` act actions; plan 015 dead-code and deprecation hygiene on the frozen 0.1.x line — parameterized benchmark runner `scripts/benchmark.mjs` absorbing the per-version runners, archived review-coverage evidence in `docs/_evidence/`, non-blocking unused-code sweep `npm run sweep:unused`, opt-in checkpoint persistence for loaded-skill names and read-path sets; plan 014 Alibaba provider enrichment — embeddings, video input, verified compatible-mode surface decision table; plan 013 post-release hardening — build single-flight, MCP SSE relay test, combined coverage summary, canonical manifest-count narrative, ACP modes/config persistence guidance; Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates. 0.2.6 (plan 026 Task 7) adds the protected coding journey: `scripts/phase26-coding-journey.test.mjs` runs a packed consumer through real provider calls, a digest-pinned Docker sandbox, the durable Postgres worktree lifecycle, provider-driven ACP edits with policy approval, named checks with `diagnosticDelta`, patch review over the server ArtifactService, cross-replica process recovery, durable cancellation, real GitHub PR push/reconcile/cleanup, host Playwright inspection, and the host PTY adapter (frozen profile) — the retained `scripts/phase26-coding-journey-report.json` gates release evidence (pass/blocked/protected, never a passing skip).
167
+ - [Release and install](release-and-install.md): current **0.5.4** package graph — generated inventory in the [package-inventory section](#package-inventory) and the release page — plan 041-044 changed-package cut (progressive tool loading with `search_tools` disclosure, `@arnilo/prism-prompts` initial cut with run-ledger `promptVersion` provenance (persistence schema 9), trace-to-dataset curation in `@arnilo/prism-evals`, and composite memory-recall scoring in `@arnilo/prism-memory@0.3.2`) and independent `^0.3.0` publication; plan 050 changed-package cut (clay-integration-findings fixes + OKF v0.2 wiki bundles) and independent `^0.3.0` publication; plan 030 last-lockstep cut and independent `^0.3.0` publication; plan 029 **0.2.9** provider adoption (DeepSeek, xAI SuperGrok OAuth, ClinePass), `@arnilo/prism-impeccable`, Ponytail 4.9.0, Caveman v2.1 extras; then plan 028 **0.2.8** ACP adoption fixes; then plan 026 the fully-featured coding-agent-readiness cut: **host-selected PTY** (`pty: true` delegates only to the host `ptyBackend`, fails closed as unsupported when absent, bounded resize/TERM/attach caps), **indexed code search** (host-owned incremental index seam with explicit `indexed_literal`/`semantic` modes, literal remains the default, stale/failed/untrusted indexes fail closed `ERR_PRISM_INDEX_*`, results labeled `untrusted_index`), **coding workspaces** (`createCodingWorkspaceLifecycle`: durable CheckpointStore CAS records + LeaseStore fencing, locked worktrees, credential-free fingerprints, cleanup refusal matrix), **durable recovery** (process intent/ACP `activeRun` refs over Postgres/SQLite stores with attach-if-attested `recover()` and durable fence-checked cancellation, never fabricated exits), **patch review and diagnostics** (`createCodingPatchReviewManifest` + `assertCodingPatchAccepted` with pending/accepted/rejected/superseded bound to digest + revision + identity, opt-in LSP `syncDocument`/`diagnosticDelta`), and the **protected real coding journey** (packed consumer through real provider/Docker/Postgres/GitHub/Playwright/PTY services with retained evidence report; forge breadth GitLab/Bitbucket stays demand-gated); then plan 025 the maintainability-and-bounded-performance cut: **god-module splits** (the six remaining implementation monoliths — `src/contracts-core.ts` 1,719 L, `src/agent-session.ts` 2,049 L, `workflows/src/run.ts` 1,227 L, `server/src/handler.ts` 1,005 L, `coding-agent/src/repository.ts` 974 L, `ag-ui/src/acp/agent.ts` 836 L — split into cohesive family files behind preserved barrels, compat-preserving with zero breaking deltas, no `exports`-map subpath, `RuntimeAgentSession` kept as one class with a recorded reason), **persistence-mechanics dedup** (21 pure ownership/cursor/checkpoint/lifecycle/search helpers moved into the dependency-free `session-store-codecs`; postgres/sqlite adapters shrank 273 lines; SQL dialect stays per-adapter; no schema/shape change; cross-store conformance green), **bounded accumulation removed** (per-push `Buffer.concat` in language framing + tar parsing → chunk-array readers; framing ~100–200× faster at 4,000 chunks, tar linear at 8 MiB, caps fail-closed byte-identical; CLI `collectOutput` audited already linear), **dead-code cleanup internal-only** (62 candidates triaged: 2 internal removals + 60 allow-listed in `docs/_evidence/phase25-dead-exports-triage.md`), and **coverage close** (76 behavior-backed regressions; core 90.53/84.20/90.54 → 91.43/84.80/91.60); additive-only compat (105 helper exports), no migration; then plan 024 the package-documentation-and-compatibility-truth cut: **umbrella wording matches manifests** (`@arnilo/prism-providers` installs 11 of 14 provider adapters — Azure/Bedrock/Vertex are added separately by `prism-all`; `prism-all` installs 20 direct / 43 transitive packages and omits document-reader, OpenAPI tools, NATS, Caveman, Ponytail; membership unchanged in 0.2.x), **manifest-derived package truth** (`scripts/package-truth.mjs` → `scripts/package-truth.json` is the single source for counts, provider membership, and closures; docs literals regenerate from it and drift fails the gates), **peer-version policy Decision A** (exact `@arnilo/prism: 0.2.4` pins, atomic-upgrade rule, ERESOLVE refusal for partial upgrades, `^1.0.0` widening at 1.x), and **current-line truth** (`docs/0.1.0-readiness.md` at the 0.2.x line with 0.1.7 as the terminal 0.1.x baseline); no runtime contract delta (compat gate at 0.2.4: version literal only), no migration; then plan 023 the build-coverage-and-release-evidence-integrity cut: **build serialization** (dependency-free `scripts/with-build-lock.mjs` — one O_EXCL lockfile at `node_modules/.prism-build.lock` serializing every emit/test leaf so concurrent compilers can never expose a partial live `dist/`, stale-PID reclaim, env-overridable `PRISM_BUILD_LOCK_TIMEOUT_MS`, fail-closed; documented direct-`tsc` caveat), **corrected workspace coverage denominators** (package-local `--test-coverage-include=dist/**` so imported core `dist` no longer pollutes workspace rows — `mcp` 45.47→90.25, `rag` 19.70→94.82; evidence-based per-package thresholds in `scripts/coverage-thresholds.json` with `protectedException` for durable-leg packages shown separately, machine-readable `scripts/coverage-summary.json`), **machine-auditable release skip manifest** (`scripts/release-skip-manifest.mjs` → `scripts/release-evidence.json`: every surface recorded `pass`/`skip`/`blocked`/`protected` with reason and required env; the 33 protected/live skips named; a required surface without evidence records `blocked` and fails the release gate fail-closed — missing credentials/services can never convert into a green release), and **stabilized quality gates** (Biome 2.x `preset` config migration with zero lint diagnostics, the racy 150ms MCP bridge timing assert replaced by a deterministic barrier, load-sensitive guards carry documented `ponytail:` ceilings, machine-readable `lint-report.sarif` + `unused-report.json` retained by CI); no runtime contract delta (compat gate at 0.2.3: version literal only), no migration; then plan 022 the concurrent-state-and-durability-integrity cut: atomic model-budget reservation (`ModelRouterStateStore.reserveBudget`/`commitBudget`/`releaseBudget` with fencing tokens, `reservationTtlMs` expiry and unknown-usage reconciliation, rate/budget key-map caps with LRU eviction that never drops a held reservation), atomic conversation metadata (`SessionRecord.version` + `appendSession` `expectedVersion` CAS across Postgres/SQLite — create-only `0`, exact-version `N>0`, legacy last-write-wins when omitted; `SessionMetadataConflictError` `metadata_conflict` with versions only, HTTP 409; concurrent create/branch/archive single-statement with branch caps inside the CAS, archive wins, deleted rows never resurrect), single-consumer `EventMultiplexer` (`EventMultiplexerError` `ERR_PRISM_EVENT_MULTIPLEXER_SINGLE_CONSUMER` instead of silent queue sharing), restart-stable NATS durable consumer identity (`prism_<hmac16>` with no random suffix — crash-resumed subscribe continues from the last ack, orphaned 0.2.1 consumers reclaimed on clean stop), and bounded non-durable active-run registries (sweep + fail-closed 512 cap `ERR_PRISM_WORKFLOW_RUN_REGISTRY_OVERFLOW`); new regression surface `scripts/phase22-security.test.mjs` (4 blockers + gate accounting over built public entrypoints) + packed plain-JS `security22.mjs` consumer + the `@arnilo/prism/testing/state-concurrency-conformance` harness (7 probes across memory/Postgres/SQLite/NATS legs, no timing-only sleeps) + the `scripts/phase22-conformance.test.mjs` gate; additive-only compat (new exports only, no removals); forward-only migrations 008 (`prism_sessions.version`) and 003 (`prism_model_router_budgets.reservations`); migration `0.2.1 → 0.2.2`; then plan 021 the provider-completion-and-outbound-trust-boundaries cut: strict stream completion is the shared OpenAI-compatible default (truncated streams fail `incomplete_delta`, explicit `strictCompletion: false` opt-out), bounded success bodies via `readBoundedResponseJson` on all discovery/quota/embeddings/upload/OAuth JSON endpoints (65,536-byte ceiling, depth/property/shape caps), DNS-pinned OIDC JWKS/OPA/content fetches through the core `pinnedFetch` primitive with 3xx redirects rejected outright (private/metadata answers fail closed `ssrf_denied`), shared bounded OAuth device/token polling (`pollDeviceCodeToken`) across provider-openai and credentials-node, and the four edge fixes (Azure/Vertex credential-once, Bedrock duplicate-case/repeated-query SigV4 canonicalization, OpenAI upload failed-DELETE retention, cache `__overflow__` tokens-only); public-entrypoint threat-suite `scripts/phase21-security.test.mjs` + packed plain-JS consumer; additive-only compat (MCP transport helpers re-exported from core, no removals); migration `0.2.0 → 0.2.1`; then plan 020 the fail-closed runtime-and-sandbox-security cut on the 0.2.x review-remediation line: durable-resume decision validation in core (`assertValidAgentRunResume` — unknown decisions/malformed batches fail closed with `ERR_PRISM_DECISION_*` before any state claim, checkpoint write, or tool execution; server parser remains defense in depth), isolated work-tool subprocess environments (`@arnilo/prism-work-tools` — fixed base allow-list + explicit env + forced HOME/telemetry + late-bound per-identity tokens, 64-name/64-KiB caps, absolute binary/configDir, linear output capture), and explicit sandbox capabilities (`@arnilo/prism-coding-security` — `SandboxAdapter.capabilities` with omission-is-false fail-closed resolution, `SandboxCodingComposition.capabilities` from verified wiring, `containmentClaim` deprecated as the conservative projection; Docker reports only verified controls, native reports filesystem/process/privilege `false`); public-entrypoint security conformance (`scripts/phase20-security.test.mjs`, wired into `security:threat-suites`), packed plain-JS consumer regressions, and the sandbox-browser workflow's fail-loud Docker/native capability evidence gate — 0.2.0 never ships while a blocker is skipped; migration and rollback notes in `docs/migration.md` `0.1.7 → 0.2.0`, store-compatible with 0.1.7 in both directions; 0.1.7 was the performance-and-DX patch — dependency-free `createCacheTelemetry()` per-provider/model cache hit/miss aggregator (bounded cardinality with `__overflow__`, token counters/rates only, host-activated), host-configurable `ModelRouterSelectionPolicy` on `createModelRouter` with the reference `createCostLatencySelection` (ModelCost rank then in-memory latency EMA, default ordered behavior byte-identical), `prism providers add <name>` OpenAI-compatible provider scaffold (manifest/provider/models/cache/conformance test/docs stub, npm-name + traversal + symlink-escape validation, placeholders only), and the async `AgUiProjection` verification closeout (plan 009 Task 15 evidence recorded, no new code); plan 017 the documented breaking cut — deprecated-option removal with `docs/migration.md` `0.1.4 → 0.1.5` section and reviewed compat-baseline regeneration via `--allow-break` then `--update-baseline`: the inert provider request knobs, `RunOptions.maxToolRounds`, observational-memory flat settings keys + top-level worker aliases, `ReadToolOptions.autoResizeImages`, `INIT_PROVIDERS`; all removals fail closed naming their replacement; plan 016 internal god-module split — `agents.ts`/`contracts.ts` reorganized behind barrel re-exports with a byte-identical public entry surface, measured tree-shaking improvement in `scripts/phase16-baseline.json`, and additive `@arnilo/prism-browser` Chrome DevTools Protocol capabilities — `browser_evaluate`/`browser_observe` and `block_urls`/`unblock_urls`/`throttle`/`emulate` act actions; plan 015 dead-code and deprecation hygiene on the frozen 0.1.x line — parameterized benchmark runner `scripts/benchmark.mjs` absorbing the per-version runners, archived review-coverage evidence in `docs/_evidence/`, non-blocking unused-code sweep `npm run sweep:unused`, opt-in checkpoint persistence for loaded-skill names and read-path sets; plan 014 Alibaba provider enrichment — embeddings, video input, verified compatible-mode surface decision table; plan 013 post-release hardening — build single-flight, MCP SSE relay test, combined coverage summary, canonical manifest-count narrative, ACP modes/config persistence guidance; Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates. 0.2.6 (plan 026 Task 7) adds the protected coding journey: `scripts/phase26-coding-journey.test.mjs` runs a packed consumer through real provider calls, a digest-pinned Docker sandbox, the durable Postgres worktree lifecycle, provider-driven ACP edits with policy approval, named checks with `diagnosticDelta`, patch review over the server ArtifactService, cross-replica process recovery, durable cancellation, real GitHub PR push/reconcile/cleanup, host Playwright inspection, and the host PTY adapter (frozen profile) — the retained `scripts/phase26-coding-journey-report.json` gates release evidence (pass/blocked/protected, never a passing skip).
168
168
  - [Migrate 0.4 to 0.5](migrate-to-0.5.md): the complete 0.5.x migration guide (plans 055–066) — 0.5.0 lockstep plus **0.5.1** additive request construction (`thinkingLevel` field, kernel session/cache defaults, OpenCode Go `ProviderRequirementError`) — plus rollback.
169
169
  - [Migrate legacy 0.3 packages to 0.4](migrate-to-0.4.md): complete breaking package-reorganization guide — all retired package/import mappings, profile replacements, optional peers and host binaries, security boundaries, rollback, and npm `legacy`/deprecation lifecycle.
170
170
  - [0.1.0 / 1.0 readiness gates](0.1.0-readiness.md): command-per-gate 1.0 readiness table — frozen API surface + compat gate, migration/docs tripwires, budget table, live-suite matrix, security matrix, current-line status (**0.2.5** current line; 0.1.7 terminal 0.1.x baseline), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
@@ -180,15 +180,15 @@ The generated inventory below derives from [`scripts/package-truth.json`](../scr
180
180
 
181
181
  | package | version | notes |
182
182
  | --- | --- | --- |
183
- | `@arnilo/prism` | 0.5.3 | core — runtime, CLI/RPC, templates, docs |
184
- | `@arnilo/prism-coding-tools` | 0.5.3 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
185
- | `@arnilo/prism-core` | 0.5.3 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
186
- | `@arnilo/prism-providers` | 0.5.3 | family — all provider adapters as `/<adapter>` subpaths |
187
- | `@arnilo/prism-acp-agent` | 0.5.3 | capability — ACP adapter |
188
- | `@arnilo/prism-ag-ui` | 0.5.3 | capability — AG-UI/A2A/A2UI adapter |
189
- | `@arnilo/prism-mcp` | 0.5.3 | capability — MCP client/server/OAuth interop |
190
- | `@arnilo/prism-memory` | 0.5.3 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
191
- | `@arnilo/prism-office` | 0.5.3 | capability — /documents, /sheets, /diagrams subpaths |
192
- | `@arnilo/prism-web-tools` | 0.5.3 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
183
+ | `@arnilo/prism` | 0.5.4 | core — runtime, CLI/RPC, templates, docs |
184
+ | `@arnilo/prism-coding-tools` | 0.5.4 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
185
+ | `@arnilo/prism-core` | 0.5.4 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
186
+ | `@arnilo/prism-providers` | 0.5.4 | family — all provider adapters as `/<adapter>` subpaths |
187
+ | `@arnilo/prism-acp-agent` | 0.5.4 | capability — ACP adapter |
188
+ | `@arnilo/prism-ag-ui` | 0.5.4 | capability — AG-UI/A2A/A2UI adapter |
189
+ | `@arnilo/prism-mcp` | 0.5.4 | capability — MCP client/server/OAuth interop |
190
+ | `@arnilo/prism-memory` | 0.5.4 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
191
+ | `@arnilo/prism-office` | 0.5.4 | capability — /documents, /sheets, /diagrams subpaths |
192
+ | `@arnilo/prism-web-tools` | 0.5.4 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
193
193
  <!-- generated:package-truth:inventory end -->
194
194
 
@@ -1,6 +1,6 @@
1
1
  # Migrate Prism 0.4 to 0.5
2
2
 
3
- > **Status: 0.5.3** (tool-result content fold, additive on the 2026-09-08 `v0.5.2` tag). 0.5.0 covers plans 055–065. 0.5.1 adds kernel provider-request construction. 0.5.2 coalesces stream tokens.
3
+ > **Status: 0.5.4** (run-limit HARD split from host policy on the 2026-09-08 `v0.5.3` tag). 0.5.0 covers plans 055–065. 0.5.1 adds kernel provider-request construction. 0.5.2 coalesces stream tokens. 0.5.3 folds content-only tool results.
4
4
 
5
5
  ## What changes
6
6
 
@@ -126,6 +126,16 @@ What to do:
126
126
  4. Custom generate sites should call `applyDefaultProviderRequestOptions(request, { sessionId, thinkingLevel })`.
127
127
  5. Nothing persisted changes. Session/cache keys are correlation ids, never secrets.
128
128
 
129
+ ## 9. Run limits: HARD vs host policy (plan 067 / 0.5.4, export-shape break)
130
+
131
+ - **Removed export:** `HARD_MAX_RUN_COST` (delete the import; no replacement — `maxCost` now accepts any finite non-negative amount).
132
+ - **Reshaped export:** `HARD_RUN_LIMITS` is now `{ maxRequestBytes: 67108864, maxResponseBytes: 67108864 }` — the only process-safety caps (a giant provider frame cannot OOM the host). Product axes have no hard cap; hosts size them per workload.
133
+ - **New capability:** `RunLimits` policy axes (`maxTurns`, `maxProviderAttempts`, `maxToolRounds`, `maxToolCalls`, `maxWallTimeMs`, `maxInputTokens`, `maxOutputTokens`, `maxTotalTokens`) accept `number | null`. `null` disables the axis; omitted keys resolve to `DEFAULT_RUN_LIMITS` (unchanged fence: 16/24/8/32/120s/8 MiB/40k/10k/50k). Byte axes reject `null` and values above 64 MiB.
134
+ - **New type:** `ResolvedRunLimits` (`resolveRunLimits` return; policy axes `number | null`).
135
+ - **Resolution rules:** narrowing-only is kept — `null` acts as +Infinity, so agent `16` + run `null` → `16`; an omitted `maxProviderAttempts` lifts to `max(24, maxTurns)` (or `null` when `maxTurns` is `null`); explicitly set attempts lift only when both are finite.
136
+ - **Durable state:** runs with `maxWallTimeMs: null` persist checkpoints without `deadlineAt`; older checkpoints with a deadline still resume under it.
137
+ - **Documented ceiling:** vendors that omit usage charge zero to token counters; a configured `maxCost` stays the fail-closed envelope (missing/mixed-currency cost breaches immediately).
138
+
129
139
  ## Upgrade steps
130
140
 
131
141
  1. Bump every `@arnilo/*` dependency/peer to `^0.5.1` (0.5.0 hosts: `^0.5.0` still works until you want construction).
package/docs/migration.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Migration guide
2
2
 
3
+ ## 0.5.3 → 0.5.4 (export-shape break in `@arnilo/prism`)
4
+
5
+ Run-limit process ceilings split from host policy (plan 067). `HARD_RUN_LIMITS` shrinks to the two process-safety axes (`maxRequestBytes`/`maxResponseBytes`, 64 MiB) and `HARD_MAX_RUN_COST` is removed — delete imports; no replacement exists because product axes have no hard cap. `RunLimits` policy axes (turns, attempts, tool rounds/calls, wall time, tokens) now accept `number | null`, where `null` explicitly disables the axis and omitted keys keep the `DEFAULT_RUN_LIMITS` fence; byte axes reject `null`. Resolution stays narrowing-only (`null` acts as +Infinity), an omitted `maxProviderAttempts` lifts to at least a raised/disabled `maxTurns`, and the former `$10k` `maxCost` ceiling is gone (any finite non-negative amount is valid). `resolveRunLimits` returns the new `ResolvedRunLimits` type (policy axes `number | null`). Durable run state without a wall limit omits `deadlineAt`; older checkpoints carrying one still resume with it. `DEFAULT_RUN_LIMITS` values and all breach semantics are unchanged.
6
+
3
7
  ## 0.5.2 → 0.5.3 (additive)
4
8
 
5
9
  Content-only tool results fold onto `tool_result.result` at construction. Serializers join sibling `type:text` blocks when `result` is missing, so coding tools that return `content` (not `value`) no longer reach the model as JSON `"null"`. No import, store, or peer-range break; bump `@arnilo/prism*` to `^0.5.3`.
@@ -25,26 +25,26 @@ Do not use provider packages as a package manager, credential store, env loader,
25
25
 
26
26
  | adapter package | version |
27
27
  | --- | --- |
28
- | `@arnilo/prism-providers/ai-sdk` | 0.5.3 |
29
- | `@arnilo/prism-providers/alibaba` | 0.5.3 |
30
- | `@arnilo/prism-providers/anthropic` | 0.5.3 |
31
- | `@arnilo/prism-providers/azure` | 0.5.3 |
32
- | `@arnilo/prism-providers/bedrock` | 0.5.3 |
33
- | `@arnilo/prism-providers/clinepass` | 0.5.3 |
34
- | `@arnilo/prism-providers/commandcode` | 0.5.3 |
35
- | `@arnilo/prism-providers/deepseek` | 0.5.3 |
36
- | `@arnilo/prism-providers/google` | 0.5.3 |
37
- | `@arnilo/prism-providers/hyper` | 0.5.3 |
38
- | `@arnilo/prism-providers/kimi` | 0.5.3 |
39
- | `@arnilo/prism-providers/model-discovery` | 0.5.3 |
40
- | `@arnilo/prism-providers/neuralwatt` | 0.5.3 |
41
- | `@arnilo/prism-providers/ollama` | 0.5.3 |
42
- | `@arnilo/prism-providers/openai` | 0.5.3 |
43
- | `@arnilo/prism-providers/opencode-go` | 0.5.3 |
44
- | `@arnilo/prism-providers/openrouter` | 0.5.3 |
45
- | `@arnilo/prism-providers/vertex` | 0.5.3 |
46
- | `@arnilo/prism-providers/xai` | 0.5.3 |
47
- | `@arnilo/prism-providers/zai` | 0.5.3 |
28
+ | `@arnilo/prism-providers/ai-sdk` | 0.5.4 |
29
+ | `@arnilo/prism-providers/alibaba` | 0.5.4 |
30
+ | `@arnilo/prism-providers/anthropic` | 0.5.4 |
31
+ | `@arnilo/prism-providers/azure` | 0.5.4 |
32
+ | `@arnilo/prism-providers/bedrock` | 0.5.4 |
33
+ | `@arnilo/prism-providers/clinepass` | 0.5.4 |
34
+ | `@arnilo/prism-providers/commandcode` | 0.5.4 |
35
+ | `@arnilo/prism-providers/deepseek` | 0.5.4 |
36
+ | `@arnilo/prism-providers/google` | 0.5.4 |
37
+ | `@arnilo/prism-providers/hyper` | 0.5.4 |
38
+ | `@arnilo/prism-providers/kimi` | 0.5.4 |
39
+ | `@arnilo/prism-providers/model-discovery` | 0.5.4 |
40
+ | `@arnilo/prism-providers/neuralwatt` | 0.5.4 |
41
+ | `@arnilo/prism-providers/ollama` | 0.5.4 |
42
+ | `@arnilo/prism-providers/openai` | 0.5.4 |
43
+ | `@arnilo/prism-providers/opencode-go` | 0.5.4 |
44
+ | `@arnilo/prism-providers/openrouter` | 0.5.4 |
45
+ | `@arnilo/prism-providers/vertex` | 0.5.4 |
46
+ | `@arnilo/prism-providers/xai` | 0.5.4 |
47
+ | `@arnilo/prism-providers/zai` | 0.5.4 |
48
48
  <!-- generated:package-truth:providers end -->
49
49
 
50
50
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism's current **0.5.x** line has **10 publishable manifests**: the root `@arnilo/prism` core package plus **9 workspace packages** — **19 provider adapters** (19 provider adapter subpaths inside the `@arnilo/prism-providers` family), 3 `prism-*` family/profile packages, and 6 capability packages. (Generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json` — the manifest-derived single source for counts, provider membership, umbrella closures, and profile closures.) The last lockstep cut was 0.3.0; Decision B now publishes changed packages independently inside `^0.3.0` — the plan 039 changed-package cut moved root `@arnilo/prism` and every plan-035+ changed package to **0.3.1**, and the plan 050 changed-package cut moved root plus four changed packages to **0.3.2**; the plan 041-044 changed-package cut moves root to **0.3.3** with `@arnilo/prism-memory@0.3.2` (composite recall scoring), `@arnilo/prism-evals@0.3.1` (trace-to-dataset curation), the three session-store packages at **0.3.1** (run-ledger `promptVersion` provenance), and the initial `@arnilo/prism-prompts@0.0.1` (independent opt-in, outside `prism-all`); plan 054 consolidation then folded `@arnilo/prism-browser` and `@arnilo/prism-obscura` into the `@arnilo/prism-web-tools` family as `/browser` and `/obscura` subpaths, folded `@arnilo/prism-rag`, both compaction strategies, `@arnilo/prism-graft`, and `@arnilo/prism-wiki` into the `@arnilo/prism-memory` family as `/rag`, `/compaction/llm`, `/compaction/observational-memory`, `/graft`, and `/wiki` subpaths (deleting the `@arnilo/prism-compaction` profile), and folded all 17 `@arnilo/prism-provider-*` packages into the `@arnilo/prism-providers` family as `/<adapter>` subpaths (Azure/Bedrock/Vertex stop being special all-only manifests); independent publication continues inside `^0.3.0` ranges (which satisfy 0.3.1, 0.3.2, and 0.3.3). This page describes how they are packed, what each tarball contains, how to install them, the required non-optional **caret** `@arnilo/prism@^0.5.3` peer range, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
5
+ Prism's current **0.5.x** line has **10 publishable manifests**: the root `@arnilo/prism` core package plus **9 workspace packages** — **19 provider adapters** (19 provider adapter subpaths inside the `@arnilo/prism-providers` family), 3 `prism-*` family/profile packages, and 6 capability packages. (Generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json` — the manifest-derived single source for counts, provider membership, umbrella closures, and profile closures.) The last lockstep cut was 0.3.0; Decision B now publishes changed packages independently inside `^0.3.0` — the plan 039 changed-package cut moved root `@arnilo/prism` and every plan-035+ changed package to **0.3.1**, and the plan 050 changed-package cut moved root plus four changed packages to **0.3.2**; the plan 041-044 changed-package cut moves root to **0.3.3** with `@arnilo/prism-memory@0.3.2` (composite recall scoring), `@arnilo/prism-evals@0.3.1` (trace-to-dataset curation), the three session-store packages at **0.3.1** (run-ledger `promptVersion` provenance), and the initial `@arnilo/prism-prompts@0.0.1` (independent opt-in, outside `prism-all`); plan 054 consolidation then folded `@arnilo/prism-browser` and `@arnilo/prism-obscura` into the `@arnilo/prism-web-tools` family as `/browser` and `/obscura` subpaths, folded `@arnilo/prism-rag`, both compaction strategies, `@arnilo/prism-graft`, and `@arnilo/prism-wiki` into the `@arnilo/prism-memory` family as `/rag`, `/compaction/llm`, `/compaction/observational-memory`, `/graft`, and `/wiki` subpaths (deleting the `@arnilo/prism-compaction` profile), and folded all 17 `@arnilo/prism-provider-*` packages into the `@arnilo/prism-providers` family as `/<adapter>` subpaths (Azure/Bedrock/Vertex stop being special all-only manifests); independent publication continues inside `^0.3.0` ranges (which satisfy 0.3.1, 0.3.2, and 0.3.3). This page describes how they are packed, what each tarball contains, how to install them, the required non-optional **caret** `@arnilo/prism@^0.5.4` peer range, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
6
6
 
7
7
  Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism` peer inside the Decision B window — the caret current spec is `@arnilo/prism@^0.3.3` and every declared window peer satisfies it: packages republishing in the plan 050 cut carry `^0.3.2`; the plan 039 set keeps `^0.3.1`; unchanged packages keep their `^0.3.0` peer; profiles are pure manifests. The plan 050 republished set declares the required `@arnilo/prism@^0.3.2` peer; the plan 041-044 republished set keeps its existing `^0.3.0` window peer; unchanged packages keep their prior window. Installation activates no provider, listener, database, browser, credential, or tool capability.
8
8
 
@@ -11,16 +11,16 @@ Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package
11
11
 
12
12
  | package | version | notes |
13
13
  | --- | --- | --- |
14
- | `@arnilo/prism` | 0.5.3 | core — runtime, CLI/RPC, templates, docs |
15
- | `@arnilo/prism-coding-tools` | 0.5.3 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
16
- | `@arnilo/prism-core` | 0.5.3 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
17
- | `@arnilo/prism-providers` | 0.5.3 | family — all provider adapters as `/<adapter>` subpaths |
18
- | `@arnilo/prism-acp-agent` | 0.5.3 | capability — ACP adapter |
19
- | `@arnilo/prism-ag-ui` | 0.5.3 | capability — AG-UI/A2A/A2UI adapter |
20
- | `@arnilo/prism-mcp` | 0.5.3 | capability — MCP client/server/OAuth interop |
21
- | `@arnilo/prism-memory` | 0.5.3 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
22
- | `@arnilo/prism-office` | 0.5.3 | capability — /documents, /sheets, /diagrams subpaths |
23
- | `@arnilo/prism-web-tools` | 0.5.3 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
14
+ | `@arnilo/prism` | 0.5.4 | core — runtime, CLI/RPC, templates, docs |
15
+ | `@arnilo/prism-coding-tools` | 0.5.4 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
16
+ | `@arnilo/prism-core` | 0.5.4 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
17
+ | `@arnilo/prism-providers` | 0.5.4 | family — all provider adapters as `/<adapter>` subpaths |
18
+ | `@arnilo/prism-acp-agent` | 0.5.4 | capability — ACP adapter |
19
+ | `@arnilo/prism-ag-ui` | 0.5.4 | capability — AG-UI/A2A/A2UI adapter |
20
+ | `@arnilo/prism-mcp` | 0.5.4 | capability — MCP client/server/OAuth interop |
21
+ | `@arnilo/prism-memory` | 0.5.4 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
22
+ | `@arnilo/prism-office` | 0.5.4 | capability — /documents, /sheets, /diagrams subpaths |
23
+ | `@arnilo/prism-web-tools` | 0.5.4 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
24
24
  <!-- generated:package-truth:inventory end -->
25
25
 
26
26
 
@@ -29,26 +29,26 @@ Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package
29
29
 
30
30
  | adapter package | version |
31
31
  | --- | --- |
32
- | `@arnilo/prism-providers/ai-sdk` | 0.5.3 |
33
- | `@arnilo/prism-providers/alibaba` | 0.5.3 |
34
- | `@arnilo/prism-providers/anthropic` | 0.5.3 |
35
- | `@arnilo/prism-providers/azure` | 0.5.3 |
36
- | `@arnilo/prism-providers/bedrock` | 0.5.3 |
37
- | `@arnilo/prism-providers/clinepass` | 0.5.3 |
38
- | `@arnilo/prism-providers/commandcode` | 0.5.3 |
39
- | `@arnilo/prism-providers/deepseek` | 0.5.3 |
40
- | `@arnilo/prism-providers/google` | 0.5.3 |
41
- | `@arnilo/prism-providers/hyper` | 0.5.3 |
42
- | `@arnilo/prism-providers/kimi` | 0.5.3 |
43
- | `@arnilo/prism-providers/model-discovery` | 0.5.3 |
44
- | `@arnilo/prism-providers/neuralwatt` | 0.5.3 |
45
- | `@arnilo/prism-providers/ollama` | 0.5.3 |
46
- | `@arnilo/prism-providers/openai` | 0.5.3 |
47
- | `@arnilo/prism-providers/opencode-go` | 0.5.3 |
48
- | `@arnilo/prism-providers/openrouter` | 0.5.3 |
49
- | `@arnilo/prism-providers/vertex` | 0.5.3 |
50
- | `@arnilo/prism-providers/xai` | 0.5.3 |
51
- | `@arnilo/prism-providers/zai` | 0.5.3 |
32
+ | `@arnilo/prism-providers/ai-sdk` | 0.5.4 |
33
+ | `@arnilo/prism-providers/alibaba` | 0.5.4 |
34
+ | `@arnilo/prism-providers/anthropic` | 0.5.4 |
35
+ | `@arnilo/prism-providers/azure` | 0.5.4 |
36
+ | `@arnilo/prism-providers/bedrock` | 0.5.4 |
37
+ | `@arnilo/prism-providers/clinepass` | 0.5.4 |
38
+ | `@arnilo/prism-providers/commandcode` | 0.5.4 |
39
+ | `@arnilo/prism-providers/deepseek` | 0.5.4 |
40
+ | `@arnilo/prism-providers/google` | 0.5.4 |
41
+ | `@arnilo/prism-providers/hyper` | 0.5.4 |
42
+ | `@arnilo/prism-providers/kimi` | 0.5.4 |
43
+ | `@arnilo/prism-providers/model-discovery` | 0.5.4 |
44
+ | `@arnilo/prism-providers/neuralwatt` | 0.5.4 |
45
+ | `@arnilo/prism-providers/ollama` | 0.5.4 |
46
+ | `@arnilo/prism-providers/openai` | 0.5.4 |
47
+ | `@arnilo/prism-providers/opencode-go` | 0.5.4 |
48
+ | `@arnilo/prism-providers/openrouter` | 0.5.4 |
49
+ | `@arnilo/prism-providers/vertex` | 0.5.4 |
50
+ | `@arnilo/prism-providers/xai` | 0.5.4 |
51
+ | `@arnilo/prism-providers/zai` | 0.5.4 |
52
52
  <!-- generated:package-truth:providers end -->
53
53
 
54
54
 
@@ -137,7 +137,7 @@ A packed tarball contains only public compiled output and release files:
137
137
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
138
138
  - The core tarball additionally ships the full `docs/` directory (the docs hub), `templates/init/`, and the `templates/` gallery (e.g. `deep-research`) used by `prism init`.
139
139
  - `dist/cli.js` and the `bin` link in core.
140
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.5.3.tgz`; family packages produce `arnilo-prism-core-0.5.3.tgz`, `arnilo-prism-coding-tools-0.5.3.tgz`, `arnilo-prism-providers-0.5.3.tgz` (all 19 adapters inside), `arnilo-prism-memory-0.5.3.tgz`, `arnilo-prism-web-tools-0.5.3.tgz`, and `arnilo-prism-office-0.5.3.tgz`; capability packages like `arnilo-prism-mcp-0.5.3.tgz` carry their own package version. Independent-package tags carry their own version. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
140
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.5.4.tgz`; family packages produce `arnilo-prism-core-0.5.4.tgz`, `arnilo-prism-coding-tools-0.5.4.tgz`, `arnilo-prism-providers-0.5.4.tgz` (all 19 adapters inside), `arnilo-prism-memory-0.5.4.tgz`, `arnilo-prism-web-tools-0.5.4.tgz`, and `arnilo-prism-office-0.5.4.tgz`; capability packages like `arnilo-prism-mcp-0.5.4.tgz` carry their own package version. Independent-package tags carry their own version. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
141
141
 
142
142
  Excluded from every tarball by `files` negation:
143
143
 
@@ -59,7 +59,7 @@ await session.run("Summarize", {
59
59
  });
60
60
  ```
61
61
 
62
- Defaults/hard caps are respectively: turns 16/64, provider attempts 24/256, tool rounds 8/64, tool calls 32/256, wall time 120 seconds/30 minutes, request and response bytes 8/64 MiB, input tokens 40,000/1,000,000, output tokens 10,000/250,000, total tokens 50,000/1,000,000, and cost 10,000 currency units. Integer values must be positive safe integers. Cost needs a finite non-negative amount plus one currency; when cost is limited, absent, non-finite, or mixed-currency provider cost fails closed.
62
+ Defaults are the unconfigured fence (OWASP LLM10): turns 16, provider attempts 24, tool rounds 8, tool calls 32, wall time 120 seconds, request and response bytes 8 MiB each, input tokens 40,000, output tokens 10,000, total tokens 50,000. Hard process ceilings exist only for request/response bytes (64 MiB each), so a bug cannot OOM the host through a giant provider frame; those two axes reject `null`. Every other axis is host policy (0.5.4): omit a key for the default, set a positive safe integer sized to the workload, or set `null` to disable the axis — overnight sessions raise turns/wall/tokens, and a disabled wall still honors `RunOptions.signal`. Resolution stays narrowing-only: `RunOptions.limits` may lower `AgentConfig.limits`, `null` acts as +Infinity (agent 16 + run `null` → 16), and a raised/disabled `maxTurns` lifts an omitted `maxProviderAttempts` (default 24) to at least `maxTurns` so attempts cannot undercut turns; explicitly set attempts values are lifted only when both are finite. Cumulative token counters are billed usage across the whole run, not the context window (`contextBudget` governs window compaction). For production, prefer an explicit `maxCost`: cost needs a finite non-negative amount plus one currency, and when cost is limited, absent, non-finite, or mixed-currency provider cost fails closed. Vendors that omit usage charge zero to the token counters (local/Ollama report none), so a configured `maxCost` is the fail-closed envelope for usage-less vendors.
63
63
 
64
64
  Prism charges turns before assembly, provider attempts and request bytes before generation, response bytes per provider event, tool rounds before a batch, tool calls before dispatch, and usage before another turn. A breach stops new work, aborts active work through the run signal, emits exactly one redacted `run_limit_exceeded` event/ledger row, and throws `AgentRunError` with `result.limit` (`limit`, `maximum`, `observed`, optional `currency`). Provider-reported token/cost totals arrive after generation, so that completed provider turn can be the unavoidable overshoot boundary.
65
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",