@kindgi/agents 0.1.3 → 0.1.4-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/blocks.d.ts +101 -0
  2. package/dist/blocks.d.ts.map +1 -0
  3. package/dist/blocks.js +149 -0
  4. package/dist/blocks.js.map +1 -0
  5. package/dist/define.d.ts +17 -2
  6. package/dist/define.d.ts.map +1 -1
  7. package/dist/define.js +73 -6
  8. package/dist/define.js.map +1 -1
  9. package/dist/handlers/compose-result.d.ts.map +1 -1
  10. package/dist/handlers/compose-result.js +3 -0
  11. package/dist/handlers/compose-result.js.map +1 -1
  12. package/dist/handlers/context.d.ts +10 -0
  13. package/dist/handlers/context.d.ts.map +1 -1
  14. package/dist/handlers/dispatch-tools.d.ts.map +1 -1
  15. package/dist/handlers/dispatch-tools.js +51 -1
  16. package/dist/handlers/dispatch-tools.js.map +1 -1
  17. package/dist/handlers/errors.d.ts +12 -1
  18. package/dist/handlers/errors.d.ts.map +1 -1
  19. package/dist/handlers/errors.js.map +1 -1
  20. package/dist/handlers/evaluate-guardrails.d.ts.map +1 -1
  21. package/dist/handlers/evaluate-guardrails.js +2 -0
  22. package/dist/handlers/evaluate-guardrails.js.map +1 -1
  23. package/dist/handlers/model-call.d.ts.map +1 -1
  24. package/dist/handlers/model-call.js +11 -0
  25. package/dist/handlers/model-call.js.map +1 -1
  26. package/dist/handlers/public-types.d.ts +21 -1
  27. package/dist/handlers/public-types.d.ts.map +1 -1
  28. package/dist/handlers/rehydrate.d.ts.map +1 -1
  29. package/dist/handlers/rehydrate.js +6 -1
  30. package/dist/handlers/rehydrate.js.map +1 -1
  31. package/dist/handlers/render-prompt.d.ts.map +1 -1
  32. package/dist/handlers/render-prompt.js +4 -1
  33. package/dist/handlers/render-prompt.js.map +1 -1
  34. package/dist/handlers/replay.d.ts +143 -0
  35. package/dist/handlers/replay.d.ts.map +1 -0
  36. package/dist/handlers/replay.js +177 -0
  37. package/dist/handlers/replay.js.map +1 -0
  38. package/dist/handlers/resolve-blocks.d.ts +32 -0
  39. package/dist/handlers/resolve-blocks.d.ts.map +1 -0
  40. package/dist/handlers/resolve-blocks.js +129 -0
  41. package/dist/handlers/resolve-blocks.js.map +1 -0
  42. package/dist/handlers/resolve-tools.d.ts +6 -2
  43. package/dist/handlers/resolve-tools.d.ts.map +1 -1
  44. package/dist/handlers/resolve-tools.js +59 -27
  45. package/dist/handlers/resolve-tools.js.map +1 -1
  46. package/dist/handlers/result-shape.d.ts +7 -0
  47. package/dist/handlers/result-shape.d.ts.map +1 -1
  48. package/dist/handlers/result-shape.js.map +1 -1
  49. package/dist/handlers/run-retrievals.d.ts.map +1 -1
  50. package/dist/handlers/run-retrievals.js +34 -17
  51. package/dist/handlers/run-retrievals.js.map +1 -1
  52. package/dist/handlers/run-snapshot.d.ts.map +1 -1
  53. package/dist/handlers/run-snapshot.js +1 -0
  54. package/dist/handlers/run-snapshot.js.map +1 -1
  55. package/dist/handlers/setup.d.ts +2 -0
  56. package/dist/handlers/setup.d.ts.map +1 -1
  57. package/dist/handlers/setup.js +14 -2
  58. package/dist/handlers/setup.js.map +1 -1
  59. package/dist/handlers/turn-environment.d.ts +13 -2
  60. package/dist/handlers/turn-environment.d.ts.map +1 -1
  61. package/dist/handlers/turn-environment.js +12 -3
  62. package/dist/handlers/turn-environment.js.map +1 -1
  63. package/dist/index.d.ts +8 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +4 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/invoke.d.ts.map +1 -1
  68. package/dist/invoke.js +3 -0
  69. package/dist/invoke.js.map +1 -1
  70. package/dist/pins.d.ts +54 -0
  71. package/dist/pins.d.ts.map +1 -0
  72. package/dist/pins.js +51 -0
  73. package/dist/pins.js.map +1 -0
  74. package/dist/prompt.d.ts +12 -2
  75. package/dist/prompt.d.ts.map +1 -1
  76. package/dist/prompt.js +41 -4
  77. package/dist/prompt.js.map +1 -1
  78. package/dist/run-snapshot-binding.d.ts +5 -0
  79. package/dist/run-snapshot-binding.d.ts.map +1 -1
  80. package/dist/schema.d.ts +17 -0
  81. package/dist/schema.d.ts.map +1 -1
  82. package/dist/schema.js +5 -0
  83. package/dist/schema.js.map +1 -1
  84. package/dist/streaming.d.ts +5 -0
  85. package/dist/streaming.d.ts.map +1 -1
  86. package/dist/streaming.js.map +1 -1
  87. package/dist/types.d.ts +50 -1
  88. package/dist/types.d.ts.map +1 -1
  89. package/migrations/0004_stormy_moondragon.sql +1 -0
  90. package/migrations/meta/0004_snapshot.json +327 -0
  91. package/migrations/meta/_journal.json +7 -0
  92. package/package.json +15 -15
  93. package/src/blocks.ts +231 -0
  94. package/src/define.ts +84 -7
  95. package/src/handlers/compose-result.ts +3 -0
  96. package/src/handlers/context.ts +10 -0
  97. package/src/handlers/dispatch-tools.ts +54 -1
  98. package/src/handlers/errors.ts +13 -0
  99. package/src/handlers/evaluate-guardrails.ts +2 -0
  100. package/src/handlers/model-call.ts +14 -0
  101. package/src/handlers/public-types.ts +22 -1
  102. package/src/handlers/rehydrate.ts +21 -6
  103. package/src/handlers/render-prompt.ts +13 -7
  104. package/src/handlers/replay.ts +314 -0
  105. package/src/handlers/resolve-blocks.ts +188 -0
  106. package/src/handlers/resolve-tools.ts +76 -28
  107. package/src/handlers/result-shape.ts +8 -0
  108. package/src/handlers/run-retrievals.ts +44 -23
  109. package/src/handlers/run-snapshot.ts +1 -0
  110. package/src/handlers/setup.ts +13 -2
  111. package/src/handlers/turn-environment.ts +28 -3
  112. package/src/index.ts +37 -0
  113. package/src/invoke.ts +3 -0
  114. package/src/pins.ts +98 -0
  115. package/src/prompt.ts +52 -4
  116. package/src/run-snapshot-binding.ts +6 -0
  117. package/src/schema.ts +5 -0
  118. package/src/streaming.ts +5 -0
  119. package/src/types.ts +53 -1
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Replay turns: an eval run re-running a past run (`InvokeAgentInput.replay`)
3
+ * on an agent version, without doing anything the past run didn't already
4
+ * do. Each tool call is decided by the deployment's `ReplayBinding`:
5
+ *
6
+ * - `live`: the tool runs. Only a tool declared read-only (see
7
+ * `isReadOnlyTool`) with no approval to wait for can; a `live`
8
+ * decision for any other is refused here, whatever the binding says;
9
+ * - `recorded`: the past run's result for the same call is used;
10
+ * - `refused`: the tool doesn't run, and the model gets the given result.
11
+ *
12
+ * A turn marked as a replay with no binding refuses every call. Each
13
+ * decision is journaled (`NodeContext.record`), so a resumed turn keeps
14
+ * the decisions it made, and the turn's result lists them
15
+ * (`AgentTurnResult.replay`).
16
+ */
17
+ import type { NodeContext } from '@kindgi/handler';
18
+ import type { RunReplayRef } from '@kindgi/runtime';
19
+ import type { JournalEntry } from '@kindgi/runtime';
20
+ import type { Tool } from '@kindgi/tools';
21
+ import type { RunId, TenantId } from '@kindgi/types';
22
+ import type { RetrievedFact } from '../types.js';
23
+ import type { TurnContext } from './context.js';
24
+ /** The replay turn a `ReplayBinding` is asked about. */
25
+ export interface ReplayTurnRef {
26
+ readonly tenantId: TenantId;
27
+ /** The replay turn's own run. */
28
+ readonly runId: RunId;
29
+ readonly replay: RunReplayRef;
30
+ }
31
+ export interface ReplayToolInput extends ReplayTurnRef {
32
+ readonly tool: {
33
+ readonly id: string;
34
+ readonly version: string;
35
+ /** As the tool declares it; absent means it changes things. */
36
+ readonly mutating?: boolean;
37
+ readonly effects?: readonly string[];
38
+ };
39
+ readonly arguments: unknown;
40
+ /** The model's id for the call. */
41
+ readonly callId: string;
42
+ /** `true` when the tool's approval rules would ask for a review before it runs. */
43
+ readonly gated: boolean;
44
+ }
45
+ export type ReplayToolDecision = {
46
+ readonly kind: 'live';
47
+ } | {
48
+ readonly kind: 'recorded';
49
+ readonly result: unknown;
50
+ } | {
51
+ readonly kind: 'refused';
52
+ readonly result: unknown;
53
+ readonly reason: string;
54
+ };
55
+ /** An approval decision the past run recorded. */
56
+ export interface ReplayApproval {
57
+ readonly approved: boolean;
58
+ readonly rationale?: string;
59
+ }
60
+ /**
61
+ * How a deployment replays turns. Consulted only for a turn marked as a
62
+ * replay (`InvokeAgentInput.replay`).
63
+ */
64
+ export interface ReplayBinding {
65
+ /** Decide one tool call. */
66
+ decideTool(input: ReplayToolInput): Promise<ReplayToolDecision>;
67
+ /**
68
+ * What the turn's retrievals return: the past run's, or `undefined` to
69
+ * retrieve live. Absent: retrieve live.
70
+ */
71
+ retrievals?(input: ReplayTurnRef): Promise<readonly RetrievedFact[] | undefined>;
72
+ /**
73
+ * The past run's decision at the session approval gate, when the replay
74
+ * reaches that gate: the replay follows it. `undefined` (or absent): the
75
+ * gate is skipped, and the result says so.
76
+ */
77
+ sessionApproval?(input: ReplayTurnRef): Promise<ReplayApproval | undefined>;
78
+ }
79
+ /** One tool call of a replay turn, and what happened to it. */
80
+ export interface ReplayToolTrace {
81
+ readonly step: number;
82
+ readonly callId: string;
83
+ readonly toolId: string;
84
+ readonly toolVersion: string;
85
+ readonly arguments: unknown;
86
+ readonly source: 'live' | 'recorded' | 'refused';
87
+ /** Why it was refused. A refused call is what the turn would have done. */
88
+ readonly reason?: string;
89
+ }
90
+ /** What a replay turn did differently from a live one (`AgentTurnResult.replay`). */
91
+ export interface ReplayTurnReport extends RunReplayRef {
92
+ readonly tools: readonly ReplayToolTrace[];
93
+ /**
94
+ * The session approval gate, when the replay reached it: `followed` the
95
+ * past run's recorded decision, or `skipped` (none was recorded).
96
+ */
97
+ readonly approval?: 'followed' | 'skipped';
98
+ }
99
+ /** The `record` key of a replay's tool decision, per call. */
100
+ export declare const REPLAY_TOOL_RECORD_PREFIX = "replay-tool:";
101
+ /** The `record` key of a replay's session approval. */
102
+ export declare const REPLAY_APPROVAL_RECORD = "replay-session-approval";
103
+ /** A tool that declares it changes nothing: `mutating: false`, and no changing effect. */
104
+ export declare function isReadOnlyTool(tool: {
105
+ readonly mutating?: boolean;
106
+ readonly effects?: readonly {
107
+ readonly kind: string;
108
+ }[] | readonly string[];
109
+ }): boolean;
110
+ /**
111
+ * Decide one tool call of a replay turn, once: the binding's decision,
112
+ * held to `isReadOnlyTool`, journaled, and added to the turn's trace.
113
+ */
114
+ export declare function decideReplayTool(ctx: TurnContext, kctx: NodeContext, call: {
115
+ readonly step: number;
116
+ readonly callId: string;
117
+ readonly tool: Tool;
118
+ readonly version: string;
119
+ readonly arguments: unknown;
120
+ readonly gated: boolean;
121
+ }): Promise<ReplayToolDecision>;
122
+ /** The session approval a replay follows, decided once: the past run's, or none. */
123
+ export declare function replaySessionApproval(ctx: TurnContext, kctx: NodeContext): Promise<ReplayApproval | undefined>;
124
+ /**
125
+ * A replay at the session approval gate: it goes on when the past run's
126
+ * reviewer approved (or none was recorded), and fails as the past run did
127
+ * (`hitl-rejected`) when they rejected.
128
+ */
129
+ export declare function followReplaySessionGate(ctx: TurnContext, kctx: NodeContext): Promise<void>;
130
+ /**
131
+ * A resumed replay turn's trace and approval, from the journal: every call
132
+ * decided before the park, and the session approval if `setup` reached it.
133
+ * The step the turn parked in decides its calls again, from the journal.
134
+ */
135
+ export declare function rehydrateReplay(ctx: TurnContext, journal: readonly JournalEntry[]): void;
136
+ /** The turn's replay report, for its result. */
137
+ export declare function replayReport(ctx: TurnContext): ReplayTurnReport | undefined;
138
+ /** A replay's tag on its usage records (`ModelUsageRecord.replay`). */
139
+ export declare function replayTag(replay: RunReplayRef): {
140
+ readonly of: string;
141
+ readonly evalRunId: string;
142
+ };
143
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/handlers/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import { throwAgentTurnFailure } from './errors.js';
4
+ /** The `record` key of a replay's tool decision, per call. */
5
+ export const REPLAY_TOOL_RECORD_PREFIX = 'replay-tool:';
6
+ /** The `record` key of a replay's session approval. */
7
+ export const REPLAY_APPROVAL_RECORD = 'replay-session-approval';
8
+ /** Effects a read-only tool can't declare. */
9
+ const CHANGING_EFFECTS = new Set([
10
+ 'writes',
11
+ 'deletes',
12
+ 'spawns-run',
13
+ 'emits-event',
14
+ 'external-side-effect',
15
+ ]);
16
+ /** A tool that declares it changes nothing: `mutating: false`, and no changing effect. */
17
+ export function isReadOnlyTool(tool) {
18
+ if (tool.mutating !== false)
19
+ return false;
20
+ return !(tool.effects ?? []).some((e) => CHANGING_EFFECTS.has(typeof e === 'string' ? e : e.kind));
21
+ }
22
+ /** What the model gets for a call a replay refuses because nothing decided it. */
23
+ const NO_BINDING_REASON = 'replay: no replay binding is wired, so no tool runs';
24
+ const CHANGES_REASON = 'replay: this call changes things and has no recorded result';
25
+ const GATED_REASON = 'replay: this call needs an approval and has no recorded result';
26
+ function refusedResult(reason) {
27
+ return { status: 'not-executed', reason };
28
+ }
29
+ /**
30
+ * Decide one tool call of a replay turn, once: the binding's decision,
31
+ * held to `isReadOnlyTool`, journaled, and added to the turn's trace.
32
+ */
33
+ export async function decideReplayTool(ctx, kctx, call) {
34
+ const replay = ctx.input.replay;
35
+ if (replay === undefined)
36
+ return { kind: 'live' };
37
+ const base = {
38
+ step: call.step,
39
+ callId: call.callId,
40
+ toolId: call.tool.id,
41
+ toolVersion: call.version,
42
+ arguments: call.arguments,
43
+ };
44
+ const refuse = (reason) => ({
45
+ ...base,
46
+ source: 'refused',
47
+ reason,
48
+ result: refusedResult(reason),
49
+ });
50
+ const decided = await kctx.record(`${REPLAY_TOOL_RECORD_PREFIX}${call.callId}`, async () => {
51
+ const binding = ctx.bindings.replay;
52
+ if (binding === undefined)
53
+ return refuse(NO_BINDING_REASON);
54
+ const decision = await binding.decideTool({
55
+ tenantId: ctx.input.tenantId,
56
+ runId: kctx.runId,
57
+ replay,
58
+ tool: {
59
+ id: base.toolId,
60
+ version: call.version,
61
+ ...(call.tool.mutating !== undefined && { mutating: call.tool.mutating }),
62
+ ...(call.tool.effects !== undefined && {
63
+ effects: call.tool.effects.map((e) => e.kind),
64
+ }),
65
+ },
66
+ arguments: call.arguments,
67
+ callId: call.callId,
68
+ gated: call.gated,
69
+ });
70
+ if (decision.kind === 'recorded') {
71
+ return { ...base, source: 'recorded', result: decision.result };
72
+ }
73
+ if (decision.kind === 'refused') {
74
+ return { ...base, source: 'refused', reason: decision.reason, result: decision.result };
75
+ }
76
+ // `live` runs only a read-only tool, and never waits for an approval.
77
+ if (!isReadOnlyTool(call.tool))
78
+ return refuse(CHANGES_REASON);
79
+ if (call.gated)
80
+ return refuse(GATED_REASON);
81
+ return { ...base, source: 'live' };
82
+ });
83
+ addReplayTrace(ctx, traceOf(decided));
84
+ if (decided.source === 'live')
85
+ return { kind: 'live' };
86
+ if (decided.source === 'recorded')
87
+ return { kind: 'recorded', result: decided.result };
88
+ return { kind: 'refused', result: decided.result, reason: decided.reason ?? CHANGES_REASON };
89
+ }
90
+ /** A journaled decision's trace entry (without the result). */
91
+ function traceOf(decided) {
92
+ const { result: _result, ...trace } = decided;
93
+ return trace;
94
+ }
95
+ function addReplayTrace(ctx, entry) {
96
+ const trace = ctx.replayTrace ?? [];
97
+ ctx.replayTrace = trace;
98
+ // A step run again after a resume decides its calls again (from the journal).
99
+ if (trace.some((t) => t.callId === entry.callId))
100
+ return;
101
+ trace.push(entry);
102
+ }
103
+ /** The session approval a replay follows, decided once: the past run's, or none. */
104
+ export async function replaySessionApproval(ctx, kctx) {
105
+ const replay = ctx.input.replay;
106
+ if (replay === undefined)
107
+ return undefined;
108
+ const recorded = await kctx.record(REPLAY_APPROVAL_RECORD, async () => {
109
+ const approval = await ctx.bindings.replay?.sessionApproval?.({
110
+ tenantId: ctx.input.tenantId,
111
+ runId: kctx.runId,
112
+ replay,
113
+ });
114
+ return { approval: approval ?? null };
115
+ });
116
+ ctx.replayApproval = recorded.approval === null ? 'skipped' : 'followed';
117
+ return recorded.approval ?? undefined;
118
+ }
119
+ /**
120
+ * A replay at the session approval gate: it goes on when the past run's
121
+ * reviewer approved (or none was recorded), and fails as the past run did
122
+ * (`hitl-rejected`) when they rejected.
123
+ */
124
+ export async function followReplaySessionGate(ctx, kctx) {
125
+ const approval = await replaySessionApproval(ctx, kctx);
126
+ if (approval === undefined || approval.approved)
127
+ return;
128
+ throwAgentTurnFailure({
129
+ code: 'hitl-rejected',
130
+ message: `The replayed run's reviewer rejected the session-HITL gate${approval.rationale !== undefined ? `: ${approval.rationale}` : ''}`,
131
+ ...(approval.rationale !== undefined && { rationale: approval.rationale }),
132
+ });
133
+ }
134
+ /**
135
+ * A resumed replay turn's trace and approval, from the journal: every call
136
+ * decided before the park, and the session approval if `setup` reached it.
137
+ * The step the turn parked in decides its calls again, from the journal.
138
+ */
139
+ export function rehydrateReplay(ctx, journal) {
140
+ if (ctx.input.replay === undefined)
141
+ return;
142
+ for (const e of journal) {
143
+ if (e.kind !== 'value.recorded')
144
+ continue;
145
+ const p = (e.payload ?? {});
146
+ if (p.key === REPLAY_APPROVAL_RECORD) {
147
+ const approval = p.value?.approval;
148
+ ctx.replayApproval = approval == null ? 'skipped' : 'followed';
149
+ }
150
+ else if (p.key?.startsWith(REPLAY_TOOL_RECORD_PREFIX) === true) {
151
+ restoreDecision(ctx, p.value);
152
+ }
153
+ }
154
+ }
155
+ function restoreDecision(ctx, value) {
156
+ const decided = value;
157
+ if (decided?.source !== undefined && decided.callId !== undefined) {
158
+ addReplayTrace(ctx, traceOf(decided));
159
+ }
160
+ }
161
+ /** The turn's replay report, for its result. */
162
+ export function replayReport(ctx) {
163
+ const replay = ctx.input.replay;
164
+ if (replay === undefined)
165
+ return undefined;
166
+ return {
167
+ of: replay.of,
168
+ evalRunId: replay.evalRunId,
169
+ tools: [...(ctx.replayTrace ?? [])].sort((a, b) => a.step - b.step),
170
+ ...(ctx.replayApproval !== undefined && { approval: ctx.replayApproval }),
171
+ };
172
+ }
173
+ /** A replay's tag on its usage records (`ModelUsageRecord.replay`). */
174
+ export function replayTag(replay) {
175
+ return { of: replay.of, evalRunId: replay.evalRunId };
176
+ }
177
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/handlers/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type ModelSettings, type PromptBlockContent } from '../blocks.js';
2
+ import type { TurnContext } from './context.js';
3
+ /** The block versions a turn runs, by kind then id, as `setup` journals them. */
4
+ export interface PinnedBlockVersions {
5
+ readonly prompts: Readonly<Record<string, string>>;
6
+ readonly settings: Readonly<Record<string, string>>;
7
+ }
8
+ /** The data blocks a turn runs with, loaded at its version. */
9
+ export interface TurnBlocks {
10
+ /** The prompt block the instructions come from. */
11
+ readonly prompt?: {
12
+ readonly id: string;
13
+ readonly version: string;
14
+ readonly content: PromptBlockContent;
15
+ };
16
+ /** Each settings block's values, by block id (`ToolContext.settings`, `settings` in templates). */
17
+ readonly settings: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
18
+ /** The model-settings block's values, for the turn's model calls. */
19
+ readonly modelSettings?: ModelSettings;
20
+ readonly versions: PinnedBlockVersions;
21
+ }
22
+ /**
23
+ * Load the data blocks the agent references, each at one exact version:
24
+ * the resumed turn's own (`pinned`, from its `setup`), else the agent
25
+ * version's pin (`agent.pins`), else its range resolved now by
26
+ * `pickVersion` (an agent version published before pins). A pinned
27
+ * version that's unregistered still loads; one that's gone, a range
28
+ * nothing satisfies, or a runtime with no blocks fails the turn
29
+ * (`block-unresolvable`). `undefined` when the agent references none.
30
+ */
31
+ export declare function resolveTurnBlocks(ctx: TurnContext, pinned?: PinnedBlockVersions): Promise<TurnBlocks | undefined>;
32
+ //# sourceMappingURL=resolve-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-blocks.d.ts","sourceRoot":"","sources":["../../src/handlers/resolve-blocks.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EAExB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;KACtC,CAAC;IACF,mGAAmG;IACnG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,qEAAqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;CACxC;AASD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,WAAW,EAChB,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAqCjC"}
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import { pickVersion } from '@kindgi/tools';
4
+ import { MODEL_SETTINGS_SCHEMA, settingsSchemaIssues, } from '../blocks.js';
5
+ import { throwAgentTurnFailure } from './errors.js';
6
+ /**
7
+ * Load the data blocks the agent references, each at one exact version:
8
+ * the resumed turn's own (`pinned`, from its `setup`), else the agent
9
+ * version's pin (`agent.pins`), else its range resolved now by
10
+ * `pickVersion` (an agent version published before pins). A pinned
11
+ * version that's unregistered still loads; one that's gone, a range
12
+ * nothing satisfies, or a runtime with no blocks fails the turn
13
+ * (`block-unresolvable`). `undefined` when the agent references none.
14
+ */
15
+ export async function resolveTurnBlocks(ctx, pinned) {
16
+ const agent = ctx.input.agent;
17
+ const refs = blockRefs(ctx);
18
+ if (refs.length === 0)
19
+ return undefined;
20
+ const reader = ctx.bindings.blockReader;
21
+ if (reader === undefined) {
22
+ fail(refs[0], `agent "${agent.id}" references data blocks, but this runtime serves none`);
23
+ }
24
+ const versions = {
25
+ prompts: {},
26
+ settings: {},
27
+ };
28
+ const loaded = new Map();
29
+ for (const ref of refs) {
30
+ const version = pinned?.[ref.kind][ref.id] ??
31
+ agent.pins?.[ref.kind][ref.id] ??
32
+ (await resolveRange(ctx, ref));
33
+ const block = await reader.getVersion({
34
+ tenantId: ctx.input.tenantId,
35
+ blockId: ref.id,
36
+ version,
37
+ });
38
+ if (block === null) {
39
+ fail(ref, `${describe(ref)} runs version ${version}, which isn't published`);
40
+ }
41
+ if (block.kind !== (ref.role === 'prompt' ? 'prompt' : 'settings')) {
42
+ fail(ref, `${describe(ref)} is a ${block.kind} block`);
43
+ }
44
+ versions[ref.kind][ref.id] = version;
45
+ loaded.set(ref, block);
46
+ }
47
+ return turnBlocks(refs, loaded, versions);
48
+ }
49
+ function blockRefs(ctx) {
50
+ const agent = ctx.input.agent;
51
+ const refs = [];
52
+ if (typeof agent.instructions === 'object') {
53
+ refs.push({
54
+ kind: 'prompts',
55
+ id: agent.instructions.prompt,
56
+ range: agent.instructions.version,
57
+ role: 'prompt',
58
+ });
59
+ }
60
+ for (const s of agent.settings ?? []) {
61
+ refs.push({ kind: 'settings', id: s.id, range: s.version, role: 'settings' });
62
+ }
63
+ if (agent.modelSettings !== undefined) {
64
+ refs.push({
65
+ kind: 'settings',
66
+ id: agent.modelSettings.id,
67
+ range: agent.modelSettings.version,
68
+ role: 'model-settings',
69
+ });
70
+ }
71
+ return refs;
72
+ }
73
+ /** An unpinned reference's range, resolved over the block's active versions. */
74
+ async function resolveRange(ctx, ref) {
75
+ const available = (await ctx.bindings.blockReader?.activeVersions({
76
+ tenantId: ctx.input.tenantId,
77
+ blockId: ref.id,
78
+ })) ?? [];
79
+ const pick = pickVersion(available, ref.range);
80
+ if (pick.kind === 'ok')
81
+ return pick.version;
82
+ return fail(ref, available.length === 0
83
+ ? `${describe(ref)} has no published version`
84
+ : `${describe(ref)} has no published version in "${ref.range}" (published: ${available.join(', ')})`);
85
+ }
86
+ function turnBlocks(refs, loaded, versions) {
87
+ const settings = {};
88
+ let prompt;
89
+ let modelSettings;
90
+ for (const ref of refs) {
91
+ const block = loaded.get(ref);
92
+ if (block.kind === 'prompt') {
93
+ prompt = { id: block.id, version: block.version, content: block.content };
94
+ }
95
+ else if (ref.role === 'model-settings') {
96
+ const issues = settingsSchemaIssues(block.content.values, MODEL_SETTINGS_SCHEMA);
97
+ if (issues.length > 0) {
98
+ fail(ref, `${describe(ref)} version ${block.version} isn't model settings: ${issues.map((i) => `${i.path} ${i.message}`).join('; ')}`);
99
+ }
100
+ modelSettings = block.content.values;
101
+ }
102
+ else {
103
+ settings[block.id] = block.content.values;
104
+ }
105
+ }
106
+ return {
107
+ ...(prompt !== undefined && { prompt }),
108
+ settings,
109
+ ...(modelSettings !== undefined && { modelSettings }),
110
+ versions,
111
+ };
112
+ }
113
+ function describe(ref) {
114
+ const what = ref.role === 'prompt'
115
+ ? 'prompt'
116
+ : ref.role === 'model-settings'
117
+ ? 'model-settings'
118
+ : 'settings';
119
+ return `${what} block "${ref.id}"`;
120
+ }
121
+ function fail(ref, message) {
122
+ return throwAgentTurnFailure({
123
+ code: 'block-unresolvable',
124
+ message,
125
+ blockId: ref.id,
126
+ requestedRange: ref.range,
127
+ });
128
+ }
129
+ //# sourceMappingURL=resolve-blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-blocks.js","sourceRoot":"","sources":["../../src/handlers/resolve-blocks.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,11 @@ import type { TurnContext } from './context.js';
4
4
  /**
5
5
  * Resolve the agent's tool references against one tenant's registry
6
6
  * (`ToolRegistry.forTenant`). Throws the turn failure for an unknown
7
- * tool or an unsatisfiable version range.
7
+ * tool or an unsatisfiable version range. A tool in `pinned` (a resumed
8
+ * turn's, from its `setup`) resolves to exactly that version, and so,
9
+ * otherwise, does one in the agent version's own pins (`agent.pins`, set
10
+ * when it was published): one that's gone fails the turn rather than
11
+ * running another. Without either, the tool's range resolves.
8
12
  */
