@phi-code-admin/phi-code 0.63.4 → 0.64.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/extensions/phi/init.ts
CHANGED
|
@@ -462,10 +462,7 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
462
462
|
ctx.ui.notify(` ${status} ${p.name}${tag}${modelCount}`, "info");
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
//
|
|
466
|
-
if (cloudConfigured.length === 0) {
|
|
467
|
-
ctx.ui.notify("\n⚠️ No cloud API keys configured.\n", "warning");
|
|
468
|
-
}
|
|
465
|
+
// No warning needed — the wizard itself handles configuration
|
|
469
466
|
|
|
470
467
|
// Always offer to add a provider via select menu
|
|
471
468
|
const providerOptions = [
|
|
@@ -471,6 +471,7 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
|
|
|
471
471
|
let activeAgentPrompt: string | null = null;
|
|
472
472
|
let activeAgentTools: string[] | null = null;
|
|
473
473
|
let savedTools: string[] | null = null;
|
|
474
|
+
let phasePending = false; // true while waiting for a phase to complete
|
|
474
475
|
|
|
475
476
|
/**
|
|
476
477
|
* Parse agent .md file with YAML frontmatter
|
|
@@ -607,24 +608,55 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
|
|
|
607
608
|
/**
|
|
608
609
|
* Send the next phase in the queue.
|
|
609
610
|
*/
|
|
611
|
+
function setOrchestrationActive(active: boolean) {
|
|
612
|
+
orchestrationActive = active;
|
|
613
|
+
(globalThis as any).__phiOrchestrationActive = active;
|
|
614
|
+
}
|
|
615
|
+
|
|
610
616
|
function sendNextPhase(ctx: any) {
|
|
611
617
|
if (phaseQueue.length === 0) {
|
|
612
|
-
|
|
618
|
+
setOrchestrationActive(false);
|
|
619
|
+
phasePending = false;
|
|
613
620
|
deactivateAgent();
|
|
614
621
|
ctx.ui.notify(`\n✅ **All 5 phases complete!**`, "info");
|
|
615
622
|
return;
|
|
616
623
|
}
|
|
617
624
|
|
|
618
625
|
const phase = phaseQueue.shift()!;
|
|
626
|
+
phasePending = true;
|
|
619
627
|
|
|
620
628
|
switchModelForPhase(phase, ctx).then((modelId) => {
|
|
621
629
|
activateAgent(phase, ctx);
|
|
622
630
|
const agentName = phase.agent?.name || phase.key;
|
|
623
631
|
ctx.ui.notify(`\n${phase.label} → \`${modelId}\` (agent: ${agentName})`, "info");
|
|
624
|
-
|
|
632
|
+
// Wait for agent to be idle, then send the phase instruction
|
|
633
|
+
waitForIdleThenSend(phase.instruction, ctx);
|
|
625
634
|
});
|
|
626
635
|
}
|
|
627
636
|
|
|
637
|
+
/**
|
|
638
|
+
* Reliable phase sending: poll isIdle() then sendUserMessage.
|
|
639
|
+
* Retries up to 240 attempts (120 seconds).
|
|
640
|
+
*/
|
|
641
|
+
function waitForIdleThenSend(message: string, ctx: any) {
|
|
642
|
+
let attempts = 0;
|
|
643
|
+
const timer = setInterval(() => {
|
|
644
|
+
attempts++;
|
|
645
|
+
if (attempts > 240) {
|
|
646
|
+
clearInterval(timer);
|
|
647
|
+
ctx.ui.notify("⚠️ Orchestrator timeout — agent never became idle.", "warning");
|
|
648
|
+
setOrchestrationActive(false);
|
|
649
|
+
phasePending = false;
|
|
650
|
+
deactivateAgent();
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (ctx.isIdle()) {
|
|
654
|
+
clearInterval(timer);
|
|
655
|
+
setTimeout(() => pi.sendUserMessage(message), 300);
|
|
656
|
+
}
|
|
657
|
+
}, 500);
|
|
658
|
+
}
|
|
659
|
+
|
|
628
660
|
// ─── System Prompt Injection — Agent personas ────────────────────
|
|
629
661
|
|
|
630
662
|
pi.on("before_agent_start", async (event, _ctx) => {
|
|
@@ -636,33 +668,41 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
|
|
|
636
668
|
});
|
|
637
669
|
|
|
638
670
|
// ─── Output Event — Phase Chaining ───────────────────────────────
|
|
671
|
+
// Fires on each output chunk. We use it to detect when a phase completes.
|
|
672
|
+
// The key fix: only start ONE idle-check timer per phase, not one per chunk.
|
|
639
673
|
|
|
640
674
|
pi.on("output", async (_event, ctx) => {
|
|
641
|
-
if (!orchestrationActive ||
|
|
675
|
+
if (!orchestrationActive || !phasePending) return;
|
|
676
|
+
if (phaseQueue.length === 0 && phasePending) {
|
|
677
|
+
// Last phase in progress — wait for it to finish, then complete
|
|
678
|
+
}
|
|
642
679
|
|
|
680
|
+
// Debounce: clear any existing timer, start fresh
|
|
643
681
|
if (idlePollTimer) {
|
|
644
682
|
clearInterval(idlePollTimer);
|
|
645
683
|
idlePollTimer = null;
|
|
646
684
|
}
|
|
647
685
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
686
|
+
// After output, wait a bit then check if the agent is truly idle
|
|
687
|
+
// Use a longer initial delay (2 seconds) to let tool calls complete
|
|
688
|
+
idlePollTimer = setTimeout(() => {
|
|
689
|
+
let attempts = 0;
|
|
690
|
+
idlePollTimer = setInterval(() => {
|
|
691
|
+
attempts++;
|
|
692
|
+
if (attempts > 60) { // 30 seconds after last output
|
|
693
|
+
clearInterval(idlePollTimer!);
|
|
694
|
+
idlePollTimer = null;
|
|
695
|
+
// Don't timeout — the phase might still have tool calls
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
if (ctx.isIdle()) {
|
|
699
|
+
clearInterval(idlePollTimer!);
|
|
700
|
+
idlePollTimer = null;
|
|
701
|
+
phasePending = false;
|
|
702
|
+
sendNextPhase(ctx);
|
|
703
|
+
}
|
|
704
|
+
}, 500) as any;
|
|
705
|
+
}, 2000) as any;
|
|
666
706
|
|
|
667
707
|
// ─── /plan Command — Full workflow ───────────────────────────────
|
|
668
708
|
|
|
@@ -693,7 +733,8 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
|
|
|
693
733
|
// Build phases with model assignments + agent definitions
|
|
694
734
|
const phases = buildPhases(description);
|
|
695
735
|
phaseQueue = phases.slice(1); // Queue phases 2-5
|
|
696
|
-
|
|
736
|
+
setOrchestrationActive(true);
|
|
737
|
+
phasePending = true;
|
|
697
738
|
const firstPhase = phases[0];
|
|
698
739
|
|
|
699
740
|
ctx.ui.notify(`📋 **Orchestrator started** — 5 phases with model routing + agent roles\n`, "info");
|
|
@@ -77,6 +77,11 @@ export default function smartRouterExtension(pi: ExtensionAPI) {
|
|
|
77
77
|
return { action: "continue" };
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// Do NOT route during orchestration — the orchestrator manages models
|
|
81
|
+
if ((globalThis as any).__phiOrchestrationActive) {
|
|
82
|
+
return { action: "continue" };
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
const recommendation = router.getRecommendation(event.text);
|
|
81
86
|
|
|
82
87
|
if (recommendation.category !== "general") {
|