ai-runtime-engine 2.8.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/README.md +30 -0
- package/dist/agents/admit.d.ts +9 -1
- package/dist/agents/admit.js +10 -2
- package/dist/agents/envelope.d.ts +21 -0
- package/dist/agents/envelope.js +39 -5
- package/dist/agents/finding.d.ts +9 -3
- package/dist/agents/finding.js +14 -3
- package/dist/agents/task.d.ts +37 -0
- package/dist/agents/task.js +22 -0
- package/dist/agents/worker.d.ts +12 -1
- package/dist/agents/worker.js +14 -1
- package/dist/cli/cli.js +1 -1
- package/dist/cli/interactive/repl.js +52 -0
- package/dist/cli/interactive/session.d.ts +8 -1
- package/dist/cli/interactive/session.js +62 -10
- package/dist/executions/agentTasks.d.ts +76 -75
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/orchestration/executor.js +5 -1
- package/dist/orchestration/orchestrator.d.ts +2 -1
- package/dist/orchestration/planner.d.ts +2 -1
- package/dist/runtime/config.js +1 -1
- package/dist/runtime/events.d.ts +44 -0
- package/dist/runtime/events.js +4 -0
- package/dist/runtime/runtime.d.ts +70 -3
- package/dist/runtime/runtime.js +288 -27
- package/dist/runtime/types.d.ts +6 -0
- package/package.json +1 -1
|
@@ -13,13 +13,17 @@ import { actionCapabilityRows, renderActionCapabilities, renderCapabilityGaps }
|
|
|
13
13
|
import { renderMcpList, renderMcpDetail } from '../commands/mcp.js';
|
|
14
14
|
import { candidatesFrom, deriveCapabilitiesOffline } from '../../runtime/planning/deriveCapabilities.js';
|
|
15
15
|
import { displaySafe } from '../render.js';
|
|
16
|
+
import { AGENT_TERMINAL } from '../../agents/task.js';
|
|
17
|
+
import { TERMINAL as EXEC_TERMINAL } from '../../executions/execution.js';
|
|
16
18
|
/** Top-level slash commands, for REPL tab-completion (Phase 21b). Kept in sync with the `handle` dispatch. */
|
|
17
19
|
export const SLASH_COMMANDS = [
|
|
18
20
|
'help', 'status', 'info', 'doctor', 'cleanup', 'mode', 'compare', 'models', 'config', 'providers', 'tools', 'capabilities', 'mcp',
|
|
19
|
-
'skills', 'memory', 'conversations', 'executions', 'resume', 'resume-execution', 'pause', 'cancel', 'approve',
|
|
21
|
+
'skills', 'memory', 'conversations', 'executions', 'agents', 'resume', 'resume-execution', 'pause', 'cancel', 'approve',
|
|
20
22
|
'deny', 'learning', 'feedback', 'permissions', 'budget', 'stream', 'dry-run', 'clear', 'exit', 'quit',
|
|
21
23
|
];
|
|
22
|
-
|
|
24
|
+
/** Exported so a test can prove every reachable command is documented — the three touch points below
|
|
25
|
+
* are synced by hand, and `/agents` shipped tab-completable but absent from this list. */
|
|
26
|
+
export const HELP = [
|
|
23
27
|
'Commands:',
|
|
24
28
|
' /help show this help',
|
|
25
29
|
' /status workspace, mode, provider count',
|
|
@@ -49,6 +53,8 @@ const HELP = [
|
|
|
49
53
|
' /conversations list recent conversations',
|
|
50
54
|
' /resume <id> resume a conversation',
|
|
51
55
|
' /executions list persisted executions',
|
|
56
|
+
' /agents list agent tasks (state, progress, spend, findings)',
|
|
57
|
+
' /agents stop <id> stop one agent task',
|
|
52
58
|
' /resume-execution <id> resume an execution',
|
|
53
59
|
' /approve <id> approve an execution waiting for approval, then continue',
|
|
54
60
|
' /deny <id> deny an execution waiting for approval (cancels it)',
|
|
@@ -59,7 +65,7 @@ const HELP = [
|
|
|
59
65
|
' /stream toggle token-by-token streaming of answers',
|
|
60
66
|
' /budget show the call/cost budget (AI_MAX_CALLS / AI_MAX_COST_USD)',
|
|
61
67
|
' /clear clear the screen',
|
|
62
|
-
' /exit
|
|
68
|
+
' /exit, /quit leave the session',
|
|
63
69
|
'',
|
|
64
70
|
'Anything else is sent to the runtime as a request.',
|
|
65
71
|
];
|
|
@@ -209,6 +215,8 @@ export class ReplSession {
|
|
|
209
215
|
return this.resume(args[0]);
|
|
210
216
|
case 'executions':
|
|
211
217
|
return this.executionsList();
|
|
218
|
+
case 'agents':
|
|
219
|
+
return args[0] === 'stop' ? this.agentStop(args[1]) : this.agentsList();
|
|
212
220
|
case 'resume-execution':
|
|
213
221
|
return this.resumeExecution(args[0]);
|
|
214
222
|
case 'approve':
|
|
@@ -327,6 +335,32 @@ export class ReplSession {
|
|
|
327
335
|
return { lines: ['no conversations yet.'] };
|
|
328
336
|
return { lines: ['Recent conversations:', ...list.map((c, i) => ` ${i + 1}. ${c.id} ${c.title} (${c.turns} turns)`)] };
|
|
329
337
|
}
|
|
338
|
+
/** Agent tasks across this project's executions, newest first. */
|
|
339
|
+
agentsList() {
|
|
340
|
+
if (!this.runtime.executionStore.enabled)
|
|
341
|
+
return { lines: ['agent tasks are not persisted (stateless mode).'] };
|
|
342
|
+
const tasks = this.runtime.agentTasks().slice(0, 12);
|
|
343
|
+
if (!tasks.length)
|
|
344
|
+
return { lines: ['no agent tasks yet.', '(agents run when `runtime.agents.enabled` is set and a plan delegates to one)'] };
|
|
345
|
+
// A waiting task's question goes on its own line: it is the one thing the user must read to act.
|
|
346
|
+
const lines = tasks.flatMap((t) => {
|
|
347
|
+
const steps = `${t.innerSteps.succeeded}/${t.innerSteps.total}`;
|
|
348
|
+
const spend = `${t.callsUsed}/${t.callsReserved} call(s), ${t.toolCallsUsed} tool call(s)`;
|
|
349
|
+
const why = t.interruption ? ` (${t.interruption.kind})` : '';
|
|
350
|
+
// `stepId` is planner-authored and `question` is model-authored: both go through displaySafe,
|
|
351
|
+
// like every other untrusted string this file renders.
|
|
352
|
+
const row = ` ${t.agentTaskId} [${t.state}] ${t.agentId} @ ${displaySafe(t.stepId, 40)} ${steps} inner step(s), ${spend}, ${t.findings} finding(s)${why}`;
|
|
353
|
+
return t.question ? [row, ` ? ${displaySafe(t.question, 200)}`] : [row];
|
|
354
|
+
});
|
|
355
|
+
return { lines: ['Agent tasks:', ...lines, '', 'stop one with /agents stop <agent-task-id>'] };
|
|
356
|
+
}
|
|
357
|
+
/** Stop one agent task. Every outcome is reported — a stop that looks like nothing happened is a bug. */
|
|
358
|
+
agentStop(id) {
|
|
359
|
+
if (!id)
|
|
360
|
+
return { lines: ['usage: /agents stop <agent-task-id>'] };
|
|
361
|
+
const r = this.runtime.stopAgentTask(id);
|
|
362
|
+
return { lines: [`${r.ok ? 'stopped' : 'not stopped'} ${id}: ${r.reason}${r.state ? ` (state: ${r.state})` : ''}`] };
|
|
363
|
+
}
|
|
330
364
|
executionsList() {
|
|
331
365
|
if (!this.runtime.executionStore.enabled)
|
|
332
366
|
return { lines: ['executions are disabled (stateless mode).'] };
|
|
@@ -362,13 +396,31 @@ export class ReplSession {
|
|
|
362
396
|
status() {
|
|
363
397
|
const ws = this.runtime.workspaceInfo();
|
|
364
398
|
const providers = this.runtime.ai.providers();
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
399
|
+
const lines = [
|
|
400
|
+
`workspace: ${ws?.name ?? '(none)'}${ws?.git.branch ? ` @ ${ws.git.branch}` : ''}`,
|
|
401
|
+
`mode: ${this.mode}`,
|
|
402
|
+
`providers: ${providers.length} configured (${providers.filter((p) => p.enabled).length} enabled)`,
|
|
403
|
+
];
|
|
404
|
+
// Phase 3.6: agent work is the one thing that can be UNFINISHED and invisible — a task left waiting
|
|
405
|
+
// or interrupted holds its execution up, so /status names it rather than leaving the user to think
|
|
406
|
+
// to run /agents. Absent entirely when nothing has ever delegated, so the flag-off output is
|
|
407
|
+
// unchanged.
|
|
408
|
+
// Only executions that are themselves still going: a non-terminal task on a finished execution is
|
|
409
|
+
// stale bookkeeping, and reporting it as "unfinished work" forever would train the user to ignore
|
|
410
|
+
// this line — which is the one line that has to be trusted when something IS waiting.
|
|
411
|
+
const live = this.runtime.executionStore.enabled ? this.runtime.executions().filter((e) => !EXEC_TERMINAL.has(e.status)) : [];
|
|
412
|
+
const tasks = live.flatMap((e) => this.runtime.agentTasks(e.id));
|
|
413
|
+
if (tasks.length) {
|
|
414
|
+
const unfinished = tasks.filter((t) => !AGENT_TERMINAL.has(t.state));
|
|
415
|
+
const waiting = unfinished.filter((t) => t.state === 'waiting_for_clarification' || t.state === 'waiting_for_input');
|
|
416
|
+
lines.push(`agents: ${tasks.length} task(s), ${unfinished.length} unfinished${waiting.length ? `, ${waiting.length} waiting for an answer` : ''}`);
|
|
417
|
+
for (const t of unfinished.slice(0, 3)) {
|
|
418
|
+
lines.push(` ${t.agentTaskId} [${t.state}] ${displaySafe(t.agentId, 24)} @ ${displaySafe(t.stepId, 16)} ${t.innerSteps.succeeded}/${t.innerSteps.total} step(s)`);
|
|
419
|
+
}
|
|
420
|
+
if (unfinished.length > 3)
|
|
421
|
+
lines.push(` … ${unfinished.length - 3} more (/agents)`);
|
|
422
|
+
}
|
|
423
|
+
return { lines };
|
|
372
424
|
}
|
|
373
425
|
setOrShowMode(next) {
|
|
374
426
|
if (!next)
|
|
@@ -35,11 +35,11 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
35
35
|
detail: z.ZodOptional<z.ZodString>;
|
|
36
36
|
}, "strict", z.ZodTypeAny, {
|
|
37
37
|
at: number;
|
|
38
|
-
kind: "
|
|
38
|
+
kind: "crash" | "pause" | "parent-cancel";
|
|
39
39
|
detail?: string | undefined;
|
|
40
40
|
}, {
|
|
41
41
|
at: number;
|
|
42
|
-
kind: "
|
|
42
|
+
kind: "crash" | "pause" | "parent-cancel";
|
|
43
43
|
detail?: string | undefined;
|
|
44
44
|
}>>;
|
|
45
45
|
provenance: z.ZodObject<{
|
|
@@ -361,42 +361,14 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
361
361
|
}, "strict", z.ZodTypeAny, {
|
|
362
362
|
v: 1;
|
|
363
363
|
state: "running" | "failed" | "completed" | "waiting_for_clarification" | "cancelled" | "paused" | "waiting_for_input" | "created" | "queued";
|
|
364
|
-
createdAt: number;
|
|
365
|
-
updatedAt: number;
|
|
366
364
|
stepId: string;
|
|
367
365
|
agentTaskId: string;
|
|
368
366
|
callsUsed: number;
|
|
369
|
-
envelopeHash: string;
|
|
370
367
|
agentId: string;
|
|
371
|
-
provenance: {
|
|
372
|
-
planVersion: number;
|
|
373
|
-
executionId?: string | undefined;
|
|
374
|
-
};
|
|
375
|
-
agentDefHash: string;
|
|
376
|
-
stepInputHash: string;
|
|
377
|
-
attempt: number;
|
|
378
|
-
innerCompletedSteps: string[];
|
|
379
|
-
innerObservations: z.objectOutputType<{
|
|
380
|
-
stepId: z.ZodString;
|
|
381
|
-
skill: z.ZodOptional<z.ZodString>;
|
|
382
|
-
tool: z.ZodOptional<z.ZodString>;
|
|
383
|
-
agent: z.ZodOptional<z.ZodString>;
|
|
384
|
-
agentTaskId: z.ZodOptional<z.ZodString>;
|
|
385
|
-
ok: z.ZodBoolean;
|
|
386
|
-
output: z.ZodOptional<z.ZodString>;
|
|
387
|
-
error: z.ZodOptional<z.ZodString>;
|
|
388
|
-
code: z.ZodOptional<z.ZodString>;
|
|
389
|
-
data: z.ZodOptional<z.ZodUnknown>;
|
|
390
|
-
artifacts: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
|
|
391
|
-
callsUsed: z.ZodOptional<z.ZodNumber>;
|
|
392
|
-
}, z.ZodTypeAny, "passthrough">[];
|
|
393
|
-
innerObservationsOmitted: number;
|
|
394
368
|
innerSteps: {
|
|
395
369
|
succeeded: number;
|
|
396
370
|
total: number;
|
|
397
371
|
};
|
|
398
|
-
callsReserved: number;
|
|
399
|
-
callsRefunded: number;
|
|
400
372
|
toolCallsUsed: number;
|
|
401
373
|
findings: z.objectOutputType<{
|
|
402
374
|
id: z.ZodString;
|
|
@@ -440,7 +412,42 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
440
412
|
supersededBy: z.ZodOptional<z.ZodString>;
|
|
441
413
|
createdAt: z.ZodNumber;
|
|
442
414
|
}, z.ZodTypeAny, "passthrough">[];
|
|
415
|
+
createdAt: number;
|
|
416
|
+
updatedAt: number;
|
|
417
|
+
envelopeHash: string;
|
|
418
|
+
provenance: {
|
|
419
|
+
planVersion: number;
|
|
420
|
+
executionId?: string | undefined;
|
|
421
|
+
};
|
|
422
|
+
agentDefHash: string;
|
|
423
|
+
stepInputHash: string;
|
|
424
|
+
attempt: number;
|
|
425
|
+
innerCompletedSteps: string[];
|
|
426
|
+
innerObservations: z.objectOutputType<{
|
|
427
|
+
stepId: z.ZodString;
|
|
428
|
+
skill: z.ZodOptional<z.ZodString>;
|
|
429
|
+
tool: z.ZodOptional<z.ZodString>;
|
|
430
|
+
agent: z.ZodOptional<z.ZodString>;
|
|
431
|
+
agentTaskId: z.ZodOptional<z.ZodString>;
|
|
432
|
+
ok: z.ZodBoolean;
|
|
433
|
+
output: z.ZodOptional<z.ZodString>;
|
|
434
|
+
error: z.ZodOptional<z.ZodString>;
|
|
435
|
+
code: z.ZodOptional<z.ZodString>;
|
|
436
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
437
|
+
artifacts: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
|
|
438
|
+
callsUsed: z.ZodOptional<z.ZodNumber>;
|
|
439
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
440
|
+
innerObservationsOmitted: number;
|
|
441
|
+
callsReserved: number;
|
|
442
|
+
callsRefunded: number;
|
|
443
443
|
diagnostics: unknown[];
|
|
444
|
+
interruption?: {
|
|
445
|
+
at: number;
|
|
446
|
+
kind: "crash" | "pause" | "parent-cancel";
|
|
447
|
+
detail?: string | undefined;
|
|
448
|
+
} | undefined;
|
|
449
|
+
startedAt?: number | undefined;
|
|
450
|
+
endedAt?: number | undefined;
|
|
444
451
|
innerPlan?: {
|
|
445
452
|
id: string;
|
|
446
453
|
version: number;
|
|
@@ -458,13 +465,6 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
458
465
|
goal: string;
|
|
459
466
|
reason?: string | undefined;
|
|
460
467
|
} | undefined;
|
|
461
|
-
startedAt?: number | undefined;
|
|
462
|
-
endedAt?: number | undefined;
|
|
463
|
-
interruption?: {
|
|
464
|
-
at: number;
|
|
465
|
-
kind: "pause" | "crash" | "parent-cancel";
|
|
466
|
-
detail?: string | undefined;
|
|
467
|
-
} | undefined;
|
|
468
468
|
innerPlanVersion?: number | undefined;
|
|
469
469
|
innerCheckpoint?: z.objectOutputType<{
|
|
470
470
|
at: z.ZodNumber;
|
|
@@ -488,42 +488,14 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
488
488
|
}, {
|
|
489
489
|
v: 1;
|
|
490
490
|
state: "running" | "failed" | "completed" | "waiting_for_clarification" | "cancelled" | "paused" | "waiting_for_input" | "created" | "queued";
|
|
491
|
-
createdAt: number;
|
|
492
|
-
updatedAt: number;
|
|
493
491
|
stepId: string;
|
|
494
492
|
agentTaskId: string;
|
|
495
493
|
callsUsed: number;
|
|
496
|
-
envelopeHash: string;
|
|
497
494
|
agentId: string;
|
|
498
|
-
provenance: {
|
|
499
|
-
planVersion: number;
|
|
500
|
-
executionId?: string | undefined;
|
|
501
|
-
};
|
|
502
|
-
agentDefHash: string;
|
|
503
|
-
stepInputHash: string;
|
|
504
|
-
attempt: number;
|
|
505
|
-
innerCompletedSteps: string[];
|
|
506
|
-
innerObservations: z.objectInputType<{
|
|
507
|
-
stepId: z.ZodString;
|
|
508
|
-
skill: z.ZodOptional<z.ZodString>;
|
|
509
|
-
tool: z.ZodOptional<z.ZodString>;
|
|
510
|
-
agent: z.ZodOptional<z.ZodString>;
|
|
511
|
-
agentTaskId: z.ZodOptional<z.ZodString>;
|
|
512
|
-
ok: z.ZodBoolean;
|
|
513
|
-
output: z.ZodOptional<z.ZodString>;
|
|
514
|
-
error: z.ZodOptional<z.ZodString>;
|
|
515
|
-
code: z.ZodOptional<z.ZodString>;
|
|
516
|
-
data: z.ZodOptional<z.ZodUnknown>;
|
|
517
|
-
artifacts: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
|
|
518
|
-
callsUsed: z.ZodOptional<z.ZodNumber>;
|
|
519
|
-
}, z.ZodTypeAny, "passthrough">[];
|
|
520
|
-
innerObservationsOmitted: number;
|
|
521
495
|
innerSteps: {
|
|
522
496
|
succeeded: number;
|
|
523
497
|
total: number;
|
|
524
498
|
};
|
|
525
|
-
callsReserved: number;
|
|
526
|
-
callsRefunded: number;
|
|
527
499
|
toolCallsUsed: number;
|
|
528
500
|
findings: z.objectInputType<{
|
|
529
501
|
id: z.ZodString;
|
|
@@ -567,7 +539,42 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
567
539
|
supersededBy: z.ZodOptional<z.ZodString>;
|
|
568
540
|
createdAt: z.ZodNumber;
|
|
569
541
|
}, z.ZodTypeAny, "passthrough">[];
|
|
542
|
+
createdAt: number;
|
|
543
|
+
updatedAt: number;
|
|
544
|
+
envelopeHash: string;
|
|
545
|
+
provenance: {
|
|
546
|
+
planVersion: number;
|
|
547
|
+
executionId?: string | undefined;
|
|
548
|
+
};
|
|
549
|
+
agentDefHash: string;
|
|
550
|
+
stepInputHash: string;
|
|
551
|
+
attempt: number;
|
|
552
|
+
innerCompletedSteps: string[];
|
|
553
|
+
innerObservations: z.objectInputType<{
|
|
554
|
+
stepId: z.ZodString;
|
|
555
|
+
skill: z.ZodOptional<z.ZodString>;
|
|
556
|
+
tool: z.ZodOptional<z.ZodString>;
|
|
557
|
+
agent: z.ZodOptional<z.ZodString>;
|
|
558
|
+
agentTaskId: z.ZodOptional<z.ZodString>;
|
|
559
|
+
ok: z.ZodBoolean;
|
|
560
|
+
output: z.ZodOptional<z.ZodString>;
|
|
561
|
+
error: z.ZodOptional<z.ZodString>;
|
|
562
|
+
code: z.ZodOptional<z.ZodString>;
|
|
563
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
564
|
+
artifacts: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
|
|
565
|
+
callsUsed: z.ZodOptional<z.ZodNumber>;
|
|
566
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
567
|
+
innerObservationsOmitted: number;
|
|
568
|
+
callsReserved: number;
|
|
569
|
+
callsRefunded: number;
|
|
570
570
|
diagnostics: unknown[];
|
|
571
|
+
interruption?: {
|
|
572
|
+
at: number;
|
|
573
|
+
kind: "crash" | "pause" | "parent-cancel";
|
|
574
|
+
detail?: string | undefined;
|
|
575
|
+
} | undefined;
|
|
576
|
+
startedAt?: number | undefined;
|
|
577
|
+
endedAt?: number | undefined;
|
|
571
578
|
innerPlan?: {
|
|
572
579
|
id: string;
|
|
573
580
|
version: number;
|
|
@@ -585,13 +592,6 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
585
592
|
goal: string;
|
|
586
593
|
reason?: string | undefined;
|
|
587
594
|
} | undefined;
|
|
588
|
-
startedAt?: number | undefined;
|
|
589
|
-
endedAt?: number | undefined;
|
|
590
|
-
interruption?: {
|
|
591
|
-
at: number;
|
|
592
|
-
kind: "pause" | "crash" | "parent-cancel";
|
|
593
|
-
detail?: string | undefined;
|
|
594
|
-
} | undefined;
|
|
595
595
|
innerPlanVersion?: number | undefined;
|
|
596
596
|
innerCheckpoint?: z.objectInputType<{
|
|
597
597
|
at: z.ZodNumber;
|
|
@@ -613,15 +613,16 @@ export declare const persistedAgentTask: z.ZodObject<{
|
|
|
613
613
|
message: z.ZodString;
|
|
614
614
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
615
615
|
}>;
|
|
616
|
-
|
|
616
|
+
/** The result of reading agent tasks back: what parsed, and how much did not. */
|
|
617
|
+
export interface AgentTasksRead {
|
|
617
618
|
tasks: AgentTaskRecord[];
|
|
618
|
-
/** Records that failed validation and were left out
|
|
619
|
+
/** Records that failed validation and were left out (still on disk, untouched). */
|
|
619
620
|
dropped: number;
|
|
620
621
|
}
|
|
621
622
|
/**
|
|
622
623
|
* Validate the agent tasks on an execution. Pure: it reads, it never writes. Callers that then persist
|
|
623
624
|
* the execution are choosing to drop the unparseable records — reading alone never does.
|
|
624
625
|
*/
|
|
625
|
-
export declare function parseAgentTasks(exec: Pick<Execution, 'agentTasks'>):
|
|
626
|
+
export declare function parseAgentTasks(exec: Pick<Execution, 'agentTasks'>): AgentTasksRead;
|
|
626
627
|
/** One task by id, validated — the lookup every resume path uses. */
|
|
627
628
|
export declare function findAgentTask(exec: Pick<Execution, 'agentTasks'>, agentTaskId: string): AgentTaskRecord | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -102,8 +102,9 @@ export type { AdmissionRejection, AdmissionResult } from './agents/admit.js';
|
|
|
102
102
|
export type { StepObservationCode } from './orchestration/executor.js';
|
|
103
103
|
export { PLAN_STEP_STATUSES } from './orchestration/plan.js';
|
|
104
104
|
export { parseAgentTasks, findAgentTask } from './executions/agentTasks.js';
|
|
105
|
-
export type {
|
|
106
|
-
export { AGENT_TERMINAL, AGENT_RESUMABLE } from './agents/task.js';
|
|
105
|
+
export type { AgentTasksRead } from './executions/agentTasks.js';
|
|
106
|
+
export { AGENT_TERMINAL, AGENT_RESUMABLE, agentTaskView } from './agents/task.js';
|
|
107
|
+
export type { AgentTaskView } from './agents/task.js';
|
|
107
108
|
export type { ProgressSnapshot } from './orchestration/executor.js';
|
|
108
109
|
export { mcpToolId } from './mcp/toolAdapter.js';
|
|
109
110
|
export { MCP_PROTOCOL_VERSION } from './mcp/protocol.js';
|
package/dist/index.js
CHANGED
|
@@ -80,7 +80,7 @@ export { PLAN_STEP_STATUSES } from './orchestration/plan.js';
|
|
|
80
80
|
// trust records this version cannot parse. The state sets are exported with it because "is this task
|
|
81
81
|
// finished?" must have one answer, not one per caller.
|
|
82
82
|
export { parseAgentTasks, findAgentTask } from './executions/agentTasks.js';
|
|
83
|
-
export { AGENT_TERMINAL, AGENT_RESUMABLE } from './agents/task.js';
|
|
83
|
+
export { AGENT_TERMINAL, AGENT_RESUMABLE, agentTaskView } from './agents/task.js';
|
|
84
84
|
// ── MCP connectivity (Phase 3.2) — external servers as ordinary Runtime tools ──
|
|
85
85
|
// The CONFIG + STATUS surface is public; the client, transports, and manager internals are not, so the
|
|
86
86
|
// wire implementation stays free to change without a breaking release.
|
|
@@ -34,7 +34,11 @@ async function runStepInner(step, deps) {
|
|
|
34
34
|
if (step.agent) {
|
|
35
35
|
if (!deps.runAgent)
|
|
36
36
|
return { stepId: step.id, agent: step.agent, ok: false, code: 'agent-not-enabled', error: 'agent execution is not enabled' };
|
|
37
|
-
return
|
|
37
|
+
// `return await`, NOT a bare return. In an async function a returned promise is ADOPTED, not
|
|
38
|
+
// caught, so a bare return here escapes this try/catch entirely: a throwing agent rejected the
|
|
39
|
+
// whole executePlan instead of failing its own step, and left its wave-mates running unawaited.
|
|
40
|
+
// The skill and tool branches above both await, which is why only agents had this hole.
|
|
41
|
+
return await deps.runAgent(step, { reservation: stepCalls(step, Number.POSITIVE_INFINITY, deps.reserve), ...(deps.signal ? { signal: deps.signal } : {}) });
|
|
38
42
|
}
|
|
39
43
|
return { stepId: step.id, ok: false, error: 'step names neither a skill nor a tool' };
|
|
40
44
|
}
|
|
@@ -43,7 +43,8 @@ export interface OrchestrateInput {
|
|
|
43
43
|
routing?: RoutingPreferences;
|
|
44
44
|
/** Phase 22: run the phases that fit the call budget and pause resumably (vs. the default notify-and-wait). */
|
|
45
45
|
partial?: boolean;
|
|
46
|
-
/** Phase 3.1: pre-rendered action-capability snapshot for the planner prompt
|
|
46
|
+
/** Phase 3.1: pre-rendered, fenced action-capability snapshot for the planner prompt. Present by
|
|
47
|
+
* default from 3.0.0; `runtime.capabilities.catalog: false` removes it. */
|
|
47
48
|
capabilityCatalog?: string;
|
|
48
49
|
/** Phase 3.3: pre-rendered "Required capabilities" block for the planner prompt (opt-in). */
|
|
49
50
|
requiredCapabilities?: string;
|
|
@@ -18,7 +18,8 @@ export interface PlannerInput {
|
|
|
18
18
|
reason?: string;
|
|
19
19
|
/** Observations from a prior attempt, to inform a replan. */
|
|
20
20
|
priorObservations?: string[];
|
|
21
|
-
/** Phase 3.1: a pre-rendered, capped, fenced action-capability snapshot
|
|
21
|
+
/** Phase 3.1: a pre-rendered, capped, fenced action-capability snapshot (fenced for real as of
|
|
22
|
+
* 3.0.0, and present by default from it). Absent ⇒ the prompt is
|
|
22
23
|
* byte-identical to 2.3.0 (the catalog flag is off by default). */
|
|
23
24
|
capabilityCatalog?: string;
|
|
24
25
|
/** Phase 3.3: a pre-rendered, clamped block naming the capabilities the goal was derived to need and
|
package/dist/runtime/config.js
CHANGED
|
@@ -40,7 +40,7 @@ const agentDefinition = z
|
|
|
40
40
|
.strict();
|
|
41
41
|
/** An agent definition id: the same prompt-safe shape an MCP server id must have. */
|
|
42
42
|
const AGENT_ID_RE = /^[a-z0-9][a-z0-9_-]{0,32}$/;
|
|
43
|
-
const runtimeSettings = z.object({ defaultMode: z.enum(RUNTIME_MODES).optional(), defaultStrategy: z.enum(STRATEGIES).optional(), context: z.object({ maxTokens: z.number().optional(), verifyLoss: z.boolean().optional(), summarize: z.boolean().optional() }).strict().optional(), skills: z.object({ paths: z.array(z.string()).optional(), packages: z.array(z.string()).optional(), autoload: z.boolean().optional() }).strict().optional(), embedding: z.object({ provider: z.enum(['local', 'openai-compatible']), baseUrl: z.string().optional(), apiKeyEnv: z.string().optional(), model: z.string().optional() }).strict().optional(), intent: z.object({ aiFallback: z.boolean().optional() }).strict().optional(), organization: z.string().optional(), storage: z.object({ encrypt: z.boolean(), keyEnv: z.string() }).strict().optional(), capabilities: z.object({ catalog: z.boolean().optional(), planning: z.boolean().optional(), aliases: z.record(z.string(), z.string()).optional(), pins: z.record(z.string(), z.string()).optional() }).strict().optional(), concurrency: z.object({ maxParallelSteps: z.number().optional(), perTool: z.record(z.string(), z.number()).optional(), perSkill: z.record(z.string(), z.number()).optional(), perProvider: z.record(z.string(), z.number()).optional(), perAgent: z.record(z.string(), z.number()).optional() }).strict().optional(), agents: z.object({ enabled: z.boolean().optional(), maxToolCalls: z.number().optional(), maxDurationMs: z.number().optional(), maxInnerCalls: z.number().optional(), definitions: z.record(z.string().regex(AGENT_ID_RE, 'an agent definition id must be lowercase kebab/snake (max 33 chars)'), agentDefinition).optional() }).strict().optional() }).strict();
|
|
43
|
+
const runtimeSettings = z.object({ defaultMode: z.enum(RUNTIME_MODES).optional(), defaultStrategy: z.enum(STRATEGIES).optional(), context: z.object({ maxTokens: z.number().optional(), verifyLoss: z.boolean().optional(), summarize: z.boolean().optional() }).strict().optional(), skills: z.object({ paths: z.array(z.string()).optional(), packages: z.array(z.string()).optional(), autoload: z.boolean().optional() }).strict().optional(), embedding: z.object({ provider: z.enum(['local', 'openai-compatible']), baseUrl: z.string().optional(), apiKeyEnv: z.string().optional(), model: z.string().optional() }).strict().optional(), intent: z.object({ aiFallback: z.boolean().optional() }).strict().optional(), organization: z.string().optional(), storage: z.object({ encrypt: z.boolean(), keyEnv: z.string() }).strict().optional(), capabilities: z.object({ catalog: z.boolean().optional(), planning: z.boolean().optional(), aliases: z.record(z.string(), z.string()).optional(), pins: z.record(z.string(), z.string()).optional() }).strict().optional(), concurrency: z.object({ maxParallelSteps: z.number().optional(), perTool: z.record(z.string(), z.number()).optional(), perSkill: z.record(z.string(), z.number()).optional(), perProvider: z.record(z.string(), z.number()).optional(), perAgent: z.record(z.string(), z.number()).optional() }).strict().optional(), agents: z.object({ enabled: z.boolean().optional(), decompose: z.boolean().optional(), maxToolCalls: z.number().optional(), maxDurationMs: z.number().optional(), maxInnerCalls: z.number().optional(), definitions: z.record(z.string().regex(AGENT_ID_RE, 'an agent definition id must be lowercase kebab/snake (max 33 chars)').refine((id) => !id.startsWith('auto_'), 'the `auto_` prefix is reserved for agents the runtime derives — pick another id'), agentDefinition).optional() }).strict().optional() }).strict();
|
|
44
44
|
const learning = z.object({ enabled: z.boolean().optional() }).strict();
|
|
45
45
|
const verification = z.object({ enabled: z.boolean().optional() }).strict();
|
|
46
46
|
const budget = z.object({ maxCostUsd: z.number().optional(), maxCalls: z.number().optional() }).strict();
|
package/dist/runtime/events.d.ts
CHANGED
|
@@ -6,10 +6,15 @@
|
|
|
6
6
|
* Token-streaming extension point: `response.delta` is reserved here (content-bearing, redacted like
|
|
7
7
|
* everything else). Provider token streaming is NOT implemented in 1.0 — no delta is ever emitted yet —
|
|
8
8
|
* but declaring the arm keeps the host/emitter architecture ready for it without a breaking change.
|
|
9
|
+
*
|
|
10
|
+
* EVOLUTION CONTRACT: this union GROWS. A new arm is additive at runtime — an existing consumer keeps
|
|
11
|
+
* receiving the events it knows — but it breaks an exhaustive `switch` at COMPILE time. Consumers must
|
|
12
|
+
* carry a default case. Arms added this way are announced in the CHANGELOG.
|
|
9
13
|
*/
|
|
10
14
|
import type { Clock } from '../util/clock.js';
|
|
11
15
|
import type { ErrorCategory } from '../types.js';
|
|
12
16
|
import type { ExecutableMode, ModeSource, RuntimeMode, RuntimeStatus } from './types.js';
|
|
17
|
+
import type { AgentTaskState } from '../agents/task.js';
|
|
13
18
|
export type RuntimeEvent = {
|
|
14
19
|
type: 'runtime.started';
|
|
15
20
|
ts: number;
|
|
@@ -54,6 +59,45 @@ export type RuntimeEvent = {
|
|
|
54
59
|
ts: number;
|
|
55
60
|
runId: string;
|
|
56
61
|
text: string;
|
|
62
|
+
} | {
|
|
63
|
+
type: 'agent.task.started';
|
|
64
|
+
ts: number;
|
|
65
|
+
runId: string;
|
|
66
|
+
agentTaskId: string;
|
|
67
|
+
agentId: string;
|
|
68
|
+
stepId: string;
|
|
69
|
+
state: AgentTaskState;
|
|
70
|
+
} | {
|
|
71
|
+
type: 'agent.task.progress';
|
|
72
|
+
ts: number;
|
|
73
|
+
runId: string;
|
|
74
|
+
agentTaskId: string;
|
|
75
|
+
agentId: string;
|
|
76
|
+
stepId: string;
|
|
77
|
+
/** Per inner WAVE, never per inner step: a chatty agent would otherwise flood the ring buffer
|
|
78
|
+
* and push every other event out of it. */
|
|
79
|
+
innerSteps: {
|
|
80
|
+
total: number;
|
|
81
|
+
succeeded: number;
|
|
82
|
+
};
|
|
83
|
+
callsUsed: number;
|
|
84
|
+
toolCallsUsed: number;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'agent.task.completed';
|
|
87
|
+
ts: number;
|
|
88
|
+
runId: string;
|
|
89
|
+
agentTaskId: string;
|
|
90
|
+
agentId: string;
|
|
91
|
+
stepId: string;
|
|
92
|
+
state: AgentTaskState;
|
|
93
|
+
innerSteps: {
|
|
94
|
+
total: number;
|
|
95
|
+
succeeded: number;
|
|
96
|
+
};
|
|
97
|
+
callsUsed: number;
|
|
98
|
+
toolCallsUsed: number;
|
|
99
|
+
/** How many findings were ADMITTED. Never the findings themselves. */
|
|
100
|
+
findings: number;
|
|
57
101
|
};
|
|
58
102
|
/** Distributive Omit so an event can be emitted without pre-stamping `ts`. */
|
|
59
103
|
type WithoutTs<T> = T extends unknown ? Omit<T, 'ts'> : never;
|
package/dist/runtime/events.js
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* Token-streaming extension point: `response.delta` is reserved here (content-bearing, redacted like
|
|
7
7
|
* everything else). Provider token streaming is NOT implemented in 1.0 — no delta is ever emitted yet —
|
|
8
8
|
* but declaring the arm keeps the host/emitter architecture ready for it without a breaking change.
|
|
9
|
+
*
|
|
10
|
+
* EVOLUTION CONTRACT: this union GROWS. A new arm is additive at runtime — an existing consumer keeps
|
|
11
|
+
* receiving the events it knows — but it breaks an exhaustive `switch` at COMPILE time. Consumers must
|
|
12
|
+
* carry a default case. Arms added this way are announced in the CHANGELOG.
|
|
9
13
|
*/
|
|
10
14
|
import { systemClock } from '../util/clock.js';
|
|
11
15
|
import { redact } from '../security/redact.js';
|
|
@@ -25,6 +25,7 @@ import type { SkillSource, LoadedSource } from '../skills/discovery.js';
|
|
|
25
25
|
import type { AgentDefinition } from '../agents/definition.js';
|
|
26
26
|
import { ExecutionStore } from '../executions/store.js';
|
|
27
27
|
import type { Execution } from '../executions/execution.js';
|
|
28
|
+
import type { AgentTaskState, AgentTaskView } from '../agents/task.js';
|
|
28
29
|
import { ArtifactStore } from '../artifacts/artifacts.js';
|
|
29
30
|
import type { CompareInput } from '../comparison/comparator.js';
|
|
30
31
|
import type { ComparisonResult } from '../comparison/comparison.js';
|
|
@@ -87,6 +88,8 @@ export declare class Runtime {
|
|
|
87
88
|
/** Live runs, so a pause/cancel can abort the agent tasks actually in flight. Only ever populated
|
|
88
89
|
* when agents are enabled, so pause/cancel are unchanged with the flag off. */
|
|
89
90
|
private readonly liveRuns;
|
|
91
|
+
/** Phase 3.6: agent tasks running RIGHT NOW in this process, and how to stop each one on its own. */
|
|
92
|
+
private readonly liveAgentTasks;
|
|
90
93
|
/** The config file's `budget:` ceilings, kept only so the 3.3 pre-pass can decline a model call. */
|
|
91
94
|
private readonly _configBudget?;
|
|
92
95
|
private readonly approval?;
|
|
@@ -175,6 +178,15 @@ export declare class Runtime {
|
|
|
175
178
|
* This run's agent envelopes. THE ONLY call site of `narrowEnvelope` — never re-derive an inner
|
|
176
179
|
* catalog, a permission clamp, or a reservation anywhere else (see the header of agents/envelope.ts).
|
|
177
180
|
*/
|
|
181
|
+
/**
|
|
182
|
+
* Agents synthesized from the registry for this goal (Phase 3.7). Empty unless
|
|
183
|
+
* `runtime.agents.decompose` is on — so with the flag off nothing about planning changes.
|
|
184
|
+
*
|
|
185
|
+
* Deterministic and offline: no model call, no clock, no randomness. That is a requirement, not a
|
|
186
|
+
* preference — a derived definition is hashed into `agentDefHash`, and a resume that synthesized
|
|
187
|
+
* even slightly differently would discard every persisted inner plan as stale.
|
|
188
|
+
*/
|
|
189
|
+
private derivedAgents;
|
|
178
190
|
private agentEnvelopes;
|
|
179
191
|
/** The MCP server manager: `list()`, `status(id)`, `test(id)`, `addServer`, `removeServer`, `setEnabled`. */
|
|
180
192
|
mcp(): McpManager;
|
|
@@ -285,14 +297,28 @@ export declare class Runtime {
|
|
|
285
297
|
private runPersistence;
|
|
286
298
|
/** Run `fn` while heartbeating the execution lease so a long run never lets the lease expire. */
|
|
287
299
|
private withHeartbeat;
|
|
300
|
+
/**
|
|
301
|
+
* Build the OrchestrateInput. The optional half is an OBJECT, not a positional tail: this function
|
|
302
|
+
* grew to ten parameters and a caller that passed five of them silently got no sink, no signal and no
|
|
303
|
+
* provenance — a replan that persisted nothing and could not be cancelled. Named fields cannot be
|
|
304
|
+
* short-counted.
|
|
305
|
+
*/
|
|
288
306
|
private orchestrateInput;
|
|
289
307
|
/** Record an EXECUTED orchestration outcome for learning. plan-only, dry-run, and waiting states are
|
|
290
308
|
* skipped — no skill ran, so there is no success/failure to learn (recording them would teach noise). */
|
|
291
309
|
private recordOrchestration;
|
|
292
310
|
/**
|
|
293
|
-
* A capped, FENCED action-capability snapshot for the planner prompt (Phase 3.1
|
|
294
|
-
*
|
|
295
|
-
*
|
|
311
|
+
* A capped, FENCED action-capability snapshot for the planner prompt (Phase 3.1; ON by default from
|
|
312
|
+
* 3.0.0 — set `runtime.capabilities.catalog: false` to remove it).
|
|
313
|
+
*
|
|
314
|
+
* The fence is real as of 3.0.0 and was not before: this block carries ids that come from MCP servers
|
|
315
|
+
* and third-party skills, and it renders them as trusted-looking prompt structure on every planning
|
|
316
|
+
* iteration of every run. Flattening (`promptSafe`) bounds their shape but says nothing about their
|
|
317
|
+
* provenance, so the whole block is wrapped as untrusted data. Three comments claimed "fenced" while
|
|
318
|
+
* no fence existed; shipping that ON by default would have made a false safety claim load-bearing.
|
|
319
|
+
*
|
|
320
|
+
* Both halves are bounded. The blocked-skill list had no cap at all — measured at ~24k characters
|
|
321
|
+
* with 300 blocked skills, silently, in every prompt.
|
|
296
322
|
*/
|
|
297
323
|
private capabilityCatalogText;
|
|
298
324
|
/** Any call/cost ceiling declared in the config file's `budget:` block (router-level, not policy). */
|
|
@@ -364,6 +390,26 @@ export declare class Runtime {
|
|
|
364
390
|
* an agent step would have failed every one of those steps.
|
|
365
391
|
*/
|
|
366
392
|
private orchestrateRunners;
|
|
393
|
+
/**
|
|
394
|
+
* Reconcile findings that contradict each other, across ALL of this execution's agent tasks
|
|
395
|
+
* (Phase 3.7).
|
|
396
|
+
*
|
|
397
|
+
* `resolveConflicts` has existed since 3.4 with no caller, so two agents reaching opposite
|
|
398
|
+
* conclusions about the same subject both stayed `active` — and both were rendered into the next
|
|
399
|
+
* planning prompt, as if the runtime had no opinion about which was better supported. It does: it
|
|
400
|
+
* weighs evidence-based `confidence`, with `executionCoverage` only as a tiebreak.
|
|
401
|
+
*
|
|
402
|
+
* Runs at the ONE point new findings can appear — a task reaching a terminal state — and writes the
|
|
403
|
+
* outcome back onto the owning records, so a supersession survives a restart rather than being
|
|
404
|
+
* recomputed (and possibly recomputed differently) on every read.
|
|
405
|
+
*
|
|
406
|
+
* EVERY finding is passed in, not just the active ones. Resolving over the active subset makes the
|
|
407
|
+
* result depend on the order tasks happen to finish: a finding that beat a weak rival in wave 1 can
|
|
408
|
+
* itself lose in wave 2, and the wave-1 loser is then left pointing at a superseded finding — a
|
|
409
|
+
* broken chain nothing heals. Re-resolving the whole set each round is order-independent and gives
|
|
410
|
+
* the same answer as one pass over the final set.
|
|
411
|
+
*/
|
|
412
|
+
private resolveFindingConflicts;
|
|
367
413
|
/**
|
|
368
414
|
* A bounded, fenced brief of what the agents have already established (Phase 3.5).
|
|
369
415
|
*
|
|
@@ -409,6 +455,27 @@ export declare class Runtime {
|
|
|
409
455
|
* hand one step's completed inner work to a different step with the same id and a different input.
|
|
410
456
|
*/
|
|
411
457
|
private agentResumeLookup;
|
|
458
|
+
/**
|
|
459
|
+
* Every agent task this Runtime can see, newest execution first (Phase 3.6). Live ones (running in
|
|
460
|
+
* this process) and persisted ones are the same list: a task's record IS its status, so there is no
|
|
461
|
+
* second source to disagree with.
|
|
462
|
+
*/
|
|
463
|
+
agentTasks(executionId?: string): AgentTaskView[];
|
|
464
|
+
/**
|
|
465
|
+
* Stop one agent task. Four cases, and NONE of them is a silent no-op — a `stop` that appears to do
|
|
466
|
+
* nothing is indistinguishable from a bug:
|
|
467
|
+
*
|
|
468
|
+
* - running in this process: abort it, then let the worker record `cancelled` as it unwinds;
|
|
469
|
+
* - persisted and not finished (another process, or a dead one): write `cancelled` with a
|
|
470
|
+
* `parent-cancel` interruption, so the record stops claiming it is queued or running;
|
|
471
|
+
* - already finished: report that, and change nothing — a terminal state is sticky;
|
|
472
|
+
* - unknown id: say so.
|
|
473
|
+
*/
|
|
474
|
+
stopAgentTask(agentTaskId: string): {
|
|
475
|
+
ok: boolean;
|
|
476
|
+
state?: AgentTaskState;
|
|
477
|
+
reason: string;
|
|
478
|
+
};
|
|
412
479
|
/** Abort a run that is in flight, recording WHY so a task can tell a pause from a cancellation. */
|
|
413
480
|
private abortLiveRun;
|
|
414
481
|
/** Mark an execution paused (it can be resumed later). */
|