@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,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General utility functions for the subagent extension
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import type { Message } from "@earendil-works/pi-ai";
|
|
9
|
+
import { formatToolCall } from "./formatters.ts";
|
|
10
|
+
import type { AsyncStatus, DisplayItem, ErrorInfo, SingleResult, ToolCallSummary } from "./types.ts";
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// File System Utilities
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export function getAgentDir(): string {
|
|
17
|
+
const configured = process.env.PI_CODING_AGENT_DIR;
|
|
18
|
+
if (configured === "~") return os.homedir();
|
|
19
|
+
if (configured?.startsWith("~/")) return path.join(os.homedir(), configured.slice(2));
|
|
20
|
+
return configured || path.join(os.homedir(), ".pi", "agent");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const statusCache = new Map<string, { version: string; status: AsyncStatus }>();
|
|
24
|
+
|
|
25
|
+
function getErrorMessage(error: unknown): string {
|
|
26
|
+
return error instanceof Error ? error.message : String(error);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resolveChildCwd(baseCwd: string, childCwd: string | undefined): string {
|
|
30
|
+
if (!childCwd) return baseCwd;
|
|
31
|
+
return path.isAbsolute(childCwd) ? childCwd : path.resolve(baseCwd, childCwd);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isNotFoundError(error: unknown): boolean {
|
|
35
|
+
return typeof error === "object"
|
|
36
|
+
&& error !== null
|
|
37
|
+
&& "code" in error
|
|
38
|
+
&& (error as NodeJS.ErrnoException).code === "ENOENT";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Read async job status from disk, invalidating on replacement and in-place updates.
|
|
43
|
+
*/
|
|
44
|
+
export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
45
|
+
const statusPath = path.join(asyncDir, "status.json");
|
|
46
|
+
|
|
47
|
+
let stat: fs.BigIntStats;
|
|
48
|
+
try {
|
|
49
|
+
stat = fs.statSync(statusPath, { bigint: true });
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (isNotFoundError(error)) {
|
|
52
|
+
statusCache.delete(statusPath);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Failed to inspect async status file '${statusPath}': ${getErrorMessage(error)}`, {
|
|
56
|
+
cause: error instanceof Error ? error : undefined,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const cached = statusCache.get(statusPath);
|
|
61
|
+
const version = `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
62
|
+
if (cached && cached.version === version) {
|
|
63
|
+
return cached.status;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let content: string;
|
|
67
|
+
try {
|
|
68
|
+
content = fs.readFileSync(statusPath, "utf-8");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (isNotFoundError(error)) return null;
|
|
71
|
+
throw new Error(`Failed to read async status file '${statusPath}': ${getErrorMessage(error)}`, {
|
|
72
|
+
cause: error instanceof Error ? error : undefined,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let status: AsyncStatus;
|
|
77
|
+
try {
|
|
78
|
+
status = JSON.parse(content) as AsyncStatus;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw new Error(`Failed to parse async status file '${statusPath}': ${getErrorMessage(error)}`, {
|
|
81
|
+
cause: error instanceof Error ? error : undefined,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
statusCache.set(statusPath, { version, status });
|
|
86
|
+
if (statusCache.size > 50) {
|
|
87
|
+
const firstKey = statusCache.keys().next().value;
|
|
88
|
+
if (firstKey) statusCache.delete(firstKey);
|
|
89
|
+
}
|
|
90
|
+
return status;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Find the latest session file in a directory
|
|
95
|
+
*/
|
|
96
|
+
export function findLatestSessionFile(sessionDir: string): string | null {
|
|
97
|
+
try {
|
|
98
|
+
let latest: { path: string; mtime: number } | undefined;
|
|
99
|
+
for (const file of fs.readdirSync(sessionDir)) {
|
|
100
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
101
|
+
const filePath = path.join(sessionDir, file);
|
|
102
|
+
const mtime = fs.statSync(filePath).mtimeMs;
|
|
103
|
+
if (!latest || mtime > latest.mtime) latest = { path: filePath, mtime };
|
|
104
|
+
}
|
|
105
|
+
return latest?.path ?? null;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Message Parsing Utilities
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get the final text output from a list of messages
|
|
117
|
+
*/
|
|
118
|
+
export function getFinalOutput(messages: Message[]): string {
|
|
119
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
120
|
+
const msg = messages[i];
|
|
121
|
+
if (msg.role === "assistant") {
|
|
122
|
+
const hasAssistantError = ("errorMessage" in msg && typeof msg.errorMessage === "string" && msg.errorMessage.length > 0)
|
|
123
|
+
|| ("stopReason" in msg && msg.stopReason === "error");
|
|
124
|
+
if (hasAssistantError) continue;
|
|
125
|
+
for (let j = msg.content.length - 1; j >= 0; j--) {
|
|
126
|
+
const part = msg.content[j];
|
|
127
|
+
if (part.type === "text" && part.text.trim().length > 0) return part.text;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return "";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function getSingleResultOutput(result: Pick<SingleResult, "finalOutput" | "messages">): string {
|
|
135
|
+
return result.finalOutput ?? getFinalOutput(result.messages ?? []);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function formatResourceLimitExceeded(input: { agent: string; kind: "maxExecutionTimeMs" | "maxTokens"; limit: number; observed?: number }): string {
|
|
139
|
+
if (input.kind === "maxExecutionTimeMs") {
|
|
140
|
+
return `Resource limit exceeded for ${input.agent}: maxExecutionTimeMs ${input.limit}ms.`;
|
|
141
|
+
}
|
|
142
|
+
return `Resource limit exceeded for ${input.agent}: maxTokens ${input.limit}${input.observed !== undefined ? ` (observed ${input.observed})` : ""}.`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Extract display items (text and tool calls) from messages
|
|
147
|
+
*/
|
|
148
|
+
export function getDisplayItems(messages: Message[] | undefined): DisplayItem[] {
|
|
149
|
+
if (!messages || messages.length === 0) return [];
|
|
150
|
+
const items: DisplayItem[] = [];
|
|
151
|
+
for (const msg of messages) {
|
|
152
|
+
if (msg.role === "assistant") {
|
|
153
|
+
for (const part of msg.content) {
|
|
154
|
+
if (part.type === "text") items.push({ type: "text", text: part.text });
|
|
155
|
+
else if (part.type === "toolCall") items.push({ type: "tool", name: part.name, args: part.arguments });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return items;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function extractToolCallSummaries(messages: Message[] | undefined): ToolCallSummary[] {
|
|
163
|
+
if (!messages?.length) return [];
|
|
164
|
+
const summaries: ToolCallSummary[] = [];
|
|
165
|
+
for (const msg of messages) {
|
|
166
|
+
if (msg.role !== "assistant") continue;
|
|
167
|
+
for (const part of msg.content) {
|
|
168
|
+
if (part.type !== "toolCall") continue;
|
|
169
|
+
const args = typeof part.arguments === "object" && part.arguments !== null && !Array.isArray(part.arguments)
|
|
170
|
+
? part.arguments
|
|
171
|
+
: {};
|
|
172
|
+
summaries.push({
|
|
173
|
+
text: formatToolCall(part.name, args),
|
|
174
|
+
expandedText: formatToolCall(part.name, args, true),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return summaries;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function compactForegroundResult(result: SingleResult): SingleResult {
|
|
182
|
+
if (result.progress?.status === "running") return result;
|
|
183
|
+
const toolCalls = result.toolCalls?.length ? result.toolCalls : extractToolCallSummaries(result.messages);
|
|
184
|
+
return {
|
|
185
|
+
...result,
|
|
186
|
+
messages: undefined,
|
|
187
|
+
progress: undefined,
|
|
188
|
+
toolCalls: toolCalls.length ? toolCalls : undefined,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Detect errors in subagent execution from messages (only errors with no subsequent success)
|
|
194
|
+
*/
|
|
195
|
+
export function detectSubagentError(messages: Message[]): ErrorInfo {
|
|
196
|
+
let lastAssistantTextIndex = -1;
|
|
197
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
198
|
+
const msg = messages[i];
|
|
199
|
+
if (msg.role === "assistant") {
|
|
200
|
+
const hasText = Array.isArray(msg.content) && msg.content.some(
|
|
201
|
+
(c) => c.type === "text" && "text" in c && typeof c.text === "string" && c.text.trim().length > 0,
|
|
202
|
+
);
|
|
203
|
+
if (hasText) {
|
|
204
|
+
lastAssistantTextIndex = i;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const scanStart = lastAssistantTextIndex >= 0 ? lastAssistantTextIndex + 1 : 0;
|
|
211
|
+
|
|
212
|
+
for (let i = messages.length - 1; i >= scanStart; i--) {
|
|
213
|
+
const msg = messages[i];
|
|
214
|
+
if (msg.role !== "toolResult") continue;
|
|
215
|
+
const toolName = "toolName" in msg && typeof msg.toolName === "string" ? msg.toolName : undefined;
|
|
216
|
+
const isError = "isError" in msg && msg.isError === true;
|
|
217
|
+
const observedExit = (msg as Message & { observedExitCode?: number }).observedExitCode;
|
|
218
|
+
|
|
219
|
+
if (isError) {
|
|
220
|
+
const text = msg.content.find((c) => c.type === "text");
|
|
221
|
+
const details = text && "text" in text ? text.text : undefined;
|
|
222
|
+
const exitMatch = details?.match(/exit(?:ed)?\s*(?:with\s*)?(?:code|status)?\s*[:\s]?\s*(\d+)/i);
|
|
223
|
+
return {
|
|
224
|
+
hasError: true,
|
|
225
|
+
exitCode: observedExit ?? (exitMatch ? parseInt(exitMatch[1], 10) : 1),
|
|
226
|
+
errorType: toolName || "tool",
|
|
227
|
+
details: details?.slice(0, 200),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (toolName !== "bash") continue;
|
|
232
|
+
|
|
233
|
+
const text = msg.content.find((c) => c.type === "text");
|
|
234
|
+
if (!text || !("text" in text)) continue;
|
|
235
|
+
const output = text.text;
|
|
236
|
+
|
|
237
|
+
const exitMatch = output.match(/exit(?:ed)?\s*(?:with\s*)?(?:code|status)?\s*[:\s]?\s*(\d+)/i);
|
|
238
|
+
if (exitMatch || observedExit !== undefined) {
|
|
239
|
+
const code = observedExit ?? parseInt(exitMatch![1], 10);
|
|
240
|
+
if (code !== 0) {
|
|
241
|
+
return { hasError: true, exitCode: code, errorType: "bash", details: output.slice(0, 200) };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { hasError: false };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Extract a preview of tool arguments for display
|
|
252
|
+
*/
|
|
253
|
+
export function extractToolArgsPreview(args: Record<string, unknown>): string {
|
|
254
|
+
const truncatePreview = (value: string, maxLength: number): string =>
|
|
255
|
+
value.length > maxLength ? `${value.slice(0, maxLength - 3)}...` : value;
|
|
256
|
+
|
|
257
|
+
const stringifyPreviewValue = (value: unknown): string | undefined => {
|
|
258
|
+
if (typeof value === "string" && value.trim().length > 0) return value;
|
|
259
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
260
|
+
return undefined;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const previewArray = (value: unknown): string | undefined => {
|
|
264
|
+
if (!Array.isArray(value) || value.length === 0) return undefined;
|
|
265
|
+
const first = stringifyPreviewValue(value[0]);
|
|
266
|
+
if (!first) return undefined;
|
|
267
|
+
const suffix = value.length > 1 ? ` (+${value.length - 1} more)` : "";
|
|
268
|
+
return `${first}${suffix}`;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Handle MCP tool calls - show server/tool info
|
|
272
|
+
if (args.tool && typeof args.tool === "string") {
|
|
273
|
+
const server = args.server && typeof args.server === "string" ? `${args.server}/` : "";
|
|
274
|
+
const toolArgs = args.args && typeof args.args === "string" ? ` ${args.args.slice(0, 40)}` : "";
|
|
275
|
+
return `${server}${args.tool}${toolArgs}`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const queriesPreview = previewArray(args.queries);
|
|
279
|
+
if (queriesPreview) return truncatePreview(queriesPreview, 60);
|
|
280
|
+
if (typeof args.query === "string" && args.query.trim().length > 0) return truncatePreview(args.query, 60);
|
|
281
|
+
if (typeof args.workflow === "string" && args.workflow.trim().length > 0) return `workflow=${truncatePreview(args.workflow, 48)}`;
|
|
282
|
+
|
|
283
|
+
if (typeof args.url === "string" && args.url.trim().length > 0) return truncatePreview(args.url, 60);
|
|
284
|
+
const urlsPreview = previewArray(args.urls);
|
|
285
|
+
if (urlsPreview) return truncatePreview(urlsPreview, 60);
|
|
286
|
+
if (typeof args.prompt === "string" && args.prompt.trim().length > 0) return truncatePreview(args.prompt, 60);
|
|
287
|
+
|
|
288
|
+
const previewKeys = ["command", "path", "file_path", "pattern", "query", "url", "task", "describe", "search"];
|
|
289
|
+
for (const key of previewKeys) {
|
|
290
|
+
if (args[key] && typeof args[key] === "string") {
|
|
291
|
+
const value = args[key] as string;
|
|
292
|
+
return truncatePreview(value, 60);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Fallback: show first string value found
|
|
297
|
+
for (const [key, value] of Object.entries(args)) {
|
|
298
|
+
const arrayPreview = previewArray(value);
|
|
299
|
+
if (arrayPreview) return `${key}=${truncatePreview(arrayPreview, 50)}`;
|
|
300
|
+
if (typeof value === "string" && value.length > 0) {
|
|
301
|
+
const preview = truncatePreview(value, 50);
|
|
302
|
+
return `${key}=${preview}`;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return "";
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Extract text content from various message content formats
|
|
310
|
+
*/
|
|
311
|
+
export function extractTextFromContent(content: unknown): string {
|
|
312
|
+
if (!content) return "";
|
|
313
|
+
// Handle string content directly
|
|
314
|
+
if (typeof content === "string") return content;
|
|
315
|
+
// Handle array content
|
|
316
|
+
if (!Array.isArray(content)) return "";
|
|
317
|
+
const texts: string[] = [];
|
|
318
|
+
for (const part of content) {
|
|
319
|
+
if (part && typeof part === "object") {
|
|
320
|
+
// Handle { type: "text", text: "..." }
|
|
321
|
+
if ("type" in part && part.type === "text" && "text" in part) {
|
|
322
|
+
texts.push(String(part.text));
|
|
323
|
+
}
|
|
324
|
+
// Handle { type: "tool_result", content: "..." }
|
|
325
|
+
else if ("type" in part && part.type === "tool_result" && "content" in part) {
|
|
326
|
+
const inner = extractTextFromContent(part.content);
|
|
327
|
+
if (inner) texts.push(inner);
|
|
328
|
+
}
|
|
329
|
+
// Handle { text: "..." } without type
|
|
330
|
+
else if ("text" in part) {
|
|
331
|
+
texts.push(String(part.text));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return texts.join("\n");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ============================================================================
|
|
339
|
+
// Concurrency Utilities
|
|
340
|
+
// ============================================================================
|
|
341
|
+
|
|
342
|
+
export { mapConcurrent } from "../runs/shared/parallel-utils.ts";
|