Repository navigation
Closed
Description
What
Add a direct path to bin/muse-proxy.mjs so a chat completion no longer has to shell out to muse exec --json / a warm muse serve MSP host per request (which pays ~26k tokens of CLI harness scaffolding per call and flattens messages, losing native tool calling).
Requested directly by Drew on 2026-10-30 in the Muse side chat ("make the proxy do that", referring to the Muse CLI token-exchange mechanism).
Verified mechanism (live on amd-6, 2026-10-30)
- The Muse CLI OAuth login token is an account token (
dca:…,~/.config/muse/auth.json→providers.meta.access_token, device_code). It is NOT an inference credential: direct/v1calls with it return 401. - Exchange:
POST https://api.meta.ai/muse-code/keywithAuthorization: Bearer <dca token>,x-api-version: 1.0.0, body{"onboard": false}→ 200. Response containsapi_key(theLLM|…Muse Code plan key),is_subs_active: true,require_payment: false,subs_tier_name,subs_usage, etc. - With the minted key:
GET /v1/models→ 200 (muse-spark-1.3, muse-wonder-1.0, -contributor variants). Chat completions reach the plan quota gate (429 Subscription quota exhausted when the 5h window is full — auth accepted).
Scope
- Credential: read
$MUSE_AUTH_PATH || ~/.config/muse/auth.json; useproviders.meta.access_tokenfor the exchange; if onlyproviders.meta.api_keyis present, use it directly. Never log secret values. - Exchange + in-memory cache (10 min TTL); on upstream 401 invalidate + re-exchange once + retry once.
is_subs_active === false/require_payment === true= hard error, no silent fallback to CLI paths. - Forward
POST /v1/chat/completionsverbatim (messages/tools/tool_choice/response_format preserved; no formatPrompt flattening) to{API_BASE}/v1/chat/completionswith the minted key; base model id via existing resolveModelAndEffort, reasoning_effort passed when explicitly requested; stream = untouched SSE passthrough; non-stream = upstream status+JSON verbatim. ANY upstream HTTP response (402/429/400) passes through as-is — never fall back after Meta has answered, never retry a quota wall. - Fall back to existing warm/exec paths ONLY when direct is unavailable before any upstream response (no credential, exchange transport failure, upstream fetch throws).
- Kill switch
MUSE_PROXY_DIRECT=0; API base overrideMUSE_PROXY_META_API_BASE(default https://api.meta.ai) for tests. /health gains adirectsection (enabled, credential found, minted cached, tier/active — no secrets). /v1/models keeps the existing synthetic catalog. - Tests in
bin/muse-proxy.test.mjsagainst a local stub Meta API: exchange shape + minted-key auth, exchange caching, streaming tool_calls passthrough, 429 passthrough with NO exec fallback, and MUSE_PROXY_DIRECT=0 / no-auth.json leaving exec behavior unchanged. All pre-existing tests still pass (node --test bin/muse-proxy.test.mjson the laptop).
Related
- Warm-path work: Warm-session proxies: hold CLI/language-server sessions open instead of spawning per request #480. Proxy reconciliation: muse-proxy (PR #479): streaming responses silently drop the terminal text tail that non-streaming returns #484.
Capability only: this does NOT re-enable the OpenCode muse provider (disabled by Drew 2026-10-25) or any proxy service.
Metadata
Metadata
Assignees
Labels
No labels
Activity
dezren39 commentedon Oct 30, 2026
Final mechanism update (2026-10-30, supersedes the "forward chat completions verbatim" scope above)
Live re-verification on the laptop today settled the upstream shape — attestation is per-route, not per-client:
POST /v1/chat/completionsreturns 403client_attestation_deniedno matter what headers are sent (including the real CLI's full header set).POST /v1/responsesreturns 200 with bareAuthorizationonly — nox-tbh-*headers, no special User-Agent, plain or-contributormodel ids both work. One one-word Responses prompt cost 13 input tokens (vs ~26k through the CLI harness).So direct mode is implemented as a translation layer, not a verbatim chat forward:
POST /v1/chat/completions→ translate to upstreamPOST /v1/responses(system →instructions; messages/tools/tool_choice mapped to Responses shapes;max_tokens→max_output_tokens; reasoning effort mapped,max/ultra→xhighsince Responses tops out there), and translate the Responses result (non-stream and SSE) back to chat-completion shape.POST /v1/responses→ verbatim passthrough with only the Authorization header swapped to the minted key.POST /muse-code/key({"onboard": false},x-api-version: 1.0.0), 10-min in-memory key cache, 401 → re-exchange + retry once,is_subs_active === false/require_payment === true→ hard 502 with no CLI fallback, ANY upstream HTTP response passes through as-is (never fall back after Meta has answered), fallback to warm/exec only when direct never got an upstream response,MUSE_PROXY_DIRECT=0kill switch,/healthgains adirectsection with no secret material.Implementation in progress on branch
muse-proxy-direct-mode.feat(muse-proxy): add direct Responses mode via minted plan key (#2753)
Merge pull request #2759 from developing-today/muse-proxy-direct-mode
Merge pull request #2761 from developing-today/muse-direct-provider
Merge pull request #2762 from developing-today/muse-direct-contributor
Merge pull request #2763 from developing-today/muse-direct-replace
dezren39 commentedon Oct 30, 2026
Phase 2 complete — muse-direct is wired up and is now the only Meta door (2026-10-30)
Pool identity (for gate/registry purposes):
muse-directdraws the meta pool — the Muse Code High Usage plan — the same pool the retiredmetaandmusedoors drew. It is not a separate pool. The fleet's quota gate should treatmuse-directsessions as Meta-pool burn. The named meta quota read is unaffected by the disable (it bypasses thedisabled_providersfilter and reads the Muse CLI auth store): verified live after the change —GET /api/quota/metareturns the live plan state (5h window 3% used, weekly 59% used, plan "Muse Code High Usage").What landed
museadded todisabled_providersalongsidemeta, definitions kept full; muse-direct models switched to the contributor variants; every Meta-pool route reference retargeted: spark-plan reserve leaf, workhorse-primary target + weight, summit#maxleaf — all nowmuse-direct/…-contributor).The attestation gate is also per-tool-name (new finding)
The first throwaway-serve verification failed 403
client_attestation_denieddespite the Responses route: bisecting a real request showed the gate also rejects function tools namedbash/shell(probe-verified blocked set:bash,shell,apply_patch,search,read_file,write_file,edit_file; instructions, headers, and all other tool names pass). The proxy now aliasesshell→run_command,bash→terminalon both direct paths and translates the model's calls back (#2764 chat path, #2766 passthrough); a still-denied chat request falls back to the CLI door. Verified after the fix: a throwaway-serve session onmuse-direct/muse-spark-1.3-contributor(variant low) answeredokwith finishstop— 17,503 input tokens, which is OpenCode's own build-agent prompt (system + tool definitions); a bare request through the same door costs 10–13 input tokens, vs ~26k via the CLI harness.Deployment state (laptop)
muse-proxy.service(user unit) runs the merged code on 127.0.0.1:18747;/healthdirect: enabled, credentialFound, mintedKeyCached, tier "Muse Code High Usage", subsActive.muse-directgoes live there at its next natural respawn, and sessions pinned tometa/*/muse/*pick up the retargeted routes at the same moment.Merge pull request #2774 from developing-today/muse-proxy-nix-docs