@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.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +437 -0
  3. package/dist/adapters/claude.js +83 -0
  4. package/dist/adapters/claude.js.map +1 -0
  5. package/dist/adapters/codex.js +382 -0
  6. package/dist/adapters/codex.js.map +1 -0
  7. package/dist/adapters/index.js +21 -0
  8. package/dist/adapters/index.js.map +1 -0
  9. package/dist/adapters/opencode.js +104 -0
  10. package/dist/adapters/opencode.js.map +1 -0
  11. package/dist/adapters/pi.js +152 -0
  12. package/dist/adapters/pi.js.map +1 -0
  13. package/dist/adapters/reasonix.js +358 -0
  14. package/dist/adapters/reasonix.js.map +1 -0
  15. package/dist/adapters/types.js +2 -0
  16. package/dist/adapters/types.js.map +1 -0
  17. package/dist/agent-markers.js +3 -0
  18. package/dist/agent-markers.js.map +1 -0
  19. package/dist/aipricing.js +109 -0
  20. package/dist/aipricing.js.map +1 -0
  21. package/dist/catalog.js +274 -0
  22. package/dist/catalog.js.map +1 -0
  23. package/dist/cli.js +766 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/commands/approve.js +23 -0
  26. package/dist/commands/approve.js.map +1 -0
  27. package/dist/commands/auth.js +41 -0
  28. package/dist/commands/auth.js.map +1 -0
  29. package/dist/commands/catalog.js +172 -0
  30. package/dist/commands/catalog.js.map +1 -0
  31. package/dist/commands/code.js +113 -0
  32. package/dist/commands/code.js.map +1 -0
  33. package/dist/commands/dispatch.js +148 -0
  34. package/dist/commands/dispatch.js.map +1 -0
  35. package/dist/commands/doctor.js +545 -0
  36. package/dist/commands/doctor.js.map +1 -0
  37. package/dist/commands/gc.js +25 -0
  38. package/dist/commands/gc.js.map +1 -0
  39. package/dist/commands/init-log.js +83 -0
  40. package/dist/commands/init-log.js.map +1 -0
  41. package/dist/commands/init.js +157 -0
  42. package/dist/commands/init.js.map +1 -0
  43. package/dist/commands/log.js +24 -0
  44. package/dist/commands/log.js.map +1 -0
  45. package/dist/commands/route.js +660 -0
  46. package/dist/commands/route.js.map +1 -0
  47. package/dist/commands/run.js +199 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/runs.js +37 -0
  50. package/dist/commands/runs.js.map +1 -0
  51. package/dist/commands/serve.js +818 -0
  52. package/dist/commands/serve.js.map +1 -0
  53. package/dist/commands/status.js +14 -0
  54. package/dist/commands/status.js.map +1 -0
  55. package/dist/commands/sync.js +258 -0
  56. package/dist/commands/sync.js.map +1 -0
  57. package/dist/commands/tail.js +229 -0
  58. package/dist/commands/tail.js.map +1 -0
  59. package/dist/commands/usage.js +85 -0
  60. package/dist/commands/usage.js.map +1 -0
  61. package/dist/commands/verify.js +69 -0
  62. package/dist/commands/verify.js.map +1 -0
  63. package/dist/commands/wait.js +38 -0
  64. package/dist/commands/wait.js.map +1 -0
  65. package/dist/config.js +588 -0
  66. package/dist/config.js.map +1 -0
  67. package/dist/detect.js +445 -0
  68. package/dist/detect.js.map +1 -0
  69. package/dist/filelock.js +83 -0
  70. package/dist/filelock.js.map +1 -0
  71. package/dist/init/apply.js +96 -0
  72. package/dist/init/apply.js.map +1 -0
  73. package/dist/init/candidates.js +115 -0
  74. package/dist/init/candidates.js.map +1 -0
  75. package/dist/init/discover.js +216 -0
  76. package/dist/init/discover.js.map +1 -0
  77. package/dist/init/helpers.js +429 -0
  78. package/dist/init/helpers.js.map +1 -0
  79. package/dist/init/interactive-state.js +128 -0
  80. package/dist/init/interactive-state.js.map +1 -0
  81. package/dist/init/plan.js +225 -0
  82. package/dist/init/plan.js.map +1 -0
  83. package/dist/init/scripted-state.js +130 -0
  84. package/dist/init/scripted-state.js.map +1 -0
  85. package/dist/init/toml.js +83 -0
  86. package/dist/init/toml.js.map +1 -0
  87. package/dist/init/validate.js +149 -0
  88. package/dist/init/validate.js.map +1 -0
  89. package/dist/ledger.js +123 -0
  90. package/dist/ledger.js.map +1 -0
  91. package/dist/mcp/protocol.js +64 -0
  92. package/dist/mcp/protocol.js.map +1 -0
  93. package/dist/mcp/server.js +96 -0
  94. package/dist/mcp/server.js.map +1 -0
  95. package/dist/mcp/tools.js +210 -0
  96. package/dist/mcp/tools.js.map +1 -0
  97. package/dist/mode.js +64 -0
  98. package/dist/mode.js.map +1 -0
  99. package/dist/native/claude-shim.js +228 -0
  100. package/dist/native/claude-shim.js.map +1 -0
  101. package/dist/native/codex-auth.js +177 -0
  102. package/dist/native/codex-auth.js.map +1 -0
  103. package/dist/native/copilot-auth.js +105 -0
  104. package/dist/native/copilot-auth.js.map +1 -0
  105. package/dist/native/credentials.js +83 -0
  106. package/dist/native/credentials.js.map +1 -0
  107. package/dist/native/hosts.js +60 -0
  108. package/dist/native/hosts.js.map +1 -0
  109. package/dist/native/litellm.js +103 -0
  110. package/dist/native/litellm.js.map +1 -0
  111. package/dist/native/models.js +96 -0
  112. package/dist/native/models.js.map +1 -0
  113. package/dist/native/oauth-login.js +112 -0
  114. package/dist/native/oauth-login.js.map +1 -0
  115. package/dist/native/router.js +469 -0
  116. package/dist/native/router.js.map +1 -0
  117. package/dist/native/tls.js +73 -0
  118. package/dist/native/tls.js.map +1 -0
  119. package/dist/native/usage.js +119 -0
  120. package/dist/native/usage.js.map +1 -0
  121. package/dist/normalize.js +98 -0
  122. package/dist/normalize.js.map +1 -0
  123. package/dist/pricing.js +86 -0
  124. package/dist/pricing.js.map +1 -0
  125. package/dist/roles.js +49 -0
  126. package/dist/roles.js.map +1 -0
  127. package/dist/sessions.js +62 -0
  128. package/dist/sessions.js.map +1 -0
  129. package/dist/settings.js +131 -0
  130. package/dist/settings.js.map +1 -0
  131. package/dist/store.js +70 -0
  132. package/dist/store.js.map +1 -0
  133. package/dist/tmux.js +89 -0
  134. package/dist/tmux.js.map +1 -0
  135. package/dist/tui-ink/app-state.js +340 -0
  136. package/dist/tui-ink/app-state.js.map +1 -0
  137. package/dist/tui-ink/app.js +156 -0
  138. package/dist/tui-ink/app.js.map +1 -0
  139. package/dist/tui-ink/components/byok-step.js +102 -0
  140. package/dist/tui-ink/components/byok-step.js.map +1 -0
  141. package/dist/tui-ink/components/login-screen.js +80 -0
  142. package/dist/tui-ink/components/login-screen.js.map +1 -0
  143. package/dist/tui-ink/components/models-step.js +92 -0
  144. package/dist/tui-ink/components/models-step.js.map +1 -0
  145. package/dist/tui-ink/components/multi-select-state.js +56 -0
  146. package/dist/tui-ink/components/multi-select-state.js.map +1 -0
  147. package/dist/tui-ink/components/multi-select.js +69 -0
  148. package/dist/tui-ink/components/multi-select.js.map +1 -0
  149. package/dist/tui-ink/components/providers-step.js +285 -0
  150. package/dist/tui-ink/components/providers-step.js.map +1 -0
  151. package/dist/tui-ink/components/ranked-select-state.js +41 -0
  152. package/dist/tui-ink/components/ranked-select-state.js.map +1 -0
  153. package/dist/tui-ink/components/ranked-select.js +61 -0
  154. package/dist/tui-ink/components/ranked-select.js.map +1 -0
  155. package/dist/tui-ink/components/search-select.js +47 -0
  156. package/dist/tui-ink/components/search-select.js.map +1 -0
  157. package/dist/tui-ink/components/text-input-state.js +42 -0
  158. package/dist/tui-ink/components/text-input-state.js.map +1 -0
  159. package/dist/tui-ink/components/text-input.js +48 -0
  160. package/dist/tui-ink/components/text-input.js.map +1 -0
  161. package/dist/tui-ink/run.js +38 -0
  162. package/dist/tui-ink/run.js.map +1 -0
  163. package/dist/tui-ink/test-compile.js +4 -0
  164. package/dist/tui-ink/test-compile.js.map +1 -0
  165. package/dist/tui-ink/types.js +2 -0
  166. package/dist/tui-ink/types.js.map +1 -0
  167. package/dist/tui.js +330 -0
  168. package/dist/tui.js.map +1 -0
  169. package/dist/types.js +2 -0
  170. package/dist/types.js.map +1 -0
  171. package/dist/watchdog.js +85 -0
  172. package/dist/watchdog.js.map +1 -0
  173. package/hooks/capture-mode.mjs +56 -0
  174. package/hooks/ensure-serve.mjs +140 -0
  175. package/hooks/hooks.json +12 -0
  176. package/hooks/route-session.mjs +47 -0
  177. package/hooks/route-subagent.mjs +54 -0
  178. package/package.json +64 -0
  179. package/roles/code.md +13 -0
  180. package/roles/explore.md +9 -0
  181. package/roles/plan.md +10 -0
  182. package/roles/review.md +11 -0
  183. package/skills/loop/SKILL.md +43 -0
