@nklisch/pi-enhanced 0.2.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-x64-gnu.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
- package/node_modules/@nklisch/pi-plugins/README.md +4 -2
- package/node_modules/@nklisch/pi-plugins/dist/hooks.js +81 -8
- package/node_modules/@nklisch/pi-plugins/dist/hooks.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/mcp.js +32 -1
- package/node_modules/@nklisch/pi-plugins/dist/mcp.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.d.ts +10 -4
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js +144 -10
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js +40 -14
- package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/CHANGELOG.md +25 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +75 -47
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +171 -140
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/settings.d.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +8 -7
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +12 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +112 -105
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/decisions/0004-reconsider-ui-direction.md +5 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +31 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/default-agents.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/invocation-config.ts +7 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +18 -9
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/layered-settings.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/child-lifecycle.ts +10 -63
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/concurrency-limiter.ts +122 -76
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +3 -5
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/lifecycle-interceptor.ts +4 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/run-listeners.ts +2 -23
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +177 -252
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +90 -280
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-state.ts +153 -223
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +569 -683
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/workspace.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +78 -119
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +15 -42
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +44 -95
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +157 -90
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts +60 -68
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/conversation.ts +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query-source.ts +28 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query.ts +327 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/settings.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +171 -249
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +51 -92
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/helpers.ts +9 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/list-tool.ts +46 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/parent-tool-registry.ts +17 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/query-session-tool.ts +330 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +27 -111
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/resume-tool.ts +105 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +26 -8
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +27 -111
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/stop-tool.ts +53 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +11 -5
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +33 -27
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +6 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +121 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +430 -112
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/subagents-settings.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +8 -9
- package/node_modules/@nklisch/pi-plugins/package.json +2 -2
- package/package.json +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +0 -81
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +0 -149
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +0 -77
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
9
9
|
import type { AgentConfigLookup } from "#src/config/agent-types";
|
|
10
|
+
import type { SubagentTerminalReason } from "#src/lifecycle/subagent-state";
|
|
10
11
|
import type { LifetimeUsage } from "#src/lifecycle/usage";
|
|
11
12
|
import { getLifetimeTotal } from "#src/lifecycle/usage";
|
|
12
13
|
import type { SubagentType, ThinkingLevel } from "#src/types";
|
|
@@ -29,12 +30,14 @@ export interface WidgetAgent {
|
|
|
29
30
|
readonly id: string;
|
|
30
31
|
readonly type: SubagentType;
|
|
31
32
|
readonly status: string;
|
|
33
|
+
readonly terminalReason?: SubagentTerminalReason;
|
|
32
34
|
readonly description: string;
|
|
33
35
|
readonly modelLabel: string;
|
|
34
36
|
readonly thinkingLevel: ThinkingLevel;
|
|
35
37
|
readonly toolUses: number;
|
|
36
38
|
readonly startedAt: number;
|
|
37
39
|
readonly completedAt?: number;
|
|
40
|
+
readonly activeRuntimeMs: number;
|
|
38
41
|
readonly error?: string;
|
|
39
42
|
readonly lifetimeUsage?: Readonly<LifetimeUsage>;
|
|
40
43
|
readonly compactionCount: number;
|
|
@@ -57,27 +60,23 @@ export function renderFinishedLine(
|
|
|
57
60
|
): string {
|
|
58
61
|
const name = getDisplayName(agent.type, registry);
|
|
59
62
|
const modeLabel = getPromptModeLabel(agent.type, registry);
|
|
60
|
-
const duration = formatMs(
|
|
63
|
+
const duration = formatMs(agent.activeRuntimeMs);
|
|
61
64
|
|
|
62
65
|
let icon: string;
|
|
63
66
|
let statusText: string;
|
|
64
67
|
if (agent.status === "completed") {
|
|
65
68
|
icon = theme.fg("success", "✓");
|
|
66
69
|
statusText = "";
|
|
67
|
-
} else if (agent.status === "steered") {
|
|
68
|
-
icon = theme.fg("warning", "✓");
|
|
69
|
-
statusText = theme.fg("warning", " (turn limit)");
|
|
70
70
|
} else if (agent.status === "stopped") {
|
|
71
71
|
icon = theme.fg("dim", "■");
|
|
72
|
-
statusText = theme.fg("dim",
|
|
72
|
+
statusText = theme.fg("dim", ` stopped${agent.terminalReason ? ` (${agent.terminalReason.replaceAll("_", " ")})` : ""}`);
|
|
73
73
|
} else if (agent.status === "error") {
|
|
74
74
|
icon = theme.fg("error", "✗");
|
|
75
75
|
const errMsg = agent.error ? `: ${agent.error.slice(0, 60)}` : "";
|
|
76
76
|
statusText = theme.fg("error", ` error${errMsg}`);
|
|
77
77
|
} else {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
statusText = theme.fg("warning", " aborted");
|
|
78
|
+
icon = theme.fg("dim", "•");
|
|
79
|
+
statusText = "";
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
const parts: string[] = [formatModelThinking(agent.modelLabel, agent.thinkingLevel)];
|
|
@@ -99,7 +98,7 @@ export function renderRunningLines(
|
|
|
99
98
|
const name = getDisplayName(agent.type, registry);
|
|
100
99
|
const modeLabel = getPromptModeLabel(agent.type, registry);
|
|
101
100
|
const modeTag = modeLabel ? ` ${theme.fg("dim", `(${modeLabel})`)}` : "";
|
|
102
|
-
const elapsed = formatMs(
|
|
101
|
+
const elapsed = formatMs(agent.activeRuntimeMs);
|
|
103
102
|
|
|
104
103
|
const tokens = getLifetimeTotal(agent.lifetimeUsage);
|
|
105
104
|
const tokenText = tokens > 0 ? formatSessionTokens(tokens, agent.contextPercent, theme, agent.compactionCount) : "";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nklisch/pi-plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A small filesystem-first marketplace and plugin host for Pi.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
],
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@nklisch/pi-mcp-adapter": "2.21.0-nklisch.2",
|
|
66
|
-
"@nklisch/pi-subagents": "18.
|
|
66
|
+
"@nklisch/pi-subagents": "18.2.0-nklisch.0",
|
|
67
67
|
"jiti": "2.7.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nklisch/pi-enhanced",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Pi, enhanced — one install for nklisch's full harness: policy-gated command review, plugin marketplace, subagents, background tasks, research tools, search, model modes, and a curated UX set.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "nklisch"
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
2
|
-
import type { AgentSpawnConfig } from "#src/lifecycle/subagent-manager";
|
|
3
|
-
import { textResult } from "#src/tools/helpers";
|
|
4
|
-
import { formatModelThinking } from "#src/ui/display";
|
|
5
|
-
import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
|
|
6
|
-
import type { ParentSessionInfo, Subagent } from "#src/types";
|
|
7
|
-
|
|
8
|
-
/** Narrow manager interface for the background spawner. */
|
|
9
|
-
export interface BackgroundManagerDeps {
|
|
10
|
-
spawn(snapshot: ParentSnapshot, type: string, prompt: string, opts: AgentSpawnConfig): string;
|
|
11
|
-
getRecord(id: string): Subagent | undefined;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** All values the background spawner needs beyond the resolved config. */
|
|
15
|
-
export interface BackgroundParams {
|
|
16
|
-
config: ResolvedSpawnConfig;
|
|
17
|
-
snapshot: ParentSnapshot;
|
|
18
|
-
parentSession: ParentSessionInfo;
|
|
19
|
-
settings: { readonly maxConcurrent: number };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Spawn a background agent and return the tool result immediately.
|
|
24
|
-
* Owns: launch message formatting.
|
|
25
|
-
*/
|
|
26
|
-
export function spawnBackground(
|
|
27
|
-
manager: BackgroundManagerDeps,
|
|
28
|
-
params: BackgroundParams,
|
|
29
|
-
) {
|
|
30
|
-
const { identity, execution, presentation } = params.config;
|
|
31
|
-
|
|
32
|
-
let id: string;
|
|
33
|
-
try {
|
|
34
|
-
id = manager.spawn(params.snapshot, identity.subagentType, execution.prompt, {
|
|
35
|
-
parentSession: params.parentSession,
|
|
36
|
-
description: execution.description,
|
|
37
|
-
model: execution.model,
|
|
38
|
-
maxTurns: execution.effectiveMaxTurns,
|
|
39
|
-
inheritContext: execution.inheritContext,
|
|
40
|
-
thinkingLevel: execution.effectiveThinkingLevel,
|
|
41
|
-
isBackground: true,
|
|
42
|
-
origin: "tool",
|
|
43
|
-
invocation: execution.agentInvocation,
|
|
44
|
-
});
|
|
45
|
-
} catch (err) {
|
|
46
|
-
return textResult(err instanceof Error ? err.message : String(err));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const record = manager.getRecord(id);
|
|
50
|
-
|
|
51
|
-
const isQueued = record?.status === "queued";
|
|
52
|
-
return textResult(
|
|
53
|
-
`Agent ${isQueued ? "queued" : "started"} in background.\n` +
|
|
54
|
-
`Agent ID: ${id}\n` +
|
|
55
|
-
`Type: ${identity.displayName}\n` +
|
|
56
|
-
`Model: ${formatModelThinking(
|
|
57
|
-
record?.modelLabel ?? presentation.modelName,
|
|
58
|
-
record?.effectiveThinkingLevel ?? execution.effectiveThinkingLevel,
|
|
59
|
-
)}\n` +
|
|
60
|
-
`Runtime: 0.0s\n` +
|
|
61
|
-
`Description: ${execution.description}\n` +
|
|
62
|
-
(identity.fellBack ? `Fallback: requested ${identity.rawType}; using ${identity.subagentType}\n` : "") +
|
|
63
|
-
(record?.outputFile ? `Output file: ${record.outputFile}\n` : "") +
|
|
64
|
-
(isQueued
|
|
65
|
-
? `Position: queued (max ${params.settings.maxConcurrent} concurrent)\n`
|
|
66
|
-
: "") +
|
|
67
|
-
`\nCompletion will automatically notify and wake you with a result preview. Continue other work; do not poll.\n` +
|
|
68
|
-
`Use steer_subagent to redirect this agent while it runs.\n` +
|
|
69
|
-
`Use get_subagent_result only for full output, verbose conversation, an explicit status check or synchronization point, or recovery after a missed notification.\n` +
|
|
70
|
-
`Do not duplicate this agent's work.`,
|
|
71
|
-
{
|
|
72
|
-
...presentation.detailBase,
|
|
73
|
-
thinkingLevel: record?.effectiveThinkingLevel ?? execution.effectiveThinkingLevel,
|
|
74
|
-
toolUses: 0,
|
|
75
|
-
tokens: "",
|
|
76
|
-
durationMs: 0,
|
|
77
|
-
status: "background" as const,
|
|
78
|
-
agentId: id,
|
|
79
|
-
},
|
|
80
|
-
);
|
|
81
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { runSafely } from "#src/debug";
|
|
3
|
-
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
4
|
-
import type { AgentSpawnConfig } from "#src/lifecycle/subagent-manager";
|
|
5
|
-
import {
|
|
6
|
-
buildDetails,
|
|
7
|
-
formatLifetimeTokens,
|
|
8
|
-
getStatusNote,
|
|
9
|
-
textResult,
|
|
10
|
-
} from "#src/tools/helpers";
|
|
11
|
-
import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
|
|
12
|
-
import type { ParentSessionInfo, Subagent } from "#src/types";
|
|
13
|
-
import {
|
|
14
|
-
type AgentDetails,
|
|
15
|
-
describeActivity,
|
|
16
|
-
formatModelThinking,
|
|
17
|
-
formatMs,
|
|
18
|
-
SPINNER,
|
|
19
|
-
} from "#src/ui/display";
|
|
20
|
-
|
|
21
|
-
/** Narrow manager interface for the foreground runner. */
|
|
22
|
-
export interface ForegroundManagerDeps {
|
|
23
|
-
spawnAndWait(
|
|
24
|
-
snapshot: ParentSnapshot,
|
|
25
|
-
type: string,
|
|
26
|
-
prompt: string,
|
|
27
|
-
opts: Omit<AgentSpawnConfig, "isBackground">,
|
|
28
|
-
): Promise<Subagent>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** All values the foreground runner needs beyond the resolved config. */
|
|
32
|
-
export interface ForegroundParams {
|
|
33
|
-
config: ResolvedSpawnConfig;
|
|
34
|
-
snapshot: ParentSnapshot;
|
|
35
|
-
parentSession: ParentSessionInfo;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Run an agent synchronously in the foreground, streaming spinner updates.
|
|
40
|
-
* Owns: spinner interval, streaming onUpdate callbacks, cleanup, and result formatting.
|
|
41
|
-
*/
|
|
42
|
-
export async function runForeground(
|
|
43
|
-
manager: ForegroundManagerDeps,
|
|
44
|
-
params: ForegroundParams,
|
|
45
|
-
signal: AbortSignal | undefined,
|
|
46
|
-
onUpdate: ((update: AgentToolResult<any>) => void) | undefined,
|
|
47
|
-
) {
|
|
48
|
-
const { identity, execution, presentation } = params.config;
|
|
49
|
-
let spinnerFrame = 0;
|
|
50
|
-
const startedAt = Date.now();
|
|
51
|
-
|
|
52
|
-
let recordRef: Subagent | undefined;
|
|
53
|
-
|
|
54
|
-
const streamUpdate = (): void => {
|
|
55
|
-
runSafely("foreground progress update", () => {
|
|
56
|
-
const toolUses = recordRef?.toolUses ?? 0;
|
|
57
|
-
const details: AgentDetails = {
|
|
58
|
-
...presentation.detailBase,
|
|
59
|
-
toolUses,
|
|
60
|
-
tokens: recordRef ? formatLifetimeTokens(recordRef) : "",
|
|
61
|
-
// Read activity off the record; fall back to safe defaults before onSessionCreated fires
|
|
62
|
-
turnCount: recordRef?.turnCount ?? 1,
|
|
63
|
-
maxTurns: recordRef?.maxTurns ?? execution.effectiveMaxTurns,
|
|
64
|
-
durationMs: Date.now() - startedAt,
|
|
65
|
-
status: "running",
|
|
66
|
-
activity: describeActivity(
|
|
67
|
-
recordRef?.activeTools ?? new Map(),
|
|
68
|
-
recordRef?.responseText ?? "",
|
|
69
|
-
),
|
|
70
|
-
spinnerFrame: spinnerFrame % SPINNER.length,
|
|
71
|
-
};
|
|
72
|
-
onUpdate?.({
|
|
73
|
-
content: [{ type: "text", text: `${toolUses} tool uses...` }],
|
|
74
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Pi SDK ToolCallUpdate details type is not exported
|
|
75
|
-
details: details as any,
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Each update traverses the parent TUI tree; avoid doing that at animation
|
|
81
|
-
// speed while the foreground tool already owns the progress surface.
|
|
82
|
-
const spinnerInterval = setInterval(() => {
|
|
83
|
-
spinnerFrame++;
|
|
84
|
-
streamUpdate();
|
|
85
|
-
}, 500);
|
|
86
|
-
|
|
87
|
-
let record: Subagent;
|
|
88
|
-
try {
|
|
89
|
-
streamUpdate();
|
|
90
|
-
|
|
91
|
-
record = await manager.spawnAndWait(
|
|
92
|
-
params.snapshot,
|
|
93
|
-
identity.subagentType,
|
|
94
|
-
execution.prompt,
|
|
95
|
-
{
|
|
96
|
-
description: execution.description,
|
|
97
|
-
model: execution.model,
|
|
98
|
-
maxTurns: execution.effectiveMaxTurns,
|
|
99
|
-
inheritContext: execution.inheritContext,
|
|
100
|
-
thinkingLevel: execution.effectiveThinkingLevel,
|
|
101
|
-
origin: "tool",
|
|
102
|
-
invocation: execution.agentInvocation,
|
|
103
|
-
signal,
|
|
104
|
-
parentSession: params.parentSession,
|
|
105
|
-
observer: {
|
|
106
|
-
onSessionCreated: (agent) => {
|
|
107
|
-
recordRef = agent;
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
// Only the spawn boundary converts to an error-text result. Post-spawn
|
|
114
|
-
// formatting is internal code; its defects stay thrown tool errors so Pi
|
|
115
|
-
// reports isError rather than a success-shaped result.
|
|
116
|
-
return textResult(err instanceof Error ? err.message : String(err));
|
|
117
|
-
} finally {
|
|
118
|
-
clearInterval(spinnerInterval);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Foreground delivery returns the complete outcome inline, so retention can
|
|
122
|
-
// use the shorter consumed-session window.
|
|
123
|
-
record.markConsumed();
|
|
124
|
-
|
|
125
|
-
const tokenText = formatLifetimeTokens(record);
|
|
126
|
-
const details = buildDetails(presentation.detailBase, record, { tokens: tokenText });
|
|
127
|
-
|
|
128
|
-
const fallbackNote = identity.fellBack
|
|
129
|
-
? `Note: Unknown agent type "${identity.rawType}" — using ${identity.subagentType}.\n\n`
|
|
130
|
-
: "";
|
|
131
|
-
|
|
132
|
-
if (record.status === "error") {
|
|
133
|
-
const partial = record.result?.trim();
|
|
134
|
-
return textResult(
|
|
135
|
-
`${fallbackNote}Model: ${formatModelThinking(record.modelLabel, record.effectiveThinkingLevel)}\nRuntime: ${formatMs(details.durationMs)}\nAgent failed: ${record.error}` +
|
|
136
|
-
(partial ? `\n\nPartial output before the failure:\n${partial}` : ""),
|
|
137
|
-
details,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const durationMs = (record.completedAt ?? Date.now()) - record.startedAt;
|
|
142
|
-
const statsParts = [`${record.toolUses} tool uses`];
|
|
143
|
-
if (tokenText) statsParts.push(tokenText);
|
|
144
|
-
return textResult(
|
|
145
|
-
`${fallbackNote}Model: ${formatModelThinking(record.modelLabel, record.effectiveThinkingLevel)}\nRuntime: ${formatMs(durationMs)}\nAgent completed (${statsParts.join(", ")})${getStatusNote(record.status)}.\n\n` +
|
|
146
|
-
(record.result?.trim() ?? "No output."),
|
|
147
|
-
details,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* get-result-report.ts — Pure report assembly for get_subagent_result.
|
|
3
|
-
*
|
|
4
|
-
* All functions are stateless: they receive an AgentReport, returning
|
|
5
|
-
* formatted strings. No SDK types, no timers, no side effects.
|
|
6
|
-
* Consumed by GetResultTool.execute in get-result-tool.ts. Mirrors the
|
|
7
|
-
* result-renderer.ts pattern used by the subagent tool's TUI renderer.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { SubagentStatus } from "#src/lifecycle/subagent";
|
|
11
|
-
import type { ThinkingLevel } from "#src/types";
|
|
12
|
-
import { formatModelThinking } from "#src/ui/display";
|
|
13
|
-
|
|
14
|
-
/** The data a get_subagent_result report renders from — only what the formatter reads. */
|
|
15
|
-
export interface AgentReport {
|
|
16
|
-
id: string;
|
|
17
|
-
displayName: string;
|
|
18
|
-
modelLabel: string;
|
|
19
|
-
thinkingLevel: ThinkingLevel;
|
|
20
|
-
status: SubagentStatus;
|
|
21
|
-
toolUses: number;
|
|
22
|
-
/** Pre-formatted lifetime token total; "" when zero. */
|
|
23
|
-
tokens: string;
|
|
24
|
-
contextPercent: number | null;
|
|
25
|
-
compactionCount: number;
|
|
26
|
-
/** Pre-formatted duration string. */
|
|
27
|
-
duration: string;
|
|
28
|
-
description: string;
|
|
29
|
-
result: string | undefined;
|
|
30
|
-
error: string | undefined;
|
|
31
|
-
stoppedWhileQueued: boolean;
|
|
32
|
-
/** Present only when verbose was requested and a conversation is available. */
|
|
33
|
-
conversation?: string;
|
|
34
|
-
/** Persisted transcript remains readable after the live session is released. */
|
|
35
|
-
transcriptPath?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Assemble the stats parts: Tool uses / tokens? / Context? / Compactions? / Duration. */
|
|
39
|
-
export function renderStatsParts(report: AgentReport): string[] {
|
|
40
|
-
const parts = [`Tool uses: ${report.toolUses}`];
|
|
41
|
-
if (report.tokens) parts.push(report.tokens);
|
|
42
|
-
if (report.contextPercent !== null) parts.push(`Context: ${Math.round(report.contextPercent)}%`);
|
|
43
|
-
if (report.compactionCount) parts.push(`Compactions: ${report.compactionCount}`);
|
|
44
|
-
parts.push(`Duration: ${report.duration}`);
|
|
45
|
-
return parts;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Select the per-status body: running note, error line, or trimmed result. */
|
|
49
|
-
export function renderReportBody(report: AgentReport): string {
|
|
50
|
-
if (report.status === "queued")
|
|
51
|
-
return "Agent is queued and has not started. Use wait: true to synchronize, or rely on the automatic completion notification.";
|
|
52
|
-
if (report.status === "running")
|
|
53
|
-
return "Agent is still running. Use wait: true to synchronize, or rely on the automatic completion notification.";
|
|
54
|
-
if (report.stoppedWhileQueued)
|
|
55
|
-
return "Agent was stopped while queued and never started. No work was performed.";
|
|
56
|
-
if (report.status === "error") {
|
|
57
|
-
const partial = report.result?.trim();
|
|
58
|
-
return partial
|
|
59
|
-
? `Error: ${report.error}\n\nPartial output before the failure:\n${partial}`
|
|
60
|
-
: `Error: ${report.error}`;
|
|
61
|
-
}
|
|
62
|
-
return report.result?.trim() ?? "No output.";
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Assemble the full get_subagent_result report text. */
|
|
66
|
-
export function formatAgentReport(report: AgentReport): string {
|
|
67
|
-
let output =
|
|
68
|
-
`Agent: ${report.id}\n` +
|
|
69
|
-
`Type: ${report.displayName} | Model: ${formatModelThinking(report.modelLabel, report.thinkingLevel)} | Status: ${report.status} | ${renderStatsParts(report).join(" | ")}\n` +
|
|
70
|
-
`Description: ${report.description}\n\n`;
|
|
71
|
-
output += renderReportBody(report);
|
|
72
|
-
if (report.conversation) {
|
|
73
|
-
output += `\n\n--- Agent Conversation ---\n${report.conversation}`;
|
|
74
|
-
}
|
|
75
|
-
if (report.transcriptPath) output += `\n\nFull transcript: ${report.transcriptPath}`;
|
|
76
|
-
return output;
|
|
77
|
-
}
|