@arnilo/prism 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -1
- package/README.md +23 -20
- package/dist/agent-run-state.d.ts +1 -2
- package/dist/agent-run-state.js +0 -3
- package/dist/agent-session/session/assemble.d.ts +6 -0
- package/dist/agent-session/session/assemble.js +391 -0
- package/dist/agent-session/session/persist.d.ts +28 -0
- package/dist/agent-session/session/persist.js +166 -0
- package/dist/agent-session/session/provider-round.d.ts +6 -0
- package/dist/agent-session/session/provider-round.js +231 -0
- package/dist/agent-session/session/tool-round.d.ts +31 -0
- package/dist/agent-session/session/tool-round.js +473 -0
- package/dist/agent-session/session/types.d.ts +115 -0
- package/dist/agent-session/session/types.js +5 -0
- package/dist/agent-session/session.d.ts +49 -43
- package/dist/agent-session/session.js +11 -1177
- package/dist/capture.d.ts +63 -0
- package/dist/capture.js +67 -0
- package/dist/cli-init.d.ts +18 -2
- package/dist/cli-init.js +2 -7
- package/dist/cli-runner.d.ts +2 -2
- package/dist/cli-runner.js +45 -9
- package/dist/content.d.ts +3 -3
- package/dist/content.js +3 -1
- package/dist/contracts-core/agent.d.ts +2 -0
- package/dist/contracts-core/batch.d.ts +97 -0
- package/dist/contracts-core/batch.js +65 -0
- package/dist/contracts-core/content.d.ts +72 -1
- package/dist/contracts-core/embeddings.d.ts +30 -0
- package/dist/contracts-core/embeddings.js +17 -0
- package/dist/contracts-core/images.d.ts +60 -0
- package/dist/contracts-core/images.js +17 -0
- package/dist/contracts-core/moderation.d.ts +46 -0
- package/dist/contracts-core/moderation.js +34 -0
- package/dist/contracts-core/speech.d.ts +39 -0
- package/dist/contracts-core/speech.js +17 -0
- package/dist/contracts-core/transcription.d.ts +48 -0
- package/dist/contracts-core/transcription.js +17 -0
- package/dist/contracts-core/video.d.ts +61 -0
- package/dist/contracts-core/video.js +17 -0
- package/dist/contracts-core.d.ts +7 -0
- package/dist/contracts-core.js +7 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -3
- package/dist/node/agent-definitions.d.ts +1 -8
- package/dist/node/agent-definitions.js +0 -34
- package/dist/node/settings.d.ts +0 -1
- package/dist/node/settings.js +0 -5
- package/dist/pinned-fetch.js +29 -3
- package/dist/provider-events.js +3 -4
- package/dist/providers/media.d.ts +1 -2
- package/dist/providers/media.js +1 -4
- package/dist/rpc.d.ts +1 -1
- package/dist/rpc.js +4 -4
- package/dist/testing/provider-conformance.d.ts +114 -5
- package/dist/testing/provider-conformance.js +342 -0
- package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
- package/dist/testing/tool-effect-store-conformance.js +0 -3
- package/dist/thinking.d.ts +48 -9
- package/dist/thinking.js +134 -8
- package/docs/0.1.0-readiness.md +3 -3
- package/docs/a2a.md +2 -2
- package/docs/acp.md +3 -3
- package/docs/ag-ui-adoption.md +1 -1
- package/docs/ag-ui.md +1 -2
- package/docs/agent-definitions.md +1 -1
- package/docs/agent-events.md +5 -5
- package/docs/agent-identity.md +13 -2
- package/docs/audit-export.md +3 -3
- package/docs/batch-jobs.md +120 -0
- package/docs/cli-rpc.md +20 -9
- package/docs/coding-agent-tools.md +19 -19
- package/docs/coding-review-and-diagnostics.md +2 -2
- package/docs/coding-security.md +4 -4
- package/docs/coding-workspaces.md +2 -2
- package/docs/computer-use-linux.md +13 -2
- package/docs/context-and-skills.md +1 -1
- package/docs/conversations.md +4 -4
- package/docs/credential-storage.md +11 -7
- package/docs/credentials-and-redaction.md +1 -1
- package/docs/data-classification.md +1 -1
- package/docs/database-persistence.md +4 -4
- package/docs/dev-inspector.md +6 -6
- package/docs/device-adapters.md +2 -2
- package/docs/diagrams.md +1 -1
- package/docs/document-reader.md +6 -6
- package/docs/documents.md +5 -4
- package/docs/embeddings.md +112 -0
- package/docs/enterprise-postgres-state.md +7 -7
- package/docs/evaluations.md +8 -8
- package/docs/extensions.md +3 -3
- package/docs/forge-integration.md +3 -3
- package/docs/graft.md +2 -2
- package/docs/guardrails.md +1 -1
- package/docs/host-security.md +15 -15
- package/docs/image-generation.md +129 -0
- package/docs/impeccable.md +5 -3
- package/docs/index.md +60 -33
- package/docs/indexed-code-search.md +2 -2
- package/docs/language-intelligence.md +4 -4
- package/docs/live-testing.md +126 -0
- package/docs/mcp-tools.md +43 -12
- package/docs/middleware-hooks.md +1 -1
- package/docs/migrate-to-0.4.md +3 -3
- package/docs/migrate-to-0.5.md +122 -0
- package/docs/migration.md +29 -1
- package/docs/model-registry.md +38 -0
- package/docs/model-routing.md +5 -5
- package/docs/moderation.md +117 -0
- package/docs/multi-agent-patterns.md +4 -4
- package/docs/multimodal-content.md +26 -2
- package/docs/obscura.md +2 -2
- package/docs/observability.md +32 -7
- package/docs/openapi-tools.md +13 -3
- package/docs/operations.md +11 -0
- package/docs/performance.md +7 -7
- package/docs/persistence-credentials-multimodality-primitives.md +6 -6
- package/docs/policy-and-audit.md +17 -7
- package/docs/ponytail.md +1 -1
- package/docs/postgres-persistence.md +5 -5
- package/docs/process-sessions.md +2 -2
- package/docs/prompt-registry.md +7 -7
- package/docs/provider-caching.md +4 -0
- package/docs/provider-conformance.md +23 -1
- package/docs/provider-packages.md +39 -3
- package/docs/provider-primitives.md +1 -1
- package/docs/provider-request-policies.md +1 -1
- package/docs/providers/ai-sdk.md +15 -3
- package/docs/providers/alibaba.md +5 -1
- package/docs/providers/anthropic.md +4 -0
- package/docs/providers/azure.md +17 -1
- package/docs/providers/bedrock.md +15 -0
- package/docs/providers/clinepass.md +4 -0
- package/docs/providers/commandcode.md +253 -0
- package/docs/providers/deepseek.md +4 -0
- package/docs/providers/google.md +4 -0
- package/docs/providers/hyper.md +284 -0
- package/docs/providers/kimi.md +4 -0
- package/docs/providers/neuralwatt.md +4 -0
- package/docs/providers/ollama.md +15 -0
- package/docs/providers/openai-compatible.md +4 -0
- package/docs/providers/openai.md +4 -0
- package/docs/providers/opencode-go.md +4 -0
- package/docs/providers/openrouter.md +5 -1
- package/docs/providers/vertex.md +16 -0
- package/docs/providers/xai.md +4 -0
- package/docs/providers/zai.md +4 -0
- package/docs/rag.md +26 -4
- package/docs/release-and-install.md +103 -46
- package/docs/resource-loading.md +1 -1
- package/docs/runs-and-usage.md +14 -2
- package/docs/server.md +5 -5
- package/docs/settings-auth-trust-security.md +7 -5
- package/docs/sheets.md +2 -2
- package/docs/speech.md +126 -0
- package/docs/sqlite-persistence.md +4 -4
- package/docs/supervisors.md +3 -3
- package/docs/thinking-and-reasoning.md +93 -60
- package/docs/tool-conformance.md +1 -1
- package/docs/tool-execution-primitives.md +8 -8
- package/docs/tools.md +4 -4
- package/docs/web-tools.md +1 -1
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +17 -6
- package/docs/work-connectors.md +4 -4
- package/docs/work-tools.md +5 -5
- package/docs/workflow-orchestration-primitives.md +11 -11
- package/docs/workflows.md +5 -5
- package/package.json +11 -8
- package/templates/init/providers.json +24 -8
- package/docs/antigravity-agent.md +0 -207
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/** Finalize/persist phase of runInternal (plan 059). */
|
|
2
|
+
import { boundedLoopSnapshot, initialAgentRunState, publicState, saveAgentRunState } from "../../agent-run-state.js";
|
|
3
|
+
import { AgentRunStateError } from "../../contracts.js";
|
|
4
|
+
import { redactRunLedgerRecord } from "../../redaction.js";
|
|
5
|
+
import { isFlushableRunLedger } from "../../run-ledger.js";
|
|
6
|
+
import { snapshotLoadedSkillBodies } from "../../skill-load.js";
|
|
7
|
+
import { randomId } from "../helpers.js";
|
|
8
|
+
export async function persistDurable(session, state) {
|
|
9
|
+
const durable = session.activeDurable;
|
|
10
|
+
if (!durable)
|
|
11
|
+
throw new AgentRunStateError("Durable run state is not configured");
|
|
12
|
+
const persisted = durable.options.persistSessionState
|
|
13
|
+
? {
|
|
14
|
+
...state,
|
|
15
|
+
sessionState: {
|
|
16
|
+
loadedSkillNames: session.loadedSkills.list(),
|
|
17
|
+
...(session.activatedTools.list().length ? { activatedToolNames: session.activatedTools.list() } : {}),
|
|
18
|
+
...(durable.options.includeSkillBodies
|
|
19
|
+
? {
|
|
20
|
+
loadedSkillBodies: snapshotLoadedSkillBodies(session.activeRunSkills, session.loadedSkills, session.restoredSkillBodies.length
|
|
21
|
+
? new Map(session.restoredSkillBodies.map((e) => [e.name, e.instructions]))
|
|
22
|
+
: undefined),
|
|
23
|
+
}
|
|
24
|
+
: {}),
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
: state;
|
|
28
|
+
const saved = await saveAgentRunState({
|
|
29
|
+
checkpoints: durable.options.checkpoints,
|
|
30
|
+
state: persisted,
|
|
31
|
+
expectedVersion: durable.version,
|
|
32
|
+
ownership: session.activeOwnership,
|
|
33
|
+
fencingToken: durable.options.fencingToken,
|
|
34
|
+
redactor: session.activeRedactor,
|
|
35
|
+
maxStateBytes: durable.options.maxStateBytes,
|
|
36
|
+
});
|
|
37
|
+
durable.state = saved.state;
|
|
38
|
+
durable.version = saved.record.version;
|
|
39
|
+
return publicState(saved.state);
|
|
40
|
+
}
|
|
41
|
+
export async function suspendDurable(session, input) {
|
|
42
|
+
const durable = session.activeDurable;
|
|
43
|
+
if (!durable)
|
|
44
|
+
throw new AgentRunStateError("Durable interruption is not configured");
|
|
45
|
+
const loop = session.activeLoop;
|
|
46
|
+
const loopState = loop?.snapshot ? boundedLoopSnapshot(loop.name, loop.revision ?? "1", loop.snapshot()) : undefined;
|
|
47
|
+
const state = durable.state ??
|
|
48
|
+
initialAgentRunState({
|
|
49
|
+
agent: session.agent,
|
|
50
|
+
options: durable.options,
|
|
51
|
+
runId: input.runId,
|
|
52
|
+
sessionId: session.id,
|
|
53
|
+
leafId: session.currentLeafId,
|
|
54
|
+
model: input.model,
|
|
55
|
+
counters: input.limits.snapshot(),
|
|
56
|
+
deadlineAt: input.limits.deadlineAt,
|
|
57
|
+
status: "suspended",
|
|
58
|
+
interruption: input.interruption,
|
|
59
|
+
messages: input.messages,
|
|
60
|
+
pending: input.pending,
|
|
61
|
+
pendingCalls: input.pendingCalls,
|
|
62
|
+
interruptBeforeTool: durable.options.interruptBeforeTool,
|
|
63
|
+
});
|
|
64
|
+
return persistDurable(session, {
|
|
65
|
+
...state,
|
|
66
|
+
leafId: session.currentLeafId,
|
|
67
|
+
status: "suspended",
|
|
68
|
+
interruption: input.interruption,
|
|
69
|
+
...(input.messages ? { input: input.messages } : {}),
|
|
70
|
+
...(input.pending ? { pending: input.pending } : {}),
|
|
71
|
+
...(input.pendingCalls ? { pendingCalls: input.pendingCalls } : {}),
|
|
72
|
+
nestedRuns: input.nestedRuns ?? state.nestedRuns,
|
|
73
|
+
...(loopState ? { loopState } : {}),
|
|
74
|
+
counters: input.limits.snapshot(),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export async function persistSucceeded(ctx, loopUsage) {
|
|
78
|
+
const { session, runId, runUsage } = ctx;
|
|
79
|
+
const usage = runUsage.value() ?? loopUsage;
|
|
80
|
+
if (usage && session.activeLedger) {
|
|
81
|
+
const usageRecord = {
|
|
82
|
+
id: randomId("usage"),
|
|
83
|
+
sessionId: session.id,
|
|
84
|
+
runId,
|
|
85
|
+
scope: "run_total",
|
|
86
|
+
usage,
|
|
87
|
+
recordedAt: new Date().toISOString(),
|
|
88
|
+
...session.activeOwnership,
|
|
89
|
+
};
|
|
90
|
+
await session.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, session.activeRedactor));
|
|
91
|
+
}
|
|
92
|
+
await session.drainLedger();
|
|
93
|
+
const runState = session.activeDurable?.state
|
|
94
|
+
? await persistDurable(session, {
|
|
95
|
+
...session.activeDurable.state,
|
|
96
|
+
status: "succeeded",
|
|
97
|
+
pending: undefined,
|
|
98
|
+
pendingCalls: undefined,
|
|
99
|
+
nestedRuns: undefined,
|
|
100
|
+
stickyDecisions: undefined,
|
|
101
|
+
interruption: undefined,
|
|
102
|
+
loopState: undefined,
|
|
103
|
+
})
|
|
104
|
+
: undefined;
|
|
105
|
+
session.emit({
|
|
106
|
+
type: "agent_finished",
|
|
107
|
+
sessionId: session.id,
|
|
108
|
+
runId,
|
|
109
|
+
usage,
|
|
110
|
+
...(ctx.loopCtx.finishReason ? { finishReason: ctx.loopCtx.finishReason } : {}),
|
|
111
|
+
});
|
|
112
|
+
return session.buildRunResult({ runId, status: "succeeded", usage, runState });
|
|
113
|
+
}
|
|
114
|
+
export async function cleanupRun(input) {
|
|
115
|
+
const { session, controller, cleanupSignal, runId, model, startedAt, runStatus, runError } = input;
|
|
116
|
+
if (session.activeRun === controller)
|
|
117
|
+
session.activeRun = undefined;
|
|
118
|
+
session.activeRunId = undefined;
|
|
119
|
+
session.activeLoop = undefined;
|
|
120
|
+
session.activeGatedRound = undefined;
|
|
121
|
+
session.activeProviderTurnAbort = undefined;
|
|
122
|
+
session.pendingSoftInterrupt = false;
|
|
123
|
+
session.pendingSteers = [];
|
|
124
|
+
session.pendingSteerBytes = 0;
|
|
125
|
+
try {
|
|
126
|
+
await session.drainLedger();
|
|
127
|
+
if (session.activeLedger) {
|
|
128
|
+
const finishRecord = {
|
|
129
|
+
id: runId,
|
|
130
|
+
sessionId: session.id,
|
|
131
|
+
branchId: session.currentLeafId,
|
|
132
|
+
model,
|
|
133
|
+
provider: model.provider,
|
|
134
|
+
idempotencyKey: session.activeIdempotencyKey,
|
|
135
|
+
status: runStatus,
|
|
136
|
+
startedAt,
|
|
137
|
+
finishedAt: new Date().toISOString(),
|
|
138
|
+
abortReason: controller.signal.aborted ? String(controller.signal.reason) : undefined,
|
|
139
|
+
error: runError,
|
|
140
|
+
...(session.activePromptVersion ? { promptVersion: session.activePromptVersion } : {}),
|
|
141
|
+
...session.activeOwnership,
|
|
142
|
+
};
|
|
143
|
+
await session.activeLedger.appendRun(redactRunLedgerRecord(finishRecord, session.activeRedactor));
|
|
144
|
+
if (isFlushableRunLedger(session.activeLedger) && session.activeLedger.durability === "flush_on_terminal")
|
|
145
|
+
await session.activeLedger.flush();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
session.activeLedger = undefined;
|
|
150
|
+
session.activeEffectStore = undefined;
|
|
151
|
+
session.activeOwnership = undefined;
|
|
152
|
+
session.activeIdentity = undefined;
|
|
153
|
+
session.activeIdempotencyKey = undefined;
|
|
154
|
+
session.activeGuardrails = undefined;
|
|
155
|
+
session.activeMetadata = undefined;
|
|
156
|
+
session.activePromptVersion = undefined;
|
|
157
|
+
session.activeLimits?.dispose();
|
|
158
|
+
session.activeLimits = undefined;
|
|
159
|
+
session.activeLimitOutputBuffer = false;
|
|
160
|
+
session.activeRedactor = undefined;
|
|
161
|
+
session.activeProvider = undefined;
|
|
162
|
+
cleanupSignal();
|
|
163
|
+
session.closeSubscribers();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=persist.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Provider-round phase of runInternal (plan 059). */
|
|
2
|
+
import type { ProviderRequest, ProviderTurnResult, RunOptions, Usage } from "../../contracts.js";
|
|
3
|
+
import type { RoundContext, SessionHost } from "./types.js";
|
|
4
|
+
export declare function recordProviderUsage(ctx: RoundContext, turnUsage: Usage | undefined, turn: number, attempt: number): Promise<void>;
|
|
5
|
+
export declare function generateWithRetry(session: SessionHost, request: ProviderRequest, runId: string, options: RunOptions, signal: AbortSignal, requestSecrets?: readonly (string | undefined)[], turn?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<void>): Promise<ProviderTurnResult>;
|
|
6
|
+
export declare function generateProviderTurn(session: SessionHost, request: ProviderRequest, runId: string, signal: AbortSignal, secrets?: readonly (string | undefined)[], turn?: number, attempt?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<void>): Promise<ProviderTurnResult>;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/** Provider-round phase of runInternal (plan 059). */
|
|
2
|
+
import { assertGuardrailsAllowed, GuardrailError, runGuardrails } from "../../guardrails.js";
|
|
3
|
+
import { createProviderTurnMetadata, readProviderHttpStatus } from "../../observability.js";
|
|
4
|
+
import { providerToolCallDeltaContent } from "../../provider-events.js";
|
|
5
|
+
import { errorToErrorInfo, redactRunLedgerRecord, redactSecrets } from "../../redaction.js";
|
|
6
|
+
import { createDefaultRetryPolicy, waitForRetry } from "../../retry.js";
|
|
7
|
+
import { bridgeAbort, errorFromInfo, isSteerSoftInterrupt, jsonBytes, mergeRetry, ProviderTurnFailure, providerContent, randomId, reconstructMissingToolCalls, SteerSoftInterrupt, throwIfAborted, } from "../helpers.js";
|
|
8
|
+
/**
|
|
9
|
+
* Plan 062: price usage through the host's {@link CostCatalog} when the provider
|
|
10
|
+
* did not report a cost itself. Stale/unknown quotes, catalog failures, or
|
|
11
|
+
* non-`per_million_tokens` units degrade to usage-only (cost untouched).
|
|
12
|
+
*/
|
|
13
|
+
async function withCatalogCost(catalog, model, usage, signal) {
|
|
14
|
+
if (!catalog || usage.cost !== undefined)
|
|
15
|
+
return usage;
|
|
16
|
+
try {
|
|
17
|
+
const quote = await catalog.get(model.model, { signal });
|
|
18
|
+
if (!quote || (quote.unit !== undefined && quote.unit !== "per_million_tokens"))
|
|
19
|
+
return usage;
|
|
20
|
+
const cost = ((usage.inputTokens ?? 0) * (quote.input ?? 0) +
|
|
21
|
+
(usage.outputTokens ?? 0) * (quote.output ?? 0) +
|
|
22
|
+
(usage.cacheReadTokens ?? 0) * (quote.cacheRead ?? 0) +
|
|
23
|
+
(usage.cacheWriteTokens ?? 0) * (quote.cacheWrite ?? 0)) /
|
|
24
|
+
1_000_000;
|
|
25
|
+
if (!Number.isFinite(cost) || cost <= 0)
|
|
26
|
+
return usage;
|
|
27
|
+
return { ...usage, cost, ...(quote.currency !== undefined ? { currency: quote.currency } : {}) };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return usage; // catalog failure degrades to usage-only
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function recordProviderUsage(ctx, turnUsage, turn, attempt) {
|
|
34
|
+
const { session, limits, runUsage, runId } = ctx;
|
|
35
|
+
const usage = turnUsage
|
|
36
|
+
? await withCatalogCost(session.agent.config.costCatalog, ctx.model, turnUsage, ctx.controller.signal)
|
|
37
|
+
: undefined;
|
|
38
|
+
limits.recordUsage(usage);
|
|
39
|
+
if (!usage)
|
|
40
|
+
return;
|
|
41
|
+
runUsage.add(usage);
|
|
42
|
+
if (!session.activeLedger)
|
|
43
|
+
return;
|
|
44
|
+
const usageRecord = {
|
|
45
|
+
id: randomId("usage"),
|
|
46
|
+
sessionId: session.id,
|
|
47
|
+
runId,
|
|
48
|
+
scope: "provider_turn",
|
|
49
|
+
turn,
|
|
50
|
+
attempt,
|
|
51
|
+
usage,
|
|
52
|
+
recordedAt: new Date().toISOString(),
|
|
53
|
+
...session.activeOwnership,
|
|
54
|
+
};
|
|
55
|
+
await session.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, session.activeRedactor));
|
|
56
|
+
}
|
|
57
|
+
export async function generateWithRetry(session, request, runId, options, signal, requestSecrets = [], turn = 1, recordUsage) {
|
|
58
|
+
const retry = mergeRetry(session.agent.config.retry, options.retry);
|
|
59
|
+
const secrets = [...requestSecrets, ...(retry?.secrets ?? [])];
|
|
60
|
+
const policy = retry?.policy ?? (retry ? createDefaultRetryPolicy(retry) : undefined);
|
|
61
|
+
for (let attempt = 1;; attempt += 1) {
|
|
62
|
+
try {
|
|
63
|
+
return await generateProviderTurn(session, request, runId, signal, secrets, turn, attempt, recordUsage);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof GuardrailError || isSteerSoftInterrupt(error))
|
|
67
|
+
throw error;
|
|
68
|
+
const failure = error instanceof ProviderTurnFailure ? error : undefined;
|
|
69
|
+
const info = failure ? redactSecrets(failure.info, secrets) : errorToErrorInfo(error, secrets);
|
|
70
|
+
if (!policy || failure?.observable)
|
|
71
|
+
throw errorFromInfo(info);
|
|
72
|
+
const context = { sessionId: session.id, runId, attempt, error: info, metadata: retry?.metadata, signal };
|
|
73
|
+
let decision = await policy.decide(context);
|
|
74
|
+
const payload = (await session.agent.config.middleware?.run("retry", { context, decision })) ?? {
|
|
75
|
+
context,
|
|
76
|
+
decision,
|
|
77
|
+
};
|
|
78
|
+
decision = payload.decision;
|
|
79
|
+
if (!decision.retry)
|
|
80
|
+
throw errorFromInfo(info);
|
|
81
|
+
const delayMs = decision.delayMs ?? 0;
|
|
82
|
+
session.emit({ type: "retry_scheduled", sessionId: session.id, runId, attempt, delayMs, error: info });
|
|
83
|
+
await waitForRetry(decision, signal);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export async function generateProviderTurn(session, request, runId, signal, secrets = [], turn = 1, attempt = 1, recordUsage) {
|
|
88
|
+
session.activeLimits.charge("maxProviderAttempts");
|
|
89
|
+
session.activeLimits.charge("maxRequestBytes", jsonBytes(request));
|
|
90
|
+
const startedAt = performance.now();
|
|
91
|
+
const providerId = session.activeProvider?.id ?? request.model.provider;
|
|
92
|
+
const buildMetadata = (extra = {}) => createProviderTurnMetadata(request, providerId, { attempt, ...extra });
|
|
93
|
+
session.emit({
|
|
94
|
+
type: "provider_turn_started",
|
|
95
|
+
sessionId: session.id,
|
|
96
|
+
runId,
|
|
97
|
+
turn,
|
|
98
|
+
metadata: buildMetadata(),
|
|
99
|
+
});
|
|
100
|
+
const content = [];
|
|
101
|
+
const calls = [];
|
|
102
|
+
const toolDeltas = [];
|
|
103
|
+
let messageId;
|
|
104
|
+
let started = false;
|
|
105
|
+
let usage;
|
|
106
|
+
let usageRecorded = false;
|
|
107
|
+
const bufferedOutput = [];
|
|
108
|
+
const bufferOutput = Boolean(session.activeGuardrails?.output?.length || session.activeLimitOutputBuffer);
|
|
109
|
+
const emitOutput = (event) => {
|
|
110
|
+
if (bufferOutput)
|
|
111
|
+
bufferedOutput.push(event);
|
|
112
|
+
else
|
|
113
|
+
session.emit(event);
|
|
114
|
+
};
|
|
115
|
+
const recordTurnUsage = async () => {
|
|
116
|
+
if (usageRecorded)
|
|
117
|
+
return;
|
|
118
|
+
usageRecorded = true;
|
|
119
|
+
await recordUsage?.(usage, turn, attempt);
|
|
120
|
+
};
|
|
121
|
+
const turnAbort = new AbortController();
|
|
122
|
+
const cleanupTurn = bridgeAbort(signal, turnAbort);
|
|
123
|
+
session.activeProviderTurnAbort = turnAbort;
|
|
124
|
+
if (session.pendingSoftInterrupt) {
|
|
125
|
+
session.pendingSoftInterrupt = false;
|
|
126
|
+
turnAbort.abort(new SteerSoftInterrupt());
|
|
127
|
+
}
|
|
128
|
+
const turnRequest = { ...request, signal: turnAbort.signal };
|
|
129
|
+
try {
|
|
130
|
+
throwIfAborted(turnAbort.signal);
|
|
131
|
+
for await (const event of session.activeProvider.generate(turnRequest)) {
|
|
132
|
+
throwIfAborted(turnAbort.signal);
|
|
133
|
+
session.activeLimits.charge("maxResponseBytes", jsonBytes(event));
|
|
134
|
+
if (event.type === "error")
|
|
135
|
+
throw new ProviderTurnFailure(event.error, started);
|
|
136
|
+
if (event.type === "usage")
|
|
137
|
+
usage = event.usage;
|
|
138
|
+
if (event.type === "done") {
|
|
139
|
+
usage = event.usage ?? usage;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
if (event.type === "message_start") {
|
|
143
|
+
started = true;
|
|
144
|
+
messageId = event.messageId;
|
|
145
|
+
emitOutput({ type: "message_started", sessionId: session.id, runId, message: { id: messageId, role: "assistant", content: [] } });
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (event.type === "content_delta" || event.type === "tool_call" || event.type === "tool_call_delta") {
|
|
149
|
+
if (!started) {
|
|
150
|
+
started = true;
|
|
151
|
+
emitOutput({ type: "message_started", sessionId: session.id, runId, message: { role: "assistant", content: [] } });
|
|
152
|
+
}
|
|
153
|
+
if (event.type === "tool_call_delta") {
|
|
154
|
+
toolDeltas.push(event);
|
|
155
|
+
emitOutput({ type: "message_delta", sessionId: session.id, runId, content: providerToolCallDeltaContent(event) });
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const block = providerContent(event);
|
|
159
|
+
content.push(block);
|
|
160
|
+
if (block.type === "tool_call")
|
|
161
|
+
calls.push(block);
|
|
162
|
+
emitOutput({ type: "message_delta", sessionId: session.id, runId, content: block });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for (const call of reconstructMissingToolCalls(toolDeltas, calls)) {
|
|
166
|
+
content.push(call);
|
|
167
|
+
calls.push(call);
|
|
168
|
+
emitOutput({ type: "message_delta", sessionId: session.id, runId, content: call });
|
|
169
|
+
}
|
|
170
|
+
await recordTurnUsage();
|
|
171
|
+
if (session.activeGuardrails?.output?.length) {
|
|
172
|
+
assertGuardrailsAllowed(await runGuardrails({
|
|
173
|
+
stage: "output",
|
|
174
|
+
guardrails: session.activeGuardrails,
|
|
175
|
+
value: { content, calls, messageId, started, usage },
|
|
176
|
+
context: { sessionId: session.id, runId, metadata: session.activeMetadata ?? {}, signal: turnAbort.signal },
|
|
177
|
+
redactor: session.activeRedactor,
|
|
178
|
+
emit: (event) => session.emit(event),
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
if (bufferOutput)
|
|
182
|
+
for (const event of bufferedOutput)
|
|
183
|
+
session.emit(event);
|
|
184
|
+
const latencyMs = Math.round(performance.now() - startedAt);
|
|
185
|
+
session.emit({
|
|
186
|
+
type: "provider_turn_finished",
|
|
187
|
+
sessionId: session.id,
|
|
188
|
+
runId,
|
|
189
|
+
turn,
|
|
190
|
+
metadata: buildMetadata({ latencyMs }),
|
|
191
|
+
usage,
|
|
192
|
+
});
|
|
193
|
+
return { content, calls, messageId, started, usage };
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (isSteerSoftInterrupt(error) || isSteerSoftInterrupt(turnAbort.signal.reason)) {
|
|
197
|
+
await recordTurnUsage();
|
|
198
|
+
const latencyMs = Math.round(performance.now() - startedAt);
|
|
199
|
+
session.emit({
|
|
200
|
+
type: "provider_turn_finished",
|
|
201
|
+
sessionId: session.id,
|
|
202
|
+
runId,
|
|
203
|
+
turn,
|
|
204
|
+
metadata: buildMetadata({ latencyMs }),
|
|
205
|
+
usage,
|
|
206
|
+
});
|
|
207
|
+
throw new SteerSoftInterrupt();
|
|
208
|
+
}
|
|
209
|
+
const latencyMs = Math.round(performance.now() - startedAt);
|
|
210
|
+
const info = error instanceof ProviderTurnFailure ? redactSecrets(error.info, secrets) : errorToErrorInfo(error, secrets);
|
|
211
|
+
await recordTurnUsage();
|
|
212
|
+
session.emit({
|
|
213
|
+
type: "provider_turn_finished",
|
|
214
|
+
sessionId: session.id,
|
|
215
|
+
runId,
|
|
216
|
+
turn,
|
|
217
|
+
metadata: buildMetadata({ latencyMs, httpStatus: readProviderHttpStatus(info) }),
|
|
218
|
+
usage,
|
|
219
|
+
error: info,
|
|
220
|
+
});
|
|
221
|
+
if (error instanceof GuardrailError || error instanceof ProviderTurnFailure)
|
|
222
|
+
throw error;
|
|
223
|
+
throw new ProviderTurnFailure(info, started);
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
cleanupTurn();
|
|
227
|
+
if (session.activeProviderTurnAbort === turnAbort)
|
|
228
|
+
session.activeProviderTurnAbort = undefined;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=provider-round.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Tool-round phase of runInternal (plan 059). */
|
|
2
|
+
import type { AgentRunRef, LoopContext, NestedRunRef, PendingDecision, ResumeNestedRun, StickyDecision, ToolCallContent, ToolRegistry, ToolResult, Usage } from "../../contracts.js";
|
|
3
|
+
import { AgentDelegationSuspendedError } from "../../contracts.js";
|
|
4
|
+
import type { RoundContext, SessionHost } from "./types.js";
|
|
5
|
+
export declare function matchNestedSticky(session: SessionHost, decision: PendingDecision): StickyDecision | undefined;
|
|
6
|
+
export declare function matchStickyDecision(session: SessionHost, call: ToolCallContent, registry: ToolRegistry): StickyDecision | undefined;
|
|
7
|
+
export declare function buildPendingDecision(session: SessionHost, call: ToolCallContent, approvalId: string, registry: ToolRegistry, runId: string, metadata: Readonly<Record<string, unknown>>, signal: AbortSignal): PendingDecision;
|
|
8
|
+
export declare function applyNestedRun(session: SessionHost, input: {
|
|
9
|
+
ref: AgentRunRef;
|
|
10
|
+
toolCall: ToolCallContent;
|
|
11
|
+
path: readonly string[];
|
|
12
|
+
pending: readonly PendingDecision[];
|
|
13
|
+
hook?: ResumeNestedRun;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
toolResult: ToolResult;
|
|
16
|
+
} | {
|
|
17
|
+
entry: NestedRunRef;
|
|
18
|
+
pending: PendingDecision[];
|
|
19
|
+
}>;
|
|
20
|
+
export declare function suspendGatedRound(ctx: RoundContext): Promise<void>;
|
|
21
|
+
export declare function suspendNested(ctx: RoundContext, nested: {
|
|
22
|
+
entry: NestedRunRef;
|
|
23
|
+
toolCall: ToolCallContent;
|
|
24
|
+
pending: PendingDecision[];
|
|
25
|
+
}): Promise<never>;
|
|
26
|
+
export declare function replayToolResult(ctx: RoundContext, result: ToolResult): Promise<void>;
|
|
27
|
+
export declare function handleNestedSignal(ctx: RoundContext, error: AgentDelegationSuspendedError): Promise<void>;
|
|
28
|
+
export declare function bindChargeToolRound(ctx: RoundContext): LoopContext["chargeToolRound"];
|
|
29
|
+
export declare function bindDispatchToolCall(ctx: RoundContext): LoopContext["dispatchToolCall"];
|
|
30
|
+
export declare function replayDurableNestedAndPending(ctx: RoundContext): Promise<void>;
|
|
31
|
+
export declare function runLoopUntilSettled(ctx: RoundContext): Promise<Usage | undefined>;
|