oira666_pi-subagent 0.2.6 → 0.2.7
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/index.ts +35 -1
- package/package.json +1 -1
- package/runner.ts +20 -0
package/index.ts
CHANGED
|
@@ -425,6 +425,35 @@ function formatModelFlag(model: any): string | undefined {
|
|
|
425
425
|
return `${model.provider}/${model.id}`;
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
+
function findLastNonResumeModel(ctx: any): any | undefined {
|
|
429
|
+
const entries = (() => {
|
|
430
|
+
const leafId = ctx.sessionManager?.getLeafId?.();
|
|
431
|
+
if (leafId) {
|
|
432
|
+
const branch = ctx.sessionManager?.getBranch?.(leafId);
|
|
433
|
+
if (Array.isArray(branch)) return branch;
|
|
434
|
+
}
|
|
435
|
+
const all = ctx.sessionManager?.getEntries?.();
|
|
436
|
+
return Array.isArray(all) ? all : [];
|
|
437
|
+
})();
|
|
438
|
+
|
|
439
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
440
|
+
const entry = entries[i];
|
|
441
|
+
if (entry?.type !== "model_change") continue;
|
|
442
|
+
const provider = entry.provider;
|
|
443
|
+
const modelId = entry.modelId;
|
|
444
|
+
if (provider === RESUME_PROVIDER) continue;
|
|
445
|
+
if (typeof provider !== "string" || typeof modelId !== "string") continue;
|
|
446
|
+
const model = ctx.modelRegistry?.find?.(provider, modelId);
|
|
447
|
+
if (model) return model;
|
|
448
|
+
}
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function getRestorableModel(ctx: any): any | undefined {
|
|
453
|
+
if (ctx.model?.provider && ctx.model.provider !== RESUME_PROVIDER) return ctx.model;
|
|
454
|
+
return findLastNonResumeModel(ctx);
|
|
455
|
+
}
|
|
456
|
+
|
|
428
457
|
// ---------------------------------------------------------------------------
|
|
429
458
|
// Extension entry point
|
|
430
459
|
// ---------------------------------------------------------------------------
|
|
@@ -584,6 +613,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
584
613
|
);
|
|
585
614
|
}
|
|
586
615
|
|
|
616
|
+
const restorableModel = getRestorableModel(ctx);
|
|
617
|
+
if (ctx.model?.provider === RESUME_PROVIDER && restorableModel) {
|
|
618
|
+
await pi.setModel(restorableModel);
|
|
619
|
+
}
|
|
620
|
+
|
|
587
621
|
const resumeDisabled = parseBooleanEnv(process.env[SUBAGENT_RESUME_DISABLE_ENV]) === true;
|
|
588
622
|
if (resumeDisabled || (event.reason !== "resume" && event.reason !== "startup")) return;
|
|
589
623
|
|
|
@@ -605,7 +639,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
605
639
|
resumeState.plan = plan;
|
|
606
640
|
resumeState.phase = "tool";
|
|
607
641
|
resumeState.trigger = hasCliInitialPrompt(process.argv) ? "nextRequest" : "resumePrompt";
|
|
608
|
-
modelToRestoreAfterResume = ctx.model;
|
|
642
|
+
modelToRestoreAfterResume = restorableModel ?? ctx.model;
|
|
609
643
|
resumeModelRegistry = ctx.modelRegistry;
|
|
610
644
|
ensureSubagentToolActive(pi);
|
|
611
645
|
const resumeModel = ctx.modelRegistry.find(RESUME_PROVIDER, RESUME_MODEL_ID);
|
package/package.json
CHANGED
package/runner.ts
CHANGED
|
@@ -48,11 +48,24 @@ const TERMINAL_STOP_REASONS = new Set(["end_turn", "stop", "max_tokens", "error"
|
|
|
48
48
|
function isTerminalStopReason(reason: string | undefined): boolean {
|
|
49
49
|
return reason !== undefined && TERMINAL_STOP_REASONS.has(reason);
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
function endedWithEmptySyntheticResume(messages: Message[]): boolean {
|
|
53
|
+
const lastAssistant = [...messages].reverse().find((message: any) => message?.role === "assistant") as any;
|
|
54
|
+
return (
|
|
55
|
+
lastAssistant?.provider === RESUME_PROVIDER &&
|
|
56
|
+
lastAssistant?.model === RESUME_MODEL_ID &&
|
|
57
|
+
lastAssistant?.stopReason === "stop" &&
|
|
58
|
+
Array.isArray(lastAssistant.content) &&
|
|
59
|
+
lastAssistant.content.length === 0
|
|
60
|
+
);
|
|
61
|
+
}
|
|
51
62
|
const SUBAGENT_DEPTH_ENV = "PI_SUBAGENT_DEPTH";
|
|
52
63
|
const SUBAGENT_MAX_DEPTH_ENV = "PI_SUBAGENT_MAX_DEPTH";
|
|
53
64
|
const SUBAGENT_STACK_ENV = "PI_SUBAGENT_STACK";
|
|
54
65
|
const SUBAGENT_PREVENT_CYCLES_ENV = "PI_SUBAGENT_PREVENT_CYCLES";
|
|
55
66
|
const SUBAGENT_FALLBACK_MODEL_ENV = "PI_SUBAGENT_FALLBACK_MODEL";
|
|
67
|
+
const RESUME_PROVIDER = "pi-subagent-resume";
|
|
68
|
+
const RESUME_MODEL_ID = "synthetic-tool-call";
|
|
56
69
|
// PI_OFFLINE intentionally removed: setting it on child processes blocks all API
|
|
57
70
|
// calls and renders subagents unable to do any LLM work. Children inherit the
|
|
58
71
|
// parent's PI_OFFLINE value via process.env spread if needed.
|
|
@@ -730,6 +743,13 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
|
|
|
730
743
|
if (!result.stderr.trim()) result.stderr = "Subagent was aborted.";
|
|
731
744
|
}
|
|
732
745
|
|
|
746
|
+
if (result.exitCode === 0 && endedWithEmptySyntheticResume(result.messages)) {
|
|
747
|
+
result.exitCode = 1;
|
|
748
|
+
result.stopReason = "error";
|
|
749
|
+
result.errorMessage = "Subagent resume failed before the real model continued.";
|
|
750
|
+
if (!result.stderr.trim()) result.stderr = result.errorMessage;
|
|
751
|
+
}
|
|
752
|
+
|
|
733
753
|
if (result.exitCode === 0) {
|
|
734
754
|
const nestedErrorSummary = getNestedSubagentErrorSummary(result.messages);
|
|
735
755
|
if (nestedErrorSummary) {
|