@xingular/harness 1.1.1 → 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 +48 -0
- package/README.md +36 -28
- package/dist/cli.js +10837 -6159
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.js +18 -4
- package/dist/sdk/agents/planResearch.d.ts +27 -0
- package/dist/sdk/agents/planResearch.js +82 -0
- package/dist/sdk/agents/profiles.d.ts +5 -1
- package/dist/sdk/agents/profiles.js +21 -5
- package/dist/sdk/annotations/pageScript.js +349 -48
- package/dist/sdk/annotations/part.js +34 -23
- package/dist/sdk/annotations/store.d.ts +7 -0
- package/dist/sdk/annotations/store.js +13 -5
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/cli.js +5 -4
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +258 -0
- package/dist/sdk/commands/registry.js +48 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +20 -0
- package/dist/sdk/core/workspaceBashTool.js +50 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +41 -0
- package/dist/sdk/core/workspaceSandbox.js +360 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +33 -0
- package/dist/sdk/core/workspaceWriteOperations.js +224 -0
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +7 -0
- package/dist/sdk/harness.js +42 -2
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +8 -3
- package/dist/sdk/index.js +4 -1
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.js +32 -15
- package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
- package/dist/sdk/plugins/builtinRegistry.js +30 -8
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +6 -5
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +14 -0
- package/dist/sdk/prompt/compile.js +65 -31
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/server/methods.js +22 -2
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +7 -2
- package/dist/sdk/sessions/continuation.js +11 -6
- package/dist/sdk/sessions/contracts.d.ts +190 -4
- package/dist/sdk/sessions/contracts.js +71 -8
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +14 -3
- package/dist/sdk/sessions/planMode.js +74 -17
- package/dist/sdk/sessions/registry.d.ts +1 -1
- package/dist/sdk/sessions/registry.js +2 -2
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +38 -1
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +161 -13
- package/dist/sdk/sessions/sessions.d.ts +23 -3
- package/dist/sdk/sessions/sessions.js +225 -22
- package/dist/sdk/sessions/subagentService.d.ts +24 -0
- package/dist/sdk/sessions/subagentService.js +225 -26
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +106 -0
- package/dist/sdk/sessions/workSlice.js +329 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browserControl.js +2 -1
- package/dist/sdk/terminal/controller.d.ts +31 -3
- package/dist/sdk/terminal/controller.js +81 -29
- 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.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +88 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +177 -63
- package/dist/sdk/terminal/standalone.d.ts +7 -0
- package/dist/sdk/terminal/standalone.js +72 -13
- package/dist/sdk/terminal/subagentMonitor.d.ts +28 -6
- package/dist/sdk/terminal/subagentMonitor.js +61 -9
- package/dist/sdk/terminal/terminals.d.ts +26 -2
- package/dist/sdk/terminal/terminals.js +325 -43
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
- 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.d.ts +3 -1
- package/dist/sdk/terminal/tui/commandPages.js +17 -4
- package/dist/sdk/terminal/tui/commands.d.ts +6 -0
- package/dist/sdk/terminal/tui/commands.js +213 -124
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/pageOverlay.js +21 -5
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
- 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/notesPage.d.ts +5 -5
- package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +8 -6
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +206 -28
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +104 -19
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
- package/dist/sdk/terminal/tui/runtime.js +23 -3
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/sessionName.d.ts +2 -0
- package/dist/sdk/tools/sessionName.js +5 -3
- package/dist/sdk/tools/spawnSubagent.js +11 -8
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/terminal-opentui.js +9204 -4812
- package/dist/terminal-pi.js +1848 -272
- 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 +169 -36
- package/docs/architecture/04-prompt.md +55 -15
- package/docs/architecture/06-plugins-and-capabilities.md +36 -15
- package/docs/architecture/07-tools-and-gate.md +131 -25
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +39 -3
- package/docs/architecture/10-server-protocol.md +71 -9
- package/docs/architecture/11-terminal.md +148 -60
- package/docs/architecture/12-storage.md +30 -2
- package/docs/architecture/13-world-tools.md +22 -1
- package/docs/architecture/14-surfaces-and-parity.md +58 -8
- package/docs/architecture/README.md +20 -17
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +258 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- 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 +24 -6
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- 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/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +83 -27
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/4.0.0.md +10 -9
- package/docs/releases/README.md +35 -30
- package/docs/study/00-index.md +3 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/terminal-tui.md +162 -82
- package/package.json +4 -3
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -54
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
// Starting a session turn: the account, the run record, the compiled prompt, the tools and
|
|
2
2
|
// their gate, then Pi. Everything before Pi answers is synchronous with the caller; the reply
|
|
3
3
|
// itself streams as run events.
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
+
import { isAbsolute, join } from 'node:path';
|
|
6
7
|
import { log } from "../core/bus.js";
|
|
7
8
|
import { HarnessError, invalid } from "../core/errors.js";
|
|
9
|
+
import { formatBashCommandForApproval } from "../core/workspaceBashTool.js";
|
|
8
10
|
import { capabilitySet as parseCapabilitySet, freezeRun } from "../capabilities/runSnapshot.js";
|
|
9
11
|
import { now, writeJson } from "../core/fs.js";
|
|
12
|
+
import { resolveWorkspaceRoot, verifyWorkspaceRoot } from "../core/workspace.js";
|
|
10
13
|
import { takeChars } from "../core/text.js";
|
|
11
14
|
import { BUILTIN_PLUGIN_REGISTRY } from "../plugins/builtin.js";
|
|
12
15
|
import { sessionLaunch } from "../prompt/compile.js";
|
|
@@ -15,18 +18,44 @@ import { FIRST_PARTY_PLUGINS, firstPartyExtensions } from "../plugins/firstParty
|
|
|
15
18
|
import { imagePruning } from "../world/images.js";
|
|
16
19
|
import { materialise } from "../variant/materialise.js";
|
|
17
20
|
import { ASK_USER } from "../tools/askUser.js";
|
|
18
|
-
import {
|
|
21
|
+
import { TODO_WRITE } from "../tools/todo.js";
|
|
22
|
+
import { CHECKPOINT_WRITE, checkpointOf } from "../tools/checkpoint.js";
|
|
19
23
|
import { SESSION_NAME, sessionNameTool } from "../tools/sessionName.js";
|
|
20
24
|
import { DEFAULT_TOOL_NAMES } from "../tools/definitions.js";
|
|
25
|
+
import { GET_CAPABILITIES, getCapabilitiesTool } from "../tools/getCapabilities.js";
|
|
26
|
+
import { isActiveStatus } from "./contracts.js";
|
|
21
27
|
import { SPAWN_SUBAGENT, WAIT_SUBAGENTS, subagentDepth, subagentHistory, subagentNesting } from "./subagents.js";
|
|
22
28
|
import { selectHistory } from "./history.js";
|
|
23
29
|
import { runLineageJoin } from "./lineageJoin.js";
|
|
30
|
+
import { compactionCheckpoint, COMPACTION_CHECKPOINT_EXTENSION } from "./compactionCheckpoint.js";
|
|
31
|
+
import { createSliceState, parseWorkSlice, sliceOf, workSliceGuard, WorkSliceError, WORK_SLICE_EXTENSION } from "./workSlice.js";
|
|
24
32
|
import { piSessionFactory, runTurn, summarize } from "./runner.js";
|
|
25
|
-
import { loadRun, runDir, saveRun, updateRun } from "./runStore.js";
|
|
26
|
-
import {
|
|
33
|
+
import { loadRun, readEvents, runDir, saveRun, updateRun } from "./runStore.js";
|
|
34
|
+
import { combineWorkspaceScope, inspectRunWorkspaceWrite } from "./workspaceBoundary.js";
|
|
35
|
+
import { PLAN_INSTRUCTIONS, PLAN_RESEARCH_SUBAGENT_INSTRUCTIONS, planRefusal, planSection } from "./planMode.js";
|
|
27
36
|
import { CONTINUATION_SECTION_ID, continuationOf, continuationSection } from "./continuation.js";
|
|
28
37
|
import { deliveredSnapshot } from "../prompt/compile.js";
|
|
29
38
|
import { profileSection } from "../agents/profiles.js";
|
|
39
|
+
/** A session command acts on a saved conversation and is never combined with a request of its own. */
|
|
40
|
+
function checkCommand(command, historyFile, input) {
|
|
41
|
+
if (!historyFile)
|
|
42
|
+
throw invalid('There is no saved conversation for this command yet.');
|
|
43
|
+
if (input.plan || input.continueFrom || input.automatic || input.initialBashCommand != null || input.images?.length) {
|
|
44
|
+
throw invalid('A session command runs on its own, without plan mode, a continuation, Bash or images.');
|
|
45
|
+
}
|
|
46
|
+
switch (command?.name) {
|
|
47
|
+
case 'compact': return;
|
|
48
|
+
case 'navigate':
|
|
49
|
+
if (typeof command.entryId !== 'string' || !command.entryId)
|
|
50
|
+
throw invalid('navigate needs the entry to go to.');
|
|
51
|
+
return;
|
|
52
|
+
case 'export':
|
|
53
|
+
if (typeof command.path !== 'string' || !isAbsolute(command.path) || !command.path.endsWith('.html'))
|
|
54
|
+
throw invalid('export needs an absolute .html path.');
|
|
55
|
+
return;
|
|
56
|
+
default: throw invalid('Unknown session command.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
30
59
|
const CONTINUE_TEXT = 'Continue from where you stopped.';
|
|
31
60
|
/** Fills a continuing run's input from the run it continues, refusing anything that would differ. */
|
|
32
61
|
function continueInput(root, input) {
|
|
@@ -95,7 +124,7 @@ export class Sessions {
|
|
|
95
124
|
diagnosticGate(run, caller) {
|
|
96
125
|
return this.gate(run, caller, new Set(), true);
|
|
97
126
|
}
|
|
98
|
-
gate(run, caller, gated, diagnostic = false) {
|
|
127
|
+
gate(run, caller, gated, diagnostic = false, automatic = false) {
|
|
99
128
|
const { policy } = this.options;
|
|
100
129
|
return {
|
|
101
130
|
ask: (names) => {
|
|
@@ -103,9 +132,19 @@ export class Sessions {
|
|
|
103
132
|
gated.add(name);
|
|
104
133
|
},
|
|
105
134
|
check: async (tool, args) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
let record;
|
|
136
|
+
let inspection;
|
|
137
|
+
try {
|
|
138
|
+
record = loadRun(this.env.root, run.runId);
|
|
139
|
+
inspection = inspectRunWorkspaceWrite(record, tool, args);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
return error instanceof Error ? error.message : 'The active project workspace could not be verified.';
|
|
143
|
+
}
|
|
144
|
+
const call = { run: record, caller, tool, args: inspection.input };
|
|
145
|
+
const hostScope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
146
|
+
const scope = combineWorkspaceScope(hostScope, inspection);
|
|
147
|
+
if (!scope.allowed && (scope.automatic || (automatic && inspection.outside) || !scope.requiresApproval))
|
|
109
148
|
return scope.reason ?? 'Outside the approved work scope.';
|
|
110
149
|
try {
|
|
111
150
|
await policy.authorize?.(call);
|
|
@@ -122,11 +161,11 @@ export class Sessions {
|
|
|
122
161
|
return scope.reason ? `Refused in a refinement run: ${scope.reason}` : 'Refused in a refinement run: this call needs a person to approve it.';
|
|
123
162
|
if (call.run.trigger === 'reflection')
|
|
124
163
|
return scope.reason ? `Refused in a reflection run: ${scope.reason}` : 'Refused in a reflection run: this call needs a person to approve it.';
|
|
125
|
-
|
|
164
|
+
const boundaryAction = inspection.outside ? `${inspection.reason} ${summarize(call.args, tool)}` : summarize(call.args);
|
|
126
165
|
const decision = await run.requestApproval({
|
|
127
166
|
target: tool,
|
|
128
|
-
action:
|
|
129
|
-
operation: { tool, args: (args && typeof args === 'object' ? args : {}) },
|
|
167
|
+
action: boundaryAction,
|
|
168
|
+
operation: { tool, args: (call.args && typeof call.args === 'object' ? call.args : {}) },
|
|
130
169
|
rememberable: scope.allowed && !scope.humanOnly,
|
|
131
170
|
standing: scope.humanOnly ? (scope.allowGlobalApproval ? 'switch' : 'none') : undefined
|
|
132
171
|
});
|
|
@@ -139,6 +178,69 @@ export class Sessions {
|
|
|
139
178
|
return error instanceof Error ? error.message : 'Tool was disabled while waiting.';
|
|
140
179
|
}
|
|
141
180
|
return null;
|
|
181
|
+
},
|
|
182
|
+
workspaceBoundaryBypass: async (tool, args) => {
|
|
183
|
+
if (diagnostic || automatic || tool.toLowerCase() !== 'bash')
|
|
184
|
+
return false;
|
|
185
|
+
const record = loadRun(this.env.root, run.runId);
|
|
186
|
+
if (record.trigger != null && record.trigger !== 'user')
|
|
187
|
+
return false;
|
|
188
|
+
if (!await this.options.fullPermission?.(record))
|
|
189
|
+
return false;
|
|
190
|
+
const call = { run: record, caller, tool, args };
|
|
191
|
+
const scope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
192
|
+
if (scope.automatic || (!scope.allowed && !scope.requiresApproval) || (scope.humanOnly && !scope.allowGlobalApproval))
|
|
193
|
+
return false;
|
|
194
|
+
try {
|
|
195
|
+
await policy.authorize?.(call);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
requestWorkspaceWriteScope: async (tool, args, reason) => {
|
|
203
|
+
if (diagnostic || automatic || tool.toLowerCase() !== 'bash')
|
|
204
|
+
return false;
|
|
205
|
+
const record = loadRun(this.env.root, run.runId);
|
|
206
|
+
if (!isActiveStatus(record.status) || (record.trigger != null && record.trigger !== 'user'))
|
|
207
|
+
return false;
|
|
208
|
+
const operationArgs = (args && typeof args === 'object' && !Array.isArray(args) ? args : {});
|
|
209
|
+
if (operationArgs.workspaceWriteScope !== 'outside' || typeof operationArgs.command !== 'string' || !operationArgs.command)
|
|
210
|
+
return false;
|
|
211
|
+
const call = { run: record, caller, tool, args: operationArgs };
|
|
212
|
+
const scope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
213
|
+
if (scope.automatic || (!scope.allowed && !scope.requiresApproval))
|
|
214
|
+
return false;
|
|
215
|
+
try {
|
|
216
|
+
await policy.authorize?.(call);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const decision = await run.requestApproval({
|
|
222
|
+
target: 'workspace-write',
|
|
223
|
+
action: `${reason}\n\nCommand to be run once after approval:\n${formatBashCommandForApproval(operationArgs.command)}`,
|
|
224
|
+
operation: { tool, args: operationArgs },
|
|
225
|
+
rememberable: false,
|
|
226
|
+
standing: 'none'
|
|
227
|
+
});
|
|
228
|
+
if (decision !== 'approved')
|
|
229
|
+
return false;
|
|
230
|
+
const currentRecord = loadRun(this.env.root, run.runId);
|
|
231
|
+
if (!isActiveStatus(currentRecord.status) || (currentRecord.trigger != null && currentRecord.trigger !== 'user'))
|
|
232
|
+
return false;
|
|
233
|
+
const currentCall = { run: currentRecord, caller, tool, args: operationArgs };
|
|
234
|
+
const currentScope = (await policy.scope?.(currentCall)) ?? { allowed: true };
|
|
235
|
+
if (currentScope.automatic || (!currentScope.allowed && !currentScope.requiresApproval))
|
|
236
|
+
return false;
|
|
237
|
+
try {
|
|
238
|
+
await policy.authorize?.(currentCall);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
142
244
|
}
|
|
143
245
|
};
|
|
144
246
|
}
|
|
@@ -195,6 +297,50 @@ export class Sessions {
|
|
|
195
297
|
});
|
|
196
298
|
return { release };
|
|
197
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* Starts the next slice when a reply stopped at its work-slice boundary (PROP-0041). Never for
|
|
302
|
+
* unattended, plan, subagent, command or worktree runs, after a blocked or fruitless slice, or
|
|
303
|
+
* past the policy's slice cap. The earlier record is never reopened; this is a new run with the
|
|
304
|
+
* same pins, exactly as an application-asked continuation.
|
|
305
|
+
*/
|
|
306
|
+
async continueSlice(input) {
|
|
307
|
+
const { root, runId, source, policy } = input;
|
|
308
|
+
if (!policy.enabled || !policy.continue || policy.maxSlices <= 0)
|
|
309
|
+
return;
|
|
310
|
+
if (source.automatic || source.plan || source.command || source.run.relation || source.run.worktreeId)
|
|
311
|
+
return;
|
|
312
|
+
if ((source.depth ?? 0) > 0)
|
|
313
|
+
return;
|
|
314
|
+
const record = loadRun(root, runId);
|
|
315
|
+
if (record.terminalReason !== 'slice_complete')
|
|
316
|
+
return;
|
|
317
|
+
const events = readEvents(root, runId);
|
|
318
|
+
const checkpoint = checkpointOf(events);
|
|
319
|
+
if (checkpoint?.blocked)
|
|
320
|
+
return;
|
|
321
|
+
const progressed = events.some((event) => event.type === 'file.changed')
|
|
322
|
+
|| events.some((event) => {
|
|
323
|
+
const payload = event.payload;
|
|
324
|
+
return event.type === 'tool.completed' && payload.name === 'bash' && payload.ok === true;
|
|
325
|
+
})
|
|
326
|
+
|| (checkpoint?.done.length ?? 0) > 0;
|
|
327
|
+
if (!progressed)
|
|
328
|
+
return;
|
|
329
|
+
if (sliceOf(root, runId) >= policy.maxSlices)
|
|
330
|
+
return;
|
|
331
|
+
const next = {
|
|
332
|
+
...source,
|
|
333
|
+
run: { ...source.run, id: randomUUID(), resumedFromRunId: null, parentRunId: null, relation: null },
|
|
334
|
+
continueFrom: runId,
|
|
335
|
+
text: CONTINUE_TEXT
|
|
336
|
+
};
|
|
337
|
+
next.initialBashCommand = undefined;
|
|
338
|
+
next.initialBashContext = undefined;
|
|
339
|
+
next.images = undefined;
|
|
340
|
+
next.resume = null;
|
|
341
|
+
next.command = undefined;
|
|
342
|
+
await this.run(next).catch((error) => log(`the next work slice did not start: ${error instanceof Error ? error.message : String(error)}`));
|
|
343
|
+
}
|
|
198
344
|
async start(input) {
|
|
199
345
|
const { root } = this.env;
|
|
200
346
|
if ((input.initialBashCommand !== undefined && input.initialBashCommand !== null) || (input.initialBashContext !== undefined && input.initialBashContext !== null)) {
|
|
@@ -222,8 +368,23 @@ export class Sessions {
|
|
|
222
368
|
throw invalid('An initial Bash command is available only for a new interactive user turn.');
|
|
223
369
|
}
|
|
224
370
|
}
|
|
371
|
+
let slicePolicy;
|
|
372
|
+
try {
|
|
373
|
+
slicePolicy = parseWorkSlice(input.workSlice);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
if (error instanceof WorkSliceError)
|
|
377
|
+
throw invalid(error.message);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
225
380
|
const continuation = input.continueFrom ? continueInput(root, input) : null;
|
|
381
|
+
const previousRun = continuation ? loadRun(root, continuation.runId) : null;
|
|
382
|
+
const workspaceRoot = previousRun?.workspaceRoot
|
|
383
|
+
? verifyWorkspaceRoot(previousRun.workspaceRoot)
|
|
384
|
+
: resolveWorkspaceRoot(previousRun?.workingDirectory ?? input.cwd);
|
|
226
385
|
const historyFile = selectHistory({ sessionDir: input.sessionDir, resume: input.resume });
|
|
386
|
+
if (input.command)
|
|
387
|
+
checkCommand(input.command, historyFile, input);
|
|
227
388
|
const account = this.options.accounts.resolve(input.accountId, input.poolId);
|
|
228
389
|
const context = this.options.accounts.context(account);
|
|
229
390
|
const runId = input.run.id;
|
|
@@ -239,7 +400,7 @@ export class Sessions {
|
|
|
239
400
|
const canAskUser = pinnedAskUser || (interactivePlan && harnessToolsEnabled);
|
|
240
401
|
const requestedTools = [...new Set([
|
|
241
402
|
...input.tools.allow.filter((name) => name !== SPAWN_SUBAGENT && name !== WAIT_SUBAGENTS && (name !== ASK_USER || canAskUser)),
|
|
242
|
-
...(harnessToolsEnabled ? [...(canAskUser ? [ASK_USER] : []),
|
|
403
|
+
...(harnessToolsEnabled ? [...(canAskUser ? [ASK_USER] : []), TODO_WRITE, CHECKPOINT_WRITE, SESSION_NAME, GET_CAPABILITIES, ...DEFAULT_TOOL_NAMES] : []),
|
|
243
404
|
...(broker?.toolNames ?? []),
|
|
244
405
|
...(canSpawn ? [SPAWN_SUBAGENT, WAIT_SUBAGENTS] : [])
|
|
245
406
|
])];
|
|
@@ -276,6 +437,7 @@ export class Sessions {
|
|
|
276
437
|
sessionId: input.run.sessionId,
|
|
277
438
|
nativeSessionId: null,
|
|
278
439
|
workingDirectory: input.cwd,
|
|
440
|
+
workspaceRoot,
|
|
279
441
|
worktreeId: input.run.worktreeId ?? null,
|
|
280
442
|
goal: input.run.goal ?? takeChars(input.text, 4000),
|
|
281
443
|
attachmentCount: input.run.attachmentCount ?? 0,
|
|
@@ -290,7 +452,9 @@ export class Sessions {
|
|
|
290
452
|
variantScope: variant?.scope ?? null,
|
|
291
453
|
variantVersion: variant?.fingerprint ?? null,
|
|
292
454
|
...(input.run.profile ? { profile: input.run.profile } : {}),
|
|
293
|
-
...(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 } : {})
|
|
294
458
|
});
|
|
295
459
|
// What the session is, kept with the run so later consolidation knows which memory it had.
|
|
296
460
|
try {
|
|
@@ -310,11 +474,18 @@ export class Sessions {
|
|
|
310
474
|
if (!existsSync(input.sessionDir))
|
|
311
475
|
mkdirSync(input.sessionDir, { recursive: true });
|
|
312
476
|
const launch = input.launch ?? {};
|
|
313
|
-
const plan = planSection(input.plan === true, historyFile);
|
|
477
|
+
const plan = planSection(input.plan === true, historyFile, input.run.relation === 'subagent');
|
|
314
478
|
const delivered = historyFile ? deliveredSnapshot(historyFile) : null;
|
|
315
479
|
const resumed = continuationSection(continuation, delivered?.some((entry) => entry.id === CONTINUATION_SECTION_ID) ?? false);
|
|
316
480
|
// The profiles replace the variant's own subagent list, which they include.
|
|
317
|
-
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;
|
|
318
489
|
if (profiles && variant)
|
|
319
490
|
variant = { ...variant, sections: variant.sections.filter((section) => section.id !== profiles.id) };
|
|
320
491
|
const own = [plan, resumed, profiles].filter((section) => section !== null);
|
|
@@ -331,6 +502,11 @@ export class Sessions {
|
|
|
331
502
|
fail(error);
|
|
332
503
|
throw error;
|
|
333
504
|
}
|
|
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);
|
|
509
|
+
const sliceState = createSliceState(slicePolicy, sliceOf(root, runId));
|
|
334
510
|
const run = this.options.runs.start(input.run.sessionId, runId);
|
|
335
511
|
if (run.finished)
|
|
336
512
|
return { runId, nativeSessionId: null };
|
|
@@ -353,6 +529,11 @@ export class Sessions {
|
|
|
353
529
|
});
|
|
354
530
|
try {
|
|
355
531
|
const tools = [
|
|
532
|
+
...(harnessToolsEnabled && allow.includes(GET_CAPABILITIES) ? [getCapabilitiesTool(() => ({
|
|
533
|
+
capabilities,
|
|
534
|
+
active: pi?.getActiveToolNames?.() ?? [],
|
|
535
|
+
registered: pi?.getAllTools?.() ?? []
|
|
536
|
+
}))] : []),
|
|
356
537
|
...BUILTIN_PLUGIN_REGISTRY.tools({
|
|
357
538
|
env: this.options.env,
|
|
358
539
|
caller,
|
|
@@ -379,12 +560,15 @@ export class Sessions {
|
|
|
379
560
|
}
|
|
380
561
|
}
|
|
381
562
|
const readOnly = new Set(tools.filter((tool) => tool.readOnly).map((tool) => tool.name));
|
|
563
|
+
const checkpointPlanInstructions = input.plan
|
|
564
|
+
? () => input.run.relation === 'subagent' ? PLAN_RESEARCH_SUBAGENT_INSTRUCTIONS : PLAN_INSTRUCTIONS
|
|
565
|
+
: undefined;
|
|
382
566
|
const planModeSafety = new Map();
|
|
383
567
|
for (const tool of tools)
|
|
384
568
|
if (tool.planModeSafe)
|
|
385
569
|
planModeSafety.set(tool.name, tool.planModeSafe);
|
|
386
570
|
const gate = (() => {
|
|
387
|
-
const baseGate = this.gate(run, caller, new Set((input.tools.gated ?? []).filter((name) => capabilities.tools.includes(name))));
|
|
571
|
+
const baseGate = this.gate(run, caller, new Set((input.tools.gated ?? []).filter((name) => capabilities.tools.includes(name))), false, input.automatic === true);
|
|
388
572
|
return {
|
|
389
573
|
...baseGate,
|
|
390
574
|
check: (name, args) => {
|
|
@@ -401,7 +585,9 @@ export class Sessions {
|
|
|
401
585
|
...(input.initialBashContext !== undefined && input.initialBashContext !== null ? { initialBashContext: input.initialBashContext } : {}),
|
|
402
586
|
gate,
|
|
403
587
|
restrictTools: input.run.relation === 'subagent',
|
|
588
|
+
...(input.plan ? { plan: true } : {}),
|
|
404
589
|
cwd: input.cwd,
|
|
590
|
+
workspaceRoot,
|
|
405
591
|
sessionDir: input.sessionDir,
|
|
406
592
|
historyFile,
|
|
407
593
|
model: input.model ?? null,
|
|
@@ -414,10 +600,20 @@ export class Sessions {
|
|
|
414
600
|
account: context,
|
|
415
601
|
resources: { ids: [], skillPaths: variant?.skillPaths ?? [], promptPaths: [] },
|
|
416
602
|
variantExtensions: variant?.extensionPaths ?? [],
|
|
417
|
-
inline: [
|
|
603
|
+
inline: [
|
|
604
|
+
...firstPartyFor(root, capabilities.contributions),
|
|
605
|
+
runLineageJoin(root, runId),
|
|
606
|
+
this.options.subagents.extension(runId),
|
|
607
|
+
{ name: 'image-pruning', factory: imagePruning() },
|
|
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 }) }] : [])
|
|
610
|
+
],
|
|
418
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) } } : {}),
|
|
419
612
|
system,
|
|
420
|
-
|
|
613
|
+
...(sliceEnabled ? { slice: { state: sliceState, maxToolCalls: slicePolicy.maxToolCalls } } : {}),
|
|
614
|
+
// A command sends no request of its own, so the context update waits for the next turn.
|
|
615
|
+
update: input.command ? null : update,
|
|
616
|
+
...(input.command ? { command: input.command } : {})
|
|
421
617
|
};
|
|
422
618
|
pi = await this.factory({
|
|
423
619
|
params,
|
|
@@ -440,12 +636,19 @@ export class Sessions {
|
|
|
440
636
|
throw new HarnessError('native_resume_unavailable', 'The saved conversation could not be restored.');
|
|
441
637
|
}
|
|
442
638
|
const opened = pi;
|
|
443
|
-
|
|
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
|
+
});
|
|
444
647
|
this.options.subagents.register(input, account.id, capabilities, Boolean(pi.sessionManager));
|
|
445
|
-
if (
|
|
446
|
-
this.options.subagents.resolvedModel(runId,
|
|
648
|
+
if (openedModel)
|
|
649
|
+
this.options.subagents.resolvedModel(runId, openedModel, pi.thinkingLevel);
|
|
447
650
|
params.settle = () => this.options.subagents.verify(runId, opened.sessionManager ? subagentHistory(opened.sessionManager.getBranch()) : undefined);
|
|
448
|
-
void runTurn(run, pi, params);
|
|
651
|
+
void runTurn(run, pi, params).then(() => (sliceEnabled && !input.command ? this.continueSlice({ root, runId, source: input, policy: slicePolicy }) : undefined));
|
|
449
652
|
return { runId, nativeSessionId: pi.sessionId };
|
|
450
653
|
}
|
|
451
654
|
catch (error) {
|
|
@@ -14,7 +14,12 @@ type Started = {
|
|
|
14
14
|
export type SpawnedSubagent = Started & {
|
|
15
15
|
agent?: string;
|
|
16
16
|
unavailableTools?: string[];
|
|
17
|
+
continued?: string;
|
|
17
18
|
};
|
|
19
|
+
export interface SubagentRuntimeSettings {
|
|
20
|
+
model: string | null;
|
|
21
|
+
effort: Effort | null;
|
|
22
|
+
}
|
|
18
23
|
export interface SubagentServiceOptions {
|
|
19
24
|
/** The plugin descriptors, so a profile's plugin list can drop the tools those plugins own. */
|
|
20
25
|
descriptors?: () => readonly PluginDescriptor[];
|
|
@@ -30,12 +35,31 @@ export declare class Subagents {
|
|
|
30
35
|
private readonly launch;
|
|
31
36
|
private readonly options;
|
|
32
37
|
private readonly parents;
|
|
38
|
+
private readonly runtimeSettingsByRun;
|
|
33
39
|
constructor(env: HarnessEnv, runs: RunRegistry, launch: (input: SessionRunInput) => Promise<Started>, options?: SubagentServiceOptions);
|
|
34
40
|
/** Internal adapter contract: context comes from a live run, never from model arguments. */
|
|
35
41
|
register(input: SessionRunInput, accountId: string, capabilities: CapabilitySet, deferUntilPrompt?: boolean): void;
|
|
42
|
+
runtimeSettings(runId: string): SubagentRuntimeSettings | null;
|
|
43
|
+
private rememberRuntimeSettings;
|
|
36
44
|
resolvedModel(runId: string, model: string, effort?: Effort): void;
|
|
37
45
|
private parent;
|
|
46
|
+
private planSpawnCheck;
|
|
47
|
+
/** The plan-mode per-call gate and spawn implementation share this eligibility check. */
|
|
48
|
+
planSpawnRefusal(parentRunId: string, args: unknown): string | null;
|
|
38
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;
|
|
39
63
|
private selected;
|
|
40
64
|
results(selection: SubagentSelection): SubagentResult[];
|
|
41
65
|
wait(selection: SubagentSelection, signal?: AbortSignal): Promise<SubagentResult[]>;
|