@zhihaohong52/sonata 0.4.0
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/LICENSE +21 -0
- package/README.md +437 -0
- package/dist/adapters/claude.js +83 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.js +382 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/index.js +21 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.js +104 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/pi.js +152 -0
- package/dist/adapters/pi.js.map +1 -0
- package/dist/adapters/reasonix.js +358 -0
- package/dist/adapters/reasonix.js.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/agent-markers.js +3 -0
- package/dist/agent-markers.js.map +1 -0
- package/dist/aipricing.js +109 -0
- package/dist/aipricing.js.map +1 -0
- package/dist/catalog.js +274 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli.js +766 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/approve.js +23 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/auth.js +41 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/catalog.js +172 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/code.js +113 -0
- package/dist/commands/code.js.map +1 -0
- package/dist/commands/dispatch.js +148 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/doctor.js +545 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/gc.js +25 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/init-log.js +83 -0
- package/dist/commands/init-log.js.map +1 -0
- package/dist/commands/init.js +157 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/log.js +24 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/route.js +660 -0
- package/dist/commands/route.js.map +1 -0
- package/dist/commands/run.js +199 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/runs.js +37 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/serve.js +818 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/status.js +14 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.js +258 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/tail.js +229 -0
- package/dist/commands/tail.js.map +1 -0
- package/dist/commands/usage.js +85 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/verify.js +69 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/wait.js +38 -0
- package/dist/commands/wait.js.map +1 -0
- package/dist/config.js +588 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.js +445 -0
- package/dist/detect.js.map +1 -0
- package/dist/filelock.js +83 -0
- package/dist/filelock.js.map +1 -0
- package/dist/init/apply.js +96 -0
- package/dist/init/apply.js.map +1 -0
- package/dist/init/candidates.js +115 -0
- package/dist/init/candidates.js.map +1 -0
- package/dist/init/discover.js +216 -0
- package/dist/init/discover.js.map +1 -0
- package/dist/init/helpers.js +429 -0
- package/dist/init/helpers.js.map +1 -0
- package/dist/init/interactive-state.js +128 -0
- package/dist/init/interactive-state.js.map +1 -0
- package/dist/init/plan.js +225 -0
- package/dist/init/plan.js.map +1 -0
- package/dist/init/scripted-state.js +130 -0
- package/dist/init/scripted-state.js.map +1 -0
- package/dist/init/toml.js +83 -0
- package/dist/init/toml.js.map +1 -0
- package/dist/init/validate.js +149 -0
- package/dist/init/validate.js.map +1 -0
- package/dist/ledger.js +123 -0
- package/dist/ledger.js.map +1 -0
- package/dist/mcp/protocol.js +64 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/server.js +96 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.js +210 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mode.js +64 -0
- package/dist/mode.js.map +1 -0
- package/dist/native/claude-shim.js +228 -0
- package/dist/native/claude-shim.js.map +1 -0
- package/dist/native/codex-auth.js +177 -0
- package/dist/native/codex-auth.js.map +1 -0
- package/dist/native/copilot-auth.js +105 -0
- package/dist/native/copilot-auth.js.map +1 -0
- package/dist/native/credentials.js +83 -0
- package/dist/native/credentials.js.map +1 -0
- package/dist/native/hosts.js +60 -0
- package/dist/native/hosts.js.map +1 -0
- package/dist/native/litellm.js +103 -0
- package/dist/native/litellm.js.map +1 -0
- package/dist/native/models.js +96 -0
- package/dist/native/models.js.map +1 -0
- package/dist/native/oauth-login.js +112 -0
- package/dist/native/oauth-login.js.map +1 -0
- package/dist/native/router.js +469 -0
- package/dist/native/router.js.map +1 -0
- package/dist/native/tls.js +73 -0
- package/dist/native/tls.js.map +1 -0
- package/dist/native/usage.js +119 -0
- package/dist/native/usage.js.map +1 -0
- package/dist/normalize.js +98 -0
- package/dist/normalize.js.map +1 -0
- package/dist/pricing.js +86 -0
- package/dist/pricing.js.map +1 -0
- package/dist/roles.js +49 -0
- package/dist/roles.js.map +1 -0
- package/dist/sessions.js +62 -0
- package/dist/sessions.js.map +1 -0
- package/dist/settings.js +131 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.js +70 -0
- package/dist/store.js.map +1 -0
- package/dist/tmux.js +89 -0
- package/dist/tmux.js.map +1 -0
- package/dist/tui-ink/app-state.js +340 -0
- package/dist/tui-ink/app-state.js.map +1 -0
- package/dist/tui-ink/app.js +156 -0
- package/dist/tui-ink/app.js.map +1 -0
- package/dist/tui-ink/components/byok-step.js +102 -0
- package/dist/tui-ink/components/byok-step.js.map +1 -0
- package/dist/tui-ink/components/login-screen.js +80 -0
- package/dist/tui-ink/components/login-screen.js.map +1 -0
- package/dist/tui-ink/components/models-step.js +92 -0
- package/dist/tui-ink/components/models-step.js.map +1 -0
- package/dist/tui-ink/components/multi-select-state.js +56 -0
- package/dist/tui-ink/components/multi-select-state.js.map +1 -0
- package/dist/tui-ink/components/multi-select.js +69 -0
- package/dist/tui-ink/components/multi-select.js.map +1 -0
- package/dist/tui-ink/components/providers-step.js +285 -0
- package/dist/tui-ink/components/providers-step.js.map +1 -0
- package/dist/tui-ink/components/ranked-select-state.js +41 -0
- package/dist/tui-ink/components/ranked-select-state.js.map +1 -0
- package/dist/tui-ink/components/ranked-select.js +61 -0
- package/dist/tui-ink/components/ranked-select.js.map +1 -0
- package/dist/tui-ink/components/search-select.js +47 -0
- package/dist/tui-ink/components/search-select.js.map +1 -0
- package/dist/tui-ink/components/text-input-state.js +42 -0
- package/dist/tui-ink/components/text-input-state.js.map +1 -0
- package/dist/tui-ink/components/text-input.js +48 -0
- package/dist/tui-ink/components/text-input.js.map +1 -0
- package/dist/tui-ink/run.js +38 -0
- package/dist/tui-ink/run.js.map +1 -0
- package/dist/tui-ink/test-compile.js +4 -0
- package/dist/tui-ink/test-compile.js.map +1 -0
- package/dist/tui-ink/types.js +2 -0
- package/dist/tui-ink/types.js.map +1 -0
- package/dist/tui.js +330 -0
- package/dist/tui.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/watchdog.js +85 -0
- package/dist/watchdog.js.map +1 -0
- package/hooks/capture-mode.mjs +56 -0
- package/hooks/ensure-serve.mjs +140 -0
- package/hooks/hooks.json +12 -0
- package/hooks/route-session.mjs +47 -0
- package/hooks/route-subagent.mjs +54 -0
- package/package.json +64 -0
- package/roles/code.md +13 -0
- package/roles/explore.md +9 -0
- package/roles/plan.md +10 -0
- package/roles/review.md +11 -0
- package/skills/loop/SKILL.md +43 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { resolve4 } from 'node:dns/promises';
|
|
4
|
+
const HOSTS_PATH = '/etc/hosts';
|
|
5
|
+
const MARKER = '# sonata transparent proxy';
|
|
6
|
+
const ENTRY = `127.0.0.1 api.anthropic.com ${MARKER}`;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves api.anthropic.com's real IP BEFORE /etc/hosts is modified.
|
|
9
|
+
* Cached for the session so the router can forward to it directly.
|
|
10
|
+
*/
|
|
11
|
+
export async function resolveAnthropicIp() {
|
|
12
|
+
const ips = await resolve4('api.anthropic.com');
|
|
13
|
+
if (ips.length === 0)
|
|
14
|
+
throw new Error('sonata: could not resolve api.anthropic.com');
|
|
15
|
+
return ips[0];
|
|
16
|
+
}
|
|
17
|
+
export function hostsHasEntry() {
|
|
18
|
+
try {
|
|
19
|
+
return readFileSync(HOSTS_PATH, 'utf8').includes(MARKER);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Adds the localhost redirect to /etc/hosts. Requires sudo.
|
|
27
|
+
*
|
|
28
|
+
* The marker comment makes the entry identifiable so removeHostsEntry
|
|
29
|
+
* removes exactly what addHostsEntry wrote, nothing else.
|
|
30
|
+
*/
|
|
31
|
+
export function addHostsEntry() {
|
|
32
|
+
if (hostsHasEntry())
|
|
33
|
+
return;
|
|
34
|
+
execSync(`echo '${ENTRY}' | sudo -n tee -a ${HOSTS_PATH} > /dev/null 2>&1 || ` +
|
|
35
|
+
`echo '${ENTRY}' | sudo tee -a ${HOSTS_PATH} > /dev/null`, { stdio: 'inherit' });
|
|
36
|
+
}
|
|
37
|
+
export function removeHostsEntry() {
|
|
38
|
+
if (!hostsHasEntry())
|
|
39
|
+
return;
|
|
40
|
+
// sed -i on macOS requires '' as the backup extension
|
|
41
|
+
try {
|
|
42
|
+
execSync(`sudo -n sed -i '' '/${MARKER.replace(/[/\\]/g, '\\$&')}/d' ${HOSTS_PATH} 2>/dev/null || ` +
|
|
43
|
+
`sudo sed -i '' '/${MARKER.replace(/[/\\]/g, '\\$&')}/d' ${HOSTS_PATH}`, { stdio: 'inherit' });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Best-effort: if sudo fails, doctor will report the stale entry.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Flush DNS cache so the hosts change takes effect immediately. */
|
|
50
|
+
export function flushDns() {
|
|
51
|
+
try {
|
|
52
|
+
execSync('sudo -n dscacheutil -flushcache 2>/dev/null; sudo -n killall -HUP mDNSResponder 2>/dev/null', {
|
|
53
|
+
stdio: 'pipe',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Non-fatal: most operations will pick up the change without flushing.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=hosts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosts.js","sourceRoot":"","sources":["../../src/native/hosts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,UAAU,GAAG,YAAY,CAAC;AAChC,MAAM,MAAM,GAAG,4BAA4B,CAAC;AAC5C,MAAM,KAAK,GAAG,+BAA+B,MAAM,EAAE,CAAC;AAEtD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IAChD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACrF,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,aAAa,EAAE;QAAE,OAAO;IAC5B,QAAQ,CACN,SAAS,KAAK,sBAAsB,UAAU,uBAAuB;QACrE,SAAS,KAAK,mBAAmB,UAAU,cAAc,EACzD,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IAC7B,sDAAsD;IACtD,IAAI,CAAC;QACH,QAAQ,CACN,uBAAuB,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,UAAU,kBAAkB;YAC1F,oBAAoB,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,UAAU,EAAE,EACvE,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;IACpE,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC;QACH,QAAQ,CAAC,6FAA6F,EAAE;YACtG,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
export function envVarForGateway(gateway) {
|
|
3
|
+
return `SONATA_KEY_${gateway.toUpperCase().replace(/-/g, '_')}`;
|
|
4
|
+
}
|
|
5
|
+
function litellmModelEntry(modelName, gateway, id, gateways) {
|
|
6
|
+
// An OAuth gateway is served by one of LiteLLM's own providers, which
|
|
7
|
+
// supplies the base URL, the bearer and any refresh or token exchange.
|
|
8
|
+
// Passing api_base or api_key here would override that and break it.
|
|
9
|
+
const auth = gateways[gateway].auth;
|
|
10
|
+
if (auth === 'codex-oauth') {
|
|
11
|
+
return {
|
|
12
|
+
model_name: modelName,
|
|
13
|
+
litellm_params: { model: `chatgpt/${id}` },
|
|
14
|
+
model_info: {
|
|
15
|
+
// Without this LiteLLM uses chat-completions and POSTs to the bare
|
|
16
|
+
// backend-api/codex/ URL, which serves the ChatGPT web app.
|
|
17
|
+
mode: 'responses',
|
|
18
|
+
// The Codex backend answers any `role: system` message with
|
|
19
|
+
// `{"detail":"System messages are not allowed"}` — a 400 naming
|
|
20
|
+
// neither the field nor the shape. LiteLLM's chatgpt provider does not
|
|
21
|
+
// normalize that itself: BerriAI/litellm#22968 reports it and its fix,
|
|
22
|
+
// PR #22967, was closed without merging, so 1.98.0 still emits the
|
|
23
|
+
// rejected role. Declaring the model as not supporting system messages
|
|
24
|
+
// routes the prompt through `map_system_message_pt`, which folds it in
|
|
25
|
+
// at LiteLLM's own layer rather than sonata rewriting the body.
|
|
26
|
+
//
|
|
27
|
+
// `flattenSystemBlocks` (src/native/router.ts) remains load-bearing:
|
|
28
|
+
// that helper concatenates onto message content and raises
|
|
29
|
+
// `can only concatenate list (not "str") to list` on Claude Code's
|
|
30
|
+
// block arrays (BerriAI/litellm#32904). Flattening to a string first
|
|
31
|
+
// is what keeps this off that crash path — the two fixes are a pair,
|
|
32
|
+
// and neither is sufficient alone.
|
|
33
|
+
supports_system_message: false,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (auth === 'copilot-oauth') {
|
|
38
|
+
// Copilot speaks chat-completions, so it needs no mode override; the
|
|
39
|
+
// provider exchanges the GitHub token for a Copilot key itself.
|
|
40
|
+
return {
|
|
41
|
+
model_name: modelName,
|
|
42
|
+
litellm_params: { model: `github_copilot/${id}` },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (gateways[gateway].wireFormat === 'anthropic') {
|
|
46
|
+
return {
|
|
47
|
+
model_name: modelName,
|
|
48
|
+
litellm_params: {
|
|
49
|
+
model: `anthropic/${id}`,
|
|
50
|
+
api_base: gateways[gateway].baseUrl,
|
|
51
|
+
api_key: `os.environ/${envVarForGateway(gateway)}`,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
model_name: modelName,
|
|
57
|
+
litellm_params: {
|
|
58
|
+
model: `openai/${id}`,
|
|
59
|
+
api_base: gateways[gateway].baseUrl,
|
|
60
|
+
api_key: `os.environ/${envVarForGateway(gateway)}`,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function litellmConfig(native, masterKey, unifiedModels = {}) {
|
|
65
|
+
const modelList = Object.entries(native.models).map(([modelName, model]) => litellmModelEntry(modelName, model.gateway, model.id, native.gateways));
|
|
66
|
+
// Legacy native.models entries stay authoritative during migration: a
|
|
67
|
+
// unified [models] entry sharing a key with one is skipped rather than
|
|
68
|
+
// emitting a duplicate model_name LiteLLM would then pick between.
|
|
69
|
+
for (const [modelName, model] of Object.entries(unifiedModels)) {
|
|
70
|
+
if (modelName in native.models)
|
|
71
|
+
continue;
|
|
72
|
+
if (model.gateway === undefined || model.id === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
modelList.push(litellmModelEntry(modelName, model.gateway, model.id, native.gateways));
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
model_list: modelList,
|
|
78
|
+
// LiteLLM 1.82+ silently routes any `openai/<id>` model hit through its
|
|
79
|
+
// Anthropic /v1/messages passthrough to the OpenAI Responses API rather
|
|
80
|
+
// than chat/completions (see _should_route_to_responses_api in
|
|
81
|
+
// llms/anthropic/experimental_pass_through/messages/handler.py). Every
|
|
82
|
+
// api-key gateway sonata generates uses `openai/<id>`, and not every
|
|
83
|
+
// OpenAI-compatible backend implements the Responses API — acme's own
|
|
84
|
+
// proxy rejects the `output_text` content-block type Responses mode uses
|
|
85
|
+
// to replay a prior assistant turn, breaking any multi-turn conversation.
|
|
86
|
+
// This flag is LiteLLM's own documented opt-out.
|
|
87
|
+
litellm_settings: { drop_params: true, use_chat_completions_url_for_anthropic_messages: true },
|
|
88
|
+
general_settings: { master_key: masterKey },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** LiteLLM accepts JSON config files, so keep serialization dependency-free and stable. */
|
|
92
|
+
export function litellmConfigYaml(native, masterKey, unifiedModels = {}) {
|
|
93
|
+
return `${JSON.stringify(litellmConfig(native, masterKey, unifiedModels), null, 2)}\n`;
|
|
94
|
+
}
|
|
95
|
+
export function findLitellm() {
|
|
96
|
+
try {
|
|
97
|
+
return execFileSync('which', ['litellm'], { encoding: 'utf8' }).trim() || null;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=litellm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"litellm.js","sourceRoot":"","sources":["../../src/native/litellm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model discovery for BYOK — bringing a provider and a key, with no harness.
|
|
3
|
+
*
|
|
4
|
+
* Every harness path learns its models from a catalogue sonata can read locally
|
|
5
|
+
* (`opencode models`, `pi --list-models`, `reasonix doctor --json`). A provider
|
|
6
|
+
* the user names directly has no such catalogue, so the only place to ask is the
|
|
7
|
+
* provider itself: `GET <base>/models`, the OpenAI-compatible convention that
|
|
8
|
+
* every gateway in `WELL_KNOWN_PROVIDER_URLS` follows.
|
|
9
|
+
*
|
|
10
|
+
* It is a convention, not a guarantee. A provider may not implement it, may
|
|
11
|
+
* shape the payload differently, or may simply be unreachable — so `fetchModels`
|
|
12
|
+
* **never throws and never distinguishes those cases**: they all return `[]`, and
|
|
13
|
+
* the caller falls back to letting the user type ids. Reporting them separately
|
|
14
|
+
* would imply a difference the caller cannot act on.
|
|
15
|
+
*/
|
|
16
|
+
import { WELL_KNOWN_PROVIDER_URLS } from '../detect.js';
|
|
17
|
+
/** Where a provider's model list lives, given its base url. */
|
|
18
|
+
function modelsUrl(baseUrl) {
|
|
19
|
+
return `${baseUrl.replace(/\/+$/, '')}/models`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The models a provider reports, or why it would not say.
|
|
23
|
+
*
|
|
24
|
+
* Timeout-bounded and non-throwing, matching `copilotTokenCanExchange`: an
|
|
25
|
+
* offline machine gets an answer rather than a hang.
|
|
26
|
+
*/
|
|
27
|
+
export async function fetchModels(baseUrl, apiKey, opts = {}) {
|
|
28
|
+
const doFetch = opts.fetch ?? fetch;
|
|
29
|
+
try {
|
|
30
|
+
const response = await doFetch(modelsUrl(baseUrl), {
|
|
31
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
32
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 10_000),
|
|
33
|
+
});
|
|
34
|
+
if (response.status === 401 || response.status === 403) {
|
|
35
|
+
return { outcome: 'unauthorized', status: response.status };
|
|
36
|
+
}
|
|
37
|
+
if (!response.ok)
|
|
38
|
+
return { outcome: 'unreadable' };
|
|
39
|
+
const payload = await response.json();
|
|
40
|
+
const data = payload?.data;
|
|
41
|
+
if (!Array.isArray(data))
|
|
42
|
+
return { outcome: 'unreadable' };
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const models = [];
|
|
45
|
+
for (const entry of data) {
|
|
46
|
+
if (entry === null || typeof entry !== 'object')
|
|
47
|
+
continue;
|
|
48
|
+
const { id, name } = entry;
|
|
49
|
+
if (typeof id !== 'string' || id.trim() === '' || seen.has(id))
|
|
50
|
+
continue;
|
|
51
|
+
seen.add(id);
|
|
52
|
+
models.push(typeof name === 'string' && name.trim() !== '' ? { id, name } : { id });
|
|
53
|
+
}
|
|
54
|
+
return { outcome: 'ok', models };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Refused, timed out, DNS failure, or a body that would not parse.
|
|
58
|
+
return { outcome: 'unreachable' };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Providers a user can name without having any harness installed.
|
|
63
|
+
*
|
|
64
|
+
* Deduplicated **by url, keeping the first name**: the underlying map lists
|
|
65
|
+
* `openai` before its `openai-codex` and `codex` aliases, so keep-first is what
|
|
66
|
+
* makes the picker say `openai`.
|
|
67
|
+
*
|
|
68
|
+
* `anthropic` is excluded. Every model it serves is `claude-*`, a prefix the
|
|
69
|
+
* router reserves for Anthropic and `parseConfig` refuses, so its catalogue
|
|
70
|
+
* filters to nothing — offering a provider that can yield no usable model is
|
|
71
|
+
* worse than not offering it.
|
|
72
|
+
*/
|
|
73
|
+
export function wellKnownProviders() {
|
|
74
|
+
const byUrl = new Map();
|
|
75
|
+
for (const [name, url] of Object.entries(WELL_KNOWN_PROVIDER_URLS)) {
|
|
76
|
+
if (name === 'anthropic')
|
|
77
|
+
continue;
|
|
78
|
+
if (!byUrl.has(url))
|
|
79
|
+
byUrl.set(url, name);
|
|
80
|
+
}
|
|
81
|
+
return [...byUrl.entries()]
|
|
82
|
+
.map(([url, name]) => ({ name, url }))
|
|
83
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The config key for a BYOK model.
|
|
87
|
+
*
|
|
88
|
+
* Shared by the wizard and `cmdInit` on purpose: the wizard puts this key into
|
|
89
|
+
* `nativeKeys` and `cmdInit` looks the candidate up by it, so computing the
|
|
90
|
+
* formula twice is how the two silently stop agreeing. Slashes are flattened to
|
|
91
|
+
* dashes exactly as harness-discovered keys are.
|
|
92
|
+
*/
|
|
93
|
+
export function byokCandidateKey(gateway, id) {
|
|
94
|
+
return `${gateway}-${id}`.replace(/\//g, '-');
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/native/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { createInterface } from 'node:readline';
|
|
4
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
/**
|
|
7
|
+
* Where a sonata-minted credential lives. Persistent, unlike serve's temp
|
|
8
|
+
* directory: LiteLLM refreshes tokens into these files, and Copilot's
|
|
9
|
+
* api-key.json is short-lived and re-exchanged in place. A temp directory
|
|
10
|
+
* throws every refresh away.
|
|
11
|
+
*/
|
|
12
|
+
export function credentialDir(home, gateway) {
|
|
13
|
+
return join(home, '.config/sonata/credentials', gateway);
|
|
14
|
+
}
|
|
15
|
+
export function tokenDirEnvVar(auth) {
|
|
16
|
+
return auth === 'copilot-oauth' ? 'GITHUB_COPILOT_TOKEN_DIR' : 'CHATGPT_TOKEN_DIR';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The file whose existence proves the login worked.
|
|
20
|
+
*
|
|
21
|
+
* For Copilot that is `api-key.json`, not `access-token`: only `get_api_key()`
|
|
22
|
+
* writes it, and only that call proves the GitHub token can actually exchange
|
|
23
|
+
* for a Copilot key. Probed 2026-08-22 - a `ghu_` token authenticates fine and
|
|
24
|
+
* still tells you nothing about entitlement.
|
|
25
|
+
*/
|
|
26
|
+
export function credentialFileFor(auth) {
|
|
27
|
+
return auth === 'copilot-oauth' ? 'api-key.json' : 'auth.json';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Never `_login()`: it returns a token and persists nothing, so the next call
|
|
31
|
+
* starts a second device flow against an empty directory. Copilot needs the
|
|
32
|
+
* `get_api_key()` follow-up because the device login and the Copilot exchange
|
|
33
|
+
* are separate calls.
|
|
34
|
+
*/
|
|
35
|
+
function scriptFor(auth) {
|
|
36
|
+
return auth === 'copilot-oauth'
|
|
37
|
+
? 'from litellm.llms.github_copilot.authenticator import Authenticator\n' +
|
|
38
|
+
'a = Authenticator()\na.get_access_token()\na.get_api_key()\n'
|
|
39
|
+
: 'from litellm.llms.chatgpt.authenticator import Authenticator\n' +
|
|
40
|
+
'Authenticator().get_access_token()\n';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The interpreter that owns `litellm` is the one named in its shebang - a bare
|
|
44
|
+
* `python3` may be a different install with no litellm on its path.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveInterpreter() {
|
|
47
|
+
const path = execFileSync('sh', ['-c', 'command -v litellm'], { encoding: 'utf8' }).trim();
|
|
48
|
+
if (path === '')
|
|
49
|
+
throw new Error('litellm is not installed');
|
|
50
|
+
const first = readFileSync(path, 'utf8').split('\n', 1)[0] ?? '';
|
|
51
|
+
if (!first.startsWith('#!'))
|
|
52
|
+
throw new Error(`litellm at ${path} has no interpreter line`);
|
|
53
|
+
return first.slice(2).trim();
|
|
54
|
+
}
|
|
55
|
+
export async function loginGateway(opts) {
|
|
56
|
+
let interpreter;
|
|
57
|
+
try {
|
|
58
|
+
interpreter = opts.interpreter ?? resolveInterpreter();
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
return { ok: false, problem: `${err.message}. Install it: pip install 'litellm[proxy]'` };
|
|
62
|
+
}
|
|
63
|
+
const dir = credentialDir(opts.home, opts.gateway);
|
|
64
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
65
|
+
// PATH plus the one token-directory variable. No other parent value is
|
|
66
|
+
// forwarded, matching how serve builds childEnv. FAKE_MODE only crosses over
|
|
67
|
+
// when a test-injected interpreter is in play, so production can never leak
|
|
68
|
+
// it through an ambient env var.
|
|
69
|
+
const env = process.env.PATH ? { PATH: process.env.PATH } : {};
|
|
70
|
+
env[tokenDirEnvVar(opts.auth)] = dir;
|
|
71
|
+
if (opts.interpreter && process.env.FAKE_MODE)
|
|
72
|
+
env.FAKE_MODE = process.env.FAKE_MODE;
|
|
73
|
+
if (opts.signal?.aborted)
|
|
74
|
+
return { ok: false, problem: 'login cancelled' };
|
|
75
|
+
return await new Promise((resolve) => {
|
|
76
|
+
let child;
|
|
77
|
+
try {
|
|
78
|
+
child = spawn(interpreter, ['-c', scriptFor(opts.auth)], { env, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return resolve({ ok: false, problem: `could not run litellm's interpreter ${interpreter}` });
|
|
82
|
+
}
|
|
83
|
+
let cancelled = false;
|
|
84
|
+
const onAbort = () => { cancelled = true; child.kill('SIGTERM'); };
|
|
85
|
+
opts.signal?.addEventListener('abort', onAbort, { once: true });
|
|
86
|
+
child.on('error', () => {
|
|
87
|
+
resolve({ ok: false, problem: `could not run litellm's interpreter ${interpreter}` });
|
|
88
|
+
});
|
|
89
|
+
// Line by line, so the device code reaches the user the instant it is
|
|
90
|
+
// printed - Copilot only polls for 60 seconds.
|
|
91
|
+
for (const stream of [child.stdout, child.stderr]) {
|
|
92
|
+
createInterface({ input: stream }).on('line', (text) => opts.progress.line(text));
|
|
93
|
+
}
|
|
94
|
+
child.on('close', (code) => {
|
|
95
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
96
|
+
if (cancelled)
|
|
97
|
+
return resolve({ ok: false, problem: 'login cancelled' });
|
|
98
|
+
if (code !== 0)
|
|
99
|
+
return resolve({ ok: false, problem: `litellm's authenticator exited ${code}` });
|
|
100
|
+
// An exit code alone is not evidence.
|
|
101
|
+
const credentialPath = join(dir, credentialFileFor(opts.auth));
|
|
102
|
+
if (!existsSync(credentialPath)) {
|
|
103
|
+
return resolve({ ok: false, problem: 'the login reported success but wrote no credential' });
|
|
104
|
+
}
|
|
105
|
+
// LiteLLM writes with the process umask, commonly 0644 - fix it up rather
|
|
106
|
+
// than trust an interpreter we don't control to have written 0600.
|
|
107
|
+
chmodSync(credentialPath, 0o600);
|
|
108
|
+
resolve({ ok: true });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=oauth-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-login.js","sourceRoot":"","sources":["../../src/native/oauth-login.ts"],"names":[],"mappings":"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"}
|