@xingular/harness 1.2.0 → 1.3.1-unstable.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 +35 -0
- package/README.md +10 -5
- package/dist/cli.js +5560 -5056
- package/dist/sdk/agents/builtin.js +3 -3
- package/dist/sdk/agents/planResearch.d.ts +23 -1
- package/dist/sdk/agents/planResearch.js +71 -8
- package/dist/sdk/agents/profiles.d.ts +4 -1
- package/dist/sdk/agents/profiles.js +17 -6
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/commands/registry.d.ts +11 -3
- package/dist/sdk/commands/registry.js +3 -2
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +17 -1
- package/dist/sdk/core/workspaceBashTool.js +16 -2
- package/dist/sdk/core/workspaceSandbox.d.ts +10 -0
- package/dist/sdk/core/workspaceSandbox.js +52 -12
- package/dist/sdk/core/workspaceWriteOperations.d.ts +11 -0
- package/dist/sdk/core/workspaceWriteOperations.js +26 -8
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/plugins/builtin.js +3 -3
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +2 -2
- package/dist/sdk/prompt/compile.d.ts +2 -2
- package/dist/sdk/prompt/compile.js +14 -16
- package/dist/sdk/server/methods.js +4 -2
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +3 -3
- package/dist/sdk/sessions/compactionCheckpoint.js +12 -12
- package/dist/sdk/sessions/continuation.d.ts +4 -2
- package/dist/sdk/sessions/continuation.js +7 -6
- package/dist/sdk/sessions/contracts.d.ts +22 -4
- package/dist/sdk/sessions/contracts.js +12 -7
- package/dist/sdk/sessions/planMode.js +2 -2
- package/dist/sdk/sessions/runStore.js +3 -1
- package/dist/sdk/sessions/runner.js +2 -2
- package/dist/sdk/sessions/sessions.js +29 -11
- package/dist/sdk/sessions/subagentService.d.ts +15 -0
- package/dist/sdk/sessions/subagentService.js +194 -54
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +8 -5
- package/dist/sdk/sessions/workSlice.js +77 -45
- package/dist/sdk/terminal/controller.d.ts +20 -0
- package/dist/sdk/terminal/controller.js +43 -18
- package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
- package/dist/sdk/terminal/opentui/ansi.js +192 -0
- package/dist/sdk/terminal/opentui/model.d.ts +163 -0
- package/dist/sdk/terminal/opentui/model.js +482 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
- package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
- package/dist/sdk/terminal/opentui/theme.js +1 -0
- package/dist/sdk/terminal/piExtension.js +28 -14
- package/dist/sdk/terminal/subagentMonitor.d.ts +17 -4
- package/dist/sdk/terminal/subagentMonitor.js +29 -8
- package/dist/sdk/terminal/terminals.d.ts +7 -0
- package/dist/sdk/terminal/terminals.js +86 -14
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
- package/dist/sdk/terminal/tui/chrome.js +13 -0
- package/dist/sdk/terminal/tui/commandPages.js +14 -4
- package/dist/sdk/terminal/tui/commands.d.ts +4 -0
- package/dist/sdk/terminal/tui/commands.js +8 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +13 -6
- package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +8 -1
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +197 -25
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +8 -5
- package/dist/sdk/tools/sessionName.d.ts +2 -0
- package/dist/sdk/tools/sessionName.js +5 -3
- package/dist/sdk/tools/spawnSubagent.js +9 -7
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/terminal-opentui.js +1416 -348
- package/dist/terminal-pi.js +315 -126
- package/docs/architecture/00-overview.md +1 -1
- package/docs/architecture/01-extension-points.md +1 -1
- package/docs/architecture/02-sessions-and-runs.md +65 -34
- package/docs/architecture/04-prompt.md +8 -6
- package/docs/architecture/06-plugins-and-capabilities.md +10 -6
- package/docs/architecture/07-tools-and-gate.md +31 -5
- package/docs/architecture/09-accounts-and-connectors.md +8 -2
- package/docs/architecture/10-server-protocol.md +16 -9
- package/docs/architecture/11-terminal.md +51 -26
- package/docs/architecture/14-surfaces-and-parity.md +4 -1
- package/docs/architecture/README.md +18 -17
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +32 -21
- package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
- package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
- package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
- package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
- package/docs/architecture/proposals/README.md +10 -6
- package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
- package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
- package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
- package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
- package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
- package/docs/doctor.md +14 -1
- package/docs/parity.md +9 -9
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/README.md +2 -2
- package/docs/terminal-tui.md +85 -46
- package/package.json +1 -1
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -55
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { renderCompactionCheckpoint } from "../prompt/compile.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TODO_WRITE } from "../tools/todo.js";
|
|
3
|
+
import { todoItemSchema, MAX_TODO_ITEMS } from "./contracts.js";
|
|
4
4
|
export const COMPACTION_CHECKPOINT_EXTENSION = 'compaction-checkpoint';
|
|
5
|
-
function
|
|
6
|
-
if (!Array.isArray(value) || value.length >
|
|
5
|
+
function validatedTodo(value) {
|
|
6
|
+
if (!Array.isArray(value) || value.length > MAX_TODO_ITEMS)
|
|
7
7
|
return null;
|
|
8
8
|
const items = [];
|
|
9
9
|
for (const valueItem of value) {
|
|
10
10
|
const item = valueItem;
|
|
11
|
-
const parsed =
|
|
11
|
+
const parsed = todoItemSchema.safeParse({
|
|
12
12
|
text: typeof item?.text === 'string' ? item.text.trim() : item?.text,
|
|
13
13
|
status: item?.status
|
|
14
14
|
});
|
|
@@ -22,12 +22,12 @@ function validatedChecklist(value) {
|
|
|
22
22
|
export function compactionCheckpoint(options = {}) {
|
|
23
23
|
return (pi) => {
|
|
24
24
|
let goal = '';
|
|
25
|
-
let
|
|
25
|
+
let todo = validatedTodo(options.initialTodo ?? []) ?? [];
|
|
26
26
|
let lastCompactionKey = null;
|
|
27
27
|
let compacted = false;
|
|
28
28
|
const reset = () => {
|
|
29
29
|
goal = '';
|
|
30
|
-
|
|
30
|
+
todo = validatedTodo(options.initialTodo ?? []) ?? [];
|
|
31
31
|
lastCompactionKey = null;
|
|
32
32
|
compacted = false;
|
|
33
33
|
};
|
|
@@ -35,16 +35,16 @@ export function compactionCheckpoint(options = {}) {
|
|
|
35
35
|
if (event.messageType !== 'user')
|
|
36
36
|
return;
|
|
37
37
|
goal = event.prompt;
|
|
38
|
-
|
|
38
|
+
todo = validatedTodo(options.initialTodo ?? []) ?? [];
|
|
39
39
|
lastCompactionKey = null;
|
|
40
40
|
compacted = false;
|
|
41
41
|
});
|
|
42
42
|
pi.on('tool_result', (event) => {
|
|
43
|
-
if (event.toolName !==
|
|
43
|
+
if (event.toolName !== TODO_WRITE || event.isError)
|
|
44
44
|
return;
|
|
45
|
-
const items =
|
|
45
|
+
const items = validatedTodo(event.input.items);
|
|
46
46
|
if (items)
|
|
47
|
-
|
|
47
|
+
todo = items;
|
|
48
48
|
});
|
|
49
49
|
pi.on('context', (event) => {
|
|
50
50
|
const summary = event.messages.findLast((message) => message.role === 'compactionSummary');
|
|
@@ -60,7 +60,7 @@ export function compactionCheckpoint(options = {}) {
|
|
|
60
60
|
}
|
|
61
61
|
if (!compacted)
|
|
62
62
|
return;
|
|
63
|
-
const content = renderCompactionCheckpoint({ goal,
|
|
63
|
+
const content = renderCompactionCheckpoint({ goal, todo, planInstructions });
|
|
64
64
|
if (!content)
|
|
65
65
|
return;
|
|
66
66
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CapabilitySet } from "../capabilities/types.js";
|
|
2
2
|
import type { HostSection } from "../prompt/compile.js";
|
|
3
3
|
import type { Checkpoint } from "./contracts.js";
|
|
4
|
-
import { type
|
|
4
|
+
import { type TodoItem } from "./contracts.js";
|
|
5
5
|
import { type PendingDecision } from "./runStore.js";
|
|
6
6
|
export declare const CONTINUATION_SECTION_ID = "continuation";
|
|
7
7
|
/** Right after the plan section, before the variant's own sections. */
|
|
@@ -28,7 +28,9 @@ export interface Continuation {
|
|
|
28
28
|
capabilities: CapabilitySet | null;
|
|
29
29
|
stoppedAt: string | null;
|
|
30
30
|
terminalReason: string | null;
|
|
31
|
-
|
|
31
|
+
todo: TodoItem[];
|
|
32
|
+
/** @deprecated Use `todo`; kept for one release so hosts can migrate. */
|
|
33
|
+
checklist: TodoItem[];
|
|
32
34
|
/** The last work-slice handoff, when the run wrote one (PROP-0041). */
|
|
33
35
|
checkpoint: Checkpoint | null;
|
|
34
36
|
pending: PendingDecision[];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// own (INV-RUN-4); it says whether a run can be continued and, when the application starts a new
|
|
3
3
|
// run with `continueFrom`, tells the model where the earlier one stopped.
|
|
4
4
|
import { loadRun as loadCapabilities } from "../capabilities/runSnapshot.js";
|
|
5
|
-
import {
|
|
5
|
+
import { todoOf, describeTodo } from "../tools/todo.js";
|
|
6
6
|
import { checkpointOf, describeCheckpoint } from "../tools/checkpoint.js";
|
|
7
7
|
import { isActiveStatus } from "./contracts.js";
|
|
8
8
|
import { findHistory } from "./history.js";
|
|
@@ -18,7 +18,7 @@ const CONTINUATION_BUDGET = 2000;
|
|
|
18
18
|
export function continuationOf(root, runId, sessionDir) {
|
|
19
19
|
const record = findRun(root, runId);
|
|
20
20
|
if (!record) {
|
|
21
|
-
return { runId, sessionId: '', status: 'missing', resumable: false, reason: 'not_found', resume: null, accountId: null, variant: null, capabilities: null, stoppedAt: null, terminalReason: null, checklist: [], checkpoint: null, pending: [], lastTool: null, unfinishedSubagents: [] };
|
|
21
|
+
return { runId, sessionId: '', status: 'missing', resumable: false, reason: 'not_found', resume: null, accountId: null, variant: null, capabilities: null, stoppedAt: null, terminalReason: null, todo: [], checklist: [], checkpoint: null, pending: [], lastTool: null, unfinishedSubagents: [] };
|
|
22
22
|
}
|
|
23
23
|
const events = readEvents(root, runId);
|
|
24
24
|
const started = events.filter((event) => event.type === 'tool.started').at(-1);
|
|
@@ -46,7 +46,8 @@ export function continuationOf(root, runId, sessionDir) {
|
|
|
46
46
|
capabilities,
|
|
47
47
|
stoppedAt: record.endedAt,
|
|
48
48
|
terminalReason: record.terminalReason,
|
|
49
|
-
checklist:
|
|
49
|
+
checklist: todoOf(events),
|
|
50
|
+
todo: todoOf(events),
|
|
50
51
|
checkpoint: checkpointOf(events),
|
|
51
52
|
pending: pendingDecisions(events),
|
|
52
53
|
lastTool,
|
|
@@ -73,12 +74,12 @@ export function continuationBody(continuation) {
|
|
|
73
74
|
lines.push(continuation.lastTool.finished ? `Its last tool call, ${continuation.lastTool.name}, finished.` : `Its last tool call, ${continuation.lastTool.name}, did not finish; its effect is unknown.`);
|
|
74
75
|
if (continuation.checkpoint)
|
|
75
76
|
lines.push('', 'The handoff it wrote when it stopped:', describeCheckpoint(continuation.checkpoint));
|
|
76
|
-
if (continuation.
|
|
77
|
-
lines.push('', 'Its
|
|
77
|
+
if (continuation.todo.length)
|
|
78
|
+
lines.push('', 'Its todo list when it stopped:', describeTodo(continuation.todo));
|
|
78
79
|
if (continuation.pending.length)
|
|
79
80
|
lines.push('', 'Unanswered when it stopped (ask again if still needed; never assume an answer):', ...continuation.pending.map(describePending));
|
|
80
81
|
if (continuation.unfinishedSubagents.length)
|
|
81
|
-
lines.push('', `Subagents that did not finish: ${continuation.unfinishedSubagents.join(', ')}.
|
|
82
|
+
lines.push('', `Subagents that did not finish: ${continuation.unfinishedSubagents.join(', ')}. Their conversations are saved: continue one with spawn_subagent { "continue": "<run ID>" } if its work is still needed, instead of starting it again from scratch.`);
|
|
82
83
|
return lines.join('\n');
|
|
83
84
|
}
|
|
84
85
|
/** The dynamic section for a continuation; on a later run, the empty slot withdraws it. */
|
|
@@ -30,6 +30,7 @@ export declare const runEventTypeSchema: z.ZodEnum<{
|
|
|
30
30
|
"extension.notice": "extension.notice";
|
|
31
31
|
"reaction.added": "reaction.added";
|
|
32
32
|
"agent.message": "agent.message";
|
|
33
|
+
"todo.updated": "todo.updated";
|
|
33
34
|
"checklist.updated": "checklist.updated";
|
|
34
35
|
checkpoint: "checkpoint";
|
|
35
36
|
heartbeat: "heartbeat";
|
|
@@ -67,8 +68,8 @@ export declare const questionOptionSchema: z.ZodObject<{
|
|
|
67
68
|
sketch: z.ZodOptional<z.ZodString>;
|
|
68
69
|
}, z.core.$strip>;
|
|
69
70
|
export type QuestionOption = z.infer<typeof questionOptionSchema>;
|
|
70
|
-
/** One line of the run's
|
|
71
|
-
export declare const
|
|
71
|
+
/** One line of the run's todo list. The list has no ids: every update replaces all of it. */
|
|
72
|
+
export declare const todoItemSchema: z.ZodObject<{
|
|
72
73
|
text: z.ZodString;
|
|
73
74
|
status: z.ZodEnum<{
|
|
74
75
|
completed: "completed";
|
|
@@ -76,8 +77,8 @@ export declare const checklistItemSchema: z.ZodObject<{
|
|
|
76
77
|
in_progress: "in_progress";
|
|
77
78
|
}>;
|
|
78
79
|
}, z.core.$strict>;
|
|
79
|
-
export type
|
|
80
|
-
export declare const
|
|
80
|
+
export type TodoItem = z.infer<typeof todoItemSchema>;
|
|
81
|
+
export declare const MAX_TODO_ITEMS = 50;
|
|
81
82
|
export declare const MAX_CHECKPOINT_SUMMARY = 1200;
|
|
82
83
|
export declare const MAX_CHECKPOINT_DONE = 20;
|
|
83
84
|
export declare const MAX_CHECKPOINT_EVIDENCE = 5;
|
|
@@ -432,6 +433,16 @@ export declare const runEventPayloadSchemas: {
|
|
|
432
433
|
agentName: z.ZodString;
|
|
433
434
|
text: z.ZodString;
|
|
434
435
|
}, z.core.$strip>;
|
|
436
|
+
'todo.updated': z.ZodObject<{
|
|
437
|
+
items: z.ZodArray<z.ZodObject<{
|
|
438
|
+
text: z.ZodString;
|
|
439
|
+
status: z.ZodEnum<{
|
|
440
|
+
completed: "completed";
|
|
441
|
+
pending: "pending";
|
|
442
|
+
in_progress: "in_progress";
|
|
443
|
+
}>;
|
|
444
|
+
}, z.core.$strict>>;
|
|
445
|
+
}, z.core.$strict>;
|
|
435
446
|
'checklist.updated': z.ZodObject<{
|
|
436
447
|
items: z.ZodArray<z.ZodObject<{
|
|
437
448
|
text: z.ZodString;
|
|
@@ -624,6 +635,7 @@ export declare const runEventSchema: z.ZodObject<{
|
|
|
624
635
|
"extension.notice": "extension.notice";
|
|
625
636
|
"reaction.added": "reaction.added";
|
|
626
637
|
"agent.message": "agent.message";
|
|
638
|
+
"todo.updated": "todo.updated";
|
|
627
639
|
"checklist.updated": "checklist.updated";
|
|
628
640
|
checkpoint: "checkpoint";
|
|
629
641
|
heartbeat: "heartbeat";
|
|
@@ -681,6 +693,10 @@ export interface RunRecord {
|
|
|
681
693
|
profile?: string | null;
|
|
682
694
|
/** The short name a parent gave a subagent, shown in the roster (PROP-0030). */
|
|
683
695
|
title?: string | null;
|
|
696
|
+
/** The model the run used, as `provider/id`: the launch selection, then the one the session opened. */
|
|
697
|
+
model?: string | null;
|
|
698
|
+
/** The reasoning effort the run used. */
|
|
699
|
+
effort?: string | null;
|
|
684
700
|
}
|
|
685
701
|
export declare const runRecordSchema: z.ZodObject<{
|
|
686
702
|
resumedFromRunId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
@@ -711,6 +727,8 @@ export declare const runRecordSchema: z.ZodObject<{
|
|
|
711
727
|
variantVersion: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
712
728
|
profile: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
713
729
|
title: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
730
|
+
model: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
731
|
+
effort: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
714
732
|
}, z.core.$strip>;
|
|
715
733
|
/** Records written before PROP-0009 name the variant `harnessScope` and `harnessVersion`. */
|
|
716
734
|
export declare function upgradeRunRecord(raw: unknown): unknown;
|
|
@@ -21,6 +21,8 @@ export const runEventTypeSchema = z.enum([
|
|
|
21
21
|
'extension.notice',
|
|
22
22
|
'reaction.added',
|
|
23
23
|
'agent.message',
|
|
24
|
+
'todo.updated',
|
|
25
|
+
// Written before the rename; accepted so stored run logs keep their lists. Never written now.
|
|
24
26
|
'checklist.updated',
|
|
25
27
|
'checkpoint',
|
|
26
28
|
'heartbeat',
|
|
@@ -174,11 +176,11 @@ const extensionNoticePayload = z.object({
|
|
|
174
176
|
text: z.string(),
|
|
175
177
|
extension: z.string().optional()
|
|
176
178
|
});
|
|
177
|
-
/** One line of the run's
|
|
178
|
-
export const
|
|
179
|
-
export const
|
|
180
|
-
/** The whole
|
|
181
|
-
const
|
|
179
|
+
/** One line of the run's todo list. The list has no ids: every update replaces all of it. */
|
|
180
|
+
export const todoItemSchema = z.object({ text: z.string().min(1).max(500), status: z.enum(['pending', 'in_progress', 'completed']) }).strict();
|
|
181
|
+
export const MAX_TODO_ITEMS = 50;
|
|
182
|
+
/** The whole todo list as the model last wrote it; the latest event replaces every earlier one. */
|
|
183
|
+
const todoPayload = z.object({ items: z.array(todoItemSchema).max(MAX_TODO_ITEMS) }).strict();
|
|
182
184
|
export const MAX_CHECKPOINT_SUMMARY = 1_200;
|
|
183
185
|
export const MAX_CHECKPOINT_DONE = 20;
|
|
184
186
|
export const MAX_CHECKPOINT_EVIDENCE = 5;
|
|
@@ -319,7 +321,8 @@ export const runEventPayloadSchemas = {
|
|
|
319
321
|
'extension.notice': extensionNoticePayload,
|
|
320
322
|
'reaction.added': reactionAddedPayload,
|
|
321
323
|
'agent.message': agentMessagePayload,
|
|
322
|
-
'
|
|
324
|
+
'todo.updated': todoPayload,
|
|
325
|
+
'checklist.updated': todoPayload,
|
|
323
326
|
checkpoint: checkpointPayload,
|
|
324
327
|
heartbeat: heartbeatPayload,
|
|
325
328
|
'artifact.added': artifactPayload,
|
|
@@ -378,7 +381,9 @@ export const runRecordSchema = z.object({
|
|
|
378
381
|
variantScope: text.optional(),
|
|
379
382
|
variantVersion: text.optional(),
|
|
380
383
|
profile: text.optional(),
|
|
381
|
-
title: text.optional()
|
|
384
|
+
title: text.optional(),
|
|
385
|
+
model: text.optional(),
|
|
386
|
+
effort: text.optional()
|
|
382
387
|
});
|
|
383
388
|
/** Records written before PROP-0009 name the variant `harnessScope` and `harnessVersion`. */
|
|
384
389
|
export function upgradeRunRecord(raw) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// gate refuses everything else, and the instruction arrives as a context update.
|
|
4
4
|
import { deliveredSnapshot } from "../prompt/compile.js";
|
|
5
5
|
import { ASK_USER } from "../tools/askUser.js";
|
|
6
|
-
import {
|
|
6
|
+
import { TODO_WRITE } from "../tools/todo.js";
|
|
7
7
|
import { SESSION_NAME } from "../tools/sessionName.js";
|
|
8
8
|
import { GET_CAPABILITIES } from "../tools/getCapabilities.js";
|
|
9
9
|
import { PLAN_RESEARCH_TOOLS } from "../agents/planResearch.js";
|
|
@@ -18,7 +18,7 @@ export function normalModeTools(tools) {
|
|
|
18
18
|
return tools.filter((name) => !QUESTION_TOOL_NAMES.has(name));
|
|
19
19
|
}
|
|
20
20
|
export const PLAN_READ_ONLY_TOOLS = new Set([
|
|
21
|
-
'read', 'grep', 'find', 'ls', SESSION_NAME,
|
|
21
|
+
'read', 'grep', 'find', 'ls', SESSION_NAME, TODO_WRITE, ASK_USER, 'ask_user_question', GET_CAPABILITIES,
|
|
22
22
|
'history_search', 'history_read', 'trajectory_search', 'trajectory_read',
|
|
23
23
|
'wiki_entrypoint', 'wiki_search', 'wiki_read', 'wiki_list', 'memory_facts', 'skill_load', 'mcp_list_tools', WAIT_SUBAGENTS
|
|
24
24
|
]);
|
|
@@ -43,7 +43,9 @@ function ordered(record) {
|
|
|
43
43
|
...(record.variantScope ? { variantScope: record.variantScope } : {}),
|
|
44
44
|
...(record.variantVersion ? { variantVersion: record.variantVersion } : {}),
|
|
45
45
|
...(record.profile ? { profile: record.profile } : {}),
|
|
46
|
-
...(record.title ? { title: record.title } : {})
|
|
46
|
+
...(record.title ? { title: record.title } : {}),
|
|
47
|
+
...(record.model ? { model: record.model } : {}),
|
|
48
|
+
...(record.effort ? { effort: record.effort } : {})
|
|
47
49
|
};
|
|
48
50
|
}
|
|
49
51
|
function write(root, record) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { classifyMessage } from "../accounts/accounts.js";
|
|
2
2
|
import { EFFORTS } from "../core/effort.js";
|
|
3
3
|
import { HarnessError } from "../core/errors.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createWorkspaceShellTool } from "../core/workspaceBashTool.js";
|
|
5
5
|
import { DEFAULT_COMMAND_TIMEOUT_SECONDS, withCommandBudget } from "../core/commandBudget.js";
|
|
6
6
|
import { createWorkspaceBashOperations } from "../core/workspaceSandbox.js";
|
|
7
7
|
import { withWorkspaceWriteAuthorization, workspaceEditOperations, workspaceWriteOperations } from "../core/workspaceWriteOperations.js";
|
|
@@ -632,7 +632,7 @@ export const piSessionFactory = async ({ params, allow, gate, tools, runtime: lo
|
|
|
632
632
|
});
|
|
633
633
|
const gatedExtension = (api) => {
|
|
634
634
|
const writeAuthorizations = new Map();
|
|
635
|
-
const bash =
|
|
635
|
+
const bash = createWorkspaceShellTool(pi, params.cwd, workspaceBash);
|
|
636
636
|
const write = withWorkspaceWriteAuthorization(pi.createWriteTool(params.cwd, { operations: workspaceWriteOperations }), writeAuthorizations);
|
|
637
637
|
const edit = withWorkspaceWriteAuthorization(pi.createEditTool(params.cwd, { operations: workspaceEditOperations }), writeAuthorizations);
|
|
638
638
|
api.registerTool({ ...bash, defaultActive: false });
|
|
@@ -18,7 +18,7 @@ import { FIRST_PARTY_PLUGINS, firstPartyExtensions } from "../plugins/firstParty
|
|
|
18
18
|
import { imagePruning } from "../world/images.js";
|
|
19
19
|
import { materialise } from "../variant/materialise.js";
|
|
20
20
|
import { ASK_USER } from "../tools/askUser.js";
|
|
21
|
-
import {
|
|
21
|
+
import { TODO_WRITE } from "../tools/todo.js";
|
|
22
22
|
import { CHECKPOINT_WRITE, checkpointOf } from "../tools/checkpoint.js";
|
|
23
23
|
import { SESSION_NAME, sessionNameTool } from "../tools/sessionName.js";
|
|
24
24
|
import { DEFAULT_TOOL_NAMES } from "../tools/definitions.js";
|
|
@@ -400,7 +400,7 @@ export class Sessions {
|
|
|
400
400
|
const canAskUser = pinnedAskUser || (interactivePlan && harnessToolsEnabled);
|
|
401
401
|
const requestedTools = [...new Set([
|
|
402
402
|
...input.tools.allow.filter((name) => name !== SPAWN_SUBAGENT && name !== WAIT_SUBAGENTS && (name !== ASK_USER || canAskUser)),
|
|
403
|
-
...(harnessToolsEnabled ? [...(canAskUser ? [ASK_USER] : []),
|
|
403
|
+
...(harnessToolsEnabled ? [...(canAskUser ? [ASK_USER] : []), TODO_WRITE, CHECKPOINT_WRITE, SESSION_NAME, GET_CAPABILITIES, ...DEFAULT_TOOL_NAMES] : []),
|
|
404
404
|
...(broker?.toolNames ?? []),
|
|
405
405
|
...(canSpawn ? [SPAWN_SUBAGENT, WAIT_SUBAGENTS] : [])
|
|
406
406
|
])];
|
|
@@ -452,7 +452,9 @@ export class Sessions {
|
|
|
452
452
|
variantScope: variant?.scope ?? null,
|
|
453
453
|
variantVersion: variant?.fingerprint ?? null,
|
|
454
454
|
...(input.run.profile ? { profile: input.run.profile } : {}),
|
|
455
|
-
...(input.run.title ? { title: input.run.title } : {})
|
|
455
|
+
...(input.run.title ? { title: input.run.title } : {}),
|
|
456
|
+
...(input.model ? { model: input.model } : {}),
|
|
457
|
+
...(input.effort ? { effort: input.effort } : {})
|
|
456
458
|
});
|
|
457
459
|
// What the session is, kept with the run so later consolidation knows which memory it had.
|
|
458
460
|
try {
|
|
@@ -476,7 +478,14 @@ export class Sessions {
|
|
|
476
478
|
const delivered = historyFile ? deliveredSnapshot(historyFile) : null;
|
|
477
479
|
const resumed = continuationSection(continuation, delivered?.some((entry) => entry.id === CONTINUATION_SECTION_ID) ?? false);
|
|
478
480
|
// The profiles replace the variant's own subagent list, which they include.
|
|
479
|
-
const
|
|
481
|
+
const researchContext = input.plan === true ? {
|
|
482
|
+
frozenTools: capabilities.tools,
|
|
483
|
+
contributions: capabilities.contributions,
|
|
484
|
+
descriptors: BUILTIN_PLUGIN_REGISTRY.descriptors()
|
|
485
|
+
} : undefined;
|
|
486
|
+
const profiles = capabilities.tools.includes(SPAWN_SUBAGENT)
|
|
487
|
+
? profileSection(root, input.cwd, variant?.dir ?? null, input.plan === true, researchContext)
|
|
488
|
+
: null;
|
|
480
489
|
if (profiles && variant)
|
|
481
490
|
variant = { ...variant, sections: variant.sections.filter((section) => section.id !== profiles.id) };
|
|
482
491
|
const own = [plan, resumed, profiles].filter((section) => section !== null);
|
|
@@ -493,8 +502,10 @@ export class Sessions {
|
|
|
493
502
|
fail(error);
|
|
494
503
|
throw error;
|
|
495
504
|
}
|
|
496
|
-
//
|
|
497
|
-
const
|
|
505
|
+
// Plan-research children are bounded too, but their read-only capability set omits checkpoint_write.
|
|
506
|
+
const checkpointAvailable = capabilities.tools.includes(CHECKPOINT_WRITE);
|
|
507
|
+
const planResearchChild = input.plan === true && input.run.relation === 'subagent';
|
|
508
|
+
const sliceEnabled = slicePolicy.enabled && (checkpointAvailable || planResearchChild);
|
|
498
509
|
const sliceState = createSliceState(slicePolicy, sliceOf(root, runId));
|
|
499
510
|
const run = this.options.runs.start(input.run.sessionId, runId);
|
|
500
511
|
if (run.finished)
|
|
@@ -594,8 +605,8 @@ export class Sessions {
|
|
|
594
605
|
runLineageJoin(root, runId),
|
|
595
606
|
this.options.subagents.extension(runId),
|
|
596
607
|
{ name: 'image-pruning', factory: imagePruning() },
|
|
597
|
-
{ name: COMPACTION_CHECKPOINT_EXTENSION, factory: compactionCheckpoint({
|
|
598
|
-
...(sliceEnabled ? [{ name: WORK_SLICE_EXTENSION, factory: workSliceGuard({ policy: slicePolicy, state: sliceState }) }] : [])
|
|
608
|
+
{ name: COMPACTION_CHECKPOINT_EXTENSION, factory: compactionCheckpoint({ initialTodo: continuation?.todo, planInstructions: checkpointPlanInstructions }) },
|
|
609
|
+
...(sliceEnabled ? [{ name: WORK_SLICE_EXTENSION, factory: workSliceGuard({ policy: slicePolicy, state: sliceState, checkpointAvailable }) }] : [])
|
|
599
610
|
],
|
|
600
611
|
...(plugins ? { plugins: { loading: () => plugins.loading({ cwd: input.cwd, agentDir: context.configDir, install: true, caller: { agentId: caller.agentId ?? null, projectId: caller.projectId ?? null }, contributions: capabilities.contributions }), loaded: (extensions) => plugins.loaded(extensions) } } : {}),
|
|
601
612
|
system,
|
|
@@ -625,10 +636,17 @@ export class Sessions {
|
|
|
625
636
|
throw new HarnessError('native_resume_unavailable', 'The saved conversation could not be restored.');
|
|
626
637
|
}
|
|
627
638
|
const opened = pi;
|
|
628
|
-
|
|
639
|
+
const openedModel = pi.model?.id && pi.model.provider ? `${pi.model.provider}/${pi.model.id}` : null;
|
|
640
|
+
updateRun(root, runId, (record) => {
|
|
641
|
+
record.nativeSessionId = opened.sessionId;
|
|
642
|
+
if (openedModel)
|
|
643
|
+
record.model = openedModel;
|
|
644
|
+
if (opened.thinkingLevel)
|
|
645
|
+
record.effort = opened.thinkingLevel;
|
|
646
|
+
});
|
|
629
647
|
this.options.subagents.register(input, account.id, capabilities, Boolean(pi.sessionManager));
|
|
630
|
-
if (
|
|
631
|
-
this.options.subagents.resolvedModel(runId,
|
|
648
|
+
if (openedModel)
|
|
649
|
+
this.options.subagents.resolvedModel(runId, openedModel, pi.thinkingLevel);
|
|
632
650
|
params.settle = () => this.options.subagents.verify(runId, opened.sessionManager ? subagentHistory(opened.sessionManager.getBranch()) : undefined);
|
|
633
651
|
void runTurn(run, pi, params).then(() => (sliceEnabled && !input.command ? this.continueSlice({ root, runId, source: input, policy: slicePolicy }) : undefined));
|
|
634
652
|
return { runId, nativeSessionId: pi.sessionId };
|
|
@@ -14,6 +14,7 @@ type Started = {
|
|
|
14
14
|
export type SpawnedSubagent = Started & {
|
|
15
15
|
agent?: string;
|
|
16
16
|
unavailableTools?: string[];
|
|
17
|
+
continued?: string;
|
|
17
18
|
};
|
|
18
19
|
export interface SubagentRuntimeSettings {
|
|
19
20
|
model: string | null;
|
|
@@ -42,9 +43,23 @@ export declare class Subagents {
|
|
|
42
43
|
private rememberRuntimeSettings;
|
|
43
44
|
resolvedModel(runId: string, model: string, effort?: Effort): void;
|
|
44
45
|
private parent;
|
|
46
|
+
private planSpawnCheck;
|
|
45
47
|
/** The plan-mode per-call gate and spawn implementation share this eligibility check. */
|
|
46
48
|
planSpawnRefusal(parentRunId: string, args: unknown): string | null;
|
|
47
49
|
spawn(request: SubagentInput): Promise<SpawnedSubagent>;
|
|
50
|
+
/** Records ownership, starts the child, and writes a failed record when it never opened. */
|
|
51
|
+
private launchChild;
|
|
52
|
+
/** The children this parent may read or continue: its own, and those recovered from its history. */
|
|
53
|
+
private owned;
|
|
54
|
+
/** The newest run in a continued child's chain, among the runs this parent owns. */
|
|
55
|
+
private latestLink;
|
|
56
|
+
/** The first run of a chain: its folder holds the child's history for every later link. */
|
|
57
|
+
private firstLink;
|
|
58
|
+
/**
|
|
59
|
+
* Continues a stopped child as a new child run with `continueFrom`: the same history, profile,
|
|
60
|
+
* account, variant version and capability set, which must still lie within the parent's.
|
|
61
|
+
*/
|
|
62
|
+
private continueChild;
|
|
48
63
|
private selected;
|
|
49
64
|
results(selection: SubagentSelection): SubagentResult[];
|
|
50
65
|
wait(selection: SubagentSelection, signal?: AbortSignal): Promise<SubagentResult[]>;
|