stitchkit 0.58.0 → 0.59.1
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/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/store-driver.d.ts +199 -24
- package/dist/agent-runtime/store-driver.d.ts.map +1 -1
- package/dist/agent-runtime/store.d.ts +222 -0
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +102 -0
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -0
- package/dist/agent-runtime.d.ts +1 -1
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +416 -182
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/{index-zk5zn2nh.js → index-3nwng7hs.js} +287 -38
- package/dist/testing/agent-store-conformance.d.ts.map +1 -1
- package/dist/testing.js +29 -0
- package/dist/tools/cli-args.d.ts +16 -0
- package/dist/tools/cli-args.d.ts.map +1 -1
- package/dist/tools/cli-command.d.ts +16 -0
- package/dist/tools/cli-command.d.ts.map +1 -1
- package/dist/tools/cli-policy.d.ts +22 -0
- package/dist/tools/cli-policy.d.ts.map +1 -0
- package/dist/tools/cli.d.ts +2 -1
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +1 -1
- package/llms-full.txt +148 -47
- package/package.json +1 -1
package/dist/agent-runtime.js
CHANGED
|
@@ -900,6 +900,8 @@ import {
|
|
|
900
900
|
streamText
|
|
901
901
|
} from "ai";
|
|
902
902
|
import { z as z5 } from "zod";
|
|
903
|
+
|
|
904
|
+
// src/agent-runtime/terminal-commit.ts
|
|
903
905
|
class AgentRuntimeConflictError extends Error {
|
|
904
906
|
constructor(operation) {
|
|
905
907
|
super(`Agent runtime store conflict during ${operation}`);
|
|
@@ -911,6 +913,94 @@ function appliedSnapshot(result, operation) {
|
|
|
911
913
|
return result.snapshot;
|
|
912
914
|
throw new AgentRuntimeConflictError(operation);
|
|
913
915
|
}
|
|
916
|
+
function terminalMessageStatus(reason) {
|
|
917
|
+
if (reason === "success" || reason === "policy_stop")
|
|
918
|
+
return "completed";
|
|
919
|
+
if (reason === "interrupted" || reason === "cancelled" || reason === "shutdown") {
|
|
920
|
+
return "interrupted";
|
|
921
|
+
}
|
|
922
|
+
return "failed";
|
|
923
|
+
}
|
|
924
|
+
function canonicalTerminal(snapshot, runId, retainedAssistant) {
|
|
925
|
+
const run = snapshot.runs.find((candidate) => candidate.id === runId);
|
|
926
|
+
if (!run?.terminalReason)
|
|
927
|
+
return;
|
|
928
|
+
const assistant = snapshot.messages.find((message) => message.id === run.assistantMessageId) ?? retainedAssistant;
|
|
929
|
+
if (snapshot.conversationId !== run.conversationId || !assistant || assistant.id !== run.assistantMessageId || assistant.conversationId !== run.conversationId || assistant.runId !== run.id || assistant.role !== "assistant" || assistant.status !== terminalMessageStatus(run.terminalReason)) {
|
|
930
|
+
throw new AgentRuntimeConflictError("terminal result projection");
|
|
931
|
+
}
|
|
932
|
+
return {
|
|
933
|
+
snapshot,
|
|
934
|
+
run,
|
|
935
|
+
assistant,
|
|
936
|
+
reason: run.terminalReason,
|
|
937
|
+
committedByCaller: false,
|
|
938
|
+
...run.terminalPolicyName && { policyName: run.terminalPolicyName }
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
function interruptedCandidate(candidate, run, now) {
|
|
942
|
+
const hasInterruptControl = candidate.assistant.parts.some((part) => part.type === "control" && part.reason === "run-interrupted");
|
|
943
|
+
const parts = hasInterruptControl ? candidate.assistant.parts : [
|
|
944
|
+
...candidate.assistant.parts,
|
|
945
|
+
AgentMessagePartSchema.parse({ type: "control", reason: "run-interrupted" })
|
|
946
|
+
];
|
|
947
|
+
return {
|
|
948
|
+
run,
|
|
949
|
+
assistant: AgentMessageSchema.parse({
|
|
950
|
+
...candidate.assistant,
|
|
951
|
+
status: "interrupted",
|
|
952
|
+
parts,
|
|
953
|
+
updatedAt: now().toISOString()
|
|
954
|
+
}),
|
|
955
|
+
reason: "interrupted"
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function canRetryTerminal(current, previous, runtimeEpoch) {
|
|
959
|
+
return (current.state === "running" || current.state === "interrupt_requested") && current.ownerId === runtimeEpoch && current.fencingToken === previous.fencingToken;
|
|
960
|
+
}
|
|
961
|
+
async function commitAgentRunTerminal(input) {
|
|
962
|
+
let candidate = input.candidate;
|
|
963
|
+
while (true) {
|
|
964
|
+
const committed = await input.store.commitRunTerminal({
|
|
965
|
+
conversationId: candidate.run.conversationId,
|
|
966
|
+
runId: candidate.run.id,
|
|
967
|
+
expectedRevision: candidate.run.revision,
|
|
968
|
+
ownerId: input.runtimeEpoch,
|
|
969
|
+
...candidate.run.fencingToken !== undefined && {
|
|
970
|
+
fencingToken: candidate.run.fencingToken
|
|
971
|
+
},
|
|
972
|
+
assistant: candidate.assistant,
|
|
973
|
+
reason: candidate.reason,
|
|
974
|
+
...candidate.policyName && { policyName: candidate.policyName }
|
|
975
|
+
});
|
|
976
|
+
if (committed.outcome === "applied") {
|
|
977
|
+
const terminal2 = canonicalTerminal(committed.snapshot, candidate.run.id);
|
|
978
|
+
if (!terminal2)
|
|
979
|
+
throw new AgentRuntimeConflictError("terminal result projection");
|
|
980
|
+
return { ...terminal2, committedByCaller: true };
|
|
981
|
+
}
|
|
982
|
+
if (committed.outcome === "duplicate") {
|
|
983
|
+
const terminal2 = canonicalTerminal(committed.snapshot, candidate.run.id, committed.assistant);
|
|
984
|
+
if (!terminal2)
|
|
985
|
+
throw new AgentRuntimeConflictError("terminal result projection");
|
|
986
|
+
return terminal2;
|
|
987
|
+
}
|
|
988
|
+
if (committed.outcome !== "conflict") {
|
|
989
|
+
throw new AgentRuntimeConflictError("terminal commit");
|
|
990
|
+
}
|
|
991
|
+
const latest = await input.store.loadSnapshot(candidate.run.conversationId);
|
|
992
|
+
const terminal = canonicalTerminal(latest, candidate.run.id);
|
|
993
|
+
if (terminal)
|
|
994
|
+
return terminal;
|
|
995
|
+
const current = latest.runs.find((run) => run.id === candidate.run.id);
|
|
996
|
+
if (!current || !canRetryTerminal(current, candidate.run, input.runtimeEpoch)) {
|
|
997
|
+
throw new AgentRuntimeConflictError("terminal commit");
|
|
998
|
+
}
|
|
999
|
+
candidate = current.state === "interrupt_requested" ? interruptedCandidate(candidate, current, input.now) : { ...candidate, run: current };
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// src/agent-runtime/runtime.ts
|
|
914
1004
|
function findRun(runs, runId) {
|
|
915
1005
|
const run = runs.find((candidate) => candidate.id === runId);
|
|
916
1006
|
if (!run)
|
|
@@ -1547,59 +1637,66 @@ function createAgentRuntime(config) {
|
|
|
1547
1637
|
parts,
|
|
1548
1638
|
updatedAt: now().toISOString()
|
|
1549
1639
|
});
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1640
|
+
const terminal = await commitAgentRunTerminal({
|
|
1641
|
+
store: config.store,
|
|
1642
|
+
runtimeEpoch,
|
|
1643
|
+
candidate: {
|
|
1644
|
+
run,
|
|
1645
|
+
assistant,
|
|
1646
|
+
reason: terminalReason,
|
|
1647
|
+
...terminalPolicyName && { policyName: terminalPolicyName }
|
|
1648
|
+
},
|
|
1649
|
+
now
|
|
1650
|
+
});
|
|
1651
|
+
snapshot = terminal.snapshot;
|
|
1652
|
+
run = terminal.run;
|
|
1653
|
+
assistant = terminal.assistant;
|
|
1654
|
+
terminalReason = terminal.reason;
|
|
1655
|
+
terminalPolicyName = terminal.policyName;
|
|
1656
|
+
const terminalMetrics = terminal.committedByCaller ? {
|
|
1562
1657
|
partial: false,
|
|
1563
1658
|
durationMs: performance.now() - runStartedAt,
|
|
1564
1659
|
...usage && { usage },
|
|
1565
1660
|
...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
|
|
1566
|
-
};
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1661
|
+
} : undefined;
|
|
1662
|
+
if (terminalMetrics) {
|
|
1663
|
+
config.observe?.emit({
|
|
1664
|
+
schemaVersion: 1,
|
|
1665
|
+
eventId: agentDurableEventId("terminal", run.id, snapshot.version),
|
|
1666
|
+
type: "run-terminal",
|
|
1667
|
+
conversationId: run.conversationId,
|
|
1668
|
+
runId: run.id,
|
|
1669
|
+
traceId: trace?.traceId ?? generateId(),
|
|
1670
|
+
spanId: trace?.spanId ?? generateId(),
|
|
1671
|
+
...trace?.parentSpanId && { parentSpanId: trace.parentSpanId },
|
|
1672
|
+
state: run.state,
|
|
1673
|
+
terminalReason,
|
|
1674
|
+
...selectedModel && { modelId: selectedModel.descriptor.modelId },
|
|
1675
|
+
durationMs: terminalMetrics.durationMs,
|
|
1676
|
+
...usage && { usage },
|
|
1677
|
+
...internalCause !== undefined && { internalCause },
|
|
1678
|
+
...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt },
|
|
1679
|
+
emittedAt: now().toISOString()
|
|
1680
|
+
});
|
|
1681
|
+
await publish({
|
|
1682
|
+
type: "terminal",
|
|
1683
|
+
eventId: agentDurableEventId("terminal", run.id, snapshot.version),
|
|
1684
|
+
conversationId: run.conversationId,
|
|
1685
|
+
runId: run.id,
|
|
1686
|
+
snapshotVersion: snapshot.version,
|
|
1687
|
+
reason: terminalReason,
|
|
1688
|
+
...terminalPolicyName && { policyName: terminalPolicyName },
|
|
1689
|
+
message: assistant,
|
|
1690
|
+
metrics: terminalMetrics,
|
|
1691
|
+
emittedAt: now().toISOString()
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1597
1694
|
return {
|
|
1598
1695
|
run,
|
|
1599
1696
|
message: assistant,
|
|
1600
1697
|
reason: terminalReason,
|
|
1601
1698
|
snapshotVersion: snapshot.version,
|
|
1602
|
-
metrics: terminalMetrics,
|
|
1699
|
+
...terminalMetrics && { metrics: terminalMetrics },
|
|
1603
1700
|
...terminalPolicyName && { policyName: terminalPolicyName }
|
|
1604
1701
|
};
|
|
1605
1702
|
};
|
|
@@ -1724,7 +1821,7 @@ function createAgentRuntime(config) {
|
|
|
1724
1821
|
});
|
|
1725
1822
|
const acceptedSnapshot = appliedSnapshot(acceptance, "input acceptance");
|
|
1726
1823
|
const assignedRunId = acceptance.outcome === "duplicate" ? acceptance.runId : reservation?.admission.runId ?? runId;
|
|
1727
|
-
const acceptedRun = findRun(acceptedSnapshot.runs, assignedRunId);
|
|
1824
|
+
const acceptedRun = acceptance.outcome === "duplicate" ? acceptance.run : findRun(acceptedSnapshot.runs, assignedRunId);
|
|
1728
1825
|
const actualInputMessageId = acceptance.outcome === "duplicate" ? acceptance.inputMessageId : userMessage2.id;
|
|
1729
1826
|
const acceptedInput = acceptance.outcome === "duplicate" ? acceptance.input : acceptedSnapshot.messages.find((candidate) => candidate.id === actualInputMessageId);
|
|
1730
1827
|
if (!acceptedInput) {
|
|
@@ -1739,7 +1836,7 @@ function createAgentRuntime(config) {
|
|
|
1739
1836
|
createdAt: acceptedRun.createdAt,
|
|
1740
1837
|
updatedAt: acceptedRun.updatedAt
|
|
1741
1838
|
});
|
|
1742
|
-
const acceptedAssistant = acceptance.outcome === "duplicate" ?
|
|
1839
|
+
const acceptedAssistant = acceptance.outcome === "duplicate" ? acceptance.assistant ?? assistantPlaceholder : assistantPlaceholder;
|
|
1743
1840
|
const admission = {
|
|
1744
1841
|
inputMessageId: acceptedInput.id,
|
|
1745
1842
|
runId: acceptedRun.id,
|
|
@@ -1781,9 +1878,9 @@ function createAgentRuntime(config) {
|
|
|
1781
1878
|
}
|
|
1782
1879
|
return;
|
|
1783
1880
|
}
|
|
1784
|
-
const message =
|
|
1881
|
+
const message = acceptance.assistant;
|
|
1785
1882
|
if (!message) {
|
|
1786
|
-
const error = new Error("Duplicate terminal
|
|
1883
|
+
const error = new Error("Duplicate terminal admission has no retained canonical assistant");
|
|
1787
1884
|
outerResult.reject(error);
|
|
1788
1885
|
if (reservation?.shouldSchedule) {
|
|
1789
1886
|
reservation.admission.completion.reject(error);
|
|
@@ -1996,6 +2093,8 @@ var AgentStoreDuplicateSchema = z6.object({
|
|
|
1996
2093
|
inputMessageId: AgentRecordIdSchema,
|
|
1997
2094
|
runId: AgentRecordIdSchema,
|
|
1998
2095
|
assistantMessageId: AgentRecordIdSchema,
|
|
2096
|
+
run: AgentRunSchema,
|
|
2097
|
+
assistant: AgentMessageSchema.optional(),
|
|
1999
2098
|
snapshot: AgentSnapshotSchema
|
|
2000
2099
|
});
|
|
2001
2100
|
var AgentStoreMutationResultSchema = z6.discriminatedUnion("outcome", [
|
|
@@ -2055,18 +2154,23 @@ var ReplaceCompactedRangeSchema = z6.object({
|
|
|
2055
2154
|
});
|
|
2056
2155
|
// src/agent-runtime/store-driver.ts
|
|
2057
2156
|
import { z as z7 } from "zod";
|
|
2058
|
-
var
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
assistantMessageId: AgentRecordIdSchema
|
|
2157
|
+
var AgentRuntimeHeadSchema = z7.object({
|
|
2158
|
+
schemaVersion: z7.literal(1),
|
|
2159
|
+
conversationId: AgentRecordIdSchema,
|
|
2160
|
+
version: AgentRecordVersionSchema
|
|
2063
2161
|
});
|
|
2064
|
-
var
|
|
2162
|
+
var AgentStoredRunSchema = z7.object({
|
|
2163
|
+
schemaVersion: z7.literal(1),
|
|
2164
|
+
run: AgentRunSchema,
|
|
2165
|
+
terminalAssistant: AgentMessageSchema.optional()
|
|
2166
|
+
});
|
|
2167
|
+
var AgentAdmissionReceiptSchema = z7.object({
|
|
2065
2168
|
schemaVersion: z7.literal(1),
|
|
2066
2169
|
conversationId: AgentRecordIdSchema,
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2170
|
+
idempotencyKey: z7.string().min(1),
|
|
2171
|
+
input: AgentMessageSchema,
|
|
2172
|
+
runId: AgentRecordIdSchema,
|
|
2173
|
+
assistantMessageId: AgentRecordIdSchema
|
|
2070
2174
|
});
|
|
2071
2175
|
var AgentHistoryMutationSchema = z7.discriminatedUnion("type", [
|
|
2072
2176
|
z7.object({ type: z7.literal("admit"), input: AgentMessageSchema }),
|
|
@@ -2092,40 +2196,40 @@ var AgentRecoverableScanInputSchema = z7.object({
|
|
|
2092
2196
|
cursor: z7.string().min(1).optional(),
|
|
2093
2197
|
limit: z7.number().int().min(1).max(1000)
|
|
2094
2198
|
});
|
|
2095
|
-
function
|
|
2096
|
-
return
|
|
2199
|
+
function emptyHead(conversationId) {
|
|
2200
|
+
return AgentRuntimeHeadSchema.parse({
|
|
2097
2201
|
schemaVersion: 1,
|
|
2098
2202
|
conversationId,
|
|
2099
|
-
version: 0
|
|
2100
|
-
runs: [],
|
|
2101
|
-
admissions: []
|
|
2203
|
+
version: 0
|
|
2102
2204
|
});
|
|
2103
2205
|
}
|
|
2104
|
-
function snapshotOf(
|
|
2105
|
-
|
|
2206
|
+
function snapshotOf(head, messages, records) {
|
|
2207
|
+
validateSnapshot(head, messages, records);
|
|
2106
2208
|
return AgentSnapshotSchema.parse({
|
|
2107
2209
|
schemaVersion: 1,
|
|
2108
|
-
conversationId:
|
|
2109
|
-
version:
|
|
2210
|
+
conversationId: head.conversationId,
|
|
2211
|
+
version: head.version,
|
|
2110
2212
|
messages,
|
|
2111
|
-
runs:
|
|
2213
|
+
runs: records.map((record) => record.run).sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id))
|
|
2112
2214
|
});
|
|
2113
2215
|
}
|
|
2114
|
-
function
|
|
2216
|
+
function validateSnapshot(head, messages, records) {
|
|
2115
2217
|
const runIds = new Set;
|
|
2116
2218
|
const assistantIds = new Set;
|
|
2117
2219
|
const messageIds = new Set;
|
|
2118
|
-
const
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2220
|
+
for (const record of records) {
|
|
2221
|
+
const run = record.run;
|
|
2222
|
+
if (run.conversationId !== head.conversationId || runIds.has(run.id) || assistantIds.has(run.assistantMessageId)) {
|
|
2223
|
+
throw new TypeError("Stored agent runs contain inconsistent identities");
|
|
2224
|
+
}
|
|
2225
|
+
if (record.terminalAssistant && (record.terminalAssistant.id !== run.assistantMessageId || record.terminalAssistant.conversationId !== run.conversationId || record.terminalAssistant.runId !== run.id || record.terminalAssistant.role !== "assistant" || run.terminalReason === undefined)) {
|
|
2226
|
+
throw new TypeError("Retained terminal assistant does not match its run");
|
|
2123
2227
|
}
|
|
2124
2228
|
runIds.add(run.id);
|
|
2125
2229
|
assistantIds.add(run.assistantMessageId);
|
|
2126
2230
|
}
|
|
2127
2231
|
for (const message of messages) {
|
|
2128
|
-
if (message.conversationId !==
|
|
2232
|
+
if (message.conversationId !== head.conversationId || messageIds.has(message.id)) {
|
|
2129
2233
|
throw new TypeError("Stored agent history contains inconsistent message identities");
|
|
2130
2234
|
}
|
|
2131
2235
|
messageIds.add(message.id);
|
|
@@ -2133,23 +2237,12 @@ function validateAggregate(state, messages) {
|
|
|
2133
2237
|
throw new TypeError("Stored history occupies a reserved assistant identity");
|
|
2134
2238
|
}
|
|
2135
2239
|
if (message.runId !== undefined) {
|
|
2136
|
-
const run =
|
|
2240
|
+
const run = records.find((candidate) => candidate.run.id === message.runId)?.run;
|
|
2137
2241
|
if (!run || message.role !== "assistant" || run.assistantMessageId !== message.id) {
|
|
2138
2242
|
throw new TypeError("Stored assistant history does not match its reserved run identity");
|
|
2139
2243
|
}
|
|
2140
2244
|
}
|
|
2141
2245
|
}
|
|
2142
|
-
for (const admission of state.admissions) {
|
|
2143
|
-
const run = state.runs.find((candidate) => candidate.id === admission.runId);
|
|
2144
|
-
if (idempotencyKeys.has(admission.idempotencyKey) || admittedInputIds.has(admission.inputMessageId) || !run || run.assistantMessageId !== admission.assistantMessageId || !run.inputMessageIds.includes(admission.inputMessageId)) {
|
|
2145
|
-
throw new TypeError("Stored admission identity is inconsistent with its assigned run");
|
|
2146
|
-
}
|
|
2147
|
-
idempotencyKeys.add(admission.idempotencyKey);
|
|
2148
|
-
admittedInputIds.add(admission.inputMessageId);
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
function recoverableDescriptors(state) {
|
|
2152
|
-
return state.runs.filter((run) => ["queued", "running", "interrupt_requested"].includes(run.state)).map((run) => ({ conversationId: state.conversationId, run }));
|
|
2153
2246
|
}
|
|
2154
2247
|
var RecoverableCursorSchema = z7.tuple([AgentRecordIdSchema, AgentRecordIdSchema]);
|
|
2155
2248
|
function recoverableCursor(input) {
|
|
@@ -2179,7 +2272,7 @@ function terminalState(reason) {
|
|
|
2179
2272
|
return "abandoned";
|
|
2180
2273
|
return "failed";
|
|
2181
2274
|
}
|
|
2182
|
-
function
|
|
2275
|
+
function terminalMessageStatus2(reason) {
|
|
2183
2276
|
if (reason === "success" || reason === "policy_stop")
|
|
2184
2277
|
return "completed";
|
|
2185
2278
|
if (reason === "interrupted" || reason === "cancelled" || reason === "shutdown") {
|
|
@@ -2187,7 +2280,7 @@ function terminalMessageStatus(reason) {
|
|
|
2187
2280
|
}
|
|
2188
2281
|
return "failed";
|
|
2189
2282
|
}
|
|
2190
|
-
function applied(current,
|
|
2283
|
+
function applied(current, input, effects) {
|
|
2191
2284
|
return {
|
|
2192
2285
|
outcome: "applied",
|
|
2193
2286
|
snapshot: AgentSnapshotSchema.parse({
|
|
@@ -2196,27 +2289,14 @@ function applied(current, admissions, input, historyMutation) {
|
|
|
2196
2289
|
runs: input.runs ?? current.runs,
|
|
2197
2290
|
messages: input.messages ?? current.messages
|
|
2198
2291
|
}),
|
|
2199
|
-
|
|
2200
|
-
...
|
|
2292
|
+
...effects?.runRecord && { runRecord: effects.runRecord },
|
|
2293
|
+
...effects?.admissionReceipt && { admissionReceipt: effects.admissionReceipt },
|
|
2294
|
+
...effects?.historyMutation && { historyMutation: effects.historyMutation }
|
|
2201
2295
|
};
|
|
2202
2296
|
}
|
|
2203
|
-
function reduceStore(current,
|
|
2297
|
+
function reduceStore(current, operation) {
|
|
2204
2298
|
if (operation.type === "accept") {
|
|
2205
2299
|
const input = operation.input;
|
|
2206
|
-
const duplicate = currentAdmissions.find((candidate) => candidate.idempotencyKey === input.idempotencyKey);
|
|
2207
|
-
if (duplicate) {
|
|
2208
|
-
if (!duplicateInput) {
|
|
2209
|
-
throw new Error("Duplicate admission input is unavailable from canonical history");
|
|
2210
|
-
}
|
|
2211
|
-
return {
|
|
2212
|
-
outcome: "duplicate",
|
|
2213
|
-
input: duplicateInput,
|
|
2214
|
-
inputMessageId: duplicate.inputMessageId,
|
|
2215
|
-
runId: duplicate.runId,
|
|
2216
|
-
assistantMessageId: duplicate.assistantMessageId,
|
|
2217
|
-
snapshot: current
|
|
2218
|
-
};
|
|
2219
|
-
}
|
|
2220
2300
|
if (input.expectedVersion !== undefined && input.expectedVersion !== current.version) {
|
|
2221
2301
|
return conflict(current.version);
|
|
2222
2302
|
}
|
|
@@ -2233,16 +2313,25 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2233
2313
|
revision: coalescedRun.revision + 1,
|
|
2234
2314
|
updatedAt: new Date().toISOString()
|
|
2235
2315
|
}) : input.run;
|
|
2236
|
-
const
|
|
2316
|
+
const admissionReceipt = AgentAdmissionReceiptSchema.parse({
|
|
2317
|
+
schemaVersion: 1,
|
|
2318
|
+
conversationId: input.input.conversationId,
|
|
2237
2319
|
idempotencyKey: input.idempotencyKey,
|
|
2238
|
-
|
|
2320
|
+
input: input.input,
|
|
2239
2321
|
runId: assignedRun.id,
|
|
2240
2322
|
assistantMessageId: assignedRun.assistantMessageId
|
|
2241
2323
|
});
|
|
2242
|
-
return applied(current,
|
|
2324
|
+
return applied(current, {
|
|
2243
2325
|
messages: [...current.messages, input.input],
|
|
2244
2326
|
runs: coalescedRun ? replaceRun(current.runs, assignedRun) : [...current.runs, assignedRun]
|
|
2245
|
-
}, {
|
|
2327
|
+
}, {
|
|
2328
|
+
runRecord: AgentStoredRunSchema.parse({
|
|
2329
|
+
schemaVersion: 1,
|
|
2330
|
+
run: assignedRun
|
|
2331
|
+
}),
|
|
2332
|
+
admissionReceipt,
|
|
2333
|
+
historyMutation: { type: "admit", input: input.input }
|
|
2334
|
+
});
|
|
2246
2335
|
}
|
|
2247
2336
|
const conversationId = operation.input.conversationId;
|
|
2248
2337
|
const run = operation.type === "compact" ? undefined : current.runs.find((candidate) => candidate.id === operation.input.runId);
|
|
@@ -2262,8 +2351,8 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2262
2351
|
revision: run.revision + 1,
|
|
2263
2352
|
updatedAt: new Date().toISOString()
|
|
2264
2353
|
});
|
|
2265
|
-
return applied(current,
|
|
2266
|
-
|
|
2354
|
+
return applied(current, { runs: replaceRun(current.runs, next) }, {
|
|
2355
|
+
runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
|
|
2267
2356
|
});
|
|
2268
2357
|
}
|
|
2269
2358
|
if (operation.type === "checkpoint" && run) {
|
|
@@ -2276,10 +2365,13 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2276
2365
|
revision: run.revision + 1,
|
|
2277
2366
|
updatedAt: new Date().toISOString()
|
|
2278
2367
|
});
|
|
2279
|
-
return applied(current,
|
|
2368
|
+
return applied(current, {
|
|
2280
2369
|
runs: replaceRun(current.runs, next),
|
|
2281
2370
|
messages: replaceMessage(current.messages, input.assistant)
|
|
2282
|
-
}, {
|
|
2371
|
+
}, {
|
|
2372
|
+
runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next }),
|
|
2373
|
+
historyMutation: { type: "upsert-assistant", message: input.assistant }
|
|
2374
|
+
});
|
|
2283
2375
|
}
|
|
2284
2376
|
if (operation.type === "interrupt" && run) {
|
|
2285
2377
|
if (run.revision !== operation.input.expectedRevision || run.state !== "running") {
|
|
@@ -2291,8 +2383,8 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2291
2383
|
revision: run.revision + 1,
|
|
2292
2384
|
updatedAt: new Date().toISOString()
|
|
2293
2385
|
});
|
|
2294
|
-
return applied(current,
|
|
2295
|
-
|
|
2386
|
+
return applied(current, { runs: replaceRun(current.runs, next) }, {
|
|
2387
|
+
runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
|
|
2296
2388
|
});
|
|
2297
2389
|
}
|
|
2298
2390
|
if (operation.type === "recover" && run) {
|
|
@@ -2330,18 +2422,25 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2330
2422
|
status: "failed",
|
|
2331
2423
|
updatedAt: new Date().toISOString()
|
|
2332
2424
|
});
|
|
2333
|
-
return applied(current,
|
|
2425
|
+
return applied(current, {
|
|
2334
2426
|
runs: replaceRun(current.runs, next),
|
|
2335
2427
|
messages: replaceMessage(current.messages, assistant)
|
|
2336
|
-
}, {
|
|
2428
|
+
}, {
|
|
2429
|
+
runRecord: AgentStoredRunSchema.parse({
|
|
2430
|
+
schemaVersion: 1,
|
|
2431
|
+
run: next,
|
|
2432
|
+
terminalAssistant: assistant
|
|
2433
|
+
}),
|
|
2434
|
+
historyMutation: { type: "upsert-assistant", message: assistant }
|
|
2435
|
+
});
|
|
2337
2436
|
}
|
|
2338
|
-
return applied(current,
|
|
2339
|
-
|
|
2437
|
+
return applied(current, { runs: replaceRun(current.runs, next) }, {
|
|
2438
|
+
runRecord: AgentStoredRunSchema.parse({ schemaVersion: 1, run: next })
|
|
2340
2439
|
});
|
|
2341
2440
|
}
|
|
2342
2441
|
if (operation.type === "terminal" && run) {
|
|
2343
2442
|
const input = operation.input;
|
|
2344
|
-
if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.fencingToken !== undefined && run.fencingToken !== input.fencingToken || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !==
|
|
2443
|
+
if (run.revision !== input.expectedRevision || run.state !== "running" && run.state !== "interrupt_requested" || run.ownerId !== input.ownerId || input.fencingToken !== undefined && run.fencingToken !== input.fencingToken || input.assistant.runId !== run.id || input.assistant.id !== run.assistantMessageId || input.assistant.conversationId !== run.conversationId || input.assistant.role !== "assistant" || input.assistant.status !== terminalMessageStatus2(input.reason)) {
|
|
2345
2444
|
return conflict(run.revision);
|
|
2346
2445
|
}
|
|
2347
2446
|
const next = AgentRunSchema.parse({
|
|
@@ -2352,10 +2451,17 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2352
2451
|
revision: run.revision + 1,
|
|
2353
2452
|
updatedAt: new Date().toISOString()
|
|
2354
2453
|
});
|
|
2355
|
-
return applied(current,
|
|
2454
|
+
return applied(current, {
|
|
2356
2455
|
runs: replaceRun(current.runs, next),
|
|
2357
2456
|
messages: replaceMessage(current.messages, input.assistant)
|
|
2358
|
-
}, {
|
|
2457
|
+
}, {
|
|
2458
|
+
runRecord: AgentStoredRunSchema.parse({
|
|
2459
|
+
schemaVersion: 1,
|
|
2460
|
+
run: next,
|
|
2461
|
+
terminalAssistant: input.assistant
|
|
2462
|
+
}),
|
|
2463
|
+
historyMutation: { type: "upsert-assistant", message: input.assistant }
|
|
2464
|
+
});
|
|
2359
2465
|
}
|
|
2360
2466
|
if (operation.type === "compact") {
|
|
2361
2467
|
const input = operation.input;
|
|
@@ -2377,10 +2483,12 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2377
2483
|
input.summary,
|
|
2378
2484
|
...current.messages.slice(first + positions.length)
|
|
2379
2485
|
];
|
|
2380
|
-
return applied(current,
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2486
|
+
return applied(current, { messages }, {
|
|
2487
|
+
historyMutation: {
|
|
2488
|
+
type: "replace-compacted-range",
|
|
2489
|
+
replacedMessageIds: input.replacedMessageIds,
|
|
2490
|
+
summary: input.summary
|
|
2491
|
+
}
|
|
2384
2492
|
});
|
|
2385
2493
|
}
|
|
2386
2494
|
return { outcome: "not_found" };
|
|
@@ -2388,48 +2496,130 @@ function reduceStore(current, currentAdmissions, operation, duplicateInput) {
|
|
|
2388
2496
|
function operationConversationId(operation) {
|
|
2389
2497
|
return operation.type === "accept" ? operation.input.input.conversationId : operation.input.conversationId;
|
|
2390
2498
|
}
|
|
2499
|
+
function mergeRunRecords(...groups) {
|
|
2500
|
+
const records = new Map;
|
|
2501
|
+
for (const group of groups) {
|
|
2502
|
+
for (const rawRecord of group) {
|
|
2503
|
+
const record = AgentStoredRunSchema.parse(rawRecord);
|
|
2504
|
+
const previous = records.get(record.run.id);
|
|
2505
|
+
if (previous && previous.run.assistantMessageId !== record.run.assistantMessageId) {
|
|
2506
|
+
throw new TypeError("Stored agent run identity changed across normalized records");
|
|
2507
|
+
}
|
|
2508
|
+
records.set(record.run.id, record);
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
return [...records.values()];
|
|
2512
|
+
}
|
|
2513
|
+
function referencedRunIds(messages) {
|
|
2514
|
+
return [...new Set(messages.flatMap((message) => message.runId ? [message.runId] : []))];
|
|
2515
|
+
}
|
|
2516
|
+
function validateAdmissionReceipt(receipt, record, conversationId) {
|
|
2517
|
+
const input = receipt.input;
|
|
2518
|
+
const run = record.run;
|
|
2519
|
+
if (receipt.conversationId !== conversationId || input.conversationId !== conversationId || input.role !== "user" || input.status !== "committed" || input.runId !== undefined || receipt.runId !== run.id || receipt.assistantMessageId !== run.assistantMessageId || !run.inputMessageIds.includes(input.id)) {
|
|
2520
|
+
throw new TypeError("Admission receipt does not match its canonical run assignment");
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2391
2523
|
function createAgentRuntimeStore(driver) {
|
|
2392
2524
|
const loadSnapshot = (conversationId) => driver.transaction(async (transaction) => {
|
|
2393
|
-
const [stored, messages] = await Promise.all([
|
|
2394
|
-
driver.
|
|
2395
|
-
driver.history.load(transaction, conversationId)
|
|
2525
|
+
const [stored, messages, activeRecords] = await Promise.all([
|
|
2526
|
+
driver.head.load(transaction, conversationId),
|
|
2527
|
+
driver.history.load(transaction, conversationId),
|
|
2528
|
+
driver.runs.listActive(transaction, conversationId)
|
|
2396
2529
|
]);
|
|
2397
|
-
|
|
2530
|
+
const head = AgentRuntimeHeadSchema.parse(stored ?? emptyHead(conversationId));
|
|
2531
|
+
const referencedRecords = await driver.runs.loadMany(transaction, {
|
|
2532
|
+
conversationId,
|
|
2533
|
+
runIds: referencedRunIds(messages)
|
|
2534
|
+
});
|
|
2535
|
+
return snapshotOf(head, messages, mergeRunRecords(activeRecords, referencedRecords));
|
|
2398
2536
|
});
|
|
2399
2537
|
const mutate = (operation) => driver.transaction(async (transaction) => {
|
|
2400
2538
|
const conversationId = operationConversationId(operation);
|
|
2401
|
-
const
|
|
2402
|
-
|
|
2403
|
-
driver.
|
|
2539
|
+
const operationRunId = operation.type === "accept" ? operation.input.coalesceIntoRunId : operation.type === "compact" ? undefined : operation.input.runId;
|
|
2540
|
+
const [stored, messages, activeRecords, operationRecord, duplicateReceipt] = await Promise.all([
|
|
2541
|
+
driver.head.load(transaction, conversationId),
|
|
2542
|
+
driver.history.load(transaction, conversationId),
|
|
2543
|
+
driver.runs.listActive(transaction, conversationId),
|
|
2544
|
+
operationRunId ? driver.runs.load(transaction, { conversationId, runId: operationRunId }) : undefined,
|
|
2545
|
+
operation.type === "accept" ? driver.admissions.load(transaction, {
|
|
2546
|
+
conversationId,
|
|
2547
|
+
idempotencyKey: operation.input.idempotencyKey
|
|
2548
|
+
}) : undefined
|
|
2404
2549
|
]);
|
|
2405
|
-
const
|
|
2406
|
-
const
|
|
2407
|
-
const duplicateIdentity = operation.type === "accept" ? state.admissions.find((candidate) => candidate.idempotencyKey === operation.input.idempotencyKey) : undefined;
|
|
2408
|
-
const duplicateInput = duplicateIdentity ? await driver.history.loadById(transaction, {
|
|
2550
|
+
const head = AgentRuntimeHeadSchema.parse(stored ?? emptyHead(conversationId));
|
|
2551
|
+
const referencedRecords = await driver.runs.loadMany(transaction, {
|
|
2409
2552
|
conversationId,
|
|
2410
|
-
|
|
2411
|
-
})
|
|
2412
|
-
|
|
2413
|
-
|
|
2553
|
+
runIds: referencedRunIds(messages)
|
|
2554
|
+
});
|
|
2555
|
+
const records = mergeRunRecords(activeRecords, referencedRecords, operationRecord ? [operationRecord] : []);
|
|
2556
|
+
const current = snapshotOf(head, messages, records);
|
|
2557
|
+
if (duplicateReceipt) {
|
|
2558
|
+
const duplicateRecord = await driver.runs.load(transaction, {
|
|
2559
|
+
conversationId,
|
|
2560
|
+
runId: duplicateReceipt.runId
|
|
2561
|
+
});
|
|
2562
|
+
if (!duplicateRecord) {
|
|
2563
|
+
throw new TypeError("Admission receipt points to a missing canonical run");
|
|
2564
|
+
}
|
|
2565
|
+
validateAdmissionReceipt(duplicateReceipt, duplicateRecord, conversationId);
|
|
2566
|
+
return {
|
|
2567
|
+
outcome: "duplicate",
|
|
2568
|
+
input: duplicateReceipt.input,
|
|
2569
|
+
inputMessageId: duplicateReceipt.input.id,
|
|
2570
|
+
runId: duplicateReceipt.runId,
|
|
2571
|
+
assistantMessageId: duplicateReceipt.assistantMessageId,
|
|
2572
|
+
run: duplicateRecord.run,
|
|
2573
|
+
...duplicateRecord.terminalAssistant && {
|
|
2574
|
+
assistant: duplicateRecord.terminalAssistant
|
|
2575
|
+
},
|
|
2576
|
+
snapshot: snapshotOf(head, messages, mergeRunRecords(records, [duplicateRecord]))
|
|
2577
|
+
};
|
|
2414
2578
|
}
|
|
2415
|
-
|
|
2579
|
+
if (operation.type === "accept") {
|
|
2580
|
+
const inputCollision = await driver.admissions.loadByInputMessageId(transaction, {
|
|
2581
|
+
conversationId,
|
|
2582
|
+
inputMessageId: operation.input.input.id
|
|
2583
|
+
});
|
|
2584
|
+
if (inputCollision) {
|
|
2585
|
+
throw new TypeError("Input message identity is already assigned to an admission");
|
|
2586
|
+
}
|
|
2587
|
+
if (!operation.input.coalesceIntoRunId) {
|
|
2588
|
+
const [runCollision, assistantCollision] = await Promise.all([
|
|
2589
|
+
driver.runs.load(transaction, {
|
|
2590
|
+
conversationId,
|
|
2591
|
+
runId: operation.input.run.id
|
|
2592
|
+
}),
|
|
2593
|
+
driver.runs.loadByAssistantMessageId(transaction, {
|
|
2594
|
+
conversationId,
|
|
2595
|
+
assistantMessageId: operation.input.run.assistantMessageId
|
|
2596
|
+
})
|
|
2597
|
+
]);
|
|
2598
|
+
if (runCollision || assistantCollision) {
|
|
2599
|
+
throw new TypeError("Queued run identities are already reserved");
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
const reduced = reduceStore(current, operation);
|
|
2416
2604
|
if (reduced.outcome !== "applied")
|
|
2417
2605
|
return reduced;
|
|
2418
|
-
const
|
|
2606
|
+
const nextHead = AgentRuntimeHeadSchema.parse({
|
|
2419
2607
|
schemaVersion: 1,
|
|
2420
2608
|
conversationId,
|
|
2421
|
-
version: reduced.snapshot.version
|
|
2422
|
-
runs: reduced.snapshot.runs,
|
|
2423
|
-
admissions: reduced.admissions
|
|
2609
|
+
version: reduced.snapshot.version
|
|
2424
2610
|
});
|
|
2425
|
-
const outcome = await driver.
|
|
2611
|
+
const outcome = await driver.head.compareAndSwap(transaction, {
|
|
2426
2612
|
conversationId,
|
|
2427
2613
|
expectedVersion: current.version,
|
|
2428
|
-
next:
|
|
2429
|
-
recoverable: recoverableDescriptors(nextState)
|
|
2614
|
+
next: nextHead
|
|
2430
2615
|
});
|
|
2431
2616
|
if (outcome.outcome === "conflict")
|
|
2432
2617
|
return conflict(outcome.actualVersion);
|
|
2618
|
+
if (reduced.runRecord)
|
|
2619
|
+
await driver.runs.save(transaction, reduced.runRecord);
|
|
2620
|
+
if (reduced.admissionReceipt) {
|
|
2621
|
+
await driver.admissions.create(transaction, reduced.admissionReceipt);
|
|
2622
|
+
}
|
|
2433
2623
|
if (reduced.historyMutation) {
|
|
2434
2624
|
await driver.history.apply(transaction, reduced.historyMutation);
|
|
2435
2625
|
}
|
|
@@ -2481,10 +2671,16 @@ function createAgentRuntimeStore(driver) {
|
|
|
2481
2671
|
}
|
|
2482
2672
|
};
|
|
2483
2673
|
}
|
|
2484
|
-
function
|
|
2674
|
+
function cloneHeadMap(source) {
|
|
2485
2675
|
return new Map([...source].map(([key, value]) => [
|
|
2486
2676
|
key,
|
|
2487
|
-
|
|
2677
|
+
AgentRuntimeHeadSchema.parse(structuredClone(value))
|
|
2678
|
+
]));
|
|
2679
|
+
}
|
|
2680
|
+
function cloneNestedMap(source, clone) {
|
|
2681
|
+
return new Map([...source].map(([outerKey, values]) => [
|
|
2682
|
+
outerKey,
|
|
2683
|
+
new Map([...values].map(([innerKey, value]) => [innerKey, clone(value)]))
|
|
2488
2684
|
]));
|
|
2489
2685
|
}
|
|
2490
2686
|
function cloneHistoryMap(source) {
|
|
@@ -2494,9 +2690,10 @@ function cloneHistoryMap(source) {
|
|
|
2494
2690
|
]));
|
|
2495
2691
|
}
|
|
2496
2692
|
function createMemoryAgentRuntimeStore() {
|
|
2497
|
-
let
|
|
2693
|
+
let heads = new Map;
|
|
2694
|
+
let runs = new Map;
|
|
2695
|
+
let admissions = new Map;
|
|
2498
2696
|
let histories = new Map;
|
|
2499
|
-
let archivedMessages = new Map;
|
|
2500
2697
|
let transactionTail = Promise.resolve();
|
|
2501
2698
|
const driver = {
|
|
2502
2699
|
async transaction(work) {
|
|
@@ -2509,50 +2706,91 @@ function createMemoryAgentRuntimeStore() {
|
|
|
2509
2706
|
return;
|
|
2510
2707
|
});
|
|
2511
2708
|
const transaction = {
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
new Map([...messages].map(([messageId, message]) => [
|
|
2517
|
-
messageId,
|
|
2518
|
-
AgentMessageSchema.parse(structuredClone(message))
|
|
2519
|
-
]))
|
|
2520
|
-
]))
|
|
2709
|
+
heads: cloneHeadMap(heads),
|
|
2710
|
+
runs: cloneNestedMap(runs, (record) => AgentStoredRunSchema.parse(structuredClone(record))),
|
|
2711
|
+
admissions: cloneNestedMap(admissions, (receipt) => AgentAdmissionReceiptSchema.parse(structuredClone(receipt))),
|
|
2712
|
+
histories: cloneHistoryMap(histories)
|
|
2521
2713
|
};
|
|
2522
2714
|
try {
|
|
2523
2715
|
const result = await work(transaction);
|
|
2524
|
-
|
|
2716
|
+
heads = transaction.heads;
|
|
2717
|
+
runs = transaction.runs;
|
|
2718
|
+
admissions = transaction.admissions;
|
|
2525
2719
|
histories = transaction.histories;
|
|
2526
|
-
archivedMessages = transaction.archivedMessages;
|
|
2527
2720
|
return result;
|
|
2528
2721
|
} finally {
|
|
2529
2722
|
release.resolve();
|
|
2530
2723
|
}
|
|
2531
2724
|
},
|
|
2532
|
-
|
|
2725
|
+
head: {
|
|
2533
2726
|
async load(transaction, conversationId) {
|
|
2534
|
-
const
|
|
2535
|
-
return
|
|
2727
|
+
const head = transaction.heads.get(conversationId);
|
|
2728
|
+
return head ? AgentRuntimeHeadSchema.parse(structuredClone(head)) : undefined;
|
|
2536
2729
|
},
|
|
2537
2730
|
async compareAndSwap(transaction, input) {
|
|
2538
|
-
const current = transaction.
|
|
2731
|
+
const current = transaction.heads.get(input.conversationId);
|
|
2539
2732
|
const actualVersion = current?.version ?? 0;
|
|
2540
2733
|
if (actualVersion !== input.expectedVersion) {
|
|
2541
2734
|
return { outcome: "conflict", actualVersion };
|
|
2542
2735
|
}
|
|
2543
|
-
transaction.
|
|
2736
|
+
transaction.heads.set(input.conversationId, AgentRuntimeHeadSchema.parse(structuredClone(input.next)));
|
|
2544
2737
|
return { outcome: "applied" };
|
|
2545
2738
|
}
|
|
2546
2739
|
},
|
|
2740
|
+
runs: {
|
|
2741
|
+
async load(transaction, input) {
|
|
2742
|
+
const record = transaction.runs.get(input.conversationId)?.get(input.runId);
|
|
2743
|
+
return record ? AgentStoredRunSchema.parse(structuredClone(record)) : undefined;
|
|
2744
|
+
},
|
|
2745
|
+
async loadByAssistantMessageId(transaction, input) {
|
|
2746
|
+
const record = [...transaction.runs.get(input.conversationId)?.values() ?? []].find((candidate) => candidate.run.assistantMessageId === input.assistantMessageId);
|
|
2747
|
+
return record ? AgentStoredRunSchema.parse(structuredClone(record)) : undefined;
|
|
2748
|
+
},
|
|
2749
|
+
async loadMany(transaction, input) {
|
|
2750
|
+
const records = transaction.runs.get(input.conversationId);
|
|
2751
|
+
return input.runIds.flatMap((runId) => {
|
|
2752
|
+
const record = records?.get(runId);
|
|
2753
|
+
return record ? [AgentStoredRunSchema.parse(structuredClone(record))] : [];
|
|
2754
|
+
});
|
|
2755
|
+
},
|
|
2756
|
+
async listActive(transaction, conversationId) {
|
|
2757
|
+
return [...transaction.runs.get(conversationId)?.values() ?? []].filter((record) => ["queued", "running", "interrupt_requested"].includes(record.run.state)).map((record) => AgentStoredRunSchema.parse(structuredClone(record)));
|
|
2758
|
+
},
|
|
2759
|
+
async save(transaction, rawRecord) {
|
|
2760
|
+
const record = AgentStoredRunSchema.parse(structuredClone(rawRecord));
|
|
2761
|
+
const conversationRuns = transaction.runs.get(record.run.conversationId) ?? new Map;
|
|
2762
|
+
const collision = [...conversationRuns.values()].find((candidate) => candidate.run.id !== record.run.id && candidate.run.assistantMessageId === record.run.assistantMessageId);
|
|
2763
|
+
if (collision)
|
|
2764
|
+
throw new TypeError("Assistant message identity is already reserved");
|
|
2765
|
+
conversationRuns.set(record.run.id, record);
|
|
2766
|
+
transaction.runs.set(record.run.conversationId, conversationRuns);
|
|
2767
|
+
}
|
|
2768
|
+
},
|
|
2769
|
+
admissions: {
|
|
2770
|
+
async load(transaction, input) {
|
|
2771
|
+
const receipt = transaction.admissions.get(input.conversationId)?.get(input.idempotencyKey);
|
|
2772
|
+
return receipt ? AgentAdmissionReceiptSchema.parse(structuredClone(receipt)) : undefined;
|
|
2773
|
+
},
|
|
2774
|
+
async loadByInputMessageId(transaction, input) {
|
|
2775
|
+
const receipt = [
|
|
2776
|
+
...transaction.admissions.get(input.conversationId)?.values() ?? []
|
|
2777
|
+
].find((candidate) => candidate.input.id === input.inputMessageId);
|
|
2778
|
+
return receipt ? AgentAdmissionReceiptSchema.parse(structuredClone(receipt)) : undefined;
|
|
2779
|
+
},
|
|
2780
|
+
async create(transaction, rawReceipt) {
|
|
2781
|
+
const receipt = AgentAdmissionReceiptSchema.parse(structuredClone(rawReceipt));
|
|
2782
|
+
const conversationAdmissions = transaction.admissions.get(receipt.conversationId) ?? new Map;
|
|
2783
|
+
if (conversationAdmissions.has(receipt.idempotencyKey) || [...conversationAdmissions.values()].some((candidate) => candidate.input.id === receipt.input.id)) {
|
|
2784
|
+
throw new TypeError("Admission identity is already reserved");
|
|
2785
|
+
}
|
|
2786
|
+
conversationAdmissions.set(receipt.idempotencyKey, receipt);
|
|
2787
|
+
transaction.admissions.set(receipt.conversationId, conversationAdmissions);
|
|
2788
|
+
}
|
|
2789
|
+
},
|
|
2547
2790
|
history: {
|
|
2548
2791
|
async load(transaction, conversationId) {
|
|
2549
2792
|
return (transaction.histories.get(conversationId) ?? []).map((message) => AgentMessageSchema.parse(structuredClone(message)));
|
|
2550
2793
|
},
|
|
2551
|
-
async loadById(transaction, input) {
|
|
2552
|
-
const active = (transaction.histories.get(input.conversationId) ?? []).find((message2) => message2.id === input.messageId);
|
|
2553
|
-
const message = active ?? transaction.archivedMessages.get(input.conversationId)?.get(input.messageId);
|
|
2554
|
-
return message ? AgentMessageSchema.parse(structuredClone(message)) : undefined;
|
|
2555
|
-
},
|
|
2556
2794
|
async apply(transaction, rawMutation) {
|
|
2557
2795
|
const mutation = AgentHistoryMutationSchema.parse(rawMutation);
|
|
2558
2796
|
const conversationId = mutation.type === "admit" ? mutation.input.conversationId : mutation.type === "upsert-assistant" ? mutation.message.conversationId : mutation.summary.conversationId;
|
|
@@ -2570,11 +2808,6 @@ function createMemoryAgentRuntimeStore() {
|
|
|
2570
2808
|
const first = positions[0];
|
|
2571
2809
|
if (first === undefined)
|
|
2572
2810
|
throw new Error("Compaction history range disappeared");
|
|
2573
|
-
const archive = transaction.archivedMessages.get(conversationId) ?? new Map;
|
|
2574
|
-
for (const message of current.filter((candidate) => replaced.has(candidate.id))) {
|
|
2575
|
-
archive.set(message.id, AgentMessageSchema.parse(structuredClone(message)));
|
|
2576
|
-
}
|
|
2577
|
-
transaction.archivedMessages.set(conversationId, archive);
|
|
2578
2811
|
transaction.histories.set(conversationId, [
|
|
2579
2812
|
...current.slice(0, first),
|
|
2580
2813
|
mutation.summary,
|
|
@@ -2583,7 +2816,7 @@ function createMemoryAgentRuntimeStore() {
|
|
|
2583
2816
|
}
|
|
2584
2817
|
},
|
|
2585
2818
|
async scanRecoverable(input) {
|
|
2586
|
-
const descriptors = [...
|
|
2819
|
+
const descriptors = [...runs].flatMap(([conversationId, conversationRuns]) => [...conversationRuns.values()].filter((record) => ["queued", "running", "interrupt_requested"].includes(record.run.state)).map((record) => ({ conversationId, run: record.run }))).sort((left, right) => left.conversationId.localeCompare(right.conversationId) || left.run.id.localeCompare(right.run.id));
|
|
2587
2820
|
const cursorTuple = input.cursor ? parseRecoverableCursor(input.cursor) : undefined;
|
|
2588
2821
|
const start = cursorTuple ? descriptors.findIndex((item) => item.conversationId === cursorTuple[0] && item.run.id === cursorTuple[1]) + 1 : 0;
|
|
2589
2822
|
const items = descriptors.slice(start, start + input.limit);
|
|
@@ -2601,7 +2834,7 @@ export {
|
|
|
2601
2834
|
AcceptInputAndAssignRunSchema,
|
|
2602
2835
|
AcquireAgentRunSchema,
|
|
2603
2836
|
AgentAdmissionEventSchema,
|
|
2604
|
-
|
|
2837
|
+
AgentAdmissionReceiptSchema,
|
|
2605
2838
|
AgentAssistantPlaceholderSchema,
|
|
2606
2839
|
AgentCheckpointEventSchema,
|
|
2607
2840
|
AgentControlPartSchema,
|
|
@@ -2633,6 +2866,7 @@ export {
|
|
|
2633
2866
|
AgentRunStateSchema,
|
|
2634
2867
|
AgentRuntimeEventCursorSchema,
|
|
2635
2868
|
AgentRuntimeEventSchema,
|
|
2869
|
+
AgentRuntimeHeadSchema,
|
|
2636
2870
|
AgentSnapshotSchema,
|
|
2637
2871
|
AgentSourcePartSchema,
|
|
2638
2872
|
AgentStoreAppliedSchema,
|
|
@@ -2640,7 +2874,7 @@ export {
|
|
|
2640
2874
|
AgentStoreDuplicateSchema,
|
|
2641
2875
|
AgentStoreMutationResultSchema,
|
|
2642
2876
|
AgentStoreNotFoundSchema,
|
|
2643
|
-
|
|
2877
|
+
AgentStoredRunSchema,
|
|
2644
2878
|
AgentTerminalEventSchema,
|
|
2645
2879
|
AgentTerminalReasonSchema,
|
|
2646
2880
|
AgentTextPartSchema,
|