mu-agent 0.1.13 → 0.1.14
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/README.md +2 -2
- package/dist/bundle/chunks/{chunk-WDURT4ZM.js → chunk-AN7MSYCK.js} +1 -1
- package/dist/bundle/chunks/{chunk-3J3HSHLX.js → chunk-BK7M6BDT.js} +3 -3
- package/dist/bundle/chunks/{virtual-modules-TJPHLTRT.js → virtual-modules-U6MRV5BC.js} +1 -1
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/judge/dist/auth.js +3 -0
- package/judge/dist/setup.js +15 -4
- package/judge/manifest.json +113 -45
- package/judge/mu/{chunk-SKGYWHW6.js → chunk-6XRUK3PM.js} +1 -1
- package/judge/mu/{cloud-code-V7FOGB4J.js → cloud-code-XR7SZMJC.js} +1 -1
- package/judge/mu/index.js +485 -213
- package/kyrn/bin/kyrn-doctor +40 -12
- package/kyrn/bin/mu.mjs +24 -6
- package/package.json +2 -2
package/kyrn/bin/kyrn-doctor
CHANGED
|
@@ -74,8 +74,12 @@ if (layout === "package") {
|
|
|
74
74
|
"dependencies",
|
|
75
75
|
installed
|
|
76
76
|
? "installed"
|
|
77
|
-
: `missing: cd ${root} && npm ci --ignore-scripts && npm run hydrate:model-
|
|
77
|
+
: `missing: cd ${root} && npm ci --ignore-scripts && npm run hydrate:model-catalog`,
|
|
78
78
|
);
|
|
79
|
+
// The model list pi reads at its start is generated, not committed (installHint in mu.mjs).
|
|
80
|
+
if (installed && !existsSync(join(root, "packages", "ai", "src", "providers", "data", ".manifest.json"))) {
|
|
81
|
+
row("fix", "model list", `not generated: cd ${root} && npm run hydrate:model-catalog`);
|
|
82
|
+
}
|
|
79
83
|
|
|
80
84
|
// A link on POSIX, a small mu.cmd on Windows, where a link to a script cannot be run.
|
|
81
85
|
const linked = linkState({
|
|
@@ -118,14 +122,32 @@ row(
|
|
|
118
122
|
const config = readJson(join(agentDir, "mu.json")) ?? readJson(join(agentDir, "kyrn.json"));
|
|
119
123
|
const tiers = (env("JUDGE") ? env("JUDGE").split(",") : (config?.tiers ?? ["jev"])).map((tier) => tier.trim());
|
|
120
124
|
const mode = env("JUDGE_MODE") ?? config?.modes?.default ?? "active";
|
|
121
|
-
row("--", "judges", `${tiers.join(" > ")} · default mode ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}`);
|
|
122
125
|
const overrides = Object.entries(config?.modes ?? {}).filter(([id]) => id !== "default");
|
|
126
|
+
// The modes mu sets out of the box besides the default, as packages/kyrn-judge/src/config.ts has them: one of these in
|
|
127
|
+
// mu.json gives way to a default of off (DecisionEngine.getMode).
|
|
128
|
+
const BUILT_IN_MODES = {
|
|
129
|
+
"swarm.patch": "off",
|
|
130
|
+
"capability.disclosure": "off",
|
|
131
|
+
"notify.routing": "shadow",
|
|
132
|
+
"input.interjection": "shadow",
|
|
133
|
+
"turn.drift": "shadow",
|
|
134
|
+
};
|
|
135
|
+
// Whether any decision point asks a judge (DecisionEngine.asksJudge). With none, nothing is sent to one, and the rows
|
|
136
|
+
// about keys and judges that answer would only mislead.
|
|
137
|
+
const asksJudge = mode !== "off" || overrides.some(([id, value]) => value !== "off" && BUILT_IN_MODES[id] !== value);
|
|
138
|
+
row(
|
|
139
|
+
"--",
|
|
140
|
+
"judges",
|
|
141
|
+
`${tiers.join(" > ")} · default mode ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}${asksJudge ? "" : " · no decision point asks a judge, so nothing is sent to one"}`,
|
|
142
|
+
);
|
|
123
143
|
if (overrides.length > 0) row("--", "modes", overrides.map(([id, value]) => `${id}=${value}`).join(" "));
|
|
124
144
|
const ladder = config?.features?.swarm?.models ?? [];
|
|
125
145
|
row("--", "subagents", ladder.length > 0 ? `model ladder ${ladder.join(" < ")}` : "use the session's model (no ladder configured)");
|
|
126
146
|
|
|
127
147
|
const judgeSupport = localJudgeSupport({ platform: process.platform, env: process.env, wsl });
|
|
128
|
-
if (
|
|
148
|
+
if (!asksJudge) {
|
|
149
|
+
// Nothing asks the local judge either: whether it is up does not matter.
|
|
150
|
+
} else if (tiers.some((tier) => tier.startsWith("laya")) && !judgeSupport.runs && !judgeSupport.url) {
|
|
129
151
|
// Not a failure of this installation: the sidecar is Core ML, and there is none for this platform.
|
|
130
152
|
row("--", "local judge", `not available on ${platformName({ platform: process.platform, wsl })}: the Laya sidecar needs Core ML (macOS on Apple silicon)`);
|
|
131
153
|
row("--", "", "Laya's decision points use the next judge or their fallbacks. Use Jev, an LLM judge or MU_LOCAL_JUDGE_URL=<a server with the same API>");
|
|
@@ -175,7 +197,7 @@ const fromFile = existsSync(envFile) ? parseEnvFile(readFileSync(envFile, "utf8"
|
|
|
175
197
|
const has = (name) => Boolean(process.env[name]) || fromFile.some(([key, value]) => key === name && value !== "");
|
|
176
198
|
const where = `to ${tilde(envFile)} or to your environment`;
|
|
177
199
|
const jevTier = tiers.find((tier) => ["jev", "typesafe", "gateway"].includes((config?.judges?.[tier] ?? JEV_ROUTES[tier])?.type));
|
|
178
|
-
if (jevTier) {
|
|
200
|
+
if (jevTier && asksJudge) {
|
|
179
201
|
const judge = config?.judges?.[jevTier] ?? JEV_ROUTES[jevTier];
|
|
180
202
|
if (judge.type === "jev") {
|
|
181
203
|
// The order the registry tries: TypeSafe directly, Jev on OpenRouter, the Vercel AI Gateway, OpenCode Zen,
|
|
@@ -220,10 +242,12 @@ const classifierOf = (tier) =>
|
|
|
220
242
|
tier.startsWith("classifier:")
|
|
221
243
|
? { type: "classifier", model: tier.slice("classifier:".length) }
|
|
222
244
|
: (config?.judges?.[tier] ?? JEV_ROUTES[tier]);
|
|
223
|
-
const askedTiers =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
245
|
+
const askedTiers = asksJudge
|
|
246
|
+
? [
|
|
247
|
+
...tiers,
|
|
248
|
+
...Object.values(config?.routes ?? {}).flatMap((value) => (Array.isArray(value) ? value : String(value).split(","))),
|
|
249
|
+
].map((tier) => String(tier).trim())
|
|
250
|
+
: [];
|
|
227
251
|
for (const model of new Set(askedTiers.map(classifierOf).filter((judge) => judge?.type === "classifier").map((judge) => judge.model))) {
|
|
228
252
|
const provider = String(model ?? "").split("/")[0];
|
|
229
253
|
// OpenCode's free models answer without a key (the client sends "public", as OpenCode's own does).
|
|
@@ -325,12 +349,16 @@ const canRelate = (tier) =>
|
|
|
325
349
|
const browseTiers = config?.routes?.["browser.step"] ?? tiers;
|
|
326
350
|
const routed = Object.entries(config?.routes ?? {});
|
|
327
351
|
if (routed.length > 0) row("--", "routes", routed.map(([id, value]) => `${id} -> ${[value].flat().join(" > ")}`).join(" · "));
|
|
352
|
+
// mu's browser runs on the judge: with browser.step off it is switched off (src/extension/features/browser.ts).
|
|
353
|
+
const browseMode = config?.modes?.["browser.step"] ?? mode;
|
|
328
354
|
row(
|
|
329
|
-
[browseTiers].flat().some(canRelate) ? "ok" : "--",
|
|
355
|
+
browseMode !== "off" && [browseTiers].flat().some(canRelate) ? "ok" : "--",
|
|
330
356
|
"browse",
|
|
331
|
-
|
|
332
|
-
?
|
|
333
|
-
:
|
|
357
|
+
browseMode === "off"
|
|
358
|
+
? "off: mu's browser runs on the judge, and browser.step is off"
|
|
359
|
+
: [browseTiers].flat().some(canRelate)
|
|
360
|
+
? `driven by ${[browseTiers].flat().join(" > ")}`
|
|
361
|
+
: 'needs a judge that can match a goal to a page. In mu.json: "routes": { "browser.step": ["llm:openai/gpt-5.6-luna"] }',
|
|
334
362
|
);
|
|
335
363
|
|
|
336
364
|
const marks = { ok: "\x1b[32m ok\x1b[0m", fix: "\x1b[33mfix\x1b[0m", "--": "\x1b[2m ·\x1b[0m" };
|
package/kyrn/bin/mu.mjs
CHANGED
|
@@ -354,12 +354,26 @@ export function dependenciesInstalled({ root, platform, exists }) {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Writes the model list pi reads at its start (packages/ai/src/providers/data, not committed) from the pinned catalog in
|
|
359
|
+
* the repository: offline and the same every time, as CI builds it.
|
|
360
|
+
*/
|
|
361
|
+
const HYDRATE = "npm run hydrate:model-catalog";
|
|
362
|
+
|
|
363
|
+
/** A problem and the commands that fix it, one line to paste; Windows PowerShell 5 has no `&&`, so a list there. */
|
|
364
|
+
function stepsHint(problem, steps, platform) {
|
|
360
365
|
return platform === "win32"
|
|
361
|
-
?
|
|
362
|
-
:
|
|
366
|
+
? `${problem}. Run:\n${steps.map((step) => ` ${step}`).join("\n")}`
|
|
367
|
+
: `${problem}. Run: ${steps.join(" && ")}`;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function installHint({ root, platform }) {
|
|
371
|
+
return stepsHint("mu's dependencies aren't installed", [`cd ${root}`, "npm ci --ignore-scripts", HYDRATE], platform);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** A checkout whose dependencies are in but whose model list was never written: a clone right after npm install. */
|
|
375
|
+
export function modelDataHint({ root, platform }) {
|
|
376
|
+
return stepsHint("mu's list of models isn't generated in this checkout yet", [`cd ${root}`, HYDRATE], platform);
|
|
363
377
|
}
|
|
364
378
|
|
|
365
379
|
/** What mu says on a Node that does not strip TypeScript types, which a checkout cannot run on. */
|
|
@@ -372,12 +386,16 @@ const NO_TYPE_STRIPPING =
|
|
|
372
386
|
* pi's own source resolver (packages/coding-agent/src/experimental/source-resolver.ts: each workspace package
|
|
373
387
|
* resolves to its sources, as tsconfig.json's paths say) and Node's compile cache (compile-cache.mjs), the way pi
|
|
374
388
|
* runs its own checkout (pi-test.sh). A runtime that does not strip types, a checkout whose dependencies are not
|
|
375
|
-
* installed and one without the resolver are each said, not left to a failed
|
|
389
|
+
* installed or whose model list is not generated, and one without the resolver are each said, not left to a failed
|
|
390
|
+
* import.
|
|
376
391
|
*/
|
|
377
392
|
export function sourceRuntime({ root, platform, stripsTypes, exists }) {
|
|
378
393
|
const path = pathFor(platform);
|
|
379
394
|
if (!stripsTypes) return { error: NO_TYPE_STRIPPING };
|
|
380
395
|
if (!dependenciesInstalled({ root, platform, exists })) return { error: installHint({ root, platform }) };
|
|
396
|
+
// Without it pi fails at its first import with ERR_MODULE_NOT_FOUND for a provider's .json.
|
|
397
|
+
if (!exists(path.join(root, "packages", "ai", "src", "providers", "data", ".manifest.json")))
|
|
398
|
+
return { error: modelDataHint({ root, platform }) };
|
|
381
399
|
const resolver = path.join(root, "packages", "coding-agent", "src", "experimental", "source-resolver.ts");
|
|
382
400
|
if (!exists(resolver)) return { error: `pi's source resolver is missing from this checkout (${resolver})` };
|
|
383
401
|
// As URLs: `--import` reads a Windows path such as C:\... as a URL whose scheme is c:.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "mu: a coding agent that hands its routine decisions to a small, fast judge model, so the main model can keep its attention on the work. Built on pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"muBuild": {
|
|
43
43
|
"pi": "1.3.0",
|
|
44
44
|
"judge": "0.1.0",
|
|
45
|
-
"commit": "
|
|
45
|
+
"commit": "36ffdd935"
|
|
46
46
|
}
|
|
47
47
|
}
|