mu-agent 0.1.4 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.md +7 -3
- package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +6 -0
- package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
- package/dist/bundle/chunks/{chunk-FUXEF6JQ.js → chunk-4O2SCVYF.js} +1 -1
- package/dist/bundle/chunks/chunk-AYFRR3OD.js +2 -0
- package/dist/bundle/chunks/chunk-FU4XQUSL.js +11 -0
- package/dist/bundle/chunks/{chunk-S7SZN6Z3.js → chunk-GNYZK6XN.js} +1 -1
- package/dist/bundle/chunks/{chunk-XOBBIK6P.js → chunk-HEMXN7VJ.js} +75 -67
- package/dist/bundle/chunks/chunk-MVPXOVOJ.js +2 -0
- package/dist/bundle/chunks/chunk-UTB4DTYQ.js +2 -0
- package/dist/bundle/chunks/{chunk-WIUZI2CJ.js → chunk-V7IXECST.js} +2 -2
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +2 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/google-generative-ai-C44KRRZ4.js +2 -0
- package/dist/bundle/chunks/google-vertex-25DUXPTJ.js +2 -0
- package/dist/bundle/chunks/meta.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +5 -0
- package/dist/bundle/chunks/{openai-codex-responses-QDSOTBBO.js → openai-codex-responses-3UAYOSSR.js} +2 -2
- package/dist/bundle/chunks/{openai-completions-KQPOPEVM.js → openai-completions-FIEQGWAH.js} +3 -3
- package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +2 -0
- package/dist/bundle/chunks/{openrouter-images-N4XVVFSD.js → openrouter-images-JVEJN44Q.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-GFKBWJHZ.js → pi-messages-TM5SOOIW.js} +2 -2
- package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +2 -0
- package/dist/bundle/chunks/{virtual-modules-MYFARBUK.js → virtual-modules-V7SXVVLP.js} +1 -1
- package/dist/bundle/cli-runtime.js +3 -0
- package/dist/bundle/cli.js +4 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/export-html/template.css +10 -0
- package/dist/core/export-html/template.js +56 -18
- package/dist/modes/interactive/theme/theme-controller.d.ts +6 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +41 -3
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-json.js +3 -1
- package/dist/modes/interactive/theme/theme-json.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +7 -2
- package/dist/modes/interactive/theme/theme.d.ts +40 -7
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +122 -214
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/cli-integration.md +106 -0
- package/docs/cli.md +268 -0
- package/docs/compaction.md +45 -26
- package/docs/configuration.md +45 -0
- package/docs/containerization.md +109 -82
- package/docs/custom-provider.md +109 -722
- package/docs/docs.json +139 -99
- package/docs/environment-variables.md +3 -5
- package/docs/extensions.md +137 -2953
- package/docs/how-pi-works.md +49 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/index.md +24 -69
- package/docs/json.md +193 -65
- package/docs/keybindings.md +57 -102
- package/docs/llama-cpp.md +3 -3
- package/docs/message-types.md +261 -0
- package/docs/models.md +64 -546
- package/docs/packages.md +67 -166
- package/docs/prompt-templates.md +31 -68
- package/docs/providers.md +102 -232
- package/docs/quickstart.md +61 -106
- package/docs/rpc-commands.md +854 -0
- package/docs/rpc-extension-ui.md +200 -0
- package/docs/rpc.md +129 -1556
- package/docs/sdk.md +76 -1160
- package/docs/security.md +70 -32
- package/docs/session-format.md +25 -216
- package/docs/sessions.md +35 -141
- package/docs/settings.md +109 -387
- package/docs/shell-aliases.md +85 -5
- package/docs/skills.md +51 -190
- package/docs/slash-commands.md +60 -0
- package/docs/terminal-setup.md +105 -78
- package/docs/termux.md +74 -83
- package/docs/themes.md +71 -279
- package/docs/tmux.md +31 -39
- package/docs/tui.md +74 -910
- package/docs/usage.md +54 -272
- package/docs/windows.md +43 -17
- package/examples/README.md +13 -2
- package/examples/extensions/README.md +1 -0
- 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/debug-provider.ts +90 -0
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/plugins/pi-example-plugin/src/session.ts +3 -2
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +25 -5
- package/examples/sdk/README.md +1 -1
- package/judge/dist/auth.js +166 -28
- package/judge/dist/chrome.js +12 -1
- package/judge/dist/kyrn-judge.js +1424 -589
- package/judge/dist/setup.js +2051 -0
- package/judge/manifest.json +13 -13
- package/judge/skills/mu-browser/SKILL.md +1 -0
- package/kyrn/bin/kyrn-doctor +107 -18
- package/kyrn/bin/mu.mjs +389 -29
- package/package.json +4 -4
- package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +0 -2
- package/dist/bundle/chunks/chunk-6R7UI4IY.js +0 -2
- package/dist/bundle/chunks/chunk-CK5Z65DM.js +0 -2
- package/dist/bundle/chunks/chunk-RCZIEVGO.js +0 -11
- package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +0 -2
- package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +0 -2
- package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +0 -5
- package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +0 -2
- package/docs/development.md +0 -90
package/kyrn/bin/mu.mjs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// - npm's own `mu` command, in the npm package mu-agent (kyrn/npm/build.mjs). The package is laid out like the
|
|
10
10
|
// repository, so this file is at kyrn/bin/mu.mjs there too, and the root is two folders up in both.
|
|
11
11
|
//
|
|
12
|
-
// No dependency and no TypeScript here: this runs before
|
|
12
|
+
// No dependency and no TypeScript here: this runs before anything that could run TypeScript has been found.
|
|
13
13
|
//
|
|
14
14
|
// Every decision is an exported function that takes the platform, the environment and the file system as
|
|
15
15
|
// parameters and returns what would be done. There is no Windows machine where this is developed, so the
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
} from "node:fs";
|
|
47
47
|
import { homedir, constants as osConstants } from "node:os";
|
|
48
48
|
import nodePath from "node:path";
|
|
49
|
-
import { fileURLToPath } from "node:url";
|
|
49
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
50
50
|
|
|
51
51
|
/** pi's minimum. */
|
|
52
52
|
export const MIN_NODE = [22, 19];
|
|
@@ -100,6 +100,8 @@ export function usage(platform) {
|
|
|
100
100
|
' mu "prompt" interactive, starting with this prompt',
|
|
101
101
|
' mu -p "prompt" one-shot: print the answer and exit',
|
|
102
102
|
" mu -c | -r continue the last session | pick one to resume",
|
|
103
|
+
" mu setup connect a model (an API key, or a service from a list) and choose the judge",
|
|
104
|
+
" (mu setup --help: scripts, a key from stdin, the services it knows)",
|
|
103
105
|
" mu judge <cmd> the local judge (Laya): setup | start | stop | status | run",
|
|
104
106
|
" mu ledger [n] [--json] what the judge decided in the last n sessions",
|
|
105
107
|
" mu import --list | <file>... bring Claude Code and Codex conversations into mu (mu import --help)",
|
|
@@ -306,7 +308,7 @@ export function ensureAppView({ platform, app, upstream, fs = realFs }) {
|
|
|
306
308
|
// ---------------------------------------------------------------------------------------------------------
|
|
307
309
|
|
|
308
310
|
/**
|
|
309
|
-
* Where this mu comes from: "repo", a checkout that runs the TypeScript sources
|
|
311
|
+
* Where this mu comes from: "repo", a checkout that runs the TypeScript sources (sourceRuntime), or "package", the
|
|
310
312
|
* npm package mu-agent, which carries pi's bundle (dist/bundle/cli.js) and the judgment layer built to
|
|
311
313
|
* JavaScript (judge/dist/kyrn-judge.js). A checkout without its dependencies is still a checkout.
|
|
312
314
|
*/
|
|
@@ -316,7 +318,10 @@ export function layoutOf({ root, platform, exists }) {
|
|
|
316
318
|
return exists(path.join(root, "dist", "bundle", "cli.js")) ? "package" : "repo";
|
|
317
319
|
}
|
|
318
320
|
|
|
319
|
-
/**
|
|
321
|
+
/**
|
|
322
|
+
* The files the npm package runs: pi, the judgment layer, the sign-in of `mu auth`, the importer of `mu import` and the
|
|
323
|
+
* wizard of `mu setup`.
|
|
324
|
+
*/
|
|
320
325
|
export function packageEntries({ root, platform }) {
|
|
321
326
|
const path = pathFor(platform);
|
|
322
327
|
return {
|
|
@@ -324,6 +329,7 @@ export function packageEntries({ root, platform }) {
|
|
|
324
329
|
extension: path.join(root, "judge", "dist", "kyrn-judge.js"),
|
|
325
330
|
auth: path.join(root, "judge", "dist", "auth.js"),
|
|
326
331
|
import: path.join(root, "judge", "dist", "import.js"),
|
|
332
|
+
setup: path.join(root, "judge", "dist", "setup.js"),
|
|
327
333
|
};
|
|
328
334
|
}
|
|
329
335
|
|
|
@@ -370,6 +376,35 @@ export function installHint({ root, platform }) {
|
|
|
370
376
|
: `mu's dependencies are not installed. Run: ${steps.join(" && ")}`;
|
|
371
377
|
}
|
|
372
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Node's arguments for running a checkout's TypeScript, up to the entry file. A Node that strips types itself (on
|
|
381
|
+
* by default from 22.18) runs the sources as they are, with pi's own source resolver
|
|
382
|
+
* (packages/coding-agent/src/experimental/source-resolver.ts: each workspace package resolves to its sources, as
|
|
383
|
+
* tsconfig.json's paths say) and Node's compile cache (compile-cache.mjs). tsx runs its loader on a thread of its
|
|
384
|
+
* own and hands every file over from there: pi with the judgment layer took 2 s to start that way, about 0.85 s
|
|
385
|
+
* this way, and a checkout starts mu for every conversation the desktop app opens. A runtime that does not strip
|
|
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.
|
|
388
|
+
*/
|
|
389
|
+
export function sourceRuntime({ root, platform, stripsTypes, exists, readFile }) {
|
|
390
|
+
const path = pathFor(platform);
|
|
391
|
+
const tsx = resolveTsx({ root, platform, exists, readFile });
|
|
392
|
+
if (!tsx) return { error: installHint({ root, platform }) };
|
|
393
|
+
const resolver = path.join(root, "packages", "coding-agent", "src", "experimental", "source-resolver.ts");
|
|
394
|
+
if (!stripsTypes || !exists(resolver)) return { args: [tsx, "--tsconfig", path.join(root, "tsconfig.json")] };
|
|
395
|
+
// As URLs: `--import` reads a Windows path such as C:\... as a URL whose scheme is c:.
|
|
396
|
+
const url = (file) => pathToFileURL(file, { windows: platform === "win32" }).href;
|
|
397
|
+
return {
|
|
398
|
+
args: [
|
|
399
|
+
"--disable-warning=ExperimentalWarning",
|
|
400
|
+
"--import",
|
|
401
|
+
url(path.join(root, "kyrn", "bin", "compile-cache.mjs")),
|
|
402
|
+
"--import",
|
|
403
|
+
url(resolver),
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
373
408
|
/**
|
|
374
409
|
* pi reads <APP NAME>_CODING_AGENT_DIR and nothing else, so with the app named mu that export decides the
|
|
375
410
|
* home. The pi and KYRN spellings are exported too, for scripts that still read them.
|
|
@@ -429,7 +464,18 @@ export function launchStrategy({ platform, env, canExec }) {
|
|
|
429
464
|
*
|
|
430
465
|
* `fs` is { exists, isDir, readFile }. Returns { error } when pi cannot be started.
|
|
431
466
|
*/
|
|
432
|
-
export function planLaunch({
|
|
467
|
+
export function planLaunch({
|
|
468
|
+
platform,
|
|
469
|
+
env,
|
|
470
|
+
argv,
|
|
471
|
+
root,
|
|
472
|
+
home,
|
|
473
|
+
execPath,
|
|
474
|
+
fs,
|
|
475
|
+
canExec = false,
|
|
476
|
+
wsl = false,
|
|
477
|
+
stripsTypes = true,
|
|
478
|
+
}) {
|
|
433
479
|
const path = pathFor(platform);
|
|
434
480
|
const layout = layoutOf({ root, platform, exists: fs.exists });
|
|
435
481
|
let entry;
|
|
@@ -440,12 +486,10 @@ export function planLaunch({ platform, env, argv, root, home, execPath, fs, canE
|
|
|
440
486
|
}
|
|
441
487
|
entry = [files.cli, "-e", files.extension];
|
|
442
488
|
} else {
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
489
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists, readFile: fs.readFile });
|
|
490
|
+
if (runtime.error) return { error: runtime.error };
|
|
445
491
|
entry = [
|
|
446
|
-
|
|
447
|
-
"--tsconfig",
|
|
448
|
-
path.join(root, "tsconfig.json"),
|
|
492
|
+
...runtime.args,
|
|
449
493
|
path.join(root, "packages", "coding-agent", "src", "experimental", "cli.ts"),
|
|
450
494
|
"-e",
|
|
451
495
|
path.join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts"),
|
|
@@ -510,6 +554,101 @@ export function planLaunch({ platform, env, argv, root, home, execPath, fs, canE
|
|
|
510
554
|
};
|
|
511
555
|
}
|
|
512
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Everything about running pi inside a process of another program, such as the desktop app's runtime host, decided
|
|
559
|
+
* as planLaunch decides it and without touching anything: the module to import pi's `setupCli` and `main` from, the
|
|
560
|
+
* Node flags that process starts with, pi's arguments (the judgment layer, then `argv`) and its whole environment.
|
|
561
|
+
* The app's pi and the command line's are then one: the same files, settings, sign-ins and keys.
|
|
562
|
+
*
|
|
563
|
+
* A checkout runs in such a process only on a Node that strips TypeScript types itself, with pi's source resolver:
|
|
564
|
+
* tsx cannot be put in front of a module another program imports. Returns { error } otherwise.
|
|
565
|
+
*/
|
|
566
|
+
export function planHost({ platform, env, argv, root, home, fs, wsl = false, stripsTypes = true }) {
|
|
567
|
+
const path = pathFor(platform);
|
|
568
|
+
const launch = planLaunch({ platform, env, argv, root, home, execPath: "", fs, wsl, stripsTypes });
|
|
569
|
+
if (launch.error !== undefined) return { error: launch.error };
|
|
570
|
+
const common = {
|
|
571
|
+
env: launch.env,
|
|
572
|
+
layout: launch.layout,
|
|
573
|
+
muDir: launch.muDir,
|
|
574
|
+
appDir: launch.appDir,
|
|
575
|
+
agentDir: launch.agentDir,
|
|
576
|
+
startJudge: launch.startJudge,
|
|
577
|
+
notes: launch.notes,
|
|
578
|
+
};
|
|
579
|
+
if (launch.layout === "package") {
|
|
580
|
+
return {
|
|
581
|
+
...common,
|
|
582
|
+
module: path.join(root, "dist", "bundle", "index.js"),
|
|
583
|
+
execArgv: [],
|
|
584
|
+
args: ["-e", packageEntries({ root, platform }).extension, ...argv],
|
|
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})`,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists, readFile: fs.readFile });
|
|
594
|
+
if (runtime.error) return { error: runtime.error };
|
|
595
|
+
return {
|
|
596
|
+
...common,
|
|
597
|
+
module: path.join(root, "packages", "coding-agent", "src", "index.ts"),
|
|
598
|
+
execArgv: runtime.args,
|
|
599
|
+
args: ["-e", path.join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts"), ...argv],
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** What mu says when the local judge does not come up. */
|
|
604
|
+
const LOCAL_JUDGE_NOT_STARTED =
|
|
605
|
+
"mu: the local judge did not start (mu judge status); decisions fall back to pi's behaviour";
|
|
606
|
+
|
|
607
|
+
/** The part of the preparation that is files: the app view of a checkout, mu's agent folder, the configuration's notes. */
|
|
608
|
+
function prepareFiles({ plan, platform, root, err }) {
|
|
609
|
+
const path = pathFor(platform);
|
|
610
|
+
if (plan.layout === "repo") {
|
|
611
|
+
ensureAppView({ platform, app: plan.appDir, upstream: path.join(root, "packages", "coding-agent") });
|
|
612
|
+
}
|
|
613
|
+
mkdirSync(plan.agentDir, { recursive: true });
|
|
614
|
+
for (const note of plan.notes) err(note);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* What is done before pi starts, for the command line and the desktop app's runtime host alike: the app view that
|
|
619
|
+
* names a checkout mu, mu's agent folder, the configuration's notes (to `err`), and the local judge when the
|
|
620
|
+
* configuration asks for it. `bin` is this launcher's folder. The local judge is one shared sidecar: starting it is
|
|
621
|
+
* idempotent and never blocks pi.
|
|
622
|
+
*/
|
|
623
|
+
export function prepareLaunch({ plan, platform, root, bin, err }) {
|
|
624
|
+
prepareFiles({ plan, platform, root, err });
|
|
625
|
+
if (plan.startJudge) {
|
|
626
|
+
const started = spawnSync(pathFor(platform).join(bin, "kyrn-judge-local"), ["start"], {
|
|
627
|
+
stdio: "ignore",
|
|
628
|
+
env: plan.env,
|
|
629
|
+
});
|
|
630
|
+
if (started.status !== 0) err(LOCAL_JUDGE_NOT_STARTED);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* prepareLaunch for a program that must not stop while the local judge starts, such as the desktop app's main process:
|
|
636
|
+
* the same steps and notes, with the local judge started through a child process it waits for without blocking.
|
|
637
|
+
*/
|
|
638
|
+
export async function prepareLaunchAsync({ plan, platform, root, bin, err }) {
|
|
639
|
+
prepareFiles({ plan, platform, root, err });
|
|
640
|
+
if (!plan.startJudge) return;
|
|
641
|
+
const status = await new Promise((resolve) => {
|
|
642
|
+
const child = spawn(pathFor(platform).join(bin, "kyrn-judge-local"), ["start"], {
|
|
643
|
+
stdio: "ignore",
|
|
644
|
+
env: plan.env,
|
|
645
|
+
});
|
|
646
|
+
child.once("error", () => resolve(null));
|
|
647
|
+
child.once("close", (code) => resolve(code));
|
|
648
|
+
});
|
|
649
|
+
if (status !== 0) err(LOCAL_JUDGE_NOT_STARTED);
|
|
650
|
+
}
|
|
651
|
+
|
|
513
652
|
// ---------------------------------------------------------------------------------------------------------
|
|
514
653
|
// mu auth
|
|
515
654
|
// ---------------------------------------------------------------------------------------------------------
|
|
@@ -520,9 +659,9 @@ export const AUTH_COMMANDS = ["status", "login", "logout"];
|
|
|
520
659
|
/**
|
|
521
660
|
* `mu auth status | login <provider> | logout <provider>`: the sign-in the desktop app runs, with pi's own OAuth
|
|
522
661
|
* flows and credential store (packages/kyrn-judge/src/auth). It is pi's code, so it runs the way pi does here:
|
|
523
|
-
*
|
|
662
|
+
* from its sources in a checkout (sourceRuntime), built in the package. It reads no key, so no .env is read for it.
|
|
524
663
|
*/
|
|
525
|
-
export function planAuth({ platform, env, argv, root, home, execPath, fs, canExec = false }) {
|
|
664
|
+
export function planAuth({ platform, env, argv, root, home, execPath, fs, canExec = false, stripsTypes = true }) {
|
|
526
665
|
const path = pathFor(platform);
|
|
527
666
|
let entry;
|
|
528
667
|
if (layoutOf({ root, platform, exists: fs.exists }) === "package") {
|
|
@@ -532,10 +671,9 @@ export function planAuth({ platform, env, argv, root, home, execPath, fs, canExe
|
|
|
532
671
|
}
|
|
533
672
|
entry = [auth];
|
|
534
673
|
} else {
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
entry = [tsx, "--tsconfig", path.join(root, "tsconfig.json"), main];
|
|
674
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists, readFile: fs.readFile });
|
|
675
|
+
if (runtime.error) return { error: runtime.error };
|
|
676
|
+
entry = [...runtime.args, path.join(root, "packages", "kyrn-judge", "src", "auth", "main.ts")];
|
|
539
677
|
}
|
|
540
678
|
const agentDir = agentDirFor({ env, muDir: muHome({ home, platform, isDir: fs.isDir }), platform });
|
|
541
679
|
const childEnv = {};
|
|
@@ -598,6 +736,178 @@ export function planImport({ platform, env, argv, root, home, execPath, fs, stri
|
|
|
598
736
|
return { command: execPath, args: [...entry, ...argv], env: childEnv, agentDir };
|
|
599
737
|
}
|
|
600
738
|
|
|
739
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
740
|
+
// mu setup
|
|
741
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
742
|
+
|
|
743
|
+
/** What a "no" to the first-start question leaves in the agent folder (packages/kyrn-judge/src/setup/wizard.ts). */
|
|
744
|
+
export const SETUP_DECLINED_FILE = "setup-declined";
|
|
745
|
+
|
|
746
|
+
/** How `mu setup` says: set up, and start a session now. */
|
|
747
|
+
export const SETUP_EXIT_START = 3;
|
|
748
|
+
|
|
749
|
+
/** How `mu setup` says it was cancelled (ctrl+c): a first start then goes no further. */
|
|
750
|
+
export const SETUP_EXIT_CANCELLED = 130;
|
|
751
|
+
|
|
752
|
+
/** The options of `mu setup` that take a value (wizard.ts keeps the same list): the word after one is not a key. */
|
|
753
|
+
export const SETUP_VALUE_FLAGS = ["--service", "--model", "--base-url", "--api", "--name", "--judge"];
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* The environment variables that give pi a model on their own: packages/ai/src/env-api-keys.ts, which a test holds this
|
|
757
|
+
* list to, and AWS_BEARER_TOKEN_BEDROCK, which is there for nothing else. TYPESAFE_API_KEY is left out, as pi's
|
|
758
|
+
* typesafe provider has classifiers only (the key is Jev's). So are AWS profiles and Google Cloud's default
|
|
759
|
+
* credentials: many machines have them for other work.
|
|
760
|
+
*/
|
|
761
|
+
export const MODEL_KEY_VARIABLES = [
|
|
762
|
+
"COPILOT_GITHUB_TOKEN",
|
|
763
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
764
|
+
"ANTHROPIC_OAUTH_TOKEN",
|
|
765
|
+
"ANTHROPIC_API_KEY",
|
|
766
|
+
"ANT_LING_API_KEY",
|
|
767
|
+
"QWEN_TOKEN_PLAN_API_KEY",
|
|
768
|
+
"QWEN_TOKEN_PLAN_CN_API_KEY",
|
|
769
|
+
"OPENAI_API_KEY",
|
|
770
|
+
"AZURE_OPENAI_API_KEY",
|
|
771
|
+
"NVIDIA_API_KEY",
|
|
772
|
+
"DEEPSEEK_API_KEY",
|
|
773
|
+
"GEMINI_API_KEY",
|
|
774
|
+
"GOOGLE_CLOUD_API_KEY",
|
|
775
|
+
"GROQ_API_KEY",
|
|
776
|
+
"CEREBRAS_API_KEY",
|
|
777
|
+
"XAI_API_KEY",
|
|
778
|
+
"RADIUS_API_KEY",
|
|
779
|
+
"OPENROUTER_API_KEY",
|
|
780
|
+
"AI_GATEWAY_API_KEY",
|
|
781
|
+
"ZAI_API_KEY",
|
|
782
|
+
"ZAI_CODING_CN_API_KEY",
|
|
783
|
+
"MISTRAL_API_KEY",
|
|
784
|
+
"MINIMAX_API_KEY",
|
|
785
|
+
"MINIMAX_CN_API_KEY",
|
|
786
|
+
"MOONSHOT_API_KEY",
|
|
787
|
+
"HF_TOKEN",
|
|
788
|
+
"FIREWORKS_API_KEY",
|
|
789
|
+
"TOGETHER_API_KEY",
|
|
790
|
+
"BASETEN_API_KEY",
|
|
791
|
+
"OPENCODE_API_KEY",
|
|
792
|
+
"KIMI_API_KEY",
|
|
793
|
+
"META_API_KEY",
|
|
794
|
+
"CLOUDFLARE_API_KEY",
|
|
795
|
+
"XIAOMI_API_KEY",
|
|
796
|
+
"XIAOMI_TOKEN_PLAN_CN_API_KEY",
|
|
797
|
+
"XIAOMI_TOKEN_PLAN_AMS_API_KEY",
|
|
798
|
+
"XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
|
799
|
+
"AWS_BEARER_TOKEN_BEDROCK",
|
|
800
|
+
];
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* `mu setup`: the wizard that connects a model and chooses the judge (packages/kyrn-judge/src/setup). It is pi's code,
|
|
804
|
+
* so it runs the way `mu auth` runs: from the sources in a checkout, built in the package. A key on the command line
|
|
805
|
+
* (`mu setup <key>`) goes to the wizard in the environment, MU_SETUP_KEY, never in its argv, which every process on
|
|
806
|
+
* the machine can read. The launcher waits for the wizard, since a finished setup may go on into a session.
|
|
807
|
+
*/
|
|
808
|
+
export function planSetup({ platform, env, argv, root, home, execPath, fs, stripsTypes = true }) {
|
|
809
|
+
const path = pathFor(platform);
|
|
810
|
+
const layout = layoutOf({ root, platform, exists: fs.exists });
|
|
811
|
+
let entry;
|
|
812
|
+
if (layout === "package") {
|
|
813
|
+
const { setup } = packageEntries({ root, platform });
|
|
814
|
+
if (!fs.exists(setup)) {
|
|
815
|
+
return { error: `This mu-agent package has no mu setup (${setup} is missing). Update it: npm i -g mu-agent` };
|
|
816
|
+
}
|
|
817
|
+
entry = [setup];
|
|
818
|
+
} else {
|
|
819
|
+
const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists, readFile: fs.readFile });
|
|
820
|
+
if (runtime.error) return { error: runtime.error };
|
|
821
|
+
entry = [...runtime.args, path.join(root, "packages", "kyrn-judge", "src", "setup", "main.ts")];
|
|
822
|
+
}
|
|
823
|
+
const args = [];
|
|
824
|
+
let key;
|
|
825
|
+
for (let index = 0; index < argv.length; index++) {
|
|
826
|
+
const arg = argv[index];
|
|
827
|
+
if (SETUP_VALUE_FLAGS.includes(arg)) {
|
|
828
|
+
args.push(arg);
|
|
829
|
+
if (index + 1 < argv.length) args.push(argv[++index]);
|
|
830
|
+
} else if (arg.startsWith("-") || arg === "help") args.push(arg);
|
|
831
|
+
else if (key === undefined) key = arg;
|
|
832
|
+
else return { error: "mu setup takes one key at most (mu setup --help)", code: 2 };
|
|
833
|
+
}
|
|
834
|
+
const muDir = muHome({ home, platform, isDir: fs.isDir });
|
|
835
|
+
const agentDir = agentDirFor({ env, muDir, platform });
|
|
836
|
+
const childEnv = {};
|
|
837
|
+
for (const [name, value] of Object.entries(env)) if (typeof value === "string") childEnv[name] = value;
|
|
838
|
+
if (key !== undefined) childEnv.MU_SETUP_KEY = key;
|
|
839
|
+
childEnv.MU_AGENT_DIR = agentDir;
|
|
840
|
+
childEnv.MU_CODING_AGENT_DIR = agentDir;
|
|
841
|
+
childEnv.KYRN_CODING_AGENT_DIR = agentDir;
|
|
842
|
+
childEnv.PI_CODING_AGENT_DIR = agentDir;
|
|
843
|
+
childEnv.MU_SETUP_HOME = muDir;
|
|
844
|
+
// The .env a session gets: the wizard writes the Jev key there, and reads a proxy from it.
|
|
845
|
+
childEnv.MU_SETUP_ENV_FILE = envFilePath({ layout, root, muDir, platform });
|
|
846
|
+
return { command: execPath, args: [...entry, ...args], env: childEnv, strategy: "spawn", agentDir, keyGiven: key !== undefined };
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/** pi's own commands: none of them starts a session. */
|
|
850
|
+
const PI_COMMANDS = new Set(["install", "remove", "uninstall", "update", "list", "config", "auth"]);
|
|
851
|
+
/** Options for a run without a person (-p, --mode rpc), one that ends at once, or one that names its model itself. */
|
|
852
|
+
const NO_SETUP_FLAGS = new Set([
|
|
853
|
+
"-p",
|
|
854
|
+
"--print",
|
|
855
|
+
"--mode",
|
|
856
|
+
"-h",
|
|
857
|
+
"--help",
|
|
858
|
+
"-v",
|
|
859
|
+
"--version",
|
|
860
|
+
"--list-models",
|
|
861
|
+
"--export",
|
|
862
|
+
"--api-key",
|
|
863
|
+
"--provider",
|
|
864
|
+
"--model",
|
|
865
|
+
"--models",
|
|
866
|
+
]);
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Whether `mu` offers to set up a model before a session: only to a person at a terminal (stdin and stdout) who starts
|
|
870
|
+
* a session, on a machine where nothing gives mu a model yet, and who has not answered no before (SETUP_DECLINED_FILE)
|
|
871
|
+
* or turned the question off (MU_NO_SETUP=1). Nothing gives a model: no credential in auth.json, no provider in
|
|
872
|
+
* models.json, no default provider in settings.json, no key of MODEL_KEY_VARIABLES in the environment or the .env.
|
|
873
|
+
* A file that cannot be read counts as set up: the question is for an empty home, never for a broken one.
|
|
874
|
+
*
|
|
875
|
+
* `fs` is { exists, readFile }; `envText` is the .env the launcher reads, when there is one.
|
|
876
|
+
*/
|
|
877
|
+
export function planFirstRun({ platform, env, argv, interactive, agentDir, envText, fs }) {
|
|
878
|
+
if (!interactive) return false;
|
|
879
|
+
const off = muEnv("NO_SETUP", env);
|
|
880
|
+
if (off && off !== "0" && off.toLowerCase() !== "false") return false;
|
|
881
|
+
if (argv[0] !== undefined && PI_COMMANDS.has(argv[0])) return false;
|
|
882
|
+
if (argv.some((arg) => NO_SETUP_FLAGS.has(arg.split("=")[0]))) return false;
|
|
883
|
+
const path = pathFor(platform);
|
|
884
|
+
if (fs.exists(path.join(agentDir, SETUP_DECLINED_FILE))) return false;
|
|
885
|
+
const read = (name) => {
|
|
886
|
+
const file = path.join(agentDir, name);
|
|
887
|
+
if (!fs.exists(file)) return {};
|
|
888
|
+
try {
|
|
889
|
+
const text = fs.readFile(file).replace(/^/, "");
|
|
890
|
+
const value = text.trim() ? JSON.parse(text) : {};
|
|
891
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
892
|
+
} catch {
|
|
893
|
+
return undefined;
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
const auth = read("auth.json");
|
|
897
|
+
if (!auth || Object.keys(auth).length > 0) return false;
|
|
898
|
+
const models = read("models.json");
|
|
899
|
+
const providers = models?.providers;
|
|
900
|
+
if (!models || (providers && typeof providers === "object" && Object.keys(providers).length > 0)) return false;
|
|
901
|
+
const settings = read("settings.json");
|
|
902
|
+
if (!settings || settings.defaultProvider) return false;
|
|
903
|
+
if (MODEL_KEY_VARIABLES.some((name) => env[name])) return false;
|
|
904
|
+
if (envText !== undefined) {
|
|
905
|
+
const { entries } = parseEnvFile(envText);
|
|
906
|
+
if (entries.some(([name, value]) => value && MODEL_KEY_VARIABLES.includes(name))) return false;
|
|
907
|
+
}
|
|
908
|
+
return true;
|
|
909
|
+
}
|
|
910
|
+
|
|
601
911
|
// ---------------------------------------------------------------------------------------------------------
|
|
602
912
|
// mu link | unlink
|
|
603
913
|
// ---------------------------------------------------------------------------------------------------------
|
|
@@ -1047,6 +1357,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1047
1357
|
home,
|
|
1048
1358
|
execPath: process.execPath,
|
|
1049
1359
|
canExec,
|
|
1360
|
+
stripsTypes: Boolean(process.features.typescript),
|
|
1050
1361
|
fs: { exists: existsSync, isDir, readFile: readText },
|
|
1051
1362
|
});
|
|
1052
1363
|
if (plan.error) {
|
|
@@ -1124,6 +1435,30 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1124
1435
|
}
|
|
1125
1436
|
return handOver({ command: plan.command, args: plan.args, env: plan.env, strategy });
|
|
1126
1437
|
}
|
|
1438
|
+
// 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;
|
|
1440
|
+
if (command === "setup") {
|
|
1441
|
+
const plan = planSetup({
|
|
1442
|
+
platform,
|
|
1443
|
+
env,
|
|
1444
|
+
argv: rest,
|
|
1445
|
+
root,
|
|
1446
|
+
home,
|
|
1447
|
+
execPath: process.execPath,
|
|
1448
|
+
stripsTypes: Boolean(process.features.typescript),
|
|
1449
|
+
fs: { exists: existsSync, isDir, readFile: readText },
|
|
1450
|
+
});
|
|
1451
|
+
if (plan.error) {
|
|
1452
|
+
err(plan.error);
|
|
1453
|
+
return plan.code ?? 1;
|
|
1454
|
+
}
|
|
1455
|
+
// The key leaves this process's own command line too, as far as the platform lets a process rewrite it.
|
|
1456
|
+
if (plan.keyGiven) process.title = "mu setup";
|
|
1457
|
+
mkdirSync(plan.agentDir, { recursive: true });
|
|
1458
|
+
const code = await handOver(plan);
|
|
1459
|
+
if (code !== SETUP_EXIT_START) return code;
|
|
1460
|
+
sessionArgv = [];
|
|
1461
|
+
}
|
|
1127
1462
|
if (command === "doctor") {
|
|
1128
1463
|
const link = linkPath({ platform, env, home });
|
|
1129
1464
|
return handOver({
|
|
@@ -1184,15 +1519,51 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1184
1519
|
return 0;
|
|
1185
1520
|
}
|
|
1186
1521
|
|
|
1522
|
+
// A first start with nothing to work with: one question, and the wizard, before the session (`mu setup`). Never
|
|
1523
|
+
// right after `mu setup` itself: its subscription route leaves nothing written, and the person was just asked.
|
|
1524
|
+
const muDir = muHome({ home, platform, isDir });
|
|
1525
|
+
let envText;
|
|
1526
|
+
try {
|
|
1527
|
+
envText = readText(envFilePath({ layout, root, muDir, platform }));
|
|
1528
|
+
} catch {}
|
|
1529
|
+
const firstRun = command !== "setup" && planFirstRun({
|
|
1530
|
+
platform,
|
|
1531
|
+
env,
|
|
1532
|
+
argv: sessionArgv,
|
|
1533
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
1534
|
+
agentDir: agentDirFor({ env, muDir, platform }),
|
|
1535
|
+
envText,
|
|
1536
|
+
fs: { exists: existsSync, readFile: readText },
|
|
1537
|
+
});
|
|
1538
|
+
if (firstRun) {
|
|
1539
|
+
const setup = planSetup({
|
|
1540
|
+
platform,
|
|
1541
|
+
env,
|
|
1542
|
+
argv: ["--first-run"],
|
|
1543
|
+
root,
|
|
1544
|
+
home,
|
|
1545
|
+
execPath: process.execPath,
|
|
1546
|
+
stripsTypes: Boolean(process.features.typescript),
|
|
1547
|
+
fs: { exists: existsSync, isDir, readFile: readText },
|
|
1548
|
+
});
|
|
1549
|
+
if (!setup.error) {
|
|
1550
|
+
mkdirSync(setup.agentDir, { recursive: true });
|
|
1551
|
+
// Whatever the wizard ends with, the session follows (pi says itself when there is no model), unless it was cancelled.
|
|
1552
|
+
if ((await handOver(setup)) === SETUP_EXIT_CANCELLED) return SETUP_EXIT_CANCELLED;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Planned after the wizard: what it wrote into the .env (the Jev key) goes to the session too.
|
|
1187
1557
|
const plan = planLaunch({
|
|
1188
1558
|
platform,
|
|
1189
1559
|
env,
|
|
1190
|
-
argv,
|
|
1560
|
+
argv: sessionArgv,
|
|
1191
1561
|
root,
|
|
1192
1562
|
home,
|
|
1193
1563
|
execPath: process.execPath,
|
|
1194
1564
|
canExec,
|
|
1195
1565
|
wsl,
|
|
1566
|
+
stripsTypes: Boolean(process.features.typescript),
|
|
1196
1567
|
fs: { exists: existsSync, isDir, readFile: readText },
|
|
1197
1568
|
});
|
|
1198
1569
|
if (plan.error) {
|
|
@@ -1200,18 +1571,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1200
1571
|
return 1;
|
|
1201
1572
|
}
|
|
1202
1573
|
|
|
1203
|
-
|
|
1204
|
-
ensureAppView({ platform, app: plan.appDir, upstream: path.join(root, "packages", "coding-agent") });
|
|
1205
|
-
}
|
|
1206
|
-
mkdirSync(plan.agentDir, { recursive: true });
|
|
1207
|
-
for (const note of plan.notes) err(note);
|
|
1208
|
-
// The local judge is one shared sidecar; starting it is idempotent and must never block mu.
|
|
1209
|
-
if (plan.startJudge) {
|
|
1210
|
-
const started = spawnSync(path.join(bin, "kyrn-judge-local"), ["start"], { stdio: "ignore", env: plan.env });
|
|
1211
|
-
if (started.status !== 0) {
|
|
1212
|
-
err("mu: the local judge did not start (mu judge status); decisions fall back to pi's behaviour");
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1574
|
+
prepareLaunch({ plan, platform, root, bin, err });
|
|
1215
1575
|
if (plan.preface) out(plan.preface);
|
|
1216
1576
|
return handOver(plan);
|
|
1217
1577
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "mu: a coding agent that thinks before it acts. A small, fast judge makes the routine calls; the big model keeps its attention for the work. Built on pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"node": ">=22.19.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@earendil-works/chord": "0.
|
|
36
|
+
"@earendil-works/chord": "0.87.1",
|
|
37
37
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
38
38
|
"jiti": "2.7.0"
|
|
39
39
|
},
|
|
40
40
|
"muBuild": {
|
|
41
|
-
"pi": "0.
|
|
41
|
+
"pi": "0.87.1",
|
|
42
42
|
"judge": "0.1.0",
|
|
43
|
-
"commit": "
|
|
43
|
+
"commit": "c645b9c64"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -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-S7SZN6Z3.js";import{sanitizeSurrogates}from"./chunk-L2ZPNLYD.js";import{headersToRecord}from"./chunk-6R7UI4IY.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-RCZIEVGO.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.251",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(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 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};
|