@rowan-agent/agent 0.9.3 → 0.9.5
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/index.d.ts +130 -8
- package/dist/index.js +514 -94
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -91,12 +91,12 @@ function buildPhaseDirectiveMessage(phase, output) {
|
|
|
91
91
|
const parts = [];
|
|
92
92
|
parts.push(`<phase_content name="${escapeXml(phase.name)}">`);
|
|
93
93
|
parts.push(phase.content);
|
|
94
|
-
if (output.results && output.results.length > 0) {
|
|
94
|
+
if (output.results && output.results.length > 0 || output.instruction) {
|
|
95
95
|
parts.push(` <prev_phase_outputs>`);
|
|
96
96
|
if (output.instruction) {
|
|
97
97
|
parts.push(` <instruction>${escapeXml(output.instruction)}</instruction>`);
|
|
98
98
|
}
|
|
99
|
-
for (const r of output.results) {
|
|
99
|
+
for (const r of output.results ?? []) {
|
|
100
100
|
parts.push(` <phase name="${escapeXml(r.name)}">`);
|
|
101
101
|
if (r.output !== void 0) {
|
|
102
102
|
parts.push(jsonToXml(r.output, 3));
|
|
@@ -172,18 +172,24 @@ function buildPhaseEntry(p) {
|
|
|
172
172
|
function buildRouteDescription(availablePhases) {
|
|
173
173
|
const phasesBlock = buildStructuredSection("phase", [
|
|
174
174
|
...availablePhases.map(buildPhaseEntry),
|
|
175
|
-
{
|
|
175
|
+
{
|
|
176
|
+
name: "stop",
|
|
177
|
+
description: "Explicitly finish the current user request or task when no further user input is needed"
|
|
178
|
+
}
|
|
176
179
|
]);
|
|
177
180
|
return [
|
|
178
|
-
"Route
|
|
181
|
+
"Route is optional. Omit it when the current reply should wait for more user input and remain in the current phase.",
|
|
179
182
|
"",
|
|
180
183
|
"Rules:",
|
|
181
|
-
"-
|
|
184
|
+
"- Call route only to continue execution immediately in one or more phases, or to explicitly stop.",
|
|
185
|
+
"- `decision` lists phase executions; a single target equal to the current phase starts another iteration of that phase.",
|
|
186
|
+
"- `stop` means the current user request or task is complete and no further user input is needed; `stop` must be the only target.",
|
|
182
187
|
"- Each target may include `phase`, `reason`, `payload`.",
|
|
183
188
|
"- A phase may appear multiple times as independent execution instances.",
|
|
184
189
|
"- `payload` MUST match the phase's `payload_schema`",
|
|
185
190
|
"- `instruction` is optional shared guidance for all phases.",
|
|
186
191
|
"- Executions are independent and concurrent; order is irrelevant.",
|
|
192
|
+
"- Do not call route in the same response as an ordinary tool; finish ordinary tools first.",
|
|
187
193
|
"",
|
|
188
194
|
"<available_phases>",
|
|
189
195
|
phasesBlock,
|
|
@@ -202,12 +208,13 @@ function createRouteTool(availablePhases) {
|
|
|
202
208
|
return {
|
|
203
209
|
name: PhaseRouteTool,
|
|
204
210
|
description: buildRouteDescription(availablePhases),
|
|
205
|
-
promptSnippet: "Route to
|
|
211
|
+
promptSnippet: "Route is optional: omit it to remain in the current phase and wait for user input; use it for immediate phase execution or an explicit stop.",
|
|
206
212
|
promptGuidelines: [
|
|
207
|
-
"
|
|
213
|
+
"Do not call route together with ordinary tools.",
|
|
214
|
+
"Use route(stop) only when the current user request or task is complete and no further user input is needed."
|
|
208
215
|
],
|
|
209
216
|
parameters: Type.Object({
|
|
210
|
-
decision: Type.Array(DecisionTarget, { description: "Phase executions to start" }),
|
|
217
|
+
decision: Type.Array(DecisionTarget, { description: "Phase executions to start", minItems: 1 }),
|
|
211
218
|
instruction: Type.Optional(Type.String({ description: "Overall instruction, passed as context" }))
|
|
212
219
|
}),
|
|
213
220
|
// No-op: this tool is intercepted by phases, never executed via tool execution
|
|
@@ -220,29 +227,35 @@ function createRouteTool(availablePhases) {
|
|
|
220
227
|
};
|
|
221
228
|
}
|
|
222
229
|
function extractRouteCall(toolCalls) {
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
230
|
+
const routeCalls = toolCalls.filter((t) => t.name === PhaseRouteTool);
|
|
231
|
+
if (routeCalls.length !== 1) return void 0;
|
|
232
|
+
const routeCall = routeCalls[0];
|
|
225
233
|
let args;
|
|
226
234
|
if (typeof routeCall.args === "string") {
|
|
227
235
|
try {
|
|
228
|
-
|
|
236
|
+
const parsed = JSON.parse(routeCall.args);
|
|
237
|
+
args = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
229
238
|
} catch {
|
|
230
|
-
return
|
|
239
|
+
return { decision: [{ phase: "" }] };
|
|
231
240
|
}
|
|
232
241
|
} else {
|
|
233
|
-
args = routeCall.args;
|
|
242
|
+
args = routeCall.args !== null && typeof routeCall.args === "object" ? routeCall.args : {};
|
|
234
243
|
}
|
|
235
244
|
const decisionRaw = args.decision;
|
|
236
245
|
let decision = [];
|
|
237
246
|
if (Array.isArray(decisionRaw)) {
|
|
238
247
|
decision = decisionRaw.map((d) => {
|
|
239
|
-
const obj = d;
|
|
248
|
+
const obj = d !== null && typeof d === "object" ? d : {};
|
|
240
249
|
return {
|
|
241
|
-
|
|
250
|
+
// Empty phase is an invalid target sentinel. Never coerce malformed
|
|
251
|
+
// input to stop: only an explicit, valid stop target may terminate.
|
|
252
|
+
phase: typeof obj.phase === "string" ? obj.phase : "",
|
|
242
253
|
reason: typeof obj?.reason === "string" ? obj.reason : void 0,
|
|
243
254
|
payload: obj?.payload
|
|
244
255
|
};
|
|
245
256
|
});
|
|
257
|
+
} else if (decisionRaw !== void 0) {
|
|
258
|
+
decision = [{ phase: "" }];
|
|
246
259
|
}
|
|
247
260
|
return {
|
|
248
261
|
decision,
|
|
@@ -765,6 +778,15 @@ function contentBlocksToMessageContent(blocks) {
|
|
|
765
778
|
});
|
|
766
779
|
}
|
|
767
780
|
|
|
781
|
+
// src/loop/types.ts
|
|
782
|
+
var DEFAULT_MAX_ATTEMPTS = 16;
|
|
783
|
+
function validateMaxAttempts(value) {
|
|
784
|
+
if (value !== void 0 && (!Number.isInteger(value) || value <= 0)) {
|
|
785
|
+
throw new TypeError("maxAttempts must be a positive integer.");
|
|
786
|
+
}
|
|
787
|
+
return value;
|
|
788
|
+
}
|
|
789
|
+
|
|
768
790
|
// src/loop/errors.ts
|
|
769
791
|
var EmptyResponseError = class extends Error {
|
|
770
792
|
code = "empty_response";
|
|
@@ -882,7 +904,7 @@ async function collectStreamResult(input) {
|
|
|
882
904
|
doneResponse = event.response;
|
|
883
905
|
stopReason = event.response?.stopReason;
|
|
884
906
|
const contentBlocks2 = lastPartial?.contentBlocks ?? [];
|
|
885
|
-
const hasContent2 = contentBlocks2.length > 0 || (event.response?.content?.length ?? 0) > 0;
|
|
907
|
+
const hasContent2 = contentBlocks2.length > 0 || (event.response?.content?.length ?? 0) > 0 || (event.response?.toolCalls?.length ?? 0) > 0;
|
|
886
908
|
const shouldStoreContentParts = contentBlocks2.some((block) => block.type !== "text");
|
|
887
909
|
if (activeMessageId && hasContent2 && shouldStoreContentParts) {
|
|
888
910
|
input.message.replaceContent(activeMessageId, contentBlocksToMessageContent(contentBlocks2));
|
|
@@ -905,7 +927,7 @@ async function collectStreamResult(input) {
|
|
|
905
927
|
if (activeMessageId) {
|
|
906
928
|
await input.message.end(activeMessageId);
|
|
907
929
|
}
|
|
908
|
-
const hasContent = (lastPartial?.contentBlocks?.length ?? 0) > 0 || (doneResponse?.content?.length ?? 0) > 0;
|
|
930
|
+
const hasContent = (lastPartial?.contentBlocks?.length ?? 0) > 0 || (doneResponse?.content?.length ?? 0) > 0 || (doneResponse?.toolCalls?.length ?? 0) > 0;
|
|
909
931
|
if (!hasContent && stopReason !== "error" && stopReason !== "aborted") {
|
|
910
932
|
throw new EmptyResponseError();
|
|
911
933
|
}
|
|
@@ -1497,7 +1519,7 @@ function createDefaultPhase() {
|
|
|
1497
1519
|
filePath: "",
|
|
1498
1520
|
baseDir: "",
|
|
1499
1521
|
skills: [],
|
|
1500
|
-
content: "Execute tasks using current context.\nNo planning. No evaluation.\
|
|
1522
|
+
content: "Execute tasks using current context.\nNo planning. No evaluation.\nOmit route when more user input is needed. Use route for immediate phase execution, or route(stop) only when the current user request or task is complete and no further user input is needed."
|
|
1501
1523
|
};
|
|
1502
1524
|
}
|
|
1503
1525
|
|
|
@@ -1821,6 +1843,31 @@ function applyFirstDecision(route, output) {
|
|
|
1821
1843
|
if (first.reason) output.routeReason = first.reason;
|
|
1822
1844
|
if (first.payload !== void 0) output.payload = normalizePayload(first.payload);
|
|
1823
1845
|
}
|
|
1846
|
+
function resolveRouteDecision(route, registry) {
|
|
1847
|
+
if (!route || route.decision.length === 0) return void 0;
|
|
1848
|
+
const requestedCount = route.decision.length;
|
|
1849
|
+
const hasStop = route.decision.some(({ phase }) => phase === "stop");
|
|
1850
|
+
if (hasStop) {
|
|
1851
|
+
if (requestedCount !== 1) return void 0;
|
|
1852
|
+
return { ...route, requestedCount };
|
|
1853
|
+
}
|
|
1854
|
+
const decision = route.decision.filter(({ phase }) => registry.phases.has(phase));
|
|
1855
|
+
if (decision.length === 0) return void 0;
|
|
1856
|
+
return { ...route, decision, requestedCount };
|
|
1857
|
+
}
|
|
1858
|
+
function resolveModelRouteDecision(toolCalls, registry) {
|
|
1859
|
+
return resolveRouteDecision(toolCalls ? extractRouteCall(toolCalls) : void 0, registry);
|
|
1860
|
+
}
|
|
1861
|
+
function resolveHookRouteDecision(output, registry) {
|
|
1862
|
+
if (output.route === void 0 || output.route === "continue") return void 0;
|
|
1863
|
+
return resolveRouteDecision({
|
|
1864
|
+
decision: [{
|
|
1865
|
+
phase: output.route,
|
|
1866
|
+
...output.routeReason ? { reason: output.routeReason } : {},
|
|
1867
|
+
...output.payload === void 0 ? {} : { payload: output.payload }
|
|
1868
|
+
}]
|
|
1869
|
+
}, registry);
|
|
1870
|
+
}
|
|
1824
1871
|
function injectPhaseContent(phase, output, messages, mirror) {
|
|
1825
1872
|
try {
|
|
1826
1873
|
const phaseContent = phase.filePath ? readPhaseContent(phase) : phase.content ?? phase.description ?? "";
|
|
@@ -1952,12 +1999,13 @@ function createToolResultContent(result) {
|
|
|
1952
1999
|
}
|
|
1953
2000
|
];
|
|
1954
2001
|
}
|
|
1955
|
-
function createRouteToolResultContent(toolCall) {
|
|
2002
|
+
function createRouteToolResultContent(toolCall, error) {
|
|
1956
2003
|
return [
|
|
1957
2004
|
{
|
|
1958
2005
|
type: "tool_result",
|
|
1959
2006
|
toolUseId: toolCall.id,
|
|
1960
|
-
content: '{"ok": true}'
|
|
2007
|
+
content: error ? JSON.stringify({ ok: false, error }) : '{"ok": true}',
|
|
2008
|
+
...error ? { isError: true } : {}
|
|
1961
2009
|
}
|
|
1962
2010
|
];
|
|
1963
2011
|
}
|
|
@@ -1967,7 +2015,6 @@ async function executePhaseWithModel(ctx) {
|
|
|
1967
2015
|
);
|
|
1968
2016
|
let output = {
|
|
1969
2017
|
message: "",
|
|
1970
|
-
route: "stop",
|
|
1971
2018
|
phase: ctx.phase.name,
|
|
1972
2019
|
toolCalls: []
|
|
1973
2020
|
};
|
|
@@ -1979,15 +2026,24 @@ async function executePhaseWithModel(ctx) {
|
|
|
1979
2026
|
const collected = await ctx.execution.invokeModel(roundContext);
|
|
1980
2027
|
output = {
|
|
1981
2028
|
message: collected.text,
|
|
1982
|
-
route: "stop",
|
|
1983
2029
|
phase: ctx.phase.name,
|
|
1984
|
-
|
|
2030
|
+
// A route decision sharing a model response with an ordinary Tool is
|
|
2031
|
+
// rejected for this round. Keep ordinary calls visible so they can run,
|
|
2032
|
+
// but do not let the route escape the error/re-decision boundary.
|
|
2033
|
+
toolCalls: collected.toolCalls.some((candidate) => candidate.name === PhaseRouteTool) && collected.toolCalls.some((candidate) => candidate.name !== PhaseRouteTool) ? collected.toolCalls.filter((candidate) => candidate.name !== PhaseRouteTool) : collected.toolCalls
|
|
1985
2034
|
};
|
|
1986
2035
|
for (const toolCall of collected.toolCalls) {
|
|
1987
2036
|
if (toolCall.name !== PhaseRouteTool) continue;
|
|
1988
|
-
const messageId = ctx.messageManager.start(
|
|
1989
|
-
|
|
1990
|
-
|
|
2037
|
+
const messageId = ctx.messageManager.start(
|
|
2038
|
+
"tool",
|
|
2039
|
+
createRouteToolResultContent(
|
|
2040
|
+
toolCall,
|
|
2041
|
+
collected.toolCalls.some((candidate) => candidate.name !== PhaseRouteTool) ? "Route must be called separately after ordinary tools finish; this route decision was ignored." : void 0
|
|
2042
|
+
),
|
|
2043
|
+
{
|
|
2044
|
+
phase: ctx.phase.name
|
|
2045
|
+
}
|
|
2046
|
+
);
|
|
1991
2047
|
await ctx.messageManager.end(messageId);
|
|
1992
2048
|
}
|
|
1993
2049
|
const executableToolCalls = collected.toolCalls.filter(
|
|
@@ -2019,6 +2075,7 @@ async function startPhaseLoop(config, state) {
|
|
|
2019
2075
|
return runPhaseLoop(config, state, registry);
|
|
2020
2076
|
}
|
|
2021
2077
|
async function runPhaseLoop(config, state, registry) {
|
|
2078
|
+
const maxAttempts = validateMaxAttempts(config.maxAttempts) ?? DEFAULT_MAX_ATTEMPTS;
|
|
2022
2079
|
const resumingSuspendedRun = state.status === "suspended" && Boolean(state.currentPhase);
|
|
2023
2080
|
let currentPhaseId = resumingSuspendedRun ? state.currentPhase : registry.entryPhaseId;
|
|
2024
2081
|
let isContinuing = resumingSuspendedRun ? state.continuation?.isContinuing ?? true : false;
|
|
@@ -2030,6 +2087,53 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2030
2087
|
let previousPhaseInputMsgId;
|
|
2031
2088
|
let previousResults = resumingSuspendedRun ? state.continuation?.previousResults?.map((result) => ({ ...result })) ?? [] : [];
|
|
2032
2089
|
let pendingInstruction = resumingSuspendedRun ? state.continuation?.pendingInstruction : void 0;
|
|
2090
|
+
const awaitInput = async (prompt, resumeAsContinuing) => {
|
|
2091
|
+
if (!config.waitForInput) return void 0;
|
|
2092
|
+
const preAbort = LoopGuard.checkAbort(config.signal);
|
|
2093
|
+
if (preAbort.stopReason !== "none") {
|
|
2094
|
+
removePhaseMessage(config.context.messages, previousPhaseMsgId);
|
|
2095
|
+
removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
|
|
2096
|
+
previousPhaseMsgId = void 0;
|
|
2097
|
+
previousPhaseInputMsgId = void 0;
|
|
2098
|
+
return {
|
|
2099
|
+
type: "completed",
|
|
2100
|
+
result: await completeRun(config, state, createOutcome.aborted())
|
|
2101
|
+
};
|
|
2102
|
+
}
|
|
2103
|
+
const requestedAt = createTimestamp();
|
|
2104
|
+
const inputRequest = {
|
|
2105
|
+
phase: currentPhaseId,
|
|
2106
|
+
prompt,
|
|
2107
|
+
requestedAt
|
|
2108
|
+
};
|
|
2109
|
+
state.currentPhase = currentPhaseId;
|
|
2110
|
+
state.status = "suspended";
|
|
2111
|
+
state.attempt = 0;
|
|
2112
|
+
state.continuation = {
|
|
2113
|
+
isContinuing: resumeAsContinuing,
|
|
2114
|
+
previousPayload,
|
|
2115
|
+
previousResults: previousResults.map((result) => ({ ...result })),
|
|
2116
|
+
pendingInstruction,
|
|
2117
|
+
previousPhaseMessageId: previousPhaseMsgId
|
|
2118
|
+
};
|
|
2119
|
+
const userMessages = await config.waitForInput(state, inputRequest);
|
|
2120
|
+
state.status = "running";
|
|
2121
|
+
const abortResult = LoopGuard.checkAbort(config.signal);
|
|
2122
|
+
if (abortResult.stopReason !== "none") {
|
|
2123
|
+
removePhaseMessage(config.context.messages, previousPhaseMsgId);
|
|
2124
|
+
removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
|
|
2125
|
+
previousPhaseMsgId = void 0;
|
|
2126
|
+
previousPhaseInputMsgId = void 0;
|
|
2127
|
+
return {
|
|
2128
|
+
type: "completed",
|
|
2129
|
+
result: await completeRun(config, state, createOutcome.aborted())
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
for (const message of userMessages) {
|
|
2133
|
+
config.context.messages.push(message);
|
|
2134
|
+
}
|
|
2135
|
+
return { type: "continued" };
|
|
2136
|
+
};
|
|
2033
2137
|
while (currentPhaseId) {
|
|
2034
2138
|
const availablePhases = [];
|
|
2035
2139
|
for (const [, phase2] of registry.phases) {
|
|
@@ -2043,6 +2147,19 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2043
2147
|
previousPhaseInputMsgId = void 0;
|
|
2044
2148
|
return completeRun(config, state, createOutcome.aborted());
|
|
2045
2149
|
}
|
|
2150
|
+
if (state.attempt >= maxAttempts) {
|
|
2151
|
+
const input = await awaitInput(
|
|
2152
|
+
`The autonomous Phase execution limit (${maxAttempts}) was reached. Provide input to continue.`,
|
|
2153
|
+
false
|
|
2154
|
+
);
|
|
2155
|
+
if (input?.type === "completed") return input.result;
|
|
2156
|
+
if (input?.type === "continued") {
|
|
2157
|
+
isContinuing = false;
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
throw new Error("Phase execution reached maxAttempts but waitForInput is unavailable.");
|
|
2161
|
+
}
|
|
2162
|
+
state.attempt++;
|
|
2046
2163
|
state.metrics.iterations++;
|
|
2047
2164
|
if (needsCompaction(config.context.messages)) {
|
|
2048
2165
|
const compacted = compactMessages(config.context.messages);
|
|
@@ -2143,13 +2260,9 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2143
2260
|
}
|
|
2144
2261
|
const runtime = { phase, config, state, execution, messageManager, registry, context: phaseContext };
|
|
2145
2262
|
let output = await executePhase(runtime);
|
|
2146
|
-
let
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
if (routeDecision) {
|
|
2150
|
-
applyFirstDecision(routeDecision, output);
|
|
2151
|
-
}
|
|
2152
|
-
}
|
|
2263
|
+
let modelRouteDecision = resolveModelRouteDecision(output.toolCalls, registry);
|
|
2264
|
+
let routeDecision = modelRouteDecision;
|
|
2265
|
+
if (routeDecision) applyFirstDecision(routeDecision, output);
|
|
2153
2266
|
if (config.afterPhase) {
|
|
2154
2267
|
const extAfter = await config.afterPhase(currentPhaseId, output);
|
|
2155
2268
|
if (extAfter.abort) {
|
|
@@ -2161,52 +2274,30 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2161
2274
|
}
|
|
2162
2275
|
if (extAfter.retry && (phase.run || phase.factory)) {
|
|
2163
2276
|
output = await executePhase(runtime);
|
|
2164
|
-
|
|
2277
|
+
modelRouteDecision = resolveModelRouteDecision(output.toolCalls, registry);
|
|
2278
|
+
routeDecision = modelRouteDecision;
|
|
2165
2279
|
if (routeDecision) applyFirstDecision(routeDecision, output);
|
|
2166
2280
|
}
|
|
2167
2281
|
if (extAfter.output) {
|
|
2282
|
+
const hookHasRoute = extAfter.output.route !== void 0;
|
|
2168
2283
|
output = extAfter.output;
|
|
2284
|
+
if (hookHasRoute) {
|
|
2285
|
+
routeDecision = resolveHookRouteDecision(output, registry);
|
|
2286
|
+
} else if (phase.run || phase.factory) {
|
|
2287
|
+
output = { ...output, route: "stop" };
|
|
2288
|
+
routeDecision = void 0;
|
|
2289
|
+
} else {
|
|
2290
|
+
routeDecision = modelRouteDecision;
|
|
2291
|
+
if (routeDecision) applyFirstDecision(routeDecision, output);
|
|
2292
|
+
}
|
|
2169
2293
|
}
|
|
2170
2294
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
if (
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
removePhaseMessage(config.context.messages, previousPhaseMsgId);
|
|
2178
|
-
removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
|
|
2179
|
-
previousPhaseMsgId = void 0;
|
|
2180
|
-
previousPhaseInputMsgId = void 0;
|
|
2181
|
-
return completeRun(config, state, createOutcome.aborted());
|
|
2182
|
-
}
|
|
2183
|
-
const requestedAt = createTimestamp();
|
|
2184
|
-
const inputRequest = {
|
|
2185
|
-
phase: currentPhaseId,
|
|
2186
|
-
prompt: output.message,
|
|
2187
|
-
requestedAt
|
|
2188
|
-
};
|
|
2189
|
-
state.status = "suspended";
|
|
2190
|
-
state.continuation = {
|
|
2191
|
-
isContinuing,
|
|
2192
|
-
previousPayload,
|
|
2193
|
-
previousResults: previousResults.map((result) => ({ ...result })),
|
|
2194
|
-
pendingInstruction,
|
|
2195
|
-
previousPhaseMessageId: previousPhaseMsgId
|
|
2196
|
-
};
|
|
2197
|
-
const userMessages = await config.waitForInput(state, inputRequest);
|
|
2198
|
-
state.status = "running";
|
|
2199
|
-
const abortResult2 = LoopGuard.checkAbort(config.signal);
|
|
2200
|
-
if (abortResult2.stopReason !== "none") {
|
|
2201
|
-
removePhaseMessage(config.context.messages, previousPhaseMsgId);
|
|
2202
|
-
removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
|
|
2203
|
-
previousPhaseMsgId = void 0;
|
|
2204
|
-
previousPhaseInputMsgId = void 0;
|
|
2205
|
-
return completeRun(config, state, createOutcome.aborted());
|
|
2206
|
-
}
|
|
2207
|
-
for (const message of userMessages) {
|
|
2208
|
-
config.context.messages.push(message);
|
|
2209
|
-
}
|
|
2295
|
+
if (phase.run || phase.factory) {
|
|
2296
|
+
if (output.route === void 0 && !routeDecision) output = { ...output, route: "stop" };
|
|
2297
|
+
} else if (!phase.target && output.route === void 0 && !routeDecision) {
|
|
2298
|
+
const input = await awaitInput(output.message, true);
|
|
2299
|
+
if (input?.type === "completed") return input.result;
|
|
2300
|
+
if (input?.type === "continued") {
|
|
2210
2301
|
isContinuing = true;
|
|
2211
2302
|
continue;
|
|
2212
2303
|
}
|
|
@@ -2220,7 +2311,7 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2220
2311
|
isContinuing = true;
|
|
2221
2312
|
continue;
|
|
2222
2313
|
}
|
|
2223
|
-
if (routeDecision && routeDecision.
|
|
2314
|
+
if (routeDecision && routeDecision.requestedCount > 1) {
|
|
2224
2315
|
const contextSnapshot = snapshotMessages(config.context.messages);
|
|
2225
2316
|
const parallelTasks = /* @__PURE__ */ new Map();
|
|
2226
2317
|
const instanceIds = buildInstanceIds(routeDecision.decision.map((t) => t.phase));
|
|
@@ -2239,6 +2330,7 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2239
2330
|
registry,
|
|
2240
2331
|
pt,
|
|
2241
2332
|
payload,
|
|
2333
|
+
routeDecision.instruction,
|
|
2242
2334
|
context,
|
|
2243
2335
|
availablePhases,
|
|
2244
2336
|
instanceId,
|
|
@@ -2251,7 +2343,7 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2251
2343
|
}
|
|
2252
2344
|
const successfulResults = await waitForBackgroundTasks(parallelTasks);
|
|
2253
2345
|
previousResults = successfulResults.map((r) => ({ name: r.instanceId, output: r.payload }));
|
|
2254
|
-
pendingInstruction =
|
|
2346
|
+
pendingInstruction = void 0;
|
|
2255
2347
|
const entryPhaseId = phase.target ?? registry.entryPhaseId;
|
|
2256
2348
|
if (entryPhaseId === "stop") {
|
|
2257
2349
|
removePhaseMessage(config.context.messages, previousPhaseMsgId);
|
|
@@ -2294,6 +2386,7 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
2294
2386
|
});
|
|
2295
2387
|
previousPayload = output.payload;
|
|
2296
2388
|
previousResults = output.payload !== void 0 ? [{ name: phase.name, output: output.payload }] : [];
|
|
2389
|
+
pendingInstruction = phase.target ? void 0 : routeDecision?.instruction;
|
|
2297
2390
|
currentPhaseId = targetPhaseId;
|
|
2298
2391
|
}
|
|
2299
2392
|
throw new Error("Phase machine exited without a stop or abort transition.");
|
|
@@ -2548,10 +2641,10 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
2548
2641
|
}
|
|
2549
2642
|
};
|
|
2550
2643
|
}
|
|
2551
|
-
async function executeParallelPhase(config, state, registry, phase, payload, context, availablePhases, instanceId, groupId, index, count, sourcePhaseId) {
|
|
2644
|
+
async function executeParallelPhase(config, state, registry, phase, payload, instruction, context, availablePhases, instanceId, groupId, index, count, sourcePhaseId) {
|
|
2552
2645
|
const messages = [...context];
|
|
2553
2646
|
const allTools = buildToolsWithRouting(config, availablePhases);
|
|
2554
|
-
const phaseTools = selectPhaseTools(allTools, phase.tools);
|
|
2647
|
+
const phaseTools = selectPhaseTools(allTools, phase.tools, false);
|
|
2555
2648
|
const phaseSkills = mergeSkills(config.context.skills, phase.skills);
|
|
2556
2649
|
const systemPrompt = config.context.systemPrompt;
|
|
2557
2650
|
const phaseContext = {
|
|
@@ -2578,7 +2671,10 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
|
|
|
2578
2671
|
const messageManager = createMessageManager({ messages }, config.onMessage, config.onMessageDelta);
|
|
2579
2672
|
const phaseMsgId = injectPhaseContent(
|
|
2580
2673
|
phase,
|
|
2581
|
-
{
|
|
2674
|
+
{
|
|
2675
|
+
instruction,
|
|
2676
|
+
results: payload !== void 0 ? [{ name: sourcePhaseId, output: payload }] : []
|
|
2677
|
+
},
|
|
2582
2678
|
messages
|
|
2583
2679
|
);
|
|
2584
2680
|
const toolExecutionManager = createToolExecutionManager();
|
|
@@ -2590,8 +2686,8 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
|
|
|
2590
2686
|
const resultPayload = decision?.decision[0]?.payload !== void 0 ? normalizePayload(decision.decision[0].payload) : output.payload;
|
|
2591
2687
|
return { instanceId, phaseId: phase.name, payload: resultPayload, content: output.message };
|
|
2592
2688
|
}
|
|
2593
|
-
function selectPhaseTools(candidates, names) {
|
|
2594
|
-
const routing = candidates.filter(({ name }) => name === PhaseRouteTool);
|
|
2689
|
+
function selectPhaseTools(candidates, names, includeRouting = true) {
|
|
2690
|
+
const routing = includeRouting ? candidates.filter(({ name }) => name === PhaseRouteTool) : [];
|
|
2595
2691
|
const ordinary = candidates.filter(({ name }) => name !== PhaseRouteTool);
|
|
2596
2692
|
return [...selectNamedResources(ordinary, names, "Tool"), ...routing];
|
|
2597
2693
|
}
|
|
@@ -2895,7 +2991,7 @@ function normalizeUserInput(input) {
|
|
|
2895
2991
|
return normalized;
|
|
2896
2992
|
}
|
|
2897
2993
|
function isAssistantMessage(value) {
|
|
2898
|
-
return isRecord3(value) && hasOnlyKeys(value, ["id", "agentId", "runId", "role", "content", "metadata", "sequenceWithinRun", "createdAt", "interrupted"]) && typeof value.id === "string" && typeof value.agentId === "string" && typeof value.runId === "string" && value.role === "assistant" && Number.isInteger(value.sequenceWithinRun) && value.sequenceWithinRun >= 0 && typeof value.createdAt === "string" && isAssistantContent(value.content) && (value.metadata === void 0 || isMetadata(value.metadata)) && (value.interrupted === void 0 || typeof value.interrupted === "boolean");
|
|
2994
|
+
return isRecord3(value) && hasOnlyKeys(value, ["id", "agentId", "runId", "messageRevision", "role", "content", "metadata", "sequenceWithinRun", "createdAt", "interrupted"]) && typeof value.id === "string" && typeof value.agentId === "string" && typeof value.runId === "string" && value.role === "assistant" && (value.messageRevision === void 0 || Number.isInteger(value.messageRevision) && value.messageRevision >= 0) && Number.isInteger(value.sequenceWithinRun) && value.sequenceWithinRun >= 0 && typeof value.createdAt === "string" && isAssistantContent(value.content) && (value.metadata === void 0 || isMetadata(value.metadata)) && (value.interrupted === void 0 || typeof value.interrupted === "boolean");
|
|
2899
2995
|
}
|
|
2900
2996
|
function isToolResult(value) {
|
|
2901
2997
|
if (!isRecord3(value) || !isJsonValue(value.content) || typeof value.ok !== "boolean") return false;
|
|
@@ -3040,6 +3136,7 @@ function validateConfigResolution(agentId, value) {
|
|
|
3040
3136
|
throw new Error(`Config Provider returned an invalid resolution for Agent ${agentId}.`);
|
|
3041
3137
|
}
|
|
3042
3138
|
function snapshotConfig(config) {
|
|
3139
|
+
validateMaxAttempts(config.maxAttempts);
|
|
3043
3140
|
if (isAgentConfiguration(config)) return snapshotConfiguration(config);
|
|
3044
3141
|
const definition = Object.freeze({
|
|
3045
3142
|
...config.definition,
|
|
@@ -3193,6 +3290,7 @@ var ConfigCommandService = class {
|
|
|
3193
3290
|
const reserved = await this.store.reserveAgent({
|
|
3194
3291
|
idempotencyKey: input.idempotencyKey,
|
|
3195
3292
|
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
3293
|
+
...input.historySeed === void 0 ? {} : { historySeed: input.historySeed },
|
|
3196
3294
|
configIdentity: input.config.identity
|
|
3197
3295
|
});
|
|
3198
3296
|
if (reserved.activatedAt && reserved.currentConfigToken) return reserved.id;
|
|
@@ -4999,6 +5097,7 @@ function adaptExtensionTool2(input) {
|
|
|
4999
5097
|
|
|
5000
5098
|
// src/runtime/configuration-snapshot.ts
|
|
5001
5099
|
function resolveConfigurationSnapshot(registry, input) {
|
|
5100
|
+
validateMaxAttempts(input.maxAttempts);
|
|
5002
5101
|
const resolved = registry.resolveView(input.resourceView);
|
|
5003
5102
|
const base = resolved.agents.find(({ name }) => name === input.definition.name);
|
|
5004
5103
|
if (!base) {
|
|
@@ -5179,6 +5278,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5179
5278
|
return this.commands.createAgent({
|
|
5180
5279
|
config,
|
|
5181
5280
|
...options.metadata === void 0 ? {} : { metadata: options.metadata },
|
|
5281
|
+
...options.historySeed === void 0 ? {} : { historySeed: options.historySeed },
|
|
5182
5282
|
idempotencyKey: options.idempotencyKey ?? crypto.randomUUID()
|
|
5183
5283
|
});
|
|
5184
5284
|
}
|
|
@@ -5196,6 +5296,23 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5196
5296
|
}
|
|
5197
5297
|
await this.owned.deleteAgent(input);
|
|
5198
5298
|
}
|
|
5299
|
+
async revise(agentId, input) {
|
|
5300
|
+
this.assertOpen();
|
|
5301
|
+
const result = await this.owned.reviseMessage({ agentId, ...input });
|
|
5302
|
+
for (const runId of result.invalidatedRunIds) {
|
|
5303
|
+
const execution = this.executions.get(runId);
|
|
5304
|
+
if (execution) {
|
|
5305
|
+
execution.controller.abort();
|
|
5306
|
+
this.transientEvents.clear(runId, execution.executionId);
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
void this.pump();
|
|
5310
|
+
return result;
|
|
5311
|
+
}
|
|
5312
|
+
async compact(input = {}) {
|
|
5313
|
+
this.assertOpen();
|
|
5314
|
+
return this.owned.compact(input);
|
|
5315
|
+
}
|
|
5199
5316
|
async start(agentId, input, options) {
|
|
5200
5317
|
this.assertOpen();
|
|
5201
5318
|
const agent = await this.requireAgent(agentId);
|
|
@@ -5249,6 +5366,10 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5249
5366
|
this.assertOpen();
|
|
5250
5367
|
return this.owned.snapshotRun(runId);
|
|
5251
5368
|
}
|
|
5369
|
+
async history(agentId) {
|
|
5370
|
+
this.assertOpen();
|
|
5371
|
+
return this.owned.history(agentId);
|
|
5372
|
+
}
|
|
5252
5373
|
async respond(runId, input) {
|
|
5253
5374
|
this.assertOpen();
|
|
5254
5375
|
const snapshot = await this.owned.snapshotRun(runId);
|
|
@@ -5762,6 +5883,11 @@ function normalizePhaseRegistry(registry) {
|
|
|
5762
5883
|
if (registry?.phases.has(DEFAULT_PHASE_ID) && registry.phases.get(DEFAULT_PHASE_ID)?.filePath !== "") {
|
|
5763
5884
|
throw new TypeError(`Configured Phase collides with Rowan built-in Phase "${DEFAULT_PHASE_ID}".`);
|
|
5764
5885
|
}
|
|
5886
|
+
for (const [name] of registry?.phases ?? []) {
|
|
5887
|
+
if (name === "stop" || name === "continue") {
|
|
5888
|
+
throw new TypeError(`Configured Phase name "${name}" is reserved by Rowan routing controls.`);
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5765
5891
|
return {
|
|
5766
5892
|
phases: new Map([
|
|
5767
5893
|
[DEFAULT_PHASE_ID, createDefaultPhase()],
|
|
@@ -5793,6 +5919,7 @@ function deferred2() {
|
|
|
5793
5919
|
}
|
|
5794
5920
|
|
|
5795
5921
|
// src/runtime/durable-store.ts
|
|
5922
|
+
import { createHash } from "crypto";
|
|
5796
5923
|
var InMemoryStore = class _InMemoryStore {
|
|
5797
5924
|
incarnation;
|
|
5798
5925
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -5802,12 +5929,14 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5802
5929
|
events = [];
|
|
5803
5930
|
idempotency = /* @__PURE__ */ new Map();
|
|
5804
5931
|
operationReceipts = /* @__PURE__ */ new Map();
|
|
5932
|
+
historySeeds = /* @__PURE__ */ new Map();
|
|
5805
5933
|
consumerCheckpoints = /* @__PURE__ */ new Map();
|
|
5806
5934
|
nextAgentSequence = /* @__PURE__ */ new Map();
|
|
5807
5935
|
nextReadySequence = /* @__PURE__ */ new Map();
|
|
5808
5936
|
owner;
|
|
5809
5937
|
ownerEpoch = 0;
|
|
5810
5938
|
eventSequence = 0;
|
|
5939
|
+
retentionFloor = 1;
|
|
5811
5940
|
constructor(options = {}) {
|
|
5812
5941
|
this.incarnation = options.incarnation ?? createId("store");
|
|
5813
5942
|
}
|
|
@@ -5820,10 +5949,12 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5820
5949
|
store.events.push(...clone(state.events));
|
|
5821
5950
|
for (const [key, receipt] of state.idempotency) store.idempotency.set(key, clone(receipt));
|
|
5822
5951
|
for (const [key, receipt] of state.operationReceipts) store.operationReceipts.set(key, clone(receipt));
|
|
5952
|
+
for (const [agentId, messages] of state.historySeeds ?? []) store.historySeeds.set(agentId, clone(messages));
|
|
5823
5953
|
for (const [consumerId, cursor] of state.consumerCheckpoints ?? []) store.consumerCheckpoints.set(consumerId, cursor);
|
|
5824
5954
|
for (const [agentId, sequence] of state.nextAgentSequence) store.nextAgentSequence.set(agentId, sequence);
|
|
5825
5955
|
for (const [agentId, sequence] of state.nextReadySequence) store.nextReadySequence.set(agentId, sequence);
|
|
5826
5956
|
store.eventSequence = state.eventSequence;
|
|
5957
|
+
store.retentionFloor = Math.max(1, state.retentionFloor ?? 1);
|
|
5827
5958
|
store.ownerEpoch = Math.max(
|
|
5828
5959
|
0,
|
|
5829
5960
|
...state.runs.map((run) => run.execution?.ownerEpoch ?? 0)
|
|
@@ -5840,7 +5971,9 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5840
5971
|
events: this.events,
|
|
5841
5972
|
idempotency: [...this.idempotency.entries()],
|
|
5842
5973
|
operationReceipts: [...this.operationReceipts.entries()],
|
|
5974
|
+
historySeeds: [...this.historySeeds.entries()],
|
|
5843
5975
|
consumerCheckpoints: [...this.consumerCheckpoints.entries()],
|
|
5976
|
+
retentionFloor: this.retentionFloor,
|
|
5844
5977
|
nextAgentSequence: [...this.nextAgentSequence.entries()],
|
|
5845
5978
|
nextReadySequence: [...this.nextReadySequence.entries()],
|
|
5846
5979
|
eventSequence: this.eventSequence
|
|
@@ -5916,7 +6049,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5916
6049
|
const scope = createIdempotencyScope("create_agent", input.idempotencyKey);
|
|
5917
6050
|
const payload = canonicalJson({
|
|
5918
6051
|
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
5919
|
-
...input.configIdentity === void 0 ? {} : { configIdentity: input.configIdentity }
|
|
6052
|
+
...input.configIdentity === void 0 ? {} : { configIdentity: input.configIdentity },
|
|
6053
|
+
...input.historySeed === void 0 ? {} : { historySeed: input.historySeed }
|
|
5920
6054
|
});
|
|
5921
6055
|
const replay = this.replay(scope, payload);
|
|
5922
6056
|
if (replay) return clone(replay);
|
|
@@ -5928,6 +6062,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5928
6062
|
updatedAt: timestamp
|
|
5929
6063
|
};
|
|
5930
6064
|
this.agents.set(agent.id, agent);
|
|
6065
|
+
if (input.historySeed && input.historySeed.length > 0) this.historySeeds.set(agent.id, materializeHistorySeed(agent.id, input.historySeed));
|
|
5931
6066
|
this.nextAgentSequence.set(agent.id, 0);
|
|
5932
6067
|
this.nextReadySequence.set(agent.id, 0);
|
|
5933
6068
|
this.writeReceipt(scope, payload, agent);
|
|
@@ -5975,6 +6110,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5975
6110
|
this.agents.delete(agent.id);
|
|
5976
6111
|
this.nextAgentSequence.delete(agent.id);
|
|
5977
6112
|
this.nextReadySequence.delete(agent.id);
|
|
6113
|
+
this.historySeeds.delete(agent.id);
|
|
5978
6114
|
for (const run of runs) this.runs.delete(run.id);
|
|
5979
6115
|
for (const [messageId, message] of this.messages) {
|
|
5980
6116
|
if (runIds.has(message.runId)) this.messages.delete(messageId);
|
|
@@ -5992,6 +6128,140 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
5992
6128
|
if (key.includes(String(agent.id)) || [...runIds].some((runId) => key.includes(String(runId)))) this.operationReceipts.delete(key);
|
|
5993
6129
|
}
|
|
5994
6130
|
}
|
|
6131
|
+
reviseMessage(lease, input) {
|
|
6132
|
+
this.assertOwner(lease);
|
|
6133
|
+
if (!Number.isInteger(input.expectedMessageRevision) || input.expectedMessageRevision < 0) {
|
|
6134
|
+
throw new TypeError("expectedMessageRevision must be a non-negative integer");
|
|
6135
|
+
}
|
|
6136
|
+
if (typeof input.operationId !== "string" || input.operationId.length === 0) throw new TypeError("operationId must be non-empty");
|
|
6137
|
+
const normalized = normalizeUserInput({ content: input.content });
|
|
6138
|
+
const operationKey = `revise_message:${input.agentId}:${input.operationId}`;
|
|
6139
|
+
const operationPayload = canonicalJson([
|
|
6140
|
+
input.messageId,
|
|
6141
|
+
input.expectedMessageRevision,
|
|
6142
|
+
normalized,
|
|
6143
|
+
input.effectDigestConfirmation ?? null
|
|
6144
|
+
]);
|
|
6145
|
+
const replay = this.replayOperation(operationKey, operationPayload);
|
|
6146
|
+
if (replay) return clone(replay);
|
|
6147
|
+
const agent = this.requireAgent(input.agentId);
|
|
6148
|
+
const seed = this.historySeeds.get(agent.id) ?? [];
|
|
6149
|
+
const original = this.messages.get(input.messageId) ?? seed.find(({ id }) => id === input.messageId);
|
|
6150
|
+
if (!original || original.agentId !== agent.id || original.role !== "user") {
|
|
6151
|
+
throw new RuntimeError("message_revision_conflict", {
|
|
6152
|
+
agentId: agent.id,
|
|
6153
|
+
messageId: input.messageId,
|
|
6154
|
+
expected: input.expectedMessageRevision,
|
|
6155
|
+
actual: -1
|
|
6156
|
+
});
|
|
6157
|
+
}
|
|
6158
|
+
const actualRevision = original.messageRevision ?? 0;
|
|
6159
|
+
if (actualRevision !== input.expectedMessageRevision) {
|
|
6160
|
+
throw new RuntimeError("message_revision_conflict", {
|
|
6161
|
+
agentId: agent.id,
|
|
6162
|
+
messageId: input.messageId,
|
|
6163
|
+
expected: input.expectedMessageRevision,
|
|
6164
|
+
actual: actualRevision
|
|
6165
|
+
});
|
|
6166
|
+
}
|
|
6167
|
+
const targetRun = this.runs.get(original.runId);
|
|
6168
|
+
const isSeedMessage = !targetRun && seed.some(({ id }) => id === original.id);
|
|
6169
|
+
if (!targetRun && !isSeedMessage) {
|
|
6170
|
+
throw new RuntimeError("message_revision_conflict", {
|
|
6171
|
+
agentId: agent.id,
|
|
6172
|
+
messageId: input.messageId,
|
|
6173
|
+
expected: input.expectedMessageRevision,
|
|
6174
|
+
actual: actualRevision
|
|
6175
|
+
});
|
|
6176
|
+
}
|
|
6177
|
+
const targetAgentSequence = targetRun?.agentSequence ?? -1;
|
|
6178
|
+
const affectedRuns = [...this.runs.values()].filter((run) => run.agentId === agent.id && run.agentSequence >= targetAgentSequence).sort((left, right) => left.agentSequence - right.agentSequence);
|
|
6179
|
+
const affectedRunIds = affectedRuns.map((run) => run.id);
|
|
6180
|
+
const affectedRunSet = new Set(affectedRunIds);
|
|
6181
|
+
const affectedTools = [...this.toolCalls.values()].filter((toolCall) => affectedRunSet.has(toolCall.runId)).sort((left, right) => String(left.id).localeCompare(String(right.id)));
|
|
6182
|
+
const effectDigest = affectedTools.length > 0 ? digestToolEffects(affectedTools) : void 0;
|
|
6183
|
+
if (effectDigest && input.effectDigestConfirmation !== effectDigest) {
|
|
6184
|
+
throw new RuntimeError("tool_effect_confirmation_required", {
|
|
6185
|
+
agentId: agent.id,
|
|
6186
|
+
messageId: input.messageId,
|
|
6187
|
+
effectDigest,
|
|
6188
|
+
toolCallIds: affectedTools.map((toolCall) => toolCall.id)
|
|
6189
|
+
});
|
|
6190
|
+
}
|
|
6191
|
+
const timestamp = createTimestamp();
|
|
6192
|
+
const replacementRun = {
|
|
6193
|
+
id: createId("run"),
|
|
6194
|
+
agentId: agent.id,
|
|
6195
|
+
agentSequence: this.nextSequence(agent.id),
|
|
6196
|
+
readySequence: this.nextReady(agent.id),
|
|
6197
|
+
revision: 0,
|
|
6198
|
+
state: "queued",
|
|
6199
|
+
input: targetInput(normalized, original.metadata),
|
|
6200
|
+
initialMessageId: original.id,
|
|
6201
|
+
...(targetRun?.pinnedConfigToken ?? this.agents.get(agent.id)?.currentConfigToken) === void 0 ? {} : { pinnedConfigToken: targetRun?.pinnedConfigToken ?? this.agents.get(agent.id)?.currentConfigToken },
|
|
6202
|
+
createdAt: timestamp,
|
|
6203
|
+
updatedAt: timestamp
|
|
6204
|
+
};
|
|
6205
|
+
for (const run of affectedRuns) {
|
|
6206
|
+
const previousState = run.state;
|
|
6207
|
+
run.invalidatedBy = { messageId: original.id, messageRevision: actualRevision + 1 };
|
|
6208
|
+
if (run.state === "running" || run.state === "queued" || run.state === "input_required") {
|
|
6209
|
+
if (run.state === "running") {
|
|
6210
|
+
const openToolCalls = [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.state === "pending" || toolCall.state === "running"));
|
|
6211
|
+
for (const toolCall of openToolCalls) this.interruptToolCall(run, toolCall, "Run superseded by Message revision.");
|
|
6212
|
+
} else {
|
|
6213
|
+
delete run.openInputRequest;
|
|
6214
|
+
delete run.checkpoint;
|
|
6215
|
+
}
|
|
6216
|
+
delete run.execution;
|
|
6217
|
+
run.state = "cancelled";
|
|
6218
|
+
run.cancellationReason = "Run superseded by Message revision.";
|
|
6219
|
+
run.revision += 1;
|
|
6220
|
+
run.updatedAt = timestamp;
|
|
6221
|
+
this.appendTransition(run, previousState, "cancelled", void 0, void 0, void 0, void 0, run.cancellationReason);
|
|
6222
|
+
} else {
|
|
6223
|
+
run.revision += 1;
|
|
6224
|
+
run.updatedAt = timestamp;
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
for (const [messageId, message] of this.messages) {
|
|
6228
|
+
if (!affectedRunSet.has(message.runId)) continue;
|
|
6229
|
+
if (message.runId !== original.runId || message.sequenceWithinRun > original.sequenceWithinRun) this.messages.delete(messageId);
|
|
6230
|
+
}
|
|
6231
|
+
if (isSeedMessage) {
|
|
6232
|
+
const targetIndex = seed.findIndex(({ id }) => id === original.id);
|
|
6233
|
+
if (targetIndex >= 0) this.historySeeds.set(agent.id, seed.slice(0, targetIndex));
|
|
6234
|
+
}
|
|
6235
|
+
const revisedMessage = {
|
|
6236
|
+
...clone(original),
|
|
6237
|
+
runId: replacementRun.id,
|
|
6238
|
+
content: userInputContent(normalized),
|
|
6239
|
+
messageRevision: actualRevision + 1,
|
|
6240
|
+
sequenceWithinRun: 0,
|
|
6241
|
+
createdAt: timestamp
|
|
6242
|
+
};
|
|
6243
|
+
this.messages.set(revisedMessage.id, revisedMessage);
|
|
6244
|
+
this.runs.set(replacementRun.id, replacementRun);
|
|
6245
|
+
this.appendTransition(replacementRun, null, "queued");
|
|
6246
|
+
this.events.push({
|
|
6247
|
+
...this.baseEvent(replacementRun),
|
|
6248
|
+
kind: "message_revised",
|
|
6249
|
+
message: revisedMessage,
|
|
6250
|
+
previousRevision: actualRevision,
|
|
6251
|
+
invalidatedRunIds: affectedRunIds,
|
|
6252
|
+
targetRunId: original.runId,
|
|
6253
|
+
cutoffSequenceWithinRun: original.sequenceWithinRun
|
|
6254
|
+
});
|
|
6255
|
+
const result = {
|
|
6256
|
+
message: clone(revisedMessage),
|
|
6257
|
+
replacementRun: clone(replacementRun),
|
|
6258
|
+
invalidatedRunIds: affectedRunIds,
|
|
6259
|
+
affectedToolCallIds: affectedTools.map((toolCall) => toolCall.id),
|
|
6260
|
+
...effectDigest === void 0 ? {} : { effectDigest }
|
|
6261
|
+
};
|
|
6262
|
+
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
6263
|
+
return clone(result);
|
|
6264
|
+
}
|
|
5995
6265
|
createRun(lease, input) {
|
|
5996
6266
|
this.assertOwner(lease);
|
|
5997
6267
|
this.requireAgent(input.agentId);
|
|
@@ -6039,7 +6309,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6039
6309
|
}
|
|
6040
6310
|
if (!run.pinnedConfigToken && input.configToken) run.pinnedConfigToken = input.configToken;
|
|
6041
6311
|
let message;
|
|
6042
|
-
if (!run.checkpoint) {
|
|
6312
|
+
if (!run.checkpoint && !run.initialMessageId) {
|
|
6043
6313
|
const userInput = normalizeUserInput(run.input);
|
|
6044
6314
|
message = {
|
|
6045
6315
|
id: input.messageId ?? createId("msg"),
|
|
@@ -6064,7 +6334,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6064
6334
|
run.updatedAt = createTimestamp();
|
|
6065
6335
|
if (message) this.appendMessage(run, message);
|
|
6066
6336
|
this.appendTransition(run, "queued", "running");
|
|
6067
|
-
const result = { run: clone(run), execution: clone(execution), history: this.
|
|
6337
|
+
const result = { run: clone(run), execution: clone(execution), history: this.activeHistory(run.agentId, run.agentSequence) };
|
|
6068
6338
|
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
6069
6339
|
return result;
|
|
6070
6340
|
}
|
|
@@ -6459,7 +6729,10 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6459
6729
|
}
|
|
6460
6730
|
listEvents(lease, input = {}) {
|
|
6461
6731
|
this.assertOwner(lease);
|
|
6462
|
-
const after = input.after ? this.parseCursor(input.after) :
|
|
6732
|
+
const after = input.after ? this.parseCursor(input.after) : this.retentionFloor - 1;
|
|
6733
|
+
if (input.after && after < this.retentionFloor - 1) {
|
|
6734
|
+
throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "expired" });
|
|
6735
|
+
}
|
|
6463
6736
|
if (after > this.eventSequence) {
|
|
6464
6737
|
throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "beyond_waterline" });
|
|
6465
6738
|
}
|
|
@@ -6476,11 +6749,72 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6476
6749
|
advanceConsumerCheckpoint(lease, input) {
|
|
6477
6750
|
this.assertOwner(lease);
|
|
6478
6751
|
const next = this.parseCursor(input.cursor);
|
|
6752
|
+
if (next < this.retentionFloor - 1) {
|
|
6753
|
+
throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "expired" });
|
|
6754
|
+
}
|
|
6479
6755
|
if (next > this.eventSequence) throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "beyond_waterline" });
|
|
6480
6756
|
const previous = this.consumerCheckpoints.get(input.consumerId);
|
|
6481
6757
|
if (previous !== void 0 && next <= this.parseCursor(previous)) return;
|
|
6482
6758
|
this.consumerCheckpoints.set(input.consumerId, input.cursor);
|
|
6483
6759
|
}
|
|
6760
|
+
compact(lease, input = {}) {
|
|
6761
|
+
this.assertOwner(lease);
|
|
6762
|
+
const retentionMs = input.retentionMs ?? 7 * 24 * 60 * 60 * 1e3;
|
|
6763
|
+
if (!Number.isFinite(retentionMs) || retentionMs < 0) {
|
|
6764
|
+
throw new TypeError("retentionMs must be a non-negative finite number");
|
|
6765
|
+
}
|
|
6766
|
+
const now = input.now === void 0 ? Date.now() : Date.parse(input.now);
|
|
6767
|
+
if (!Number.isFinite(now)) throw new TypeError("now must be an ISO timestamp");
|
|
6768
|
+
const cutoff = now - retentionMs;
|
|
6769
|
+
const checkpointSequences = [...this.consumerCheckpoints.values()].map((cursor) => this.parseCursor(cursor));
|
|
6770
|
+
const consumerFloor = checkpointSequences.length > 0 ? Math.min(...checkpointSequences) : this.eventSequence;
|
|
6771
|
+
const blockedRunIds = /* @__PURE__ */ new Set();
|
|
6772
|
+
for (const run of this.runs.values()) {
|
|
6773
|
+
if (run.state === "running") blockedRunIds.add(run.id);
|
|
6774
|
+
}
|
|
6775
|
+
for (const tool of this.toolCalls.values()) {
|
|
6776
|
+
if (tool.state === "pending" || tool.state === "running" || tool.state === "indeterminate") {
|
|
6777
|
+
blockedRunIds.add(tool.runId);
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
let deleteThrough = this.retentionFloor - 1;
|
|
6781
|
+
for (const event of this.events) {
|
|
6782
|
+
const sequence = this.parseCursor(event.cursor);
|
|
6783
|
+
if (sequence < this.retentionFloor) continue;
|
|
6784
|
+
if (sequence > consumerFloor) break;
|
|
6785
|
+
if (Date.parse(event.createdAt) > cutoff || blockedRunIds.has(event.runId)) break;
|
|
6786
|
+
const eventRun = this.runs.get(event.runId);
|
|
6787
|
+
if (!eventRun || eventRun.invalidatedBy === void 0 || !["completed", "failed", "cancelled"].includes(eventRun.state) || Date.parse(eventRun.updatedAt) > cutoff) break;
|
|
6788
|
+
deleteThrough = sequence;
|
|
6789
|
+
}
|
|
6790
|
+
const deletedEvents = deleteThrough >= this.retentionFloor ? this.events.filter((event) => this.parseCursor(event.cursor) <= deleteThrough) : [];
|
|
6791
|
+
if (deleteThrough >= this.retentionFloor) {
|
|
6792
|
+
this.events.splice(0, this.events.length, ...this.events.filter((event) => this.parseCursor(event.cursor) > deleteThrough));
|
|
6793
|
+
this.retentionFloor = deleteThrough + 1;
|
|
6794
|
+
for (const [consumerId, cursor] of this.consumerCheckpoints) {
|
|
6795
|
+
if (this.parseCursor(cursor) < this.retentionFloor - 1) {
|
|
6796
|
+
this.consumerCheckpoints.delete(consumerId);
|
|
6797
|
+
}
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6800
|
+
const activeMessageRunIds = new Set([...this.messages.values()].map((message) => message.runId));
|
|
6801
|
+
const deletableRuns = [...this.runs.values()].filter((run) => run.invalidatedBy !== void 0 && ["completed", "failed", "cancelled"].includes(run.state) && Date.parse(run.updatedAt) <= cutoff && !activeMessageRunIds.has(run.id) && !blockedRunIds.has(run.id) && this.events.filter((event) => event.runId === run.id).every((event) => this.parseCursor(event.cursor) <= consumerFloor && Date.parse(event.createdAt) <= cutoff));
|
|
6802
|
+
const deletedRunIds = deletableRuns.map((run) => run.id);
|
|
6803
|
+
const deletedRunSet = new Set(deletedRunIds);
|
|
6804
|
+
const deletedTools = [...this.toolCalls.values()].filter((tool) => deletedRunSet.has(tool.runId));
|
|
6805
|
+
for (const runId of deletedRunIds) this.runs.delete(runId);
|
|
6806
|
+
for (const [messageId, message] of this.messages) {
|
|
6807
|
+
if (deletedRunSet.has(message.runId)) this.messages.delete(messageId);
|
|
6808
|
+
}
|
|
6809
|
+
for (const tool of deletedTools) this.toolCalls.delete(tool.id);
|
|
6810
|
+
return {
|
|
6811
|
+
deletedRunIds,
|
|
6812
|
+
deletedToolCallIds: deletedTools.map((tool) => tool.id),
|
|
6813
|
+
deletedEventCount: deletedEvents.length,
|
|
6814
|
+
retentionFloor: `${this.incarnation}:${this.retentionFloor}`,
|
|
6815
|
+
...deletedRunIds.length === 0 && deletedEvents.length === 0 ? { skipped: "no_eligible_events" } : {}
|
|
6816
|
+
};
|
|
6817
|
+
}
|
|
6484
6818
|
replay(scope, payload) {
|
|
6485
6819
|
const key = encodeIdempotencyScope(this.incarnation, scope);
|
|
6486
6820
|
const receipt = this.idempotency.get(key);
|
|
@@ -6578,8 +6912,16 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6578
6912
|
messagesForRun(runId) {
|
|
6579
6913
|
return [...this.messages.values()].filter((message) => message.runId === runId).sort((a, b) => a.sequenceWithinRun - b.sequenceWithinRun);
|
|
6580
6914
|
}
|
|
6581
|
-
history(
|
|
6582
|
-
|
|
6915
|
+
history(lease, agentId) {
|
|
6916
|
+
this.assertOwner(lease);
|
|
6917
|
+
this.requireAgent(agentId);
|
|
6918
|
+
return this.activeHistory(agentId, Number.MAX_SAFE_INTEGER);
|
|
6919
|
+
}
|
|
6920
|
+
activeHistory(agentId, beforeSequence) {
|
|
6921
|
+
return clone([
|
|
6922
|
+
...this.historySeeds.get(agentId) ?? [],
|
|
6923
|
+
...[...this.runs.values()].filter((run) => run.agentId === agentId && run.agentSequence <= beforeSequence).sort((a, b) => a.agentSequence - b.agentSequence).flatMap((run) => this.messagesForRun(run.id))
|
|
6924
|
+
].map((message) => ({ ...message, messageRevision: message.messageRevision ?? 0 })));
|
|
6583
6925
|
}
|
|
6584
6926
|
appendMessage(run, message) {
|
|
6585
6927
|
this.events.push(this.baseEvent(run, {
|
|
@@ -6650,6 +6992,12 @@ var MemoryOwnedStore = class {
|
|
|
6650
6992
|
async deleteAgent(input) {
|
|
6651
6993
|
this.store.deleteAgent(this.lease, input);
|
|
6652
6994
|
}
|
|
6995
|
+
async reviseMessage(input) {
|
|
6996
|
+
return this.store.reviseMessage(this.lease, input);
|
|
6997
|
+
}
|
|
6998
|
+
async compact(input) {
|
|
6999
|
+
return this.store.compact(this.lease, input);
|
|
7000
|
+
}
|
|
6653
7001
|
async createRun(input) {
|
|
6654
7002
|
return this.store.createRun(this.lease, input);
|
|
6655
7003
|
}
|
|
@@ -6686,6 +7034,9 @@ var MemoryOwnedStore = class {
|
|
|
6686
7034
|
async snapshotRun(runId) {
|
|
6687
7035
|
return this.store.snapshotRun(this.lease, runId);
|
|
6688
7036
|
}
|
|
7037
|
+
async history(agentId) {
|
|
7038
|
+
return this.store.history(this.lease, agentId);
|
|
7039
|
+
}
|
|
6689
7040
|
async listAgents() {
|
|
6690
7041
|
return this.store.listAgents(this.lease);
|
|
6691
7042
|
}
|
|
@@ -6733,6 +7084,41 @@ function userInputContent(input) {
|
|
|
6733
7084
|
function userInputMetadata(input) {
|
|
6734
7085
|
return typeof input === "string" ? void 0 : input.metadata;
|
|
6735
7086
|
}
|
|
7087
|
+
function targetInput(input, metadata) {
|
|
7088
|
+
const content = typeof input === "string" ? input : input.content;
|
|
7089
|
+
return metadata === void 0 ? { content } : { content, metadata: clone(metadata) };
|
|
7090
|
+
}
|
|
7091
|
+
function materializeHistorySeed(agentId, source) {
|
|
7092
|
+
const seedRunId = createId("seed");
|
|
7093
|
+
const toolIds = /* @__PURE__ */ new Map();
|
|
7094
|
+
return source.map((message, sequenceWithinRun) => {
|
|
7095
|
+
const content = remapSeedContent(message.content, toolIds);
|
|
7096
|
+
return {
|
|
7097
|
+
...clone(message),
|
|
7098
|
+
id: createId("msg"),
|
|
7099
|
+
agentId,
|
|
7100
|
+
runId: seedRunId,
|
|
7101
|
+
content,
|
|
7102
|
+
messageRevision: message.messageRevision ?? 0,
|
|
7103
|
+
sequenceWithinRun,
|
|
7104
|
+
createdAt: createTimestamp()
|
|
7105
|
+
};
|
|
7106
|
+
});
|
|
7107
|
+
}
|
|
7108
|
+
function remapSeedContent(content, toolIds) {
|
|
7109
|
+
if (typeof content === "string") return content;
|
|
7110
|
+
return content.map((part) => {
|
|
7111
|
+
if (part.type === "tool_use" || part.type === "tool_result") {
|
|
7112
|
+
const toolCallId = toolIds.get(part.toolCallId) ?? createId("tool");
|
|
7113
|
+
toolIds.set(part.toolCallId, toolCallId);
|
|
7114
|
+
return part.type === "tool_result" ? { ...part, toolCallId, result: clone(part.result) } : { ...part, toolCallId };
|
|
7115
|
+
}
|
|
7116
|
+
return clone(part);
|
|
7117
|
+
});
|
|
7118
|
+
}
|
|
7119
|
+
function digestToolEffects(toolCalls) {
|
|
7120
|
+
return createHash("sha256").update(canonicalJson(toolCalls)).digest("hex");
|
|
7121
|
+
}
|
|
6736
7122
|
function assertToolValue(value, argument) {
|
|
6737
7123
|
assertUtf8ByteLimit(canonicalJson(value), TOOL_VALUE_JSON_BYTES, argument);
|
|
6738
7124
|
}
|
|
@@ -6740,8 +7126,9 @@ function assertToolValue(value, argument) {
|
|
|
6740
7126
|
// src/runtime/sqlite-durable-store.ts
|
|
6741
7127
|
import { Database } from "bun:sqlite";
|
|
6742
7128
|
var SCHEMA_ID = "rowan.agent.runtime";
|
|
6743
|
-
var SCHEMA_VERSION = "
|
|
7129
|
+
var SCHEMA_VERSION = "2";
|
|
6744
7130
|
var SCHEMA_VALUE = `${SCHEMA_ID}:${SCHEMA_VERSION}`;
|
|
7131
|
+
var RETENTION_FLOOR_KEY = "retention_floor";
|
|
6745
7132
|
var STATE_ROW = 1;
|
|
6746
7133
|
var CURRENT_TABLES = /* @__PURE__ */ new Set([
|
|
6747
7134
|
"runtime_meta",
|
|
@@ -6909,6 +7296,9 @@ var SqliteStore = class {
|
|
|
6909
7296
|
async deleteAgent(lease, input) {
|
|
6910
7297
|
return this.invoke(lease, (store, current) => store.deleteAgent(current, input));
|
|
6911
7298
|
}
|
|
7299
|
+
async reviseMessage(lease, input) {
|
|
7300
|
+
return this.invoke(lease, (store, current) => store.reviseMessage(current, input));
|
|
7301
|
+
}
|
|
6912
7302
|
async createRun(lease, input) {
|
|
6913
7303
|
return this.invoke(lease, (store, current) => store.createRun(current, input));
|
|
6914
7304
|
}
|
|
@@ -6945,6 +7335,9 @@ var SqliteStore = class {
|
|
|
6945
7335
|
async snapshotRun(lease, runId) {
|
|
6946
7336
|
return this.invoke(lease, (store, current) => store.snapshotRun(current, runId), false);
|
|
6947
7337
|
}
|
|
7338
|
+
async history(lease, agentId) {
|
|
7339
|
+
return this.invoke(lease, (store, current) => store.history(current, agentId), false);
|
|
7340
|
+
}
|
|
6948
7341
|
async listAgents(lease) {
|
|
6949
7342
|
return this.invoke(lease, (store, current) => store.listAgents(current), false);
|
|
6950
7343
|
}
|
|
@@ -6955,15 +7348,19 @@ var SqliteStore = class {
|
|
|
6955
7348
|
this.assertOpen();
|
|
6956
7349
|
return this.readTransaction(() => {
|
|
6957
7350
|
this.requireMatchingOwner(lease, true);
|
|
6958
|
-
const
|
|
7351
|
+
const retentionRow = this.database.query(
|
|
7352
|
+
"SELECT value FROM runtime_meta WHERE key = ?"
|
|
7353
|
+
).get(RETENTION_FLOOR_KEY);
|
|
7354
|
+
const retentionFloor = Math.max(1, Number(retentionRow?.value ?? "1"));
|
|
7355
|
+
const after = input.after ? parseEventCursor(lease, input.after) : retentionFloor - 1;
|
|
7356
|
+
if (input.after && after < retentionFloor - 1) {
|
|
7357
|
+
throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "expired" });
|
|
7358
|
+
}
|
|
6959
7359
|
if (input.after) {
|
|
6960
7360
|
const latest = this.database.query(
|
|
6961
|
-
"SELECT
|
|
7361
|
+
"SELECT max(sequence) AS sequence FROM run_events"
|
|
6962
7362
|
).get();
|
|
6963
|
-
const waterline = latest
|
|
6964
|
-
lease,
|
|
6965
|
-
JSON.parse(latest.payload_json).cursor
|
|
6966
|
-
) : 0;
|
|
7363
|
+
const waterline = latest.sequence ?? 0;
|
|
6967
7364
|
if (after > waterline) {
|
|
6968
7365
|
throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "beyond_waterline" });
|
|
6969
7366
|
}
|
|
@@ -6981,6 +7378,15 @@ var SqliteStore = class {
|
|
|
6981
7378
|
async advanceConsumerCheckpoint(lease, input) {
|
|
6982
7379
|
return this.invoke(lease, (store, current) => store.advanceConsumerCheckpoint(current, input));
|
|
6983
7380
|
}
|
|
7381
|
+
async compact(lease, input = {}) {
|
|
7382
|
+
this.assertOpen();
|
|
7383
|
+
const result = this.invoke(lease, (store, current) => store.compact(current, input));
|
|
7384
|
+
if (result.deletedEventCount > 0 || result.deletedRunIds.length > 0) {
|
|
7385
|
+
this.database.run("PRAGMA wal_checkpoint(PASSIVE)");
|
|
7386
|
+
this.database.run("PRAGMA incremental_vacuum");
|
|
7387
|
+
}
|
|
7388
|
+
return result;
|
|
7389
|
+
}
|
|
6984
7390
|
async renewOwner(lease, leaseMs) {
|
|
6985
7391
|
this.assertOpen();
|
|
6986
7392
|
assertOwnerInput(lease.ownerId, leaseMs);
|
|
@@ -7033,6 +7439,7 @@ var SqliteStore = class {
|
|
|
7033
7439
|
if (sql) this.database.run(sql);
|
|
7034
7440
|
}
|
|
7035
7441
|
this.database.run("INSERT INTO runtime_meta (key, value) VALUES (?, ?)", ["schema_version", SCHEMA_VALUE]);
|
|
7442
|
+
this.database.run("INSERT INTO runtime_meta (key, value) VALUES (?, ?)", [RETENTION_FLOOR_KEY, "1"]);
|
|
7036
7443
|
const state = new InMemoryStore();
|
|
7037
7444
|
this.database.run("INSERT INTO runtime_owner (singleton, epoch) VALUES (?, ?)", [STATE_ROW, 0]);
|
|
7038
7445
|
this.database.run("INSERT INTO runtime_state (singleton, state_json) VALUES (?, ?)", [STATE_ROW, JSON.stringify(state.exportState())]);
|
|
@@ -7081,6 +7488,10 @@ var SqliteStore = class {
|
|
|
7081
7488
|
}
|
|
7082
7489
|
persistState(state) {
|
|
7083
7490
|
this.writeState(state);
|
|
7491
|
+
this.database.run(
|
|
7492
|
+
"INSERT INTO runtime_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
|
7493
|
+
[RETENTION_FLOOR_KEY, String(Math.max(1, state.retentionFloor ?? 1))]
|
|
7494
|
+
);
|
|
7084
7495
|
for (const table of ["consumer_checkpoints", "idempotency", "run_events", "messages", "input_requests", "tool_calls", "runs", "agents"]) {
|
|
7085
7496
|
this.database.run(`DELETE FROM ${table}`);
|
|
7086
7497
|
}
|
|
@@ -7199,6 +7610,12 @@ var SqliteOwnedStore = class {
|
|
|
7199
7610
|
deleteAgent(input) {
|
|
7200
7611
|
return this.store.deleteAgent(this.lease, input);
|
|
7201
7612
|
}
|
|
7613
|
+
reviseMessage(input) {
|
|
7614
|
+
return this.store.reviseMessage(this.lease, input);
|
|
7615
|
+
}
|
|
7616
|
+
compact(input) {
|
|
7617
|
+
return this.store.compact(this.lease, input);
|
|
7618
|
+
}
|
|
7202
7619
|
createRun(input) {
|
|
7203
7620
|
return this.store.createRun(this.lease, input);
|
|
7204
7621
|
}
|
|
@@ -7235,6 +7652,9 @@ var SqliteOwnedStore = class {
|
|
|
7235
7652
|
snapshotRun(runId) {
|
|
7236
7653
|
return this.store.snapshotRun(this.lease, runId);
|
|
7237
7654
|
}
|
|
7655
|
+
history(agentId) {
|
|
7656
|
+
return this.store.history(this.lease, agentId);
|
|
7657
|
+
}
|
|
7238
7658
|
listAgents() {
|
|
7239
7659
|
return this.store.listAgents(this.lease);
|
|
7240
7660
|
}
|