mu-agent 0.1.8 → 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 +27 -0
- package/README.md +34 -30
- package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
- package/dist/bundle/chunks/anthropic.js +1 -1
- 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-S3GGRYIO.js → chunk-5AGIVGSV.js} +1 -1
- package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
- package/dist/bundle/chunks/{chunk-F5ZABL6Z.js → chunk-7CBJINYJ.js} +2 -2
- 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-H3QXYIF7.js → chunk-CF5GWZHW.js} +1 -1
- package/dist/bundle/chunks/{chunk-4OBXYPH4.js → chunk-DNNHZBQR.js} +1 -1
- 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-TAOL3JFA.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-NG4PO5FP.js → chunk-O7IPTASE.js} +120 -103
- package/dist/bundle/chunks/{chunk-LD2P6SFZ.js → chunk-PMRZO46Y.js} +1 -1
- package/dist/bundle/chunks/chunk-QOEEJKS4.js +9 -0
- package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
- package/dist/bundle/chunks/{chunk-NTSWBG4X.js → chunk-RAQ6TU76.js} +1 -1
- 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-RLZVFGW4.js → chunk-X234222Q.js} +29 -92
- package/dist/bundle/chunks/{cli-AOVD3SSZ.js → cli-722OL3K5.js} +4 -4
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +117 -13
- 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-XMFHGQC5.js → google-generative-ai-D2VJQBTK.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-4XRRNP74.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-TEDK3E5I.js → lib-4AVRLBHM.js} +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-XT44PI3C.js → llama-cpp-classify-5YHLY3RC.js} +2 -2
- 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-N5BSDOA5.js → node-KCMANYC2.js} +1 -1
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +1 -1
- 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-ZVXWCSIM.js → openrouter-images-7T452AS5.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
- 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/rpc-entry.js +1 -1
- package/dist/core/export-html/template.js +21 -16
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/light.json +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 +13 -16
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +22 -29
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/cli-integration.md +1 -1
- package/docs/cli.md +22 -10
- package/docs/codemode.md +29 -6
- package/docs/compaction.md +5 -5
- package/docs/custom-provider.md +53 -1
- package/docs/docs.json +8 -0
- package/docs/environment-variables.md +3 -1
- package/docs/extensions.md +122 -13
- package/docs/json.md +3 -3
- package/docs/keybindings.md +5 -4
- package/docs/llama-cpp.md +9 -2
- package/docs/mcp.md +4 -2
- package/docs/message-types.md +22 -4
- package/docs/models-configuration.md +187 -0
- package/docs/models.md +18 -2
- package/docs/nvidia-rtx-llama-cpp.md +96 -0
- package/docs/providers.md +47 -0
- package/docs/sessions.md +1 -1
- package/docs/settings.md +8 -5
- package/docs/terminal-setup.md +14 -0
- package/docs/themes.md +4 -2
- package/docs/tui.md +71 -1
- package/docs/usage.md +1 -1
- package/examples/README.md +0 -3
- 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/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/minimal-mode.ts +4 -5
- 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/judge/dist/auth.js +41 -10
- package/judge/dist/import.js +26 -21
- package/judge/dist/setup.js +124 -120
- package/judge/manifest.json +630 -250
- package/judge/{dist/kyrn-judge.js → mu/index.js} +1393 -545
- package/judge/themes/mu-dark.json +80 -0
- package/judge/themes/mu-light.json +80 -0
- package/kyrn/bin/kyrn-doctor +17 -17
- package/kyrn/bin/kyrn-judge-local +2 -2
- package/kyrn/bin/kyrn-ledger +1 -1
- package/kyrn/bin/mu.mjs +74 -47
- package/package.json +4 -5
- package/dist/bundle/chunks/anthropic-messages-MI4QHRXW.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-E3QGN4VN.js +0 -2
- package/dist/bundle/chunks/chunk-33KL6IIQ.js +0 -20
- package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
- package/dist/bundle/chunks/chunk-C47CLQZK.js +0 -2
- package/dist/bundle/chunks/chunk-HQHD6PZI.js +0 -2
- package/dist/bundle/chunks/chunk-KJUDFE6Y.js +0 -11
- package/dist/bundle/chunks/chunk-TE3GUV6H.js +0 -9
- package/dist/bundle/chunks/chunk-VIV3CWXG.js +0 -2
- package/dist/bundle/chunks/chunk-WE4MXUQS.js +0 -11
- package/dist/bundle/chunks/chunk-Y2PP32XV.js +0 -2
- package/dist/bundle/chunks/chunk-YLY6CKPK.js +0 -132
- package/dist/bundle/chunks/chunk-ZE5FMF3V.js +0 -99
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NM3JRRWQ.js +0 -2
- package/dist/bundle/chunks/easter-egg-3d-G2LUBEMZ.js +0 -2
- package/dist/bundle/chunks/execute-MZVUC6BB.js +0 -388
- package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
- package/dist/bundle/chunks/mistral-conversations-Q22M3IBG.js +0 -5
- package/dist/bundle/chunks/openai-codex-responses-4MYQSO5E.js +0 -10
- package/dist/bundle/chunks/openai-completions-OSRCWAAA.js +0 -7
- package/dist/bundle/chunks/openai-responses-UHF3DHNG.js +0 -3
- package/dist/bundle/chunks/runtime-VJMMDLVH.js +0 -2
- package/dist/bundle/chunks/typesafe-system-one-PRR5K6CI.js +0 -2
- package/dist/bundle/chunks/virtual-modules-RJXJGCPI.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.10] - 2026-10-21
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- English: the kernel's messages (the `en` side of `say({ zh, en })`), the manifest's titles and summaries, `mu --help`, `mu doctor` and `mu ledger` were rewritten after `docs/writing-style.md`. The Chinese text is unchanged.
|
|
10
|
+
- Themes: the package ships `judge/themes/mu-dark.json` and `mu-light.json`. An interactive `mu` passes `--theme <judge/themes>`, and `--use-theme mu-light/mu-dark` unless the command line has `--use-theme` or `settings.json` names a theme. `-p`, `--print` and `--mode` get neither. `system` is still pi's theme.
|
|
11
|
+
- pi's startup list names the judgment layer `mu`, not `kyrn-judge.js`: its bundle in the package is `judge/mu/index.js` (it was `judge/dist/kyrn-judge.js`).
|
|
12
|
+
- The package's description and README say what mu does by default: 38 of the 40 decision points act from the start, and approvals fall back to asking you.
|
|
13
|
+
- The welcome screen drops its box: the wordmark, the version, pi's version, then the judge, the model and the working directory, and a closing rule. Judge names show as `Jev` and `Laya`; a verdict's mark is a pink `◆`.
|
|
14
|
+
|
|
15
|
+
## [0.1.9] - 2026-10-19
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Two decision points, 40 in all:
|
|
20
|
+
- `tool.description` (feature `injection`, option `descriptions`, on by default): every MCP tool's description, with its parameters' descriptions, is asked about once per server when it first appears and again when it changes. Does it ask the AI for more than calling the tool? Over 0.5 the tool is removed from the active tools before any request carries it (before the turn, and before the results of a step in which a server connected), kept off at each step, and calls to it are blocked; the user is told once. Without a verdict only `<IMPORTANT>` blocks and "do not tell the user" count. Measured in `kyrn/docs/features/tool-descriptions.md`.
|
|
21
|
+
- `skill.capture` (feature `procedures`): after a run of `minSteps` (6) or more steps that ran `minCommands` (2) or more shell commands and did not end in an error, the judge says whether it was a reusable procedure. Over 0.7 the writer model (else the conversation's model) drafts a SKILL.md, kept in `<agent dir>/mu/skill-drafts` where pi does not load it. `/skills`, `/skills show|accept|reject <name>`; `accept --project` installs into the project. At most `maxPending` (3) drafts per project. Measured in `kyrn/docs/features/procedures.md`.
|
|
22
|
+
- `tool.injection` screens bash and PowerShell results when the command runs a fetching program (`features.injection.fetchCommands`: curl, wget, gh, glab, lynx, w3m, Invoke-WebRequest, Invoke-RestMethod, iwr, irm), unless every address it names is local; `gh` and `glab` always count.
|
|
23
|
+
- The report of a `delegate` or `hive` sub-agent whose tool results had passages withheld comes back under a warning; the parent counts the withheld notes in the child's event stream, with no extra judge call.
|
|
24
|
+
- Built on pi 1.3.0 and upstream main after it (e28e70804, d2e7d8b7c).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Claude Sonnet 5.5 keeps Anthropic's cache read price, and Kimi K3 on Moonshot its official rates, when models.dev lists others.
|
|
29
|
+
- The goal's time cap and the web download cap show their units as units.
|
|
30
|
+
- `@earendil-works/pi-telemetry` declares the `source` export condition, so tests that run without a build resolve it.
|
|
31
|
+
|
|
5
32
|
## [0.1.8] - 2026-10-06
|
|
6
33
|
|
|
7
34
|
### Added
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# mu
|
|
2
2
|
|
|
3
|
-
**A coding agent
|
|
3
|
+
**A coding agent with a judgment kernel.** It hands its routine decisions to a small, fast judge model, so the main model can keep its attention on the work.
|
|
4
4
|
|
|
5
|
-
> **Early development.**
|
|
5
|
+
> **Early development.** The authors use mu every day, but names, settings and file formats may still change. Source, docs and the desktop app: [github.com/qybaihe/mu](https://github.com/qybaihe/mu) (README in English, 简体中文, 繁體中文, 日本語 and 한국어).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -11,50 +11,54 @@ npm i -g mu-agent
|
|
|
11
11
|
mu
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
You need Node.js 22.19 or newer. The package is
|
|
14
|
+
You need Node.js 22.19 or newer. The package is `mu-agent`; the command is `mu`. It runs on macOS, Linux, Windows and WSL.
|
|
15
15
|
|
|
16
|
-
`mu setup` connects a model from your shell
|
|
16
|
+
`mu setup` connects a model from your shell. Paste an API key and mu detects the service from the key's format (DeepSeek, Qwen, Kimi, GLM, SiliconFlow, StepFun, OpenRouter, OpenCode Zen, OpenAI, Anthropic, Google Gemini, xAI), or pick Ollama or your own endpoint. It checks the key with one request, picks a starting model and sets up the judge. If no model is set up yet, the first `mu` run offers to start setup.
|
|
17
17
|
|
|
18
|
-
Inside mu, `/login` signs in to a
|
|
18
|
+
Inside mu, `/login` signs in to a provider or a subscription and `/model` switches models. `/help` lists everything. `mu doctor` checks your setup from the shell.
|
|
19
19
|
|
|
20
20
|
## What it adds to pi
|
|
21
21
|
|
|
22
|
-
mu is built on [pi](https://github.com/earendil-works/pi). It hands the small questions a coding agent keeps asking to a **judge**: is this message a new task or a correction, does this command need your permission, which part of a long test log matters, which
|
|
22
|
+
mu is built on [pi](https://github.com/earendil-works/pi). It hands the small questions a coding agent keeps asking to a **judge**: is this message a new task or a correction, does this command need your permission, which part of a long test log matters, which subagent fits a job, what should the browser click next. Code acts on the answers, and the main model only sees what it needs.
|
|
23
23
|
|
|
24
|
-
- **Every decision is visible.** Each
|
|
25
|
-
- **Every decision
|
|
26
|
-
-
|
|
24
|
+
- **Every decision is visible.** Each decision point is `off`, `shadow` (asked and logged, but not acted on) or `active`. `/ledger` and `mu ledger` show the verdicts.
|
|
25
|
+
- **Every decision has a fallback.** When the judge is unsure, slow or unreachable, a plain rule decides, or pi's default behavior runs. For approvals, the fallback is to ask you.
|
|
26
|
+
- **And more:** a task frame that keeps your constraints in your own words, three permission modes (`/permissions`), goal mode (`/goal`), a plain-language progress board (`/board`), checkpoints and `/rewind`, subagents that edit in their own git worktrees (`delegate`), read-only hives of investigators (`hive`), a judge-driven browser (`browse`), and the rules, skills and MCP servers you already set up in Claude Code, Cursor and Codex.
|
|
27
27
|
|
|
28
28
|
## Choose a judge
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Out of the box, Jev 1.13 on OpenCode Zen answers for free (for a limited time) and needs no key. What it judges goes to OpenCode, which doesn't train on it, and mu reminds you of that once a day. To send nothing anywhere, start mu with `MU_JUDGE=off`, or use the local judge, Laya.
|
|
31
31
|
|
|
32
|
-
- **Jev** (hosted): set `TYPESAFE_API_KEY` (TypeSafe), `MU_JUDGE_OPENROUTER_API_KEY` (Jev on OpenRouter), `AI_GATEWAY_API_KEY` (Vercel AI Gateway)
|
|
33
|
-
- **Another classifier** from pi's catalog: `/mu judge classifier:<provider>/<model>`,
|
|
34
|
-
- **CLM** (self-hosted; its encoder needs a GPU): start `clm-serve` from [Contrastive-LM/CLM](https://github.com/Contrastive-LM/CLM), then `/mu judge clm`. For a server on another machine, add `"judges": { "clm": { "type": "clm", "baseUrl": "http://<host>:8700" } }` to `~/.mu/agent/mu.json`.
|
|
35
|
-
- **Laya** (local, macOS on Apple
|
|
32
|
+
- **Jev** (hosted): set `TYPESAFE_API_KEY` (TypeSafe), `MU_JUDGE_OPENROUTER_API_KEY` (Jev on OpenRouter), `AI_GATEWAY_API_KEY` (Vercel AI Gateway), `OPENCODE_API_KEY` (OpenCode Zen) or `CLOUDFLARE_API_KEY` with `CLOUDFLARE_ACCOUNT_ID` (Cloudflare Workers AI) in your environment, or add it to `~/.mu/.env` as `KEY=value`. `mu setup` asks for a key and writes it there. mu reads that file as data and never prints it, and starts using the key automatically.
|
|
33
|
+
- **Another classifier** from pi's catalog: `/mu judge classifier:<provider>/<model>`, for example Cloudflare's Clef (`clef`, `clef-flash`) or a System One model on OpenRouter, with that provider's key.
|
|
34
|
+
- **CLM** (self-hosted; its encoder needs a GPU): start `clm-serve` from [Contrastive-LM/CLM](https://github.com/Contrastive-LM/CLM), then run `/mu judge clm`. For a server on another machine, add `"judges": { "clm": { "type": "clm", "baseUrl": "http://<host>:8700" } }` to `~/.mu/agent/mu.json`. If the server was started with `CLM_API_KEY`, set the same value in `MU_JUDGE_CLM_API_KEY`. `mu doctor` checks the server.
|
|
35
|
+
- **Laya** (local, macOS on Apple silicon): `mu judge setup` installs it into `~/.mu/local-judge`. It downloads about 930 MB, and only when you run that command.
|
|
36
36
|
- **Any model you already use:** `/mu judge llm:<provider>/<model>`.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
38 of the 40 decision points act on their verdicts from the start (`active`); `context.compact` and `output.drift` belong to features that are off until you turn them on. To only record what the judge would do, run `/mu mode default shadow`, or put `"modes": { "default": "shadow" }` in `~/.mu/agent/mu.json`.
|
|
39
39
|
|
|
40
40
|
## Commands
|
|
41
41
|
|
|
42
42
|
```text
|
|
43
|
-
mu
|
|
44
|
-
mu "prompt"
|
|
45
|
-
mu -p "prompt" one
|
|
46
|
-
mu -c | -r continue the last session | pick
|
|
47
|
-
mu setup
|
|
48
|
-
mu judge <cmd> the local judge (
|
|
49
|
-
mu ledger [n] [--json]
|
|
50
|
-
mu
|
|
51
|
-
mu
|
|
52
|
-
mu
|
|
53
|
-
mu
|
|
54
|
-
mu help | version
|
|
43
|
+
mu start a session in the current directory
|
|
44
|
+
mu "prompt" start a session with this prompt
|
|
45
|
+
mu -p "prompt" run one prompt, print the answer and exit
|
|
46
|
+
mu -c | -r continue the last session | pick a session to resume
|
|
47
|
+
mu setup connect a model and choose a judge (see mu setup --help for scripting and services)
|
|
48
|
+
mu judge <cmd> manage the local judge, Laya (macOS on Apple silicon): setup | start | stop | status | run
|
|
49
|
+
mu ledger [n] [--json] print the judge's verdicts from the last n sessions
|
|
50
|
+
mu import --list | <file>... import Claude Code and Codex conversations (mu import --help)
|
|
51
|
+
mu doctor check the installation, the judges and the connections
|
|
52
|
+
mu auth <cmd> sign-in helper for the desktop app: status | login | logout
|
|
53
|
+
mu link | unlink put the mu command on your PATH | remove it
|
|
54
|
+
mu help | version show this help | print the version
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
`mu --help`
|
|
57
|
+
Everything else goes to pi unchanged: `mu --help` also shows pi's options. mu keeps its files in `~/.mu`, separate from a regular pi install in `~/.pi`.
|
|
58
|
+
|
|
59
|
+
## Themes
|
|
60
|
+
|
|
61
|
+
In the terminal, mu starts in its own themes, `mu-dark` or `mu-light` to match your terminal, until you pick a theme in `/settings`. Choose `system` there to use your terminal's own palette.
|
|
58
62
|
|
|
59
63
|
## Update and remove
|
|
60
64
|
|
|
@@ -63,8 +67,8 @@ npm i -g mu-agent@latest
|
|
|
63
67
|
npm rm -g mu-agent
|
|
64
68
|
```
|
|
65
69
|
|
|
66
|
-
Removing the package
|
|
70
|
+
Removing the package keeps `~/.mu` (your sessions, settings and sign-ins).
|
|
67
71
|
|
|
68
72
|
## License
|
|
69
73
|
|
|
70
|
-
MIT. pi is by Mario Zechner and contributors
|
|
74
|
+
MIT. pi is by Mario Zechner and contributors. Third-party code in the judgment kernel is listed in `judge/THIRD_PARTY_NOTICES.md`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
+
import{ANTHROPIC_FEDERATION_RULE_ID_ENV,ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,ANTHROPIC_ORGANIZATION_ID_ENV,ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,ANTHROPIC_WORKSPACE_ID_ENV}from"./chunk-UKVNB6C4.js";import{buildCopilotDynamicHeaders,hasCopilotVisionInput}from"./chunk-PGXDEOVV.js";import{Anthropic}from"./chunk-7CBJINYJ.js";import{retryProviderRequest}from"./chunk-PMRZO46Y.js";import{adjustMaxTokensForThinking,buildBaseOptions,clampMaxTokensToContext,getJsonSchemaToolParameters,getPiUserAgent,resolveJsonSchemaStrictSampling,splitErrorToolResultImages,transformMessages}from"./chunk-R4VPBBDS.js";import{sanitizeSurrogates}from"./chunk-L2ZPNLYD.js";import{headersToRecord}from"./chunk-UTB4DTYQ.js";import{getProviderEnvValue}from"./chunk-7DDKXS2Q.js";import{parseJsonWithRepair,parseStreamingJson,parseToolCallArguments}from"./chunk-3V45WARH.js";import{calculateCost,getCurrentTools,getInitialSystemMessage,getSystemMessageText,renderSystemMessageUpdate,resolveTranscript}from"./chunk-WCGU75WO.js";import{AssistantMessageEventStream,appendAssistantMessageDiagnostic}from"./chunk-LPXNMA2W.js";import"./chunk-JXWJOIH4.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 convertImageBlock(image){return{type:"image",source:{type:"base64",media_type:image.mimeType,data:image.data}}}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)}:convertImageBlock(block));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",INLINE_TOOLS_BETA="inline-tools-2026-09-15",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 hasRequestAuth(apiKey,headers){return!!apiKey||hasHeader(headers,"authorization")||hasHeader(headers,"x-api-key")||hasHeader(headers,"cf-aig-authorization")}function assertRequestAuth(provider,apiKey,headers){if(!hasRequestAuth(apiKey,headers))throw new Error(`No API key for provider: ${provider}`)}var PiAnthropic=class extends Anthropic{_shouldResolveDefaultCredentials(){return!1}};function getAnthropicFederation(model,apiKey,headers,env){if(model.provider!=="anthropic"||hasRequestAuth(apiKey,headers))return;let federationRuleId=getProviderEnvValue(ANTHROPIC_FEDERATION_RULE_ID_ENV,env),organizationId=getProviderEnvValue(ANTHROPIC_ORGANIZATION_ID_ENV,env),identityTokenFile=getProviderEnvValue(ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,env);if(!(!federationRuleId||!organizationId||!identityTokenFile))return{organization_id:organizationId,workspace_id:getProviderEnvValue(ANTHROPIC_WORKSPACE_ID_ENV,env),authentication:{type:"oidc_federation",federation_rule_id:federationRuleId,service_account_id:getProviderEnvValue(ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,env),identity_token:{source:"file",path:identityTokenFile}}}}var federationClient,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 output={role:"assistant",content:[],api:model.api,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 client,isOAuth,usageModel=model,inputTransformations;if(options?.client)client=options.client,isOAuth=!1;else{let apiKey=options?.apiKey,federation=getAnthropicFederation(model,apiKey,options?.headers,options?.env);federation||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,federation);client=created.client,isOAuth=created.isOAuthToken}let requestOptions={...options?.signal?{signal:options.signal}:{},...options?.timeoutMs!==void 0?{timeout:options.timeoutMs}:{},maxRetries:0},disablePreferredStrictTools=!1,response;for(;;){options?.signal?.throwIfAborted();let built=buildParams(model,normalizedContext,isOAuth,options,disablePreferredStrictTools);built.providerThinkingLevel&&(output.providerThinkingLevel=built.providerThinkingLevel);let params=built.params,nextParams=await options?.onPayload?.(params,model);nextParams!==void 0&&(params={...nextParams,stream:!0});try{response=await retryProviderRequest(()=>client.beta.messages.create(params,requestOptions).asResponse(),{maxRetries:options?.maxRetries,maxRetryDelayMs:options?.maxRetryDelayMs,signal:options?.signal});break}catch(error){if(options?.signal?.aborted||disablePreferredStrictTools||!built.hasPreferredStrictTools||!(error instanceof Anthropic.APIError)||error.status!==400||error.type!=="invalid_request_error"||!["The compiled grammar is too large","Too many strict tools (","Schemas contains too many parameters with union types ("].some(message=>error.message.includes(message)))throw error;disablePreferredStrictTools=!0,appendAssistantMessageDiagnostic(output,{type:"anthropic_strict_tools_fallback",timestamp:Date.now(),error:{message:error.message},details:{reason:"strict_tool_limits_exceeded"}})}}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"&&(Object.assign(block,parseToolCallArguments(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)=>{getAnthropicFederation(model,options?.apiKey,options?.headers,options?.env)||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,federation){if(model.provider==="github-copilot")return{client:new PiAnthropic({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 PiAnthropic({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);if(federation){let key=JSON.stringify([model.baseUrl,federation]);if(federationClient?.key!==key||federationClient.fetch!==fetch){let client2=new PiAnthropic({apiKey:null,authToken:null,config:federation,baseURL:model.baseUrl,dangerouslyAllowBrowser:!0,fetch});federationClient={key,fetch,client:client2}}return{client:federationClient.client.withOptions({defaultHeaders}),isOAuthToken:!1}}return{client:new PiAnthropic({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(INLINE_TOOLS_BETA),[...new Set(features)]}function buildParams(model,context,isOAuthToken2,options,disablePreferredStrictTools=!1){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,hasPreferredStrictTools=!1,convertToolDefinitions=(tools,toolCacheControl2)=>{let definitions=convertTools(tools,isOAuthToken2,compat.supportsEagerToolInputStreaming,compat.supportsStrictTools,toolCacheControl2,disablePreferredStrictTools);return definitions.some((definition,index)=>{let config=tools[index].constrainedSampling;return definition.strict===!0&&config&&config.type==="json_schema"&&config.strict==="prefer"})&&(hasPreferredStrictTools=!0),definitions},initialTools=initialSystemMessage?.toolsAdded??[],nativeToolChanges=compat.supportsMidConvoSystemMessages&&compat.supportsMidConvoToolChanges&&initialTools.length>0,thinkingDisabled=model.reasoning&&options?.thinkingEnabled===!1&&model.thinkingLevelMap?.off!==null,effortMessages=model.compat?.supportsMidConvoEffort===!0&&!thinkingDisabled,converted=convertMessages(conversationMessages,isOAuthToken2,cacheControl,compat.allowEmptySignature,effortMessages?model.provider:void 0,nativeToolChanges?convertToolDefinitions:void 0),activeEffort=options?.effort??"high",betaFeatures=getBetaFeatures(model,context,isOAuthToken2,nativeToolChanges,options),params={model:model.id,messages:effortMessages?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)params.tools=[...convertToolDefinitions(initialTools,toolCacheControl),DEFERRED_TOOL_PLACEHOLDER];else{let tools=getCurrentTools(context.messages);tools.length>0&&(params.tools=convertToolDefinitions(tools,toolCacheControl))}if(thinkingDisabled)params.thinking={type:"disabled"};else if(effortMessages)params.thinking={type:"adaptive",display:options?.thinkingDisplay??"summarized",block_binding:{prefix_mismatch_behavior:"drop_block"}},params.output_config={effort:"high"};else if(model.reasoning&&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}}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,hasPreferredStrictTools,providerThinkingLevel:effortMessages?activeEffort:void 0}}function normalizeToolCallId(id){return id.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)}function convertToolResult(msg,content=msg.content){return{type:"tool_result",tool_use_id:msg.toolCallId,content:convertContentBlocks(content),is_error:msg.isError}}function convertMessages(transformedMessages,isOAuthToken2,cacheControl,allowEmptySignature=!1,managedProvider,convertToolDefinitions){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)}),convertToolDefinitions){let added=msg.toolsAdded??[],redefined=new Set(added.map(tool=>tool.name));for(let tool of msg.toolsRemoved??[])redefined.has(tool.name)||blocks.push({type:"tool_removal",tool:{type:"tool_reference",name:isOAuthToken2?toClaudeCodeName(tool.name):tool.name}});for(let definition of convertToolDefinitions(added))blocks.push({type:"tool_addition",tool:{type:"tool_definition",definition}})}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)}:convertImageBlock(item)).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=[],errorImages=[],j=i;for(;j<transformedMessages.length&&transformedMessages[j].role==="toolResult";){let toolMsg=transformedMessages[j],split=splitErrorToolResultImages(toolMsg);toolResults.push(convertToolResult(toolMsg,split?.content)),split&&errorImages.push({type:"text",text:split.caption},...split.images.map(convertImageBlock)),j++}i=j-1,params.push({role:"user",content:[...toolResults,...errorImages]})}}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}var ANTHROPIC_STRICT_UNSUPPORTED_KEYWORDS=new Set(["minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","maxItems","uniqueItems","minContains","maxContains","minProperties","maxProperties"]),ANTHROPIC_STRICT_STRING_FORMATS=new Set(["date-time","time","date","duration","email","hostname","uri","ipv4","ipv6","uuid"]),isAnthropicStrictUnsupportedKeyword=(key,value)=>ANTHROPIC_STRICT_UNSUPPORTED_KEYWORDS.has(key)?!0:key==="minItems"?value!==0&&value!==1:key==="format"?typeof value!="string"||!ANTHROPIC_STRICT_STRING_FORMATS.has(value):!1;function convertTools(tools,isOAuthToken2,supportsEagerToolInputStreaming,supportsStrictTools,cacheControl,disablePreferredStrictTools=!1){return tools?tools.map((tool,index)=>{let config=tool.constrainedSampling,strict=disablePreferredStrictTools&&config&&config.type==="json_schema"&&config.strict==="prefer"?void 0:resolveJsonSchemaStrictSampling(tool,supportsStrictTools,isAnthropicStrictUnsupportedKeyword),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};
|
|
@@ -83,4 +83,4 @@ var __require=(x=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(x,{get:(
|
|
|
83
83
|
${details?`<div class="details">${details}</div>`:""}
|
|
84
84
|
</main>
|
|
85
85
|
</body>
|
|
86
|
-
</html>`}function oauthSuccessHtml(message){return renderPage({heading:"Signed in",message})}function oauthErrorHtml(message,details){return renderPage({heading:"Sign-in did not complete",message,details})}function sendPage(response,status,html){response.writeHead(status,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),response.end(html)}async function startOAuthCallbackServer(options){let{providerName,signal}=options;if(signal?.aborted)throw new Error("Login cancelled");let resolveWait=()=>{},rejectWait=()=>{},waitPromise=new Promise((resolve,reject)=>{resolveWait=resolve,rejectWait=reject});waitPromise.catch(()=>{});let claimed=!1,settled=!1,timer,onAbort=()=>finish({error:new Error("Login cancelled")}),finish=result=>{settled||(settled=!0,timer&&clearTimeout(timer),signal?.removeEventListener("abort",onAbort),"error"in result?rejectWait(result.error):resolveWait(result.value))},server=createServer((request,response)=>{(async()=>{let url=new URL(request.url??"/","http://localhost");if(request.method!=="GET"||url.pathname!==options.path){sendPage(response,404,oauthErrorHtml("Callback route not found."));return}if(options.state!==void 0&&url.searchParams.get("state")!==options.state){sendPage(response,400,oauthErrorHtml("State mismatch."));return}if(claimed||settled){sendPage(response,409,oauthErrorHtml("This sign-in has already been handled."));return}let error=url.searchParams.get("error");if(error){let description=url.searchParams.get("error_description")??error;sendPage(response,400,oauthErrorHtml(`${providerName} authorization failed.`,description)),finish({error:new Error(`${providerName} authorization failed: ${description}`)});return}let code=url.searchParams.get("code");if(!code){sendPage(response,400,oauthErrorHtml("Missing authorization code."));return}claimed=!0;try{let value=await options.complete(code);sendPage(response,200,oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`)),finish({value})}catch(error2){let failure=error2 instanceof Error?error2:new Error(String(error2));sendPage(response,502,oauthErrorHtml(`${providerName} sign-in failed.`,failure.message)),finish({error:failure})}})()});await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(options.port,options.host,()=>{server.off("error",reject),resolve()})});let address=server.address();if(!address||typeof address=="string")throw server.close(),new Error("OAuth callback server did not bind to TCP");server.on("error",error=>finish({error})),signal?.addEventListener("abort",onAbort,{once:!0}),options.timeoutMs!==void 0&&(timer=setTimeout(()=>finish({error:new Error(`${providerName} sign-in timed out`)}),options.timeoutMs));let redirectHost=options.redirectHost??options.host;return{redirectUri:`http://${redirectHost.includes(":")?`[${redirectHost}]`:redirectHost}:${address.port}${options.path}`,wait:()=>waitPromise,cancel:()=>{claimed||finish({value:void 0})},close:()=>{finish({error:new Error("OAuth callback server closed")}),server.close()}}}async function waitForCallbackOrManualInput(interaction,callback,prompt){let manualAbort=new AbortController,manualError,manual=interaction.prompt({type:"manual_code",...prompt,signal:manualAbort.signal}).then(input=>(callback?.cancel(),input)).catch(error=>{manualError=error instanceof Error?error:new Error(String(error)),callback?.cancel()});try{let value=await callback?.wait();if(manualError)throw manualError;if(value!==void 0)return{type:"callback",value};let input=await manual;if(manualError)throw manualError;return{type:"manual",input:input??""}}finally{manualAbort.abort()}}function base64urlEncode(bytes){let binary="";for(let byte of bytes)binary+=String.fromCharCode(byte);return btoa(binary).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function generatePKCE(){let verifierBytes=new Uint8Array(32);crypto.getRandomValues(verifierBytes);let verifier=base64urlEncode(verifierBytes),data=new TextEncoder().encode(verifier),hashBuffer=await crypto.subtle.digest("SHA-256",data),challenge=base64urlEncode(new Uint8Array(hashBuffer));return{verifier,challenge}}var decode=s=>atob(s),CLIENT_ID=decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl"),AUTHORIZE_URL="https://claude.ai/oauth/authorize",TOKEN_URL="https://platform.claude.com/v1/oauth/token",CALLBACK_HOST=getProviderEnvValue("PI_OAUTH_CALLBACK_HOST")||"127.0.0.1",CALLBACK_PORT=53692,CALLBACK_PATH="/callback",REDIRECT_URI=`http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`,COPY_CODE_REDIRECT_URI="https://platform.claude.com/oauth/code/callback",ANTHROPIC_BROWSER_LOGIN_METHOD="browser",ANTHROPIC_COPY_CODE_LOGIN_METHOD="copy_code",SCOPES="org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";function parseAuthorizationInput(input){let value=input.trim();if(!value)return{};try{let url=new URL(value);return{code:url.searchParams.get("code")??void 0,state:url.searchParams.get("state")??void 0}}catch{}if(value.includes("#")){let[code,state]=value.split("#",2);return{code,state}}if(value.includes("code=")){let params=new URLSearchParams(value);return{code:params.get("code")??void 0,state:params.get("state")??void 0}}return{code:value}}function formatErrorDetails(error){if(error instanceof Error){let details=[`${error.name}: ${error.message}`],errorWithCode=error;return errorWithCode.code&&details.push(`code=${errorWithCode.code}`),typeof errorWithCode.errno<"u"&&details.push(`errno=${String(errorWithCode.errno)}`),typeof error.cause<"u"&&details.push(`cause=${formatErrorDetails(error.cause)}`),error.stack&&details.push(`stack=${error.stack}`),details.join("; ")}return String(error)}async function postJson(url,body,signal){let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(body),signal:AbortSignal.any([signal,AbortSignal.timeout(3e4)])}),responseBody=await response.text();if(!response.ok)throw new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);return responseBody}async function exchangeAuthorizationCode(code,state,verifier,redirectUri,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"authorization_code",client_id:CLIENT_ID,code,state,redirect_uri:redirectUri,code_verifier:verifier},signal)}catch(error){throw new Error(`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`)}let tokenData;try{tokenData=JSON.parse(responseBody)}catch(error){throw new Error(`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:tokenData.refresh_token,access:tokenData.access_token,expires:Date.now()+tokenData.expires_in*1e3-300*1e3}}async function loginAnthropic(interaction){let{verifier,challenge}=await generatePKCE(),callback=await startOAuthCallbackServer({providerName:"Anthropic",host:CALLBACK_HOST,port:CALLBACK_PORT,path:CALLBACK_PATH,state:verifier,complete:async code=>code,signal:interaction.signal}).catch(()=>{});try{let authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:REDIRECT_URI,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."});let result=await waitForCallbackOrManualInput(interaction,callback,{message:"Complete login in your browser, or paste the authorization code / redirect URL here:",placeholder:REDIRECT_URI}),code,state=verifier;if(result.type==="callback")code=result.value;else{let parsed=parseAuthorizationInput(result.input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");code=parsed.code,state=parsed.state??verifier}if(!code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(code,state,verifier,REDIRECT_URI,interaction.signal)}finally{callback?.close()}}async function loginAnthropicCopyCode(interaction){let{verifier,challenge}=await generatePKCE(),authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:COPY_CODE_REDIRECT_URI,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser, then copy the code Anthropic shows and paste it here."});let input=await interaction.prompt({type:"manual_code",message:"Paste the code Anthropic shows after you sign in:",placeholder:"code#state",signal:interaction.signal}),parsed=parseAuthorizationInput(input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");if(!parsed.code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(parsed.code,parsed.state??verifier,verifier,COPY_CODE_REDIRECT_URI,interaction.signal)}async function refreshAnthropicToken(refreshToken,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"refresh_token",client_id:CLIENT_ID,refresh_token:refreshToken},signal)}catch(error){throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`)}let data;try{data=JSON.parse(responseBody)}catch(error){throw new Error(`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:data.refresh_token,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3}}var anthropicOAuth={name:"Anthropic (Claude Pro/Max)",isSubscription:!0,async login(interaction){let method=await interaction.prompt({type:"select",message:"Select Anthropic login method:",options:[{id:ANTHROPIC_BROWSER_LOGIN_METHOD,label:"Browser login (default)"},{id:ANTHROPIC_COPY_CODE_LOGIN_METHOD,label:"Copy code login (headless)"}]});if(method===ANTHROPIC_COPY_CODE_LOGIN_METHOD)return loginAnthropicCopyCode(interaction);if(method!==ANTHROPIC_BROWSER_LOGIN_METHOD)throw new Error(`Unknown Anthropic login method: ${method}`);return loginAnthropic(interaction)},refresh:(credential,signal)=>refreshAnthropicToken(credential.refresh,signal),async toAuth(credential){return{apiKey:credential.access}}};export{anthropicOAuth};
|
|
86
|
+
</html>`}function oauthSuccessHtml(message){return renderPage({heading:"Signed in",message})}function oauthErrorHtml(message,details){return renderPage({heading:"Sign-in did not complete",message,details})}function sendPage(response,status,html){response.writeHead(status,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),response.end(html)}async function startOAuthCallbackServer(options){let{providerName,signal}=options;if(signal?.aborted)throw new Error("Login cancelled");let resolveWait=()=>{},rejectWait=()=>{},waitPromise=new Promise((resolve,reject)=>{resolveWait=resolve,rejectWait=reject});waitPromise.catch(()=>{});let claimed=!1,settled=!1,timer,onAbort=()=>finish({error:new Error("Login cancelled")}),finish=result=>{settled||(settled=!0,timer&&clearTimeout(timer),signal?.removeEventListener("abort",onAbort),"error"in result?rejectWait(result.error):resolveWait(result.value))},server=createServer((request,response)=>{(async()=>{let url=new URL(request.url??"/","http://localhost");if(request.method!=="GET"||url.pathname!==options.path){sendPage(response,404,oauthErrorHtml("Callback route not found."));return}if(options.state!==void 0&&url.searchParams.get("state")!==options.state){sendPage(response,400,oauthErrorHtml("State mismatch."));return}if(claimed||settled){sendPage(response,409,oauthErrorHtml("This sign-in has already been handled."));return}let error=url.searchParams.get("error");if(error){let description=url.searchParams.get("error_description")??error;sendPage(response,400,oauthErrorHtml(`${providerName} authorization failed.`,description)),finish({error:new Error(`${providerName} authorization failed: ${description}`)});return}let code=url.searchParams.get("code");if(!code){sendPage(response,400,oauthErrorHtml("Missing authorization code."));return}claimed=!0;try{let value=await options.complete(code);sendPage(response,200,oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`)),finish({value})}catch(error2){let failure=error2 instanceof Error?error2:new Error(String(error2));sendPage(response,502,oauthErrorHtml(`${providerName} sign-in failed.`,failure.message)),finish({error:failure})}})()});await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(options.port,options.host,()=>{server.off("error",reject),resolve()})});let address=server.address();if(!address||typeof address=="string")throw server.close(),new Error("OAuth callback server did not bind to TCP");server.on("error",error=>finish({error})),signal?.addEventListener("abort",onAbort,{once:!0}),options.timeoutMs!==void 0&&(timer=setTimeout(()=>finish({error:new Error(`${providerName} sign-in timed out`)}),options.timeoutMs));let redirectHost=options.redirectHost??options.host;return{redirectUri:`http://${redirectHost.includes(":")?`[${redirectHost}]`:redirectHost}:${address.port}${options.path}`,wait:()=>waitPromise,cancel:()=>{claimed||finish({value:void 0})},close:()=>{finish({error:new Error("OAuth callback server closed")}),server.close()}}}async function waitForCallbackOrManualInput(interaction,callback,prompt){let manualAbort=new AbortController,manualError,manual=interaction.prompt({type:"manual_code",...prompt,signal:manualAbort.signal}).then(input=>(callback?.cancel(),input)).catch(error=>{manualError=error instanceof Error?error:new Error(String(error)),callback?.cancel()});try{let value=await callback?.wait();if(manualError)throw manualError;if(value!==void 0)return{type:"callback",value};let input=await manual;if(manualError)throw manualError;return{type:"manual",input:input??""}}finally{manualAbort.abort()}}function base64urlEncode(bytes){let binary="";for(let byte of bytes)binary+=String.fromCharCode(byte);return btoa(binary).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function generatePKCE(){let verifierBytes=new Uint8Array(32);crypto.getRandomValues(verifierBytes);let verifier=base64urlEncode(verifierBytes),data=new TextEncoder().encode(verifier),hashBuffer=await crypto.subtle.digest("SHA-256",data),challenge=base64urlEncode(new Uint8Array(hashBuffer));return{verifier,challenge}}var decode=s=>atob(s),CLIENT_ID=decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl"),AUTHORIZE_URL="https://claude.ai/oauth/authorize",TOKEN_URL="https://platform.claude.com/v1/oauth/token",CALLBACK_HOST=getProviderEnvValue("PI_OAUTH_CALLBACK_HOST")||"127.0.0.1",CALLBACK_PORT=53692,CALLBACK_PATH="/callback",REDIRECT_URI=`http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`,COPY_CODE_REDIRECT_URI="https://platform.claude.com/oauth/code/callback",ANTHROPIC_BROWSER_LOGIN_METHOD="browser",ANTHROPIC_COPY_CODE_LOGIN_METHOD="copy_code",SCOPES="org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";function parseAuthorizationInput(input){let value=input.trim();if(!value)return{};try{let url=new URL(value);return{code:url.searchParams.get("code")??void 0,state:url.searchParams.get("state")??void 0}}catch{}if(value.includes("#")){let[code,state]=value.split("#",2);return{code,state}}if(value.includes("code=")){let params=new URLSearchParams(value);return{code:params.get("code")??void 0,state:params.get("state")??void 0}}return{code:value}}function formatErrorDetails(error){if(error instanceof Error){let details=[`${error.name}: ${error.message}`],errorWithCode=error;return errorWithCode.code&&details.push(`code=${errorWithCode.code}`),typeof errorWithCode.errno<"u"&&details.push(`errno=${String(errorWithCode.errno)}`),typeof error.cause<"u"&&details.push(`cause=${formatErrorDetails(error.cause)}`),error.stack&&details.push(`stack=${error.stack}`),details.join("; ")}return String(error)}async function postJson(url,body,signal){let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(body),signal:AbortSignal.any([signal,AbortSignal.timeout(3e4)])}),responseBody=await response.text();if(!response.ok)throw new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);return responseBody}async function exchangeAuthorizationCode(code,state,verifier,redirectUri,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"authorization_code",client_id:CLIENT_ID,code,state,redirect_uri:redirectUri,code_verifier:verifier},signal)}catch(error){throw new Error(`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`)}let tokenData;try{tokenData=JSON.parse(responseBody)}catch(error){throw new Error(`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:tokenData.refresh_token,access:tokenData.access_token,expires:Date.now()+tokenData.expires_in*1e3-300*1e3}}async function loginAnthropic(interaction){let{verifier,challenge}=await generatePKCE(),startCallbackServer=port=>startOAuthCallbackServer({providerName:"Anthropic",host:CALLBACK_HOST,port,path:CALLBACK_PATH,redirectHost:"localhost",state:verifier,complete:async code=>code,signal:interaction.signal}),callback=await startCallbackServer(CALLBACK_PORT).catch(()=>startCallbackServer(0)).catch(()=>{}),redirectUri=callback?.redirectUri??REDIRECT_URI;try{let authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:redirectUri,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."});let result=await waitForCallbackOrManualInput(interaction,callback,{message:"Complete login in your browser, or paste the authorization code / redirect URL here:",placeholder:redirectUri}),code,state=verifier;if(result.type==="callback")code=result.value;else{let parsed=parseAuthorizationInput(result.input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");code=parsed.code,state=parsed.state??verifier}if(!code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(code,state,verifier,redirectUri,interaction.signal)}finally{callback?.close()}}async function loginAnthropicCopyCode(interaction){let{verifier,challenge}=await generatePKCE(),authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:COPY_CODE_REDIRECT_URI,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser, then copy the code Anthropic shows and paste it here."});let input=await interaction.prompt({type:"manual_code",message:"Paste the code Anthropic shows after you sign in:",placeholder:"code#state",signal:interaction.signal}),parsed=parseAuthorizationInput(input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");if(!parsed.code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(parsed.code,parsed.state??verifier,verifier,COPY_CODE_REDIRECT_URI,interaction.signal)}async function refreshAnthropicToken(refreshToken,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"refresh_token",client_id:CLIENT_ID,refresh_token:refreshToken},signal)}catch(error){throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`)}let data;try{data=JSON.parse(responseBody)}catch(error){throw new Error(`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:data.refresh_token,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3}}var anthropicOAuth={name:"Anthropic (Claude Pro/Max)",isSubscription:!0,async login(interaction){let method=await interaction.prompt({type:"select",message:"Select Anthropic login method:",options:[{id:ANTHROPIC_BROWSER_LOGIN_METHOD,label:"Browser login (default)"},{id:ANTHROPIC_COPY_CODE_LOGIN_METHOD,label:"Copy code login (headless)"}]});if(method===ANTHROPIC_COPY_CODE_LOGIN_METHOD)return loginAnthropicCopyCode(interaction);if(method!==ANTHROPIC_BROWSER_LOGIN_METHOD)throw new Error(`Unknown Anthropic login method: ${method}`);return loginAnthropic(interaction)},refresh:(credential,signal)=>refreshAnthropicToken(credential.refresh,signal),async toAuth(credential){return{apiKey:credential.access}}};export{anthropicOAuth};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
|
|
2
|
+
import{convertResponsesMessages,convertResponsesTools,processResponsesStream}from"./chunk-LMNWTX2L.js";import{resolveAzureConfig,resolveDeploymentName}from"./chunk-TMTOQ7H7.js";import{clampOpenAIPromptCacheKey}from"./chunk-PRRNXB7S.js";import{AzureOpenAI}from"./chunk-CF5GWZHW.js";import{formatProviderError,normalizeProviderError}from"./chunk-TEPMHNKQ.js";import"./chunk-PJACZCIR.js";import{retryProviderRequest}from"./chunk-PMRZO46Y.js";import{buildBaseOptions,createGrammarToolInputProperties,getPiUserAgent,resolveSamplingParams}from"./chunk-R4VPBBDS.js";import"./chunk-L2ZPNLYD.js";import{headersToRecord}from"./chunk-UTB4DTYQ.js";import"./chunk-7DDKXS2Q.js";import"./chunk-3V45WARH.js";import{clampThinkingLevel,getDeclaredTools,resolveTranscript,resolveTranscriptTools}from"./chunk-WCGU75WO.js";import{AssistantMessageEventStream}from"./chunk-LPXNMA2W.js";import"./chunk-JXWJOIH4.js";var AZURE_TOOL_CALL_PROVIDERS=new Set(["openai","openai-codex","opencode","azure"]),OPENAI_RESPONSES_MIN_OUTPUT_TOKENS=16;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 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};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);let reasoningEffort=options?.reasoningEffort??(options?.reasoningSummary?"medium":void 0);if(model.reasoning)if(reasoningEffort){let effort=options?.reasoningEffort?model.thinkingLevelMap?.[options.reasoningEffort]??options.reasoningEffort:reasoningEffort;params.reasoning={effort,summary:options?.reasoningSummary||"auto"},params.include=["reasoning.encrypted_content"]}else model.thinkingLevelMap?.off!==null&&(params.reasoning={effort:model.thinkingLevelMap?.off??"none"});let samplingParams=resolveSamplingParams(model,reasoningEffort??"off",options?.samplingParams);return samplingParams&&Object.assign(params,samplingParams),params}export{stream,streamSimple};
|