9
- export declare function resolveTurnTools(registry: ToolRegistry, agent: Agent): NonNullable<TurnContext['tools']>;
13
+ export declare function resolveTurnTools(registry: ToolRegistry, agent: Agent, pinned?: Readonly<Record<string, string>>): NonNullable<TurnContext['tools']>;
10
14
  //# sourceMappingURL=resolve-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-tools.d.ts","sourceRoot":"","sources":["../../src/handlers/resolve-tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAQ,YAAY,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,KAAK,GACX,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAgDnC"}
1
+ {"version":3,"file":"resolve-tools.d.ts","sourceRoot":"","sources":["../../src/handlers/resolve-tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,YAAY,EAAkB,MAAM,eAAe,CAAC;AAGnF,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACxC,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAgCnC"}
@@ -4,9 +4,13 @@ import { throwAgentTurnFailure } from './errors.js';
4
4
  /**
5
5
  * Resolve the agent's tool references against one tenant's registry
6
6
  * (`ToolRegistry.forTenant`). Throws the turn failure for an unknown
7
- * tool or an unsatisfiable version range.
7
+ * tool or an unsatisfiable version range. A tool in `pinned` (a resumed
8
+ * turn's, from its `setup`) resolves to exactly that version, and so,
9
+ * otherwise, does one in the agent version's own pins (`agent.pins`, set
10
+ * when it was published): one that's gone fails the turn rather than
11
+ * running another. Without either, the tool's range resolves.
8
12
  */
9
- export function resolveTurnTools(registry, agent) {
13
+ export function resolveTurnTools(registry, agent, pinned) {
10
14
  const definitions = [];
11
15
  const byName = new Map();
12
16
  for (const ref of agent.tools) {
@@ -15,32 +19,15 @@ export function resolveTurnTools(registry, agent) {
15
19
  // (npm-compatible semver, backed by `maxSatisfying`); capture `resolvedVersion` in
16
20
  // the byName map so `dispatch-tools` can emit it in provenance +
17
21
  // telemetry — a replay can then pin against the same version.
18
- const resolved = registry.resolve(ref.id, ref.version);
22
+ const turnPin = pinned?.[ref.id];
23
+ const pin = turnPin ?? agent.pins?.tools[ref.id];
24
+ // A pin names its exact version, which a retired (unregistered) one
25
+ // still serves; a range picks among the active versions only.
26
+ const resolved = pin !== undefined
27
+ ? exactVersion(registry, ref.id, pin)
28
+ : registry.resolve(ref.id, ref.version);
19
29
  if (resolved.kind === 'err') {
20
- const err = resolved.error;
21
- if (err.code === 'tool-not-found') {
22
- throwAgentTurnFailure({
23
- code: 'unresolved-tool',
24
- message: `Tool "${ref.id}" declared by agent "${agent.id}" is not registered`,
25
- toolId: ref.id,
26
- });
27
- }
28
- if (err.code === 'invalid-version-range' || err.code === 'tool-version-unresolvable') {
29
- throwAgentTurnFailure({
30
- code: 'tool-version-unresolvable',
31
- message: err.message,
32
- toolId: ref.id,
33
- requestedRange: ref.version,
34
- ...(err.code === 'tool-version-unresolvable' && {
35
- availableVersions: err.availableVersions,
36
- }),
37
- });
38
- }
39
- throwAgentTurnFailure({
40
- code: 'unresolved-tool',
41
- message: err.message,
42
- toolId: ref.id,
43
- });
30
+ throwUnresolved(agent, ref, resolved.error, pin, turnPin !== undefined ? 'turn' : 'agent');
44
31
  }
45
32
  const { tool, resolvedVersion } = resolved.value;
46
33
  definitions.push({
@@ -52,4 +39,49 @@ export function resolveTurnTools(registry, agent) {
52
39
  }
53
40
  return { definitions, byName };
54
41
  }
42
+ /** A pinned tool version, retired or not, as a resolution. */
43
+ function exactVersion(registry, id, version) {
44
+ const found = registry.getVersion(id, version);
45
+ return found.kind === 'ok'
46
+ ? { kind: 'ok', value: { tool: found.value, resolvedVersion: version } }
47
+ : found;
48
+ }
49
+ /**
50
+ * Fail the turn for a tool that didn't resolve. A pinned version that's
51
+ * gone names whose pin it was: the turn's own (it started with that
52
+ * version) or the agent version's (it was published with it).
53
+ */
54
+ function throwUnresolved(agent, ref, err, pin, pinnedBy) {
55
+ const available = err.code === 'tool-version-unresolvable' && {
56
+ availableVersions: err.availableVersions,
57
+ };
58
+ if (pin !== undefined) {
59
+ throwAgentTurnFailure({
60
+ code: 'tool-version-unresolvable',
61
+ message: pinnedBy === 'turn'
62
+ ? `Tool "${ref.id}": this turn started with version ${pin}, which is no longer registered; it doesn't run another version mid-turn. ${err.message}`
63
+ : `Tool "${ref.id}": agent "${agent.id}" version ${agent.version} runs version ${pin} (its pins), which isn't registered; it doesn't run another version. ${err.message}`,
64
+ toolId: ref.id,
65
+ requestedRange: ref.version,
66
+ ...available,
67
+ });
68
+ }
69
+ if (err.code === 'tool-not-found') {
70
+ throwAgentTurnFailure({
71
+ code: 'unresolved-tool',
72
+ message: `Tool "${ref.id}" declared by agent "${agent.id}" is not registered`,
73
+ toolId: ref.id,
74
+ });
75
+ }
76
+ if (err.code === 'invalid-version-range' || err.code === 'tool-version-unresolvable') {
77
+ throwAgentTurnFailure({
78
+ code: 'tool-version-unresolvable',
79
+ message: err.message,
80
+ toolId: ref.id,
81
+ requestedRange: ref.version,
82
+ ...available,
83
+ });
84
+ }
85
+ throwAgentTurnFailure({ code: 'unresolved-tool', message: err.message, toolId: ref.id });
86
+ }
55
87
  //# sourceMappingURL=resolve-tools.js.map