@fitchmultz/pi-subagents 0.0.0-stage → 0.44.5
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 +1654 -0
- package/LICENSE +21 -0
- package/README.md +1533 -2
- package/agents/context-builder.md +97 -0
- package/agents/debugger.md +51 -0
- package/agents/delegate.md +13 -0
- package/agents/fixer.md +37 -0
- package/agents/oracle.md +71 -0
- package/agents/planner.md +72 -0
- package/agents/researcher.md +51 -0
- package/agents/reviewer-claude.md +69 -0
- package/agents/reviewer-gpt.md +68 -0
- package/agents/reviewer-ponytail.md +82 -0
- package/agents/reviewer-security.md +81 -0
- package/agents/reviewer.md +69 -0
- package/agents/scout.md +66 -0
- package/agents/ui-designer.md +51 -0
- package/agents/watcher.md +26 -0
- package/agents/worker.md +46 -0
- package/agents/writer.md +36 -0
- package/dist/agents/agent-management.js +923 -0
- package/dist/agents/agent-scope.js +7 -0
- package/dist/agents/agent-selection.js +20 -0
- package/dist/agents/agent-serializer.js +100 -0
- package/dist/agents/agents.js +752 -0
- package/dist/agents/chain-serializer.js +367 -0
- package/dist/agents/frontmatter.js +21 -0
- package/dist/agents/identity.js +29 -0
- package/dist/agents/skills.js +570 -0
- package/dist/extension/build-info.js +1 -0
- package/dist/extension/compact-tools.js +112 -0
- package/dist/extension/config.js +22 -0
- package/dist/extension/control-notices.js +29 -0
- package/dist/extension/doctor.js +143 -0
- package/dist/extension/fanout-child.js +326 -0
- package/dist/extension/index.js +577 -0
- package/dist/extension/schemas.js +416 -0
- package/dist/extension/tool-input.js +20 -0
- package/dist/extension/tool-result.js +14 -0
- package/dist/history/canonical-result.js +81 -0
- package/dist/history/database.js +72 -0
- package/dist/history/index.js +199 -0
- package/dist/history/ingest.js +468 -0
- package/dist/history/queries.js +350 -0
- package/dist/history/store.js +216 -0
- package/dist/history/types.js +4 -0
- package/dist/history/worker.js +466 -0
- package/dist/intercom/intercom-bridge.js +112 -0
- package/dist/intercom/live-intercom.js +94 -0
- package/dist/intercom/result-intercom.js +373 -0
- package/dist/pi-intercom/agent-dir.js +10 -0
- package/dist/pi-intercom/bridge.js +750 -0
- package/dist/pi-intercom/broker/broker.js +426 -0
- package/dist/pi-intercom/broker/client.js +492 -0
- package/dist/pi-intercom/broker/framing.js +65 -0
- package/dist/pi-intercom/broker/paths.js +42 -0
- package/dist/pi-intercom/broker/pid.js +66 -0
- package/dist/pi-intercom/broker/spawn.js +221 -0
- package/dist/pi-intercom/config.js +102 -0
- package/dist/pi-intercom/index.js +2942 -0
- package/dist/pi-intercom/reply-tracker.js +182 -0
- package/dist/pi-intercom/session-targets.js +128 -0
- package/dist/pi-intercom/subagent-live-events.js +132 -0
- package/dist/pi-intercom/topics.js +157 -0
- package/dist/pi-intercom/types.js +163 -0
- package/dist/pi-intercom/ui/compose.js +269 -0
- package/dist/pi-intercom/ui/inline-message.js +80 -0
- package/dist/pi-intercom/ui/session-list.js +124 -0
- package/dist/runs/background/async-control.js +95 -0
- package/dist/runs/background/async-execution.js +676 -0
- package/dist/runs/background/async-job-tracker.js +383 -0
- package/dist/runs/background/async-result-file.js +58 -0
- package/dist/runs/background/async-resume.js +305 -0
- package/dist/runs/background/async-status.js +442 -0
- package/dist/runs/background/completion-dedupe.js +69 -0
- package/dist/runs/background/completion-delivery.js +245 -0
- package/dist/runs/background/notify.js +71 -0
- package/dist/runs/background/parallel-groups.js +55 -0
- package/dist/runs/background/result-watcher.js +426 -0
- package/dist/runs/background/run-id-resolver.js +64 -0
- package/dist/runs/background/run-status.js +382 -0
- package/dist/runs/background/stale-run-reconciler.js +335 -0
- package/dist/runs/background/subagent-runner-launcher.js +55 -0
- package/dist/runs/background/subagent-runner.js +1872 -0
- package/dist/runs/background/top-level-async.js +5 -0
- package/dist/runs/foreground/chain-clarify.js +1152 -0
- package/dist/runs/foreground/clarify-invocation.js +72 -0
- package/dist/runs/foreground/execution-input.js +423 -0
- package/dist/runs/foreground/foreground-control.js +817 -0
- package/dist/runs/foreground/question-control.js +88 -0
- package/dist/runs/foreground/run-async-path.js +205 -0
- package/dist/runs/foreground/subagent-executor.js +442 -0
- package/dist/runs/foreground/subagent-params.js +165 -0
- package/dist/runs/foreground/wait-run.js +141 -0
- package/dist/runs/shared/acceptance-contract.js +253 -0
- package/dist/runs/shared/acceptance-evaluation.js +256 -0
- package/dist/runs/shared/acceptance-finalization.js +280 -0
- package/dist/runs/shared/acceptance-reports.js +147 -0
- package/dist/runs/shared/acceptance.js +4 -0
- package/dist/runs/shared/chain-outputs.js +110 -0
- package/dist/runs/shared/child-attempt.js +693 -0
- package/dist/runs/shared/child-execution-cwd.js +96 -0
- package/dist/runs/shared/child-observations.js +114 -0
- package/dist/runs/shared/claude-code.js +199 -0
- package/dist/runs/shared/completion-guard.js +31 -0
- package/dist/runs/shared/dynamic-fanout.js +274 -0
- package/dist/runs/shared/history-index.js +72 -0
- package/dist/runs/shared/mcp-direct-tool-allowlist.js +334 -0
- package/dist/runs/shared/model-fallback.js +185 -0
- package/dist/runs/shared/mutating-tool-guard.js +170 -0
- package/dist/runs/shared/native-finalization.js +101 -0
- package/dist/runs/shared/native-usage.js +153 -0
- package/dist/runs/shared/nested-events.js +700 -0
- package/dist/runs/shared/nested-path.js +48 -0
- package/dist/runs/shared/nested-render.js +108 -0
- package/dist/runs/shared/parallel-utils.js +61 -0
- package/dist/runs/shared/parent-receipts.js +68 -0
- package/dist/runs/shared/parent-usage.js +121 -0
- package/dist/runs/shared/pi-args.js +310 -0
- package/dist/runs/shared/pi-spawn.js +52 -0
- package/dist/runs/shared/run-history-queries.js +45 -0
- package/dist/runs/shared/run-history.js +110 -0
- package/dist/runs/shared/run-id-ambiguity.js +4 -0
- package/dist/runs/shared/run-records.js +679 -0
- package/dist/runs/shared/session-cwd-preload.js +33 -0
- package/dist/runs/shared/single-output.js +222 -0
- package/dist/runs/shared/streaming-text.js +15 -0
- package/dist/runs/shared/structured-output.js +55 -0
- package/dist/runs/shared/subagent-control.js +179 -0
- package/dist/runs/shared/subagent-prompt-runtime.js +197 -0
- package/dist/runs/shared/subagent-tool-loop-guard.js +66 -0
- package/dist/runs/shared/supervisor-questions.js +350 -0
- package/dist/runs/shared/workflow-graph.js +214 -0
- package/dist/runs/shared/workflow-policy.js +84 -0
- package/dist/runs/shared/worktree.js +525 -0
- package/dist/shared/agent-context-policy.js +126 -0
- package/dist/shared/artifacts.js +96 -0
- package/dist/shared/atomic-json.js +13 -0
- package/dist/shared/cooperative.js +20 -0
- package/dist/shared/execution-cwd.js +14 -0
- package/dist/shared/file-coalescer.js +21 -0
- package/dist/shared/fork-context.js +49 -0
- package/dist/shared/formatters.js +85 -0
- package/dist/shared/journal-reader.js +407 -0
- package/dist/shared/lazy-tools.js +32 -0
- package/dist/shared/model-info.js +68 -0
- package/dist/shared/native-session.js +15 -0
- package/dist/shared/native-tui.js +18 -0
- package/dist/shared/native-typebox.js +20 -0
- package/dist/shared/post-exit-stdio-guard.js +197 -0
- package/dist/shared/prompt-sections.js +8 -0
- package/dist/shared/session-entries.js +52 -0
- package/dist/shared/session-identity.js +14 -0
- package/dist/shared/settings.js +254 -0
- package/dist/shared/status-format.js +111 -0
- package/dist/shared/temp-root.js +114 -0
- package/dist/shared/types.js +207 -0
- package/dist/shared/ui-mode.js +3 -0
- package/dist/shared/utils.js +334 -0
- package/dist/slash/prompt-template-bridge.js +298 -0
- package/dist/slash/slash-bridge.js +116 -0
- package/dist/slash/slash-commands.js +607 -0
- package/dist/slash/slash-live-state.js +246 -0
- package/dist/tui/action-hints.js +75 -0
- package/dist/tui/agent-history.js +197 -0
- package/dist/tui/agent-view.js +1656 -0
- package/dist/tui/render.js +1515 -0
- package/docs/intercom-bridge.md +212 -0
- package/docs/intercom.md +581 -0
- package/docs/performance.md +121 -0
- package/package.json +102 -4
- package/prompts/gather-context-and-clarify.md +14 -0
- package/prompts/parallel-cleanup.md +62 -0
- package/prompts/parallel-context-build.md +56 -0
- package/prompts/parallel-handoff-plan.md +62 -0
- package/prompts/parallel-research.md +51 -0
- package/prompts/parallel-review.md +59 -0
- package/prompts/review-loop.md +42 -0
- package/scripts/build.mjs +134 -0
- package/scripts/check-compat.mjs +48 -0
- package/scripts/compat-host.mjs +19 -0
- package/scripts/intercom-bridge-credentials.mjs +143 -0
- package/scripts/intercom-remote.mjs +103 -0
- package/scripts/linux-smoke.sh +51 -0
- package/scripts/local-install-smoke.mjs +66 -0
- package/scripts/native-package-smoke.mjs +82 -0
- package/scripts/package-smoke.mjs +209 -0
- package/scripts/prepare.mjs +67 -0
- package/scripts/real-pi-smoke.mjs +415 -0
- package/scripts/run-tests.mjs +149 -0
- package/skills/pi-intercom/SKILL.md +113 -0
- package/skills/pi-intercom/evals/evals.json +29 -0
- package/skills/pi-intercom/evals/trigger-evals.json +47 -0
- package/skills/pi-intercom/references/peer-sessions.md +69 -0
- package/skills/pi-subagents/SKILL.md +76 -0
- package/skills/pi-subagents/evals/evals.json +29 -0
- package/skills/pi-subagents/evals/trigger-evals.json +42 -0
- package/skills/pi-subagents/references/full-orchestration-guide.md +863 -0
- package/src/agents/agent-management.ts +813 -0
- package/src/agents/agent-scope.ts +7 -0
- package/src/agents/agent-selection.ts +23 -0
- package/src/agents/agent-serializer.ts +99 -0
- package/src/agents/agents.ts +916 -0
- package/src/agents/chain-serializer.ts +329 -0
- package/src/agents/frontmatter.ts +21 -0
- package/src/agents/identity.ts +30 -0
- package/src/agents/skills.ts +637 -0
- package/src/extension/build-info.ts +2 -0
- package/src/extension/compact-tools.ts +114 -0
- package/src/extension/config.ts +23 -0
- package/src/extension/control-notices.ts +47 -0
- package/src/extension/doctor.ts +171 -0
- package/src/extension/fanout-child.ts +312 -0
- package/src/extension/index.ts +649 -0
- package/src/extension/schemas.ts +444 -0
- package/src/extension/tool-input.ts +19 -0
- package/src/extension/tool-result.ts +16 -0
- package/src/history/canonical-result.ts +62 -0
- package/src/history/database.ts +59 -0
- package/src/history/index.ts +156 -0
- package/src/history/ingest.ts +349 -0
- package/src/history/queries.ts +241 -0
- package/src/history/store.ts +203 -0
- package/src/history/types.ts +166 -0
- package/src/history/worker.ts +321 -0
- package/src/intercom/intercom-bridge.ts +123 -0
- package/src/intercom/live-intercom.ts +104 -0
- package/src/intercom/result-intercom.ts +429 -0
- package/src/pi-intercom/agent-dir.ts +9 -0
- package/src/pi-intercom/bridge.ts +668 -0
- package/src/pi-intercom/broker/broker.ts +463 -0
- package/src/pi-intercom/broker/client.ts +558 -0
- package/src/pi-intercom/broker/framing.ts +77 -0
- package/src/pi-intercom/broker/paths.ts +47 -0
- package/src/pi-intercom/broker/pid.ts +59 -0
- package/src/pi-intercom/broker/spawn.ts +248 -0
- package/src/pi-intercom/config.ts +142 -0
- package/src/pi-intercom/index.ts +2929 -0
- package/src/pi-intercom/reply-tracker.ts +211 -0
- package/src/pi-intercom/session-targets.ts +172 -0
- package/src/pi-intercom/subagent-live-events.ts +133 -0
- package/src/pi-intercom/topics.ts +125 -0
- package/src/pi-intercom/types.ts +271 -0
- package/src/pi-intercom/ui/compose.ts +289 -0
- package/src/pi-intercom/ui/inline-message.ts +92 -0
- package/src/pi-intercom/ui/session-list.ts +139 -0
- package/src/runs/background/async-control.ts +89 -0
- package/src/runs/background/async-execution.ts +850 -0
- package/src/runs/background/async-job-tracker.ts +385 -0
- package/src/runs/background/async-result-file.ts +62 -0
- package/src/runs/background/async-resume.ts +333 -0
- package/src/runs/background/async-status.ts +481 -0
- package/src/runs/background/completion-dedupe.ts +79 -0
- package/src/runs/background/completion-delivery.ts +195 -0
- package/src/runs/background/notify.ts +123 -0
- package/src/runs/background/parallel-groups.ts +53 -0
- package/src/runs/background/result-watcher.ts +423 -0
- package/src/runs/background/run-id-resolver.ts +69 -0
- package/src/runs/background/run-status.ts +384 -0
- package/src/runs/background/stale-run-reconciler.ts +369 -0
- package/src/runs/background/subagent-runner-launcher.ts +56 -0
- package/src/runs/background/subagent-runner.ts +2053 -0
- package/src/runs/background/top-level-async.ts +13 -0
- package/src/runs/foreground/chain-clarify.ts +1340 -0
- package/src/runs/foreground/clarify-invocation.ts +77 -0
- package/src/runs/foreground/execution-input.ts +467 -0
- package/src/runs/foreground/foreground-control.ts +821 -0
- package/src/runs/foreground/question-control.ts +82 -0
- package/src/runs/foreground/run-async-path.ts +243 -0
- package/src/runs/foreground/subagent-executor.ts +501 -0
- package/src/runs/foreground/subagent-params.ts +320 -0
- package/src/runs/foreground/wait-run.ts +124 -0
- package/src/runs/shared/acceptance-contract.ts +257 -0
- package/src/runs/shared/acceptance-evaluation.ts +275 -0
- package/src/runs/shared/acceptance-finalization.ts +353 -0
- package/src/runs/shared/acceptance-reports.ts +152 -0
- package/src/runs/shared/acceptance.ts +33 -0
- package/src/runs/shared/chain-outputs.ts +114 -0
- package/src/runs/shared/child-attempt.ts +623 -0
- package/src/runs/shared/child-execution-cwd.ts +91 -0
- package/src/runs/shared/child-observations.ts +99 -0
- package/src/runs/shared/claude-code.ts +243 -0
- package/src/runs/shared/completion-guard.ts +35 -0
- package/src/runs/shared/dynamic-fanout.ts +295 -0
- package/src/runs/shared/history-index.ts +69 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +376 -0
- package/src/runs/shared/model-fallback.ts +219 -0
- package/src/runs/shared/mutating-tool-guard.ts +194 -0
- package/src/runs/shared/native-finalization.ts +128 -0
- package/src/runs/shared/native-usage.ts +113 -0
- package/src/runs/shared/nested-events.ts +752 -0
- package/src/runs/shared/nested-path.ts +52 -0
- package/src/runs/shared/nested-render.ts +119 -0
- package/src/runs/shared/parallel-utils.ts +153 -0
- package/src/runs/shared/parent-receipts.ts +59 -0
- package/src/runs/shared/parent-usage.ts +121 -0
- package/src/runs/shared/pi-args.ts +350 -0
- package/src/runs/shared/pi-spawn.ts +52 -0
- package/src/runs/shared/run-history-queries.ts +44 -0
- package/src/runs/shared/run-history.ts +100 -0
- package/src/runs/shared/run-id-ambiguity.ts +4 -0
- package/src/runs/shared/run-records.ts +607 -0
- package/src/runs/shared/session-cwd-preload.ts +27 -0
- package/src/runs/shared/single-output.ts +267 -0
- package/src/runs/shared/streaming-text.ts +18 -0
- package/src/runs/shared/structured-output.ts +68 -0
- package/src/runs/shared/subagent-control.ts +219 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +201 -0
- package/src/runs/shared/subagent-tool-loop-guard.ts +89 -0
- package/src/runs/shared/supervisor-questions.ts +415 -0
- package/src/runs/shared/workflow-graph.ts +220 -0
- package/src/runs/shared/workflow-policy.ts +125 -0
- package/src/runs/shared/worktree.ts +635 -0
- package/src/shared/agent-context-policy.ts +184 -0
- package/src/shared/artifacts.ts +95 -0
- package/src/shared/atomic-json.ts +16 -0
- package/src/shared/cooperative.ts +21 -0
- package/src/shared/execution-cwd.ts +14 -0
- package/src/shared/file-coalescer.ts +29 -0
- package/src/shared/fork-context.ts +68 -0
- package/src/shared/formatters.ts +84 -0
- package/src/shared/journal-reader.ts +333 -0
- package/src/shared/lazy-tools.ts +36 -0
- package/src/shared/model-info.ts +81 -0
- package/src/shared/native-session.ts +8 -0
- package/src/shared/native-tui.ts +10 -0
- package/src/shared/native-typebox.ts +14 -0
- package/src/shared/post-exit-stdio-guard.ts +204 -0
- package/src/shared/prompt-sections.ts +10 -0
- package/src/shared/session-entries.ts +49 -0
- package/src/shared/session-identity.ts +18 -0
- package/src/shared/settings.ts +384 -0
- package/src/shared/status-format.ts +123 -0
- package/src/shared/temp-root.ts +107 -0
- package/src/shared/types.ts +1260 -0
- package/src/shared/ui-mode.ts +5 -0
- package/src/shared/utils.ts +342 -0
- package/src/slash/prompt-template-bridge.ts +408 -0
- package/src/slash/slash-bridge.ts +178 -0
- package/src/slash/slash-commands.ts +617 -0
- package/src/slash/slash-live-state.ts +292 -0
- package/src/tui/action-hints.ts +69 -0
- package/src/tui/agent-history.ts +210 -0
- package/src/tui/agent-view.ts +1323 -0
- package/src/tui/render.ts +1550 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type AgentConfig, type AgentDiscoveryOptions, type AgentScope } from "../../agents/agents.ts";
|
|
3
|
+
import { materializeAgentDefaultOutputPath, normalizeSingleOutputOverride } from "../shared/single-output.ts";
|
|
4
|
+
import type { IntercomBridgeState } from "../../intercom/intercom-bridge.ts";
|
|
5
|
+
import {
|
|
6
|
+
type ChainStep,
|
|
7
|
+
type DynamicParallelStep,
|
|
8
|
+
type ParallelStep,
|
|
9
|
+
type SequentialStep,
|
|
10
|
+
} from "../../shared/settings.ts";
|
|
11
|
+
import {
|
|
12
|
+
type AcceptanceInput,
|
|
13
|
+
type ControlConfig,
|
|
14
|
+
type ExtensionConfig,
|
|
15
|
+
type JsonSchemaObject,
|
|
16
|
+
type MaxOutputConfig,
|
|
17
|
+
type ManagementRunState,
|
|
18
|
+
type NestedRouteInfo,
|
|
19
|
+
type ResolvedControlConfig,
|
|
20
|
+
type SingleResult,
|
|
21
|
+
type SubagentExecutionResult,
|
|
22
|
+
type SubagentRunMode,
|
|
23
|
+
type SubagentState,
|
|
24
|
+
} from "../../shared/types.ts";
|
|
25
|
+
|
|
26
|
+
export function maxParallelTasksMessage(maxParallelTasks: number): string {
|
|
27
|
+
return `Max ${maxParallelTasks} tasks. Split the batch into smaller parallel calls or raise parallel.maxTasks in ~/.pi/agent/extensions/subagent/config.json.`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TaskParam {
|
|
31
|
+
agent: string;
|
|
32
|
+
task: string;
|
|
33
|
+
label?: string;
|
|
34
|
+
cwd?: string;
|
|
35
|
+
count?: number;
|
|
36
|
+
outputSchema?: JsonSchemaObject;
|
|
37
|
+
output?: string | boolean;
|
|
38
|
+
outputMode?: "inline" | "file-only";
|
|
39
|
+
reads?: string[] | boolean;
|
|
40
|
+
progress?: boolean;
|
|
41
|
+
model?: string;
|
|
42
|
+
skill?: string | string[] | boolean;
|
|
43
|
+
acceptance?: AcceptanceInput;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
47
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isTaskParamLike(value: unknown): value is TaskParam {
|
|
51
|
+
return isRecord(value) && typeof value.agent === "string";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isDynamicParallelStepLike(value: unknown): value is DynamicParallelStep {
|
|
55
|
+
return isRecord(value)
|
|
56
|
+
&& isRecord(value.expand)
|
|
57
|
+
&& isRecord(value.parallel)
|
|
58
|
+
&& typeof value.parallel.agent === "string"
|
|
59
|
+
&& isRecord(value.collect)
|
|
60
|
+
&& typeof value.collect.as === "string";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isParallelStepLike(value: unknown): value is ParallelStep {
|
|
64
|
+
return isRecord(value) && Array.isArray(value.parallel) && value.parallel.every(isTaskParamLike);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isSequentialStepLike(value: unknown): value is SequentialStep {
|
|
68
|
+
return isRecord(value) && typeof value.agent === "string";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isChainStepLike(value: unknown): value is ChainStep {
|
|
72
|
+
if (!isRecord(value)) return false;
|
|
73
|
+
return isDynamicParallelStepLike(value) || isParallelStepLike(value) || isSequentialStepLike(value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SubagentParamsLike {
|
|
77
|
+
action?: string;
|
|
78
|
+
id?: string;
|
|
79
|
+
runId?: string;
|
|
80
|
+
questionId?: string;
|
|
81
|
+
decision?: "accepted" | "needs_changes";
|
|
82
|
+
offset?: number;
|
|
83
|
+
limit?: number;
|
|
84
|
+
cursor?: string;
|
|
85
|
+
sort?: "attention" | "newest" | "oldest" | "relevance";
|
|
86
|
+
state?: ManagementRunState;
|
|
87
|
+
text?: string;
|
|
88
|
+
query?: string;
|
|
89
|
+
before?: number;
|
|
90
|
+
full?: boolean;
|
|
91
|
+
dir?: string;
|
|
92
|
+
index?: number;
|
|
93
|
+
agent?: string;
|
|
94
|
+
task?: string;
|
|
95
|
+
label?: string;
|
|
96
|
+
message?: string;
|
|
97
|
+
/** Internal human-view provenance; not accepted by the model tool schema. */
|
|
98
|
+
messageOrigin?: "human";
|
|
99
|
+
chain?: ChainStep[];
|
|
100
|
+
tasks?: TaskParam[];
|
|
101
|
+
concurrency?: number;
|
|
102
|
+
timeoutMs?: number;
|
|
103
|
+
maxRuntimeMs?: number;
|
|
104
|
+
extendMs?: number;
|
|
105
|
+
worktree?: boolean;
|
|
106
|
+
context?: "fresh" | "fork";
|
|
107
|
+
async?: boolean;
|
|
108
|
+
clarify?: boolean;
|
|
109
|
+
share?: boolean;
|
|
110
|
+
control?: ControlConfig;
|
|
111
|
+
sessionDir?: string;
|
|
112
|
+
cwd?: string;
|
|
113
|
+
maxOutput?: MaxOutputConfig;
|
|
114
|
+
artifacts?: boolean;
|
|
115
|
+
includeProgress?: boolean;
|
|
116
|
+
progress?: boolean;
|
|
117
|
+
model?: string;
|
|
118
|
+
skill?: string | string[] | boolean;
|
|
119
|
+
output?: string | boolean;
|
|
120
|
+
outputMode?: "inline" | "file-only";
|
|
121
|
+
outputSchema?: JsonSchemaObject;
|
|
122
|
+
agentScope?: string;
|
|
123
|
+
chainName?: string;
|
|
124
|
+
config?: unknown;
|
|
125
|
+
chainDir?: string;
|
|
126
|
+
acceptance?: AcceptanceInput;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function resolveAsyncExecutionMode(
|
|
130
|
+
params: Pick<SubagentParamsLike, "async" | "clarify" | "timeoutMs" | "maxRuntimeMs">,
|
|
131
|
+
asyncByDefault: boolean,
|
|
132
|
+
): { effectiveAsync: boolean; backgroundRequestedWhileClarifying: boolean } {
|
|
133
|
+
const hasForegroundTimeout = params.timeoutMs !== undefined || params.maxRuntimeMs !== undefined;
|
|
134
|
+
const requestedAsync = params.async ?? (hasForegroundTimeout ? false : asyncByDefault);
|
|
135
|
+
return {
|
|
136
|
+
effectiveAsync: requestedAsync && params.clarify !== true,
|
|
137
|
+
backgroundRequestedWhileClarifying: params.async === true && params.clarify === true,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
type RawSubagentParamsLike = Record<string, unknown>;
|
|
142
|
+
|
|
143
|
+
function stringValue(params: RawSubagentParamsLike, key: string): string | undefined {
|
|
144
|
+
const value = params[key];
|
|
145
|
+
return typeof value === "string" ? value : undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function booleanValue(params: RawSubagentParamsLike, key: string): boolean | undefined {
|
|
149
|
+
const value = params[key];
|
|
150
|
+
return typeof value === "boolean" ? value : undefined;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function numberValue(params: RawSubagentParamsLike, key: string): number | undefined {
|
|
154
|
+
const value = params[key];
|
|
155
|
+
return typeof value === "number" ? value : undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function contextValue(params: RawSubagentParamsLike): SubagentParamsLike["context"] {
|
|
159
|
+
const value = params.context;
|
|
160
|
+
return value === "fresh" || value === "fork" ? value : undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function outputModeValue(params: RawSubagentParamsLike): SubagentParamsLike["outputMode"] {
|
|
164
|
+
const value = params.outputMode;
|
|
165
|
+
return value === "inline" || value === "file-only" ? value : undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function outputValue(params: RawSubagentParamsLike): SubagentParamsLike["output"] {
|
|
169
|
+
const value = params.output;
|
|
170
|
+
return typeof value === "string" || typeof value === "boolean" ? value : undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function usesAgentDefaultOutput(output: string | boolean | undefined): boolean {
|
|
174
|
+
return output === undefined || output === true || output === "true";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function resolveTopLevelOutputOverride(params: {
|
|
178
|
+
requestedOutput: string | boolean | undefined;
|
|
179
|
+
agentDefaultOutput: string | false | undefined;
|
|
180
|
+
artifactsDir: string;
|
|
181
|
+
runId: string;
|
|
182
|
+
agent: string;
|
|
183
|
+
index?: number;
|
|
184
|
+
}): string | false | undefined {
|
|
185
|
+
const effectiveOutput = usesAgentDefaultOutput(params.requestedOutput)
|
|
186
|
+
? normalizeSingleOutputOverride(true, params.agentDefaultOutput)
|
|
187
|
+
: normalizeSingleOutputOverride(params.requestedOutput, params.agentDefaultOutput);
|
|
188
|
+
if (!usesAgentDefaultOutput(params.requestedOutput)) return effectiveOutput;
|
|
189
|
+
return materializeAgentDefaultOutputPath({
|
|
190
|
+
output: effectiveOutput,
|
|
191
|
+
artifactsDir: params.artifactsDir,
|
|
192
|
+
runId: params.runId,
|
|
193
|
+
agent: params.agent,
|
|
194
|
+
index: params.index,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function skillValue(params: RawSubagentParamsLike): SubagentParamsLike["skill"] {
|
|
199
|
+
const value = params.skill;
|
|
200
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
201
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function maxOutputValue(params: RawSubagentParamsLike): MaxOutputConfig | undefined {
|
|
205
|
+
const value = params.maxOutput;
|
|
206
|
+
if (!isRecord(value)) return undefined;
|
|
207
|
+
return {
|
|
208
|
+
...(typeof value.bytes === "number" ? { bytes: value.bytes } : {}),
|
|
209
|
+
...(typeof value.lines === "number" ? { lines: value.lines } : {}),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isControlConfig(value: unknown): value is ControlConfig {
|
|
214
|
+
return isRecord(value);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isAcceptanceInput(value: unknown): value is AcceptanceInput {
|
|
218
|
+
return isRecord(value);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function normalizeSubagentParamsLike(params: RawSubagentParamsLike): SubagentParamsLike {
|
|
222
|
+
const normalized: SubagentParamsLike = {
|
|
223
|
+
action: stringValue(params, "action"),
|
|
224
|
+
id: stringValue(params, "id"),
|
|
225
|
+
runId: stringValue(params, "runId"),
|
|
226
|
+
questionId: stringValue(params, "questionId"),
|
|
227
|
+
decision: params.decision === "accepted" || params.decision === "needs_changes" ? params.decision : undefined,
|
|
228
|
+
offset: numberValue(params, "offset"),
|
|
229
|
+
limit: numberValue(params, "limit"),
|
|
230
|
+
cursor: stringValue(params, "cursor"),
|
|
231
|
+
sort: ["attention", "newest", "oldest", "relevance"].includes(String(params.sort)) ? params.sort as SubagentParamsLike["sort"] : undefined,
|
|
232
|
+
state: ["live", "completed", "failed", "blocked", "paused", "unknown"].includes(String(params.state)) ? params.state as ManagementRunState : undefined,
|
|
233
|
+
text: stringValue(params, "text"),
|
|
234
|
+
query: stringValue(params, "query"),
|
|
235
|
+
before: numberValue(params, "before"),
|
|
236
|
+
full: booleanValue(params, "full"),
|
|
237
|
+
dir: stringValue(params, "dir"),
|
|
238
|
+
index: numberValue(params, "index"),
|
|
239
|
+
agent: stringValue(params, "agent"),
|
|
240
|
+
task: stringValue(params, "task"),
|
|
241
|
+
label: stringValue(params, "label"),
|
|
242
|
+
message: stringValue(params, "message"),
|
|
243
|
+
concurrency: numberValue(params, "concurrency"),
|
|
244
|
+
timeoutMs: numberValue(params, "timeoutMs"),
|
|
245
|
+
maxRuntimeMs: numberValue(params, "maxRuntimeMs"),
|
|
246
|
+
extendMs: numberValue(params, "extendMs"),
|
|
247
|
+
worktree: booleanValue(params, "worktree"),
|
|
248
|
+
context: contextValue(params),
|
|
249
|
+
async: booleanValue(params, "async"),
|
|
250
|
+
clarify: booleanValue(params, "clarify"),
|
|
251
|
+
share: booleanValue(params, "share"),
|
|
252
|
+
control: isControlConfig(params.control) ? params.control : undefined,
|
|
253
|
+
sessionDir: stringValue(params, "sessionDir"),
|
|
254
|
+
cwd: stringValue(params, "cwd"),
|
|
255
|
+
maxOutput: maxOutputValue(params),
|
|
256
|
+
artifacts: booleanValue(params, "artifacts"),
|
|
257
|
+
includeProgress: booleanValue(params, "includeProgress"),
|
|
258
|
+
progress: booleanValue(params, "progress"),
|
|
259
|
+
model: stringValue(params, "model"),
|
|
260
|
+
skill: skillValue(params),
|
|
261
|
+
output: outputValue(params),
|
|
262
|
+
outputMode: outputModeValue(params),
|
|
263
|
+
outputSchema: isRecord(params.outputSchema) ? params.outputSchema : undefined,
|
|
264
|
+
agentScope: stringValue(params, "agentScope"),
|
|
265
|
+
chainName: stringValue(params, "chainName"),
|
|
266
|
+
config: params.config,
|
|
267
|
+
chainDir: stringValue(params, "chainDir"),
|
|
268
|
+
acceptance: isAcceptanceInput(params.acceptance) ? params.acceptance : undefined,
|
|
269
|
+
};
|
|
270
|
+
if (params.tasks !== undefined) {
|
|
271
|
+
if (!Array.isArray(params.tasks) || !params.tasks.every(isTaskParamLike)) {
|
|
272
|
+
throw new Error("tasks must be an array of task objects with an agent.");
|
|
273
|
+
}
|
|
274
|
+
normalized.tasks = params.tasks;
|
|
275
|
+
}
|
|
276
|
+
if (params.chain !== undefined) {
|
|
277
|
+
if (!Array.isArray(params.chain) || !params.chain.every(isChainStepLike)) {
|
|
278
|
+
throw new Error("chain must contain valid sequential, parallel, or dynamic fanout steps.");
|
|
279
|
+
}
|
|
280
|
+
normalized.chain = params.chain;
|
|
281
|
+
}
|
|
282
|
+
return normalized;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface ExecutorDeps {
|
|
286
|
+
pi: ExtensionAPI;
|
|
287
|
+
state: SubagentState;
|
|
288
|
+
config: ExtensionConfig;
|
|
289
|
+
asyncByDefault: boolean;
|
|
290
|
+
tempArtifactsDir: string;
|
|
291
|
+
getSubagentSessionRoot: (parentSessionFile: string | null) => string;
|
|
292
|
+
expandTilde: (p: string) => string;
|
|
293
|
+
discoverAgents: (cwd: string, scope: AgentScope, options?: AgentDiscoveryOptions) => { agents: AgentConfig[] };
|
|
294
|
+
allowMutatingManagementActions?: boolean;
|
|
295
|
+
ensureSessionState?: (ctx: ExtensionContext) => void | Promise<void>;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface ExecutionContextData {
|
|
299
|
+
params: SubagentParamsLike;
|
|
300
|
+
effectiveCwd: string;
|
|
301
|
+
ctx: ExtensionContext;
|
|
302
|
+
signal: AbortSignal | undefined;
|
|
303
|
+
onUpdate?: (r: SubagentExecutionResult) => void;
|
|
304
|
+
agents: AgentConfig[];
|
|
305
|
+
runId: string;
|
|
306
|
+
shareEnabled: boolean;
|
|
307
|
+
sessionRoot: string;
|
|
308
|
+
sessionDirForIndex: (idx?: number) => string;
|
|
309
|
+
sessionFileForIndex: (idx?: number) => string | undefined;
|
|
310
|
+
sessionFileForAgentIndex: (agentName: string | undefined, idx?: number) => string | undefined;
|
|
311
|
+
artifactsEnabled: boolean;
|
|
312
|
+
artifactsDir: string;
|
|
313
|
+
backgroundRequestedWhileClarifying: boolean;
|
|
314
|
+
effectiveAsync: boolean;
|
|
315
|
+
foregroundTimeoutMs?: number;
|
|
316
|
+
controlConfig: ResolvedControlConfig;
|
|
317
|
+
intercomBridge: IntercomBridgeState;
|
|
318
|
+
nestedRoute?: NestedRouteInfo;
|
|
319
|
+
onDetachedResultsSettled?: (mode: SubagentRunMode, results: SingleResult[], totalSteps?: number) => void;
|
|
320
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { writeAsyncControlRequest } from "../background/async-control.ts";
|
|
3
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { ownedRunExecutionResult, ownedRunProgressResult, ownedRunStatusResult, ownedRunView, resolveOwnedRun } from "../shared/run-records.ts";
|
|
5
|
+
import { formatSupervisorQuestions, getRunMetadataDir, listOwnedRunQuestions, questionProcessAlive, readRunJson, supervisorQuestionPage } from "../shared/supervisor-questions.ts";
|
|
6
|
+
import { formatRunAction } from "../../shared/status-format.ts";
|
|
7
|
+
import { getSingleResultOutput, readStatus } from "../../shared/utils.ts";
|
|
8
|
+
import { INTERCOM_DETACH_REQUEST_EVENT, INTERCOM_DETACH_RESPONSE_EVENT, POLL_INTERVAL_MS, type OwnedRun, type SubagentExecutionResult } from "../../shared/types.ts";
|
|
9
|
+
import { resolveSubagentRunId } from "../background/run-id-resolver.ts";
|
|
10
|
+
import { resolveNestedAsyncDir } from "../shared/nested-events.ts";
|
|
11
|
+
import { nestedResolutionScopeForExecutor } from "./foreground-control.ts";
|
|
12
|
+
import type { ExecutorDeps } from "./subagent-params.ts";
|
|
13
|
+
|
|
14
|
+
/** Wait on the saved outcome, not the transient notification file or an early terminal status. */
|
|
15
|
+
export async function waitForOwnedRun(input: {
|
|
16
|
+
id: string;
|
|
17
|
+
index?: number;
|
|
18
|
+
deps: ExecutorDeps;
|
|
19
|
+
ctx: ExtensionContext;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
onUpdate?: (result: SubagentExecutionResult) => void;
|
|
22
|
+
cancelNewRun?: boolean;
|
|
23
|
+
executionResult?: boolean;
|
|
24
|
+
includeProgress?: boolean;
|
|
25
|
+
}): Promise<SubagentExecutionResult> {
|
|
26
|
+
const { deps, id, index, ctx } = input;
|
|
27
|
+
const owner = ctx.sessionManager.getSessionId(), session = deps.state.currentSessionId;
|
|
28
|
+
let run: OwnedRun | undefined, nested = false;
|
|
29
|
+
try {
|
|
30
|
+
run = resolveOwnedRun(deps.state, id);
|
|
31
|
+
if (!run) {
|
|
32
|
+
const resolved = resolveSubagentRunId(id, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
33
|
+
if (resolved?.kind === "nested") {
|
|
34
|
+
const asyncDir = resolveNestedAsyncDir(resolved.match.rootRunId, resolved.match.run);
|
|
35
|
+
const status = asyncDir ? readStatus(asyncDir) : null;
|
|
36
|
+
if (status?.runId === resolved.id) {
|
|
37
|
+
const savedOwner = readRunJson<{ sessionId: string }>(path.join(getRunMetadataDir(resolved.id), "question-owner.json"));
|
|
38
|
+
// Read through the authorized route without adopting the descendant or attributing its usage to this caller.
|
|
39
|
+
run = { runId: resolved.id, rootRunId: resolved.match.rootRunId, ownerSessionId: savedOwner?.sessionId ?? status.sessionId ?? "",
|
|
40
|
+
source: "async", mode: status.mode, cwd: status.cwd ?? "", task: "Nested delegated run", startedAt: status.startedAt, asyncDir, pid: status.pid,
|
|
41
|
+
children: (status.steps ?? []).map((step, index) => ({ agent: step.agent, index, sessionFile: step.sessionFile })) };
|
|
42
|
+
nested = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return { content: [{ type: "text", text: String(error) }], isError: true, details: { mode: "management", results: [] } };
|
|
48
|
+
}
|
|
49
|
+
if (!run || (!nested && run.ownerSessionId !== owner)) return { content: [{ type: "text", text: "Run is not available to wait on in this session. This wait did not start or stop work." }], isError: true, details: { mode: "management", results: [] } };
|
|
50
|
+
const target = run;
|
|
51
|
+
const waiting = deps.state.waitingRuns ??= new Map();
|
|
52
|
+
waiting.set(target.runId, (waiting.get(target.runId) ?? 0) + 1);
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
let finished = false, timer: ReturnType<typeof setInterval> | undefined, unsubscribe: (() => void) | undefined;
|
|
55
|
+
let previous = "";
|
|
56
|
+
const finish = (status: "completed" | "cancelled" | "yielded" | "awaiting_input" | "unavailable", text: string, result?: SubagentExecutionResult) => {
|
|
57
|
+
if (finished) return;
|
|
58
|
+
finished = true;
|
|
59
|
+
const remaining = (waiting.get(target.runId) ?? 1) - 1;
|
|
60
|
+
if (remaining) waiting.set(target.runId, remaining); else waiting.delete(target.runId);
|
|
61
|
+
if (timer) clearInterval(timer);
|
|
62
|
+
unsubscribe?.(); input.signal?.removeEventListener("abort", abort);
|
|
63
|
+
const execution = input.executionResult && status === "completed" ? ownedRunExecutionResult(target, deps.state, index, input.includeProgress) : undefined;
|
|
64
|
+
const saved = status === "completed" ? readRunJson<{ completionId?: string }>(path.join(getRunMetadataDir(target.runId), "result.json")) : undefined;
|
|
65
|
+
resolve({ ...result, ...execution, content: status === "completed" && execution ? execution.content : [{ type: "text", text }],
|
|
66
|
+
...(status === "unavailable" || status === "cancelled" ? { isError: true } : {}),
|
|
67
|
+
details: { mode: "management", results: [], ...result?.details, ...execution?.details, wait: { runId: target.runId, completionId: saved?.completionId, index, status } } });
|
|
68
|
+
};
|
|
69
|
+
const abort = () => {
|
|
70
|
+
if (input.cancelNewRun && target.asyncDir) {
|
|
71
|
+
writeAsyncControlRequest(target.asyncDir, target.runId, "cancel");
|
|
72
|
+
}
|
|
73
|
+
finish("cancelled", input.cancelNewRun ? `Wait cancelled; cancellation requested for newly launched run ${target.runId}. Process exit is not yet confirmed.` : `Stopped waiting for ${target.runId}. The child was not stopped; completion will arrive automatically.`);
|
|
74
|
+
};
|
|
75
|
+
const check = () => {
|
|
76
|
+
if (deps.state.currentSessionId !== session || ctx.sessionManager.getSessionId() !== owner) { finish("unavailable", "The owning session changed. This wait ended without stopping the child."); return; }
|
|
77
|
+
try {
|
|
78
|
+
const runQuestions = listOwnedRunQuestions(target.ownerSessionId, target.runId);
|
|
79
|
+
// Poll execution facts once. Native conversation configuration is only
|
|
80
|
+
// needed when returning an inspection, never for live progress.
|
|
81
|
+
const view = ownedRunView(target, deps.state, {
|
|
82
|
+
pendingInput: runQuestions.some((question) => question.state === "awaiting_input" || question.state === "answer_pending"),
|
|
83
|
+
readConfiguration: false, includeContinuations: false,
|
|
84
|
+
});
|
|
85
|
+
const children = view.children.filter((child) => index === undefined || child.index === index);
|
|
86
|
+
if (index !== undefined && !children.length) { finish("unavailable", `Run ${target.runId} has no child at index ${index}.`); return; }
|
|
87
|
+
const questions = runQuestions.filter((question) => question.ownerSessionId === owner && (index === undefined || question.index === index) && question.state === "awaiting_input");
|
|
88
|
+
if (questions.length) {
|
|
89
|
+
const result = ownedRunStatusResult(target, deps.state);
|
|
90
|
+
const page = supervisorQuestionPage(questions), childSafe = Boolean(nestedResolutionScopeForExecutor(deps));
|
|
91
|
+
Object.assign(result.details, page);
|
|
92
|
+
finish("awaiting_input", `Run ${target.runId} needs input; waiting ended without stopping it.\n\n${formatSupervisorQuestions(page.questions, childSafe)}\n\nAll questions: ${formatRunAction("questions", target.runId, index === undefined ? {} : { index }, childSafe)}`, result); return;
|
|
93
|
+
}
|
|
94
|
+
if ((index !== undefined || view.resultPath) && children.every((child) => child.result && child.state !== "live" && child.state !== "unknown") && (index !== undefined || view.state !== "live")) {
|
|
95
|
+
const result = ownedRunStatusResult(target, deps.state);
|
|
96
|
+
result.isError = children.some((child) => child.state === "failed") || (index === undefined && view.state === "failed") || undefined;
|
|
97
|
+
finish("completed", [`Saved result for ${target.runId}${index !== undefined ? ` child ${index}` : ""}: ${index !== undefined ? children[0]!.state : view.state}`, ...children.map((child) => `\n${child.agent}: ${child.state}\n${getSingleResultOutput(child.result!) || child.result?.error || "(no output)"}`), result.content.map((part) => part.type === "text" ? part.text : "").join("\n")].join("\n"), result);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const pid = target.pid ?? (target.asyncDir ? readStatus(target.asyncDir)?.pid : undefined);
|
|
101
|
+
const producerAlive = pid ? questionProcessAlive({ pid }) : children.some((child) => child.state === "live");
|
|
102
|
+
if (!producerAlive) { finish("unavailable", `No saved final result is available for ${target.runId}; completion is unconfirmed. Inspect the saved session. No work was started.`, ownedRunStatusResult(target, deps.state)); return; }
|
|
103
|
+
const update = `Waiting for ${target.runId}${index !== undefined ? ` child ${index}` : ""}: ${children.map((child) => child.state).join(", ")}. ${input.cancelNewRun ? "Cancelling requests cancellation of this newly launched run; process exit still needs confirmation." : "Cancelling this wait leaves existing work alive."}`;
|
|
104
|
+
if (input.onUpdate) {
|
|
105
|
+
const progress = ownedRunProgressResult(target, deps.state, index, view);
|
|
106
|
+
const signature = JSON.stringify(progress.details.progress?.map(({ durationMs: _duration, ...activity }) => activity));
|
|
107
|
+
if (signature !== previous) { previous = signature; input.onUpdate({ ...progress, content: [{ type: "text", text: update }, ...progress.content] }); }
|
|
108
|
+
}
|
|
109
|
+
} catch (error) { finish("unavailable", `Wait could not read ${target.runId}: ${error instanceof Error ? error.message : String(error)}`); }
|
|
110
|
+
};
|
|
111
|
+
unsubscribe = deps.pi.events.on(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
|
|
112
|
+
if (finished || !payload || typeof payload !== "object") return;
|
|
113
|
+
const requestId = (payload as { requestId?: unknown }).requestId;
|
|
114
|
+
if (typeof requestId !== "string") return;
|
|
115
|
+
deps.pi.events.emit(INTERCOM_DETACH_RESPONSE_EVENT, { requestId, accepted: true });
|
|
116
|
+
finish("yielded", `Released the wait for an incoming Intercom message. Run ${target.runId} is unchanged. Continue useful work or end the turn; completion will arrive automatically.`);
|
|
117
|
+
});
|
|
118
|
+
input.signal?.addEventListener("abort", abort, { once: true });
|
|
119
|
+
if (input.signal?.aborted) abort(); else check();
|
|
120
|
+
// Unlike passive background tracking, this foreground call owes a result.
|
|
121
|
+
// The detached runner cannot keep this process alive; finish() releases the timer.
|
|
122
|
+
if (!finished) timer = setInterval(check, POLL_INTERVAL_MS);
|
|
123
|
+
});
|
|
124
|
+
}
|