@arnilo/prism 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/agent-definitions.js +2 -3
- package/dist/agent-loops.js +12 -7
- package/dist/agent-run-lifecycle.d.ts +1 -2
- package/dist/agent-run-lifecycle.js +1 -1
- package/dist/agent-run-state.js +16 -3
- package/dist/agents.d.ts +1 -1
- package/dist/agents.js +121 -51
- package/dist/cache-helpers.js +18 -9
- package/dist/checkpoints.js +5 -9
- package/dist/cli-init.js +3 -7
- package/dist/cli-runner.d.ts +1 -1
- package/dist/cli-runner.js +74 -13
- package/dist/compaction.js +5 -4
- package/dist/config.js +7 -4
- package/dist/content.js +26 -24
- package/dist/context-budget.js +12 -8
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.js +4 -1
- package/dist/contribution-parsing.js +6 -2
- package/dist/conversations.js +2 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/credentials.js +3 -1
- package/dist/event-multiplexer.js +1 -3
- package/dist/feedback.js +11 -9
- package/dist/guardrails.d.ts +1 -1
- package/dist/guardrails.js +17 -14
- package/dist/identity.js +10 -2
- package/dist/index.d.ts +82 -83
- package/dist/index.js +42 -42
- package/dist/input.d.ts +2 -2
- package/dist/input.js +40 -24
- package/dist/instruction-injection.d.ts +1 -1
- package/dist/node/agent-definitions.js +16 -8
- package/dist/node/contribution-discovery.d.ts +1 -2
- package/dist/node/contribution-discovery.js +3 -3
- package/dist/node/session-store-jsonl.js +10 -7
- package/dist/node/settings.d.ts +1 -1
- package/dist/node/settings.js +1 -1
- package/dist/node/system-project-prompts.js +2 -4
- package/dist/node/trust.js +1 -1
- package/dist/persistence-lifecycle.js +1 -3
- package/dist/provider-events.js +3 -1
- package/dist/provider-request-policy.js +3 -4
- package/dist/providers/media.d.ts +1 -1
- package/dist/providers/openai-compatible.js +3 -4
- package/dist/providers/openai-primitives.js +7 -7
- package/dist/redaction.d.ts +1 -0
- package/dist/redaction.js +5 -2
- package/dist/resources.d.ts +2 -2
- package/dist/resources.js +2 -2
- package/dist/rpc.js +42 -9
- package/dist/run-ledger.js +13 -4
- package/dist/run-limits.js +49 -10
- package/dist/secure-agent.js +1 -1
- package/dist/security.js +7 -2
- package/dist/session-stores.d.ts +1 -1
- package/dist/session-stores.js +13 -13
- package/dist/structured-output.js +2 -2
- package/dist/system-prompts.js +7 -2
- package/dist/testing/compaction-conformance.js +5 -1
- package/dist/testing/extension-conformance.js +15 -3
- package/dist/testing/feedback.d.ts +1 -3
- package/dist/testing/feedback.js +1 -1
- package/dist/testing/persistence-schema.js +206 -37
- package/dist/testing/provider-conformance.js +3 -3
- package/dist/testing/run-ledger-conformance.js +1 -1
- package/dist/testing/session-store-conformance.js +1 -1
- package/dist/testing/tool-conformance.js +30 -5
- package/dist/thinking.js +4 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +24 -5
- package/docs/0.1.0-readiness.md +139 -0
- package/docs/index.md +3 -1
- package/docs/migration.md +29 -0
- package/docs/performance.md +33 -0
- package/docs/public-contracts.md +1 -1
- package/docs/release-and-install.md +106 -17
- package/package.json +14 -6
- package/docs/review-coverage-2026-07-14.md +0 -260
- package/docs/review-coverage-2026-07-15.md +0 -193
- package/docs/review-coverage-2026-07-17-provider-validation.md +0 -192
- package/docs/review-coverage-2026-07-19-phase-3.md +0 -174
- package/docs/review-coverage-2026-07-20-phase-4.md +0 -175
- package/docs/review-coverage-2026-07-21-phase-5.md +0 -172
- package/docs/review-coverage-2026-07-22-phase-6.md +0 -209
- package/docs/review-coverage-2026-07-22-phase-7.md +0 -173
- package/docs/review-coverage-2026-07-23-phase-8.md +0 -245
- package/docs/review-coverage-2026-07-25-phase-9.md +0 -256
- package/docs/review-coverage-2026-07-26-phase-10.md +0 -132
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.16] - 2026-07-26
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Phase 11 simplification/readiness: new public export `resolveRedactor` from `@arnilo/prism` (single survivor of four private copies across evals/memory/rag/workflows) and a new internal `@arnilo/prism-session-store-codecs` package (shared SQLite/Postgres row codecs, not enrolled in any profile family), bringing the exact graph to **44 publishable manifests**.
|
|
7
|
+
- Offline pre-publish release gates: `npm run release:gate` (API-surface `.d.ts` diff vs `scripts/compat-baseline/`, tarball deny-list, exact version ranges), wired into `npm run sdk:ready`.
|
|
8
|
+
- Performance budgets in `scripts/budgets.json`, enforced by `scripts/budget-gate.test.mjs` (in `npm test`) and `scripts/benchmark-0.0.16.mjs`.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Dropped historical `docs/review-coverage-*.md` from the root tarball (11 files, ~283 KB): packed size 659,478 → ≈575,680 bytes, 281 → 270 files.
|
|
12
|
+
- All six profiles (`prism-all`, `prism-base`, `prism-code`, `prism-compaction`, `prism-providers`, `prism-sdk`) retained on adoption evidence; zero retirements. No runtime behavior changes.
|
|
13
|
+
|
|
3
14
|
## [0.0.15] - 2026-07-26
|
|
4
15
|
|
|
5
16
|
### Added
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAgent } from "./agents.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createSkillRegistry, resolveActiveSkills } from "./skills.js";
|
|
3
3
|
import { createToolRegistry } from "./tools.js";
|
|
4
4
|
/** Resolve an {@link AgentDefinition} into a runnable {@link Agent}.
|
|
5
5
|
*
|
|
@@ -96,8 +96,7 @@ function hasList(value) {
|
|
|
96
96
|
return typeof value === "object" && value !== null && "list" in value && typeof value.list === "function";
|
|
97
97
|
}
|
|
98
98
|
function resolveSkills(names, tools, context) {
|
|
99
|
-
const registry = context.skillsRegistry ??
|
|
100
|
-
(context.registries?.skills ? createSkillRegistry(context.registries.skills.list()) : undefined);
|
|
99
|
+
const registry = context.skillsRegistry ?? (context.registries?.skills ? createSkillRegistry(context.registries.skills.list()) : undefined);
|
|
101
100
|
if (!names && !context.activateAllCapabilities)
|
|
102
101
|
return undefined;
|
|
103
102
|
if (!registry) {
|
package/dist/agent-loops.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { inputMessages } from "./input.js";
|
|
2
1
|
import { createId } from "./ids.js";
|
|
2
|
+
import { inputMessages } from "./input.js";
|
|
3
3
|
import { artifactStructuredOutputRequest, withoutStructuredOutput } from "./structured-output.js";
|
|
4
4
|
function throwIfAborted(signal) {
|
|
5
5
|
if (signal.aborted)
|
|
@@ -8,7 +8,10 @@ function throwIfAborted(signal) {
|
|
|
8
8
|
function toolResultMessage(result) {
|
|
9
9
|
return {
|
|
10
10
|
role: "tool",
|
|
11
|
-
content: [
|
|
11
|
+
content: [
|
|
12
|
+
{ type: "tool_result", toolCallId: result.toolCallId, name: result.name, result: result.value, error: result.error },
|
|
13
|
+
...(result.content ?? []),
|
|
14
|
+
],
|
|
12
15
|
metadata: result.metadata,
|
|
13
16
|
};
|
|
14
17
|
}
|
|
@@ -121,7 +124,11 @@ export function generateValidateReviseLoop(opts) {
|
|
|
121
124
|
continue;
|
|
122
125
|
}
|
|
123
126
|
if (toolRounds >= ctx.maxToolRounds) {
|
|
124
|
-
const result = {
|
|
127
|
+
const result = {
|
|
128
|
+
ok: false,
|
|
129
|
+
errors: [{ message: "maximum tool rounds exceeded" }],
|
|
130
|
+
metadata: { reason: "tool_round_limit" },
|
|
131
|
+
};
|
|
125
132
|
ctx.emit({ type: "artifact_failed", sessionId: ctx.sessionId, runId: ctx.runId, turn, attempt: attempts + 1, result });
|
|
126
133
|
return usage;
|
|
127
134
|
}
|
|
@@ -166,7 +173,7 @@ export function generateValidateReviseLoop(opts) {
|
|
|
166
173
|
: undefined;
|
|
167
174
|
const attempt = ++attempts;
|
|
168
175
|
ctx.emit({ type: "artifact_validation_started", sessionId: ctx.sessionId, runId: ctx.runId, turn, attempt });
|
|
169
|
-
const result = parseFailure ?? await opts.validator(parsed.value, artifactCtx);
|
|
176
|
+
const result = parseFailure ?? (await opts.validator(parsed.value, artifactCtx));
|
|
170
177
|
ctx.emit({ type: "artifact_validation_finished", sessionId: ctx.sessionId, runId: ctx.runId, turn, attempt, result });
|
|
171
178
|
if (result.ok) {
|
|
172
179
|
ctx.emit({ type: "artifact_finished", sessionId: ctx.sessionId, runId: ctx.runId, turn, attempt, result });
|
|
@@ -213,9 +220,7 @@ export async function dispatchToolCallsInOrder(calls, ctx) {
|
|
|
213
220
|
if (calls.length === 0)
|
|
214
221
|
return;
|
|
215
222
|
ctx.chargeToolRound?.(calls);
|
|
216
|
-
const concurrency = calls.some((call) => ctx.isToolCallExclusive?.(call))
|
|
217
|
-
? 1
|
|
218
|
-
: Math.max(1, Math.min(ctx.toolConcurrency, calls.length));
|
|
223
|
+
const concurrency = calls.some((call) => ctx.isToolCallExclusive?.(call)) ? 1 : Math.max(1, Math.min(ctx.toolConcurrency, calls.length));
|
|
219
224
|
if (concurrency === 1) {
|
|
220
225
|
for (const call of calls) {
|
|
221
226
|
const result = await ctx.dispatchToolCall(call);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { Agent, AgentEvent, AgentRunRef, AgentRunResult, AgentRunResume, AgentRunStatusResult, OwnershipScope, SubscribeOptions } from "./contracts.js";
|
|
2
|
-
import type { CheckpointStore } from "./contracts.js";
|
|
1
|
+
import type { Agent, AgentEvent, AgentRunRef, AgentRunResult, AgentRunResume, AgentRunStatusResult, CheckpointStore, OwnershipScope, SubscribeOptions } from "./contracts.js";
|
|
3
2
|
export interface AgentRunLifecycleAgent {
|
|
4
3
|
readonly agent: Agent;
|
|
5
4
|
/** Current host-authored revision; it must match the stored revision. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AgentRunStateError } from "./contracts.js";
|
|
2
1
|
import { loadAgentRunState, publicState } from "./agent-run-state.js";
|
|
3
2
|
import { resumeAgentRun, resumeAgentRunStream } from "./agents.js";
|
|
3
|
+
import { AgentRunStateError } from "./contracts.js";
|
|
4
4
|
function assertAgentId(actual, expected) {
|
|
5
5
|
if (expected !== undefined && actual !== expected)
|
|
6
6
|
throw new AgentRunStateError("Agent run capability mismatch");
|
package/dist/agent-run-state.js
CHANGED
|
@@ -21,7 +21,9 @@ export function agentFingerprint(agent, revision) {
|
|
|
21
21
|
model: config.model,
|
|
22
22
|
tools: tools.map((tool) => ({ name: tool.name, parameters: tool.parameters, exclusive: tool.exclusive })),
|
|
23
23
|
guardrails: guardrails.map((guardrail) => ({ name: guardrail.name, stage: guardrail.stage, revision: guardrail.revision })),
|
|
24
|
-
loop: typeof config.loop === "object" && config.loop && "strategy" in config.loop
|
|
24
|
+
loop: typeof config.loop === "object" && config.loop && "strategy" in config.loop
|
|
25
|
+
? config.loop.strategy
|
|
26
|
+
: (config.loop?.name ?? "single-shot"),
|
|
25
27
|
});
|
|
26
28
|
return createHash("sha256").update(value).digest("hex");
|
|
27
29
|
}
|
|
@@ -43,7 +45,10 @@ export async function loadAgentRunState(checkpoints, ref, ownership) {
|
|
|
43
45
|
const record = await checkpoints.loadCheckpoint({ namespace: AGENT_RUN_STATE_NAMESPACE, key: ref.runId, ...ownership });
|
|
44
46
|
if (!record)
|
|
45
47
|
throw new AgentRunStateError(`No durable agent run ${ref.runId}`);
|
|
46
|
-
if (ref.sessionId &&
|
|
48
|
+
if (ref.sessionId &&
|
|
49
|
+
record.value &&
|
|
50
|
+
typeof record.value === "object" &&
|
|
51
|
+
record.value.sessionId !== ref.sessionId) {
|
|
47
52
|
throw new AgentRunStateError("Agent run session mismatch");
|
|
48
53
|
}
|
|
49
54
|
return { record, state: parseAgentRunState(record.value, record.version) };
|
|
@@ -95,7 +100,15 @@ export function parseAgentRunState(value, version) {
|
|
|
95
100
|
const state = value;
|
|
96
101
|
if (state.schemaVersion !== AGENT_RUN_STATE_SCHEMA_VERSION)
|
|
97
102
|
throw new AgentRunStateError(`Unsupported agent run state schemaVersion ${String(state.schemaVersion)}`);
|
|
98
|
-
if (!state.agentId ||
|
|
103
|
+
if (!state.agentId ||
|
|
104
|
+
!state.definitionRevision ||
|
|
105
|
+
!state.fingerprint ||
|
|
106
|
+
!state.runId ||
|
|
107
|
+
!state.sessionId ||
|
|
108
|
+
!state.model ||
|
|
109
|
+
!state.status ||
|
|
110
|
+
!state.counters ||
|
|
111
|
+
!state.deadlineAt) {
|
|
99
112
|
throw new AgentRunStateError("Malformed agent run state");
|
|
100
113
|
}
|
|
101
114
|
return boundState({ ...state, version }, DEFAULT_MAX_AGENT_RUN_STATE_BYTES);
|
package/dist/agents.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Agent, AgentConfig, AgentEvent, AgentRunResult, AgentRunResume, AgentRunResumeOptions, AgentRunResumeStreamOptions,
|
|
1
|
+
import type { Agent, AgentConfig, AgentEvent, AgentRunRef, AgentRunResult, AgentRunResume, AgentRunResumeOptions, AgentRunResumeStreamOptions, AgentSession, AgentSessionConfig } from "./contracts.js";
|
|
2
2
|
export declare function createAgent(config: AgentConfig): Agent;
|
|
3
3
|
export declare function createAgentSession(config: AgentSessionConfig & {
|
|
4
4
|
readonly agent: Agent;
|
package/dist/agents.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { AgentRunError, AgentRunStateError, DEFAULT_MAX_PENDING_STEER_BYTES, DEFAULT_MAX_PENDING_STEERS, } from "./contracts.js";
|
|
2
1
|
import { resolveLoop, resolveToolConcurrency } from "./agent-loops.js";
|
|
3
|
-
import {
|
|
4
|
-
import { assertGuardrailsAllowed, GuardrailError, runGuardrails } from "./guardrails.js";
|
|
5
|
-
import { createProviderTurnMetadata, readProviderHttpStatus } from "./observability.js";
|
|
2
|
+
import { agentFingerprint, initialAgentRunState, loadAgentRunState, publicState, saveAgentRunState, validateRunStateOptions, } from "./agent-run-state.js";
|
|
6
3
|
import { createDefaultCompactionStrategy, isCompactionEntryData } from "./compaction.js";
|
|
4
|
+
import { AgentRunError, AgentRunStateError, DEFAULT_MAX_PENDING_STEER_BYTES, DEFAULT_MAX_PENDING_STEERS } from "./contracts.js";
|
|
5
|
+
import { assertGuardrailsAllowed, GuardrailError, runGuardrails } from "./guardrails.js";
|
|
6
|
+
import { identityTelemetryAttributes, ownershipFromIdentity, resolveRunIdentity } from "./identity.js";
|
|
7
|
+
import { createId } from "./ids.js";
|
|
7
8
|
import { assembleProviderInput } from "./input.js";
|
|
9
|
+
import { createProviderTurnMetadata, readProviderHttpStatus } from "./observability.js";
|
|
8
10
|
import { providerToolCallDeltaContent, reconstructToolCallDeltas } from "./provider-events.js";
|
|
9
11
|
import { createProviderRequestPolicyChain, normalizeProviderRequestPolicyResult } from "./provider-request-policy.js";
|
|
10
|
-
import {
|
|
11
|
-
import { errorToErrorInfo, redactAgentEvent, redactProviderRequest, redactRunLedgerRecord, redactSecrets, redactSessionEntry } from "./redaction.js";
|
|
12
|
-
import { composeSystemPrompt, mergeSystemPromptConfig } from "./system-prompts.js";
|
|
12
|
+
import { errorToErrorInfo, redactAgentEvent, redactProviderRequest, redactRunLedgerRecord, redactSecrets, redactSessionEntry, } from "./redaction.js";
|
|
13
13
|
import { createDefaultRetryPolicy, waitForRetry } from "./retry.js";
|
|
14
|
-
import { createMemorySessionStore, createSessionEntry, getSessionBranchEntries, rebuildSessionContext } from "./session-stores.js";
|
|
15
14
|
import { isFlushableRunLedger } from "./run-ledger.js";
|
|
16
|
-
import { createToolRegistry, dispatchToolCall } from "./tools.js";
|
|
17
15
|
import { RunLimitError, RunLimitTracker, resolveRunLimits } from "./run-limits.js";
|
|
18
|
-
import {
|
|
16
|
+
import { createMemorySessionStore, createSessionEntry, getSessionBranchEntries, rebuildSessionContext, } from "./session-stores.js";
|
|
19
17
|
import { resolveActiveSkills } from "./skills.js";
|
|
20
|
-
import {
|
|
18
|
+
import { assertStructuredOutputRequestSupported, resolveRunProviderOptions } from "./structured-output.js";
|
|
19
|
+
import { composeSystemPrompt, mergeSystemPromptConfig } from "./system-prompts.js";
|
|
20
|
+
import { createToolRegistry, dispatchToolCall } from "./tools.js";
|
|
21
21
|
export function createAgent(config) {
|
|
22
22
|
return {
|
|
23
23
|
config,
|
|
@@ -39,7 +39,9 @@ export async function* resumeAgentRunStream(agent, ref, resume, options) {
|
|
|
39
39
|
const prepared = await prepareAgentRunResume(agent, ref, resume, options, options.signal);
|
|
40
40
|
const subscription = prepared.session.subscribe(options);
|
|
41
41
|
let settled = false;
|
|
42
|
-
const runPromise = executePreparedAgentRunResume(prepared, options.signal).finally(() => {
|
|
42
|
+
const runPromise = executePreparedAgentRunResume(prepared, options.signal).finally(() => {
|
|
43
|
+
settled = true;
|
|
44
|
+
});
|
|
43
45
|
try {
|
|
44
46
|
for await (const event of subscription) {
|
|
45
47
|
if ("runId" in event && event.runId !== ref.runId)
|
|
@@ -58,7 +60,9 @@ export async function* resumeAgentRunStream(agent, ref, resume, options) {
|
|
|
58
60
|
async function prepareAgentRunResume(agent, ref, resume, options, signal) {
|
|
59
61
|
throwIfAbortedSignal(signal);
|
|
60
62
|
const { record, state } = await loadAgentRunState(options.checkpoints, ref, options.ownership);
|
|
61
|
-
if (state.definitionRevision !== options.definitionRevision ||
|
|
63
|
+
if (state.definitionRevision !== options.definitionRevision ||
|
|
64
|
+
state.agentId !== (agent.config.id ?? agent.config.name) ||
|
|
65
|
+
state.fingerprint !== agentFingerprint(agent, options.definitionRevision)) {
|
|
62
66
|
throw new AgentRunStateError("Agent definition revision or fingerprint mismatch on resume");
|
|
63
67
|
}
|
|
64
68
|
if (record.version !== resume.expectedVersion || state.status !== "suspended") {
|
|
@@ -211,7 +215,11 @@ class RuntimeAgentSession {
|
|
|
211
215
|
}
|
|
212
216
|
}
|
|
213
217
|
async resumeDurable(state, runState, ownership, signal) {
|
|
214
|
-
return this.runInternal(state.input ?? [], { runState, ownership, signal }, state.runId, {
|
|
218
|
+
return this.runInternal(state.input ?? [], { runState, ownership, signal }, state.runId, {
|
|
219
|
+
options: runState,
|
|
220
|
+
state,
|
|
221
|
+
version: state.version,
|
|
222
|
+
});
|
|
215
223
|
}
|
|
216
224
|
async recordDurableDenial(runId, interruption, version, ownership) {
|
|
217
225
|
this.activeLedger = this.agent.config.runLedger;
|
|
@@ -229,7 +237,11 @@ class RuntimeAgentSession {
|
|
|
229
237
|
}
|
|
230
238
|
}
|
|
231
239
|
async runInternal(input, options, runId, resumed) {
|
|
232
|
-
if (this.agent.config.secure &&
|
|
240
|
+
if (this.agent.config.secure &&
|
|
241
|
+
(options.redactor !== undefined ||
|
|
242
|
+
options.ownership !== undefined ||
|
|
243
|
+
options.validate !== undefined ||
|
|
244
|
+
options.runState !== undefined)) {
|
|
233
245
|
throw new AgentRunStateError("Secure agent defaults cannot be replaced per run");
|
|
234
246
|
}
|
|
235
247
|
const requestedLimits = options.maxToolRounds === undefined
|
|
@@ -316,7 +328,14 @@ class RuntimeAgentSession {
|
|
|
316
328
|
const { registry, tools } = activeTools(this.agent.config.tools);
|
|
317
329
|
const activeSkills = this.resolveRunSkills(options, tools);
|
|
318
330
|
if (options.model && JSON.stringify(options.model) !== JSON.stringify(this.agent.config.model)) {
|
|
319
|
-
await this.appendEntry(createSessionEntry({
|
|
331
|
+
await this.appendEntry(createSessionEntry({
|
|
332
|
+
sessionId: this.id,
|
|
333
|
+
parentId: this.currentLeafId,
|
|
334
|
+
runId,
|
|
335
|
+
kind: "model_change",
|
|
336
|
+
previousModel: this.agent.config.model,
|
|
337
|
+
model: options.model,
|
|
338
|
+
}));
|
|
320
339
|
}
|
|
321
340
|
const inputMessages = inputToMessages(input).map((message) => this.redact(message));
|
|
322
341
|
const inputGuardrails = await runGuardrails({
|
|
@@ -340,7 +359,9 @@ class RuntimeAgentSession {
|
|
|
340
359
|
await this.appendMessage(message, runId);
|
|
341
360
|
await this.autoCompact(runId, options, controller.signal, inputMessages);
|
|
342
361
|
const maxToolRounds = resolvedLimits.maxToolRounds;
|
|
343
|
-
const systemInstructions = composeSystemPrompt(mergeSystemPromptConfig(this.agent.config.systemPrompt, options.systemPrompt), {
|
|
362
|
+
const systemInstructions = composeSystemPrompt(mergeSystemPromptConfig(this.agent.config.systemPrompt, options.systemPrompt), {
|
|
363
|
+
base: this.agent.config.instructions,
|
|
364
|
+
});
|
|
344
365
|
const contextProviders = [
|
|
345
366
|
...(this.agent.config.context ?? []),
|
|
346
367
|
// ponytail: skill context after host context; no per-skill token budget yet.
|
|
@@ -429,7 +450,7 @@ class RuntimeAgentSession {
|
|
|
429
450
|
limits.charge("maxTurns");
|
|
430
451
|
assembledTurn = false;
|
|
431
452
|
const policyResult = await this.applyProviderRequestPolicies(request, runId, options, metadata, controller.signal);
|
|
432
|
-
const middlewareRequest = await this.agent.config.middleware?.run("provider_request", policyResult.request) ?? policyResult.request;
|
|
453
|
+
const middlewareRequest = (await this.agent.config.middleware?.run("provider_request", policyResult.request)) ?? policyResult.request;
|
|
433
454
|
try {
|
|
434
455
|
return await this.generateWithRetry(this.redactProviderRequest(middlewareRequest), runId, options, controller.signal, policyResult.secrets, this.activeLoopTurn, recordProviderUsage);
|
|
435
456
|
}
|
|
@@ -468,12 +489,22 @@ class RuntimeAgentSession {
|
|
|
468
489
|
return;
|
|
469
490
|
const pending = durable.state?.pending;
|
|
470
491
|
if (pending?.call.id === mediatedCall.id && pending.status === "ready") {
|
|
471
|
-
await this.persistDurable({
|
|
492
|
+
await this.persistDurable({
|
|
493
|
+
...durable.state,
|
|
494
|
+
status: "running",
|
|
495
|
+
pending: { ...pending, status: "dispatched" },
|
|
496
|
+
interruption: undefined,
|
|
497
|
+
});
|
|
472
498
|
return;
|
|
473
499
|
}
|
|
474
500
|
if (!durable.options.interruptBeforeTool)
|
|
475
501
|
return;
|
|
476
|
-
const interruption = {
|
|
502
|
+
const interruption = {
|
|
503
|
+
kind: "tool_approval",
|
|
504
|
+
reason: "Tool side effect requires approval",
|
|
505
|
+
toolCallId: mediatedCall.id,
|
|
506
|
+
toolName: mediatedCall.name,
|
|
507
|
+
};
|
|
477
508
|
throw new AgentRunSuspended(await this.suspendDurable({
|
|
478
509
|
runId,
|
|
479
510
|
model,
|
|
@@ -508,13 +539,19 @@ class RuntimeAgentSession {
|
|
|
508
539
|
const result = await ctx.dispatchToolCall(resumed.state.pending.call);
|
|
509
540
|
await ctx.appendMessage({
|
|
510
541
|
role: "tool",
|
|
511
|
-
content: [
|
|
542
|
+
content: [
|
|
543
|
+
{ type: "tool_result", toolCallId: result.toolCallId, name: result.name, result: result.value, error: result.error },
|
|
544
|
+
...(result.content ?? []),
|
|
545
|
+
],
|
|
512
546
|
metadata: result.metadata,
|
|
513
547
|
});
|
|
514
548
|
}
|
|
515
549
|
const loopUsage = await loop.run(ctx);
|
|
516
550
|
if (loop.name === "generate-validate-revise" && !artifactFinished) {
|
|
517
|
-
throw Object.assign(new Error(artifactFailedInfo?.message ?? "artifact loop ended without a validated artifact"), {
|
|
551
|
+
throw Object.assign(new Error(artifactFailedInfo?.message ?? "artifact loop ended without a validated artifact"), {
|
|
552
|
+
name: "ArtifactFailed",
|
|
553
|
+
code: artifactFailedInfo?.code ?? "artifact_failed",
|
|
554
|
+
});
|
|
518
555
|
}
|
|
519
556
|
usage = runUsage.value() ?? loopUsage;
|
|
520
557
|
if (usage && this.activeLedger) {
|
|
@@ -661,21 +698,22 @@ class RuntimeAgentSession {
|
|
|
661
698
|
const durable = this.activeDurable;
|
|
662
699
|
if (!durable)
|
|
663
700
|
throw new AgentRunStateError("Durable interruption is not configured");
|
|
664
|
-
const state = durable.state ??
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
701
|
+
const state = durable.state ??
|
|
702
|
+
initialAgentRunState({
|
|
703
|
+
agent: this.agent,
|
|
704
|
+
options: durable.options,
|
|
705
|
+
runId: input.runId,
|
|
706
|
+
sessionId: this.id,
|
|
707
|
+
leafId: this.currentLeafId,
|
|
708
|
+
model: input.model,
|
|
709
|
+
counters: input.limits.snapshot(),
|
|
710
|
+
deadlineAt: input.limits.deadlineAt,
|
|
711
|
+
status: "suspended",
|
|
712
|
+
interruption: input.interruption,
|
|
713
|
+
messages: input.messages,
|
|
714
|
+
pending: input.pending,
|
|
715
|
+
interruptBeforeTool: durable.options.interruptBeforeTool,
|
|
716
|
+
});
|
|
679
717
|
return this.persistDurable({
|
|
680
718
|
...state,
|
|
681
719
|
leafId: this.currentLeafId,
|
|
@@ -723,7 +761,13 @@ class RuntimeAgentSession {
|
|
|
723
761
|
await this.rebuildHistory();
|
|
724
762
|
}
|
|
725
763
|
fork(options = {}) {
|
|
726
|
-
return createAgentSession({
|
|
764
|
+
return createAgentSession({
|
|
765
|
+
agent: this.agent,
|
|
766
|
+
id: this.id,
|
|
767
|
+
store: this.store,
|
|
768
|
+
leafId: options.leafId ?? this.currentLeafId,
|
|
769
|
+
metadata: this.metadata,
|
|
770
|
+
});
|
|
727
771
|
}
|
|
728
772
|
async clone(options = {}) {
|
|
729
773
|
const id = options.id ?? randomId("session");
|
|
@@ -739,7 +783,13 @@ class RuntimeAgentSession {
|
|
|
739
783
|
const { id: _oldId, parentId: _oldParentId, sessionId: _oldSessionId, ...rest } = entry;
|
|
740
784
|
await this.store.append({ ...rest, id: nextId, parentId: entry.parentId ? remap.get(entry.parentId) : undefined, sessionId: id });
|
|
741
785
|
}
|
|
742
|
-
return createAgentSession({
|
|
786
|
+
return createAgentSession({
|
|
787
|
+
agent: this.agent,
|
|
788
|
+
id,
|
|
789
|
+
store: this.store,
|
|
790
|
+
leafId: branch.length ? remap.get(branch[branch.length - 1].id) : undefined,
|
|
791
|
+
metadata: this.metadata,
|
|
792
|
+
});
|
|
743
793
|
}
|
|
744
794
|
branchReader() {
|
|
745
795
|
// ponytail: prefer the store's readBranchPath (one ancestor-chain query) when present so a
|
|
@@ -753,9 +803,7 @@ class RuntimeAgentSession {
|
|
|
753
803
|
// the resolver entirely; otherwise `RunOptions.providerSource` overrides
|
|
754
804
|
// `AgentConfig.providerSource` for this run. A miss on every source fails
|
|
755
805
|
// closed with `Unknown provider: ${model.provider}` before any provider turn.
|
|
756
|
-
const provider = this.agent.config.provider ??
|
|
757
|
-
options.providerSource?.(model) ??
|
|
758
|
-
this.agent.config.providerSource?.(model);
|
|
806
|
+
const provider = this.agent.config.provider ?? options.providerSource?.(model) ?? this.agent.config.providerSource?.(model);
|
|
759
807
|
if (!provider)
|
|
760
808
|
throw new Error(`Unknown provider: ${model.provider}`);
|
|
761
809
|
this.activeProvider = provider;
|
|
@@ -828,7 +876,10 @@ class RuntimeAgentSession {
|
|
|
828
876
|
throw errorFromInfo(info);
|
|
829
877
|
const context = { sessionId: this.id, runId, attempt, error: info, metadata: retry?.metadata, signal };
|
|
830
878
|
let decision = await policy.decide(context);
|
|
831
|
-
const payload = await this.agent.config.middleware?.run("retry", { context, decision }) ?? {
|
|
879
|
+
const payload = (await this.agent.config.middleware?.run("retry", { context, decision })) ?? {
|
|
880
|
+
context,
|
|
881
|
+
decision,
|
|
882
|
+
};
|
|
832
883
|
decision = payload.decision;
|
|
833
884
|
if (!decision.retry)
|
|
834
885
|
throw errorFromInfo(info);
|
|
@@ -1029,16 +1080,35 @@ class RuntimeAgentSession {
|
|
|
1029
1080
|
throwIfAbortedSignal(signal);
|
|
1030
1081
|
const entries = await this.entries();
|
|
1031
1082
|
const secrets = options.secrets ?? [];
|
|
1032
|
-
const strategy = options.strategy ??
|
|
1033
|
-
|
|
1083
|
+
const strategy = options.strategy ??
|
|
1084
|
+
createDefaultCompactionStrategy({ keepRecentEntries: options.keepRecentEntries, maxSummaryChars: options.maxSummaryChars, secrets });
|
|
1085
|
+
const context = {
|
|
1086
|
+
sessionId: this.id,
|
|
1087
|
+
entries,
|
|
1088
|
+
keepRecentEntries: options.keepRecentEntries,
|
|
1089
|
+
trigger,
|
|
1090
|
+
secrets,
|
|
1091
|
+
metadata: options.metadata,
|
|
1092
|
+
signal,
|
|
1093
|
+
};
|
|
1034
1094
|
this.emit({ type: "compaction_started", sessionId: this.id, runId });
|
|
1035
1095
|
let result = await strategy.compact(context);
|
|
1036
1096
|
result = { ...result, summary: redactSecrets(result.summary, secrets) };
|
|
1037
|
-
const payload = await this.agent.config.middleware?.run("compaction", { context, result }) ?? {
|
|
1097
|
+
const payload = (await this.agent.config.middleware?.run("compaction", { context, result })) ?? {
|
|
1098
|
+
context,
|
|
1099
|
+
result,
|
|
1100
|
+
};
|
|
1038
1101
|
result = { ...payload.result, summary: redactSecrets(payload.result.summary, secrets) };
|
|
1039
1102
|
const source = result.entries?.find((entry) => entry.kind === "compaction");
|
|
1040
1103
|
const data = isCompactionEntryData(source?.data) ? source.data : undefined;
|
|
1041
|
-
const entry = createSessionEntry({
|
|
1104
|
+
const entry = createSessionEntry({
|
|
1105
|
+
sessionId: this.id,
|
|
1106
|
+
parentId: this.currentLeafId,
|
|
1107
|
+
runId,
|
|
1108
|
+
kind: "compaction",
|
|
1109
|
+
summary: result.summary,
|
|
1110
|
+
data,
|
|
1111
|
+
});
|
|
1042
1112
|
await this.appendEntry(entry);
|
|
1043
1113
|
const finalResult = { ...result, entries: [entry] };
|
|
1044
1114
|
this.emit({ type: "compaction_finished", sessionId: this.id, runId, summary: finalResult.summary });
|
|
@@ -1181,8 +1251,8 @@ class SteerSoftInterrupt extends Error {
|
|
|
1181
1251
|
}
|
|
1182
1252
|
}
|
|
1183
1253
|
function isSteerSoftInterrupt(error) {
|
|
1184
|
-
return error instanceof SteerSoftInterrupt
|
|
1185
|
-
|
|
1254
|
+
return (error instanceof SteerSoftInterrupt ||
|
|
1255
|
+
(typeof error === "object" && error !== null && error.code === STEER_SOFT_INTERRUPT_CODE));
|
|
1186
1256
|
}
|
|
1187
1257
|
function finalAssistantMessage(history) {
|
|
1188
1258
|
for (let index = history.length - 1; index >= 0; index -= 1) {
|
|
@@ -1295,8 +1365,8 @@ function createUsageAccumulator() {
|
|
|
1295
1365
|
if (value !== undefined)
|
|
1296
1366
|
sums.set(key, (sums.get(key) ?? 0) + value);
|
|
1297
1367
|
}
|
|
1298
|
-
const total = usage.totalTokens
|
|
1299
|
-
|
|
1368
|
+
const total = usage.totalTokens ??
|
|
1369
|
+
(usage.inputTokens !== undefined || usage.outputTokens !== undefined
|
|
1300
1370
|
? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
|
|
1301
1371
|
: undefined);
|
|
1302
1372
|
if (total !== undefined)
|
package/dist/cache-helpers.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export function sanitizeCacheKey(value, maxLength) {
|
|
2
|
-
const key = value
|
|
2
|
+
const key = value
|
|
3
|
+
?.replace(/[^A-Za-z0-9_.:-]+/g, "-")
|
|
4
|
+
.replace(/^-+|-+$/g, "")
|
|
5
|
+
.slice(0, Math.max(0, maxLength));
|
|
3
6
|
return key || undefined;
|
|
4
7
|
}
|
|
5
8
|
export function mapCacheRetention(retention, model) {
|
|
@@ -37,7 +40,7 @@ export function cacheSavings(usage, model) {
|
|
|
37
40
|
const cacheRead = model.cost?.cacheRead;
|
|
38
41
|
if (read === undefined || input === undefined || cacheRead === undefined)
|
|
39
42
|
return undefined;
|
|
40
|
-
return read * Math.max(0, input - cacheRead) / costUnitDivisor(model.cost?.unit);
|
|
43
|
+
return (read * Math.max(0, input - cacheRead)) / costUnitDivisor(model.cost?.unit);
|
|
41
44
|
}
|
|
42
45
|
export function cacheUsageReport(usage, model) {
|
|
43
46
|
if (!usage)
|
|
@@ -48,17 +51,23 @@ export function cacheUsageReport(usage, model) {
|
|
|
48
51
|
cacheWriteTokens: usage.cacheWriteTokens ?? 0,
|
|
49
52
|
hitRate: cacheHitRate(usage),
|
|
50
53
|
estimatedSavings,
|
|
51
|
-
currency: estimatedSavings === undefined ? usage.currency : model?.cost?.currency ?? usage.currency,
|
|
54
|
+
currency: estimatedSavings === undefined ? usage.currency : (model?.cost?.currency ?? usage.currency),
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
function resolveBreakpoint(messages, breakpoint) {
|
|
55
58
|
switch (breakpoint.location) {
|
|
56
|
-
case "system_prompt":
|
|
57
|
-
|
|
58
|
-
case "
|
|
59
|
-
|
|
60
|
-
case "
|
|
61
|
-
|
|
59
|
+
case "system_prompt":
|
|
60
|
+
return messages.findIndex((message) => message.role === "system");
|
|
61
|
+
case "tools":
|
|
62
|
+
return messages.findIndex((message) => message.role === "tool" || message.content.some((block) => block.type === "tool_call" || block.type === "tool_result"));
|
|
63
|
+
case "stable_context":
|
|
64
|
+
return messages.findIndex((message) => message.role !== "system");
|
|
65
|
+
case "last_stable_message":
|
|
66
|
+
return messages.length > 1 ? messages.length - 2 : messages.length - 1;
|
|
67
|
+
case "last_user_message":
|
|
68
|
+
return findLastIndex(messages, (message) => message.role === "user");
|
|
69
|
+
case "message_id":
|
|
70
|
+
return messages.findIndex((message) => message.id === breakpoint.messageId);
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
function findLastIndex(items, predicate) {
|
package/dist/checkpoints.js
CHANGED
|
@@ -61,9 +61,7 @@ export function createMemoryCheckpointStore(options = {}) {
|
|
|
61
61
|
throwIfAborted(query.signal);
|
|
62
62
|
const offset = decodeCursor(query.cursor);
|
|
63
63
|
const limit = Math.min(Math.max(1, query.limit ?? 100), maxPageSize);
|
|
64
|
-
const categories = query.category === undefined
|
|
65
|
-
? undefined
|
|
66
|
-
: new Set(Array.isArray(query.category) ? query.category : [query.category]);
|
|
64
|
+
const categories = query.category === undefined ? undefined : new Set(Array.isArray(query.category) ? query.category : [query.category]);
|
|
67
65
|
const items = [...records.values()]
|
|
68
66
|
.filter((record) => query.namespace === undefined || record.namespace === query.namespace)
|
|
69
67
|
.filter((record) => query.keyPrefix === undefined || record.key.startsWith(query.keyPrefix))
|
|
@@ -104,14 +102,12 @@ function ownership(input) {
|
|
|
104
102
|
};
|
|
105
103
|
}
|
|
106
104
|
function ownershipMatches(expected, actual) {
|
|
107
|
-
return expected.tenantId === actual.tenantId
|
|
108
|
-
&& expected.accountId === actual.accountId
|
|
109
|
-
&& expected.userId === actual.userId;
|
|
105
|
+
return expected.tenantId === actual.tenantId && expected.accountId === actual.accountId && expected.userId === actual.userId;
|
|
110
106
|
}
|
|
111
107
|
function ownershipFilterMatches(expected, actual) {
|
|
112
|
-
return (expected.tenantId === undefined || expected.tenantId === actual.tenantId)
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
return ((expected.tenantId === undefined || expected.tenantId === actual.tenantId) &&
|
|
109
|
+
(expected.accountId === undefined || expected.accountId === actual.accountId) &&
|
|
110
|
+
(expected.userId === undefined || expected.userId === actual.userId));
|
|
115
111
|
}
|
|
116
112
|
function assertOwnership(expected, actual) {
|
|
117
113
|
if (!ownershipMatches(expected, actual)) {
|
package/dist/cli-init.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { access, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
1
|
import { constants as fsConstants, readFileSync } from "node:fs";
|
|
2
|
+
import { access, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
export class InitUsageError extends Error {
|
|
@@ -305,12 +305,8 @@ function buildTokens(input) {
|
|
|
305
305
|
? `2. Copy \`.env.example\` to \`.env\` and set \`${input.provider.envKey}\`.\n3. Run \`npm start\` for a live provider call.`
|
|
306
306
|
: `2. Run \`npm start\` (mock provider; no network or credentials).`;
|
|
307
307
|
const optionalDocs = [
|
|
308
|
-
...(input.withWorkflows
|
|
309
|
-
|
|
310
|
-
: []),
|
|
311
|
-
...(input.withEvals
|
|
312
|
-
? ["- `src/evals-example.ts` — deterministic scorer example using `@arnilo/prism-evals`."]
|
|
313
|
-
: []),
|
|
308
|
+
...(input.withWorkflows ? ["- `src/workflows-example.ts` — tiny DAG example using `@arnilo/prism-workflows`."] : []),
|
|
309
|
+
...(input.withEvals ? ["- `src/evals-example.ts` — deterministic scorer example using `@arnilo/prism-evals`."] : []),
|
|
314
310
|
].join("\n");
|
|
315
311
|
return {
|
|
316
312
|
__PROJECT_NAME__: input.projectName,
|
package/dist/cli-runner.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface CliOptions {
|
|
|
46
46
|
readonly agentsMdFile?: string;
|
|
47
47
|
readonly systemMdFile?: string;
|
|
48
48
|
/** Runtime-populated: AGENTS.md/SYSTEM.md layers loaded from disk (print/json modes only;
|
|
49
|
-
|
|
49
|
+
* RPC is host-owned). Threaded into `AgentConfig.systemPrompt` by `defaultCreateSession`. */
|
|
50
50
|
readonly systemPromptLayers: readonly SystemPromptContribution[];
|
|
51
51
|
}
|
|
52
52
|
export interface CliRuntime {
|