@exaudeus/workrail 3.74.1 → 3.74.3
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/application/services/workflow-interpreter.js +22 -0
- package/dist/console-ui/assets/{index-BmDxs-a5.js → index-ByqIsoyt.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/session-scope.d.ts +7 -1
- package/dist/daemon/workflow-runner.d.ts +11 -4
- package/dist/daemon/workflow-runner.js +92 -66
- package/dist/manifest.json +13 -13
- package/dist/v2/durable-core/domain/context-template-resolver.js +34 -9
- package/docs/ideas/backlog.md +227 -27
- package/package.json +1 -1
- package/workflows/routines/tension-driven-design.json +26 -15
- package/workflows/wr.discovery.json +153 -16
|
@@ -120,8 +120,6 @@ export interface WorkflowDeliveryFailed {
|
|
|
120
120
|
}
|
|
121
121
|
export type WorkflowRunResult = WorkflowRunSuccess | WorkflowRunError | WorkflowRunTimeout | WorkflowRunStuck | WorkflowDeliveryFailed;
|
|
122
122
|
export type ChildWorkflowRunResult = WorkflowRunSuccess | WorkflowRunError | WorkflowRunTimeout | WorkflowRunStuck;
|
|
123
|
-
export type SteerRegistry = Map<string, (text: string) => void>;
|
|
124
|
-
export type AbortRegistry = Map<string, () => void>;
|
|
125
123
|
export interface OrphanedSession {
|
|
126
124
|
readonly sessionId: string;
|
|
127
125
|
readonly continueToken: string;
|
|
@@ -159,6 +157,14 @@ export declare function buildAgentClient(trigger: WorkflowTrigger, apiKey: strin
|
|
|
159
157
|
agentClient: Anthropic | AnthropicBedrock;
|
|
160
158
|
modelId: string;
|
|
161
159
|
};
|
|
160
|
+
export type TerminalSignal = {
|
|
161
|
+
readonly kind: 'stuck';
|
|
162
|
+
readonly reason: 'repeated_tool_call' | 'no_progress' | 'stall';
|
|
163
|
+
} | {
|
|
164
|
+
readonly kind: 'timeout';
|
|
165
|
+
readonly reason: 'wall_clock' | 'max_turns';
|
|
166
|
+
};
|
|
167
|
+
export declare function setTerminalSignal(state: SessionState, signal: TerminalSignal): boolean;
|
|
162
168
|
export interface SessionState {
|
|
163
169
|
isComplete: boolean;
|
|
164
170
|
lastStepNotes: string | undefined;
|
|
@@ -172,8 +178,7 @@ export interface SessionState {
|
|
|
172
178
|
}>;
|
|
173
179
|
issueSummaries: string[];
|
|
174
180
|
pendingSteerParts: string[];
|
|
175
|
-
|
|
176
|
-
timeoutReason: 'wall_clock' | 'max_turns' | null;
|
|
181
|
+
terminalSignal: TerminalSignal | null;
|
|
177
182
|
turnCount: number;
|
|
178
183
|
}
|
|
179
184
|
export declare function createSessionState(initialToken: string): SessionState;
|
|
@@ -221,6 +226,8 @@ export type PreAgentSessionResult = {
|
|
|
221
226
|
} | {
|
|
222
227
|
readonly kind: 'complete';
|
|
223
228
|
readonly result: WorkflowRunResult;
|
|
229
|
+
readonly workrailSessionId: string | null;
|
|
230
|
+
readonly handle: SessionHandle | undefined;
|
|
224
231
|
};
|
|
225
232
|
export interface AgentReadySession {
|
|
226
233
|
readonly preAgentSession: PreAgentSession;
|
|
@@ -50,6 +50,7 @@ exports.buildSystemPrompt = buildSystemPrompt;
|
|
|
50
50
|
exports.tagToStatsOutcome = tagToStatsOutcome;
|
|
51
51
|
exports.sidecardLifecycleFor = sidecardLifecycleFor;
|
|
52
52
|
exports.buildAgentClient = buildAgentClient;
|
|
53
|
+
exports.setTerminalSignal = setTerminalSignal;
|
|
53
54
|
exports.createSessionState = createSessionState;
|
|
54
55
|
exports.evaluateStuckSignals = evaluateStuckSignals;
|
|
55
56
|
exports.finalizeSession = finalizeSession;
|
|
@@ -880,6 +881,13 @@ function buildAgentClient(trigger, apiKey, env) {
|
|
|
880
881
|
modelId: 'claude-sonnet-4-6',
|
|
881
882
|
};
|
|
882
883
|
}
|
|
884
|
+
function setTerminalSignal(state, signal) {
|
|
885
|
+
if (state.terminalSignal === null) {
|
|
886
|
+
state.terminalSignal = signal;
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
883
891
|
function createSessionState(initialToken) {
|
|
884
892
|
return {
|
|
885
893
|
isComplete: false,
|
|
@@ -891,13 +899,12 @@ function createSessionState(initialToken) {
|
|
|
891
899
|
lastNToolCalls: [],
|
|
892
900
|
issueSummaries: [],
|
|
893
901
|
pendingSteerParts: [],
|
|
894
|
-
|
|
895
|
-
timeoutReason: null,
|
|
902
|
+
terminalSignal: null,
|
|
896
903
|
turnCount: 0,
|
|
897
904
|
};
|
|
898
905
|
}
|
|
899
906
|
function evaluateStuckSignals(state, config) {
|
|
900
|
-
if (config.maxTurns > 0 && state.turnCount >= config.maxTurns && state.
|
|
907
|
+
if (config.maxTurns > 0 && state.turnCount >= config.maxTurns && state.terminalSignal === null) {
|
|
901
908
|
return { kind: 'max_turns_exceeded' };
|
|
902
909
|
}
|
|
903
910
|
if (state.lastNToolCalls.length === config.stuckRepeatThreshold &&
|
|
@@ -913,8 +920,8 @@ function evaluateStuckSignals(state, config) {
|
|
|
913
920
|
state.stepAdvanceCount === 0) {
|
|
914
921
|
return { kind: 'no_progress', turnCount: state.turnCount, maxTurns: config.maxTurns };
|
|
915
922
|
}
|
|
916
|
-
if (state.
|
|
917
|
-
return { kind: 'timeout_imminent', timeoutReason: state.
|
|
923
|
+
if (state.terminalSignal?.kind === 'timeout') {
|
|
924
|
+
return { kind: 'timeout_imminent', timeoutReason: state.terminalSignal.reason };
|
|
918
925
|
}
|
|
919
926
|
return null;
|
|
920
927
|
}
|
|
@@ -1004,8 +1011,7 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1004
1011
|
}
|
|
1005
1012
|
catch (e) {
|
|
1006
1013
|
const message = e instanceof Error ? e.message : String(e);
|
|
1007
|
-
|
|
1008
|
-
return { kind: 'complete', result: { _tag: 'error', workflowId: trigger.workflowId, message, stopReason: 'error' } };
|
|
1014
|
+
return { kind: 'complete', result: { _tag: 'error', workflowId: trigger.workflowId, message, stopReason: 'error' }, workrailSessionId: null, handle: undefined };
|
|
1009
1015
|
}
|
|
1010
1016
|
const state = createSessionState('');
|
|
1011
1017
|
let continueToken;
|
|
@@ -1023,7 +1029,6 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1023
1029
|
else {
|
|
1024
1030
|
const startResult = await (0, start_js_1.executeStartWorkflow)({ workflowId: trigger.workflowId, workspacePath: trigger.workspacePath, goal: trigger.goal }, ctx, { is_autonomous: 'true', workspacePath: trigger.workspacePath, triggerSource: 'daemon' });
|
|
1025
1031
|
if (startResult.isErr()) {
|
|
1026
|
-
writeExecutionStats(statsDir, sessionId, trigger.workflowId, startMs, 'error', 0);
|
|
1027
1032
|
return {
|
|
1028
1033
|
kind: 'complete',
|
|
1029
1034
|
result: {
|
|
@@ -1032,6 +1037,8 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1032
1037
|
message: `start_workflow failed: ${startResult.error.kind} -- ${JSON.stringify(startResult.error)}`,
|
|
1033
1038
|
stopReason: 'error',
|
|
1034
1039
|
},
|
|
1040
|
+
workrailSessionId: null,
|
|
1041
|
+
handle: undefined,
|
|
1035
1042
|
};
|
|
1036
1043
|
}
|
|
1037
1044
|
const r = startResult.value.response;
|
|
@@ -1057,7 +1064,6 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1057
1064
|
workspacePath: trigger.workspacePath,
|
|
1058
1065
|
});
|
|
1059
1066
|
if (persistResult.kind === 'err') {
|
|
1060
|
-
writeExecutionStats(statsDir, sessionId, trigger.workflowId, startMs, 'error', 0);
|
|
1061
1067
|
return {
|
|
1062
1068
|
kind: 'complete',
|
|
1063
1069
|
result: {
|
|
@@ -1066,6 +1072,8 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1066
1072
|
message: `Initial token persist failed: ${persistResult.error.code} -- ${persistResult.error.message}`,
|
|
1067
1073
|
stopReason: 'error',
|
|
1068
1074
|
},
|
|
1075
|
+
workrailSessionId: state.workrailSessionId,
|
|
1076
|
+
handle: undefined,
|
|
1069
1077
|
};
|
|
1070
1078
|
}
|
|
1071
1079
|
}
|
|
@@ -1097,7 +1105,6 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1097
1105
|
await execFileAsync('git', ['-C', trigger.workspacePath, 'worktree', 'remove', '--force', sessionWorkspacePath]);
|
|
1098
1106
|
}
|
|
1099
1107
|
catch { }
|
|
1100
|
-
writeExecutionStats(statsDir, sessionId, trigger.workflowId, startMs, 'error', 0);
|
|
1101
1108
|
return {
|
|
1102
1109
|
kind: 'complete',
|
|
1103
1110
|
result: {
|
|
@@ -1106,6 +1113,8 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1106
1113
|
message: `Worktree sidecar persist failed: ${worktreePersistResult.error.code} -- ${worktreePersistResult.error.message}`,
|
|
1107
1114
|
stopReason: 'error',
|
|
1108
1115
|
},
|
|
1116
|
+
workrailSessionId: state.workrailSessionId,
|
|
1117
|
+
handle: undefined,
|
|
1109
1118
|
};
|
|
1110
1119
|
}
|
|
1111
1120
|
console.log(`[WorkflowRunner] Worktree created: sessionId=${sessionId} branch=${branchPrefix}${sessionId} path=${sessionWorkspacePath}`);
|
|
@@ -1113,10 +1122,11 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1113
1122
|
catch (e) {
|
|
1114
1123
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
1115
1124
|
console.error(`[WorkflowRunner] Worktree creation failed: sessionId=${sessionId} error=${errMsg}`);
|
|
1116
|
-
writeExecutionStats(statsDir, sessionId, trigger.workflowId, startMs, 'error', 0);
|
|
1117
1125
|
return {
|
|
1118
1126
|
kind: 'complete',
|
|
1119
1127
|
result: { _tag: 'error', workflowId: trigger.workflowId, message: `Worktree creation failed: ${errMsg}`, stopReason: 'error' },
|
|
1128
|
+
workrailSessionId: state.workrailSessionId,
|
|
1129
|
+
handle: undefined,
|
|
1120
1130
|
};
|
|
1121
1131
|
}
|
|
1122
1132
|
}
|
|
@@ -1126,16 +1136,6 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1126
1136
|
handle = activeSessionSet?.register(state.workrailSessionId, (text) => { state.pendingSteerParts.push(text); });
|
|
1127
1137
|
}
|
|
1128
1138
|
if (isComplete) {
|
|
1129
|
-
const lifecycle = sidecardLifecycleFor('success', trigger.branchStrategy);
|
|
1130
|
-
if (lifecycle.kind === 'delete_now') {
|
|
1131
|
-
await fs.unlink(path.join(sessionsDir, `${sessionId}.json`)).catch(() => { });
|
|
1132
|
-
}
|
|
1133
|
-
emitter?.emit({ kind: 'session_completed', sessionId, workflowId: trigger.workflowId, outcome: 'success', detail: 'stop', ...(0, _shared_js_1.withWorkrailSession)(state.workrailSessionId) });
|
|
1134
|
-
if (state.workrailSessionId !== null) {
|
|
1135
|
-
daemonRegistry?.unregister(state.workrailSessionId, 'completed');
|
|
1136
|
-
handle?.dispose();
|
|
1137
|
-
}
|
|
1138
|
-
writeExecutionStats(statsDir, sessionId, trigger.workflowId, startMs, 'success', 0);
|
|
1139
1139
|
return {
|
|
1140
1140
|
kind: 'complete',
|
|
1141
1141
|
result: {
|
|
@@ -1146,6 +1146,8 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1146
1146
|
...(sessionWorktreePath !== undefined ? { sessionId } : {}),
|
|
1147
1147
|
...(trigger.botIdentity !== undefined ? { botIdentity: trigger.botIdentity } : {}),
|
|
1148
1148
|
},
|
|
1149
|
+
workrailSessionId: state.workrailSessionId,
|
|
1150
|
+
handle,
|
|
1149
1151
|
};
|
|
1150
1152
|
}
|
|
1151
1153
|
return {
|
|
@@ -1169,14 +1171,13 @@ async function buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, st
|
|
|
1169
1171
|
},
|
|
1170
1172
|
};
|
|
1171
1173
|
}
|
|
1172
|
-
function constructTools(
|
|
1173
|
-
const {
|
|
1174
|
-
const { fileTracker, onAdvance, onComplete, emitter, activeSessionSet, maxIssueSummaries } = scope;
|
|
1174
|
+
function constructTools(ctx, apiKey, schemas, scope) {
|
|
1175
|
+
const { fileTracker, onAdvance, onComplete, onTokenUpdate, onIssueReported, getCurrentToken, sessionWorkspacePath, spawnCurrentDepth, spawnMaxDepth, emitter, activeSessionSet, } = scope;
|
|
1175
1176
|
const sid = scope.sessionId;
|
|
1176
1177
|
const workrailSid = scope.workrailSessionId;
|
|
1177
1178
|
const readFileStateMap = fileTracker.toMap();
|
|
1178
1179
|
return [
|
|
1179
|
-
(0, continue_workflow_js_1.makeCompleteStepTool)(sid, ctx,
|
|
1180
|
+
(0, continue_workflow_js_1.makeCompleteStepTool)(sid, ctx, getCurrentToken, onAdvance, onComplete, onTokenUpdate, schemas, index_js_1.executeContinueWorkflow, emitter, workrailSid),
|
|
1180
1181
|
(0, continue_workflow_js_1.makeContinueWorkflowTool)(sid, ctx, onAdvance, onComplete, schemas, index_js_1.executeContinueWorkflow, emitter, workrailSid),
|
|
1181
1182
|
(0, bash_js_1.makeBashTool)(sessionWorkspacePath, schemas, sid, emitter, workrailSid),
|
|
1182
1183
|
(0, file_tools_js_1.makeReadTool)(sessionWorkspacePath, readFileStateMap, schemas, sid, emitter, workrailSid),
|
|
@@ -1184,11 +1185,7 @@ function constructTools(session, ctx, apiKey, schemas, scope) {
|
|
|
1184
1185
|
(0, glob_grep_js_1.makeGlobTool)(sessionWorkspacePath, schemas, sid, emitter, workrailSid),
|
|
1185
1186
|
(0, glob_grep_js_1.makeGrepTool)(sessionWorkspacePath, schemas, sid, emitter, workrailSid),
|
|
1186
1187
|
(0, file_tools_js_1.makeEditTool)(sessionWorkspacePath, readFileStateMap, schemas, sid, emitter, workrailSid),
|
|
1187
|
-
(0, report_issue_js_1.makeReportIssueTool)(sid, emitter, workrailSid, undefined,
|
|
1188
|
-
if (state.issueSummaries.length < maxIssueSummaries) {
|
|
1189
|
-
state.issueSummaries.push(summary);
|
|
1190
|
-
}
|
|
1191
|
-
}),
|
|
1188
|
+
(0, report_issue_js_1.makeReportIssueTool)(sid, emitter, workrailSid, undefined, onIssueReported),
|
|
1192
1189
|
(0, spawn_agent_js_1.makeSpawnAgentTool)(sid, ctx, apiKey, workrailSid ?? '', spawnCurrentDepth, spawnMaxDepth, runWorkflow, schemas, emitter, activeSessionSet),
|
|
1193
1190
|
(0, signal_coordinator_js_1.makeSignalCoordinatorTool)(sid, emitter, workrailSid),
|
|
1194
1191
|
];
|
|
@@ -1207,7 +1204,7 @@ function buildTurnEndSubscriber(ctx) {
|
|
|
1207
1204
|
const signal = evaluateStuckSignals(ctx.state, ctx.stuckConfig);
|
|
1208
1205
|
if (signal !== null) {
|
|
1209
1206
|
if (signal.kind === 'max_turns_exceeded') {
|
|
1210
|
-
ctx.state
|
|
1207
|
+
setTerminalSignal(ctx.state, { kind: 'timeout', reason: 'max_turns' });
|
|
1211
1208
|
ctx.emitter?.emit({ kind: 'agent_stuck', sessionId: ctx.sessionId, reason: 'timeout_imminent', detail: 'Max-turn limit reached', ...(0, _shared_js_1.withWorkrailSession)(ctx.state.workrailSessionId) });
|
|
1212
1209
|
ctx.agent.abort();
|
|
1213
1210
|
return;
|
|
@@ -1215,20 +1212,22 @@ function buildTurnEndSubscriber(ctx) {
|
|
|
1215
1212
|
else if (signal.kind === 'repeated_tool_call') {
|
|
1216
1213
|
ctx.emitter?.emit({ kind: 'agent_stuck', sessionId: ctx.sessionId, reason: 'repeated_tool_call', detail: `Same tool+args called ${ctx.stuckRepeatThreshold} times: ${signal.toolName}`, toolName: signal.toolName, argsSummary: signal.argsSummary, ...(0, _shared_js_1.withWorkrailSession)(ctx.state.workrailSessionId) });
|
|
1217
1214
|
void writeStuckOutboxEntry({ workflowId: ctx.workflowId, reason: 'repeated_tool_call', ...(ctx.state.issueSummaries.length > 0 ? { issueSummaries: [...ctx.state.issueSummaries] } : {}) });
|
|
1218
|
-
if (ctx.stuckConfig.stuckAbortPolicy !== 'notify_only'
|
|
1219
|
-
ctx.state
|
|
1220
|
-
|
|
1221
|
-
|
|
1215
|
+
if (ctx.stuckConfig.stuckAbortPolicy !== 'notify_only') {
|
|
1216
|
+
if (setTerminalSignal(ctx.state, { kind: 'stuck', reason: 'repeated_tool_call' })) {
|
|
1217
|
+
ctx.agent.abort();
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1222
1220
|
}
|
|
1223
1221
|
}
|
|
1224
1222
|
else if (signal.kind === 'no_progress') {
|
|
1225
1223
|
ctx.emitter?.emit({ kind: 'agent_stuck', sessionId: ctx.sessionId, reason: 'no_progress', detail: `${signal.turnCount} turns used, 0 step advances (${signal.maxTurns} turn limit)`, ...(0, _shared_js_1.withWorkrailSession)(ctx.state.workrailSessionId) });
|
|
1226
1224
|
if (ctx.stuckConfig.noProgressAbortEnabled) {
|
|
1227
1225
|
void writeStuckOutboxEntry({ workflowId: ctx.workflowId, reason: 'no_progress', ...(ctx.state.issueSummaries.length > 0 ? { issueSummaries: [...ctx.state.issueSummaries] } : {}) });
|
|
1228
|
-
if (ctx.stuckConfig.stuckAbortPolicy !== 'notify_only'
|
|
1229
|
-
ctx.state
|
|
1230
|
-
|
|
1231
|
-
|
|
1226
|
+
if (ctx.stuckConfig.stuckAbortPolicy !== 'notify_only') {
|
|
1227
|
+
if (setTerminalSignal(ctx.state, { kind: 'stuck', reason: 'no_progress' })) {
|
|
1228
|
+
ctx.agent.abort();
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1232
1231
|
}
|
|
1233
1232
|
}
|
|
1234
1233
|
}
|
|
@@ -1264,7 +1263,7 @@ function buildAgentCallbacks(sessionId, state, modelId, emitter, stuckRepeatThre
|
|
|
1264
1263
|
emitter?.emit({ kind: 'tool_call_failed', sessionId, toolName, durationMs, errorMessage, ...(0, _shared_js_1.withWorkrailSession)(state.workrailSessionId) });
|
|
1265
1264
|
},
|
|
1266
1265
|
onStallDetected: () => {
|
|
1267
|
-
state
|
|
1266
|
+
setTerminalSignal(state, { kind: 'stuck', reason: 'stall' });
|
|
1268
1267
|
emitter?.emit({
|
|
1269
1268
|
kind: 'agent_stuck',
|
|
1270
1269
|
sessionId,
|
|
@@ -1281,27 +1280,31 @@ function buildAgentCallbacks(sessionId, state, modelId, emitter, stuckRepeatThre
|
|
|
1281
1280
|
};
|
|
1282
1281
|
}
|
|
1283
1282
|
function buildSessionResult(state, stopReason, errorMessage, trigger, sessionId, sessionWorktreePath) {
|
|
1284
|
-
if (state.
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1283
|
+
if (state.terminalSignal !== null) {
|
|
1284
|
+
const signal = state.terminalSignal;
|
|
1285
|
+
if (signal.kind === 'stuck') {
|
|
1286
|
+
return {
|
|
1287
|
+
_tag: 'stuck',
|
|
1288
|
+
workflowId: trigger.workflowId,
|
|
1289
|
+
reason: signal.reason,
|
|
1290
|
+
message: `Session aborted: stuck heuristic fired (${signal.reason})`,
|
|
1291
|
+
stopReason: 'aborted',
|
|
1292
|
+
...(state.issueSummaries.length > 0 ? { issueSummaries: [...state.issueSummaries] } : {}),
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
if (signal.kind === 'timeout') {
|
|
1296
|
+
const limitDescription = signal.reason === 'wall_clock'
|
|
1297
|
+
? `${trigger.agentConfig?.maxSessionMinutes ?? exports.DEFAULT_SESSION_TIMEOUT_MINUTES} minutes`
|
|
1298
|
+
: `${trigger.agentConfig?.maxTurns ?? exports.DEFAULT_MAX_TURNS} turns`;
|
|
1299
|
+
return {
|
|
1300
|
+
_tag: 'timeout',
|
|
1301
|
+
workflowId: trigger.workflowId,
|
|
1302
|
+
reason: signal.reason,
|
|
1303
|
+
message: `Workflow ${signal.reason === 'wall_clock' ? 'timed out' : 'exceeded turn limit'} after ${limitDescription}`,
|
|
1304
|
+
stopReason: 'aborted',
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
return (0, assert_never_js_1.assertNever)(signal);
|
|
1305
1308
|
}
|
|
1306
1309
|
if (stopReason === 'error' || errorMessage) {
|
|
1307
1310
|
const errMsg = errorMessage ?? 'Agent stopped with error reason';
|
|
@@ -1359,14 +1362,24 @@ async function buildAgentReadySession(preAgentSession, trigger, ctx, apiKey, ses
|
|
|
1359
1362
|
fileTracker: new session_scope_js_1.DefaultFileStateTracker(preAgentSession.readFileState),
|
|
1360
1363
|
onAdvance,
|
|
1361
1364
|
onComplete,
|
|
1365
|
+
onTokenUpdate: (t) => { state.currentContinueToken = t; },
|
|
1366
|
+
onIssueReported: (summary) => {
|
|
1367
|
+
if (state.issueSummaries.length < MAX_ISSUE_SUMMARIES) {
|
|
1368
|
+
state.issueSummaries.push(summary);
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1371
|
+
onSteer: (text) => { state.pendingSteerParts.push(text); },
|
|
1372
|
+
getCurrentToken: () => state.currentContinueToken,
|
|
1373
|
+
sessionWorkspacePath,
|
|
1374
|
+
spawnCurrentDepth: preAgentSession.spawnCurrentDepth,
|
|
1375
|
+
spawnMaxDepth: preAgentSession.spawnMaxDepth,
|
|
1362
1376
|
workrailSessionId: state.workrailSessionId,
|
|
1363
1377
|
emitter,
|
|
1364
1378
|
sessionId,
|
|
1365
1379
|
workflowId: trigger.workflowId,
|
|
1366
1380
|
activeSessionSet,
|
|
1367
|
-
maxIssueSummaries: MAX_ISSUE_SUMMARIES,
|
|
1368
1381
|
};
|
|
1369
|
-
const tools = constructTools(
|
|
1382
|
+
const tools = constructTools(ctx, apiKey, schemas, scope);
|
|
1370
1383
|
const contextLoader = new context_loader_js_1.DefaultContextLoader(loadDaemonSoul, loadWorkspaceContext, loadSessionNotes, ctx);
|
|
1371
1384
|
const baseCtx = await contextLoader.loadBase(trigger);
|
|
1372
1385
|
const contextBundle = await contextLoader.loadSession(startContinueToken, baseCtx);
|
|
@@ -1430,9 +1443,7 @@ async function runAgentLoop(session, trigger, conversationPath) {
|
|
|
1430
1443
|
try {
|
|
1431
1444
|
const timeoutPromise = new Promise((_, reject) => {
|
|
1432
1445
|
timeoutHandle = setTimeout(() => {
|
|
1433
|
-
|
|
1434
|
-
state.timeoutReason = 'wall_clock';
|
|
1435
|
-
}
|
|
1446
|
+
setTerminalSignal(state, { kind: 'timeout', reason: 'wall_clock' });
|
|
1436
1447
|
reject(new Error('Workflow timed out'));
|
|
1437
1448
|
}, sessionTimeoutMs);
|
|
1438
1449
|
});
|
|
@@ -1486,6 +1497,21 @@ async function runWorkflow(trigger, ctx, apiKey, daemonRegistry, emitter, active
|
|
|
1486
1497
|
});
|
|
1487
1498
|
const preResult = await buildPreAgentSession(trigger, ctx, apiKey, sessionId, startMs, statsDir, sessionsDir, emitter, daemonRegistry, activeSessionSet, source);
|
|
1488
1499
|
if (preResult.kind === 'complete') {
|
|
1500
|
+
const earlyCtx = {
|
|
1501
|
+
sessionId,
|
|
1502
|
+
workrailSessionId: preResult.workrailSessionId,
|
|
1503
|
+
startMs,
|
|
1504
|
+
stepAdvanceCount: 0,
|
|
1505
|
+
branchStrategy: trigger.branchStrategy,
|
|
1506
|
+
statsDir,
|
|
1507
|
+
sessionsDir,
|
|
1508
|
+
conversationPath: path.join(sessionsDir, `${sessionId}-conversation.jsonl`),
|
|
1509
|
+
emitter,
|
|
1510
|
+
daemonRegistry,
|
|
1511
|
+
workflowId: trigger.workflowId,
|
|
1512
|
+
};
|
|
1513
|
+
preResult.handle?.dispose();
|
|
1514
|
+
await finalizeSession(preResult.result, earlyCtx);
|
|
1489
1515
|
return preResult.result;
|
|
1490
1516
|
}
|
|
1491
1517
|
const readySession = await buildAgentReadySession(preResult.session, trigger, ctx, apiKey, sessionId, emitter, daemonRegistry, activeSessionSet);
|
package/dist/manifest.json
CHANGED
|
@@ -142,8 +142,8 @@
|
|
|
142
142
|
"bytes": 1507
|
|
143
143
|
},
|
|
144
144
|
"application/services/workflow-interpreter.js": {
|
|
145
|
-
"sha256": "
|
|
146
|
-
"bytes":
|
|
145
|
+
"sha256": "b340f4e4c2b54b2c9ac97c99b5e67b11d472a3d16944bf77b16badb7d887b088",
|
|
146
|
+
"bytes": 23716
|
|
147
147
|
},
|
|
148
148
|
"application/services/workflow-service.d.ts": {
|
|
149
149
|
"sha256": "c9c9e2ab4396c46da0f12af93133ca1e7da94bdc88f67a074d8f6c43ef0a5b3b",
|
|
@@ -473,8 +473,8 @@
|
|
|
473
473
|
"sha256": "5fe866e54f796975dec5d8ba9983aefd86074db212d3fccd64eed04bc9f0b3da",
|
|
474
474
|
"bytes": 8011
|
|
475
475
|
},
|
|
476
|
-
"console-ui/assets/index-
|
|
477
|
-
"sha256": "
|
|
476
|
+
"console-ui/assets/index-ByqIsoyt.js": {
|
|
477
|
+
"sha256": "86f5c9d133d4c98fef157087edd26d9a811fd0e68018a797b52a9a44eb501ead",
|
|
478
478
|
"bytes": 768234
|
|
479
479
|
},
|
|
480
480
|
"console-ui/assets/index-DHrKiMCf.css": {
|
|
@@ -482,7 +482,7 @@
|
|
|
482
482
|
"bytes": 60673
|
|
483
483
|
},
|
|
484
484
|
"console-ui/index.html": {
|
|
485
|
-
"sha256": "
|
|
485
|
+
"sha256": "9f03a646bde4274beaade4ded2699065b901624e5173627ebd20babed3f2e7e3",
|
|
486
486
|
"bytes": 417
|
|
487
487
|
},
|
|
488
488
|
"console/standalone-console.d.ts": {
|
|
@@ -662,8 +662,8 @@
|
|
|
662
662
|
"bytes": 247
|
|
663
663
|
},
|
|
664
664
|
"daemon/session-scope.d.ts": {
|
|
665
|
-
"sha256": "
|
|
666
|
-
"bytes":
|
|
665
|
+
"sha256": "35e102ecaeb59fbb57b715a43c030e8aba7a2e0aa757d0f828dc677910020ada",
|
|
666
|
+
"bytes": 1681
|
|
667
667
|
},
|
|
668
668
|
"daemon/session-scope.js": {
|
|
669
669
|
"sha256": "2f5295aa36b8d46b162a2b1f4d6f13af00517796aa468956563a8de46e2ecd56",
|
|
@@ -774,12 +774,12 @@
|
|
|
774
774
|
"bytes": 429
|
|
775
775
|
},
|
|
776
776
|
"daemon/workflow-runner.d.ts": {
|
|
777
|
-
"sha256": "
|
|
778
|
-
"bytes":
|
|
777
|
+
"sha256": "27fd8ac603948712aaf266ef57d2c165c1b4f92f877358debc40ad4f43d5b24c",
|
|
778
|
+
"bytes": 13463
|
|
779
779
|
},
|
|
780
780
|
"daemon/workflow-runner.js": {
|
|
781
|
-
"sha256": "
|
|
782
|
-
"bytes":
|
|
781
|
+
"sha256": "458be357c7dd86b215aaa8eabb3fe7ddb05172a0a4a771523232dc9b012ea156",
|
|
782
|
+
"bytes": 80362
|
|
783
783
|
},
|
|
784
784
|
"di/container.d.ts": {
|
|
785
785
|
"sha256": "003bb7fb7478d627524b9b1e76bd0a963a243794a687ff233b96dc0e33a06d9f",
|
|
@@ -2138,8 +2138,8 @@
|
|
|
2138
2138
|
"bytes": 161
|
|
2139
2139
|
},
|
|
2140
2140
|
"v2/durable-core/domain/context-template-resolver.js": {
|
|
2141
|
-
"sha256": "
|
|
2142
|
-
"bytes":
|
|
2141
|
+
"sha256": "05a0f2f61cf666b160677e6b22faa624f290e4a9f26fae98283c8cfc5b71a546",
|
|
2142
|
+
"bytes": 2129
|
|
2143
2143
|
},
|
|
2144
2144
|
"v2/durable-core/domain/decision-trace-builder.d.ts": {
|
|
2145
2145
|
"sha256": "f897dd17019bb094c72b1b19d7e731d535f66256ae38a0b08646d2604be0663d",
|
|
@@ -4,23 +4,48 @@ exports.CONTEXT_TOKEN_PATTERN = void 0;
|
|
|
4
4
|
exports.resolveContextTemplates = resolveContextTemplates;
|
|
5
5
|
exports.CONTEXT_TOKEN_PATTERN = /\{\{(?!wr\.)([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)\}\}/;
|
|
6
6
|
function resolveDotPath(base, path) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
if (path.length === 0)
|
|
8
|
+
return { kind: 'ok', value: base };
|
|
9
|
+
const rootKey = path[0];
|
|
10
|
+
if (base === null || typeof base !== 'object') {
|
|
11
|
+
return { kind: 'missing_root', rootKey };
|
|
12
|
+
}
|
|
13
|
+
const rootValue = base[rootKey];
|
|
14
|
+
if (rootValue === undefined || rootValue === null) {
|
|
15
|
+
return { kind: 'missing_root', rootKey };
|
|
16
|
+
}
|
|
17
|
+
let current = rootValue;
|
|
18
|
+
for (let i = 1; i < path.length; i++) {
|
|
19
|
+
const segment = path[i];
|
|
20
|
+
if (current === null || typeof current !== 'object') {
|
|
21
|
+
const actualType = current === null ? 'null' : typeof current;
|
|
22
|
+
const raw = String(current);
|
|
23
|
+
const preview = raw.length > 60 ? raw.slice(0, 60) + '…' : raw;
|
|
24
|
+
return { kind: 'wrong_type', failedAtKey: path.slice(0, i).join('.'), actualType, preview };
|
|
25
|
+
}
|
|
11
26
|
current = current[segment];
|
|
12
27
|
}
|
|
13
|
-
|
|
28
|
+
if (current === undefined || current === null) {
|
|
29
|
+
return { kind: 'leaf_missing', fullPath: path.join('.') };
|
|
30
|
+
}
|
|
31
|
+
return { kind: 'ok', value: current };
|
|
14
32
|
}
|
|
15
33
|
function resolveContextTemplates(template, context) {
|
|
16
34
|
if (!template.includes('{{'))
|
|
17
35
|
return template;
|
|
18
36
|
const re = new RegExp(exports.CONTEXT_TOKEN_PATTERN.source, 'g');
|
|
19
37
|
return template.replace(re, (_match, dotPath) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
38
|
+
const segments = dotPath.split('.');
|
|
39
|
+
const result = resolveDotPath(context, segments);
|
|
40
|
+
switch (result.kind) {
|
|
41
|
+
case 'ok':
|
|
42
|
+
return String(result.value);
|
|
43
|
+
case 'missing_root':
|
|
44
|
+
return `[unset: ${dotPath}]`;
|
|
45
|
+
case 'wrong_type':
|
|
46
|
+
return `[unset: ${dotPath} -- '${result.failedAtKey}' is ${result.actualType} ("${result.preview}"), not object]`;
|
|
47
|
+
case 'leaf_missing':
|
|
48
|
+
return `[unset: ${dotPath}]`;
|
|
23
49
|
}
|
|
24
|
-
return String(value);
|
|
25
50
|
});
|
|
26
51
|
}
|