pi-subagents 0.80.0 → 0.81.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 +28 -0
- package/bundle/agents.js +18 -0
- package/bundle/background-work.js +16 -0
- package/bundle/capability-ceiling.js +22 -0
- package/bundle/child-tool-plan.js +11 -0
- package/bundle/chunk-26C3WLYQ.js +8388 -0
- package/bundle/chunk-2XYWN7QJ.js +128 -0
- package/bundle/chunk-2ZSNH26H.js +4164 -0
- package/bundle/chunk-3DC5KBVP.js +235 -0
- package/bundle/chunk-3IF2PGW7.js +380 -0
- package/bundle/chunk-4QFZZV3O.js +57 -0
- package/bundle/chunk-563BHAZ5.js +1365 -0
- package/bundle/chunk-5LFLVSTM.js +260 -0
- package/bundle/chunk-62OCY2S4.js +14 -0
- package/bundle/chunk-74RT5YQE.js +326 -0
- package/bundle/chunk-7F6RKT6W.js +132 -0
- package/bundle/chunk-7J4ZXMY7.js +18 -0
- package/bundle/chunk-ARRKBB2B.js +179 -0
- package/bundle/chunk-BJN5LUQY.js +458 -0
- package/bundle/chunk-BPS2AGBZ.js +5421 -0
- package/bundle/chunk-CEKS3TFO.js +1337 -0
- package/bundle/chunk-CTPAE36Y.js +94 -0
- package/bundle/chunk-D4EHT5SJ.js +14 -0
- package/bundle/chunk-EYNJ6VL6.js +526 -0
- package/bundle/chunk-G5DKFLLI.js +1185 -0
- package/bundle/chunk-KSWQVGDW.js +1027 -0
- package/bundle/chunk-L5ZHE4L4.js +946 -0
- package/bundle/chunk-LSRUTHT7.js +57 -0
- package/bundle/chunk-N2BN7BF5.js +159 -0
- package/bundle/chunk-NF7IEKBH.js +490 -0
- package/bundle/chunk-NIXWDZZV.js +9 -0
- package/bundle/chunk-NNLASTQE.js +4082 -0
- package/bundle/chunk-TUWLXTAM.js +935 -0
- package/bundle/chunk-UKG4V45O.js +228 -0
- package/bundle/chunk-V2JWDB5U.js +753 -0
- package/bundle/chunk-V3BIUPLU.js +9163 -0
- package/bundle/chunk-V6MR5TOQ.js +270 -0
- package/bundle/chunk-VJHOELQP.js +8245 -0
- package/bundle/chunk-WSBNENFS.js +732 -0
- package/bundle/chunk-XMFLCKMQ.js +16664 -0
- package/bundle/chunk-YFCK7H2S.js +129 -0
- package/bundle/chunk-YYREO77V.js +137 -0
- package/bundle/chunk-Z7KVHQHL.js +173 -0
- package/bundle/chunk-ZBC44JJ3.js +8606 -0
- package/bundle/chunk-ZP3HODFH.js +175 -0
- package/bundle/control-channel.js +11 -0
- package/bundle/delegation.js +14 -0
- package/bundle/external-job-provider.js +20 -0
- package/bundle/external-runs.js +21 -0
- package/bundle/index.js +30 -0
- package/bundle/inspectors.js +8 -0
- package/bundle/intercom-bridge.js +11 -0
- package/bundle/preflight.js +425 -0
- package/bundle/project-panes.js +28 -0
- package/bundle/required-child-extensions.js +6 -0
- package/bundle/shared-types.js +8 -0
- package/bundle/workflow-resources.js +7 -0
- package/docs/extension-api.md +27 -0
- package/docs/observability.md +6 -2
- package/package.json +18 -18
- package/src/agents/frontmatter.d.ts +2 -0
- package/src/agents/frontmatter.js +9 -2
- package/src/api/delegation.d.ts +20 -0
- package/src/extension/index.js +27 -7
- package/src/runs/background/run-child-session.js +18 -0
- package/src/runs/background/stale-run-reconciler.js +2 -0
- package/src/runs/foreground/execution.js +39 -2
- package/src/runs/shared/structured-output.d.ts +1 -0
- package/src/runs/shared/structured-output.js +1 -0
- package/src/shared/accessible-dir.js +4 -1
- package/src/shared/provider-diagnostics.d.ts +9 -0
- package/src/shared/provider-diagnostics.js +75 -0
- package/src/shared/types.d.ts +3 -0
- package/src/slash/delegation-adapters.d.ts +3 -1
- package/src/slash/delegation-adapters.js +7 -0
- package/src/slash/prompt-template-bridge.js +3 -1
- package/src/slash/subagents-admin.d.ts +1 -0
- package/src/slash/subagents-admin.js +1 -1
- package/src/tui/fleet-layout.d.ts +20 -0
- package/src/tui/fleet-layout.js +17 -0
- package/src/tui/fleet-viewport.d.ts +12 -0
- package/src/tui/fleet-viewport.js +35 -0
- package/src/tui/fleet.d.ts +5 -6
- package/src/tui/fleet.js +69 -51
- package/src/workflows/structured-workflow-scripts.d.ts +1 -0
- package/src/workflows/structured-workflow-scripts.js +5 -4
- package/src/workflows/workflow-resources.js +2 -2
|
@@ -39,6 +39,8 @@ function foldBlock(block) {
|
|
|
39
39
|
/**
|
|
40
40
|
* Normalize a simple-scalar frontmatter list from comma-separated or block-list syntax.
|
|
41
41
|
* Only the standard `- item` marker is removed; ordinary hyphenated values stay intact.
|
|
42
|
+
* A trailing ` #...` comment is dropped from unquoted `- item` lines. Single-line values are left
|
|
43
|
+
* alone because parseFrontmatter has already removed their quotes, so `"notes #1.md"` must survive.
|
|
42
44
|
*/
|
|
43
45
|
export function parseFrontmatterList(raw) {
|
|
44
46
|
if (raw === undefined)
|
|
@@ -47,8 +49,9 @@ export function parseFrontmatterList(raw) {
|
|
|
47
49
|
.split("\n")
|
|
48
50
|
.flatMap((line) => {
|
|
49
51
|
const value = line.trim();
|
|
50
|
-
const listItem = value.match(/^-\s+(.+)$/);
|
|
51
|
-
|
|
52
|
+
const listItem = value.match(/^-\s+(.+)$/)?.[1];
|
|
53
|
+
const item = listItem === undefined || /^["']/.test(listItem) ? listItem ?? value : listItem.replace(/(?:^|\s)#.*$/, "");
|
|
54
|
+
return item.split(",");
|
|
52
55
|
})
|
|
53
56
|
.map((value) => value.trim())
|
|
54
57
|
.filter(Boolean);
|
|
@@ -80,6 +83,10 @@ export function parseFrontmatter(content) {
|
|
|
80
83
|
for (const line of lines) {
|
|
81
84
|
const indent = line.search(/\S|$/); // position of first non-whitespace char
|
|
82
85
|
const trimmed = line.trim();
|
|
86
|
+
// Comment lines are content only inside a | or > block scalar. Elsewhere they must
|
|
87
|
+
// neither end a pending list block nor become part of its value.
|
|
88
|
+
if (trimmed.startsWith("#") && !currentFolded && !currentLiteral)
|
|
89
|
+
continue;
|
|
83
90
|
if (currentKey !== null && currentBlockLines !== null && (indent > (currentIndent ?? 0) || ((currentFolded || currentLiteral) && trimmed === ""))) {
|
|
84
91
|
// This line is part of the current block value
|
|
85
92
|
currentBlockLines.push(line);
|
package/src/api/delegation.d.ts
CHANGED
|
@@ -53,7 +53,26 @@ export interface SubagentDelegationUpdateUsage {
|
|
|
53
53
|
cacheWrite: number;
|
|
54
54
|
turns: number;
|
|
55
55
|
}
|
|
56
|
+
/** Observed assistant-request errors and Pi retries, not provider-internal HTTP attempts. */
|
|
57
|
+
export interface SubagentDelegationProviderDiagnostics {
|
|
58
|
+
errorCount: number;
|
|
59
|
+
lastError?: {
|
|
60
|
+
kind: "rate_limited" | "transient_other" | "unknown";
|
|
61
|
+
/** Fixed safe description; never the raw provider error/body. */
|
|
62
|
+
message: string;
|
|
63
|
+
at: number;
|
|
64
|
+
};
|
|
65
|
+
retry?: {
|
|
66
|
+
phase: "backoff" | "in_flight";
|
|
67
|
+
attempt: number;
|
|
68
|
+
maxAttempts: number;
|
|
69
|
+
delayMs: number;
|
|
70
|
+
/** Observation time of auto_retry_start; delayMs is Pi's planned delay. */
|
|
71
|
+
scheduledAt: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
56
74
|
export interface SubagentDelegationUpdate extends SubagentDelegationStarted {
|
|
75
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
57
76
|
runId?: string;
|
|
58
77
|
currentTool?: string;
|
|
59
78
|
currentToolArgs?: string;
|
|
@@ -88,6 +107,7 @@ export interface SubagentDelegationUsage {
|
|
|
88
107
|
durationMs: number;
|
|
89
108
|
}
|
|
90
109
|
export interface SubagentDelegationTerminalResponse extends SubagentDelegationStarted {
|
|
110
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
91
111
|
status: Exclude<SubagentDelegationStatus, "invalid_request">;
|
|
92
112
|
error?: string;
|
|
93
113
|
runId?: string;
|
package/src/extension/index.js
CHANGED
|
@@ -43,6 +43,7 @@ import { createResultWatcher } from "../runs/background/result-watcher.js";
|
|
|
43
43
|
import { createResultDeliveryOwnership } from "../runs/background/result-delivery-ownership.js";
|
|
44
44
|
import { createScheduledRunManager } from "../runs/background/scheduled-runs.js";
|
|
45
45
|
import { registerSlashCommands } from "../slash/slash-commands.js";
|
|
46
|
+
import { ADMIN_MESSAGE_TYPE } from "../slash/subagents-admin.js";
|
|
46
47
|
import { registerPromptTemplateDelegationBridge } from "../slash/prompt-template-bridge.js";
|
|
47
48
|
import { registerMainWatchdog } from "../watchdog/register-main.js";
|
|
48
49
|
import { registerSlashSubagentBridge } from "../slash/slash-bridge.js";
|
|
@@ -557,13 +558,32 @@ export default function registerSubagentExtension(pi) {
|
|
|
557
558
|
return undefined;
|
|
558
559
|
return createSlashResultComponent(details, options, theme, config.mainWindowRenderer, foregroundDetachShortcut, () => state.lastUiContext?.ui.theme ?? theme);
|
|
559
560
|
});
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
561
|
+
// Pi sends custom messages to the model as plain user messages, so every model-visible
|
|
562
|
+
// pi-subagents message is wrapped in a marker naming its source. The marker depends only on
|
|
563
|
+
// the message, so history renders the same bytes every turn and cached prefixes stay valid.
|
|
564
|
+
const markedMessageTypes = new Set([...SUBAGENT_MESSAGE_TYPES, "subagent-compaction-resume", SLASH_RESULT_TYPE, SLASH_TEXT_RESULT_TYPE, ADMIN_MESSAGE_TYPE]);
|
|
565
|
+
pi.on("context", (event) => {
|
|
566
|
+
const messages = [];
|
|
567
|
+
for (const message of event.messages) {
|
|
568
|
+
if (message.role !== "custom" || !markedMessageTypes.has(message.customType)) {
|
|
569
|
+
messages.push(message);
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
// Keep view-only reports in the transcript/RPC stream, but out of model context.
|
|
573
|
+
// SLASH_RESULT_TYPE carries delegated work and must remain model-visible.
|
|
574
|
+
if (message.customType === SLASH_TEXT_RESULT_TYPE && message.details?.viewOnly === true)
|
|
575
|
+
continue;
|
|
576
|
+
const open = `<pi_subagents_notice type="${message.customType}" origin="automated message from the pi-subagents extension, not typed by the user">`;
|
|
577
|
+
const close = "</pi_subagents_notice>";
|
|
578
|
+
messages.push({
|
|
579
|
+
...message,
|
|
580
|
+
content: typeof message.content === "string"
|
|
581
|
+
? `${open}\n${message.content}\n${close}`
|
|
582
|
+
: [{ type: "text", text: `${open}\n` }, ...message.content, { type: "text", text: `\n${close}` }],
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
return { messages };
|
|
586
|
+
});
|
|
567
587
|
pi.registerMessageRenderer(SLASH_TEXT_RESULT_TYPE, (message, _options, _theme) => {
|
|
568
588
|
const content = typeof message.content === "string"
|
|
569
589
|
? message.content
|
|
@@ -10,6 +10,8 @@ import { createReportedChildSessionInput } from "../shared/child-launch.js";
|
|
|
10
10
|
import { createPartialOutputTracker, formatPartialOutput } from "../shared/partial-output.js";
|
|
11
11
|
import { childSessionHasQueuedMessages, projectChildSessionEventForJson } from "../shared/child-session.js";
|
|
12
12
|
import { reconcileAttemptUsage } from "../shared/usage-reconciliation.js";
|
|
13
|
+
import { isOrdinaryToolForMidToolExit } from "../shared/process-signal.js";
|
|
14
|
+
import { STRUCTURED_OUTPUT_FOLLOW_UP } from "../shared/structured-output.js";
|
|
13
15
|
import { formatSteerMessage } from "../shared/subagent-prompt-runtime.js";
|
|
14
16
|
import { takeMatchingAcceptedSteer, unconsumedSteerReason } from "./steering.js";
|
|
15
17
|
/** Events the child emits while the model streams; not persisted into the diagnostic log. */
|
|
@@ -616,6 +618,22 @@ export function runChildSession(input) {
|
|
|
616
618
|
abortChild();
|
|
617
619
|
messageBaseline = created.messages.length;
|
|
618
620
|
await created.prompt(input.prompt);
|
|
621
|
+
// A structured child that finished normally without calling structured_output gets one more turn (#2997).
|
|
622
|
+
if (input.launch.session.runtime.structuredOutput
|
|
623
|
+
&& !structuredOutputToolInvoked
|
|
624
|
+
&& !settled
|
|
625
|
+
&& !created.shutDown
|
|
626
|
+
&& !interrupted
|
|
627
|
+
&& !timedOut
|
|
628
|
+
&& !stopped
|
|
629
|
+
&& !forcedTermination
|
|
630
|
+
&& !error
|
|
631
|
+
&& !assistantError
|
|
632
|
+
&& !input.launch.capture.toolDiagnostic()
|
|
633
|
+
&& !(currentTool && isOrdinaryToolForMidToolExit(currentTool))) {
|
|
634
|
+
applyChildLifecycle("cancel-drain");
|
|
635
|
+
await created.prompt(STRUCTURED_OUTPUT_FOLLOW_UP);
|
|
636
|
+
}
|
|
619
637
|
promptSettled = true;
|
|
620
638
|
settle(undefined);
|
|
621
639
|
}
|
|
@@ -273,6 +273,8 @@ function buildFailedRepair(status, asyncDir, now, reason) {
|
|
|
273
273
|
agent: resultAgent,
|
|
274
274
|
mode: status.mode,
|
|
275
275
|
...(status.completionOwnerId ? { completionOwnerId: status.completionOwnerId } : {}),
|
|
276
|
+
...(status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {}),
|
|
277
|
+
...(status.workflowKey ? { workflowKey: status.workflowKey } : {}),
|
|
276
278
|
success: false,
|
|
277
279
|
state: "failed",
|
|
278
280
|
summary: message,
|
|
@@ -24,7 +24,7 @@ import { deriveChildSessionName } from "../../shared/child-session-name.js";
|
|
|
24
24
|
import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.js";
|
|
25
25
|
import { qualifyModelWithProvider, resolveEffectiveThinking } from "../../shared/model-info.js";
|
|
26
26
|
import { assertThinkingWithinCeiling, intersectThinkingCeilings } from "../../shared/thinking-ceiling.js";
|
|
27
|
-
import { formatStructuredOutputRejectionError, MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, MISSING_STRUCTURED_OUTPUT_CALL_ERROR } from "../shared/structured-output.js";
|
|
27
|
+
import { formatStructuredOutputRejectionError, MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, STRUCTURED_OUTPUT_FOLLOW_UP } from "../shared/structured-output.js";
|
|
28
28
|
import { formatMidToolExitError, isOrdinaryToolForMidToolExit } from "../shared/process-signal.js";
|
|
29
29
|
import { formatChildToolDiagnostic } from "../shared/tool-availability.js";
|
|
30
30
|
import { formatChildModelResolutionDiagnostic, formatInheritedProviderDiagnostic, isChildModelResolutionFailure } from "../shared/model-resolution-diagnostic.js";
|
|
@@ -45,6 +45,7 @@ import { acceptChildWatchdogEvent, applyChildWatchdogMessage, childWatchdogIsAct
|
|
|
45
45
|
import { buildInProcessChildLaunch, createReportedChildSessionInput } from "../shared/child-launch.js";
|
|
46
46
|
import { childSessionFactory, childSessionHasQueuedMessages, projectChildSessionEventForJson } from "../shared/child-session.js";
|
|
47
47
|
import { reconcileAttemptUsage } from "../shared/usage-reconciliation.js";
|
|
48
|
+
import { clearProviderRetry, observeProviderDiagnostics, snapshotProviderDiagnostics } from "../../shared/provider-diagnostics.js";
|
|
48
49
|
const artifactOutputByResult = new WeakMap();
|
|
49
50
|
const acceptanceOutputByResult = new WeakMap();
|
|
50
51
|
function emptyUsage() {
|
|
@@ -165,6 +166,7 @@ function snapshotProgress(progress) {
|
|
|
165
166
|
...progress,
|
|
166
167
|
task: PROMPT_REDACTED,
|
|
167
168
|
skills: progress.skills ? [...progress.skills] : undefined,
|
|
169
|
+
providerDiagnostics: snapshotProviderDiagnostics(progress.providerDiagnostics),
|
|
168
170
|
recentTools: boundStreamedRecentTools(progress.recentTools),
|
|
169
171
|
recentOutput: boundStreamedRecentOutput(progress.recentOutput),
|
|
170
172
|
};
|
|
@@ -175,6 +177,7 @@ function snapshotResult(result, progress) {
|
|
|
175
177
|
task: PROMPT_REDACTED,
|
|
176
178
|
messages: result.outputMode === "file-only" && result.savedOutputPath ? undefined : result.messages ? [...result.messages] : undefined,
|
|
177
179
|
usage: { ...result.usage },
|
|
180
|
+
providerDiagnostics: snapshotProviderDiagnostics(result.providerDiagnostics),
|
|
178
181
|
skills: result.skills ? [...result.skills] : undefined,
|
|
179
182
|
controlEvents: result.controlEvents ? result.controlEvents.map((event) => ({ ...event })) : undefined,
|
|
180
183
|
progress,
|
|
@@ -198,6 +201,7 @@ function snapshotStreamResult(result, progress) {
|
|
|
198
201
|
}
|
|
199
202
|
function captureStructuredDelegationProgressState(progress, result) {
|
|
200
203
|
return {
|
|
204
|
+
providerDiagnostics: progress.providerDiagnostics,
|
|
201
205
|
currentTool: progress.currentTool,
|
|
202
206
|
currentToolArgs: progress.currentToolArgs,
|
|
203
207
|
recentOutput: [...progress.recentOutput],
|
|
@@ -210,7 +214,9 @@ function captureStructuredDelegationProgressState(progress, result) {
|
|
|
210
214
|
};
|
|
211
215
|
}
|
|
212
216
|
function structuredDelegationProgressChanged(previous, progress, result) {
|
|
213
|
-
|
|
217
|
+
// Observations replace internal diagnostics; no transcript walk or serialization on heartbeats.
|
|
218
|
+
if (previous.providerDiagnostics !== progress.providerDiagnostics
|
|
219
|
+
|| previous.currentTool !== progress.currentTool
|
|
214
220
|
|| previous.currentToolArgs !== progress.currentToolArgs
|
|
215
221
|
|| previous.activityState !== progress.activityState
|
|
216
222
|
|| previous.model !== (progress.model ?? result.model)
|
|
@@ -352,6 +358,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
352
358
|
exitCode: 0,
|
|
353
359
|
outputState: "absent",
|
|
354
360
|
messages: [],
|
|
361
|
+
providerDiagnostics: shared.providerDiagnostics,
|
|
355
362
|
usage: emptyUsage(),
|
|
356
363
|
model: modelArg,
|
|
357
364
|
...(resolvedThinking ? { thinking: resolvedThinking } : {}),
|
|
@@ -383,6 +390,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
383
390
|
let cacheReadUsageComplete = true;
|
|
384
391
|
let cacheWriteUsageComplete = true;
|
|
385
392
|
const progress = {
|
|
393
|
+
providerDiagnostics: result.providerDiagnostics,
|
|
386
394
|
index: options.index ?? 0,
|
|
387
395
|
agent: agent.name,
|
|
388
396
|
...(childSessionName ? { sessionName: childSessionName } : {}),
|
|
@@ -972,6 +980,14 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
972
980
|
return;
|
|
973
981
|
}
|
|
974
982
|
const now = Date.now();
|
|
983
|
+
const providerDiagnostics = observeProviderDiagnostics(result.providerDiagnostics, evt, now);
|
|
984
|
+
if (providerDiagnostics !== result.providerDiagnostics) {
|
|
985
|
+
result.providerDiagnostics = providerDiagnostics;
|
|
986
|
+
progress.providerDiagnostics = providerDiagnostics;
|
|
987
|
+
// message_end already emits synchronously below; retry-only transitions need their own update.
|
|
988
|
+
if (evt.type !== "message_end")
|
|
989
|
+
fireUpdate();
|
|
990
|
+
}
|
|
975
991
|
progress.durationMs = now - startTime;
|
|
976
992
|
progress.lastActivityAt = now;
|
|
977
993
|
updateActivityState(now);
|
|
@@ -1396,6 +1412,24 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
1396
1412
|
// A runtime replacement can stop a child that detached while it was still being created.
|
|
1397
1413
|
if (!hostStopReason)
|
|
1398
1414
|
await created.prompt(`Task: ${task}`);
|
|
1415
|
+
// A structured child that finished normally without calling structured_output gets one more turn (#2997).
|
|
1416
|
+
if (options.structuredOutput
|
|
1417
|
+
&& !structuredOutputToolInvoked
|
|
1418
|
+
&& !sessionSettled
|
|
1419
|
+
&& !lifecycleFinished
|
|
1420
|
+
&& !hostStopReason
|
|
1421
|
+
&& !created.shutDown
|
|
1422
|
+
&& !abortedBySignal
|
|
1423
|
+
&& !interruptedByControl
|
|
1424
|
+
&& !result.timedOut
|
|
1425
|
+
&& !forcedTermination
|
|
1426
|
+
&& !result.error
|
|
1427
|
+
&& !assistantError
|
|
1428
|
+
&& !capture.toolDiagnostic()
|
|
1429
|
+
&& !(progress.currentTool && isOrdinaryToolForMidToolExit(progress.currentTool))) {
|
|
1430
|
+
applyChildLifecycle("cancel-drain");
|
|
1431
|
+
await created.prompt(STRUCTURED_OUTPUT_FOLLOW_UP);
|
|
1432
|
+
}
|
|
1399
1433
|
settle(undefined);
|
|
1400
1434
|
}
|
|
1401
1435
|
catch (error) {
|
|
@@ -1404,6 +1438,8 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
|
|
|
1404
1438
|
})();
|
|
1405
1439
|
});
|
|
1406
1440
|
result.exitCode = exitCode;
|
|
1441
|
+
result.providerDiagnostics = clearProviderRetry(result.providerDiagnostics);
|
|
1442
|
+
progress.providerDiagnostics = result.providerDiagnostics;
|
|
1407
1443
|
if (afterCompactionSettlement) {
|
|
1408
1444
|
result[AFTER_COMPACTION_SETTLEMENT] = true;
|
|
1409
1445
|
}
|
|
@@ -1855,6 +1891,7 @@ async function runSyncCompletionInner(runtimeCwd, agents, agentName, task, optio
|
|
|
1855
1891
|
orcaProgressTab,
|
|
1856
1892
|
launchWarnings,
|
|
1857
1893
|
verifyModel,
|
|
1894
|
+
providerDiagnostics: lastResult?.providerDiagnostics,
|
|
1858
1895
|
});
|
|
1859
1896
|
lastResult = attemptResult;
|
|
1860
1897
|
sumUsage(aggregateUsage, attemptResult.usage);
|
|
@@ -2,6 +2,7 @@ import type { Message } from "@earendil-works/pi-ai";
|
|
|
2
2
|
import type { JsonSchemaObject } from "../../shared/types.ts";
|
|
3
3
|
import type { ResolvedAcceptanceReportMode } from "./acceptance.ts";
|
|
4
4
|
export declare const MISSING_STRUCTURED_OUTPUT_CALL_ERROR = "Missing structured_output call; this step has outputSchema and must finish by calling structured_output.";
|
|
5
|
+
export declare const STRUCTURED_OUTPUT_FOLLOW_UP = "You ended without calling `structured_output`. Call it now with your result. Do not repeat the work.";
|
|
5
6
|
export declare const MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR = "Missing acceptanceReport in structured_output call; acceptance.report is \"on\".";
|
|
6
7
|
export declare const STRUCTURED_OUTPUT_REJECTION_ERROR = "structured_output was invoked but no valid output was captured.";
|
|
7
8
|
export declare const INVALID_STRUCTURED_OUTPUT_SCHEMA_ERROR = "Structured output invocation was rejected: invalid outputSchema.";
|
|
@@ -14,6 +14,7 @@ import { pathToFileURL } from "node:url";
|
|
|
14
14
|
import { PI_CODING_AGENT_PACKAGE_ROOT_ENV } from "../../shared/utils.js";
|
|
15
15
|
import { resolveInstalledPiPackageRoot, resolvePiPackageRoot } from "./pi-spawn.js";
|
|
16
16
|
export const MISSING_STRUCTURED_OUTPUT_CALL_ERROR = "Missing structured_output call; this step has outputSchema and must finish by calling structured_output.";
|
|
17
|
+
export const STRUCTURED_OUTPUT_FOLLOW_UP = "You ended without calling `structured_output`. Call it now with your result. Do not repeat the work.";
|
|
17
18
|
export const MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR = "Missing acceptanceReport in structured_output call; acceptance.report is \"on\".";
|
|
18
19
|
export const STRUCTURED_OUTPUT_REJECTION_ERROR = "structured_output was invoked but no valid output was captured.";
|
|
19
20
|
export const INVALID_STRUCTURED_OUTPUT_SCHEMA_ERROR = "Structured output invocation was rejected: invalid outputSchema.";
|
|
@@ -4,7 +4,10 @@ export function ensureAccessibleDir(dirPath, options = {}) {
|
|
|
4
4
|
const fsImpl = options.fs ?? fs;
|
|
5
5
|
const pid = options.pid ?? process.pid;
|
|
6
6
|
const retryDirectoryErrors = options.retryDirectoryErrors ?? process.platform === "win32";
|
|
7
|
-
|
|
7
|
+
// Runs synchronously at extension registration. The full ladder would block
|
|
8
|
+
// every Pi start for ~7.9 s on a directory with broken ACLs before reaching
|
|
9
|
+
// the pid fallback, so only its first steps (85 ms per operation) are used here.
|
|
10
|
+
const retryDelaysMs = retryDirectoryErrors ? options.retryDelaysMs ?? DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS.slice(0, 3) : [];
|
|
8
11
|
const wait = options.wait ?? waitForFileSystemRetry;
|
|
9
12
|
const mkdirWithRetry = (target) => {
|
|
10
13
|
runFileSystemOperationWithRetry(() => {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SubagentDelegationProviderDiagnostics } from "../api/delegation.ts";
|
|
2
|
+
import type { ChildSessionEvent } from "../runs/shared/child-session.ts";
|
|
3
|
+
type Diagnostics = SubagentDelegationProviderDiagnostics;
|
|
4
|
+
/** Immutable, bounded observations only. This never decides whether to retry. */
|
|
5
|
+
export declare function observeProviderDiagnostics(current: Diagnostics | undefined, event: ChildSessionEvent, at: number): Diagnostics | undefined;
|
|
6
|
+
export declare function clearProviderRetry(current: Diagnostics | undefined): Diagnostics | undefined;
|
|
7
|
+
export declare function snapshotProviderDiagnostics(current: Diagnostics | undefined): Diagnostics | undefined;
|
|
8
|
+
export declare function sameProviderDiagnostics(left: Diagnostics | undefined, right: Diagnostics | undefined): boolean;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isRetryableAssistantError } from "@earendil-works/pi-ai";
|
|
2
|
+
// Account exhaustion can also carry 429. Do not present it as transient throttling.
|
|
3
|
+
// Pi's classifier supplies its own provider-specific quota/billing exclusions too.
|
|
4
|
+
const ACCOUNT_LIMIT = /quota|billing|out of budget|available balance|(?:account|subscription|credits?|balance|usage)[\s_-]*(?:(?:is|are|has been|have been)[\s_-]*)?(?:limit|exhaust|deplet|exceed)|(?:insufficient|exhausted|depleted|low|no(?:[\s_-]+remaining)?)[\s_-]*(?:credits?|balance|fund)/i;
|
|
5
|
+
const RATE_LIMIT = /\brate[\s_-]*limit(?:ed|ing|s|_(?:exceeded|error))?\b|\btoo[\s_-]+many[\s_-]+requests\b|\b(?:HTTP(?:\/\d(?:\.\d)?)?\s*[:=]?\s*429|(?:status|statusCode|status_code)["']?\s*[:=]?\s*429)\b|^\s*429\b/i;
|
|
6
|
+
function classifyError(message) {
|
|
7
|
+
const text = message.errorMessage;
|
|
8
|
+
if (!text || ACCOUNT_LIMIT.test(text) || !isRetryableAssistantError(message))
|
|
9
|
+
return "unknown";
|
|
10
|
+
return RATE_LIMIT.test(text) ? "rate_limited" : "transient_other";
|
|
11
|
+
}
|
|
12
|
+
const SAFE_ERROR_MESSAGES = {
|
|
13
|
+
rate_limited: "Assistant request was rate limited.",
|
|
14
|
+
transient_other: "Assistant request encountered a transient provider or transport error.",
|
|
15
|
+
unknown: "Assistant request failed.",
|
|
16
|
+
};
|
|
17
|
+
/** Immutable, bounded observations only. This never decides whether to retry. */
|
|
18
|
+
export function observeProviderDiagnostics(current, event, at) {
|
|
19
|
+
if (event.type === "message_end") {
|
|
20
|
+
const message = event.message;
|
|
21
|
+
if (message?.role === "assistant" && message.stopReason === "error") {
|
|
22
|
+
const kind = classifyError(message);
|
|
23
|
+
return {
|
|
24
|
+
...current,
|
|
25
|
+
errorCount: (current?.errorCount ?? 0) + 1,
|
|
26
|
+
lastError: { kind, message: SAFE_ERROR_MESSAGES[kind], at },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (event.type === "auto_retry_start") {
|
|
31
|
+
const { attempt, maxAttempts, delayMs } = event;
|
|
32
|
+
if (typeof attempt === "number" && Number.isSafeInteger(attempt) && attempt > 0
|
|
33
|
+
&& typeof maxAttempts === "number" && Number.isSafeInteger(maxAttempts) && maxAttempts >= attempt
|
|
34
|
+
&& typeof delayMs === "number" && Number.isFinite(delayMs) && delayMs >= 0) {
|
|
35
|
+
return { ...current, errorCount: current?.errorCount ?? 0, retry: { phase: "backoff", attempt, maxAttempts, delayMs, scheduledAt: at } };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if ((event.type === "agent_start" || event.type === "turn_start") && current?.retry?.phase === "backoff") {
|
|
39
|
+
return { ...current, retry: { ...current.retry, phase: "in_flight" } };
|
|
40
|
+
}
|
|
41
|
+
else if (event.type === "auto_retry_end" || event.type === "agent_settled") {
|
|
42
|
+
return clearProviderRetry(current);
|
|
43
|
+
}
|
|
44
|
+
return current;
|
|
45
|
+
}
|
|
46
|
+
export function clearProviderRetry(current) {
|
|
47
|
+
if (!current?.retry)
|
|
48
|
+
return current;
|
|
49
|
+
const { retry: _retry, ...history } = current;
|
|
50
|
+
return history;
|
|
51
|
+
}
|
|
52
|
+
export function snapshotProviderDiagnostics(current) {
|
|
53
|
+
if (!current)
|
|
54
|
+
return undefined;
|
|
55
|
+
return {
|
|
56
|
+
errorCount: current.errorCount,
|
|
57
|
+
...(current.lastError ? { lastError: { ...current.lastError } } : {}),
|
|
58
|
+
...(current.retry ? { retry: { ...current.retry } } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function sameProviderDiagnostics(left, right) {
|
|
62
|
+
if (left === right)
|
|
63
|
+
return true;
|
|
64
|
+
if (!left || !right)
|
|
65
|
+
return false;
|
|
66
|
+
return left.errorCount === right.errorCount
|
|
67
|
+
&& left.lastError?.kind === right.lastError?.kind
|
|
68
|
+
&& left.lastError?.message === right.lastError?.message
|
|
69
|
+
&& left.lastError?.at === right.lastError?.at
|
|
70
|
+
&& left.retry?.phase === right.retry?.phase
|
|
71
|
+
&& left.retry?.attempt === right.retry?.attempt
|
|
72
|
+
&& left.retry?.maxAttempts === right.retry?.maxAttempts
|
|
73
|
+
&& left.retry?.delayMs === right.retry?.delayMs
|
|
74
|
+
&& left.retry?.scheduledAt === right.retry?.scheduledAt;
|
|
75
|
+
}
|
package/src/shared/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Type definitions for the subagent extension
|
|
3
3
|
*/
|
|
4
4
|
import type { Message } from "@earendil-works/pi-ai";
|
|
5
|
+
import type { SubagentDelegationProviderDiagnostics } from "../api/delegation.ts";
|
|
5
6
|
import type { AgentConfig } from "../agents/agents.ts";
|
|
6
7
|
import type { FSWatcher } from "node:fs";
|
|
7
8
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
@@ -864,6 +865,7 @@ export interface ChildWatchdogProgress {
|
|
|
864
865
|
warnings?: ChildWatchdogWarningSummary[];
|
|
865
866
|
}
|
|
866
867
|
export interface AgentProgress {
|
|
868
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
867
869
|
index: number;
|
|
868
870
|
agent: string;
|
|
869
871
|
/** Human-readable display name for the child's session, when derived at launch. */
|
|
@@ -1159,6 +1161,7 @@ export interface SingleResult {
|
|
|
1159
1161
|
toolBudget?: ToolBudgetState;
|
|
1160
1162
|
toolBudgetBlocked?: boolean;
|
|
1161
1163
|
messages?: Message[];
|
|
1164
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
1162
1165
|
usage: Usage;
|
|
1163
1166
|
model?: string;
|
|
1164
1167
|
/** Authoritative before/after Git evidence captured by a pane-native remote machine. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SubagentDelegationRequest, type SubagentDelegationResponse, type SubagentDelegationThinking, type SubagentDelegationUpdate, type SubagentDelegationUpdateUsage } from "../api/delegation.ts";
|
|
1
|
+
import { type SubagentDelegationProviderDiagnostics, type SubagentDelegationRequest, type SubagentDelegationResponse, type SubagentDelegationThinking, type SubagentDelegationUpdate, type SubagentDelegationUpdateUsage } from "../api/delegation.ts";
|
|
2
2
|
import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, IntercomBridgeConfig, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
|
|
3
3
|
export interface PromptTemplateDelegationRequest {
|
|
4
4
|
requestId: string;
|
|
@@ -88,6 +88,7 @@ export interface PromptTemplateBridgeResult {
|
|
|
88
88
|
review?: ReviewProjection;
|
|
89
89
|
effects?: EffectsProjection;
|
|
90
90
|
usage?: Usage;
|
|
91
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
91
92
|
progressSummary?: {
|
|
92
93
|
toolCount?: number;
|
|
93
94
|
durationMs?: number;
|
|
@@ -116,6 +117,7 @@ export interface PromptTemplateBridgeResult {
|
|
|
116
117
|
cacheRead?: number;
|
|
117
118
|
cacheWrite?: number;
|
|
118
119
|
turnCount?: number;
|
|
120
|
+
providerDiagnostics?: SubagentDelegationProviderDiagnostics;
|
|
119
121
|
}>;
|
|
120
122
|
};
|
|
121
123
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cloneJsonWithinByteLimit } from "./delegation-json.js";
|
|
2
|
+
import { clearProviderRetry, snapshotProviderDiagnostics } from "../shared/provider-diagnostics.js";
|
|
2
3
|
export function parsePromptTemplateRequest(data) {
|
|
3
4
|
if (!data || typeof data !== "object")
|
|
4
5
|
return undefined;
|
|
@@ -207,6 +208,9 @@ export function toSubagentDelegationUpdate(request, result) {
|
|
|
207
208
|
...(typeof legacy.durationMs === "number" ? { durationMs: legacy.durationMs } : {}),
|
|
208
209
|
...(typeof legacy.tokens === "number" ? { tokens: legacy.tokens } : {}),
|
|
209
210
|
...(legacy.usage ? { usage: legacy.usage } : {}),
|
|
211
|
+
...(result.details?.progress?.[0]?.providerDiagnostics ? {
|
|
212
|
+
providerDiagnostics: snapshotProviderDiagnostics(result.details.progress[0].providerDiagnostics),
|
|
213
|
+
} : {}),
|
|
210
214
|
};
|
|
211
215
|
}
|
|
212
216
|
function resolveSubagentDelegationStatus(result, aborted) {
|
|
@@ -282,6 +286,9 @@ export function toSubagentDelegationResponse(request, result, aborted) {
|
|
|
282
286
|
...(typeof child?.exitCode === "number" ? { exitCode: child.exitCode } : {}),
|
|
283
287
|
...(childLaunchContractDigest ? { launchContractDigest: childLaunchContractDigest } : {}),
|
|
284
288
|
...(projectedResult ? { result: projectedResult } : {}),
|
|
289
|
+
...(child?.providerDiagnostics ? {
|
|
290
|
+
providerDiagnostics: snapshotProviderDiagnostics(clearProviderRetry(child.providerDiagnostics)),
|
|
291
|
+
} : {}),
|
|
285
292
|
...(usage ? {
|
|
286
293
|
usage: {
|
|
287
294
|
input: usage.input,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SUBAGENT_DELEGATION_CANCEL_EVENT, SUBAGENT_DELEGATION_REQUEST_EVENT, SUBAGENT_DELEGATION_RESPONSE_EVENT, SUBAGENT_DELEGATION_STARTED_EVENT, SUBAGENT_DELEGATION_UPDATE_EVENT, } from "../api/delegation.js";
|
|
2
2
|
import { parseSubagentDelegationRequest } from "./delegation-request.js";
|
|
3
|
+
import { sameProviderDiagnostics } from "../shared/provider-diagnostics.js";
|
|
3
4
|
import { parsePromptTemplateRequest, toDelegationUpdate, toPromptTemplateResponse, toSubagentDelegationExecutionParams, toSubagentDelegationResponse, toSubagentDelegationUpdate, } from "./delegation-adapters.js";
|
|
4
5
|
export const PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT = SUBAGENT_DELEGATION_REQUEST_EVENT;
|
|
5
6
|
export const PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT = SUBAGENT_DELEGATION_STARTED_EVENT;
|
|
@@ -58,7 +59,8 @@ function sameStructuredDelegationUpdateProgress(left, right) {
|
|
|
58
59
|
&& left.model === right.model
|
|
59
60
|
&& left.toolCount === right.toolCount
|
|
60
61
|
&& left.tokens === right.tokens
|
|
61
|
-
&& sameUpdateUsage(left.usage, right.usage)
|
|
62
|
+
&& sameUpdateUsage(left.usage, right.usage)
|
|
63
|
+
&& sameProviderDiagnostics(left.providerDiagnostics, right.providerDiagnostics);
|
|
62
64
|
}
|
|
63
65
|
export function registerPromptTemplateDelegationBridge(options) {
|
|
64
66
|
const legacyControllers = new Map();
|
|
@@ -7,7 +7,7 @@ import { editableAgentConfig, preservedAgentFrontmatterFields } from "../agents/
|
|
|
7
7
|
import { findModelInfo, getSupportedThinkingLevels, toModelInfo } from "../shared/model-info.js";
|
|
8
8
|
import { SelectorComponent } from "./selector.js";
|
|
9
9
|
import { canRenderComponents } from "../shared/extension-context.js";
|
|
10
|
-
const ADMIN_MESSAGE_TYPE = "subagents-admin";
|
|
10
|
+
export const ADMIN_MESSAGE_TYPE = "subagents-admin";
|
|
11
11
|
const INHERIT_MODEL_CHOICE = "Default / inherit session model";
|
|
12
12
|
const INHERIT_THINKING_CHOICE = "Default / inherit session thinking";
|
|
13
13
|
function sourceRank(source) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface FleetRect {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FleetLayout {
|
|
8
|
+
width: number;
|
|
9
|
+
rows: number;
|
|
10
|
+
bodyHeight: number;
|
|
11
|
+
roster: FleetRect;
|
|
12
|
+
output: FleetRect;
|
|
13
|
+
rosterStart: number;
|
|
14
|
+
rosterKeys: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Coordinates are overlay-local, matching Pi's normalized input contract. */
|
|
17
|
+
export declare function fleetLayout(width: number, rows: number, selected: number, items: readonly {
|
|
18
|
+
key: string;
|
|
19
|
+
}[]): FleetLayout | undefined;
|
|
20
|
+
export declare function fleetContains(rect: FleetRect, x: number, y: number): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Coordinates are overlay-local, matching Pi's normalized input contract. */
|
|
2
|
+
export function fleetLayout(width, rows, selected, items) {
|
|
3
|
+
if (width < 36)
|
|
4
|
+
return undefined;
|
|
5
|
+
const bodyHeight = Math.max(2, Math.floor(rows * 0.85) - 6);
|
|
6
|
+
const rosterWidth = Math.max(22, Math.min(46, Math.floor((width - 3) * 0.38)));
|
|
7
|
+
const rosterStart = Math.max(0, Math.min(selected - bodyHeight + 1, Math.max(0, items.length - bodyHeight)));
|
|
8
|
+
return {
|
|
9
|
+
width, rows, bodyHeight, rosterStart,
|
|
10
|
+
roster: { x: 1, y: 3, width: rosterWidth, height: bodyHeight },
|
|
11
|
+
output: { x: rosterWidth + 2, y: 3, width: Math.max(1, width - rosterWidth - 3), height: bodyHeight },
|
|
12
|
+
rosterKeys: items.slice(rosterStart, rosterStart + bodyHeight).map((item) => item.key),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function fleetContains(rect, x, y) {
|
|
16
|
+
return x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ScrollView } from "@earendil-works/pi-tui";
|
|
2
|
+
/** Overlay-local clipping: ordinary overlays do not enter Pi's scroll layout traversal. */
|
|
3
|
+
export declare class FleetViewport {
|
|
4
|
+
private readonly body;
|
|
5
|
+
readonly scroll: ScrollView;
|
|
6
|
+
private readonly requestRender;
|
|
7
|
+
private resetTopOnLayout;
|
|
8
|
+
constructor(requestRender: () => void);
|
|
9
|
+
render(lines: string[], width: number, height: number): string[];
|
|
10
|
+
resetTop(): void;
|
|
11
|
+
follow(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ScrollView } from "@earendil-works/pi-tui";
|
|
2
|
+
/** Overlay-local clipping: ordinary overlays do not enter Pi's scroll layout traversal. */
|
|
3
|
+
export class FleetViewport {
|
|
4
|
+
body = {
|
|
5
|
+
lines: [],
|
|
6
|
+
render() { return this.lines; },
|
|
7
|
+
invalidate() { },
|
|
8
|
+
};
|
|
9
|
+
scroll = new ScrollView(this.body, { follow: "end", overscroll: "contain" });
|
|
10
|
+
requestRender;
|
|
11
|
+
resetTopOnLayout = false;
|
|
12
|
+
constructor(requestRender) {
|
|
13
|
+
this.requestRender = requestRender;
|
|
14
|
+
}
|
|
15
|
+
render(lines, width, height) {
|
|
16
|
+
this.body.lines = lines;
|
|
17
|
+
const rendered = this.scroll.render(width);
|
|
18
|
+
this.scroll.updateLayout(rendered.length, height, this.requestRender);
|
|
19
|
+
if (this.resetTopOnLayout) {
|
|
20
|
+
this.resetTopOnLayout = false;
|
|
21
|
+
this.scroll.scrollTo(0, { disableFollow: true });
|
|
22
|
+
}
|
|
23
|
+
return rendered.slice(this.scroll.scrollTop, this.scroll.scrollTop + this.scroll.viewportHeight);
|
|
24
|
+
}
|
|
25
|
+
resetTop() {
|
|
26
|
+
// Apply again after the new view's dimensions arrive: disableFollow suppresses following
|
|
27
|
+
// at the actual content end, which may differ from the previous view's end.
|
|
28
|
+
this.resetTopOnLayout = true;
|
|
29
|
+
this.scroll.scrollTo(0, { disableFollow: true });
|
|
30
|
+
}
|
|
31
|
+
follow() {
|
|
32
|
+
this.resetTopOnLayout = false;
|
|
33
|
+
this.scroll.scrollToEnd();
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/tui/fleet.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { type Component, type MarkdownTheme } from "@earendil-works/pi-tui";
|
|
2
|
+
import { type Component, type MarkdownTheme, type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
|
|
3
3
|
import { type ExternalRun } from "../api/external-runs.ts";
|
|
4
4
|
import { type FleetKeybindingAction, type FleetKeybindingsConfig, type ForegroundChildControl, type ForegroundResumeChild, type ForegroundResumeRun, type ForegroundRunControl, type SubagentState } from "../shared/types.ts";
|
|
5
5
|
import { type AsyncRunSummary } from "../runs/background/async-status.ts";
|
|
@@ -111,11 +111,8 @@ export declare class SubagentFleetComponent implements Component {
|
|
|
111
111
|
private snapshot;
|
|
112
112
|
private selected;
|
|
113
113
|
private selectedKey;
|
|
114
|
-
private
|
|
115
|
-
private
|
|
116
|
-
private detailLineCount;
|
|
117
|
-
private detailViewportHeight;
|
|
118
|
-
private bodyHeight;
|
|
114
|
+
private readonly viewport;
|
|
115
|
+
private renderedLayout;
|
|
119
116
|
private expandedTools;
|
|
120
117
|
private promptAuditOpen;
|
|
121
118
|
private promptAuditView;
|
|
@@ -141,6 +138,7 @@ export declare class SubagentFleetComponent implements Component {
|
|
|
141
138
|
private stopRefresh;
|
|
142
139
|
private refresh;
|
|
143
140
|
private moveSelection;
|
|
141
|
+
private selectItem;
|
|
144
142
|
private selectedPromptAudit;
|
|
145
143
|
private promptAuditItems;
|
|
146
144
|
private selectedPromptText;
|
|
@@ -155,6 +153,7 @@ export declare class SubagentFleetComponent implements Component {
|
|
|
155
153
|
private setActionNotice;
|
|
156
154
|
private runAction;
|
|
157
155
|
private scrollDetail;
|
|
156
|
+
handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
|
|
158
157
|
handleInput(data: string): void;
|
|
159
158
|
private rosterLines;
|
|
160
159
|
private renderedTranscript;
|