@qduc/term2 0.10.1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +18 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +66 -24
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +10 -11
- package/dist/app.js.map +1 -1
- package/dist/components/layout/BackgroundTasksPanel.d.ts +10 -0
- package/dist/components/layout/BackgroundTasksPanel.d.ts.map +1 -0
- package/dist/components/layout/BackgroundTasksPanel.js +79 -0
- package/dist/components/layout/BackgroundTasksPanel.js.map +1 -0
- package/dist/components/layout/BottomArea.d.ts +3 -0
- package/dist/components/layout/BottomArea.d.ts.map +1 -1
- package/dist/components/layout/BottomArea.js +3 -1
- package/dist/components/layout/BottomArea.js.map +1 -1
- package/dist/components/message/CommandMessage.js +25 -3
- package/dist/components/message/CommandMessage.js.map +1 -1
- package/dist/components/message/SubagentActivityMessage.d.ts +1 -0
- package/dist/components/message/SubagentActivityMessage.d.ts.map +1 -1
- package/dist/components/message/SubagentActivityMessage.js +3 -3
- package/dist/components/message/SubagentActivityMessage.js.map +1 -1
- package/dist/components/message/command-message-helpers.d.ts +4 -4
- package/dist/components/message/command-message-helpers.d.ts.map +1 -1
- package/dist/components/message/command-message-helpers.js +10 -0
- package/dist/components/message/command-message-helpers.js.map +1 -1
- package/dist/components/prompt/ApprovalPrompt.d.ts.map +1 -1
- package/dist/components/prompt/ApprovalPrompt.js +28 -3
- package/dist/components/prompt/ApprovalPrompt.js.map +1 -1
- package/dist/hooks/conversation-ui-reducer.d.ts +5 -0
- package/dist/hooks/conversation-ui-reducer.d.ts.map +1 -1
- package/dist/hooks/conversation-ui-reducer.js +8 -0
- package/dist/hooks/conversation-ui-reducer.js.map +1 -1
- package/dist/hooks/settings-completion-config.d.ts.map +1 -1
- package/dist/hooks/settings-completion-config.js +4 -0
- package/dist/hooks/settings-completion-config.js.map +1 -1
- package/dist/hooks/use-conversation.d.ts +3 -0
- package/dist/hooks/use-conversation.d.ts.map +1 -1
- package/dist/hooks/use-conversation.js +24 -1
- package/dist/hooks/use-conversation.js.map +1 -1
- package/dist/lib/agent-client.d.ts +16 -1
- package/dist/lib/agent-client.d.ts.map +1 -1
- package/dist/lib/agent-client.js +22 -1
- package/dist/lib/agent-client.js.map +1 -1
- package/dist/lib/agent-configuration.d.ts.map +1 -1
- package/dist/lib/agent-configuration.js +5 -0
- package/dist/lib/agent-configuration.js.map +1 -1
- package/dist/lib/agent-factory.d.ts +18 -0
- package/dist/lib/agent-factory.d.ts.map +1 -1
- package/dist/lib/agent-factory.js +5 -0
- package/dist/lib/agent-factory.js.map +1 -1
- package/dist/lib/chained-input-filter.d.ts +20 -0
- package/dist/lib/chained-input-filter.d.ts.map +1 -1
- package/dist/lib/chained-input-filter.js +75 -0
- package/dist/lib/chained-input-filter.js.map +1 -1
- package/dist/lib/subagent-bridge.d.ts +57 -4
- package/dist/lib/subagent-bridge.d.ts.map +1 -1
- package/dist/lib/subagent-bridge.js +141 -8
- package/dist/lib/subagent-bridge.js.map +1 -1
- package/dist/prompts/anthropic.md +6 -55
- package/dist/prompts/async-subagent-delegation.d.ts +10 -0
- package/dist/prompts/async-subagent-delegation.d.ts.map +1 -0
- package/dist/prompts/async-subagent-delegation.js +50 -0
- package/dist/prompts/async-subagent-delegation.js.map +1 -0
- package/dist/prompts/async-subagent-delegation.ts +65 -0
- package/dist/prompts/gpt-5.6.md +49 -0
- package/dist/prompts/kimi.md +25 -63
- package/dist/prompts/orchestrator-prompt.test.ts +77 -0
- package/dist/prompts/orchestrator.md +30 -3
- package/dist/prompts/prompt-constructor.d.ts +2 -0
- package/dist/prompts/prompt-constructor.d.ts.map +1 -1
- package/dist/prompts/prompt-constructor.js +9 -1
- package/dist/prompts/prompt-constructor.js.map +1 -1
- package/dist/prompts/prompt-constructor.test.ts +72 -0
- package/dist/prompts/prompt-constructor.ts +15 -0
- package/dist/prompts/prompt-profiles.d.ts.map +1 -1
- package/dist/prompts/prompt-profiles.js +5 -0
- package/dist/prompts/prompt-profiles.js.map +1 -1
- package/dist/prompts/prompt-profiles.test.ts +20 -0
- package/dist/prompts/prompt-profiles.ts +5 -0
- package/dist/prompts/search-via-shell.d.ts.map +1 -1
- package/dist/prompts/search-via-shell.js +8 -25
- package/dist/prompts/search-via-shell.js.map +1 -1
- package/dist/prompts/search-via-shell.test.ts +18 -0
- package/dist/prompts/search-via-shell.ts +8 -25
- package/dist/prompts/subagent-delegation.d.ts.map +1 -1
- package/dist/prompts/subagent-delegation.js +2 -1
- package/dist/prompts/subagent-delegation.js.map +1 -1
- package/dist/prompts/subagent-delegation.test.ts +15 -0
- package/dist/prompts/subagent-delegation.ts +2 -1
- package/dist/prompts/subagents/researcher.md +6 -0
- package/dist/prompts/subagents/worker-prompt.test.ts +35 -0
- package/dist/prompts/subagents/worker.md +8 -0
- package/dist/services/agent-runtime/execution-budget.d.ts +6 -0
- package/dist/services/agent-runtime/execution-budget.d.ts.map +1 -1
- package/dist/services/agent-runtime/execution-budget.js +32 -24
- package/dist/services/agent-runtime/execution-budget.js.map +1 -1
- package/dist/services/agent-runtime/permission-resolver.js +1 -1
- package/dist/services/agent-runtime/permission-resolver.js.map +1 -1
- package/dist/services/conversation/conversation-adapter.d.ts +11 -3
- package/dist/services/conversation/conversation-adapter.d.ts.map +1 -1
- package/dist/services/conversation/conversation-adapter.js +125 -31
- package/dist/services/conversation/conversation-adapter.js.map +1 -1
- package/dist/services/conversation/conversation-events.d.ts +36 -1
- package/dist/services/conversation/conversation-events.d.ts.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.d.ts.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.js +263 -32
- package/dist/services/conversation/conversation-orchestrator.js.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.types.d.ts +2 -0
- package/dist/services/conversation/conversation-orchestrator.types.d.ts.map +1 -1
- package/dist/services/conversation/conversation-replay.d.ts.map +1 -1
- package/dist/services/conversation/conversation-replay.js +1 -0
- package/dist/services/conversation/conversation-replay.js.map +1 -1
- package/dist/services/conversation/conversation-service.d.ts +25 -0
- package/dist/services/conversation/conversation-service.d.ts.map +1 -1
- package/dist/services/conversation/conversation-service.js +44 -0
- package/dist/services/conversation/conversation-service.js.map +1 -1
- package/dist/services/conversation/conversation-store.d.ts +6 -0
- package/dist/services/conversation/conversation-store.d.ts.map +1 -1
- package/dist/services/conversation/conversation-store.js +17 -0
- package/dist/services/conversation/conversation-store.js.map +1 -1
- package/dist/services/conversation-agent-client.d.ts +13 -0
- package/dist/services/conversation-agent-client.d.ts.map +1 -1
- package/dist/services/logging/conversation-log-events.d.ts +10 -1
- package/dist/services/logging/conversation-log-events.d.ts.map +1 -1
- package/dist/services/logging/conversation-log-events.js.map +1 -1
- package/dist/services/logging/conversation-log-writer.d.ts +1 -0
- package/dist/services/logging/conversation-log-writer.d.ts.map +1 -1
- package/dist/services/logging/conversation-log-writer.js +1 -1
- package/dist/services/logging/conversation-log-writer.js.map +1 -1
- package/dist/services/logging/conversation-logger.d.ts.map +1 -1
- package/dist/services/logging/conversation-logger.js +11 -0
- package/dist/services/logging/conversation-logger.js.map +1 -1
- package/dist/services/plan-mode-interceptor.js +2 -2
- package/dist/services/plan-mode-interceptor.js.map +1 -1
- package/dist/services/queue/queue-controller.d.ts +1 -0
- package/dist/services/queue/queue-controller.d.ts.map +1 -1
- package/dist/services/queue/queue-controller.js +7 -4
- package/dist/services/queue/queue-controller.js.map +1 -1
- package/dist/services/retry/retry-classifier.d.ts.map +1 -1
- package/dist/services/retry/retry-classifier.js +4 -2
- package/dist/services/retry/retry-classifier.js.map +1 -1
- package/dist/services/session/session-composition.d.ts +23 -0
- package/dist/services/session/session-composition.d.ts.map +1 -1
- package/dist/services/session/session-composition.js +65 -1
- package/dist/services/session/session-composition.js.map +1 -1
- package/dist/services/settings/settings-merger.d.ts.map +1 -1
- package/dist/services/settings/settings-merger.js +2 -0
- package/dist/services/settings/settings-merger.js.map +1 -1
- package/dist/services/settings/settings-schema.d.ts +15 -0
- package/dist/services/settings/settings-schema.d.ts.map +1 -1
- package/dist/services/settings/settings-schema.js +23 -0
- package/dist/services/settings/settings-schema.js.map +1 -1
- package/dist/services/subagents/execution-runner.d.ts +5 -2
- package/dist/services/subagents/execution-runner.d.ts.map +1 -1
- package/dist/services/subagents/execution-runner.js +125 -10
- package/dist/services/subagents/execution-runner.js.map +1 -1
- package/dist/services/subagents/mentor-runner.d.ts +5 -1
- package/dist/services/subagents/mentor-runner.d.ts.map +1 -1
- package/dist/services/subagents/mentor-runner.js +60 -3
- package/dist/services/subagents/mentor-runner.js.map +1 -1
- package/dist/services/subagents/runtime.d.ts +2 -0
- package/dist/services/subagents/runtime.d.ts.map +1 -1
- package/dist/services/subagents/runtime.js +32 -2
- package/dist/services/subagents/runtime.js.map +1 -1
- package/dist/services/subagents/subagent-async-registry.d.ts +67 -0
- package/dist/services/subagents/subagent-async-registry.d.ts.map +1 -0
- package/dist/services/subagents/subagent-async-registry.js +506 -0
- package/dist/services/subagents/subagent-async-registry.js.map +1 -0
- package/dist/services/subagents/subagent-manager.d.ts +31 -0
- package/dist/services/subagents/subagent-manager.d.ts.map +1 -1
- package/dist/services/subagents/subagent-manager.js +61 -1
- package/dist/services/subagents/subagent-manager.js.map +1 -1
- package/dist/services/subagents/subagent-notification-store.d.ts +107 -0
- package/dist/services/subagents/subagent-notification-store.d.ts.map +1 -0
- package/dist/services/subagents/subagent-notification-store.js +209 -0
- package/dist/services/subagents/subagent-notification-store.js.map +1 -0
- package/dist/services/subagents/subagent-run-control.d.ts +41 -0
- package/dist/services/subagents/subagent-run-control.d.ts.map +1 -0
- package/dist/services/subagents/subagent-run-control.js +166 -0
- package/dist/services/subagents/subagent-run-control.js.map +1 -0
- package/dist/services/subagents/subagent-session.d.ts +12 -1
- package/dist/services/subagents/subagent-session.d.ts.map +1 -1
- package/dist/services/subagents/subagent-session.js +29 -6
- package/dist/services/subagents/subagent-session.js.map +1 -1
- package/dist/services/subagents/tool-policy.d.ts +24 -4
- package/dist/services/subagents/tool-policy.d.ts.map +1 -1
- package/dist/services/subagents/tool-policy.js +134 -14
- package/dist/services/subagents/tool-policy.js.map +1 -1
- package/dist/services/subagents/types.d.ts +104 -0
- package/dist/services/subagents/types.d.ts.map +1 -1
- package/dist/services/subagents/types.js +1 -0
- package/dist/services/subagents/types.js.map +1 -1
- package/dist/services/subagents/utils.d.ts +6 -0
- package/dist/services/subagents/utils.d.ts.map +1 -1
- package/dist/services/subagents/utils.js +21 -0
- package/dist/services/subagents/utils.js.map +1 -1
- package/dist/tools/agent/ask-orchestrator.d.ts +11 -0
- package/dist/tools/agent/ask-orchestrator.d.ts.map +1 -0
- package/dist/tools/agent/ask-orchestrator.js +39 -0
- package/dist/tools/agent/ask-orchestrator.js.map +1 -0
- package/dist/tools/agent/run-subagent-async.d.ts +67 -0
- package/dist/tools/agent/run-subagent-async.d.ts.map +1 -0
- package/dist/tools/agent/run-subagent-async.js +401 -0
- package/dist/tools/agent/run-subagent-async.js.map +1 -0
- package/dist/tools/file/code-context.d.ts +1 -0
- package/dist/tools/file/code-context.d.ts.map +1 -1
- package/dist/tools/file/code-context.js +4 -4
- package/dist/tools/file/code-context.js.map +1 -1
- package/dist/tools/file/grep.d.ts +1 -0
- package/dist/tools/file/grep.d.ts.map +1 -1
- package/dist/tools/file/grep.js +16 -10
- package/dist/tools/file/grep.js.map +1 -1
- package/dist/types/message.d.ts +1 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/conversation/conversation-event-handler.d.ts.map +1 -1
- package/dist/utils/conversation/conversation-event-handler.js +7 -3
- package/dist/utils/conversation/conversation-event-handler.js.map +1 -1
- package/dist/utils/settings-command.d.ts.map +1 -1
- package/dist/utils/settings-command.js +10 -0
- package/dist/utils/settings-command.js.map +1 -1
- package/dist/utils/shell/sandbox/sandbox-network-approval.d.ts +2 -1
- package/dist/utils/shell/sandbox/sandbox-network-approval.d.ts.map +1 -1
- package/dist/utils/shell/sandbox/sandbox-network-approval.js +17 -1
- package/dist/utils/shell/sandbox/sandbox-network-approval.js.map +1 -1
- package/dist/utils/shell/sandbox/sandbox-network-store.d.ts +20 -0
- package/dist/utils/shell/sandbox/sandbox-network-store.d.ts.map +1 -0
- package/dist/utils/shell/sandbox/sandbox-network-store.js +99 -0
- package/dist/utils/shell/sandbox/sandbox-network-store.js.map +1 -0
- package/package.json +1 -1
|
@@ -4,11 +4,13 @@ import { isAbortLike, safeEmit } from './utils.js';
|
|
|
4
4
|
import { normalizeAgentRunUsage, extractUsage } from '../../utils/ai/token-usage.js';
|
|
5
5
|
import { adaptLegacyRole, adaptLegacyDefinition } from '../agent-runtime/legacy-adapter.js';
|
|
6
6
|
import { createAgentRuntimeFromSubagentRuntime } from '../agent-runtime/compose-agent-runtime.js';
|
|
7
|
+
import { SubagentRegistryError } from './subagent-async-registry.js';
|
|
7
8
|
export class SubagentManager {
|
|
8
9
|
#logger;
|
|
9
10
|
#settings;
|
|
10
11
|
#onEvent;
|
|
11
12
|
#runtime;
|
|
13
|
+
#mentorActive = false;
|
|
12
14
|
constructor(deps) {
|
|
13
15
|
this.#logger = deps.logger;
|
|
14
16
|
this.#settings = deps.settings;
|
|
@@ -17,6 +19,7 @@ export class SubagentManager {
|
|
|
17
19
|
}
|
|
18
20
|
resetMentorSession() {
|
|
19
21
|
this.#runtime.mentorRunner.reset();
|
|
22
|
+
this.#runtime.asyncRegistry.reset();
|
|
20
23
|
}
|
|
21
24
|
clearCache() {
|
|
22
25
|
this.#runtime.nestedRunner.clearCache();
|
|
@@ -67,8 +70,14 @@ export class SubagentManager {
|
|
|
67
70
|
parentTool: request.parentTool,
|
|
68
71
|
});
|
|
69
72
|
try {
|
|
73
|
+
if (request.role === 'mentor') {
|
|
74
|
+
if (this.#mentorActive || this.#runtime.asyncRegistry.hasActiveRunForRole('mentor')) {
|
|
75
|
+
throw new SubagentRegistryError('already_active', 'Mentor session is already active');
|
|
76
|
+
}
|
|
77
|
+
this.#mentorActive = true;
|
|
78
|
+
}
|
|
70
79
|
const result = request.role === 'mentor'
|
|
71
|
-
? await this.#runtime.mentorRunner.run(agentId, request.task, request.signal)
|
|
80
|
+
? await this.#runtime.mentorRunner.run(agentId, request.task, request.signal, undefined, request.executionBudget)
|
|
72
81
|
: await this.#runtime.executionRunner.run(agentId, request, this.#resolveRoleDefinition(request.role));
|
|
73
82
|
safeEmit(this.#logger, this.#onEvent, { type: 'subagent_completed', result });
|
|
74
83
|
return result;
|
|
@@ -95,6 +104,57 @@ export class SubagentManager {
|
|
|
95
104
|
safeEmit(this.#logger, this.#onEvent, { type: 'subagent_completed', result });
|
|
96
105
|
return result;
|
|
97
106
|
}
|
|
107
|
+
finally {
|
|
108
|
+
if (request.role === 'mentor')
|
|
109
|
+
this.#mentorActive = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Start an asynchronous subagent run.
|
|
114
|
+
*
|
|
115
|
+
* Delegates to the SubagentAsyncRegistry, which owns the live session and
|
|
116
|
+
* run lifecycle. The returned handle exposes only the live-run contract.
|
|
117
|
+
*/
|
|
118
|
+
startRunAsync(request) {
|
|
119
|
+
if (request.role === 'mentor' && this.#mentorActive) {
|
|
120
|
+
throw new SubagentRegistryError('already_active', 'Mentor session is already active');
|
|
121
|
+
}
|
|
122
|
+
return this.#runtime.asyncRegistry.startRun(request);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Retrieve the result of a previously started asynchronous subagent run.
|
|
126
|
+
*/
|
|
127
|
+
getRunResult(runId, signal) {
|
|
128
|
+
return this.#runtime.asyncRegistry.getResult(runId, signal);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Non-blocking progress snapshot for the peek (get_subagent_status) tool.
|
|
132
|
+
* One run when `runId` is provided, all non-evicted runs otherwise. Never
|
|
133
|
+
* awaits and never carries completion detail.
|
|
134
|
+
*/
|
|
135
|
+
getRunStatus(runId) {
|
|
136
|
+
return this.#runtime.asyncRegistry.getRunStatus(runId);
|
|
137
|
+
}
|
|
138
|
+
/** Queue parent steering or an ask_orchestrator answer without awaiting a run. */
|
|
139
|
+
sendMessageToAsyncRun(params) {
|
|
140
|
+
return this.#runtime.asyncRegistry.sendMessage(params.target, params.message, params.reply_to);
|
|
141
|
+
}
|
|
142
|
+
/** Request two-phase parent cancellation by canonical runId or active name. */
|
|
143
|
+
cancelAsyncRun(target) {
|
|
144
|
+
return this.#runtime.asyncRegistry.cancelRun(target);
|
|
145
|
+
}
|
|
146
|
+
abortAsyncRun(runId) {
|
|
147
|
+
this.#runtime.asyncRegistry.abortRun(runId);
|
|
148
|
+
}
|
|
149
|
+
resetAsyncRuns() {
|
|
150
|
+
this.#runtime.asyncRegistry.reset();
|
|
151
|
+
}
|
|
152
|
+
/** Cancel all live asynchronous runs for an explicit parent abort. */
|
|
153
|
+
cancelAllAsyncRuns() {
|
|
154
|
+
this.#runtime.asyncRegistry.cancelAllRuns();
|
|
155
|
+
}
|
|
156
|
+
dispose() {
|
|
157
|
+
this.#runtime.asyncRegistry.dispose();
|
|
98
158
|
}
|
|
99
159
|
}
|
|
100
160
|
//# sourceMappingURL=subagent-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-manager.js","sourceRoot":"","sources":["../../../source/services/subagents/subagent-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EAAE,qBAAqB,EAAwB,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAErF,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC5F,OAAO,EAAE,qCAAqC,EAAE,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"subagent-manager.js","sourceRoot":"","sources":["../../../source/services/subagents/subagent-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { ConversationEvent } from '../conversation/conversation-events.js';
|
|
2
|
+
/** A completed background run that still owes the main agent a notification. */
|
|
3
|
+
export interface BackgroundSubagentCompletionNotification {
|
|
4
|
+
kind: 'completion';
|
|
5
|
+
/** Stable per logical run, so replay cannot duplicate a completion. */
|
|
6
|
+
messageId: string;
|
|
7
|
+
runId: string;
|
|
8
|
+
role: string;
|
|
9
|
+
status: 'completed' | 'failed' | 'cancelled';
|
|
10
|
+
preview: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
completedAt: number;
|
|
13
|
+
}
|
|
14
|
+
/** A live execution segment's bounded request for its owning orchestrator. */
|
|
15
|
+
export interface BackgroundSubagentQuestionNotification {
|
|
16
|
+
kind: 'question';
|
|
17
|
+
messageId: string;
|
|
18
|
+
runId: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
role: string;
|
|
21
|
+
question: string;
|
|
22
|
+
askedAt: number;
|
|
23
|
+
}
|
|
24
|
+
/** A message-id-keyed queue item for a background async subagent. */
|
|
25
|
+
export type BackgroundSubagentNotification = BackgroundSubagentCompletionNotification | BackgroundSubagentQuestionNotification;
|
|
26
|
+
export type BackgroundSubagentTaskStatus = 'running' | 'completed' | 'failed' | 'cancelled';
|
|
27
|
+
/** The single most recent tool call observed for a live background run. */
|
|
28
|
+
export interface BackgroundSubagentTaskTool {
|
|
29
|
+
/** Display-ready command line, e.g. `grep "TODO" src/`. */
|
|
30
|
+
label: string;
|
|
31
|
+
state: 'running' | 'success' | 'failed';
|
|
32
|
+
}
|
|
33
|
+
/** Conversation-scoped projection of one background subagent lifecycle. */
|
|
34
|
+
export interface BackgroundSubagentTask {
|
|
35
|
+
runId: string;
|
|
36
|
+
role: string;
|
|
37
|
+
task: string;
|
|
38
|
+
status: BackgroundSubagentTaskStatus;
|
|
39
|
+
startedAt: number;
|
|
40
|
+
completedAt?: number;
|
|
41
|
+
/** Absent until the run calls its first tool; dropped once the run settles. */
|
|
42
|
+
lastTool?: BackgroundSubagentTaskTool;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The delivery half of {@link SubagentNotificationStore}, for callers that hand
|
|
46
|
+
* pending notifications to the main agent but never produce them.
|
|
47
|
+
*/
|
|
48
|
+
export interface BackgroundSubagentNotificationPort {
|
|
49
|
+
readonly pendingCount: number;
|
|
50
|
+
drain(): BackgroundSubagentNotification[];
|
|
51
|
+
retain(notifications: readonly BackgroundSubagentNotification[]): void;
|
|
52
|
+
}
|
|
53
|
+
/** Read-only lifecycle projection used by the background-tasks UI. */
|
|
54
|
+
export interface BackgroundSubagentTaskPort {
|
|
55
|
+
getSnapshot(): readonly BackgroundSubagentTask[];
|
|
56
|
+
setObserver(observer: (() => void) | null): void;
|
|
57
|
+
}
|
|
58
|
+
export interface SubagentNotificationStoreDeps {
|
|
59
|
+
/** Injectable clock so completion timestamps stay deterministic under test. */
|
|
60
|
+
now?: () => number;
|
|
61
|
+
/** How long terminal tasks remain visible in the background overview. */
|
|
62
|
+
recentTaskRetentionMs?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Upper bound on remembered notification ids. The async registry caps
|
|
65
|
+
* sessions at 50 and TTLs terminal runs out after 30 minutes, so a few
|
|
66
|
+
* hundred ids covers replay protection while staying O(1) in memory.
|
|
67
|
+
*/
|
|
68
|
+
deliveredIdCap?: number;
|
|
69
|
+
}
|
|
70
|
+
export declare const BACKGROUND_TASK_RECENT_RETENTION_MS = 5000;
|
|
71
|
+
/**
|
|
72
|
+
* Pending notifications for background (async) subagent runs.
|
|
73
|
+
*
|
|
74
|
+
* Owns three invariants the callers must not have to re-derive:
|
|
75
|
+
* - Only async completions and async registry questions are notifiable.
|
|
76
|
+
* Foreground and nested activity has no async flag and never surfaces here.
|
|
77
|
+
* - A message is announced at most once, ever. Completion ids are stable per
|
|
78
|
+
* run while each question has its own id, allowing one live run to ask more
|
|
79
|
+
* than once over its lifetime without replaying either message.
|
|
80
|
+
* - Delivery is confirmed by the caller, not by reading. `drain()` hands over
|
|
81
|
+
* the pending batch and clears it; a caller whose delivery failed calls
|
|
82
|
+
* `retain()` to put the batch back at the front of the queue. Drain/retain
|
|
83
|
+
* was chosen over peek/commit because the common path (delivery succeeds) is
|
|
84
|
+
* then a single call, and because retained notifications are handed back as
|
|
85
|
+
* values rather than leaving the store holding provisional state. A message
|
|
86
|
+
* id stays deduped across both paths, so a retained notification is
|
|
87
|
+
* redelivered exactly once and a replayed event for it is still dropped.
|
|
88
|
+
*/
|
|
89
|
+
export declare class SubagentNotificationStore implements BackgroundSubagentNotificationPort {
|
|
90
|
+
#private;
|
|
91
|
+
constructor(deps?: SubagentNotificationStoreDeps);
|
|
92
|
+
/**
|
|
93
|
+
* Updates the read-only task projection for async starts, tool activity, and
|
|
94
|
+
* completions. Only the newest tool call of a live run is kept: the overview
|
|
95
|
+
* answers "what is it doing now", not "what has it done".
|
|
96
|
+
*/
|
|
97
|
+
recordLifecycle(event: ConversationEvent): boolean;
|
|
98
|
+
getTaskSnapshot(): readonly BackgroundSubagentTask[];
|
|
99
|
+
/** Records one novel async completion or question, returning whether it woke the queue. */
|
|
100
|
+
enqueue(event: ConversationEvent): boolean;
|
|
101
|
+
get pendingCount(): number;
|
|
102
|
+
/** Hands over every pending notification in completion order and clears them. */
|
|
103
|
+
drain(): BackgroundSubagentNotification[];
|
|
104
|
+
/** Returns undelivered notifications to the queue, ahead of anything newer. */
|
|
105
|
+
retain(notifications: readonly BackgroundSubagentNotification[]): void;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=subagent-notification-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-notification-store.d.ts","sourceRoot":"","sources":["../../../source/services/subagents/subagent-notification-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,wCAAwC,CAAC;AAKhD,gFAAgF;AAChF,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,YAAY,CAAC;IACnB,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,8EAA8E;AAC9E,MAAM,WAAW,sCAAsC;IACrD,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,MAAM,8BAA8B,GACtC,wCAAwC,GACxC,sCAAsC,CAAC;AAE3C,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE5F,2EAA2E;AAC3E,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;CACzC;AAED,2EAA2E;AAC3E,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,KAAK,IAAI,8BAA8B,EAAE,CAAC;IAC1C,MAAM,CAAC,aAAa,EAAE,SAAS,8BAA8B,EAAE,GAAG,IAAI,CAAC;CACxE;AAED,sEAAsE;AACtE,MAAM,WAAW,0BAA0B;IACzC,WAAW,IAAI,SAAS,sBAAsB,EAAE,CAAC;IACjD,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,6BAA6B;IAC5C,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAGD,eAAO,MAAM,mCAAmC,OAAQ,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,yBAA0B,YAAW,kCAAkC;;IASlF,YAAY,IAAI,GAAE,6BAAkC,EAInD;IAED;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CA+CjD;IA6BD,eAAe,IAAI,SAAS,sBAAsB,EAAE,CAQnD;IAED,2FAA2F;IAC3F,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAQzC;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,iFAAiF;IACjF,KAAK,IAAI,8BAA8B,EAAE,CAOxC;IAED,+EAA+E;IAC/E,MAAM,CAAC,aAAa,EAAE,SAAS,8BAA8B,EAAE,GAAG,IAAI,CASrE;CA+CF"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { formatToolCommand, parseToolArguments } from '../../utils/conversation/conversation-utils.js';
|
|
2
|
+
import { truncatePreview } from './utils.js';
|
|
3
|
+
const DEFAULT_DELIVERED_ID_CAP = 256;
|
|
4
|
+
export const BACKGROUND_TASK_RECENT_RETENTION_MS = 5_000;
|
|
5
|
+
/**
|
|
6
|
+
* Pending notifications for background (async) subagent runs.
|
|
7
|
+
*
|
|
8
|
+
* Owns three invariants the callers must not have to re-derive:
|
|
9
|
+
* - Only async completions and async registry questions are notifiable.
|
|
10
|
+
* Foreground and nested activity has no async flag and never surfaces here.
|
|
11
|
+
* - A message is announced at most once, ever. Completion ids are stable per
|
|
12
|
+
* run while each question has its own id, allowing one live run to ask more
|
|
13
|
+
* than once over its lifetime without replaying either message.
|
|
14
|
+
* - Delivery is confirmed by the caller, not by reading. `drain()` hands over
|
|
15
|
+
* the pending batch and clears it; a caller whose delivery failed calls
|
|
16
|
+
* `retain()` to put the batch back at the front of the queue. Drain/retain
|
|
17
|
+
* was chosen over peek/commit because the common path (delivery succeeds) is
|
|
18
|
+
* then a single call, and because retained notifications are handed back as
|
|
19
|
+
* values rather than leaving the store holding provisional state. A message
|
|
20
|
+
* id stays deduped across both paths, so a retained notification is
|
|
21
|
+
* redelivered exactly once and a replayed event for it is still dropped.
|
|
22
|
+
*/
|
|
23
|
+
export class SubagentNotificationStore {
|
|
24
|
+
#pending = new Map();
|
|
25
|
+
#seen = new Set();
|
|
26
|
+
#tasks = new Map();
|
|
27
|
+
#settledTaskIds = new Set();
|
|
28
|
+
#now;
|
|
29
|
+
#deliveredIdCap;
|
|
30
|
+
#recentTaskRetentionMs;
|
|
31
|
+
constructor(deps = {}) {
|
|
32
|
+
this.#now = deps.now ?? Date.now;
|
|
33
|
+
this.#deliveredIdCap = Math.max(1, deps.deliveredIdCap ?? DEFAULT_DELIVERED_ID_CAP);
|
|
34
|
+
this.#recentTaskRetentionMs = Math.max(0, deps.recentTaskRetentionMs ?? BACKGROUND_TASK_RECENT_RETENTION_MS);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Updates the read-only task projection for async starts, tool activity, and
|
|
38
|
+
* completions. Only the newest tool call of a live run is kept: the overview
|
|
39
|
+
* answers "what is it doing now", not "what has it done".
|
|
40
|
+
*/
|
|
41
|
+
recordLifecycle(event) {
|
|
42
|
+
if (event.type === 'subagent_tool_started' || event.type === 'subagent_command_message') {
|
|
43
|
+
return this.#recordToolActivity(event);
|
|
44
|
+
}
|
|
45
|
+
if (event.type === 'subagent_started' && event.async === true) {
|
|
46
|
+
if (this.#settledTaskIds.has(event.agentId))
|
|
47
|
+
return false;
|
|
48
|
+
const existing = this.#tasks.get(event.agentId);
|
|
49
|
+
if (existing && existing.status !== 'running')
|
|
50
|
+
return false;
|
|
51
|
+
if (existing?.status === 'running' && existing.role === event.role && existing.task === event.task) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
this.#tasks.set(event.agentId, {
|
|
55
|
+
runId: event.agentId,
|
|
56
|
+
role: event.role,
|
|
57
|
+
task: event.task,
|
|
58
|
+
status: 'running',
|
|
59
|
+
startedAt: existing?.startedAt ?? this.#now(),
|
|
60
|
+
});
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (event.type !== 'subagent_completed' || event.async !== true)
|
|
64
|
+
return false;
|
|
65
|
+
const result = event.result;
|
|
66
|
+
if (!result?.agentId)
|
|
67
|
+
return false;
|
|
68
|
+
if (this.#settledTaskIds.has(result.agentId))
|
|
69
|
+
return false;
|
|
70
|
+
const existing = this.#tasks.get(result.agentId);
|
|
71
|
+
if (existing && existing.status !== 'running')
|
|
72
|
+
return false;
|
|
73
|
+
const completedAt = this.#now();
|
|
74
|
+
this.#tasks.set(result.agentId, {
|
|
75
|
+
runId: result.agentId,
|
|
76
|
+
role: existing?.role ?? result.role,
|
|
77
|
+
task: existing?.task ?? '',
|
|
78
|
+
status: result.status,
|
|
79
|
+
startedAt: existing?.startedAt ?? completedAt,
|
|
80
|
+
completedAt,
|
|
81
|
+
});
|
|
82
|
+
this.#settledTaskIds.add(result.agentId);
|
|
83
|
+
while (this.#settledTaskIds.size > this.#deliveredIdCap) {
|
|
84
|
+
const oldest = this.#settledTaskIds.values().next().value;
|
|
85
|
+
if (oldest === undefined)
|
|
86
|
+
break;
|
|
87
|
+
this.#settledTaskIds.delete(oldest);
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Projects the newest tool call of a live run. Tool events carry no `async`
|
|
93
|
+
* flag, so membership in the running task map is what scopes this to
|
|
94
|
+
* background runs — foreground and nested activity never registers a task.
|
|
95
|
+
*/
|
|
96
|
+
#recordToolActivity(event) {
|
|
97
|
+
const task = this.#tasks.get(event.agentId);
|
|
98
|
+
if (!task || task.status !== 'running')
|
|
99
|
+
return false;
|
|
100
|
+
const lastTool = event.type === 'subagent_tool_started'
|
|
101
|
+
? {
|
|
102
|
+
label: formatToolCommand(event.toolName, parseToolArguments(event.arguments)),
|
|
103
|
+
state: 'running',
|
|
104
|
+
}
|
|
105
|
+
: {
|
|
106
|
+
label: event.message?.command ?? '',
|
|
107
|
+
state: event.message?.success === false ? 'failed' : 'success',
|
|
108
|
+
};
|
|
109
|
+
if (!lastTool.label)
|
|
110
|
+
return false;
|
|
111
|
+
if (task.lastTool?.label === lastTool.label && task.lastTool.state === lastTool.state)
|
|
112
|
+
return false;
|
|
113
|
+
this.#tasks.set(event.agentId, { ...task, lastTool });
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
getTaskSnapshot() {
|
|
117
|
+
const now = this.#now();
|
|
118
|
+
for (const [runId, task] of this.#tasks) {
|
|
119
|
+
if (task.completedAt !== undefined && now - task.completedAt >= this.#recentTaskRetentionMs) {
|
|
120
|
+
this.#tasks.delete(runId);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return [...this.#tasks.values()];
|
|
124
|
+
}
|
|
125
|
+
/** Records one novel async completion or question, returning whether it woke the queue. */
|
|
126
|
+
enqueue(event) {
|
|
127
|
+
const notification = this.#notificationFor(event);
|
|
128
|
+
if (!notification || this.#seen.has(notification.messageId))
|
|
129
|
+
return false;
|
|
130
|
+
this.#pending.set(notification.messageId, notification);
|
|
131
|
+
this.#seen.add(notification.messageId);
|
|
132
|
+
this.#evictOldestSeen();
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
get pendingCount() {
|
|
136
|
+
return this.#pending.size;
|
|
137
|
+
}
|
|
138
|
+
/** Hands over every pending notification in completion order and clears them. */
|
|
139
|
+
drain() {
|
|
140
|
+
const drained = [...this.#pending.values()];
|
|
141
|
+
this.#pending.clear();
|
|
142
|
+
// Handing the batch over is the point at which old ids become evictable:
|
|
143
|
+
// nothing is owed a notification any more, only replay protection.
|
|
144
|
+
this.#evictOldestSeen();
|
|
145
|
+
return drained;
|
|
146
|
+
}
|
|
147
|
+
/** Returns undelivered notifications to the queue, ahead of anything newer. */
|
|
148
|
+
retain(notifications) {
|
|
149
|
+
if (notifications.length === 0)
|
|
150
|
+
return;
|
|
151
|
+
const newer = [...this.#pending.values()];
|
|
152
|
+
this.#pending.clear();
|
|
153
|
+
for (const notification of notifications) {
|
|
154
|
+
this.#pending.set(notification.messageId, notification);
|
|
155
|
+
this.#seen.add(notification.messageId);
|
|
156
|
+
}
|
|
157
|
+
for (const notification of newer)
|
|
158
|
+
this.#pending.set(notification.messageId, notification);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Drops the oldest remembered ids once the cap is exceeded, skipping runs that
|
|
162
|
+
* still owe a notification: correctness of an undelivered notification wins
|
|
163
|
+
* over the memory bound, and the pending queue is itself bounded by the number
|
|
164
|
+
* of runs the registry will retain. Forgetting an id only costs replay
|
|
165
|
+
* protection for a run that was delivered long ago.
|
|
166
|
+
*/
|
|
167
|
+
#evictOldestSeen() {
|
|
168
|
+
if (this.#seen.size <= this.#deliveredIdCap)
|
|
169
|
+
return;
|
|
170
|
+
for (const messageId of this.#seen) {
|
|
171
|
+
if (this.#seen.size <= this.#deliveredIdCap)
|
|
172
|
+
return;
|
|
173
|
+
if (this.#pending.has(messageId))
|
|
174
|
+
continue;
|
|
175
|
+
this.#seen.delete(messageId);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
#notificationFor(event) {
|
|
179
|
+
if (event.type === 'subagent_completed' && event.async === true) {
|
|
180
|
+
const result = event.result;
|
|
181
|
+
const runId = result?.agentId;
|
|
182
|
+
if (!result || !runId)
|
|
183
|
+
return undefined;
|
|
184
|
+
return {
|
|
185
|
+
kind: 'completion',
|
|
186
|
+
messageId: `completion:${runId}`,
|
|
187
|
+
runId,
|
|
188
|
+
role: result.role,
|
|
189
|
+
status: result.status,
|
|
190
|
+
preview: truncatePreview(result.finalText || result.error),
|
|
191
|
+
...(result.error ? { error: result.error } : {}),
|
|
192
|
+
completedAt: this.#now(),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (event.type === 'subagent_question' && event.async === true && event.messageId && event.runId) {
|
|
196
|
+
return {
|
|
197
|
+
kind: 'question',
|
|
198
|
+
messageId: event.messageId,
|
|
199
|
+
runId: event.runId,
|
|
200
|
+
...(event.name !== undefined ? { name: event.name } : {}),
|
|
201
|
+
role: event.role,
|
|
202
|
+
question: event.question,
|
|
203
|
+
askedAt: this.#now(),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=subagent-notification-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-notification-store.js","sourceRoot":"","sources":["../../../source/services/subagents/subagent-notification-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface SubagentRunControlOptions {
|
|
2
|
+
maxMailboxMessages?: number;
|
|
3
|
+
maxMailboxCharacters?: number;
|
|
4
|
+
maxContinuationSegments?: number;
|
|
5
|
+
createQuestionId?: () => string;
|
|
6
|
+
}
|
|
7
|
+
export interface PendingSubagentQuestion {
|
|
8
|
+
messageId: string;
|
|
9
|
+
question: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AskedSubagentQuestion extends PendingSubagentQuestion {
|
|
12
|
+
answer: Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Per-logical-run coordination state. The registry owns lifecycle and identity;
|
|
16
|
+
* runners receive only the narrow callbacks they need for a segment.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SubagentRunControl {
|
|
19
|
+
#private;
|
|
20
|
+
constructor(options?: SubagentRunControlOptions);
|
|
21
|
+
get currentSegmentController(): AbortController | undefined;
|
|
22
|
+
get activeToolCount(): number;
|
|
23
|
+
get cancellationRequested(): boolean;
|
|
24
|
+
get hasQueuedSteering(): boolean;
|
|
25
|
+
get currentSegmentAbortReason(): 'steer' | 'cancel' | undefined;
|
|
26
|
+
get continuationSegments(): number;
|
|
27
|
+
canStartContinuation(): boolean;
|
|
28
|
+
startContinuation(): boolean;
|
|
29
|
+
get pendingQuestion(): PendingSubagentQuestion | undefined;
|
|
30
|
+
beginSegment(): AbortController;
|
|
31
|
+
endSegment(controller: AbortController): void;
|
|
32
|
+
onToolStart(): void;
|
|
33
|
+
onToolComplete(): void;
|
|
34
|
+
enqueueSteering(message: string): void;
|
|
35
|
+
consumeSteering(): string | undefined;
|
|
36
|
+
ask(question: string): AskedSubagentQuestion;
|
|
37
|
+
answer(messageId: string, answer: string): boolean;
|
|
38
|
+
requestCancellation(): void;
|
|
39
|
+
settle(reason?: Error): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=subagent-run-control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-run-control.d.ts","sourceRoot":"","sources":["../../../source/services/subagents/subagent-run-control.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,yBAAyB;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB;AAOD;;;GAGG;AACH,qBAAa,kBAAkB;;IAgB7B,YAAY,OAAO,GAAE,yBAA8B,EAKlD;IAED,IAAI,wBAAwB,IAAI,eAAe,GAAG,SAAS,CAE1D;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAED,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED,IAAI,yBAAyB,IAAI,OAAO,GAAG,QAAQ,GAAG,SAAS,CAE9D;IAED,IAAI,oBAAoB,IAAI,MAAM,CAEjC;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,iBAAiB,IAAI,OAAO,CAI3B;IAED,IAAI,eAAe,IAAI,uBAAuB,GAAG,SAAS,CAEzD;IAED,YAAY,IAAI,eAAe,CAO9B;IAED,UAAU,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAM5C;IAED,WAAW,IAAI,IAAI,CAElB;IAED,cAAc,IAAI,IAAI,CAIrB;IAED,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAarC;IAED,eAAe,IAAI,MAAM,GAAG,SAAS,CAQpC;IAED,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAe3C;IAED,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAMjD;IAED,mBAAmB,IAAI,IAAI,CAO1B;IAED,MAAM,CAAC,MAAM,QAA+C,GAAG,IAAI,CAKlE;CAaF"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
const DEFAULT_MAX_MAILBOX_MESSAGES = 4;
|
|
3
|
+
const DEFAULT_MAX_MAILBOX_CHARACTERS = 4_000;
|
|
4
|
+
const DEFAULT_MAX_CONTINUATION_SEGMENTS = 3;
|
|
5
|
+
const MAX_QUESTION_CHARACTERS = 1_200;
|
|
6
|
+
const TRUNCATION_MARKER = '[Earlier steering omitted]';
|
|
7
|
+
/**
|
|
8
|
+
* Per-logical-run coordination state. The registry owns lifecycle and identity;
|
|
9
|
+
* runners receive only the narrow callbacks they need for a segment.
|
|
10
|
+
*/
|
|
11
|
+
export class SubagentRunControl {
|
|
12
|
+
#maxMailboxMessages;
|
|
13
|
+
#maxMailboxCharacters;
|
|
14
|
+
#maxContinuationSegments;
|
|
15
|
+
#createQuestionId;
|
|
16
|
+
#controller;
|
|
17
|
+
#abortReason;
|
|
18
|
+
#activeToolCount = 0;
|
|
19
|
+
#interruptWhenToolsIdle = false;
|
|
20
|
+
#cancellationRequested = false;
|
|
21
|
+
#mailbox = [];
|
|
22
|
+
#mailboxCharacters = 0;
|
|
23
|
+
#mailboxTruncated = false;
|
|
24
|
+
#continuationSegments = 0;
|
|
25
|
+
#question;
|
|
26
|
+
constructor(options = {}) {
|
|
27
|
+
this.#maxMailboxMessages = options.maxMailboxMessages ?? DEFAULT_MAX_MAILBOX_MESSAGES;
|
|
28
|
+
this.#maxMailboxCharacters = options.maxMailboxCharacters ?? DEFAULT_MAX_MAILBOX_CHARACTERS;
|
|
29
|
+
this.#maxContinuationSegments = options.maxContinuationSegments ?? DEFAULT_MAX_CONTINUATION_SEGMENTS;
|
|
30
|
+
this.#createQuestionId = options.createQuestionId ?? randomUUID;
|
|
31
|
+
}
|
|
32
|
+
get currentSegmentController() {
|
|
33
|
+
return this.#controller;
|
|
34
|
+
}
|
|
35
|
+
get activeToolCount() {
|
|
36
|
+
return this.#activeToolCount;
|
|
37
|
+
}
|
|
38
|
+
get cancellationRequested() {
|
|
39
|
+
return this.#cancellationRequested;
|
|
40
|
+
}
|
|
41
|
+
get hasQueuedSteering() {
|
|
42
|
+
return this.#mailbox.length > 0;
|
|
43
|
+
}
|
|
44
|
+
get currentSegmentAbortReason() {
|
|
45
|
+
return this.#abortReason;
|
|
46
|
+
}
|
|
47
|
+
get continuationSegments() {
|
|
48
|
+
return this.#continuationSegments;
|
|
49
|
+
}
|
|
50
|
+
canStartContinuation() {
|
|
51
|
+
return !this.#cancellationRequested && this.#continuationSegments < this.#maxContinuationSegments;
|
|
52
|
+
}
|
|
53
|
+
startContinuation() {
|
|
54
|
+
if (!this.canStartContinuation())
|
|
55
|
+
return false;
|
|
56
|
+
this.#continuationSegments++;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
get pendingQuestion() {
|
|
60
|
+
return this.#question && { messageId: this.#question.messageId, question: this.#question.question };
|
|
61
|
+
}
|
|
62
|
+
beginSegment() {
|
|
63
|
+
if (this.#controller)
|
|
64
|
+
throw new Error('A subagent segment is already active.');
|
|
65
|
+
const controller = new AbortController();
|
|
66
|
+
this.#controller = controller;
|
|
67
|
+
this.#abortReason = undefined;
|
|
68
|
+
if (this.#cancellationRequested)
|
|
69
|
+
this.#abortCurrentSegment('cancel');
|
|
70
|
+
return controller;
|
|
71
|
+
}
|
|
72
|
+
endSegment(controller) {
|
|
73
|
+
if (this.#controller !== controller)
|
|
74
|
+
return;
|
|
75
|
+
this.#controller = undefined;
|
|
76
|
+
this.#abortReason = undefined;
|
|
77
|
+
this.#activeToolCount = 0;
|
|
78
|
+
this.#interruptWhenToolsIdle = false;
|
|
79
|
+
}
|
|
80
|
+
onToolStart() {
|
|
81
|
+
this.#activeToolCount++;
|
|
82
|
+
}
|
|
83
|
+
onToolComplete() {
|
|
84
|
+
if (this.#activeToolCount === 0)
|
|
85
|
+
return;
|
|
86
|
+
this.#activeToolCount--;
|
|
87
|
+
if (this.#activeToolCount === 0 && this.#interruptWhenToolsIdle)
|
|
88
|
+
this.#abortCurrentSegment();
|
|
89
|
+
}
|
|
90
|
+
enqueueSteering(message) {
|
|
91
|
+
this.#mailbox.push(message);
|
|
92
|
+
this.#mailboxCharacters += message.length;
|
|
93
|
+
while (this.#mailbox.length > this.#maxMailboxMessages ||
|
|
94
|
+
(this.#mailbox.length > 1 && this.#mailboxCharacters > this.#maxMailboxCharacters)) {
|
|
95
|
+
const removed = this.#mailbox.shift();
|
|
96
|
+
this.#mailboxCharacters -= removed?.length ?? 0;
|
|
97
|
+
this.#mailboxTruncated = true;
|
|
98
|
+
}
|
|
99
|
+
this.#interruptWhenToolsIdle = true;
|
|
100
|
+
if (this.#activeToolCount === 0)
|
|
101
|
+
this.#abortCurrentSegment();
|
|
102
|
+
}
|
|
103
|
+
consumeSteering() {
|
|
104
|
+
if (this.#mailbox.length === 0)
|
|
105
|
+
return undefined;
|
|
106
|
+
const messages = this.#mailbox;
|
|
107
|
+
const truncated = this.#mailboxTruncated;
|
|
108
|
+
this.#mailbox = [];
|
|
109
|
+
this.#mailboxCharacters = 0;
|
|
110
|
+
this.#mailboxTruncated = false;
|
|
111
|
+
return [truncated ? TRUNCATION_MARKER : undefined, ...messages].filter(Boolean).join('\n');
|
|
112
|
+
}
|
|
113
|
+
ask(question) {
|
|
114
|
+
const boundedQuestion = question.trim();
|
|
115
|
+
if (boundedQuestion.length === 0)
|
|
116
|
+
throw new Error('A subagent question cannot be empty.');
|
|
117
|
+
if (boundedQuestion.length > MAX_QUESTION_CHARACTERS)
|
|
118
|
+
throw new Error(`Question exceeds ${MAX_QUESTION_CHARACTERS} characters.`);
|
|
119
|
+
if (this.#question)
|
|
120
|
+
throw new Error('A subagent question is already pending.');
|
|
121
|
+
let resolve;
|
|
122
|
+
let reject;
|
|
123
|
+
const answer = new Promise((resolveAnswer, rejectAnswer) => {
|
|
124
|
+
resolve = resolveAnswer;
|
|
125
|
+
reject = rejectAnswer;
|
|
126
|
+
});
|
|
127
|
+
const pending = { messageId: this.#createQuestionId(), question: boundedQuestion, resolve, reject };
|
|
128
|
+
this.#question = pending;
|
|
129
|
+
return { messageId: pending.messageId, question: boundedQuestion, answer };
|
|
130
|
+
}
|
|
131
|
+
answer(messageId, answer) {
|
|
132
|
+
if (!this.#question || this.#question.messageId !== messageId)
|
|
133
|
+
return false;
|
|
134
|
+
const pending = this.#question;
|
|
135
|
+
this.#question = undefined;
|
|
136
|
+
pending.resolve(answer);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
requestCancellation() {
|
|
140
|
+
this.#cancellationRequested = true;
|
|
141
|
+
this.#mailbox = [];
|
|
142
|
+
this.#mailboxCharacters = 0;
|
|
143
|
+
this.#mailboxTruncated = false;
|
|
144
|
+
this.#rejectPendingQuestion(new Error('The subagent run was cancelled.'));
|
|
145
|
+
this.#abortCurrentSegment('cancel');
|
|
146
|
+
}
|
|
147
|
+
settle(reason = new Error('The subagent run was cancelled.')) {
|
|
148
|
+
this.#mailbox = [];
|
|
149
|
+
this.#mailboxCharacters = 0;
|
|
150
|
+
this.#mailboxTruncated = false;
|
|
151
|
+
this.#rejectPendingQuestion(reason);
|
|
152
|
+
}
|
|
153
|
+
#rejectPendingQuestion(reason) {
|
|
154
|
+
if (!this.#question)
|
|
155
|
+
return;
|
|
156
|
+
const pending = this.#question;
|
|
157
|
+
this.#question = undefined;
|
|
158
|
+
pending.reject(reason);
|
|
159
|
+
}
|
|
160
|
+
#abortCurrentSegment(reason = 'steer') {
|
|
161
|
+
this.#abortReason = reason;
|
|
162
|
+
if (this.#controller && !this.#controller.signal.aborted)
|
|
163
|
+
this.#controller.abort();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=subagent-run-control.js.map
|