@underactive/pi-topping-moa-fusion 0.4.4 → 0.4.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 +12 -0
- package/package.json +5 -5
- package/src/moa/modelRuntime.ts +29 -1
- package/src/planning/planMode.ts +10 -1
- package/src/planning/tools/mfPlanSubagent.ts +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.4.5]
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Verified compatibility with pi 1.3.0: no pi export this extension imports was removed or changed, and typecheck and the full test suite pass against 1.3.0.
|
|
10
|
+
- Updated all four pi development dependencies from 1.1.0 to 1.3.0.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- On pi 1.3.0 and later, a bare model id in `moa-explore` or `mf-plan` frontmatter (e.g. `gpt-6-luna`) no longer makes the `mf_plan_subagent` child exit with `Model "…" is ambiguous across providers` when several authenticated providers offer that id. Earlier pi picked the first in catalog order. The tool now qualifies a bare id as `provider/id` before spawning: it prefers a provider with working credentials, then catalog order. Qualified refs and ids the registry does not know are passed through unchanged.
|
|
15
|
+
- On pi 1.2.0 and later, `before_agent_start` also fires for runs another extension starts with `pi.sendMessage(…, { triggerTurn: true })`. Those runs no longer receive plan-mode instructions or consume the one-shot plan-exit reminder meant for the user's next prompt. Hosts that do not report the run's message type are treated as user runs, as before.
|
|
16
|
+
|
|
5
17
|
## [0.4.4]
|
|
6
18
|
|
|
7
19
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@underactive/pi-topping-moa-fusion",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Pi extension implementing /mf-plan — Claude Code-style 5-phase plan mode with a Mixture-of-Agents proposer/synthesizer pipeline.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"typebox": "*"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@earendil-works/pi-agent-core": "1.
|
|
54
|
-
"@earendil-works/pi-ai": "1.
|
|
55
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
56
|
-
"@earendil-works/pi-tui": "1.
|
|
53
|
+
"@earendil-works/pi-agent-core": "1.3.0",
|
|
54
|
+
"@earendil-works/pi-ai": "1.3.0",
|
|
55
|
+
"@earendil-works/pi-coding-agent": "1.3.0",
|
|
56
|
+
"@earendil-works/pi-tui": "1.3.0",
|
|
57
57
|
"@types/node": "^24.0.0",
|
|
58
58
|
"typebox": "^1.3.3",
|
|
59
59
|
"typescript": "^5.8.0"
|
package/src/moa/modelRuntime.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { calculateCost } from "@earendil-works/pi-ai";
|
|
1
|
+
import { calculateCost, type Api, type Model } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import * as fs from "node:fs";
|
|
@@ -59,6 +59,34 @@ export function modelExtensionOptions(ctx: ExtensionContext, ref: ModelRef): { l
|
|
|
59
59
|
return modelUsesExtensionRegisteredProvider(ctx, ref) ? { loadExtensions: true } : {};
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** The slice of pi's `ModelRegistry` that qualifying a bare model id reads. */
|
|
63
|
+
export interface BareModelRegistry {
|
|
64
|
+
getAll(): Model<Api>[];
|
|
65
|
+
getAvailable(): Model<Api>[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Qualify a bare frontmatter model id (`claude-haiku-4-5`) as `provider/id` before it
|
|
70
|
+
* reaches a child's `--model`. Since pi 1.3.0 a bare id that several authenticated
|
|
71
|
+
* providers offer is a hard "ambiguous across providers" error, where earlier pi
|
|
72
|
+
* picked the first in catalog order. Prefers a provider with working credentials,
|
|
73
|
+
* then catalog order, which restores the earlier behavior. Values that already
|
|
74
|
+
* contain a `/`, and ids the registry does not know, are returned unchanged for
|
|
75
|
+
* the child to resolve.
|
|
76
|
+
*/
|
|
77
|
+
export function qualifyBareModelId(registry: BareModelRegistry, model: string): string {
|
|
78
|
+
if (model.includes("/")) return model;
|
|
79
|
+
const lower = model.toLowerCase();
|
|
80
|
+
const matches = (candidate: Model<Api>) => candidate.id.toLowerCase() === lower;
|
|
81
|
+
try {
|
|
82
|
+
const chosen = registry.getAvailable().find(matches) ?? registry.getAll().find(matches);
|
|
83
|
+
return chosen ? `${chosen.provider}/${chosen.id}` : model;
|
|
84
|
+
} catch {
|
|
85
|
+
// A stale registry must not block the spawn; the child resolves the bare id.
|
|
86
|
+
return model;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
62
90
|
export function resolveContextWindow(ctx: ExtensionContext, ref: ModelRef): number | undefined {
|
|
63
91
|
return ctx.modelRegistry.find(ref.provider, ref.id)?.contextWindow;
|
|
64
92
|
}
|
package/src/planning/planMode.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
AgentBeforeSettleEvent,
|
|
6
6
|
AgentSettledEvent,
|
|
7
7
|
AgentStartEvent,
|
|
8
|
+
BeforeAgentStartEvent,
|
|
8
9
|
ExtensionAPI,
|
|
9
10
|
ExtensionContext,
|
|
10
11
|
MessageEndEvent,
|
|
@@ -739,7 +740,15 @@ export function createPlanModeController(pi: ExtensionAPI) {
|
|
|
739
740
|
return !isPlanModeInstructionText(msg.content);
|
|
740
741
|
}) };
|
|
741
742
|
},
|
|
742
|
-
onBeforeAgentStart: async () => {
|
|
743
|
+
onBeforeAgentStart: async (event?: Partial<Pick<BeforeAgentStartEvent, "messageType">>) => {
|
|
744
|
+
// pi >= 1.2 also fires this for runs another extension starts with
|
|
745
|
+
// sendMessage(..., { triggerTurn: true }). Those must neither receive plan
|
|
746
|
+
// instructions nor consume the one-shot exit reminder meant for the user's
|
|
747
|
+
// next prompt. Older hosts omit messageType and only fire for user runs.
|
|
748
|
+
if (event?.messageType === "custom") {
|
|
749
|
+
if (!planModeEnabled) deactivatePlanOnlyTools();
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
743
752
|
if (needsExitReminder) {
|
|
744
753
|
needsExitReminder = false;
|
|
745
754
|
// The reminder turn is also the first normal-mode turn: repair a
|
|
@@ -8,7 +8,7 @@ import * as path from "node:path";
|
|
|
8
8
|
import { installShippedAgents, shippedAgentsDir, withAuthoritativeMoaAgents } from "../../agents/authoritative.ts";
|
|
9
9
|
import { loadMoaConfig } from "../../config/settings.ts";
|
|
10
10
|
import { discoverAgents, parseAgentFile } from "../../agents/discovery.ts";
|
|
11
|
-
import { modelExtensionOptions } from "../../moa/modelRuntime.ts";
|
|
11
|
+
import { modelExtensionOptions, qualifyBareModelId } from "../../moa/modelRuntime.ts";
|
|
12
12
|
import { CancelRun, type CancelRowExtras, type CancelSession } from "../../runtime/cancelRun.ts";
|
|
13
13
|
import { MutationTripwire, formatMutationWarning } from "../../runtime/mutationTripwire.ts";
|
|
14
14
|
import { getFinalOutput, getResultOutput, isFailedResult, truncateOutput } from "../../runtime/results.ts";
|
|
@@ -141,7 +141,16 @@ export function registerMfPlanSubagentTool(pi: ExtensionAPI, host: MfPlanSubagen
|
|
|
141
141
|
const planOverride = sessionModel
|
|
142
142
|
? { model: `${sessionModel.provider}/${sessionModel.id}`, thinking: host.currentThinkingLevel() }
|
|
143
143
|
: undefined;
|
|
144
|
-
|
|
144
|
+
// Shipped and hand-edited frontmatter can carry a bare id, which pi >= 1.3.0
|
|
145
|
+
// rejects as ambiguous when several authenticated providers offer it. Qualify
|
|
146
|
+
// it here; thinking stays undefined so the frontmatter level still applies.
|
|
147
|
+
const frontmatterOverrideFor = (agentName: string): { model: string; thinking?: ThinkingLevel } | undefined => {
|
|
148
|
+
const model = agents.find((agent) => agent.name === agentName)?.model;
|
|
149
|
+
if (!model) return undefined;
|
|
150
|
+
const qualified = qualifyBareModelId(ctx.modelRegistry, model);
|
|
151
|
+
return qualified === model ? undefined : { model: qualified };
|
|
152
|
+
};
|
|
153
|
+
const overrideFor = (agentName: string) => (agentName === "mf-plan" && planOverride ? planOverride : frontmatterOverrideFor(agentName));
|
|
145
154
|
|
|
146
155
|
// An agent whose effective model belongs to an extension-registered
|
|
147
156
|
// provider (claude-bridge, cursor-bridge) or is an extension-registered virtual model
|