@@ -0,0 +1,469 @@
1
+ import { createServer } from 'node:http';
2
+ import { createUsageCollector, usageFromJsonBody } from './usage.js';
3
+ const HOP_BY_HOP_HEADERS = new Set([
4
+ 'content-encoding',
5
+ 'transfer-encoding',
6
+ 'content-length',
7
+ 'connection',
8
+ ]);
9
+ function targetUrl(base, url) {
10
+ return `${base.replace(/\/$/, '')}/${url.replace(/^\//, '')}`;
11
+ }
12
+ function requestHeaders(headers) {
13
+ return Object.fromEntries(Object.entries(headers).filter(([name]) => !['host', 'content-length'].includes(name.toLowerCase())));
14
+ }
15
+ function responseHeaders(headers) {
16
+ return Object.fromEntries([...headers.entries()].filter(([name]) => !HOP_BY_HOP_HEADERS.has(name.toLowerCase())));
17
+ }
18
+ async function* responseBody(body) {
19
+ const reader = body.getReader();
20
+ try {
21
+ while (true) {
22
+ const { done, value } = await reader.read();
23
+ if (done)
24
+ return;
25
+ yield value;
26
+ }
27
+ }
28
+ finally {
29
+ reader.releaseLock();
30
+ }
31
+ }
32
+ async function drainBody(body) {
33
+ if (Buffer.isBuffer(body))
34
+ return;
35
+ try {
36
+ for await (const _chunk of body) { /* discard */ }
37
+ }
38
+ catch { /* the body failing to drain is not itself an error */ }
39
+ }
40
+ /**
41
+ * Lets the client advance before inspecting its chunk. This keeps accounting
42
+ * off the response critical path; `finally` also accounts for disconnects.
43
+ */
44
+ async function* observe(body, onChunk, onEnd) {
45
+ let complete = false;
46
+ try {
47
+ for await (const chunk of body) {
48
+ yield chunk;
49
+ try {
50
+ onChunk(chunk);
51
+ }
52
+ catch { /* A malformed frame must not interrupt the response. */ }
53
+ }
54
+ complete = true;
55
+ }
56
+ finally {
57
+ try {
58
+ onEnd(complete);
59
+ }
60
+ catch { /* Ledger failures must not escape a disconnected stream either. */ }
61
+ }
62
+ }
63
+ function headerNumber(headers, name) {
64
+ const value = Number(headers[name]);
65
+ return Number.isFinite(value) ? value : undefined;
66
+ }
67
+ /**
68
+ * Adds accounting only when requested. The guard intentionally covers parsing,
69
+ * timestamps, and emission: a ledger defect cannot change router behaviour.
70
+ */
71
+ function withUsageRecording(response, ctx, deps) {
72
+ if (deps.recordUsage === undefined)
73
+ return response;
74
+ try {
75
+ const now = deps.now ?? Date.now;
76
+ const fallbacks = headerNumber(response.headers, 'x-litellm-attempted-fallbacks');
77
+ const retries = headerNumber(response.headers, 'x-litellm-attempted-retries');
78
+ const emit = (tokens, complete) => {
79
+ try {
80
+ const endedAt = now();
81
+ deps.recordUsage?.({
82
+ // Priced at request start, not completion (spec §3): a stream that
83
+ // crosses a price-window boundary must keep the rate it started
84
+ // under. `ms` is the genuine duration and stays tied to `endedAt`.
85
+ ts: new Date(ctx.startedAt).toISOString(),
86
+ ms: endedAt - ctx.startedAt,
87
+ session: ctx.session,
88
+ alias: ctx.alias,
89
+ role: ctx.role,
90
+ tier: ctx.tier,
91
+ key: ctx.key,
92
+ gateway: ctx.gateway,
93
+ upstream: ctx.upstream,
94
+ litellmModel: response.headers['x-litellm-model-name'],
95
+ callId: response.headers['x-litellm-call-id'],
96
+ status: response.status,
97
+ complete,
98
+ tokens,
99
+ // The router knows observations, while serve owns pricing config.
100
+ price: { source: 'none' },
101
+ attempts: ctx.attempts,
102
+ litellm: fallbacks === undefined && retries === undefined
103
+ ? undefined
104
+ : { fallbacks: fallbacks ?? 0, retries: retries ?? 0 },
105
+ });
106
+ }
107
+ catch { /* Accounting is strictly best-effort. */ }
108
+ };
109
+ if (Buffer.isBuffer(response.body)) {
110
+ const { tokens, complete } = usageFromJsonBody(response.body);
111
+ emit(tokens, complete);
112
+ return response;
113
+ }
114
+ const collector = createUsageCollector();
115
+ return {
116
+ ...response,
117
+ body: observe(response.body, (chunk) => collector.push(chunk), (streamComplete) => {
118
+ const { tokens, complete } = collector.finish();
119
+ emit(tokens, streamComplete && complete);
120
+ }),
121
+ };
122
+ }
123
+ catch {
124
+ return response;
125
+ }
126
+ }
127
+ /**
128
+ * The model a request names, for logging which upstream served it.
129
+ *
130
+ * Without this the routing decision is invisible: LiteLLM's access log records
131
+ * the path and status but not the model, so "did this agent really run on the
132
+ * foreign model?" could only be answered by inference.
133
+ */
134
+ export function requestedModel(body) {
135
+ try {
136
+ const model = JSON.parse(body.toString()).model;
137
+ return typeof model === 'string' ? model : undefined;
138
+ }
139
+ catch {
140
+ return undefined;
141
+ }
142
+ }
143
+ /** Rewrites only the `model` field of a JSON body; returns it unchanged if it does not parse. */
144
+ export function withModel(body, model) {
145
+ let payload;
146
+ try {
147
+ payload = JSON.parse(body.toString());
148
+ }
149
+ catch {
150
+ return body;
151
+ }
152
+ return Buffer.from(JSON.stringify({ ...payload, model }));
153
+ }
154
+ export const TIER_COOLDOWN_MS = 60_000;
155
+ /** Module-level so a cooling-down key stays cool across requests. Test seam: `clearCooldowns()`. */
156
+ const cooldowns = new Map();
157
+ export function clearCooldowns() {
158
+ cooldowns.clear();
159
+ }
160
+ /**
161
+ * An Anthropic-shaped error body: `{"type":"error","error":{"type":...,
162
+ * "message":...}}`. An Anthropic-compatible client (Claude Code included)
163
+ * expects this exact envelope on every path — a flat `{type, message}` or a
164
+ * bare `{error: {...}}` with no top-level `type: "error"` is silently
165
+ * discarded, surfacing a generic error instead of the actual message (in
166
+ * particular, the fallback command a tier's 529 names to activate harness
167
+ * dispatch).
168
+ */
169
+ function anthropicErrorBody(type, message) {
170
+ return Buffer.from(JSON.stringify({ type: 'error', error: { type, message } }));
171
+ }
172
+ function isClaudeRequest(body) {
173
+ try {
174
+ return JSON.parse(body.toString()).model?.startsWith('claude-') === true;
175
+ }
176
+ catch {
177
+ return true;
178
+ }
179
+ }
180
+ /**
181
+ * Flattens an Anthropic `system` block array into a single string.
182
+ *
183
+ * Claude Code always sends `system` as an array of text blocks. LiteLLM turns a
184
+ * *string* system prompt into a `developer` message, which the Codex backend
185
+ * accepts, but leaves block arrays as role `system` — and that backend answers
186
+ * `{"detail":"System messages are not allowed"}`, a 400 naming neither the
187
+ * field nor the shape. Probed directly: a string system prompt succeeds, the
188
+ * identical text as a one-element array fails.
189
+ *
190
+ * So the array is joined here, before LiteLLM sees it. The text is unchanged
191
+ * and its order preserved; only the shape differs, and the string form is the
192
+ * one both sides agree on. `cache_control` is dropped with the blocks, which
193
+ * costs prompt caching on this path — the alternative is a request that cannot
194
+ * be sent at all.
195
+ *
196
+ * Returns the body untouched unless it is JSON with a non-empty `system` array:
197
+ * an empty array is already accepted, and a non-JSON body is not ours to parse.
198
+ */
199
+ export function flattenSystemBlocks(body) {
200
+ let payload;
201
+ try {
202
+ payload = JSON.parse(body.toString());
203
+ }
204
+ catch {
205
+ return body;
206
+ }
207
+ const system = payload.system;
208
+ if (!Array.isArray(system) || system.length === 0)
209
+ return body;
210
+ const text = system
211
+ .map((block) => {
212
+ if (typeof block === 'string')
213
+ return block;
214
+ const { type, text: blockText } = (block ?? {});
215
+ // Only text blocks carry a prompt. Anything else (an image, a shape added
216
+ // later) has no string form, so leaving the body alone is safer than
217
+ // silently dropping content.
218
+ return type === 'text' && typeof blockText === 'string' ? blockText : null;
219
+ })
220
+ .filter((part) => part !== null);
221
+ if (text.length !== system.length)
222
+ return body;
223
+ return Buffer.from(JSON.stringify({ ...payload, system: text.join('\n\n') }));
224
+ }
225
+ /**
226
+ * Forwards an already-litellm-shaped request (auth swapped, system flattened,
227
+ * model rewritten if this is a tier candidate) and applies the 500->529
228
+ * empty-completion rewrite. Shared by the plain litellm path and the tier
229
+ * fallback loop so the two forwarding paths cannot drift apart.
230
+ */
231
+ async function forwardToLitellm(body, headers, req, deps) {
232
+ try {
233
+ await deps.litellmReady?.();
234
+ const response = await deps.fetch(targetUrl(deps.litellmBase, req.url), { method: req.method, headers, body: body.length > 0 ? body : undefined });
235
+ // LiteLLM returns 500 when ChatGPT's Codex endpoint yields output:[]. That
236
+ // usually means the upstream was overloaded and returned an empty completion
237
+ // rather than a real error. Re-emitting it as 529 (overloaded) lets Claude
238
+ // Code treat it as a retriable backpressure signal rather than a hard fault.
239
+ if (response.status === 500) {
240
+ const responseBodyBuf = response.body === null
241
+ ? Buffer.alloc(0)
242
+ : Buffer.concat(await async function () { const chunks = []; for await (const c of responseBody(response.body))
243
+ chunks.push(Buffer.from(c)); return chunks; }());
244
+ const text = responseBodyBuf.toString();
245
+ if (text.includes('Unknown items in responses API response')) {
246
+ const msg = 'upstream returned empty completion (overloaded) — retry';
247
+ deps.log?.(`router: 500 from litellm rewritten to 529 (${requestedModel(body) ?? '?'}): empty output`);
248
+ return {
249
+ status: 529,
250
+ headers: { 'content-type': 'application/json' },
251
+ body: anthropicErrorBody('overloaded_error', msg),
252
+ };
253
+ }
254
+ return {
255
+ status: response.status,
256
+ headers: responseHeaders(response.headers),
257
+ body: responseBodyBuf,
258
+ };
259
+ }
260
+ return {
261
+ status: response.status,
262
+ headers: responseHeaders(response.headers),
263
+ body: response.body === null ? Buffer.alloc(0) : responseBody(response.body),
264
+ };
265
+ }
266
+ catch (error) {
267
+ const message = error instanceof Error ? error.message : String(error);
268
+ return {
269
+ status: 502,
270
+ headers: { 'content-type': 'application/json' },
271
+ body: anthropicErrorBody('router_error', message),
272
+ };
273
+ }
274
+ }
275
+ function litellmHeaders(headers, litellmKey) {
276
+ const out = { ...headers };
277
+ for (const name of Object.keys(out)) {
278
+ if (name.toLowerCase() === 'authorization' || name.toLowerCase() === 'x-api-key')
279
+ delete out[name];
280
+ }
281
+ out.authorization = `Bearer ${litellmKey}`;
282
+ return out;
283
+ }
284
+ /**
285
+ * Tries each native-routed candidate for a `sonata-<role>-<tier>` alias in
286
+ * rank order, skipping any inside its post-failure cooldown window. The first
287
+ * response that is neither ≥500, 429, nor a candidate-specific auth failure
288
+ * (401/403) goes to the client — retry is inherently pre-first-byte, so this
289
+ * never interferes with an in-progress stream.
290
+ */
291
+ async function routeTierRequest(req, deps, alias, startedAt, session) {
292
+ // Once per request, not once per candidate: a candidate skipped for being
293
+ // in its post-failure cooldown window would otherwise mean this never
294
+ // fires at all, silently masking a real config change behind an unrelated
295
+ // stale cooldown until it expires on its own.
296
+ deps.checkModelChange?.();
297
+ const resolved = deps.resolveTier?.(alias);
298
+ if (resolved === undefined) {
299
+ return {
300
+ status: 400,
301
+ headers: { 'content-type': 'application/json' },
302
+ body: anthropicErrorBody('invalid_request_error', `unknown sonata tier alias "${alias}" — run \`sonata sync\` and check [tiers] in sonata.toml`),
303
+ };
304
+ }
305
+ const now = deps.now ?? Date.now;
306
+ const headers = litellmHeaders(requestHeaders(req.headers), deps.litellmKey);
307
+ const flattened = flattenSystemBlocks(req.body);
308
+ const candidates = resolved.routes.filter((route) => route.native !== undefined);
309
+ const attempts = [];
310
+ for (const route of candidates) {
311
+ const until = cooldowns.get(route.key);
312
+ if (until !== undefined && until > now())
313
+ continue;
314
+ const body = withModel(flattened, route.key);
315
+ const response = await forwardToLitellm(body, headers, { ...req, body }, deps);
316
+ // 429 is treated as a failure alongside 5xx (not as one of "our" 4xx
317
+ // mistakes to return as-is): it's the upstream saying it's overloaded,
318
+ // exactly the transient case ranked fallback exists for. 401/403 are also
319
+ // retried — they are credential failures specific to THIS candidate's
320
+ // gateway (an expired or rejected key), so a later candidate on a
321
+ // different gateway with a working credential is worth trying, and they
322
+ // must not take down every tier that ranks the affected gateway first.
323
+ // Every other 4xx (e.g. 400) means the request itself was wrong, which
324
+ // retrying can't fix.
325
+ if (response.status >= 500 || response.status === 429 || response.status === 401 || response.status === 403) {
326
+ await drainBody(response.body);
327
+ attempts.push({ key: route.key, status: response.status });
328
+ cooldowns.set(route.key, now() + TIER_COOLDOWN_MS);
329
+ deps.log?.(`router: ${route.key} failed (${response.status}), trying next`);
330
+ continue;
331
+ }
332
+ deps.log?.(`${req.method} ${req.url} model=${alias} -> ${route.key} -> litellm`);
333
+ return withUsageRecording(response, {
334
+ startedAt,
335
+ session,
336
+ alias,
337
+ role: resolved.role,
338
+ tier: resolved.tier,
339
+ key: route.key,
340
+ gateway: route.native.gateway,
341
+ upstream: 'litellm',
342
+ attempts,
343
+ }, deps);
344
+ }
345
+ const label = `${resolved.role}-${resolved.tier}`;
346
+ deps.log?.(`router: all native routes for ${label} failed`);
347
+ return withUsageRecording({
348
+ status: 529,
349
+ headers: { 'content-type': 'application/json' },
350
+ body: anthropicErrorBody('overloaded_error', `all native routes for ${label} failed; fall back with: ` +
351
+ `sonata dispatch --tier ${label} --task-file <path> (or trailing task text) — ` +
352
+ 'dispatch requires one of those; the router has no task text of its own to supply'),
353
+ }, {
354
+ startedAt,
355
+ session,
356
+ alias,
357
+ role: resolved.role,
358
+ tier: resolved.tier,
359
+ upstream: 'litellm',
360
+ attempts,
361
+ }, deps);
362
+ }
363
+ export async function routeRequest(req, deps) {
364
+ const alias = requestedModel(req.body);
365
+ const session = req.headers['x-claude-code-session-id'];
366
+ let startedAt = 0;
367
+ if (deps.recordUsage !== undefined) {
368
+ try {
369
+ startedAt = (deps.now ?? Date.now)();
370
+ }
371
+ catch { /* A broken accounting clock must not stop routing. */ }
372
+ }
373
+ if (alias !== undefined && alias.startsWith('sonata-') && deps.resolveTier?.(alias) !== undefined) {
374
+ return routeTierRequest(req, deps, alias, startedAt, session);
375
+ }
376
+ const anthropic = isClaudeRequest(req.body);
377
+ const headers = requestHeaders(req.headers);
378
+ const upstream = anthropic ? 'anthropic' : 'litellm';
379
+ // Anthropic understands its own block arrays; only the foreign path needs the
380
+ // string form, so the request Anthropic receives stays byte-identical.
381
+ const body = anthropic ? req.body : flattenSystemBlocks(req.body);
382
+ deps.log?.(`${req.method} ${req.url} model=${requestedModel(req.body) ?? '?'} -> ${upstream}`);
383
+ if (!anthropic) {
384
+ // A direct `--model <key>` request never goes through `resolveTier` (the
385
+ // key isn't a `sonata-*` alias), so this is the only place such a
386
+ // request's config-change check can fire.
387
+ deps.checkModelChange?.();
388
+ return withUsageRecording(await forwardToLitellm(body, litellmHeaders(headers, deps.litellmKey), req, deps), {
389
+ startedAt,
390
+ session,
391
+ alias: alias ?? '',
392
+ // For a direct `--model <key>` request, `alias` IS the config key.
393
+ // Recording it (and its gateway) is what lets `resolvePrice` price this
394
+ // request class at all; without it a direct-model row is `source:
395
+ // 'none'` even when full price config exists for that exact model.
396
+ // `key` is only set when `alias` is defined, matching how optional
397
+ // `RecordContext` fields are handled elsewhere — never an own property
398
+ // with value `undefined`.
399
+ ...(alias !== undefined ? { key: alias, gateway: deps.resolveGateway?.(alias) } : {}),
400
+ upstream: 'litellm',
401
+ attempts: [],
402
+ }, deps);
403
+ }
404
+ try {
405
+ const response = await deps.fetch(targetUrl(deps.anthropicBase ?? 'https://api.anthropic.com', req.url), { method: req.method, headers, body: body.length > 0 ? body : undefined });
406
+ return withUsageRecording({
407
+ status: response.status,
408
+ headers: responseHeaders(response.headers),
409
+ body: response.body === null ? Buffer.alloc(0) : responseBody(response.body),
410
+ }, { startedAt, session, alias: alias ?? '', upstream: 'anthropic', attempts: [] }, deps);
411
+ }
412
+ catch (error) {
413
+ const message = error instanceof Error ? error.message : String(error);
414
+ return withUsageRecording({
415
+ status: 502,
416
+ headers: { 'content-type': 'application/json' },
417
+ body: anthropicErrorBody('router_error', message),
418
+ }, { startedAt, session, alias: alias ?? '', upstream: 'anthropic', attempts: [] }, deps);
419
+ }
420
+ }
421
+ function incomingHeaders(req) {
422
+ const headers = {};
423
+ for (const [name, value] of Object.entries(req.headers)) {
424
+ if (value !== undefined)
425
+ headers[name] = Array.isArray(value) ? value.join(', ') : value;
426
+ }
427
+ return headers;
428
+ }
429
+ async function readBody(req) {
430
+ const chunks = [];
431
+ for await (const chunk of req)
432
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
433
+ return Buffer.concat(chunks);
434
+ }
435
+ async function respond(res, routed) {
436
+ res.writeHead(routed.status, routed.headers);
437
+ if (Buffer.isBuffer(routed.body)) {
438
+ res.end(routed.body);
439
+ return;
440
+ }
441
+ for await (const chunk of routed.body)
442
+ res.write(chunk);
443
+ res.end();
444
+ }
445
+ export function createRouterServer(deps) {
446
+ return createServer(async (req, res) => {
447
+ try {
448
+ if (deps.health && new URL(req.url ?? '/', 'http://localhost').pathname === '/__sonata_health') {
449
+ res.writeHead(200, { 'content-type': 'application/json' });
450
+ res.end(JSON.stringify({
451
+ status: 'ok', sonata: true, configPath: deps.configPath ?? null, instanceId: deps.instanceId ?? null,
452
+ }));
453
+ return;
454
+ }
455
+ await respond(res, await routeRequest({
456
+ method: req.method ?? 'GET',
457
+ url: req.url ?? '/',
458
+ headers: incomingHeaders(req),
459
+ body: await readBody(req),
460
+ }, deps));
461
+ }
462
+ catch {
463
+ if (!res.headersSent)
464
+ res.writeHead(500, { 'content-type': 'application/json' });
465
+ res.end(anthropicErrorBody('router_error', 'failed to route request'));
466
+ }
467
+ });
468
+ }
469
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/native/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ export function tlsDir(home) {
5
+ return join(home, '.config', 'sonata', 'tls');
6
+ }
7
+ export function caKeyPath(home) {
8
+ return join(tlsDir(home), 'ca.key');
9
+ }
10
+ export function caCertPath(home) {
11
+ return join(tlsDir(home), 'ca.pem');
12
+ }
13
+ export function serverKeyPath(home) {
14
+ return join(tlsDir(home), 'server.key');
15
+ }
16
+ export function serverCertPath(home) {
17
+ return join(tlsDir(home), 'server.pem');
18
+ }
19
+ export function hasCerts(home) {
20
+ return (existsSync(caKeyPath(home)) &&
21
+ existsSync(caCertPath(home)) &&
22
+ existsSync(serverKeyPath(home)) &&
23
+ existsSync(serverCertPath(home)));
24
+ }
25
+ /**
26
+ * Generates a local CA and a server cert for api.anthropic.com.
27
+ *
28
+ * The CA is what NODE_EXTRA_CA_CERTS points at so spawned `claude -p`
29
+ * processes trust the local server. The server cert has a SAN for the
30
+ * hostname so TLS handshakes succeed.
31
+ *
32
+ * Uses openssl — the only non-Node dependency, universally available on
33
+ * macOS and Linux. The certs are long-lived (10 years) since they never
34
+ * leave the machine.
35
+ */
36
+ export function generateCerts(home) {
37
+ const dir = tlsDir(home);
38
+ mkdirSync(dir, { recursive: true });
39
+ const caKey = caKeyPath(home);
40
+ const caCert = caCertPath(home);
41
+ const srvKey = serverKeyPath(home);
42
+ const srvCert = serverCertPath(home);
43
+ // CA key + self-signed CA cert
44
+ execFileSync('openssl', [
45
+ 'req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1',
46
+ '-keyout', caKey, '-out', caCert,
47
+ '-days', '3650', '-nodes',
48
+ '-subj', '/CN=Sonata Local CA',
49
+ ], { stdio: 'pipe' });
50
+ // Server key + CSR + sign with CA
51
+ const csrPath = join(dir, 'server.csr');
52
+ execFileSync('openssl', [
53
+ 'req', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1',
54
+ '-keyout', srvKey, '-out', csrPath, '-nodes',
55
+ '-subj', '/CN=api.anthropic.com',
56
+ ], { stdio: 'pipe' });
57
+ const extPath = join(dir, 'server.ext');
58
+ execFileSync('bash', ['-c', `cat > '${extPath}' << 'EOF'
59
+ subjectAltName=DNS:api.anthropic.com
60
+ EOF`], { stdio: 'pipe' });
61
+ execFileSync('openssl', [
62
+ 'x509', '-req', '-in', csrPath, '-CA', caCert, '-CAkey', caKey,
63
+ '-CAcreateserial', '-out', srvCert,
64
+ '-days', '3650', '-extfile', extPath,
65
+ ], { stdio: 'pipe' });
66
+ }
67
+ export function readServerTls(home) {
68
+ return {
69
+ key: readFileSync(serverKeyPath(home), 'utf8'),
70
+ cert: readFileSync(serverCertPath(home), 'utf8'),
71
+ };
72
+ }
73
+ //# sourceMappingURL=tls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/native/tls.ts"],"names":[],"mappings":"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"}