@atolis-hq/wake 0.2.44 → 0.2.46
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/src/adapters/claude/claude-runner.js +54 -1
- package/dist/src/adapters/codex/codex-runner.js +87 -5
- package/dist/src/adapters/cursor/cursor-runner.js +54 -1
- package/dist/src/adapters/fake/fake-runner.js +32 -1
- package/dist/src/adapters/runner/runtime-events.js +32 -0
- package/dist/src/core/tick-runner.js +36 -0
- package/dist/src/domain/runtime-events.js +36 -0
- package/dist/src/domain/schema.js +18 -0
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseClaudePrintResult, parseRunnerResult } from '../../domain/schema.js';
|
|
2
2
|
import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
3
3
|
import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
4
|
+
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
4
5
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
5
6
|
export { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
6
7
|
function slugify(value, maxLength = 40) {
|
|
@@ -221,7 +222,18 @@ export function createClaudeRunner(options) {
|
|
|
221
222
|
args,
|
|
222
223
|
cwd: input.workspacePath ?? options.cwd,
|
|
223
224
|
timeoutMs: options.settings.timeoutMs,
|
|
224
|
-
|
|
225
|
+
onProcessStart: async (identity) => {
|
|
226
|
+
await input.onProcessStart?.(identity);
|
|
227
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
228
|
+
type: 'agent.process.started',
|
|
229
|
+
runId: input.runId,
|
|
230
|
+
projection: input.projection,
|
|
231
|
+
routing: input.routing,
|
|
232
|
+
cli: CLAUDE_CLI_NAME,
|
|
233
|
+
model,
|
|
234
|
+
payload: { pid: identity.pid, processStartedAt: identity.processStartedAt },
|
|
235
|
+
}));
|
|
236
|
+
},
|
|
225
237
|
});
|
|
226
238
|
const responseTranscriptPath = await writeRunnerTranscript({
|
|
227
239
|
config: input.config,
|
|
@@ -250,6 +262,15 @@ export function createClaudeRunner(options) {
|
|
|
250
262
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
251
263
|
exitCode: result.exitCode,
|
|
252
264
|
}));
|
|
265
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
266
|
+
type: 'agent.process.exited',
|
|
267
|
+
runId: input.runId,
|
|
268
|
+
projection: input.projection,
|
|
269
|
+
routing: input.routing,
|
|
270
|
+
cli: CLAUDE_CLI_NAME,
|
|
271
|
+
model,
|
|
272
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
273
|
+
}));
|
|
253
274
|
let parsedReason;
|
|
254
275
|
let stdoutFailureDetail;
|
|
255
276
|
const trimmedStdout = result.stdout.trim();
|
|
@@ -295,6 +316,16 @@ export function createClaudeRunner(options) {
|
|
|
295
316
|
}
|
|
296
317
|
const parsed = parseClaudePrintOutput(result.stdout);
|
|
297
318
|
const sandboxLog = readSandboxLogBreadcrumb();
|
|
319
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
320
|
+
type: 'agent.progress',
|
|
321
|
+
runId: input.runId,
|
|
322
|
+
projection: input.projection,
|
|
323
|
+
routing: input.routing,
|
|
324
|
+
cli: CLAUDE_CLI_NAME,
|
|
325
|
+
model,
|
|
326
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
327
|
+
payload: { message: 'Claude print result received', raw: parsed },
|
|
328
|
+
}));
|
|
298
329
|
console.log(formatClaudeRunLogLine({
|
|
299
330
|
phase: 'success',
|
|
300
331
|
runId: input.runId,
|
|
@@ -307,6 +338,28 @@ export function createClaudeRunner(options) {
|
|
|
307
338
|
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
308
339
|
}));
|
|
309
340
|
const tokenUsage = extractTokenUsage(parsed);
|
|
341
|
+
if (tokenUsage !== undefined) {
|
|
342
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
343
|
+
type: 'agent.usage.updated',
|
|
344
|
+
runId: input.runId,
|
|
345
|
+
projection: input.projection,
|
|
346
|
+
routing: input.routing,
|
|
347
|
+
cli: CLAUDE_CLI_NAME,
|
|
348
|
+
model,
|
|
349
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
350
|
+
payload: { tokenUsage },
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
354
|
+
type: 'agent.process.exited',
|
|
355
|
+
runId: input.runId,
|
|
356
|
+
projection: input.projection,
|
|
357
|
+
routing: input.routing,
|
|
358
|
+
cli: CLAUDE_CLI_NAME,
|
|
359
|
+
model,
|
|
360
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
361
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
362
|
+
}));
|
|
310
363
|
return {
|
|
311
364
|
result: parsed.result,
|
|
312
365
|
model,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
2
2
|
import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
3
|
+
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
3
4
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
4
5
|
import { parseRunnerResult } from '../../domain/schema.js';
|
|
5
6
|
const CODEX_CLI_NAME = 'Codex';
|
|
@@ -268,7 +269,18 @@ export function createCodexRunner(options) {
|
|
|
268
269
|
}),
|
|
269
270
|
cwd,
|
|
270
271
|
timeoutMs: options.settings.timeoutMs,
|
|
271
|
-
|
|
272
|
+
onProcessStart: async (identity) => {
|
|
273
|
+
await input.onProcessStart?.(identity);
|
|
274
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
275
|
+
type: 'agent.process.started',
|
|
276
|
+
runId: input.runId,
|
|
277
|
+
projection: input.projection,
|
|
278
|
+
routing: input.routing,
|
|
279
|
+
cli: CODEX_CLI_NAME,
|
|
280
|
+
model,
|
|
281
|
+
payload: { pid: identity.pid, processStartedAt: identity.processStartedAt },
|
|
282
|
+
}));
|
|
283
|
+
},
|
|
272
284
|
});
|
|
273
285
|
const responseTranscriptPath = await writeRunnerTranscript({
|
|
274
286
|
config: input.config,
|
|
@@ -300,6 +312,15 @@ export function createCodexRunner(options) {
|
|
|
300
312
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
301
313
|
exitCode: result.exitCode,
|
|
302
314
|
}));
|
|
315
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
316
|
+
type: 'agent.process.exited',
|
|
317
|
+
runId: input.runId,
|
|
318
|
+
projection: input.projection,
|
|
319
|
+
routing: input.routing,
|
|
320
|
+
cli: CODEX_CLI_NAME,
|
|
321
|
+
model,
|
|
322
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
323
|
+
}));
|
|
303
324
|
return {
|
|
304
325
|
result: [
|
|
305
326
|
result.timedOut
|
|
@@ -331,6 +352,60 @@ export function createCodexRunner(options) {
|
|
|
331
352
|
}
|
|
332
353
|
const parsed = extractCodexExecResult(result.stdout);
|
|
333
354
|
const sandboxLog = readSandboxLogBreadcrumb();
|
|
355
|
+
const rawEvents = result.stdout
|
|
356
|
+
.split(/\r?\n/)
|
|
357
|
+
.filter((line) => line.trim().length > 0)
|
|
358
|
+
.map((line) => JSON.parse(line));
|
|
359
|
+
for (const raw of rawEvents) {
|
|
360
|
+
if (raw.type === 'thread.started' && typeof raw.thread_id === 'string') {
|
|
361
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
362
|
+
type: 'agent.session.started',
|
|
363
|
+
runId: input.runId,
|
|
364
|
+
projection: input.projection,
|
|
365
|
+
routing: input.routing,
|
|
366
|
+
cli: CODEX_CLI_NAME,
|
|
367
|
+
model,
|
|
368
|
+
sessionId: raw.thread_id,
|
|
369
|
+
payload: { raw },
|
|
370
|
+
}));
|
|
371
|
+
}
|
|
372
|
+
else if (raw.type === 'turn.completed') {
|
|
373
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
374
|
+
type: 'agent.turn.completed',
|
|
375
|
+
runId: input.runId,
|
|
376
|
+
projection: input.projection,
|
|
377
|
+
routing: input.routing,
|
|
378
|
+
cli: CODEX_CLI_NAME,
|
|
379
|
+
model,
|
|
380
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
381
|
+
payload: { raw },
|
|
382
|
+
}));
|
|
383
|
+
}
|
|
384
|
+
else if (raw.type === 'item.completed') {
|
|
385
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
386
|
+
type: 'agent.progress',
|
|
387
|
+
runId: input.runId,
|
|
388
|
+
projection: input.projection,
|
|
389
|
+
routing: input.routing,
|
|
390
|
+
cli: CODEX_CLI_NAME,
|
|
391
|
+
model,
|
|
392
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
393
|
+
payload: { raw },
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (parsed.tokenUsage !== undefined) {
|
|
398
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
399
|
+
type: 'agent.usage.updated',
|
|
400
|
+
runId: input.runId,
|
|
401
|
+
projection: input.projection,
|
|
402
|
+
routing: input.routing,
|
|
403
|
+
cli: CODEX_CLI_NAME,
|
|
404
|
+
model,
|
|
405
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
406
|
+
payload: { tokenUsage: parsed.tokenUsage },
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
334
409
|
console.log(formatCodexRunLogLine({
|
|
335
410
|
phase: 'success',
|
|
336
411
|
runId: input.runId,
|
|
@@ -342,6 +417,16 @@ export function createCodexRunner(options) {
|
|
|
342
417
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
343
418
|
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
344
419
|
}));
|
|
420
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
421
|
+
type: 'agent.process.exited',
|
|
422
|
+
runId: input.runId,
|
|
423
|
+
projection: input.projection,
|
|
424
|
+
routing: input.routing,
|
|
425
|
+
cli: CODEX_CLI_NAME,
|
|
426
|
+
model,
|
|
427
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
428
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
429
|
+
}));
|
|
345
430
|
return {
|
|
346
431
|
result: parsed.result,
|
|
347
432
|
model,
|
|
@@ -354,10 +439,7 @@ export function createCodexRunner(options) {
|
|
|
354
439
|
metadata: {
|
|
355
440
|
stdout: result.stdout,
|
|
356
441
|
stderr: result.stderr,
|
|
357
|
-
raw:
|
|
358
|
-
.split(/\r?\n/)
|
|
359
|
-
.filter((line) => line.trim().length > 0)
|
|
360
|
-
.map((line) => JSON.parse(line)),
|
|
442
|
+
raw: rawEvents,
|
|
361
443
|
skipApproval: stagePrompt.skipApproval,
|
|
362
444
|
allowAutoApproval: stagePrompt.allowAutoApproval,
|
|
363
445
|
...(promptTranscriptPath === undefined ? {} : { promptTranscriptPath }),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseRunnerResult } from '../../domain/schema.js';
|
|
2
2
|
import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
3
3
|
import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
4
|
+
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
4
5
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
5
6
|
const CURSOR_CLI_NAME = 'Cursor';
|
|
6
7
|
export function buildCursorAgentArgs(input) {
|
|
@@ -219,7 +220,18 @@ export function createCursorRunner(options) {
|
|
|
219
220
|
}),
|
|
220
221
|
cwd,
|
|
221
222
|
timeoutMs: options.settings.timeoutMs,
|
|
222
|
-
|
|
223
|
+
onProcessStart: async (identity) => {
|
|
224
|
+
await input.onProcessStart?.(identity);
|
|
225
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
226
|
+
type: 'agent.process.started',
|
|
227
|
+
runId: input.runId,
|
|
228
|
+
projection: input.projection,
|
|
229
|
+
routing: input.routing,
|
|
230
|
+
cli: CURSOR_CLI_NAME,
|
|
231
|
+
model,
|
|
232
|
+
payload: { pid: identity.pid, processStartedAt: identity.processStartedAt },
|
|
233
|
+
}));
|
|
234
|
+
},
|
|
223
235
|
});
|
|
224
236
|
const responseTranscriptPath = await writeRunnerTranscript({
|
|
225
237
|
config: input.config,
|
|
@@ -248,6 +260,15 @@ export function createCursorRunner(options) {
|
|
|
248
260
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
249
261
|
exitCode: result.exitCode,
|
|
250
262
|
}));
|
|
263
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
264
|
+
type: 'agent.process.exited',
|
|
265
|
+
runId: input.runId,
|
|
266
|
+
projection: input.projection,
|
|
267
|
+
routing: input.routing,
|
|
268
|
+
cli: CURSOR_CLI_NAME,
|
|
269
|
+
model,
|
|
270
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
271
|
+
}));
|
|
251
272
|
return {
|
|
252
273
|
result: [
|
|
253
274
|
result.timedOut
|
|
@@ -299,6 +320,28 @@ export function createCursorRunner(options) {
|
|
|
299
320
|
};
|
|
300
321
|
}
|
|
301
322
|
const sandboxLog = readSandboxLogBreadcrumb();
|
|
323
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
324
|
+
type: 'agent.progress',
|
|
325
|
+
runId: input.runId,
|
|
326
|
+
projection: input.projection,
|
|
327
|
+
routing: input.routing,
|
|
328
|
+
cli: CURSOR_CLI_NAME,
|
|
329
|
+
model,
|
|
330
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
331
|
+
payload: { message: 'Cursor agent result received', raw: parsed },
|
|
332
|
+
}));
|
|
333
|
+
if (parsed.tokenUsage !== undefined) {
|
|
334
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
335
|
+
type: 'agent.usage.updated',
|
|
336
|
+
runId: input.runId,
|
|
337
|
+
projection: input.projection,
|
|
338
|
+
routing: input.routing,
|
|
339
|
+
cli: CURSOR_CLI_NAME,
|
|
340
|
+
model,
|
|
341
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
342
|
+
payload: { tokenUsage: parsed.tokenUsage },
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
302
345
|
console.log(formatCursorRunLogLine({
|
|
303
346
|
phase: 'success',
|
|
304
347
|
runId: input.runId,
|
|
@@ -310,6 +353,16 @@ export function createCursorRunner(options) {
|
|
|
310
353
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
311
354
|
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
312
355
|
}));
|
|
356
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
357
|
+
type: 'agent.process.exited',
|
|
358
|
+
runId: input.runId,
|
|
359
|
+
projection: input.projection,
|
|
360
|
+
routing: input.routing,
|
|
361
|
+
cli: CURSOR_CLI_NAME,
|
|
362
|
+
model,
|
|
363
|
+
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
364
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
365
|
+
}));
|
|
313
366
|
return {
|
|
314
367
|
result: parsed.result,
|
|
315
368
|
model,
|
|
@@ -1,6 +1,37 @@
|
|
|
1
|
+
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
1
2
|
export function createFakeRunner(result, options) {
|
|
2
3
|
return {
|
|
3
4
|
async run(_) {
|
|
5
|
+
const cli = options?.cli ?? 'Fake';
|
|
6
|
+
await emitRuntimeEvent(_.onRuntimeEvent, runnerRuntimeEvent({
|
|
7
|
+
type: 'agent.process.started',
|
|
8
|
+
runId: _.runId,
|
|
9
|
+
projection: _.projection,
|
|
10
|
+
routing: _.routing,
|
|
11
|
+
cli,
|
|
12
|
+
model: 'fake',
|
|
13
|
+
payload: { synthetic: true },
|
|
14
|
+
}));
|
|
15
|
+
await emitRuntimeEvent(_.onRuntimeEvent, runnerRuntimeEvent({
|
|
16
|
+
type: 'agent.progress',
|
|
17
|
+
runId: _.runId,
|
|
18
|
+
projection: _.projection,
|
|
19
|
+
routing: _.routing,
|
|
20
|
+
cli,
|
|
21
|
+
model: 'fake',
|
|
22
|
+
sessionId: 'fake-session-1',
|
|
23
|
+
payload: { message: 'Fake runner completed', synthetic: true },
|
|
24
|
+
}));
|
|
25
|
+
await emitRuntimeEvent(_.onRuntimeEvent, runnerRuntimeEvent({
|
|
26
|
+
type: 'agent.process.exited',
|
|
27
|
+
runId: _.runId,
|
|
28
|
+
projection: _.projection,
|
|
29
|
+
routing: _.routing,
|
|
30
|
+
cli,
|
|
31
|
+
model: 'fake',
|
|
32
|
+
sessionId: 'fake-session-1',
|
|
33
|
+
payload: { exitCode: 0, synthetic: true },
|
|
34
|
+
}));
|
|
4
35
|
return (result ?? {
|
|
5
36
|
result: [
|
|
6
37
|
'Fake runner completed',
|
|
@@ -11,7 +42,7 @@ export function createFakeRunner(result, options) {
|
|
|
11
42
|
'DONE',
|
|
12
43
|
].join('\n'),
|
|
13
44
|
model: 'fake',
|
|
14
|
-
cli
|
|
45
|
+
cli,
|
|
15
46
|
session_id: 'fake-session-1',
|
|
16
47
|
metadata: {
|
|
17
48
|
source: 'fake-runner',
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function runnerKindForCli(cli) {
|
|
2
|
+
if (cli === 'Claude') {
|
|
3
|
+
return 'claude';
|
|
4
|
+
}
|
|
5
|
+
if (cli === 'Codex') {
|
|
6
|
+
return 'codex';
|
|
7
|
+
}
|
|
8
|
+
if (cli === 'Cursor') {
|
|
9
|
+
return 'cursor';
|
|
10
|
+
}
|
|
11
|
+
return 'fake';
|
|
12
|
+
}
|
|
13
|
+
export function runnerRuntimeEvent(input) {
|
|
14
|
+
return {
|
|
15
|
+
type: input.type,
|
|
16
|
+
runId: input.runId,
|
|
17
|
+
workItemId: input.projection.workItemKey,
|
|
18
|
+
runner: {
|
|
19
|
+
name: input.routing?.runnerName ?? input.cli.toLowerCase(),
|
|
20
|
+
kind: input.routing?.runnerKind ?? runnerKindForCli(input.cli),
|
|
21
|
+
cli: input.cli,
|
|
22
|
+
...(input.model === undefined ? {} : { model: input.model }),
|
|
23
|
+
},
|
|
24
|
+
...(input.sessionId === undefined ? {} : { sessionId: input.sessionId }),
|
|
25
|
+
payload: input.payload ?? {},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export async function emitRuntimeEvent(emit, event) {
|
|
29
|
+
if (emit !== undefined) {
|
|
30
|
+
await emit(event);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -6,6 +6,7 @@ import { acquireFileLock } from '../lib/lock.js';
|
|
|
6
6
|
import { CORRELATION_REGISTERED_EVENT, CORRELATION_PRIMARY_CONFLICT_EVENT, parseRunnerArtifacts, parseRunnerResult, } from '../domain/schema.js';
|
|
7
7
|
import { maxConfiguredRunnerTimeoutMs, resolveRunnerRouting } from '../domain/runner-routing.js';
|
|
8
8
|
import { awaitingApprovalRunnerSentinel, stageLabelForStage } from '../domain/stages.js';
|
|
9
|
+
import { isMeaningfulRuntimeEvent } from '../domain/runtime-events.js';
|
|
9
10
|
import { chooseAction as chooseWorkflowAction, entryStage as workflowEntryStage, isKnownWorkflowStage, workflowChangedBlockReason, workflowForProjection, workflowLabelForWorkflowName, workflowNameForProjection, } from '../domain/workflows.js';
|
|
10
11
|
import { createEventEnvelope } from '../lib/event-log.js';
|
|
11
12
|
import { branchNameForIssue } from '../domain/branch-naming.js';
|
|
@@ -399,7 +400,17 @@ export function createTickRunner(deps) {
|
|
|
399
400
|
return watch;
|
|
400
401
|
}
|
|
401
402
|
async function markPendingActionableIssues(projections) {
|
|
403
|
+
const activeRunWorkItemKeys = new Set();
|
|
404
|
+
const now = deps.clock.now();
|
|
405
|
+
for (const record of await deps.stateStore.listRunRecords()) {
|
|
406
|
+
if (record.status === 'running' && (await isRunningRecordActive(record, now))) {
|
|
407
|
+
activeRunWorkItemKeys.add(record.workItemKey);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
402
410
|
for (const projection of projections) {
|
|
411
|
+
if (activeRunWorkItemKeys.has(projection.workItemKey)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
403
414
|
const statusLabel = statusLabelForStage(projection.wake.stage);
|
|
404
415
|
const stageLabel = stageLabelForStage(projection.wake.stage);
|
|
405
416
|
const workflowLabel = workflowLabelForWorkflowName(workflowNameForProjection(projection, deps.config));
|
|
@@ -1052,6 +1063,30 @@ export function createTickRunner(deps) {
|
|
|
1052
1063
|
lifecycle,
|
|
1053
1064
|
});
|
|
1054
1065
|
}
|
|
1066
|
+
async function appendRuntimeEvent(event) {
|
|
1067
|
+
const timestamp = event.timestamp ?? deps.clock.now().toISOString();
|
|
1068
|
+
await deps.stateStore.updateRunRecordIf(runId, {
|
|
1069
|
+
expect: (record) => record.status === 'running' &&
|
|
1070
|
+
record.lease?.leaseId === lease.leaseId &&
|
|
1071
|
+
record.lease.ownerInstanceId === ownerInstanceId,
|
|
1072
|
+
update: (record) => {
|
|
1073
|
+
const runtimeEvents = record.runtimeEvents ?? [];
|
|
1074
|
+
const sequence = event.sequence ?? runtimeEvents.length;
|
|
1075
|
+
const normalizedEvent = {
|
|
1076
|
+
...event,
|
|
1077
|
+
timestamp,
|
|
1078
|
+
sequence,
|
|
1079
|
+
};
|
|
1080
|
+
return {
|
|
1081
|
+
...record,
|
|
1082
|
+
runtimeEvents: [...runtimeEvents, normalizedEvent],
|
|
1083
|
+
...(isMeaningfulRuntimeEvent(normalizedEvent)
|
|
1084
|
+
? { lastMeaningfulActivityAt: normalizedEvent.timestamp }
|
|
1085
|
+
: {}),
|
|
1086
|
+
};
|
|
1087
|
+
},
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1055
1090
|
const claimedAt = eventStampNow();
|
|
1056
1091
|
const claimedEvent = createEventEnvelope({
|
|
1057
1092
|
eventId: `${runId}-claimed`,
|
|
@@ -1201,6 +1236,7 @@ export function createTickRunner(deps) {
|
|
|
1201
1236
|
}),
|
|
1202
1237
|
});
|
|
1203
1238
|
},
|
|
1239
|
+
onRuntimeEvent: appendRuntimeEvent,
|
|
1204
1240
|
});
|
|
1205
1241
|
clearInterval(leaseRenewalTimer);
|
|
1206
1242
|
leaseRenewalTimer = undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const runtimeEventTypeValues = [
|
|
2
|
+
'run.claimed',
|
|
3
|
+
'run.started',
|
|
4
|
+
'workspace.preparing',
|
|
5
|
+
'workspace.ready',
|
|
6
|
+
'agent.process.started',
|
|
7
|
+
'agent.session.started',
|
|
8
|
+
'agent.progress',
|
|
9
|
+
'agent.tool.requested',
|
|
10
|
+
'agent.approval.requested',
|
|
11
|
+
'agent.input.required',
|
|
12
|
+
'agent.usage.updated',
|
|
13
|
+
'agent.turn.completed',
|
|
14
|
+
'agent.process.exited',
|
|
15
|
+
'run.completed',
|
|
16
|
+
'run.failed',
|
|
17
|
+
'run.stalled',
|
|
18
|
+
'run.canceled',
|
|
19
|
+
];
|
|
20
|
+
export function isMeaningfulRuntimeEvent(event) {
|
|
21
|
+
return (event.type === 'agent.progress' ||
|
|
22
|
+
event.type === 'agent.tool.requested' ||
|
|
23
|
+
event.type === 'agent.approval.requested' ||
|
|
24
|
+
event.type === 'agent.input.required' ||
|
|
25
|
+
event.type === 'agent.usage.updated' ||
|
|
26
|
+
event.type === 'agent.turn.completed');
|
|
27
|
+
}
|
|
28
|
+
export function runtimeEventPayload(input) {
|
|
29
|
+
return {
|
|
30
|
+
...(input.message === undefined ? {} : { message: input.message }),
|
|
31
|
+
...(input.raw === undefined ? {} : { raw: input.raw }),
|
|
32
|
+
...(input.exitCode === undefined ? {} : { exitCode: input.exitCode }),
|
|
33
|
+
...(input.timedOut === undefined ? {} : { timedOut: input.timedOut }),
|
|
34
|
+
...(input.tokenUsage === undefined ? {} : { tokenUsage: input.tokenUsage }),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -5,6 +5,7 @@ import { z } from 'zod';
|
|
|
5
5
|
import { reservedCommandNames } from './custom-commands.js';
|
|
6
6
|
import { runnerSentinelValues } from './stages.js';
|
|
7
7
|
import { correlationProvenanceSchema, correlationRelationSchema, correlationRoleSchema, resourceUriSchema, } from './resource-uri.js';
|
|
8
|
+
import { runtimeEventTypeValues } from './runtime-events.js';
|
|
8
9
|
import { alwaysManualIgnoredLabels } from './manual-labels.js';
|
|
9
10
|
const isoTimestampSchema = z.string().datetime({ offset: true });
|
|
10
11
|
const identifierSchema = z.string().min(1);
|
|
@@ -47,6 +48,21 @@ export const executionAttemptLifecycleValues = [
|
|
|
47
48
|
export const executionOutcomeSchema = z.enum(executionOutcomeValues);
|
|
48
49
|
export const workflowOutcomeSchema = z.enum(workflowOutcomeValues);
|
|
49
50
|
export const executionAttemptLifecycleSchema = z.enum(executionAttemptLifecycleValues);
|
|
51
|
+
export const runtimeEventSchema = z.object({
|
|
52
|
+
type: z.enum(runtimeEventTypeValues),
|
|
53
|
+
runId: z.string(),
|
|
54
|
+
workItemId: z.string(),
|
|
55
|
+
runner: z.object({
|
|
56
|
+
name: z.string(),
|
|
57
|
+
kind: z.enum(['fake', 'claude', 'codex', 'cursor']),
|
|
58
|
+
cli: z.string(),
|
|
59
|
+
model: z.string().optional(),
|
|
60
|
+
}),
|
|
61
|
+
sessionId: z.string().optional(),
|
|
62
|
+
timestamp: isoTimestampSchema,
|
|
63
|
+
sequence: z.number().int().nonnegative(),
|
|
64
|
+
payload: z.record(z.string(), z.unknown()).default({}),
|
|
65
|
+
});
|
|
50
66
|
export const defaultAgentIdentity = 'Wake';
|
|
51
67
|
export const defaultSmokePrompt = `This is ${defaultAgentIdentity}, reply with "hi ${defaultAgentIdentity} only"`;
|
|
52
68
|
const modelOverridesSchema = z
|
|
@@ -361,6 +377,8 @@ export const runRecordSchema = z.preprocess((input) => {
|
|
|
361
377
|
workerProcessStartedAt: z.string().optional(),
|
|
362
378
|
agentPid: z.number().int().positive().optional(),
|
|
363
379
|
agentProcessStartedAt: z.string().optional(),
|
|
380
|
+
lastMeaningfulActivityAt: isoTimestampSchema.optional(),
|
|
381
|
+
runtimeEvents: z.array(runtimeEventSchema).optional(),
|
|
364
382
|
tokenUsage: runTokenUsageSchema.optional(),
|
|
365
383
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
366
384
|
}));
|
package/dist/src/version.js
CHANGED