mu-agent 0.1.7 → 0.1.10
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 +52 -0
- package/README.md +34 -29
- package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
- package/dist/bundle/chunks/anthropic.js +2 -2
- package/dist/bundle/chunks/azure-openai-responses-Y4BBWQ3N.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +12 -9
- package/dist/bundle/chunks/{chunk-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
- package/dist/bundle/chunks/{chunk-XDUWOHPL.js → chunk-5AGIVGSV.js} +3 -3
- package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
- package/dist/bundle/chunks/chunk-7CBJINYJ.js +20 -0
- package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
- package/dist/bundle/chunks/chunk-BSS6T6KQ.js +2 -0
- package/dist/bundle/chunks/chunk-CF5GWZHW.js +31 -0
- package/dist/bundle/chunks/chunk-DNNHZBQR.js +4 -0
- package/dist/bundle/chunks/chunk-FN6OEZYR.js +2 -0
- package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
- package/dist/bundle/chunks/chunk-HZNN636Z.js +130 -0
- package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
- package/dist/bundle/chunks/{chunk-4O2SCVYF.js → chunk-KIDDRTZP.js} +4 -4
- package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
- package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
- package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
- package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
- package/dist/bundle/chunks/chunk-O7IPTASE.js +1221 -0
- package/dist/bundle/chunks/chunk-PMRZO46Y.js +2 -0
- package/dist/bundle/chunks/chunk-QOEEJKS4.js +9 -0
- package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
- package/dist/bundle/chunks/chunk-RAQ6TU76.js +2 -0
- package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
- package/dist/bundle/chunks/chunk-SGOTYFMT.js +91 -0
- package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
- package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
- package/dist/bundle/chunks/chunk-VJLOQZKR.js +9 -0
- package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
- package/dist/bundle/chunks/chunk-X234222Q.js +64 -0
- package/dist/bundle/chunks/cli-722OL3K5.js +51 -0
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +478 -0
- package/dist/bundle/chunks/easter-egg-3d-6H34EDGX.js +2 -0
- package/dist/bundle/chunks/execute-KVSEIDWL.js +499 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-C44KRRZ4.js → google-generative-ai-D2VJQBTK.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-25DUXPTJ.js → google-vertex-SQG2BO6C.js} +1 -1
- package/dist/bundle/chunks/https-proxy-agent-LVOO5TPL.js +13 -0
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{jiti-loader-C3NU2SDH.js → jiti-loader-GL4HJFAD.js} +1 -1
- package/dist/bundle/chunks/{jiti-static-loader-E6ANQD5T.js → jiti-static-loader-2RCDI6B4.js} +1 -1
- package/dist/bundle/chunks/{lib-HGQMNYVT.js → lib-4AVRLBHM.js} +2 -2
- package/dist/bundle/chunks/llama-cpp-classify-5YHLY3RC.js +22 -0
- package/dist/bundle/chunks/mistral-conversations-BDARVJTT.js +5 -0
- package/dist/bundle/chunks/{multipart-parser-SQ6GDJL7.js → multipart-parser-FMGQ7342.js} +1 -1
- package/dist/bundle/chunks/{node-TWVVAGPO.js → node-AUOGOBCN.js} +1 -1
- package/dist/bundle/chunks/node-KCMANYC2.js +16 -0
- package/dist/bundle/chunks/openai-chatgpt.js +86 -0
- package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +2 -2
- package/dist/bundle/chunks/openai-completions-UOA7MELD.js +7 -0
- package/dist/bundle/chunks/openai-decisions-HLM372N6.js +5 -0
- package/dist/bundle/chunks/openai-responses-TII7ZY5X.js +3 -0
- package/dist/bundle/chunks/{openrouter-images-JVEJN44Q.js → openrouter-images-7T452AS5.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +2 -2
- package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
- package/dist/bundle/chunks/radius.js +2 -2
- package/dist/bundle/chunks/runtime-O3ELDOM7.js +2 -0
- package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
- package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
- package/dist/bundle/chunks/virtual-modules-IKEARUOZ.js +2 -0
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/export-html/template.js +37 -16
- package/dist/modes/interactive/theme/dark.json +60 -73
- package/dist/modes/interactive/theme/light.json +58 -70
- package/dist/modes/interactive/theme/system-theme.d.ts +55 -0
- package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/system-theme.js +546 -0
- package/dist/modes/interactive/theme/system-theme.js.map +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +43 -9
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +121 -79
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.js +105 -0
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.js +94 -0
- package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts +47 -56
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +149 -143
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/dist/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/docs/cli-integration.md +1 -1
- package/docs/cli.md +78 -13
- package/docs/codemode.md +230 -0
- package/docs/compaction.md +5 -5
- package/docs/configuration.md +2 -0
- package/docs/custom-provider.md +53 -1
- package/docs/docs.json +21 -1
- package/docs/environment-variables.md +5 -3
- package/docs/extensions.md +172 -10
- package/docs/index.md +1 -1
- package/docs/json.md +3 -3
- package/docs/keybindings.md +7 -6
- package/docs/llama-cpp.md +21 -1
- package/docs/mcp.md +272 -0
- package/docs/message-types.md +22 -4
- package/docs/models-configuration.md +187 -0
- package/docs/models.md +100 -2
- package/docs/nvidia-rtx-llama-cpp.md +96 -0
- package/docs/packages.md +1 -1
- package/docs/providers.md +66 -6
- package/docs/quickstart.md +16 -2
- package/docs/rpc-commands.md +9 -3
- package/docs/rpc.md +3 -1
- package/docs/sdk.md +8 -3
- package/docs/security.md +2 -0
- package/docs/session-format.md +5 -1
- package/docs/sessions.md +1 -1
- package/docs/settings.md +30 -8
- package/docs/terminal-setup.md +14 -0
- package/docs/themes.md +31 -7
- package/docs/tui.md +71 -1
- package/docs/usage.md +2 -2
- package/docs/virtual-models.md +114 -0
- package/docs/windows.md +2 -0
- package/examples/README.md +1 -4
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/built-in-tool-renderer.ts +16 -40
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/jev-router.ts +113 -0
- package/examples/extensions/minimal-mode.ts +28 -101
- package/examples/extensions/overlay-test.ts +2 -2
- package/examples/extensions/plan-mode/index.ts +6 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/index.ts +4 -6
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-client.ts +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/14-codemode-mcp.ts +61 -0
- package/examples/sdk/README.md +2 -1
- package/judge/THIRD_PARTY_NOTICES.md +63 -0
- package/judge/dist/auth.js +169 -123
- package/judge/dist/import.js +36 -30
- package/judge/dist/setup.js +250 -120
- package/judge/manifest.json +1008 -316
- package/judge/{dist/kyrn-judge.js → mu/index.js} +6933 -5995
- package/judge/themes/mu-dark.json +80 -0
- package/judge/themes/mu-light.json +80 -0
- package/kyrn/bin/kyrn-doctor +75 -25
- package/kyrn/bin/kyrn-judge-local +2 -2
- package/kyrn/bin/kyrn-ledger +1 -1
- package/kyrn/bin/mu.mjs +149 -107
- package/package.json +4 -5
- package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +0 -2
- package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
- package/dist/bundle/chunks/chunk-AYFRR3OD.js +0 -2
- package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
- package/dist/bundle/chunks/chunk-FU4XQUSL.js +0 -11
- package/dist/bundle/chunks/chunk-GNYZK6XN.js +0 -2
- package/dist/bundle/chunks/chunk-HEMXN7VJ.js +0 -1653
- package/dist/bundle/chunks/chunk-MVPXOVOJ.js +0 -2
- package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
- package/dist/bundle/chunks/chunk-V7IXECST.js +0 -11
- package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +0 -2
- package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
- package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +0 -5
- package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
- package/dist/bundle/chunks/openai-codex-responses-3UAYOSSR.js +0 -10
- package/dist/bundle/chunks/openai-completions-FIEQGWAH.js +0 -7
- package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +0 -2
- package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +0 -2
- package/dist/bundle/chunks/virtual-modules-V7SXVVLP.js +0 -2
- package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
- package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-json.js +0 -132
- package/dist/modes/interactive/theme/theme-json.js.map +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +0 -361
- package/examples/plugins/pi-example-plugin/README.md +0 -38
- package/examples/plugins/pi-example-plugin/package.json +0 -10
- package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
- package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
- package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
package/kyrn/bin/mu.mjs
CHANGED
|
@@ -94,26 +94,28 @@ export function platformName({ platform, wsl }) {
|
|
|
94
94
|
export function usage(platform) {
|
|
95
95
|
const linkDir = platform === "win32" ? "%USERPROFILE%\\.local\\bin" : "~/.local/bin";
|
|
96
96
|
return [
|
|
97
|
-
"mu
|
|
97
|
+
"mu: a coding agent with a judgment kernel, built on pi.",
|
|
98
98
|
"",
|
|
99
|
-
" mu
|
|
100
|
-
' mu "prompt"
|
|
101
|
-
' mu -p "prompt" one
|
|
102
|
-
" mu -c | -r continue the last session | pick
|
|
103
|
-
" mu setup connect a model (an API key
|
|
104
|
-
" (mu setup --help
|
|
105
|
-
" mu judge <cmd> the local judge (
|
|
106
|
-
" mu ledger [n] [--json]
|
|
107
|
-
" mu import --list | <file>...
|
|
108
|
-
" mu doctor check the installation",
|
|
109
|
-
" mu auth <cmd>
|
|
99
|
+
" mu start a session in the current directory",
|
|
100
|
+
' mu "prompt" start a session with this prompt',
|
|
101
|
+
' mu -p "prompt" run one prompt, print the answer and exit',
|
|
102
|
+
" mu -c | -r continue the last session | pick a session to resume",
|
|
103
|
+
" mu setup connect a model (paste an API key or pick a service) and choose a judge",
|
|
104
|
+
" (see mu setup --help for scripting, reading a key from stdin and the supported services)",
|
|
105
|
+
" mu judge <cmd> manage the local judge, Laya (macOS on Apple silicon): setup | start | stop | status | run",
|
|
106
|
+
" mu ledger [n] [--json] print the judge's verdicts from the last n sessions",
|
|
107
|
+
" mu import --list | <file>... import Claude Code and Codex conversations (mu import --help)",
|
|
108
|
+
" mu doctor check the installation, the judges and the connections",
|
|
109
|
+
" mu auth <cmd> sign-in helper for the desktop app (JSON lines):",
|
|
110
110
|
" status | login <provider> | logout <provider>",
|
|
111
|
-
` mu link | unlink put the
|
|
112
|
-
" mu migrate [--dry-run]
|
|
113
|
-
" mu help | version",
|
|
111
|
+
` mu link | unlink put the mu command on your PATH (${linkDir}) | remove it`,
|
|
112
|
+
" mu migrate [--dry-run] move the old home folder, ~/.kyrn, to ~/.mu (once)",
|
|
113
|
+
" mu help | version show this help | print the version",
|
|
114
114
|
"",
|
|
115
|
-
"Everything else goes to
|
|
116
|
-
"and
|
|
115
|
+
"Everything else goes to pi unchanged: mu --help also shows pi's options,",
|
|
116
|
+
"and mu install|remove|update|list|config manage pi packages.",
|
|
117
|
+
"",
|
|
118
|
+
"Formerly KYRN: the kyrn commands still work.",
|
|
117
119
|
].join("\n");
|
|
118
120
|
}
|
|
119
121
|
|
|
@@ -310,7 +312,7 @@ export function ensureAppView({ platform, app, upstream, fs = realFs }) {
|
|
|
310
312
|
/**
|
|
311
313
|
* Where this mu comes from: "repo", a checkout that runs the TypeScript sources (sourceRuntime), or "package", the
|
|
312
314
|
* npm package mu-agent, which carries pi's bundle (dist/bundle/cli.js) and the judgment layer built to
|
|
313
|
-
* JavaScript (judge/
|
|
315
|
+
* JavaScript (judge/mu/index.js). A checkout without its dependencies is still a checkout.
|
|
314
316
|
*/
|
|
315
317
|
export function layoutOf({ root, platform, exists }) {
|
|
316
318
|
const path = pathFor(platform);
|
|
@@ -326,7 +328,7 @@ export function packageEntries({ root, platform }) {
|
|
|
326
328
|
const path = pathFor(platform);
|
|
327
329
|
return {
|
|
328
330
|
cli: path.join(root, "dist", "bundle", "cli.js"),
|
|
329
|
-
extension: path.join(root, "judge", "
|
|
331
|
+
extension: path.join(root, "judge", "mu", "index.js"),
|
|
330
332
|
auth: path.join(root, "judge", "dist", "auth.js"),
|
|
331
333
|
import: path.join(root, "judge", "dist", "import.js"),
|
|
332
334
|
setup: path.join(root, "judge", "dist", "setup.js"),
|
|
@@ -339,59 +341,45 @@ export function envFilePath({ layout, root, muDir, platform }) {
|
|
|
339
341
|
}
|
|
340
342
|
|
|
341
343
|
/**
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
344
|
+
* Whether a checkout's dependencies are installed: undici, which pi and the judgment layer both depend on, is found
|
|
345
|
+
* the way Node resolves an import: here, then in every parent. A git worktree of this repository kept under the
|
|
346
|
+
* main checkout (as the agent worktrees are) has no node_modules of its own and runs on the main checkout's,
|
|
347
|
+
* exactly as its imports do.
|
|
345
348
|
*/
|
|
346
|
-
export function
|
|
349
|
+
export function dependenciesInstalled({ root, platform, exists }) {
|
|
347
350
|
const path = pathFor(platform);
|
|
348
|
-
// Looked for the way Node resolves an import: here, then in every parent. A git worktree of this repository
|
|
349
|
-
// kept under the main checkout (as the agent worktrees are) has no node_modules of its own and runs on the
|
|
350
|
-
// main checkout's, exactly as its imports do.
|
|
351
351
|
for (let dir = root; ; dir = path.dirname(dir)) {
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
if (path.dirname(dir) === dir) return undefined;
|
|
352
|
+
if (exists(path.join(dir, "node_modules", "undici", "package.json"))) return true;
|
|
353
|
+
if (path.dirname(dir) === dir) return false;
|
|
355
354
|
}
|
|
356
355
|
}
|
|
357
356
|
|
|
358
|
-
function tsxEntry(dir, path, exists, readFile) {
|
|
359
|
-
let bin;
|
|
360
|
-
try {
|
|
361
|
-
bin = JSON.parse(readFile(path.join(dir, "package.json"))).bin;
|
|
362
|
-
} catch {
|
|
363
|
-
return undefined;
|
|
364
|
-
}
|
|
365
|
-
const relative = typeof bin === "string" ? bin : bin?.tsx;
|
|
366
|
-
if (typeof relative !== "string") return undefined;
|
|
367
|
-
const entry = path.join(dir, ...relative.split("/").filter((part) => part && part !== "."));
|
|
368
|
-
return exists(entry) ? entry : undefined;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
357
|
export function installHint({ root, platform }) {
|
|
372
358
|
const steps = [`cd ${root}`, "npm ci --ignore-scripts", "npm run hydrate:model-data"];
|
|
373
359
|
// Windows PowerShell 5 has no `&&`.
|
|
374
360
|
return platform === "win32"
|
|
375
|
-
? `mu's dependencies
|
|
376
|
-
: `mu's dependencies
|
|
361
|
+
? `mu's dependencies aren't installed. Run:\n${steps.map((step) => ` ${step}`).join("\n")}`
|
|
362
|
+
: `mu's dependencies aren't installed. Run: ${steps.join(" && ")}`;
|
|
377
363
|
}
|
|
378
364
|
|
|
365
|
+
/** What mu says on a Node that does not strip TypeScript types, which a checkout cannot run on. */
|
|
366
|
+
const NO_TYPE_STRIPPING =
|
|
367
|
+
"mu runs a source checkout's TypeScript with Node's built-in type stripping (on by default since Node 22.18), but this Node doesn't strip types. Use Node 22.19 or newer.";
|
|
368
|
+
|
|
379
369
|
/**
|
|
380
|
-
* Node's arguments for running a checkout's TypeScript, up to the entry file.
|
|
381
|
-
*
|
|
382
|
-
* (packages/coding-agent/src/experimental/source-resolver.ts: each workspace package
|
|
383
|
-
* tsconfig.json's paths say) and Node's compile cache (compile-cache.mjs)
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
* types (`stripsTypes` false; an Electron that runs mu as Node may not), or a checkout from before the resolver,
|
|
387
|
-
* still goes through tsx. tsx is one of the checkout's dependencies either way: without it they are not installed.
|
|
370
|
+
* Node's arguments for running a checkout's TypeScript, up to the entry file. Node strips the types itself (on by
|
|
371
|
+
* default from 22.18, in both Electrons the desktop app runs mu with too) and runs the sources as they are, with
|
|
372
|
+
* pi's own source resolver (packages/coding-agent/src/experimental/source-resolver.ts: each workspace package
|
|
373
|
+
* resolves to its sources, as tsconfig.json's paths say) and Node's compile cache (compile-cache.mjs), the way pi
|
|
374
|
+
* 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 import.
|
|
388
376
|
*/
|
|
389
|
-
export function sourceRuntime({ root, platform, stripsTypes, exists
|
|
377
|
+
export function sourceRuntime({ root, platform, stripsTypes, exists }) {
|
|
390
378
|
const path = pathFor(platform);
|
|
391
|
-
|
|
392
|
-
if (!
|
|
379
|
+
if (!stripsTypes) return { error: NO_TYPE_STRIPPING };
|
|
380
|
+
if (!dependenciesInstalled({ root, platform, exists })) return { error: installHint({ root, platform }) };
|
|
393
381
|
const resolver = path.join(root, "packages", "coding-agent", "src", "experimental", "source-resolver.ts");
|
|
394
|
-
if (!
|
|
382
|
+
if (!exists(resolver)) return { error: `pi's source resolver is missing from this checkout (${resolver})` };
|
|
395
383
|
// As URLs: `--import` reads a Windows path such as C:\... as a URL whose scheme is c:.
|
|
396
384
|
const url = (file) => pathToFileURL(file, { windows: platform === "win32" }).href;
|
|
397
385
|
return {
|
|
@@ -442,10 +430,10 @@ export function localJudgeSupport({ platform, env, wsl = false }) {
|
|
|
442
430
|
runs: false,
|
|
443
431
|
url,
|
|
444
432
|
message: [
|
|
445
|
-
`The local judge (Laya) is a Core ML sidecar
|
|
446
|
-
"mu works without it:
|
|
447
|
-
"the desktop app
|
|
448
|
-
"
|
|
433
|
+
`The local judge (Laya) is a Core ML sidecar that runs only on macOS on Apple silicon, not on ${where}.`,
|
|
434
|
+
"mu works without it: Jev answers by default (free on OpenCode Zen, or with your own key: mu setup), or set an LLM judge in mu.json.",
|
|
435
|
+
"A local judge for the desktop app is in progress. Without a judge, decision points use their fallbacks.",
|
|
436
|
+
"To use a server that implements the same API (GET /health, POST /evaluate), set:",
|
|
449
437
|
" MU_LOCAL_JUDGE_URL=http://host:port",
|
|
450
438
|
].join("\n"),
|
|
451
439
|
};
|
|
@@ -458,6 +446,42 @@ export function launchStrategy({ platform, env, canExec }) {
|
|
|
458
446
|
return "exec";
|
|
459
447
|
}
|
|
460
448
|
|
|
449
|
+
/** How the judgment layer's extension joins pi's arguments: in front for a session, never in front of pi's own
|
|
450
|
+
* commands (PI_COMMANDS), which pi reads as its first argument — an -e before them would turn them into a prompt.
|
|
451
|
+
* The judgment layer never runs for them, so its extension stays out of their way. */
|
|
452
|
+
function judgeArgs({ argv, layout, root, platform, agentDir, readFile }) {
|
|
453
|
+
if (PI_COMMANDS.has(argv[0])) return [];
|
|
454
|
+
const path = pathFor(platform);
|
|
455
|
+
const extension =
|
|
456
|
+
layout === "package"
|
|
457
|
+
? ["-e", packageEntries({ root, platform }).extension]
|
|
458
|
+
: ["-e", path.join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts")];
|
|
459
|
+
return [...extension, ...themeArgs({ argv, layout, root, platform, agentDir, readFile })];
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** mu's own terminal themes, beside the judgment layer's files. */
|
|
463
|
+
export function themesDir({ layout, root, platform }) {
|
|
464
|
+
const path = pathFor(platform);
|
|
465
|
+
return layout === "package" ? path.join(root, "judge", "themes") : path.join(root, "packages", "kyrn-judge", "themes");
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* An interactive session gets mu's themes (mu-light and mu-dark, which /settings then lists beside pi's) and, while the
|
|
470
|
+
* person has chosen no theme of their own, starts in them: light or dark as the terminal is. A theme chosen in
|
|
471
|
+
* /settings is saved in settings.json and wins; so does --use-theme. Print and RPC modes draw nothing and get neither.
|
|
472
|
+
*/
|
|
473
|
+
function themeArgs({ argv, layout, root, platform, agentDir, readFile }) {
|
|
474
|
+
if (argv.includes("--mode") || argv.includes("-p") || argv.includes("--print")) return [];
|
|
475
|
+
const args = ["--theme", themesDir({ layout, root, platform })];
|
|
476
|
+
if (argv.includes("--use-theme") || !agentDir || !readFile) return args;
|
|
477
|
+
let chosen = false;
|
|
478
|
+
try {
|
|
479
|
+
const settings = JSON.parse(readFile(pathFor(platform).join(agentDir, "settings.json")));
|
|
480
|
+
chosen = typeof settings?.theme === "string" && settings.theme !== "";
|
|
481
|
+
} catch {}
|
|
482
|
+
return chosen ? args : [...args, "--use-theme", "mu-light/mu-dark"];
|
|
483
|
+
}
|
|
484
|
+
|
|
461
485
|
/**
|
|
462
486
|
* Everything about starting pi, decided without touching anything: the command, its arguments as an array
|
|
463
487
|
* (never a shell string) and the child's whole environment.
|
|
@@ -484,16 +508,11 @@ export function planLaunch({
|
|
|
484
508
|
if (!fs.exists(files.extension)) {
|
|
485
509
|
return { error: `This mu-agent package is incomplete (${files.extension} is missing). Reinstall it: npm i -g mu-agent` };
|
|
486
510
|
}
|
|
487
|
-
entry = [files.cli
|
|
511
|
+
entry = [files.cli];
|
|
488
512
|
} else {
|
|
489
|
-
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists
|
|
513
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
|
|
490
514
|
if (runtime.error) return { error: runtime.error };
|
|
491
|
-
entry = [
|
|
492
|
-
...runtime.args,
|
|
493
|
-
path.join(root, "packages", "coding-agent", "src", "experimental", "cli.ts"),
|
|
494
|
-
"-e",
|
|
495
|
-
path.join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts"),
|
|
496
|
-
];
|
|
515
|
+
entry = [...runtime.args, path.join(root, "packages", "coding-agent", "src", "cli.ts")];
|
|
497
516
|
}
|
|
498
517
|
|
|
499
518
|
const muDir = muHome({ home, platform, isDir: fs.isDir });
|
|
@@ -511,7 +530,7 @@ export function planLaunch({
|
|
|
511
530
|
const parsed = parseEnvFile(envText);
|
|
512
531
|
fromFile = envFileAdditions({ env, entries: parsed.entries, platform });
|
|
513
532
|
// Line numbers only: the text of a line that did not parse may well be a secret.
|
|
514
|
-
if (parsed.problems.length > 0) notes.push(`mu: .env: skipped line ${parsed.problems.join(", ")} (
|
|
533
|
+
if (parsed.problems.length > 0) notes.push(`mu: .env: skipped ${parsed.problems.length === 1 ? "line" : "lines"} ${parsed.problems.join(", ")} (expected KEY=VALUE)`);
|
|
515
534
|
}
|
|
516
535
|
|
|
517
536
|
const childEnv = {};
|
|
@@ -534,14 +553,14 @@ export function planLaunch({
|
|
|
534
553
|
if (support.runs) startJudge = true;
|
|
535
554
|
else if (!support.url) {
|
|
536
555
|
notes.push(
|
|
537
|
-
`mu: the configuration asks for the local judge (
|
|
556
|
+
`mu: the configuration asks for the local judge (Laya), which runs on macOS only; on ${platformName({ platform, wsl })} its decision points use the next judge or their fallbacks (mu judge status)`,
|
|
538
557
|
);
|
|
539
558
|
}
|
|
540
559
|
}
|
|
541
560
|
|
|
542
561
|
return {
|
|
543
562
|
command: execPath,
|
|
544
|
-
args: [...entry, ...argv],
|
|
563
|
+
args: [...entry, ...judgeArgs({ argv, layout, root, platform, agentDir, readFile: fs.readFile }), ...argv],
|
|
545
564
|
env: childEnv,
|
|
546
565
|
strategy: launchStrategy({ platform, env, canExec }),
|
|
547
566
|
layout,
|
|
@@ -550,7 +569,7 @@ export function planLaunch({
|
|
|
550
569
|
agentDir,
|
|
551
570
|
startJudge,
|
|
552
571
|
notes,
|
|
553
|
-
preface: argv[0] === "-h" || argv[0] === "--help" ? `${usage(platform)}\n\
|
|
572
|
+
preface: argv[0] === "-h" || argv[0] === "--help" ? `${usage(platform)}\n\npi's help (mu passes all of this through):\n` : undefined,
|
|
554
573
|
};
|
|
555
574
|
}
|
|
556
575
|
|
|
@@ -560,8 +579,7 @@ export function planLaunch({
|
|
|
560
579
|
* Node flags that process starts with, pi's arguments (the judgment layer, then `argv`) and its whole environment.
|
|
561
580
|
* The app's pi and the command line's are then one: the same files, settings, sign-ins and keys.
|
|
562
581
|
*
|
|
563
|
-
* A checkout runs
|
|
564
|
-
* tsx cannot be put in front of a module another program imports. Returns { error } otherwise.
|
|
582
|
+
* A checkout runs there as it runs on the command line (sourceRuntime). Returns { error } when pi cannot run.
|
|
565
583
|
*/
|
|
566
584
|
export function planHost({ platform, env, argv, root, home, fs, wsl = false, stripsTypes = true }) {
|
|
567
585
|
const path = pathFor(platform);
|
|
@@ -581,28 +599,22 @@ export function planHost({ platform, env, argv, root, home, fs, wsl = false, str
|
|
|
581
599
|
...common,
|
|
582
600
|
module: path.join(root, "dist", "bundle", "index.js"),
|
|
583
601
|
execArgv: [],
|
|
584
|
-
args: [
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
const resolver = path.join(root, "packages", "coding-agent", "src", "experimental", "source-resolver.ts");
|
|
588
|
-
if (!stripsTypes || !fs.exists(resolver)) {
|
|
589
|
-
return {
|
|
590
|
-
error: `pi's sources run inside another program only on a Node that strips TypeScript types itself (22.18 or newer), with pi's source resolver (${resolver})`,
|
|
602
|
+
args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
|
|
591
603
|
};
|
|
592
604
|
}
|
|
593
|
-
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists
|
|
605
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
|
|
594
606
|
if (runtime.error) return { error: runtime.error };
|
|
595
607
|
return {
|
|
596
608
|
...common,
|
|
597
609
|
module: path.join(root, "packages", "coding-agent", "src", "index.ts"),
|
|
598
610
|
execArgv: runtime.args,
|
|
599
|
-
args: [
|
|
611
|
+
args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
|
|
600
612
|
};
|
|
601
613
|
}
|
|
602
614
|
|
|
603
615
|
/** What mu says when the local judge does not come up. */
|
|
604
616
|
const LOCAL_JUDGE_NOT_STARTED =
|
|
605
|
-
"mu: the local judge
|
|
617
|
+
"mu: the local judge (Laya) didn't start; decision points use the next judge or their fallbacks. Run mu judge status for details.";
|
|
606
618
|
|
|
607
619
|
/** The part of the preparation that is files: the app view of a checkout, mu's agent folder, the configuration's notes. */
|
|
608
620
|
function prepareFiles({ plan, platform, root, err }) {
|
|
@@ -671,7 +683,7 @@ export function planAuth({ platform, env, argv, root, home, execPath, fs, canExe
|
|
|
671
683
|
}
|
|
672
684
|
entry = [auth];
|
|
673
685
|
} else {
|
|
674
|
-
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists
|
|
686
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
|
|
675
687
|
if (runtime.error) return { error: runtime.error };
|
|
676
688
|
entry = [...runtime.args, path.join(root, "packages", "kyrn-judge", "src", "auth", "main.ts")];
|
|
677
689
|
}
|
|
@@ -705,8 +717,7 @@ export function planJudge({ platform, env, argv, bin, wsl = false }) {
|
|
|
705
717
|
/**
|
|
706
718
|
* `mu import`: Claude Code and Codex conversations into mu's sessions (packages/kyrn-judge/src/import). The importer
|
|
707
719
|
* needs nothing but Node: the npm package runs its build, judge/dist/import.js, and a checkout its TypeScript with
|
|
708
|
-
* Node's own type stripping (on by default from 22.18).
|
|
709
|
-
* an Electron that runs mu as Node may not) takes the sources through tsx, as pi runs in a checkout.
|
|
720
|
+
* Node's own type stripping (on by default from 22.18).
|
|
710
721
|
*/
|
|
711
722
|
export function planImport({ platform, env, argv, root, home, execPath, fs, stripsTypes = true }) {
|
|
712
723
|
const path = pathFor(platform);
|
|
@@ -720,12 +731,8 @@ export function planImport({ platform, env, argv, root, home, execPath, fs, stri
|
|
|
720
731
|
} else {
|
|
721
732
|
const source = path.join(root, "packages", "kyrn-judge", "src", "import", "cli.ts");
|
|
722
733
|
if (!fs.exists(source)) return { error: `mu import is missing from this checkout (${source})` };
|
|
723
|
-
if (stripsTypes)
|
|
724
|
-
|
|
725
|
-
const tsx = resolveTsx({ root, platform, exists: fs.exists, readFile: fs.readFile });
|
|
726
|
-
if (!tsx) return { error: installHint({ root, platform }) };
|
|
727
|
-
entry = [tsx, "--tsconfig", path.join(root, "tsconfig.json"), source];
|
|
728
|
-
}
|
|
734
|
+
if (!stripsTypes) return { error: NO_TYPE_STRIPPING };
|
|
735
|
+
entry = ["--disable-warning=ExperimentalWarning", source];
|
|
729
736
|
}
|
|
730
737
|
const agentDir = agentDirFor({ env, muDir: muHome({ home, platform, isDir: fs.isDir }), platform });
|
|
731
738
|
const childEnv = {};
|
|
@@ -763,6 +770,8 @@ export const MODEL_KEY_VARIABLES = [
|
|
|
763
770
|
"ANTHROPIC_AUTH_TOKEN",
|
|
764
771
|
"ANTHROPIC_OAUTH_TOKEN",
|
|
765
772
|
"ANTHROPIC_API_KEY",
|
|
773
|
+
// Anthropic's workload identity federation needs three variables together; its rule id stands for them.
|
|
774
|
+
"ANTHROPIC_FEDERATION_RULE_ID",
|
|
766
775
|
"ANT_LING_API_KEY",
|
|
767
776
|
"QWEN_TOKEN_PLAN_API_KEY",
|
|
768
777
|
"QWEN_TOKEN_PLAN_CN_API_KEY",
|
|
@@ -816,7 +825,7 @@ export function planSetup({ platform, env, argv, root, home, execPath, fs, strip
|
|
|
816
825
|
}
|
|
817
826
|
entry = [setup];
|
|
818
827
|
} else {
|
|
819
|
-
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists
|
|
828
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
|
|
820
829
|
if (runtime.error) return { error: runtime.error };
|
|
821
830
|
entry = [...runtime.args, path.join(root, "packages", "kyrn-judge", "src", "setup", "main.ts")];
|
|
822
831
|
}
|
|
@@ -846,8 +855,41 @@ export function planSetup({ platform, env, argv, root, home, execPath, fs, strip
|
|
|
846
855
|
return { command: execPath, args: [...entry, ...args], env: childEnv, strategy: "spawn", agentDir, keyGiven: key !== undefined };
|
|
847
856
|
}
|
|
848
857
|
|
|
849
|
-
/** pi's own commands: none of them starts a session. */
|
|
850
|
-
const PI_COMMANDS = new Set(["install", "remove", "uninstall", "update", "list", "config", "auth"]);
|
|
858
|
+
/** pi's own commands, read from its first argument: none of them starts a session. */
|
|
859
|
+
const PI_COMMANDS = new Set(["install", "remove", "uninstall", "update", "list", "config", "auth", "mcp"]);
|
|
860
|
+
|
|
861
|
+
/** Options of `pi mcp add` that take a value (extensions/mcp/cli.ts); the rest are flags. */
|
|
862
|
+
const MCP_ADD_VALUES = new Set([
|
|
863
|
+
"--url",
|
|
864
|
+
"--env",
|
|
865
|
+
"--cwd",
|
|
866
|
+
"--header",
|
|
867
|
+
"--bearer-token-env-var",
|
|
868
|
+
"--oauth-client-id",
|
|
869
|
+
"--oauth-client-secret",
|
|
870
|
+
"--oauth-callback-port",
|
|
871
|
+
"--oauth-client-name",
|
|
872
|
+
"--exposure",
|
|
873
|
+
"--description",
|
|
874
|
+
]);
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* `mu mcp add` without `--exposure`: the server's tools are `deferred`, loaded by tool_search when a task needs them,
|
|
878
|
+
* instead of pi's default `codemode`, which reaches them only from scripts. Like pi, the options end at `--` or at the
|
|
879
|
+
* second positional argument; what follows belongs to the server's command.
|
|
880
|
+
*/
|
|
881
|
+
export function mcpAddDefaults(argv) {
|
|
882
|
+
if (argv[0] !== "mcp" || argv[1] !== "add") return argv;
|
|
883
|
+
let positionals = 0;
|
|
884
|
+
for (let index = 2; index < argv.length && positionals < 2; index++) {
|
|
885
|
+
const arg = argv[index];
|
|
886
|
+
if (arg === "--") break;
|
|
887
|
+
if (arg === "--exposure") return argv;
|
|
888
|
+
if (MCP_ADD_VALUES.has(arg)) index++;
|
|
889
|
+
else if (!arg.startsWith("-")) positionals++;
|
|
890
|
+
}
|
|
891
|
+
return [...argv.slice(0, 2), "--exposure", "deferred", ...argv.slice(2)];
|
|
892
|
+
}
|
|
851
893
|
/** Options for a run without a person (-p, --mode rpc), one that ends at once, or one that names its model itself. */
|
|
852
894
|
const NO_SETUP_FLAGS = new Set([
|
|
853
895
|
"-p",
|
|
@@ -988,7 +1030,7 @@ export function planLink({ platform, env, home, bin, argv, fs }) {
|
|
|
988
1030
|
return {
|
|
989
1031
|
action: "refuse",
|
|
990
1032
|
errors: [
|
|
991
|
-
`${link} already exists and is not this mu
|
|
1033
|
+
`${link} already exists and is not this mu, so it was left alone. To use another folder: MU_LINK_DIR=<dir> mu link`,
|
|
992
1034
|
],
|
|
993
1035
|
};
|
|
994
1036
|
}
|
|
@@ -1016,7 +1058,7 @@ export function planLink({ platform, env, home, bin, argv, fs }) {
|
|
|
1016
1058
|
if (windows && /[^\x00-\x7f]/.test(content)) {
|
|
1017
1059
|
notes.push(
|
|
1018
1060
|
"Note: the path from that folder to this repository has non-ASCII characters in it, and cmd reads a batch file in the",
|
|
1019
|
-
"console's code page. If
|
|
1061
|
+
"console's code page. If mu then can't find its target, choose a folder on the same drive (MU_LINK_DIR), or put",
|
|
1020
1062
|
`${bin} on your PATH instead.`,
|
|
1021
1063
|
);
|
|
1022
1064
|
}
|
|
@@ -1185,8 +1227,8 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
|
|
|
1185
1227
|
return 0;
|
|
1186
1228
|
}
|
|
1187
1229
|
if (fs.exists(next) || fs.isLink(next)) {
|
|
1188
|
-
err(`${next} already exists, so nothing was moved.
|
|
1189
|
-
err("look at both
|
|
1230
|
+
err(`${next} already exists, so nothing was moved. mu never merges or overwrites two home folders:`);
|
|
1231
|
+
err("look at both and decide which one to keep.");
|
|
1190
1232
|
return 1;
|
|
1191
1233
|
}
|
|
1192
1234
|
// Whatever is running would write into the gap between the rename and the link, and split the home in two.
|
|
@@ -1195,10 +1237,10 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
|
|
|
1195
1237
|
try {
|
|
1196
1238
|
pid = Number.parseInt(fs.readFile(path.join(old, "local-judge", "judge.pid")).trim(), 10);
|
|
1197
1239
|
} catch {}
|
|
1198
|
-
if (pid > 0 && alive(pid)) busy.push(` the local judge (pid ${pid}). Stop it
|
|
1240
|
+
if (pid > 0 && alive(pid)) busy.push(` the local judge (pid ${pid}). Stop it with mu judge stop`);
|
|
1199
1241
|
const found = findBusy({ platform, old, run, self });
|
|
1200
1242
|
if (!found) {
|
|
1201
|
-
err("Nothing was moved: the list of running processes
|
|
1243
|
+
err("Nothing was moved: mu couldn't read the list of running processes (tasklist, powershell), so it can't tell whether mu is still running.");
|
|
1202
1244
|
return 1;
|
|
1203
1245
|
}
|
|
1204
1246
|
const list = (pids) => pids.join(" ");
|
|
@@ -1232,7 +1274,7 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
|
|
|
1232
1274
|
out(`renamed ${path.join(next, config)} -> mu.json`);
|
|
1233
1275
|
}
|
|
1234
1276
|
out(`linked ${old} -> ${next} (paths stored from before the rename keep working)`);
|
|
1235
|
-
out("
|
|
1277
|
+
out("To check it, run mu doctor");
|
|
1236
1278
|
return 0;
|
|
1237
1279
|
}
|
|
1238
1280
|
|
|
@@ -1314,7 +1356,7 @@ function handOver({ command, args, env, strategy }) {
|
|
|
1314
1356
|
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(signal, () => relay(signal));
|
|
1315
1357
|
if (process.platform === "win32") process.on("SIGBREAK", () => {});
|
|
1316
1358
|
child.on("error", (error) => {
|
|
1317
|
-
err(`mu:
|
|
1359
|
+
err(`mu: couldn't start ${command}: ${error.message}`);
|
|
1318
1360
|
resolve(1);
|
|
1319
1361
|
});
|
|
1320
1362
|
child.on("exit", (code, signal) => resolve(code ?? 128 + (osConstants.signals[signal] ?? 0)));
|
|
@@ -1411,7 +1453,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1411
1453
|
out(await response.text());
|
|
1412
1454
|
return 0;
|
|
1413
1455
|
} catch {
|
|
1414
|
-
out(`
|
|
1456
|
+
out(`The local judge server isn't answering at ${plan.url}. Check that it's running.`);
|
|
1415
1457
|
return 1;
|
|
1416
1458
|
}
|
|
1417
1459
|
}
|
|
@@ -1436,7 +1478,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1436
1478
|
return handOver({ command: plan.command, args: plan.args, env: plan.env, strategy });
|
|
1437
1479
|
}
|
|
1438
1480
|
// What the session gets, when there is one: after a `mu setup` that ends in "start mu now", a plain session.
|
|
1439
|
-
let sessionArgv = argv;
|
|
1481
|
+
let sessionArgv = mcpAddDefaults(argv);
|
|
1440
1482
|
if (command === "setup") {
|
|
1441
1483
|
const plan = planSetup({
|
|
1442
1484
|
platform,
|
|
@@ -1508,7 +1550,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1508
1550
|
return 0;
|
|
1509
1551
|
}
|
|
1510
1552
|
// Asked before `version` too, as it always was: a checkout without its dependencies says so at the first command.
|
|
1511
|
-
if (layout === "repo" && !
|
|
1553
|
+
if (layout === "repo" && !dependenciesInstalled({ root, platform, exists: existsSync })) {
|
|
1512
1554
|
err(installHint({ root, platform }));
|
|
1513
1555
|
return 1;
|
|
1514
1556
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-agent",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "mu: a coding agent that
|
|
3
|
+
"version": "0.1.10",
|
|
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": {
|
|
7
7
|
"mu": "kyrn/bin/mu.mjs"
|
|
@@ -33,13 +33,12 @@
|
|
|
33
33
|
"node": ">=22.19.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@earendil-works/chord": "0.87.1",
|
|
37
36
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
38
37
|
"jiti": "2.7.0"
|
|
39
38
|
},
|
|
40
39
|
"muBuild": {
|
|
41
|
-
"pi": "
|
|
40
|
+
"pi": "1.3.0",
|
|
42
41
|
"judge": "0.1.0",
|
|
43
|
-
"commit": "
|
|
42
|
+
"commit": "84e66744e"
|
|
44
43
|
}
|
|
45
44
|
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
-
import{buildCopilotDynamicHeaders,hasCopilotVisionInput}from"./chunk-PGXDEOVV.js";import{Anthropic}from"./chunk-DTD7JQ7Y.js";import{retryProviderRequest}from"./chunk-XNGRGP62.js";import{adjustMaxTokensForThinking,buildBaseOptions,clampMaxTokensToContext,getJsonSchemaToolParameters,getPiUserAgent,resolveJsonSchemaStrictSampling,transformMessages}from"./chunk-GNYZK6XN.js";import{sanitizeSurrogates}from"./chunk-L2ZPNLYD.js";import{headersToRecord}from"./chunk-UTB4DTYQ.js";import{getProviderEnvValue}from"./chunk-DRQDKNXA.js";import{parseJsonWithRepair,parseStreamingJson}from"./chunk-TRDNDS6A.js";import{calculateCost,getCurrentTools,getDeclaredTools,getInitialSystemMessage,getSystemMessageText,hasToolRedefinitions,renderSystemMessageUpdate,resolveTranscript}from"./chunk-FU4XQUSL.js";import{AssistantMessageEventStream,appendAssistantMessageDiagnostic}from"./chunk-A3JYRWB6.js";import"./chunk-4L3WN2XY.js";function resolveCacheRetention(cacheRetention,env){return cacheRetention||(getProviderEnvValue("PI_CACHE_RETENTION",env)==="long"?"long":"short")}function getCacheControl(model,cacheRetention,env){let retention=resolveCacheRetention(cacheRetention,env);if(retention==="none")return{retention};let ttl=retention==="long"&&getAnthropicCompat(model).supportsLongCacheRetention?"1h":void 0;return{retention,cacheControl:{type:"ephemeral",...ttl&&{ttl}}}}var claudeCodeVersion="2.1.280",claudeCodeTools=["Read","Write","Edit","Bash","Grep","Glob","AskUserQuestion","EnterPlanMode","ExitPlanMode","KillShell","NotebookEdit","Skill","Task","TaskOutput","TodoWrite","WebFetch","WebSearch"],ccToolLookup=new Map(claudeCodeTools.map(t=>[t.toLowerCase(),t])),toClaudeCodeName=name=>ccToolLookup.get(name.toLowerCase())??name,fromClaudeCodeName=(name,tools)=>{if(tools&&tools.length>0){let lowerName=name.toLowerCase(),matchedTool=tools.find(tool=>tool.name.toLowerCase()===lowerName);if(matchedTool)return matchedTool.name}return name};function convertContentBlocks(content){if(!content.some(c=>c.type==="image"))return sanitizeSurrogates(content.map(c=>c.text).join(`
|
|
3
|
-
`));let blocks=content.map(block=>block.type==="text"?{type:"text",text:sanitizeSurrogates(block.text)}:{type:"image",source:{type:"base64",media_type:block.mimeType,data:block.data}});return blocks.some(b=>b.type==="text")||blocks.unshift({type:"text",text:"(see attached image)"}),blocks}var FINE_GRAINED_TOOL_STREAMING_BETA="fine-grained-tool-streaming-2025-05-14",INTERLEAVED_THINKING_BETA="interleaved-thinking-2025-05-14",SERVER_SIDE_FALLBACK_BETA="server-side-fallback-2026-07-01",MID_CONVERSATION_OUTPUT_CONFIG_BETA="mid-conversation-output-config-2026-07-01",THINKING_BINDING_CONTROLS_BETA="thinking-binding-controls-2026-08-01",MID_CONVERSATION_TOOL_CHANGES_BETA="mid-conversation-tool-changes-2026-07-01",DEFERRED_TOOL_PLACEHOLDER={name:"__pi_deferred_placeholder__",description:"Reserved placeholder. Never available. Never call this.",input_schema:{type:"object",properties:{},required:[]},defer_loading:!0};function shouldUseServerSideFallbackBeta(model){return(model.compat?.allowedFallbackModels?.length??0)>0}function getAnthropicCompat(model){let isOpenRouter=model.provider==="openrouter"||model.baseUrl.includes("openrouter.ai");return{supportsEagerToolInputStreaming:model.compat?.supportsEagerToolInputStreaming??!0,supportsLongCacheRetention:model.compat?.supportsLongCacheRetention??!0,sendSessionAffinityHeaders:model.compat?.sendSessionAffinityHeaders??isOpenRouter,sessionAffinityFormat:model.compat?.sessionAffinityFormat??(isOpenRouter?"openrouter":void 0),supportsCacheControlOnTools:model.compat?.supportsCacheControlOnTools??!0,supportsTemperature:model.compat?.supportsTemperature??!0,allowEmptySignature:model.compat?.allowEmptySignature??!1,supportsStrictTools:model.compat?.supportsStrictTools??!1,supportsMidConvoSystemMessages:model.compat?.supportsMidConvoSystemMessages??!1,supportsMidConvoToolChanges:model.compat?.supportsMidConvoToolChanges??!1}}function mergeHeaders(...headerSources){let merged={};for(let headers of headerSources)headers&&Object.assign(merged,headers);return merged}function mergeClientHeaders(...headerSources){return mergeHeaders({"User-Agent":getPiUserAgent()},...headerSources)}function hasHeader(headers,name){if(!headers)return!1;let expected=name.toLowerCase();for(let[key,value]of Object.entries(headers))if(key.toLowerCase()===expected&&value!==null&&value.trim().length>0)return!0;return!1}function assertRequestAuth(provider,apiKey,headers){if(!apiKey&&!(hasHeader(headers,"authorization")||hasHeader(headers,"x-api-key")||hasHeader(headers,"cf-aig-authorization")))throw new Error(`No API key for provider: ${provider}`)}var ANTHROPIC_MESSAGE_EVENTS=new Set(["message_start","message_delta","message_stop","content_block_start","content_block_delta","content_block_stop"]);function flushSseEvent(state){if(!state.event&&state.data.length===0)return null;let event={event:state.event,data:state.data.join(`
|
|
4
|
-
`),raw:[...state.raw]};return state.event=null,state.data=[],state.raw=[],event}function decodeSseLine(line,state){if(line==="")return flushSseEvent(state);if(state.raw.push(line),line.startsWith(":"))return null;let delimiterIndex=line.indexOf(":"),fieldName=delimiterIndex===-1?line:line.slice(0,delimiterIndex),value=delimiterIndex===-1?"":line.slice(delimiterIndex+1);return value.startsWith(" ")&&(value=value.slice(1)),fieldName==="event"?state.event=value:fieldName==="data"&&state.data.push(value),null}function nextLineBreakIndex(text){let carriageReturnIndex=text.indexOf("\r"),newlineIndex=text.indexOf(`
|
|
5
|
-
`);return carriageReturnIndex===-1?newlineIndex:newlineIndex===-1?carriageReturnIndex:Math.min(carriageReturnIndex,newlineIndex)}function consumeLine(text){let lineBreakIndex=nextLineBreakIndex(text);if(lineBreakIndex===-1)return null;let nextIndex=lineBreakIndex+1;return text[lineBreakIndex]==="\r"&&text[nextIndex]===`
|
|
6
|
-
`&&(nextIndex+=1),{line:text.slice(0,lineBreakIndex),rest:text.slice(nextIndex)}}async function*iterateSseMessages(body,signal){let reader=body.getReader(),decoder=new TextDecoder,state={event:null,data:[],raw:[]},buffer="";try{for(;;){if(signal?.aborted)throw new Error("Request was aborted");let{value,done}=await reader.read();if(done)break;buffer+=decoder.decode(value,{stream:!0});let consumed2=consumeLine(buffer);for(;consumed2;){buffer=consumed2.rest;let event=decodeSseLine(consumed2.line,state);event&&(yield event),consumed2=consumeLine(buffer)}}buffer+=decoder.decode();let consumed=consumeLine(buffer);for(;consumed;){buffer=consumed.rest;let event=decodeSseLine(consumed.line,state);event&&(yield event),consumed=consumeLine(buffer)}if(buffer.length>0){let event=decodeSseLine(buffer,state);event&&(yield event)}let trailingEvent=flushSseEvent(state);trailingEvent&&(yield trailingEvent)}finally{reader.releaseLock()}}async function*iterateAnthropicEvents(response,signal){if(!response.body)throw new Error("Attempted to iterate over an Anthropic response with no body");let sawMessageStart=!1,sawMessageEnd=!1;for await(let sse of iterateSseMessages(response.body,signal)){if(sse.event==="error")throw new Error(sse.data);if(ANTHROPIC_MESSAGE_EVENTS.has(sse.event??""))try{let event=parseJsonWithRepair(sse.data);event.type==="message_start"?sawMessageStart=!0:event.type==="message_stop"&&(sawMessageEnd=!0),yield event}catch(error){let message=error instanceof Error?error.message:String(error);throw new Error(`Could not parse Anthropic SSE event ${sse.event}: ${message}; data=${sse.data}; raw=${sse.raw.join("\\n")}`)}}if(sawMessageStart&&!sawMessageEnd)throw new Error("Anthropic stream ended before message_stop")}var stream=(model,context,options)=>{let stream2=new AssistantMessageEventStream,normalizedContext=resolveTranscript(context,getAnthropicCompat(model).supportsMidConvoSystemMessages),currentTools=getCurrentTools(normalizedContext.messages);return(async()=>{let providerThinkingLevel=model.compat?.supportsMidConvoEffort?options?.effort??"high":void 0,output={role:"assistant",content:[],api:model.api,provider:model.provider,model:model.id,...providerThinkingLevel===void 0?{}:{providerThinkingLevel},usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};try{let client,isOAuth,usageModel=model,inputTransformations;if(options?.client)client=options.client,isOAuth=!1;else{let apiKey=options?.apiKey;assertRequestAuth(model.provider,apiKey,options?.headers);let copilotDynamicHeaders;if(model.provider==="github-copilot"){let hasImages=hasCopilotVisionInput(normalizedContext.messages);copilotDynamicHeaders=buildCopilotDynamicHeaders({messages:normalizedContext.messages,hasImages})}let cacheSessionId=resolveCacheRetention(options?.cacheRetention,options?.env)==="none"?void 0:options?.sessionId,created=createClient(model,apiKey,options?.headers,options?.fetch,copilotDynamicHeaders,cacheSessionId);client=created.client,isOAuth=created.isOAuthToken}let params=buildParams(model,normalizedContext,isOAuth,options),nextParams=await options?.onPayload?.(params,model);nextParams!==void 0&&(params={...nextParams,stream:!0});let requestOptions={...options?.signal?{signal:options.signal}:{},...options?.timeoutMs!==void 0?{timeout:options.timeoutMs}:{},maxRetries:0},response=await retryProviderRequest(()=>client.beta.messages.create(params,requestOptions).asResponse(),{maxRetries:options?.maxRetries,maxRetryDelayMs:options?.maxRetryDelayMs,signal:options?.signal});await options?.onResponse?.({status:response.status,headers:headersToRecord(response.headers)},model),stream2.push({type:"start",partial:output});let blocks=output.content;for await(let event of iterateAnthropicEvents(response,options?.signal))if(await options?.onProviderStreamEvent?.(event,model),event.type==="message_start"){output.responseId=event.message.id;let transformations=event.message.input_transformations;Array.isArray(transformations)&&(inputTransformations=transformations);let responseModel=event.message.model;responseModel!==model.id&&(output.responseModel=responseModel);let fallbackCost=responseModel===model.id?void 0:model.compat?.allowedFallbackModels?.find(fallback=>fallback.provider===model.provider&&fallback.model===responseModel)?.cost;usageModel=fallbackCost?{...model,id:responseModel,cost:fallbackCost}:model,output.usage.input=event.message.usage.input_tokens||0,output.usage.output=event.message.usage.output_tokens||0,output.usage.cacheRead=event.message.usage.cache_read_input_tokens||0,output.usage.cacheWrite=event.message.usage.cache_creation_input_tokens||0,output.usage.cacheWrite1h=event.message.usage.cache_creation?.ephemeral_1h_input_tokens||0,output.usage.totalTokens=output.usage.input+output.usage.output+output.usage.cacheRead+output.usage.cacheWrite,calculateCost(usageModel,output.usage)}else if(event.type==="content_block_start"){if(event.content_block.type==="fallback"){if(output.content.length>0)throw new Error("Anthropic performed an unsupported mid-output model fallback");continue}if(event.content_block.type==="text"){let block={type:"text",text:event.content_block.text??"",index:event.index};output.content.push(block),stream2.push({type:"text_start",contentIndex:output.content.length-1,partial:output})}else if(event.content_block.type==="thinking"){let block={type:"thinking",thinking:event.content_block.thinking??"",thinkingSignature:event.content_block.signature??"",index:event.index};output.content.push(block),stream2.push({type:"thinking_start",contentIndex:output.content.length-1,partial:output})}else if(event.content_block.type==="redacted_thinking"){let block={type:"thinking",thinking:"[Reasoning redacted]",thinkingSignature:event.content_block.data,redacted:!0,index:event.index};output.content.push(block),stream2.push({type:"thinking_start",contentIndex:output.content.length-1,partial:output})}else if(event.content_block.type==="tool_use"){let block={type:"toolCall",id:event.content_block.id,name:isOAuth?fromClaudeCodeName(event.content_block.name,currentTools):event.content_block.name,arguments:event.content_block.input??{},partialJson:"",index:event.index};output.content.push(block),stream2.push({type:"toolcall_start",contentIndex:output.content.length-1,partial:output})}}else if(event.type==="content_block_delta"){if(event.delta.type==="text_delta"){let index=blocks.findIndex(b=>b.index===event.index),block=blocks[index];block&&block.type==="text"&&(block.text+=event.delta.text,stream2.push({type:"text_delta",contentIndex:index,delta:event.delta.text,partial:output}))}else if(event.delta.type==="thinking_delta"){let index=blocks.findIndex(b=>b.index===event.index),block=blocks[index];block&&block.type==="thinking"&&(block.thinking+=event.delta.thinking,stream2.push({type:"thinking_delta",contentIndex:index,delta:event.delta.thinking,partial:output}))}else if(event.delta.type==="input_json_delta"){let index=blocks.findIndex(b=>b.index===event.index),block=blocks[index];block&&block.type==="toolCall"&&(block.partialJson+=event.delta.partial_json,block.arguments=parseStreamingJson(block.partialJson),stream2.push({type:"toolcall_delta",contentIndex:index,delta:event.delta.partial_json,partial:output}))}else if(event.delta.type==="signature_delta"){let index=blocks.findIndex(b=>b.index===event.index),block=blocks[index];block&&block.type==="thinking"&&(block.thinkingSignature=block.thinkingSignature||"",block.thinkingSignature+=event.delta.signature)}}else if(event.type==="content_block_stop"){let index=blocks.findIndex(b=>b.index===event.index),block=blocks[index];block&&(delete block.index,block.type==="text"?stream2.push({type:"text_end",contentIndex:index,content:block.text,partial:output}):block.type==="thinking"?stream2.push({type:"thinking_end",contentIndex:index,content:block.thinking,partial:output}):block.type==="toolCall"&&(block.arguments=parseStreamingJson(block.partialJson),delete block.partialJson,stream2.push({type:"toolcall_end",contentIndex:index,toolCall:block,partial:output})))}else if(event.type==="message_delta"){let transformations=event.input_transformations;if(Array.isArray(transformations)&&(inputTransformations=transformations),event.delta.stop_reason){output.rawStopReason=event.delta.stop_reason;let stopReasonResult=mapStopReason(event.delta.stop_reason,event.delta.stop_details);output.stopReason=stopReasonResult.stopReason,stopReasonResult.errorMessage&&(output.errorMessage=stopReasonResult.errorMessage)}if(event.usage){event.usage.input_tokens!=null&&(output.usage.input=event.usage.input_tokens),event.usage.output_tokens!=null&&(output.usage.output=event.usage.output_tokens),event.usage.cache_read_input_tokens!=null&&(output.usage.cacheRead=event.usage.cache_read_input_tokens),event.usage.cache_creation_input_tokens!=null&&(output.usage.cacheWrite=event.usage.cache_creation_input_tokens);let cacheCreation=event.usage.cache_creation;cacheCreation?.ephemeral_1h_input_tokens!=null&&(output.usage.cacheWrite1h=cacheCreation.ephemeral_1h_input_tokens);let thinkingTokens=event.usage.output_tokens_details?.thinking_tokens;thinkingTokens!=null&&(output.usage.reasoning=thinkingTokens)}output.usage.totalTokens=output.usage.input+output.usage.output+output.usage.cacheRead+output.usage.cacheWrite,calculateCost(usageModel,output.usage)}if(options?.signal?.aborted)throw new Error("Request was aborted");if(output.stopReason==="pending")throw new Error("Anthropic stream ended without a stop reason");if(output.stopReason==="aborted"||output.stopReason==="error")throw new Error(output.errorMessage||"An unknown error occurred");inputTransformations&&inputTransformations.length>0&&appendAssistantMessageDiagnostic(output,{type:"anthropic_input_transformations",timestamp:Date.now(),details:{transformations:inputTransformations.map(transformation=>({type:transformation.type??void 0,path:transformation.path??void 0,reason:transformation.reason??void 0}))}}),stream2.push({type:"done",reason:output.stopReason,message:output}),stream2.end()}catch(error){for(let block of output.content)delete block.index,delete block.partialJson;output.stopReason=options?.signal?.aborted?"aborted":"error",output.errorMessage=error instanceof Error?error.message:JSON.stringify(error),stream2.push({type:"error",reason:output.stopReason,error:output}),stream2.end()}})(),stream2};function mapThinkingLevelToEffort(model,level){let mapped=level?model.thinkingLevelMap?.[level]:void 0;if(typeof mapped=="string")return mapped;switch(level){case"minimal":case"low":return"low";case"medium":return"medium";case"high":return"high";default:return"high"}}var streamSimple=(model,context,options)=>{assertRequestAuth(model.provider,options?.apiKey,options?.headers);let base={...buildBaseOptions(model,context,options,options?.apiKey),toolChoice:options?.toolChoice};if(!options?.reasoning)return stream(model,context,{...base,thinkingEnabled:!1});if(model.compat?.forceAdaptiveThinking===!0){let effort=mapThinkingLevelToEffort(model,options.reasoning);return stream(model,context,{...base,thinkingEnabled:!0,effort})}let adjusted=adjustMaxTokensForThinking(base.maxTokens,model.maxTokens,options.reasoning,options.thinkingBudgets),maxTokens=clampMaxTokensToContext(model,context,adjusted.maxTokens);return stream(model,context,{...base,maxTokens,thinkingEnabled:!0,thinkingBudgetTokens:Math.min(adjusted.thinkingBudget,Math.max(0,maxTokens-1024))})};function isOAuthToken(apiKey){return apiKey.includes("sk-ant-oat")}function createClient(model,apiKey,optionsHeaders,fetch,dynamicHeaders,sessionId){if(model.provider==="github-copilot")return{client:new Anthropic({apiKey:null,authToken:apiKey??null,baseURL:model.baseUrl,dangerouslyAllowBrowser:!0,fetch,defaultHeaders:mergeClientHeaders({accept:"application/json","anthropic-dangerous-direct-browser-access":"true"},model.headers,dynamicHeaders,optionsHeaders)}),isOAuthToken:!1};if(apiKey&&isOAuthToken(apiKey))return{client:new Anthropic({apiKey:null,authToken:apiKey,baseURL:model.baseUrl,dangerouslyAllowBrowser:!0,fetch,defaultHeaders:mergeClientHeaders({accept:"application/json","anthropic-dangerous-direct-browser-access":"true","user-agent":`claude-cli/${claudeCodeVersion}`,"x-app":"cli"},model.headers,optionsHeaders)}),isOAuthToken:!0};let compat=getAnthropicCompat(model),sessionAffinityHeaders={};if(sessionId&&compat.sendSessionAffinityHeaders){let header=compat.sessionAffinityFormat==="openrouter"?"x-session-id":"x-session-affinity";sessionAffinityHeaders[header]=sessionId}let defaultHeaders=mergeClientHeaders({accept:"application/json","anthropic-dangerous-direct-browser-access":"true"},sessionAffinityHeaders,model.headers,optionsHeaders);return{client:new Anthropic({apiKey:apiKey??null,authToken:null,baseURL:model.baseUrl,dangerouslyAllowBrowser:!0,fetch,defaultHeaders}),isOAuthToken:!1}}function getBetaFeatures(model,context,isOAuthToken2,nativeToolChanges,options){let configuredFeatures;for(let headers of[model.headers,options?.headers])for(let[name,value]of Object.entries(headers??{}))name.toLowerCase()==="anthropic-beta"&&(configuredFeatures=value);if(configuredFeatures===null)return[];if(configuredFeatures!==void 0)return[...new Set(configuredFeatures.split(",").map(feature=>feature.trim()).filter(feature=>feature.length>0))];let features=[];return isOAuthToken2&&features.push("claude-code-20250219","oauth-2025-04-20"),shouldUseFineGrainedToolStreamingBeta(model,context)&&features.push(FINE_GRAINED_TOOL_STREAMING_BETA),model.reasoning&&options?.thinkingEnabled===!0&&(options.interleavedThinking??!0)&&model.compat?.forceAdaptiveThinking!==!0&&features.push(INTERLEAVED_THINKING_BETA),shouldUseServerSideFallbackBeta(model)&&features.push(SERVER_SIDE_FALLBACK_BETA),model.compat?.supportsMidConvoEffort===!0&&features.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA,THINKING_BINDING_CONTROLS_BETA),nativeToolChanges&&features.push(MID_CONVERSATION_TOOL_CHANGES_BETA),[...new Set(features)]}function buildParams(model,context,isOAuthToken2,options){let{cacheControl}=getCacheControl(model,options?.cacheRetention,options?.env),compat=getAnthropicCompat(model),initialSystemMessage=getInitialSystemMessage(context.messages),initialSystemText=initialSystemMessage?getSystemMessageText(initialSystemMessage):"",transformedMessages=transformMessages(context.messages,model,normalizeToolCallId),conversationMessages=initialSystemMessage?transformedMessages.slice(1):transformedMessages,initialTools=initialSystemMessage?.toolsAdded??[],nativeToolChanges=compat.supportsMidConvoSystemMessages&&compat.supportsMidConvoToolChanges&&initialTools.length>0&&!hasToolRedefinitions(context.messages),converted=convertMessages(conversationMessages,isOAuthToken2,cacheControl,compat.allowEmptySignature,model.compat?.supportsMidConvoEffort===!0?model.provider:void 0,nativeToolChanges),activeEffort=options?.effort??"high",betaFeatures=getBetaFeatures(model,context,isOAuthToken2,nativeToolChanges,options),params={model:model.id,messages:model.compat?.supportsMidConvoEffort===!0?insertThinkingLevelMessages(converted,activeEffort):converted.messages,max_tokens:options?.maxTokens??model.maxTokens,stream:!0,...betaFeatures.length>0?{betas:betaFeatures}:{}};isOAuthToken2?(params.system=[{type:"text",text:"You are Claude Code, Anthropic's official CLI for Claude.",...cacheControl?{cache_control:cacheControl}:{}}],initialSystemText&¶ms.system.push({type:"text",text:sanitizeSurrogates(initialSystemText),...cacheControl?{cache_control:cacheControl}:{}})):initialSystemText&&(params.system=[{type:"text",text:sanitizeSurrogates(initialSystemText),...cacheControl?{cache_control:cacheControl}:{}}]),options?.temperature!==void 0&&!options?.thinkingEnabled&&model.compat?.supportsMidConvoEffort!==!0&&compat.supportsTemperature&&(params.temperature=options.temperature);let toolCacheControl=compat.supportsCacheControlOnTools?cacheControl:void 0;if(nativeToolChanges){let initialNames=new Set(initialTools.map(tool=>tool.name)),laterTools=getDeclaredTools(context.messages).filter(tool=>!initialNames.has(tool.name));params.tools=[...convertTools(initialTools,isOAuthToken2,compat.supportsEagerToolInputStreaming,compat.supportsStrictTools,toolCacheControl),DEFERRED_TOOL_PLACEHOLDER,...convertTools(laterTools,isOAuthToken2,compat.supportsEagerToolInputStreaming,compat.supportsStrictTools).map(tool=>({...tool,defer_loading:!0}))]}else{let tools=getCurrentTools(context.messages);tools.length>0&&(params.tools=convertTools(tools,isOAuthToken2,compat.supportsEagerToolInputStreaming,compat.supportsStrictTools,toolCacheControl))}if(model.compat?.supportsMidConvoEffort===!0)params.thinking={type:"adaptive",display:options?.thinkingDisplay??"summarized",block_binding:{prefix_mismatch_behavior:"drop_block"}},params.output_config={effort:"high"};else if(model.reasoning)if(options?.thinkingEnabled){let display=options.thinkingDisplay??"summarized";model.compat?.forceAdaptiveThinking===!0?(params.thinking={type:"adaptive",display},options.effort&&(params.output_config={effort:options.effort})):params.thinking={type:"enabled",budget_tokens:options.thinkingBudgetTokens||1024,display}}else options?.thinkingEnabled===!1&&model.thinkingLevelMap?.off!==null&&(params.thinking={type:"disabled"});if(options?.metadata){let userId=options.metadata.user_id;typeof userId=="string"&&(params.metadata={user_id:userId})}options?.toolChoice&&(typeof options.toolChoice=="string"?params.tool_choice={type:options.toolChoice}:params.tool_choice=options.toolChoice);let allowedFallbackModels=model.compat?.allowedFallbackModels;return allowedFallbackModels&&allowedFallbackModels.length>0&&(params.fallbacks=allowedFallbackModels.map(fallback=>({model:fallback.model}))),params}function normalizeToolCallId(id){return id.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)}function convertToolResult(msg){return{type:"tool_result",tool_use_id:msg.toolCallId,content:convertContentBlocks(msg.content),is_error:msg.isError}}function convertMessages(transformedMessages,isOAuthToken2,cacheControl,allowEmptySignature=!1,managedProvider,nativeToolChanges=!1){let params=[],assistantLevels=new Map,pendingSystemMessages=[],flushPendingSystemMessages=()=>{params.push(...pendingSystemMessages),pendingSystemMessages.length=0};for(let i=0;i<transformedMessages.length;i++){let msg=transformedMessages[i];if(msg.role==="system"){let text=renderSystemMessageUpdate(msg),blocks=[];if(text.length>0&&blocks.push({type:"text",text:sanitizeSurrogates(text)}),nativeToolChanges){for(let tool of msg.toolsRemoved??[])blocks.push({type:"tool_removal",tool:{type:"tool_reference",name:isOAuthToken2?toClaudeCodeName(tool.name):tool.name}});for(let tool of msg.toolsAdded??[])blocks.push({type:"tool_addition",tool:{type:"tool_reference",name:isOAuthToken2?toClaudeCodeName(tool.name):tool.name}})}blocks.length>0&&pendingSystemMessages.push({role:"system",content:blocks})}else if(msg.role==="user")if(typeof msg.content=="string")msg.content.trim().length>0&¶ms.push({role:"user",content:sanitizeSurrogates(msg.content)});else{let filteredBlocks=msg.content.map(item=>item.type==="text"?{type:"text",text:sanitizeSurrogates(item.text)}:{type:"image",source:{type:"base64",media_type:item.mimeType,data:item.data}}).filter(b=>b.type==="text"?b.text.trim().length>0:!0);if(filteredBlocks.length===0)continue;params.push({role:"user",content:filteredBlocks})}else if(msg.role==="assistant"){flushPendingSystemMessages();let blocks=[];for(let block of msg.content)if(block.type==="text"){if(block.text.trim().length===0)continue;blocks.push({type:"text",text:sanitizeSurrogates(block.text)})}else if(block.type==="thinking"){if(block.redacted){blocks.push({type:"redacted_thinking",data:block.thinkingSignature});continue}let thinkingSignature=block.thinkingSignature,hasThinkingSignature=!!thinkingSignature&&thinkingSignature.trim().length>0;if(block.thinking.trim().length===0&&!hasThinkingSignature)continue;hasThinkingSignature?blocks.push({type:"thinking",thinking:sanitizeSurrogates(block.thinking),signature:thinkingSignature}):blocks.push(allowEmptySignature?{type:"thinking",thinking:sanitizeSurrogates(block.thinking),signature:""}:{type:"text",text:sanitizeSurrogates(block.thinking)})}else block.type==="toolCall"&&blocks.push({type:"tool_use",id:block.id,name:isOAuthToken2?toClaudeCodeName(block.name):block.name,input:block.arguments??{}});if(blocks.length===0)continue;let messageIndex=params.length;params.push({role:"assistant",content:blocks}),managedProvider!==void 0&&msg.api==="anthropic-messages"&&msg.provider===managedProvider&&isAnthropicEffort(msg.providerThinkingLevel)&&assistantLevels.set(messageIndex,msg.providerThinkingLevel)}else if(msg.role==="toolResult"){let toolResults=[],j=i;for(;j<transformedMessages.length&&transformedMessages[j].role==="toolResult";)toolResults.push(convertToolResult(transformedMessages[j])),j++;i=j-1,params.push({role:"user",content:toolResults})}}if(flushPendingSystemMessages(),cacheControl&¶ms.length>0){let lastMessage=params[params.length-1];if(lastMessage.role==="user"||lastMessage.role==="system")if(Array.isArray(lastMessage.content)){let lastBlock=lastMessage.content[lastMessage.content.length-1];lastBlock&&(lastBlock.type==="text"||lastBlock.type==="image"||lastBlock.type==="tool_result"||lastBlock.type==="tool_addition"||lastBlock.type==="tool_removal")&&(lastBlock.cache_control=cacheControl)}else typeof lastMessage.content=="string"&&(lastMessage.content=[{type:"text",text:lastMessage.content,cache_control:cacheControl}])}return{messages:params,assistantLevels}}function isAnthropicEffort(value){return value==="low"||value==="medium"||value==="high"||value==="xhigh"||value==="max"}function insertThinkingLevelMessages(converted,activeEffort){let messages=[];for(let index=0;index<converted.messages.length;index++){let historicalEffort=converted.assistantLevels.get(index);historicalEffort!==void 0&&messages.push({role:"system",content:[],output_config:{effort:historicalEffort}}),messages.push(converted.messages[index])}return messages.push({role:"system",content:[],output_config:{effort:activeEffort}}),messages}function shouldUseFineGrainedToolStreamingBeta(model,context){return getCurrentTools(context.messages).length>0&&!getAnthropicCompat(model).supportsEagerToolInputStreaming}function convertTools(tools,isOAuthToken2,supportsEagerToolInputStreaming,supportsStrictTools,cacheControl){return tools?tools.map((tool,index)=>{let strict=resolveJsonSchemaStrictSampling(tool,supportsStrictTools),parameters=getJsonSchemaToolParameters(tool,strict),schema=parameters,legacyInputSchema={type:"object",properties:schema.properties??{},required:schema.required??[]},inputSchema=strict===!0?{...parameters,...legacyInputSchema}:legacyInputSchema;return{name:isOAuthToken2?toClaudeCodeName(tool.name):tool.name,description:tool.description,...supportsEagerToolInputStreaming?{eager_input_streaming:!0}:{},...strict===!0?{strict:!0}:{},input_schema:inputSchema,...cacheControl&&index===tools.length-1?{cache_control:cacheControl}:{}}}):[]}function mapStopReason(reason,stopDetails){switch(reason){case"end_turn":return{stopReason:"stop"};case"max_tokens":return{stopReason:"length"};case"tool_use":return{stopReason:"toolUse"};case"refusal":return{stopReason:"error",errorMessage:stopDetails?.explanation||"The model refused to complete the request"};case"pause_turn":return{stopReason:"stop"};case"stop_sequence":return{stopReason:"stop"};case"sensitive":return{stopReason:"error",errorMessage:"Provider stopped with: sensitive"};default:throw new Error(`Unhandled stop reason: ${reason}`)}}export{stream,streamSimple};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
-
import{convertResponsesMessages,convertResponsesTools,processResponsesStream}from"./chunk-V7IXECST.js";import{clampOpenAIPromptCacheKey}from"./chunk-PRRNXB7S.js";import{AzureOpenAI}from"./chunk-NUHFSC37.js";import{formatProviderError,normalizeProviderError}from"./chunk-TEPMHNKQ.js";import"./chunk-PJACZCIR.js";import{retryProviderRequest}from"./chunk-XNGRGP62.js";import{buildBaseOptions,createGrammarToolInputProperties,getPiUserAgent}from"./chunk-GNYZK6XN.js";import"./chunk-L2ZPNLYD.js";import{headersToRecord}from"./chunk-UTB4DTYQ.js";import{getProviderEnvValue}from"./chunk-DRQDKNXA.js";import"./chunk-TRDNDS6A.js";import{clampThinkingLevel,getDeclaredTools,resolveTranscript,resolveTranscriptTools}from"./chunk-FU4XQUSL.js";import{AssistantMessageEventStream}from"./chunk-A3JYRWB6.js";import"./chunk-4L3WN2XY.js";var DEFAULT_AZURE_API_VERSION="v1",AZURE_TOOL_CALL_PROVIDERS=new Set(["openai","openai-codex","opencode","azure-openai-responses"]),OPENAI_RESPONSES_MIN_OUTPUT_TOKENS=16;function parseDeploymentNameMap(value){let map=new Map;if(!value)return map;for(let entry of value.split(",")){let trimmed=entry.trim();if(!trimmed)continue;let[modelId,deploymentName]=trimmed.split("=",2);!modelId||!deploymentName||map.set(modelId.trim(),deploymentName.trim())}return map}function resolveDeploymentName(model,options){return options?.azureDeploymentName?options.azureDeploymentName:parseDeploymentNameMap(getProviderEnvValue("AZURE_OPENAI_DEPLOYMENT_NAME_MAP",options?.env)).get(model.id)||model.id}function formatAzureOpenAIError(error){return formatProviderError(normalizeProviderError(error),"Azure OpenAI API error")}var stream=(model,context,options)=>{let stream2=new AssistantMessageEventStream,normalizedContext=resolveTranscript(context,model.compat?.supportsMidConvoSystemMessages);return(async()=>{let deploymentName=resolveDeploymentName(model,options),output={role:"assistant",content:[],api:"azure-openai-responses",provider:model.provider,model:model.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"pending",timestamp:Date.now()};try{let apiKey=options?.apiKey;if(!apiKey)throw new Error(`No API key for provider: ${model.provider}`);let client=createClient(model,apiKey,options),grammarToolInputProperties=createGrammarToolInputProperties(getDeclaredTools(normalizedContext.messages),model.compat?.supportsOpenAIGrammarTools??!1),params=buildParams(model,normalizedContext,options,deploymentName,grammarToolInputProperties),nextParams=await options?.onPayload?.(params,model);nextParams!==void 0&&(params=nextParams);let requestOptions={...options?.signal?{signal:options.signal}:{},...options?.timeoutMs!==void 0?{timeout:options.timeoutMs}:{},maxRetries:0},{data:openaiStream,response}=await retryProviderRequest(()=>client.responses.create(params,requestOptions).withResponse(),{maxRetries:options?.maxRetries,maxRetryDelayMs:options?.maxRetryDelayMs,signal:options?.signal});if(await options?.onResponse?.({status:response.status,headers:headersToRecord(response.headers)},model),stream2.push({type:"start",partial:output}),await processResponsesStream(openaiStream,output,stream2,model,{onProviderStreamEvent:options?.onProviderStreamEvent,grammarToolInputProperties}),options?.signal?.aborted)throw new Error("Request was aborted");if(output.stopReason==="pending")throw new Error("Azure OpenAI Responses stream ended without a stop reason");if(output.stopReason==="aborted"||output.stopReason==="error")throw new Error(output.errorMessage||"An unknown error occurred");stream2.push({type:"done",reason:output.stopReason,message:output}),stream2.end()}catch(error){for(let block of output.content)delete block.index,delete block.partialJson,delete block.customInput;output.stopReason=options?.signal?.aborted?"aborted":"error",output.errorMessage=formatAzureOpenAIError(error),stream2.push({type:"error",reason:output.stopReason,error:output}),stream2.end()}})(),stream2},streamSimple=(model,context,options)=>{let apiKey=options?.apiKey;if(!apiKey)throw new Error(`No API key for provider: ${model.provider}`);let base={...buildBaseOptions(model,context,options,apiKey),toolChoice:options?.toolChoice},clampedReasoning=options?.reasoning?clampThinkingLevel(model,options.reasoning):void 0;return stream(model,context,{...base,reasoningEffort:clampedReasoning==="off"?void 0:clampedReasoning})};function normalizeAzureBaseUrl(baseUrl){let trimmed=baseUrl.trim().replace(/\/+$/,""),url;try{url=new URL(trimmed)}catch{throw new Error(`Invalid Azure OpenAI base URL: ${baseUrl}`)}let isAzureHost=url.hostname.endsWith(".openai.azure.com")||url.hostname.endsWith(".cognitiveservices.azure.com")||url.hostname.endsWith(".ai.azure.com"),normalizedPath=url.pathname.replace(/\/+$/,"");return isAzureHost&&(normalizedPath===""||normalizedPath==="/"||normalizedPath==="/openai"||normalizedPath==="/openai/v1/responses")&&(url.pathname="/openai/v1",url.search=""),url.toString().replace(/\/+$/,"")}function buildDefaultBaseUrl(resourceName){return`https://${resourceName}.openai.azure.com/openai/v1`}function resolveAzureConfig(model,options){let apiVersion=options?.azureApiVersion||getProviderEnvValue("AZURE_OPENAI_API_VERSION",options?.env)||DEFAULT_AZURE_API_VERSION,baseUrl=options?.azureBaseUrl?.trim()||getProviderEnvValue("AZURE_OPENAI_BASE_URL",options?.env)?.trim()||void 0,resourceName=options?.azureResourceName||getProviderEnvValue("AZURE_OPENAI_RESOURCE_NAME",options?.env),resolvedBaseUrl=baseUrl;if(!resolvedBaseUrl&&resourceName&&(resolvedBaseUrl=buildDefaultBaseUrl(resourceName)),!resolvedBaseUrl&&model.baseUrl&&(resolvedBaseUrl=model.baseUrl),!resolvedBaseUrl)throw new Error("Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME, or pass azureBaseUrl, azureResourceName, or model.baseUrl.");return{baseUrl:normalizeAzureBaseUrl(resolvedBaseUrl),apiVersion}}function createClient(model,apiKey,options){let headers={"User-Agent":getPiUserAgent(),...model.headers};options?.headers&&Object.assign(headers,options.headers);let{baseUrl,apiVersion}=resolveAzureConfig(model,options);return new AzureOpenAI({apiKey,apiVersion,dangerouslyAllowBrowser:!0,fetch:options?.fetch,defaultHeaders:headers,baseURL:baseUrl})}function buildParams(model,context,options,deploymentName,grammarToolInputProperties=createGrammarToolInputProperties(getDeclaredTools(context.messages),model.compat?.supportsOpenAIGrammarTools??!1)){let supportsAdditionalTools=model.compat?.supportsAdditionalTools??!1,supportsToolSearch=model.compat?.supportsToolSearch??!1,transcriptTools=resolveTranscriptTools(context.messages,supportsAdditionalTools||supportsToolSearch),messages=convertResponsesMessages(model,context,AZURE_TOOL_CALL_PROVIDERS,{grammarToolInputProperties,supportsMidConvoSystemMessages:model.compat?.supportsMidConvoSystemMessages??!1,supportsAdditionalTools,supportsToolSearch,toolOptions:{supportsStrictMode:model.compat?.supportsStrictMode??!0,supportsOpenAIGrammarTools:model.compat?.supportsOpenAIGrammarTools??!1}}),params={model:deploymentName,input:messages,stream:!0,prompt_cache_key:clampOpenAIPromptCacheKey(options?.sessionId),store:!1};if(options?.maxTokens&&(params.max_output_tokens=Math.max(options.maxTokens,OPENAI_RESPONSES_MIN_OUTPUT_TOKENS)),options?.temperature!==void 0&&(params.temperature=options?.temperature),transcriptTools.requestTools.length>0&&(params.tools=convertResponsesTools(transcriptTools.requestTools,{supportsStrictMode:model.compat?.supportsStrictMode??!0,supportsOpenAIGrammarTools:model.compat?.supportsOpenAIGrammarTools??!1})),options?.toolChoice!==void 0&&(params.tool_choice=options.toolChoice),model.reasoning)if(options?.reasoningEffort||options?.reasoningSummary){let effort=options?.reasoningEffort?model.thinkingLevelMap?.[options.reasoningEffort]??options.reasoningEffort:"medium";params.reasoning={effort,summary:options?.reasoningSummary||"auto"},params.include=["reasoning.encrypted_content"]}else model.thinkingLevelMap?.off!==null&&(params.reasoning={effort:model.thinkingLevelMap?.off??"none"});return options?.samplingParams&&Object.assign(params,options.samplingParams),params}export{stream,streamSimple};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
-
var FifoQueue=class{incoming=[];outgoing=[];get length(){return this.incoming.length+this.outgoing.length}enqueue(value){this.incoming.push(value)}dequeue(){if(this.outgoing.length===0)for(;this.incoming.length>0;)this.outgoing.push(this.incoming.pop());return this.outgoing.pop()}},EventStream=class{queue=new FifoQueue;waiting=new FifoQueue;done=!1;finalResultPromise;resolveFinalResult;isComplete;extractResult;constructor(isComplete,extractResult){this.isComplete=isComplete,this.extractResult=extractResult,this.finalResultPromise=new Promise(resolve=>{this.resolveFinalResult=resolve})}push(event){if(this.done)return;this.isComplete(event)&&(this.done=!0,this.resolveFinalResult(this.extractResult(event)));let waiter=this.waiting.dequeue();waiter?waiter({value:event,done:!1}):this.queue.enqueue(event)}end(result){for(this.done=!0,result!==void 0&&this.resolveFinalResult(result);this.waiting.length>0;)this.waiting.dequeue()({value:void 0,done:!0})}async*[Symbol.asyncIterator](){for(;;)if(this.queue.length>0)yield this.queue.dequeue();else{if(this.done)return;{let result=await new Promise(resolve=>this.waiting.enqueue(resolve));if(result.done)return;yield result.value}}}result(){return this.finalResultPromise}},AssistantMessageEventStream=class extends EventStream{constructor(){super(event=>event.type==="done"||event.type==="error",event=>{if(event.type==="done")return event.message;if(event.type==="error")return event.error;throw new Error("Unexpected event type for final result")})}};function createAssistantMessageEventStream(){return new AssistantMessageEventStream}function formatThrownValue(value){return value instanceof Error?value.message||value.name:typeof value=="string"?value:String(value)}function extractDiagnosticError(error){if(!(error instanceof Error))return{name:"ThrownValue",message:formatThrownValue(error)};let code=error.code;return{name:error.name||void 0,message:error.message||error.name,stack:error.stack,code:typeof code=="string"||typeof code=="number"?code:void 0}}function createAssistantMessageDiagnostic(type,error,details){return{type,timestamp:Date.now(),error:extractDiagnosticError(error),details}}function appendAssistantMessageDiagnostic(message,diagnostic){message.diagnostics=[...message.diagnostics??[],diagnostic]}export{EventStream,AssistantMessageEventStream,createAssistantMessageEventStream,formatThrownValue,extractDiagnosticError,createAssistantMessageDiagnostic,appendAssistantMessageDiagnostic};
|