stitchkit 0.84.0 → 0.85.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 +78 -0
- package/dist/agent-runtime/control-schema.d.ts +61 -0
- package/dist/agent-runtime/control-schema.d.ts.map +1 -1
- package/dist/agent-runtime/deferred-tool-search.d.ts.map +1 -1
- package/dist/agent-runtime/deferred-tool-selection.d.ts +17 -0
- package/dist/agent-runtime/deferred-tool-selection.d.ts.map +1 -1
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
- package/dist/agent-runtime/event-schema.d.ts +88 -1
- package/dist/agent-runtime/event-schema.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-operation-lifecycle.d.ts +21 -0
- package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -0
- package/dist/agent-runtime/schemas.d.ts +67 -0
- package/dist/agent-runtime/schemas.d.ts.map +1 -1
- package/dist/agent-runtime/sqlite.d.ts.map +1 -1
- package/dist/agent-runtime/store-driver.d.ts +26 -1
- package/dist/agent-runtime/store-driver.d.ts.map +1 -1
- package/dist/agent-runtime/store.d.ts +208 -0
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +9 -0
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
- package/dist/agent-runtime-browser.js +11 -3
- package/dist/agent-runtime-harness.js +4 -4
- package/dist/agent-runtime-sqlite-bun.js +3 -3
- package/dist/agent-runtime-sqlite-node.js +3 -3
- package/dist/agent-runtime.d.ts +2 -2
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +32 -6
- package/dist/{index-85vfqd7m.js → index-4hk633vz.js} +11 -3
- package/dist/{index-cksjz4eg.js → index-66nxrgy0.js} +17 -16
- package/dist/{index-st8v8739.js → index-9merfjxf.js} +141 -14
- package/dist/{index-5s3zajp8.js → index-ff0kcqvp.js} +9 -3
- package/dist/{index-19eet1qx.js → index-fq492hg0.js} +31 -5
- package/dist/{index-x1th9s8c.js → index-x15ss2dx.js} +50 -1
- package/dist/testing.js +26 -2
- package/dist/tools/async-operation.d.ts +18 -1
- package/dist/tools/async-operation.d.ts.map +1 -1
- package/dist/tools.js +3 -1
- package/llms-full.txt +69 -8
- package/package.json +1 -1
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
AgentRecordIdSchema,
|
|
6
6
|
AgentRecordVersionSchema,
|
|
7
7
|
AgentRunMetricsSchema,
|
|
8
|
+
AgentRunOperationSchema,
|
|
8
9
|
AgentRunSchema,
|
|
9
10
|
AgentRunStateSchema,
|
|
10
11
|
AgentTerminalReasonSchema,
|
|
11
12
|
AgentTimestampSchema
|
|
12
|
-
} from "./index-
|
|
13
|
+
} from "./index-x15ss2dx.js";
|
|
13
14
|
|
|
14
15
|
// src/agent-runtime/event-schema.ts
|
|
15
16
|
import { z } from "zod";
|
|
@@ -63,6 +64,12 @@ var AgentRunStateEventSchema = EventIdentitySchema.extend({
|
|
|
63
64
|
snapshotVersion: AgentRecordVersionSchema,
|
|
64
65
|
state: AgentRunStateSchema
|
|
65
66
|
});
|
|
67
|
+
var AgentRunOperationEventSchema = EventIdentitySchema.extend({
|
|
68
|
+
type: z.literal("run-operation"),
|
|
69
|
+
eventId: AgentRecordIdSchema,
|
|
70
|
+
snapshotVersion: AgentRecordVersionSchema,
|
|
71
|
+
operation: AgentRunOperationSchema
|
|
72
|
+
});
|
|
66
73
|
var AgentToolStatusEventSchema = EventIdentitySchema.extend({
|
|
67
74
|
type: z.literal("tool-status"),
|
|
68
75
|
runtimeEpoch: z.string().min(1),
|
|
@@ -90,6 +97,7 @@ var AgentRuntimeEventSchema = z.discriminatedUnion("type", [
|
|
|
90
97
|
AgentReasoningEndEventSchema,
|
|
91
98
|
AgentCheckpointEventSchema,
|
|
92
99
|
AgentRunStateEventSchema,
|
|
100
|
+
AgentRunOperationEventSchema,
|
|
93
101
|
AgentToolStatusEventSchema,
|
|
94
102
|
AgentTerminalEventSchema
|
|
95
103
|
]);
|
|
@@ -100,7 +108,7 @@ var AgentRuntimeEventCursorSchema = z.object({
|
|
|
100
108
|
sequence: z.int().nonnegative().optional()
|
|
101
109
|
});
|
|
102
110
|
function isDurableEvent(event) {
|
|
103
|
-
return event.type === "admission" || event.type === "assistant-checkpoint" || event.type === "run-state" || event.type === "terminal";
|
|
111
|
+
return event.type === "admission" || event.type === "assistant-checkpoint" || event.type === "run-state" || event.type === "run-operation" || event.type === "terminal";
|
|
104
112
|
}
|
|
105
113
|
function advanceAgentRuntimeEventCursor(rawCursor, event) {
|
|
106
114
|
const cursor = AgentRuntimeEventCursorSchema.parse(rawCursor);
|
|
@@ -132,4 +140,4 @@ function agentDurableEventId(type, runId, snapshotVersion) {
|
|
|
132
140
|
return `${runId}:${type}:${snapshotVersion}`;
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
export { AgentAdmissionEventSchema, AgentTransientDeltaEventSchema, AgentReasoningStartEventSchema, AgentReasoningDeltaEventSchema, AgentReasoningEndEventSchema, AgentCheckpointEventSchema, AgentRunStateEventSchema, AgentToolStatusEventSchema, AgentTerminalEventSchema, AgentRuntimeEventSchema, AgentRuntimeEventCursorSchema, advanceAgentRuntimeEventCursor, agentDurableEventId };
|
|
143
|
+
export { AgentAdmissionEventSchema, AgentTransientDeltaEventSchema, AgentReasoningStartEventSchema, AgentReasoningDeltaEventSchema, AgentReasoningEndEventSchema, AgentCheckpointEventSchema, AgentRunStateEventSchema, AgentRunOperationEventSchema, AgentToolStatusEventSchema, AgentTerminalEventSchema, AgentRuntimeEventSchema, AgentRuntimeEventCursorSchema, advanceAgentRuntimeEventCursor, agentDurableEventId };
|
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
AgentRuntimeHeadSchema,
|
|
9
9
|
AgentStoredRunSchema,
|
|
10
10
|
createAgentRuntimeStore
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-fq492hg0.js";
|
|
12
12
|
import {
|
|
13
13
|
AgentMessageSchema,
|
|
14
14
|
AgentRunSchema
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-x15ss2dx.js";
|
|
16
16
|
|
|
17
17
|
// src/agent-runtime/sqlite.ts
|
|
18
18
|
import { z } from "zod";
|
|
@@ -244,19 +244,20 @@ function createSqliteAgentRuntimeStore(config) {
|
|
|
244
244
|
});
|
|
245
245
|
return result;
|
|
246
246
|
};
|
|
247
|
+
const runTransaction = (access, work) => serial(async () => {
|
|
248
|
+
database.exec(access === "read" ? "BEGIN" : "BEGIN IMMEDIATE");
|
|
249
|
+
try {
|
|
250
|
+
const result = await work(database);
|
|
251
|
+
database.exec("COMMIT");
|
|
252
|
+
return result;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
database.exec("ROLLBACK");
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
247
258
|
const driver = {
|
|
248
259
|
conversations: sqliteConversationPurge(database),
|
|
249
|
-
transaction: (work) =>
|
|
250
|
-
database.exec("BEGIN IMMEDIATE");
|
|
251
|
-
try {
|
|
252
|
-
const result = await work(database);
|
|
253
|
-
database.exec("COMMIT");
|
|
254
|
-
return result;
|
|
255
|
-
} catch (error) {
|
|
256
|
-
database.exec("ROLLBACK");
|
|
257
|
-
throw error;
|
|
258
|
-
}
|
|
259
|
-
}),
|
|
260
|
+
transaction: (work, options) => runTransaction(options?.access ?? "write", work),
|
|
260
261
|
head: {
|
|
261
262
|
async load(transaction, conversationId) {
|
|
262
263
|
const value = transaction.prepare("SELECT version FROM stitchkit_agent_runtime_heads WHERE conversation_id = ?").get(conversationId);
|
|
@@ -437,7 +438,7 @@ function createSqliteAgentRuntimeStore(config) {
|
|
|
437
438
|
`).run(message.conversationId, message.id, position, encodeJson(message));
|
|
438
439
|
}
|
|
439
440
|
},
|
|
440
|
-
scanRecoverable: (input) =>
|
|
441
|
+
scanRecoverable: (input) => runTransaction("read", async () => {
|
|
441
442
|
const cursor = input.cursor ? parseRecoveryCursor(input.cursor) : undefined;
|
|
442
443
|
const values = cursor ? [cursor[0], cursor[0], cursor[1], input.limit + 1] : [input.limit + 1];
|
|
443
444
|
const rows = database.prepare(`
|
|
@@ -466,7 +467,7 @@ function createSqliteAgentRuntimeStore(config) {
|
|
|
466
467
|
return {
|
|
467
468
|
store: createAgentRuntimeStore(driver),
|
|
468
469
|
conversations: {
|
|
469
|
-
list: (input) =>
|
|
470
|
+
list: (input) => runTransaction("read", async () => {
|
|
470
471
|
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1000) {
|
|
471
472
|
throw new TypeError("Conversation page limit must be between 1 and 1000");
|
|
472
473
|
}
|
|
@@ -517,7 +518,7 @@ function createSqliteAgentRuntimeStore(config) {
|
|
|
517
518
|
...hasMore && last ? { nextCursor: conversationCursor(last.conversation_id) } : {}
|
|
518
519
|
});
|
|
519
520
|
}),
|
|
520
|
-
messages: (input) =>
|
|
521
|
+
messages: (input) => runTransaction("read", async () => {
|
|
521
522
|
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1000) {
|
|
522
523
|
throw new TypeError("Conversation message page limit must be between 1 and 1000");
|
|
523
524
|
}
|
|
@@ -12,17 +12,18 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
AgentRuntimeEventSchema,
|
|
14
14
|
agentDurableEventId
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-4hk633vz.js";
|
|
16
16
|
import {
|
|
17
17
|
AgentAssistantPlaceholderSchema,
|
|
18
18
|
AgentJsonObjectSchema,
|
|
19
19
|
AgentMessagePartSchema,
|
|
20
20
|
AgentMessageSchema,
|
|
21
21
|
AgentProvenanceSchema,
|
|
22
|
+
AgentRunOperationSchema,
|
|
22
23
|
AgentRunSchema,
|
|
23
24
|
AgentSnapshotSchema,
|
|
24
25
|
runStateForTerminalReason
|
|
25
|
-
} from "./index-
|
|
26
|
+
} from "./index-x15ss2dx.js";
|
|
26
27
|
import {
|
|
27
28
|
isAgentToolError
|
|
28
29
|
} from "./index-3xnq72rz.js";
|
|
@@ -1074,6 +1075,73 @@ function createIdleDeadline(parent, timeoutMs) {
|
|
|
1074
1075
|
};
|
|
1075
1076
|
}
|
|
1076
1077
|
|
|
1078
|
+
// src/agent-runtime/run-operation-lifecycle.ts
|
|
1079
|
+
function createAgentRunOperationLifecycle(config) {
|
|
1080
|
+
let active;
|
|
1081
|
+
const record = async (operation) => {
|
|
1082
|
+
const current = config.currentRun();
|
|
1083
|
+
const snapshot = appliedSnapshot(await config.store.recordRunOperation({
|
|
1084
|
+
conversationId: current.conversationId,
|
|
1085
|
+
runId: current.id,
|
|
1086
|
+
expectedRevision: current.revision,
|
|
1087
|
+
ownerId: config.runtimeEpoch,
|
|
1088
|
+
...current.fencingToken !== undefined && { fencingToken: current.fencingToken },
|
|
1089
|
+
operation
|
|
1090
|
+
}), "run operation");
|
|
1091
|
+
config.acceptSnapshot(snapshot);
|
|
1092
|
+
const run = findRun(snapshot.runs, current.id);
|
|
1093
|
+
active = operation;
|
|
1094
|
+
await config.publish({
|
|
1095
|
+
type: "run-operation",
|
|
1096
|
+
eventId: agentDurableEventId("run-operation", run.id, snapshot.version),
|
|
1097
|
+
conversationId: run.conversationId,
|
|
1098
|
+
runId: run.id,
|
|
1099
|
+
snapshotVersion: snapshot.version,
|
|
1100
|
+
operation,
|
|
1101
|
+
emittedAt: config.now().toISOString()
|
|
1102
|
+
});
|
|
1103
|
+
};
|
|
1104
|
+
return {
|
|
1105
|
+
startCompaction(operationId) {
|
|
1106
|
+
return record(AgentRunOperationSchema.parse({
|
|
1107
|
+
operationId,
|
|
1108
|
+
kind: "compaction",
|
|
1109
|
+
phase: "started",
|
|
1110
|
+
startedAt: config.now().toISOString()
|
|
1111
|
+
}));
|
|
1112
|
+
},
|
|
1113
|
+
startModelRequest(providerCallId, step) {
|
|
1114
|
+
return record(AgentRunOperationSchema.parse({
|
|
1115
|
+
operationId: `${providerCallId}:${step}`,
|
|
1116
|
+
kind: "model-request",
|
|
1117
|
+
phase: "started",
|
|
1118
|
+
step,
|
|
1119
|
+
startedAt: config.now().toISOString()
|
|
1120
|
+
}));
|
|
1121
|
+
},
|
|
1122
|
+
firstOutput() {
|
|
1123
|
+
if (active?.kind !== "model-request" || active.phase !== "started") {
|
|
1124
|
+
return Promise.resolve();
|
|
1125
|
+
}
|
|
1126
|
+
return record(AgentRunOperationSchema.parse({
|
|
1127
|
+
...active,
|
|
1128
|
+
phase: "first-output",
|
|
1129
|
+
firstOutputAt: config.now().toISOString()
|
|
1130
|
+
}));
|
|
1131
|
+
},
|
|
1132
|
+
finish(phase) {
|
|
1133
|
+
if (!active || ["completed", "failed", "cancelled"].includes(active.phase)) {
|
|
1134
|
+
return Promise.resolve();
|
|
1135
|
+
}
|
|
1136
|
+
return record(AgentRunOperationSchema.parse({
|
|
1137
|
+
...active,
|
|
1138
|
+
phase,
|
|
1139
|
+
finishedAt: config.now().toISOString()
|
|
1140
|
+
}));
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1077
1145
|
// src/agent-runtime/run-execution.ts
|
|
1078
1146
|
function snapshotForRunPrompt(snapshot, runId) {
|
|
1079
1147
|
const runIndex = snapshot.runs.findIndex((candidate) => candidate.id === runId);
|
|
@@ -1184,7 +1252,7 @@ function createRunExecutor(dependencies) {
|
|
|
1184
1252
|
let observedVersion = snapshot.version;
|
|
1185
1253
|
const parts = [];
|
|
1186
1254
|
const absorbed = new Map;
|
|
1187
|
-
let
|
|
1255
|
+
let eventsSinceCheckpoint = 0;
|
|
1188
1256
|
let sequence = 0;
|
|
1189
1257
|
let terminalReason = "success";
|
|
1190
1258
|
let nonModelUsage = input.acceptedRun.usage;
|
|
@@ -1199,6 +1267,18 @@ function createRunExecutor(dependencies) {
|
|
|
1199
1267
|
let terminalPolicyName;
|
|
1200
1268
|
const idleDeadline = createIdleDeadline(input.signal, idleTimeoutMs);
|
|
1201
1269
|
const executionSignal = idleDeadline.signal;
|
|
1270
|
+
const operationLifecycle = createAgentRunOperationLifecycle({
|
|
1271
|
+
store: config.store,
|
|
1272
|
+
runtimeEpoch,
|
|
1273
|
+
currentRun: () => run,
|
|
1274
|
+
acceptSnapshot: (next) => {
|
|
1275
|
+
snapshot = next;
|
|
1276
|
+
observedVersion = next.version;
|
|
1277
|
+
run = findRun(next.runs, run.id);
|
|
1278
|
+
},
|
|
1279
|
+
publish,
|
|
1280
|
+
now
|
|
1281
|
+
});
|
|
1202
1282
|
const updateReasoning = (text, metadata) => {
|
|
1203
1283
|
const provider = providerEnvelope(metadata);
|
|
1204
1284
|
if (reasoningPartIndex === undefined) {
|
|
@@ -1256,14 +1336,30 @@ function createRunExecutor(dependencies) {
|
|
|
1256
1336
|
};
|
|
1257
1337
|
try {
|
|
1258
1338
|
if (config.history?.compact) {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1339
|
+
await operationLifecycle.startCompaction(generateId());
|
|
1340
|
+
let compacted;
|
|
1341
|
+
try {
|
|
1342
|
+
compacted = await config.history.compact({
|
|
1343
|
+
conversationId: run.conversationId,
|
|
1344
|
+
store: config.store,
|
|
1345
|
+
signal: executionSignal
|
|
1346
|
+
});
|
|
1347
|
+
snapshot = compacted.snapshot;
|
|
1348
|
+
observedVersion = snapshot.version;
|
|
1349
|
+
run = findRun(snapshot.runs, run.id);
|
|
1350
|
+
await operationLifecycle.finish("completed");
|
|
1351
|
+
} catch (error) {
|
|
1352
|
+
const latest = await config.store.loadRun({
|
|
1353
|
+
conversationId: run.conversationId,
|
|
1354
|
+
runId: run.id
|
|
1355
|
+
});
|
|
1356
|
+
if (latest?.run.ownerId === runtimeEpoch) {
|
|
1357
|
+
observedVersion = latest.snapshotVersion;
|
|
1358
|
+
run = latest.run;
|
|
1359
|
+
}
|
|
1360
|
+
await operationLifecycle.finish(executionSignal.aborted ? "cancelled" : "failed");
|
|
1361
|
+
throw error;
|
|
1362
|
+
}
|
|
1267
1363
|
if (compacted.usage) {
|
|
1268
1364
|
nonModelUsage = addUsage(nonModelUsage, compacted.usage);
|
|
1269
1365
|
usage = modelUsage ? addUsage(nonModelUsage, modelUsage) : nonModelUsage;
|
|
@@ -1418,6 +1514,9 @@ function createRunExecutor(dependencies) {
|
|
|
1418
1514
|
abortSignal: executionSignal,
|
|
1419
1515
|
maxRetries: 0,
|
|
1420
1516
|
stopWhen: stopConditions,
|
|
1517
|
+
onLanguageModelCallStart: async (event) => {
|
|
1518
|
+
await operationLifecycle.startModelRequest(event.callId, step);
|
|
1519
|
+
},
|
|
1421
1520
|
repairToolCall: deferredToolRepair(config.loop?.prepareStep),
|
|
1422
1521
|
...config.loop?.toolApproval && {
|
|
1423
1522
|
toolApproval: config.loop.toolApproval,
|
|
@@ -1428,6 +1527,13 @@ function createRunExecutor(dependencies) {
|
|
|
1428
1527
|
},
|
|
1429
1528
|
...(config.loop?.prepareStep || injection) && {
|
|
1430
1529
|
prepareStep: async (options) => {
|
|
1530
|
+
const previousStep = options.steps.at(-1);
|
|
1531
|
+
if (previousStep) {
|
|
1532
|
+
lastPromptTokens = selectedModel?.normalizeUsage?.({
|
|
1533
|
+
usage: previousStep.usage,
|
|
1534
|
+
providerMetadata: previousStep.providerMetadata
|
|
1535
|
+
})?.inputTokens ?? normalizeSdkUsage(previousStep.usage).inputTokens;
|
|
1536
|
+
}
|
|
1431
1537
|
const prepared = await config.loop?.prepareStep?.({
|
|
1432
1538
|
...options,
|
|
1433
1539
|
...runtimeContext
|
|
@@ -1442,11 +1548,14 @@ function createRunExecutor(dependencies) {
|
|
|
1442
1548
|
});
|
|
1443
1549
|
for await (const part of result.stream) {
|
|
1444
1550
|
idleDeadline.touch();
|
|
1445
|
-
|
|
1551
|
+
eventsSinceCheckpoint += 1;
|
|
1446
1552
|
sequence += 1;
|
|
1447
|
-
if (firstOutputAt === undefined &&
|
|
1553
|
+
if (firstOutputAt === undefined && (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call")) {
|
|
1448
1554
|
firstOutputAt = performance.now();
|
|
1449
1555
|
}
|
|
1556
|
+
if (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call") {
|
|
1557
|
+
await operationLifecycle.firstOutput();
|
|
1558
|
+
}
|
|
1450
1559
|
if (part.type === "text-delta") {
|
|
1451
1560
|
appendText(parts, part.text);
|
|
1452
1561
|
await publish({
|
|
@@ -1552,6 +1661,7 @@ function createRunExecutor(dependencies) {
|
|
|
1552
1661
|
status: "interrupted",
|
|
1553
1662
|
emittedAt: now().toISOString()
|
|
1554
1663
|
});
|
|
1664
|
+
await checkpoint();
|
|
1555
1665
|
throw part.error;
|
|
1556
1666
|
}
|
|
1557
1667
|
const output = isAgentToolError(part.error) ? jsonValue(part.error.output) : { message: "Tool execution failed" };
|
|
@@ -1661,6 +1771,7 @@ function createRunExecutor(dependencies) {
|
|
|
1661
1771
|
terminalReason = part.error instanceof AgentContextOverflowError ? "context_overflow" : "provider_failure";
|
|
1662
1772
|
internalCause = part.error;
|
|
1663
1773
|
} else if (part.type === "finish-step") {
|
|
1774
|
+
await operationLifecycle.finish(part.finishReason === "error" ? "failed" : "completed");
|
|
1664
1775
|
const stepTrace = trace ? config.observe?.rootTrace(trace) : undefined;
|
|
1665
1776
|
const stepUsage = selectedModel.normalizeUsage?.({
|
|
1666
1777
|
usage: part.usage,
|
|
@@ -1696,9 +1807,21 @@ function createRunExecutor(dependencies) {
|
|
|
1696
1807
|
modelUsage = mergeModelTotals(normalizeSdkUsage(part.totalUsage), modelUsage);
|
|
1697
1808
|
usage = nonModelUsage ? addUsage(nonModelUsage, modelUsage) : modelUsage;
|
|
1698
1809
|
}
|
|
1699
|
-
|
|
1810
|
+
const structuralBoundary = [
|
|
1811
|
+
"tool-call",
|
|
1812
|
+
"tool-result",
|
|
1813
|
+
"tool-error",
|
|
1814
|
+
"tool-output-denied",
|
|
1815
|
+
"tool-approval-request",
|
|
1816
|
+
"tool-approval-response",
|
|
1817
|
+
"finish-step"
|
|
1818
|
+
].includes(part.type);
|
|
1819
|
+
if (structuralBoundary || eventsSinceCheckpoint >= checkpointEveryEvents) {
|
|
1700
1820
|
await checkpoint();
|
|
1821
|
+
eventsSinceCheckpoint = 0;
|
|
1822
|
+
}
|
|
1701
1823
|
}
|
|
1824
|
+
await operationLifecycle.finish(executionSignal.aborted ? "cancelled" : terminalReason === "provider_failure" ? "failed" : "completed");
|
|
1702
1825
|
if (terminalPolicyName !== undefined)
|
|
1703
1826
|
terminalReason = "policy_stop";
|
|
1704
1827
|
if (executionSignal.aborted)
|
|
@@ -1732,6 +1855,10 @@ function createRunExecutor(dependencies) {
|
|
|
1732
1855
|
observedVersion = latest.snapshotVersion;
|
|
1733
1856
|
run = latestRun;
|
|
1734
1857
|
}
|
|
1858
|
+
const staleOwner = isToolExecutionControlError(error) && error.reason === "stale_run";
|
|
1859
|
+
if (!staleOwner) {
|
|
1860
|
+
await operationLifecycle.finish(executionSignal.aborted || durableInterrupt ? "cancelled" : "failed");
|
|
1861
|
+
}
|
|
1735
1862
|
if (isToolExecutionControlError(error) || executionSignal.aborted || durableInterrupt) {
|
|
1736
1863
|
terminalReason = executionSignal.aborted ? abortTerminalReason(executionSignal) : "interrupted";
|
|
1737
1864
|
parts.push(AgentMessagePartSchema.parse({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentRuntimeEventSchema
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-4hk633vz.js";
|
|
4
4
|
import {
|
|
5
5
|
AgentMessagePartSchema,
|
|
6
6
|
AgentSnapshotSchema
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-x15ss2dx.js";
|
|
8
8
|
|
|
9
9
|
// src/agent-runtime/control-schema.ts
|
|
10
10
|
import { z } from "zod";
|
|
@@ -82,7 +82,13 @@ var AgentMultiSessionCursorSchema = z.object({
|
|
|
82
82
|
}).strict())
|
|
83
83
|
}).strict();
|
|
84
84
|
function durable(event) {
|
|
85
|
-
return [
|
|
85
|
+
return [
|
|
86
|
+
"admission",
|
|
87
|
+
"assistant-checkpoint",
|
|
88
|
+
"run-state",
|
|
89
|
+
"run-operation",
|
|
90
|
+
"terminal"
|
|
91
|
+
].includes(event.type);
|
|
86
92
|
}
|
|
87
93
|
function advanceAgentMultiSessionCursor(raw, event) {
|
|
88
94
|
const cursor = AgentMultiSessionCursorSchema.parse(raw);
|
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
AgentMessageSchema,
|
|
6
6
|
AgentRecordIdSchema,
|
|
7
7
|
AgentRecordVersionSchema,
|
|
8
|
+
AgentRunOperationSchema,
|
|
8
9
|
AgentRunSchema,
|
|
9
10
|
AgentSnapshotSchema,
|
|
10
11
|
AgentTerminalReasonSchema,
|
|
11
12
|
AgentUsageSchema,
|
|
12
13
|
runStateForTerminalReason
|
|
13
|
-
} from "./index-
|
|
14
|
+
} from "./index-x15ss2dx.js";
|
|
14
15
|
|
|
15
16
|
// src/agent-runtime/conversations.ts
|
|
16
17
|
import { z } from "zod";
|
|
@@ -114,6 +115,14 @@ var CheckpointRunAssistantSchema = z3.object({
|
|
|
114
115
|
assistant: AgentMessageSchema,
|
|
115
116
|
usage: AgentUsageSchema.optional()
|
|
116
117
|
});
|
|
118
|
+
var RecordRunOperationSchema = z3.object({
|
|
119
|
+
conversationId: AgentRecordIdSchema,
|
|
120
|
+
runId: AgentRecordIdSchema,
|
|
121
|
+
expectedRevision: AgentRecordVersionSchema,
|
|
122
|
+
ownerId: z3.string().min(1),
|
|
123
|
+
fencingToken: AgentRecordVersionSchema.optional(),
|
|
124
|
+
operation: AgentRunOperationSchema
|
|
125
|
+
});
|
|
117
126
|
var CommitRunTerminalSchema = z3.object({
|
|
118
127
|
conversationId: AgentRecordIdSchema,
|
|
119
128
|
runId: AgentRecordIdSchema,
|
|
@@ -437,6 +446,19 @@ function reduceStore(current, operation) {
|
|
|
437
446
|
historyMutations: [{ type: "upsert-assistant", message: input.assistant }]
|
|
438
447
|
});
|
|
439
448
|
}
|
|
449
|
+
if (operation.type === "operation" && run) {
|
|
450
|
+
const input = operation.input;
|
|
451
|
+
if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.fencingToken !== undefined && run.fencingToken !== input.fencingToken) {
|
|
452
|
+
return conflict(run.revision);
|
|
453
|
+
}
|
|
454
|
+
const next = AgentRunSchema.parse({
|
|
455
|
+
...run,
|
|
456
|
+
lastOperation: input.operation,
|
|
457
|
+
revision: run.revision + 1,
|
|
458
|
+
updatedAt: new Date().toISOString()
|
|
459
|
+
});
|
|
460
|
+
return applied(current, { runs: replaceRun(current.runs, next) }, { runRecords: [AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })] });
|
|
461
|
+
}
|
|
440
462
|
if (operation.type === "interrupt" && run) {
|
|
441
463
|
if (run.revision !== operation.input.expectedRevision || run.state !== "running") {
|
|
442
464
|
return conflict(run.revision);
|
|
@@ -640,7 +662,7 @@ function createAgentRuntimeStore(driver) {
|
|
|
640
662
|
runIds: referencedRunIds(messages)
|
|
641
663
|
});
|
|
642
664
|
return snapshotOf(head, messages, mergeRunRecords(activeRecords, referencedRecords));
|
|
643
|
-
});
|
|
665
|
+
}, { access: "read" });
|
|
644
666
|
const loadRun = (input) => driver.transaction(async (transaction) => {
|
|
645
667
|
const [stored, record] = await Promise.all([
|
|
646
668
|
driver.head.load(transaction, input.conversationId),
|
|
@@ -658,7 +680,7 @@ function createAgentRuntimeStore(driver) {
|
|
|
658
680
|
run: parsed.run,
|
|
659
681
|
...parsed.terminalAssistant && { assistant: parsed.terminalAssistant }
|
|
660
682
|
});
|
|
661
|
-
});
|
|
683
|
+
}, { access: "read" });
|
|
662
684
|
const listActiveRuns = (conversationId) => driver.transaction(async (transaction) => {
|
|
663
685
|
const [records, messages] = await Promise.all([
|
|
664
686
|
driver.runs.listActive(transaction, conversationId),
|
|
@@ -674,7 +696,7 @@ function createAgentRuntimeStore(driver) {
|
|
|
674
696
|
}
|
|
675
697
|
}
|
|
676
698
|
return orderRuns(messages, runs);
|
|
677
|
-
});
|
|
699
|
+
}, { access: "read" });
|
|
678
700
|
const mutate = (operation) => driver.transaction(async (transaction) => {
|
|
679
701
|
const conversationId = operationConversationId(operation);
|
|
680
702
|
if (await driver.conversations?.isPurged(transaction, conversationId)) {
|
|
@@ -794,6 +816,10 @@ function createAgentRuntimeStore(driver) {
|
|
|
794
816
|
type: "checkpoint",
|
|
795
817
|
input: CheckpointRunAssistantSchema.parse(input)
|
|
796
818
|
}),
|
|
819
|
+
recordRunOperation: (input) => mutate({
|
|
820
|
+
type: "operation",
|
|
821
|
+
input: RecordRunOperationSchema.parse(input)
|
|
822
|
+
}),
|
|
797
823
|
requestRunInterrupt: (input) => mutate({
|
|
798
824
|
type: "interrupt",
|
|
799
825
|
input: RequestRunInterruptSchema.parse(input)
|
|
@@ -988,4 +1014,4 @@ function createMemoryAgentRuntimeStore() {
|
|
|
988
1014
|
return createAgentRuntimeStore(driver);
|
|
989
1015
|
}
|
|
990
1016
|
|
|
991
|
-
export { AgentConversationSummarySchema, AgentConversationPageSchema, AgentConversationMessagePageSchema, AgentConversationPurgeInputSchema, AgentConversationPurgeResultSchema, AgentConversationPurgedError, purgeAgentConversation, AgentStoreConflictSchema, AgentStoreNotFoundSchema, AgentStoreAppliedSchema, AgentStoreDuplicateSchema, AgentStoreMutationResultSchema, AgentRunViewSchema, AcceptInputAndAssignRunSchema, AcquireAgentRunSchema, CheckpointRunAssistantSchema, CommitRunTerminalSchema, RequestRunInterruptSchema, RecoverAgentRunSchema, ReplaceCompactedRangeSchema, AgentRecoverableDescriptorSchema, AgentRecoverablePageSchema, AgentRuntimeHeadSchema, AgentStoredRunSchema, AgentAdmissionReceiptSchema, AgentHistoryMutationSchema, ACTIVE_AGENT_RUN_STATES, createAgentRuntimeStore, createMemoryAgentRuntimeStore };
|
|
1017
|
+
export { AgentConversationSummarySchema, AgentConversationPageSchema, AgentConversationMessagePageSchema, AgentConversationPurgeInputSchema, AgentConversationPurgeResultSchema, AgentConversationPurgedError, purgeAgentConversation, AgentStoreConflictSchema, AgentStoreNotFoundSchema, AgentStoreAppliedSchema, AgentStoreDuplicateSchema, AgentStoreMutationResultSchema, AgentRunViewSchema, AcceptInputAndAssignRunSchema, AcquireAgentRunSchema, CheckpointRunAssistantSchema, RecordRunOperationSchema, CommitRunTerminalSchema, RequestRunInterruptSchema, RecoverAgentRunSchema, ReplaceCompactedRangeSchema, AgentRecoverableDescriptorSchema, AgentRecoverablePageSchema, AgentRuntimeHeadSchema, AgentStoredRunSchema, AgentAdmissionReceiptSchema, AgentHistoryMutationSchema, ACTIVE_AGENT_RUN_STATES, createAgentRuntimeStore, createMemoryAgentRuntimeStore };
|
|
@@ -125,6 +125,54 @@ var AgentRunStateSchema = z.enum([
|
|
|
125
125
|
"abandoned"
|
|
126
126
|
]);
|
|
127
127
|
var AgentRunQueuePrioritySchema = z.enum(["interrupt-next"]);
|
|
128
|
+
var AgentRunOperationKindSchema = z.enum(["model-request", "compaction"]);
|
|
129
|
+
var AgentRunOperationPhaseSchema = z.enum([
|
|
130
|
+
"started",
|
|
131
|
+
"first-output",
|
|
132
|
+
"completed",
|
|
133
|
+
"failed",
|
|
134
|
+
"cancelled"
|
|
135
|
+
]);
|
|
136
|
+
var AgentRunOperationFieldsSchema = z.object({
|
|
137
|
+
operationId: AgentRecordIdSchema,
|
|
138
|
+
kind: AgentRunOperationKindSchema,
|
|
139
|
+
phase: AgentRunOperationPhaseSchema,
|
|
140
|
+
step: z.int().nonnegative().optional(),
|
|
141
|
+
startedAt: AgentTimestampSchema,
|
|
142
|
+
firstOutputAt: AgentTimestampSchema.optional(),
|
|
143
|
+
finishedAt: AgentTimestampSchema.optional()
|
|
144
|
+
});
|
|
145
|
+
var AgentRunOperationSchema = AgentRunOperationFieldsSchema.superRefine((operation, ctx) => {
|
|
146
|
+
if (operation.kind === "model-request" !== (operation.step !== undefined)) {
|
|
147
|
+
ctx.addIssue({
|
|
148
|
+
code: "custom",
|
|
149
|
+
path: ["step"],
|
|
150
|
+
message: "Only a model request has a step identity"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (operation.kind === "compaction" && operation.phase === "first-output") {
|
|
154
|
+
ctx.addIssue({
|
|
155
|
+
code: "custom",
|
|
156
|
+
path: ["phase"],
|
|
157
|
+
message: "Compaction has no first-output phase"
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (operation.phase === "first-output" && operation.firstOutputAt === undefined || operation.phase === "started" && operation.firstOutputAt !== undefined || operation.kind === "compaction" && operation.firstOutputAt !== undefined) {
|
|
161
|
+
ctx.addIssue({
|
|
162
|
+
code: "custom",
|
|
163
|
+
path: ["firstOutputAt"],
|
|
164
|
+
message: "Only model output phases carry the observed first-output timestamp"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const terminal = ["completed", "failed", "cancelled"].includes(operation.phase);
|
|
168
|
+
if (terminal !== (operation.finishedAt !== undefined)) {
|
|
169
|
+
ctx.addIssue({
|
|
170
|
+
code: "custom",
|
|
171
|
+
path: ["finishedAt"],
|
|
172
|
+
message: "A terminal operation phase carries its observed finish timestamp"
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
128
176
|
var AgentTerminalReasonSchema = z.enum([
|
|
129
177
|
"success",
|
|
130
178
|
"policy_stop",
|
|
@@ -204,6 +252,7 @@ var AgentRunFieldsSchema = z.object({
|
|
|
204
252
|
terminalPolicyName: z.string().min(1).optional(),
|
|
205
253
|
absorbedIntoRunId: AgentRecordIdSchema.optional(),
|
|
206
254
|
usage: AgentUsageSchema.optional(),
|
|
255
|
+
lastOperation: AgentRunOperationSchema.optional(),
|
|
207
256
|
createdAt: AgentTimestampSchema,
|
|
208
257
|
updatedAt: AgentTimestampSchema
|
|
209
258
|
});
|
|
@@ -277,4 +326,4 @@ var AgentRunMetricsSchema = z.object({
|
|
|
277
326
|
ttftMs: z.number().nonnegative().optional()
|
|
278
327
|
});
|
|
279
328
|
|
|
280
|
-
export { AgentRecordIdSchema, AgentRecordVersionSchema, AgentTimestampSchema, AgentJsonObjectSchema, AgentProviderEnvelopeSchema, AgentTextPartSchema, AgentReasoningPartSchema, AgentFilePartSchema, AgentSourcePartSchema, AgentToolCallPartSchema, AgentToolResultPartSchema, AgentToolApprovalRequestPartSchema, AgentToolApprovalResponsePartSchema, AgentOpaquePartSchema, AgentControlPartSchema, AgentMessagePartSchema, AgentMessageRoleSchema, AgentMessageStatusSchema, AgentMessageSchema, AgentAssistantPlaceholderSchema, AgentRunStateSchema, AgentRunQueuePrioritySchema, AgentTerminalReasonSchema, runStateForTerminalReason, AgentProvenanceSchema, AgentUsageValueSchema, AgentCostValueSchema, AgentUsageSchema, AgentRunSchema, AgentSnapshotSchema, AgentRunMetricsSchema };
|
|
329
|
+
export { AgentRecordIdSchema, AgentRecordVersionSchema, AgentTimestampSchema, AgentJsonObjectSchema, AgentProviderEnvelopeSchema, AgentTextPartSchema, AgentReasoningPartSchema, AgentFilePartSchema, AgentSourcePartSchema, AgentToolCallPartSchema, AgentToolResultPartSchema, AgentToolApprovalRequestPartSchema, AgentToolApprovalResponsePartSchema, AgentOpaquePartSchema, AgentControlPartSchema, AgentMessagePartSchema, AgentMessageRoleSchema, AgentMessageStatusSchema, AgentMessageSchema, AgentAssistantPlaceholderSchema, AgentRunStateSchema, AgentRunQueuePrioritySchema, AgentRunOperationKindSchema, AgentRunOperationPhaseSchema, AgentRunOperationSchema, AgentTerminalReasonSchema, runStateForTerminalReason, AgentProvenanceSchema, AgentUsageValueSchema, AgentCostValueSchema, AgentUsageSchema, AgentRunSchema, AgentSnapshotSchema, AgentRunMetricsSchema };
|
package/dist/testing.js
CHANGED
|
@@ -7,7 +7,7 @@ import"./index-3z73fh2c.js";
|
|
|
7
7
|
import {
|
|
8
8
|
AgentMessageSchema,
|
|
9
9
|
AgentRunSchema
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-x15ss2dx.js";
|
|
11
11
|
import {
|
|
12
12
|
RealtimeRejectDirectionSchema,
|
|
13
13
|
RealtimeRejectFaultSchema,
|
|
@@ -450,10 +450,34 @@ async function conformanceScenario(store, conversationIds) {
|
|
|
450
450
|
if (!recoverable.items.some((item) => item.run.id === running.id)) {
|
|
451
451
|
throw new Error("A running run must appear in a recoverable scan");
|
|
452
452
|
}
|
|
453
|
+
const operation = await store.recordRunOperation({
|
|
454
|
+
conversationId,
|
|
455
|
+
runId: running.id,
|
|
456
|
+
expectedRevision: checkpointedRun.revision,
|
|
457
|
+
ownerId: "conformance-owner",
|
|
458
|
+
fencingToken: checkpointedRun.fencingToken,
|
|
459
|
+
operation: {
|
|
460
|
+
operationId: "model-call-1:0",
|
|
461
|
+
kind: "model-request",
|
|
462
|
+
phase: "first-output",
|
|
463
|
+
step: 0,
|
|
464
|
+
startedAt: "2026-08-22T00:00:01.800Z",
|
|
465
|
+
firstOutputAt: "2026-08-22T00:00:01.900Z"
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
requireOutcome(operation, "applied");
|
|
469
|
+
const operatedRun = operation.snapshot.runs.find((run) => run.id === running.id);
|
|
470
|
+
if (operatedRun?.lastOperation?.operationId !== "model-call-1:0") {
|
|
471
|
+
throw new Error("Run operation identity did not survive its durable mutation");
|
|
472
|
+
}
|
|
473
|
+
const operatedView = await store.loadRun({ conversationId, runId: running.id });
|
|
474
|
+
if (operatedView?.run.lastOperation?.startedAt !== "2026-08-22T00:00:01.800Z") {
|
|
475
|
+
throw new Error("loadRun did not retain the original operation timestamp");
|
|
476
|
+
}
|
|
453
477
|
const interrupted = await store.requestRunInterrupt({
|
|
454
478
|
conversationId,
|
|
455
479
|
runId: running.id,
|
|
456
|
-
expectedRevision:
|
|
480
|
+
expectedRevision: operatedRun.revision
|
|
457
481
|
});
|
|
458
482
|
requireOutcome(interrupted, "applied");
|
|
459
483
|
const interruptedRun = interrupted.snapshot.runs.find((run) => run.id === running.id);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ZodObject, type ZodType, z } from 'zod';
|
|
2
2
|
import { AsyncOperationCancelResultSchema, type AsyncOperationCapability } from './async-operation-contract.js';
|
|
3
3
|
export { type AsyncOperationCancelResult, AsyncOperationCancelResultSchema, type AsyncOperationCapability, type AsyncOperationSnapshotSchema, type AsyncOperationSnapshotSchemaWithProgress, createAsyncOperationSnapshotSchema, } from './async-operation-contract.js';
|
|
4
|
-
import type { ContractDef, EndpointDef, EndpointToolAnnotations, HttpMethod } from '../contract/index.js';
|
|
4
|
+
import type { ContractDef, EndpointDef, EndpointToolAnnotations, HttpMethod, Transport } from '../contract/index.js';
|
|
5
5
|
import type { Handlers } from '../server/types.js';
|
|
6
6
|
import { type RuntimeToolDefinition, type RuntimeToolDefinitionWithOutput, type RuntimeToolHandlerContext, type RuntimeToolTransport } from './runtime-tool.js';
|
|
7
7
|
export interface AsyncOperationIdentity {
|
|
@@ -148,6 +148,23 @@ interface AsyncOperationContractBaseConfig<TStartInput extends ZodType, TId exte
|
|
|
148
148
|
artifacts?: TArtifacts;
|
|
149
149
|
descriptions?: Partial<Record<AsyncOperationCapability, string>>;
|
|
150
150
|
scopes?: TScopes;
|
|
151
|
+
/**
|
|
152
|
+
* Which transports carry each capability. Absent, an endpoint is a tool on
|
|
153
|
+
* every transport, which is the framework default.
|
|
154
|
+
*
|
|
155
|
+
* It has to be declarable HERE because this contract is built inside the
|
|
156
|
+
* framework: an application that made tools opt-in with
|
|
157
|
+
* `createContractFactory({ toolExposure: 'explicit' })` set that default on
|
|
158
|
+
* its OWN factory, and these endpoints never pass through it. Without this
|
|
159
|
+
* field a consumer who had decided that agents get only the tools it names
|
|
160
|
+
* was still handed `start` and `cancel` — both effectful — with no way to say
|
|
161
|
+
* otherwise short of rebuilding the contract by hand.
|
|
162
|
+
*
|
|
163
|
+
* The default is unchanged on purpose. Unlike the tracking ingest, an async
|
|
164
|
+
* operation is a plausible thing for an agent to start and follow, so this
|
|
165
|
+
* says who decides rather than deciding for everyone.
|
|
166
|
+
*/
|
|
167
|
+
expose?: Partial<Record<AsyncOperationCapability, readonly Transport[]>>;
|
|
151
168
|
}
|
|
152
169
|
export type AsyncOperationContractConfig<TStartInput extends ZodType, TId extends ZodType, TSnapshot extends ZodType, TCancel extends true | undefined = undefined, TResult extends ZodType | undefined = undefined, TArtifacts extends ZodType | undefined = undefined, TScope extends string = 'public', TScopes extends Partial<Record<AsyncOperationCapability, string>> = Record<never, never>> = AsyncOperationContractBaseConfig<TStartInput, TId, TSnapshot, TCancel, TResult, TArtifacts, TScope, TScopes> & {
|
|
153
170
|
startOutput?: never;
|