@oeronteros-1/opencode-orchestra 0.5.3 → 1.0.1

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 (72) hide show
  1. package/CHANGELOG.md +63 -9
  2. package/GITHUB_RELEASE_1.0.0.md +84 -0
  3. package/README.md +95 -7
  4. package/dashboard-dist/assets/index-CN3CG5oG.js +124 -0
  5. package/dashboard-dist/assets/{index-89Gs8jun.css → index-j0b0ZK2D.css} +1 -1
  6. package/dashboard-dist/index.html +2 -2
  7. package/dist/agents/workers.d.ts +14 -1
  8. package/dist/agents/workers.js +10 -0
  9. package/dist/agents/workers.js.map +1 -1
  10. package/dist/cli.js +63 -3
  11. package/dist/cli.js.map +1 -1
  12. package/dist/config/schema.d.ts +23 -0
  13. package/dist/config/schema.js +18 -1
  14. package/dist/config/schema.js.map +1 -1
  15. package/dist/dashboard/server.d.ts +11 -0
  16. package/dist/dashboard/server.js +152 -33
  17. package/dist/dashboard/server.js.map +1 -1
  18. package/dist/diagnostics/completion.d.ts +5 -0
  19. package/dist/diagnostics/completion.js +145 -0
  20. package/dist/diagnostics/completion.js.map +1 -0
  21. package/dist/diagnostics/doctor.d.ts +58 -0
  22. package/dist/diagnostics/doctor.js +354 -0
  23. package/dist/diagnostics/doctor.js.map +1 -0
  24. package/dist/diagnostics/update.d.ts +17 -0
  25. package/dist/diagnostics/update.js +89 -0
  26. package/dist/diagnostics/update.js.map +1 -0
  27. package/dist/index.js +141 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/plugin-status.d.ts +34 -0
  30. package/dist/plugin-status.js +90 -0
  31. package/dist/plugin-status.js.map +1 -0
  32. package/dist/routing/budget-guard.d.ts +36 -0
  33. package/dist/routing/budget-guard.js +52 -0
  34. package/dist/routing/budget-guard.js.map +1 -0
  35. package/dist/routing/classifier-cache.d.ts +25 -0
  36. package/dist/routing/classifier-cache.js +46 -0
  37. package/dist/routing/classifier-cache.js.map +1 -0
  38. package/dist/routing/fallback.d.ts +41 -0
  39. package/dist/routing/fallback.js +81 -0
  40. package/dist/routing/fallback.js.map +1 -0
  41. package/dist/routing/model-discovery.js +3 -1
  42. package/dist/routing/model-discovery.js.map +1 -1
  43. package/dist/routing/model-resolver.d.ts +11 -0
  44. package/dist/routing/model-resolver.js +27 -7
  45. package/dist/routing/model-resolver.js.map +1 -1
  46. package/dist/routing/observer.d.ts +22 -0
  47. package/dist/routing/observer.js +64 -0
  48. package/dist/routing/observer.js.map +1 -0
  49. package/dist/routing/planner.d.ts +24 -0
  50. package/dist/routing/planner.js +106 -0
  51. package/dist/routing/planner.js.map +1 -0
  52. package/dist/routing/pricing/estimate.d.ts +60 -0
  53. package/dist/routing/pricing/estimate.js +81 -0
  54. package/dist/routing/pricing/estimate.js.map +1 -0
  55. package/dist/routing/pricing/prices.d.ts +19 -0
  56. package/dist/routing/pricing/prices.js +74 -0
  57. package/dist/routing/pricing/prices.js.map +1 -0
  58. package/dist/routing/pricing/refresh.d.ts +30 -0
  59. package/dist/routing/pricing/refresh.js +105 -0
  60. package/dist/routing/pricing/refresh.js.map +1 -0
  61. package/dist/telemetry/analytics.d.ts +45 -0
  62. package/dist/telemetry/analytics.js +78 -0
  63. package/dist/telemetry/analytics.js.map +1 -0
  64. package/dist/telemetry/ledger.d.ts +13 -1
  65. package/dist/telemetry/ledger.js +29 -1
  66. package/dist/telemetry/ledger.js.map +1 -1
  67. package/dist/tools.d.ts +6 -1
  68. package/dist/tools.js +77 -7
  69. package/dist/tools.js.map +1 -1
  70. package/package.json +17 -4
  71. package/schema/opencode-orchestra.schema.json +15 -2
  72. package/dashboard-dist/assets/index-Bhe8OPZD.js +0 -124
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ import { applyDiscoveredModels, discoverConnectedModels } from "./routing/model-
6
6
  import { primarySystemHint } from "./superpowers/compatibility.js";
7
7
  import { Ledger } from "./telemetry/ledger.js";
8
8
  import { createOrchestraTools } from "./tools.js";
9
+ import { createStreamObserver } from "./routing/observer.js";
10
+ import { createPriceRefresher } from "./routing/pricing/refresh.js";
11
+ import { detectMcpPresence, resolvePluginVersion, PACKAGE_NAME } from "./plugin-status.js";
9
12
  function mergeAgent(base, override) {
10
13
  if (!override)
11
14
  return base;
@@ -18,6 +21,74 @@ function mergeAgent(base, override) {
18
21
  },
19
22
  };
20
23
  }
24
+ // Stream observers keyed by message part id. These let us flag low-confidence
25
+ // or self-correcting output *while a worker is still generating*, before any
26
+ // finalized answer exists, so escalation can fire early instead of post-hoc.
27
+ const streamObservers = new Map();
28
+ const flaggedParts = new Set();
29
+ const STREAM_CONFIDENCE_THRESHOLD = 0.6;
30
+ // Opt-in reply text and prompt text accumulation, keyed by message id. Only
31
+ // populated when `telemetry.storeTexts` is enabled; otherwise dropped.
32
+ const replyBuffers = new Map();
33
+ // A chat.message prompt precedes its assistant message and has a different id,
34
+ // so prompts are correlated by session rather than by assistant message id.
35
+ const promptBuffers = new Map();
36
+ const MAX_TEXT_BUFFERS = 512;
37
+ let storeTextsFlag = false;
38
+ function pruneOldest(map) {
39
+ while (map.size > MAX_TEXT_BUFFERS) {
40
+ const oldest = map.keys().next().value;
41
+ if (oldest === undefined)
42
+ break;
43
+ map.delete(oldest);
44
+ }
45
+ }
46
+ function trackStreamDelta(sessionID, part, delta) {
47
+ if (!delta)
48
+ return;
49
+ const partID = part.id;
50
+ let observer = streamObservers.get(partID);
51
+ if (!observer) {
52
+ observer = createStreamObserver({ threshold: STREAM_CONFIDENCE_THRESHOLD });
53
+ streamObservers.set(partID, observer);
54
+ }
55
+ const observation = observer.push(delta);
56
+ if (observation.lowConfidence && !flaggedParts.has(partID)) {
57
+ flaggedParts.add(partID);
58
+ void logStreamFlag(sessionID, partID, observation).catch(() => undefined);
59
+ }
60
+ if (storeTextsFlag) {
61
+ replyBuffers.set(part.messageID, `${replyBuffers.get(part.messageID) ?? ""}${delta}`);
62
+ pruneOldest(replyBuffers);
63
+ }
64
+ }
65
+ function endStream(messageID) {
66
+ // A finalized message no longer needs an accumulated reply after its event
67
+ // handler has consumed it. Keep the id parameter explicit for lifecycle use.
68
+ if (!storeTextsFlag)
69
+ replyBuffers.delete(messageID);
70
+ // Observers are pruned lazily by size to bound memory over a long session.
71
+ if (streamObservers.size > 512) {
72
+ const overflow = streamObservers.size - 512;
73
+ let removed = 0;
74
+ for (const key of streamObservers.keys()) {
75
+ if (removed >= overflow)
76
+ break;
77
+ streamObservers.delete(key);
78
+ flaggedParts.delete(key);
79
+ removed += 1;
80
+ }
81
+ }
82
+ }
83
+ // Stub logger: replaced when the plugin body captures `client.app.log`.
84
+ let streamLog = () => Promise.resolve();
85
+ function logStreamFlag(sessionID, partID, observation) {
86
+ return streamLog(sessionID, "orchestra stream observer flagged low-confidence output", {
87
+ partID,
88
+ confidence: observation.confidence,
89
+ flags: observation.flags,
90
+ });
91
+ }
21
92
  export const OrchestraPlugin = async ({ client, directory }, rawOptions = {}) => {
22
93
  const loaded = await loadConfig(directory, rawOptions);
23
94
  const discovered = await discoverConnectedModels(client);
@@ -29,8 +100,30 @@ export const OrchestraPlugin = async ({ client, directory }, rawOptions = {}) =>
29
100
  ...Object.values(orchestra.models.worker),
30
101
  orchestra.models.judge,
31
102
  ];
32
- const ledger = new Ledger(directory, orchestra.telemetry.directory, orchestra.telemetry.enabled, pools);
103
+ const ledger = new Ledger(directory, orchestra.telemetry.directory, orchestra.telemetry.enabled, pools, orchestra.telemetry.storeTexts);
104
+ storeTextsFlag = orchestra.telemetry.storeTexts;
105
+ const refreshSource = orchestra.pricing.endpoint
106
+ ? { endpoint: orchestra.pricing.endpoint, refreshIntervalHours: orchestra.pricing.refreshIntervalHours }
107
+ : undefined;
108
+ const priceRefresher = createPriceRefresher(undefined, refreshSource);
109
+ priceRefresher.start();
33
110
  const systemHint = primarySystemHint(orchestra);
111
+ const pluginStatus = {
112
+ name: PACKAGE_NAME,
113
+ version: await resolvePluginVersion(),
114
+ budget: orchestra.budget,
115
+ modelStrategy: orchestra.models.strategy,
116
+ configuredModels: pools.flat().length,
117
+ discoveredModels: discovered.length,
118
+ configSource: loaded.source ?? "plugin options/defaults",
119
+ mcp: await detectMcpPresence(),
120
+ };
121
+ streamLog = (sessionID, message, extra) => client.app
122
+ .log({
123
+ body: { service: "opencode-orchestra", level: "warn", message, extra: { sessionID, ...extra } },
124
+ })
125
+ .then(() => undefined)
126
+ .catch(() => undefined);
34
127
  await client.app
35
128
  .log({
36
129
  body: {
@@ -59,19 +152,65 @@ export const OrchestraPlugin = async ({ client, directory }, rawOptions = {}) =>
59
152
  description: "Show OpenCode Orchestra usage and escalation status",
60
153
  template: "Call the orchestra_status tool and present its result verbatim.",
61
154
  };
155
+ mutable.command["plugin-status"] ??= {
156
+ description: "Show the OpenCode Orchestra plugin's own runtime status",
157
+ template: "Call the orchestra_plugin_status tool and present its result verbatim.",
158
+ };
62
159
  mutable.command.orchestra ??= {
63
160
  description: "Classify a task and delegate it to orch-lead",
64
161
  template: "Call orchestra_route for this task: $ARGUMENTS. Then delegate the full task once to orch-lead using the returned profile and constraints.",
65
162
  };
66
163
  },
67
- tool: createOrchestraTools(orchestra, ledger),
164
+ tool: createOrchestraTools(orchestra, ledger, pluginStatus, {
165
+ get snapshot() { return priceRefresher.snapshot; },
166
+ }),
167
+ dispose: async () => {
168
+ priceRefresher.stop();
169
+ promptBuffers.clear();
170
+ replyBuffers.clear();
171
+ streamObservers.clear();
172
+ flaggedParts.clear();
173
+ },
174
+ "chat.message": async ({ sessionID }, output) => {
175
+ if (!storeTextsFlag || !sessionID)
176
+ return;
177
+ const text = output.parts
178
+ .filter((part) => part.type === "text")
179
+ .map((part) => part.text)
180
+ .join("")
181
+ .trim();
182
+ if (text) {
183
+ promptBuffers.set(sessionID, text);
184
+ pruneOldest(promptBuffers);
185
+ }
186
+ },
68
187
  event: async ({ event }) => {
188
+ if (event.type === "message.part.updated") {
189
+ const part = event.properties.part;
190
+ trackStreamDelta(part.sessionID, part, event.properties.delta ?? "");
191
+ return;
192
+ }
69
193
  if (event.type !== "message.updated")
70
194
  return;
71
195
  const info = event.properties.info;
72
196
  if (info.role !== "assistant")
73
197
  return;
198
+ endStream(info.id);
74
199
  await ledger.recordAssistant(info);
200
+ if (storeTextsFlag) {
201
+ const prompt = promptBuffers.get(info.sessionID);
202
+ const reply = replyBuffers.get(info.id);
203
+ promptBuffers.delete(info.sessionID);
204
+ replyBuffers.delete(info.id);
205
+ if (prompt !== undefined || reply !== undefined) {
206
+ const text = {};
207
+ if (prompt !== undefined)
208
+ text.prompt = prompt;
209
+ if (reply !== undefined)
210
+ text.reply = reply;
211
+ await ledger.recordText(info.sessionID, info.id, text);
212
+ }
213
+ }
75
214
  },
76
215
  ...(systemHint
77
216
  ? {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export declare const PACKAGE_NAME = "@oeronteros-1/opencode-orchestra";
2
+ /**
3
+ * Resolve the installed package version from `package.json`. The compiled
4
+ * output lives in `dist/`, so the package root is one level up. Falls back to
5
+ * "unknown" when the manifest cannot be read (e.g. running from an unpacked
6
+ * source tree without a package.json next to the dist folder).
7
+ */
8
+ export declare function resolvePluginVersion(): Promise<string>;
9
+ /**
10
+ * Snapshot of the plugin's own runtime state. Unlike `orchestra_status` (which
11
+ * reports per-session usage/escalation telemetry), this reports the plugin
12
+ * itself: what version is loaded, which budget/strategy are active, where the
13
+ * config came from, how many models were discovered, and which companion MCPs
14
+ * are present in the OpenCode configuration.
15
+ */
16
+ export interface PluginStatus {
17
+ name: string;
18
+ version: string;
19
+ budget: string;
20
+ modelStrategy: string;
21
+ configuredModels: number;
22
+ discoveredModels: number;
23
+ configSource: string;
24
+ mcp: Record<string, boolean>;
25
+ }
26
+ /**
27
+ * Detect which companion MCPs are configured in the OpenCode main config.
28
+ * Mirrors the dashboard's `mcpStatus` helper without importing the HTTP server.
29
+ */
30
+ export declare function detectMcpPresence(configDirectory?: string): Promise<Record<string, boolean>>;
31
+ /**
32
+ * Format the plugin status snapshot as a stable, human-readable report.
33
+ */
34
+ export declare function formatPluginStatus(status: PluginStatus): Promise<string>;
@@ -0,0 +1,90 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parse } from "jsonc-parser";
4
+ import { openCodeConfigDirectory } from "./config/paths.js";
5
+ export const PACKAGE_NAME = "@oeronteros-1/opencode-orchestra";
6
+ /**
7
+ * Resolve the installed package version from `package.json`. The compiled
8
+ * output lives in `dist/`, so the package root is one level up. Falls back to
9
+ * "unknown" when the manifest cannot be read (e.g. running from an unpacked
10
+ * source tree without a package.json next to the dist folder).
11
+ */
12
+ export async function resolvePluginVersion() {
13
+ try {
14
+ const here = new URL(".", import.meta.url);
15
+ const inline = new URL("../package.json", here);
16
+ const pkg = JSON.parse(await readFile(inline, "utf8"));
17
+ if (pkg.version)
18
+ return pkg.version;
19
+ }
20
+ catch {
21
+ // Fall through to the unknown marker.
22
+ }
23
+ return "unknown";
24
+ }
25
+ async function readTextOr(file, fallback) {
26
+ try {
27
+ return await readFile(file, "utf8");
28
+ }
29
+ catch {
30
+ return fallback;
31
+ }
32
+ }
33
+ async function findMainConfig(configDirectory) {
34
+ for (const name of ["opencode.json", "opencode.jsonc"]) {
35
+ const candidate = path.join(configDirectory, name);
36
+ try {
37
+ await readFile(candidate, "utf8");
38
+ return candidate;
39
+ }
40
+ catch {
41
+ // Try the next name.
42
+ }
43
+ }
44
+ return path.join(configDirectory, "opencode.json");
45
+ }
46
+ function parseJsonc(text) {
47
+ const value = parse(text, [], { allowTrailingComma: true, disallowComments: false });
48
+ return typeof value === "object" && value !== null && !Array.isArray(value)
49
+ ? value
50
+ : {};
51
+ }
52
+ /**
53
+ * Detect which companion MCPs are configured in the OpenCode main config.
54
+ * Mirrors the dashboard's `mcpStatus` helper without importing the HTTP server.
55
+ */
56
+ export async function detectMcpPresence(configDirectory = openCodeConfigDirectory()) {
57
+ const root = parseJsonc(await readTextOr(await findMainConfig(configDirectory), "{}"));
58
+ const mcp = typeof root.mcp === "object" && root.mcp !== null && !Array.isArray(root.mcp)
59
+ ? root.mcp
60
+ : {};
61
+ return {
62
+ context7: "context7" in mcp,
63
+ codebaseMemory: "codebase-memory" in mcp,
64
+ memoryGraph: "memorygraph" in mcp,
65
+ supermemory: "supermemory" in mcp,
66
+ };
67
+ }
68
+ /**
69
+ * Format the plugin status snapshot as a stable, human-readable report.
70
+ */
71
+ export async function formatPluginStatus(status) {
72
+ const mcp = Object.entries({ ...status.mcp })
73
+ .sort(([a], [b]) => a.localeCompare(b))
74
+ .map(([name, present]) => ` ${name.padEnd(24)} ${present ? "connected" : "not configured"}`)
75
+ .join("\n");
76
+ return [
77
+ "OpenCode Orchestra plugin status",
78
+ "",
79
+ `plugin: ${status.name}@${status.version}`,
80
+ `budget: ${status.budget}`,
81
+ `model strategy: ${status.modelStrategy}`,
82
+ `configured models: ${status.configuredModels}`,
83
+ `discovered models: ${status.discoveredModels}`,
84
+ `config source: ${status.configSource}`,
85
+ "",
86
+ "MCP servers:",
87
+ mcp || " none detected",
88
+ ].join("\n");
89
+ }
90
+ //# sourceMappingURL=plugin-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-status.js","sourceRoot":"","sources":["../src/plugin-status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { BudgetMode, ModelCost } from "../config/schema.js";
2
+ /** How much paid-model spend a single work branch is allowed before we cut it. */
3
+ export interface PaidBudgetLimit {
4
+ /** Maximum paid-model calls a branch may make before termination. */
5
+ maxPaidCalls: number;
6
+ /** Soft warning threshold (fraction of maxPaidCalls). */
7
+ warnAt: number;
8
+ enabled: boolean;
9
+ }
10
+ /**
11
+ * Derive a paid-call budget for a branch of work from the global budget mode.
12
+ * eco/balanced keep it tight (no or few paid calls); quality/ebobo open it up.
13
+ *
14
+ * "Early termination" here is budget-aware: a branch is stopped as soon as it
15
+ * has burned its paid-call allowance, so paid models never silently overrun.
16
+ */
17
+ export declare function paidBudgetFor(mode: BudgetMode, explicit?: Partial<PaidBudgetLimit>): PaidBudgetLimit;
18
+ export interface BudgetSnapshot {
19
+ paidCallsUsed: number;
20
+ remaining: number;
21
+ terminated: boolean;
22
+ warning: boolean;
23
+ }
24
+ export interface BudgetGuard {
25
+ /** Record a paid call and report whether the branch should stop. */
26
+ recordPaidCall(cost: ModelCost): BudgetSnapshot;
27
+ /** Current remaining paid-call allowance. */
28
+ remaining(): number;
29
+ reset(): void;
30
+ }
31
+ /**
32
+ * Guard a single work branch. Only the costs of a *paid* model advance the
33
+ * counter; free/subscription calls are free passes (mode already prices them
34
+ * in elsewhere). Once paidCallsUsed reaches the cap the branch is terminated.
35
+ */
36
+ export declare function createBudgetGuard(limit: PaidBudgetLimit): BudgetGuard;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Derive a paid-call budget for a branch of work from the global budget mode.
3
+ * eco/balanced keep it tight (no or few paid calls); quality/ebobo open it up.
4
+ *
5
+ * "Early termination" here is budget-aware: a branch is stopped as soon as it
6
+ * has burned its paid-call allowance, so paid models never silently overrun.
7
+ */
8
+ export function paidBudgetFor(mode, explicit) {
9
+ const base = {
10
+ eco: { maxPaidCalls: 0, warnAt: 0, enabled: false },
11
+ balanced: { maxPaidCalls: 1, warnAt: 1, enabled: true },
12
+ quality: { maxPaidCalls: 6, warnAt: 0.7, enabled: true },
13
+ ebobo: { maxPaidCalls: 12, warnAt: 0.75, enabled: true },
14
+ };
15
+ const defaults = base[mode];
16
+ return {
17
+ ...defaults,
18
+ ...explicit,
19
+ enabled: (explicit?.enabled ?? defaults.enabled) && (explicit?.maxPaidCalls ?? defaults.maxPaidCalls) >= 0,
20
+ };
21
+ }
22
+ /**
23
+ * Guard a single work branch. Only the costs of a *paid* model advance the
24
+ * counter; free/subscription calls are free passes (mode already prices them
25
+ * in elsewhere). Once paidCallsUsed reaches the cap the branch is terminated.
26
+ */
27
+ export function createBudgetGuard(limit) {
28
+ let paidCallsUsed = 0;
29
+ const cap = limit.maxPaidCalls;
30
+ const warnAt = Math.round(limit.warnAt * cap);
31
+ const snapshot = () => {
32
+ const remaining = Math.max(0, cap - paidCallsUsed);
33
+ return {
34
+ paidCallsUsed,
35
+ remaining,
36
+ terminated: cap > 0 && paidCallsUsed >= cap,
37
+ warning: !limit.enabled ? false : cap > 0 && paidCallsUsed >= warnAt && paidCallsUsed < cap,
38
+ };
39
+ };
40
+ return {
41
+ recordPaidCall(cost) {
42
+ if (cost === "paid")
43
+ paidCallsUsed += 1;
44
+ return snapshot();
45
+ },
46
+ remaining: () => Math.max(0, cap - paidCallsUsed),
47
+ reset() {
48
+ paidCallsUsed = 0;
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=budget-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget-guard.js","sourceRoot":"","sources":["../../src/routing/budget-guard.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAgB,EAAE,QAAmC;IACjF,MAAM,IAAI,GAAgF;QACxF,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE;QACnD,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;QACvD,OAAO,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;QACxD,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;KACzD,CAAA;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3B,OAAO;QACL,GAAG,QAAQ;QACX,GAAG,QAAQ;QACX,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC;KAC3G,CAAA;AACH,CAAC;AAiBD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAA;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAA;IAE7C,MAAM,QAAQ,GAAG,GAAmB,EAAE;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,aAAa,CAAC,CAAA;QAClD,OAAO;YACL,aAAa;YACb,SAAS;YACT,UAAU,EAAE,GAAG,GAAG,CAAC,IAAI,aAAa,IAAI,GAAG;YAC3C,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,aAAa,IAAI,MAAM,IAAI,aAAa,GAAG,GAAG;SAC5F,CAAA;IACH,CAAC,CAAA;IAED,OAAO;QACL,cAAc,CAAC,IAAI;YACjB,IAAI,IAAI,KAAK,MAAM;gBAAE,aAAa,IAAI,CAAC,CAAA;YACvC,OAAO,QAAQ,EAAE,CAAA;QACnB,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,aAAa,CAAC;QACjD,KAAK;YACH,aAAa,GAAG,CAAC,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { Classification } from "./classifier.js";
2
+ /**
3
+ * Memoized classification cache: near-duplicate tasks reuse a previous
4
+ * classification instead of re-running the (judge-token-burning) classifier.
5
+ * Content-addressed by a normalized fingerprint and LRU-bounded in process.
6
+ */
7
+ export interface CacheEntry {
8
+ key: string;
9
+ classification: Classification;
10
+ createdAt: number;
11
+ hits: number;
12
+ lastHit: number;
13
+ }
14
+ export interface ClassifierCacheOptions {
15
+ maxEntries?: number;
16
+ }
17
+ /** Normalize a task into a stable fingerprint (case/punct/whitespace folding). */
18
+ export declare function fingerprint(task: string): string;
19
+ export declare function createClassifierCache(options?: ClassifierCacheOptions): {
20
+ get(task: string): Classification | undefined;
21
+ set(task: string, classification: Classification): void;
22
+ clear(): void;
23
+ size: () => number;
24
+ };
25
+ export type ClassifierCache = ReturnType<typeof createClassifierCache>;
@@ -0,0 +1,46 @@
1
+ /** Normalize a task into a stable fingerprint (case/punct/whitespace folding). */
2
+ export function fingerprint(task) {
3
+ return task
4
+ .toLowerCase()
5
+ .normalize("NFKC")
6
+ .replace(/[^\p{L}\p{N}\s]/gu, " ")
7
+ .replace(/\s+/g, " ")
8
+ .trim();
9
+ }
10
+ export function createClassifierCache(options = {}) {
11
+ const maxEntries = options.maxEntries ?? 256;
12
+ const map = new Map();
13
+ function touch(entry) {
14
+ map.delete(entry.key);
15
+ map.set(entry.key, entry);
16
+ }
17
+ return {
18
+ get(task) {
19
+ const key = fingerprint(task);
20
+ const entry = map.get(key);
21
+ if (!entry)
22
+ return undefined;
23
+ entry.hits += 1;
24
+ entry.lastHit = Date.now();
25
+ touch(entry);
26
+ return entry.classification;
27
+ },
28
+ set(task, classification) {
29
+ const key = fingerprint(task);
30
+ const now = Date.now();
31
+ const entry = { key, classification, createdAt: now, hits: 0, lastHit: now };
32
+ map.set(key, entry);
33
+ while (map.size > maxEntries) {
34
+ const oldest = map.keys().next().value;
35
+ if (oldest === undefined)
36
+ break;
37
+ map.delete(oldest);
38
+ }
39
+ },
40
+ clear() {
41
+ map.clear();
42
+ },
43
+ size: () => map.size,
44
+ };
45
+ }
46
+ //# sourceMappingURL=classifier-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier-cache.js","sourceRoot":"","sources":["../../src/routing/classifier-cache.ts"],"names":[],"mappings":"AAoBA,kFAAkF;AAClF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC;SACjC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAkC,EAAE;IACxE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAA;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAA;IAEzC,SAAS,KAAK,CAAC,KAAiB;QAC9B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACrB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,OAAO;QACL,GAAG,CAAC,IAAY;YACd,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;YAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAA;YAC5B,KAAK,CAAC,IAAI,IAAI,CAAC,CAAA;YACf,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC1B,KAAK,CAAC,KAAK,CAAC,CAAA;YACZ,OAAO,KAAK,CAAC,cAAc,CAAA;QAC7B,CAAC;QACD,GAAG,CAAC,IAAY,EAAE,cAA8B;YAC9C,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,MAAM,KAAK,GAAe,EAAE,GAAG,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAA;YACxF,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACnB,OAAO,GAAG,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA;gBACtC,IAAI,MAAM,KAAK,SAAS;oBAAE,MAAK;gBAC/B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;QACD,KAAK;YACH,GAAG,CAAC,KAAK,EAAE,CAAA;QACb,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI;KACrB,CAAA;AACH,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { BudgetMode, ModelCandidateInput, ModelCost } from "../config/schema.js";
2
+ import { resolveModel } from "./model-resolver.js";
3
+ export interface FallbackEntry {
4
+ id: string;
5
+ cost: ModelCost;
6
+ /** Lower is cheaper; used to prefer cheaper fallbacks after a failure. */
7
+ costRank: number;
8
+ }
9
+ export interface FallbackChain {
10
+ /** The winning model id (first choice). */
11
+ primary: string;
12
+ /** Ordered cheaper alternatives after the primary. */
13
+ alternatives: FallbackEntry[];
14
+ /** All entries (primary + alternatives) in failover order. */
15
+ all: FallbackEntry[];
16
+ }
17
+ interface RetryableError {
18
+ /** HTTP status or "timeout". Rate-limit (429) and 5xx are retryable. */
19
+ kind: "rate-limit" | "server" | "timeout" | "other";
20
+ }
21
+ /**
22
+ * Classify an error into retryable categories. A retryable failure should
23
+ * trigger failover to a cheaper model in the chain.
24
+ */
25
+ export declare function classifyError(error: unknown): RetryableError;
26
+ export declare function isRetryable(kind: RetryableError["kind"]): boolean;
27
+ /**
28
+ * Build a failover chain for a capability pool. The primary is the current
29
+ * winner; alternatives are the remaining candidates sorted by increasing cost
30
+ * (cheaper first), so a retry steps down in price instead of up.
31
+ */
32
+ export declare function buildFallbackChain(pool: ModelCandidateInput[], capability: Parameters<typeof resolveModel>[0]["capability"], budget: BudgetMode, allowPaid: boolean, options?: {
33
+ preferredCosts?: ModelCost[];
34
+ preferredTiers?: Parameters<typeof resolveModel>[0]["preferredTiers"];
35
+ }): FallbackChain | undefined;
36
+ /**
37
+ * Given a chain and the id of a model that just failed, return the next
38
+ * cheaper alternative to try, or undefined when the chain is exhausted.
39
+ */
40
+ export declare function nextAfterFailure(chain: FallbackChain, failedId: string): string | undefined;
41
+ export {};
@@ -0,0 +1,81 @@
1
+ import { normalizeCandidate, resolveModel } from "./model-resolver.js";
2
+ const COST_RANK = { paid: 2, subscription: 1, free: 0 };
3
+ /**
4
+ * Classify an error into retryable categories. A retryable failure should
5
+ * trigger failover to a cheaper model in the chain.
6
+ */
7
+ export function classifyError(error) {
8
+ const candidate = typeof error === "object" && error !== null ? error : undefined;
9
+ const message = typeof error === "string"
10
+ ? error
11
+ : candidate?.message
12
+ ? String(candidate.message)
13
+ : error instanceof Error
14
+ ? error.message
15
+ : String(error);
16
+ const status = candidate?.status ?? candidate?.statusCode;
17
+ const text = (status !== undefined ? String(status) + " " : "") + message.toLowerCase();
18
+ if (status === 429 || text.includes("429") || text.includes("rate limit") || text.includes("rate-limit") || text.includes("too many requests")) {
19
+ return { kind: "rate-limit" };
20
+ }
21
+ if (status === 408 || text.includes("timeout") || text.includes("timed out")) {
22
+ return { kind: "timeout" };
23
+ }
24
+ if ((status !== undefined && status >= 500) || text.includes("internal server error") || text.includes("service unavailable") || text.includes("overloaded")) {
25
+ return { kind: "server" };
26
+ }
27
+ return { kind: "other" };
28
+ }
29
+ export function isRetryable(kind) {
30
+ return kind === "rate-limit" || kind === "server" || kind === "timeout";
31
+ }
32
+ /**
33
+ * Build a failover chain for a capability pool. The primary is the current
34
+ * winner; alternatives are the remaining candidates sorted by increasing cost
35
+ * (cheaper first), so a retry steps down in price instead of up.
36
+ */
37
+ export function buildFallbackChain(pool, capability, budget, allowPaid, options = {}) {
38
+ const normalized = pool.map(normalizeCandidate);
39
+ if (normalized.length === 0)
40
+ return undefined;
41
+ const winner = resolveModel({
42
+ pool,
43
+ capability,
44
+ budget,
45
+ allowPaid,
46
+ ...(options.preferredCosts ? { preferredCosts: options.preferredCosts } : {}),
47
+ ...(options.preferredTiers ? { preferredTiers: options.preferredTiers } : {}),
48
+ });
49
+ const primary = winner?.id ?? normalized[0]?.id;
50
+ if (!primary)
51
+ return undefined;
52
+ const byId = new Map(normalized.map((candidate) => [candidate.id, candidate]));
53
+ const primaryEntry = toEntry(byId.get(primary));
54
+ const alternatives = normalized
55
+ .filter((candidate) => candidate.id !== primary)
56
+ .sort((a, b) => COST_RANK[a.cost] - COST_RANK[b.cost] || a.id.localeCompare(b.id))
57
+ .map((candidate) => toEntry(candidate));
58
+ return {
59
+ primary,
60
+ alternatives,
61
+ all: primaryEntry ? [primaryEntry, ...alternatives] : alternatives,
62
+ };
63
+ }
64
+ function toEntry(candidate) {
65
+ return {
66
+ id: candidate?.id ?? "",
67
+ cost: candidate?.cost ?? "free",
68
+ costRank: COST_RANK[candidate?.cost ?? "free"],
69
+ };
70
+ }
71
+ /**
72
+ * Given a chain and the id of a model that just failed, return the next
73
+ * cheaper alternative to try, or undefined when the chain is exhausted.
74
+ */
75
+ export function nextAfterFailure(chain, failedId) {
76
+ const index = chain.all.findIndex((entry) => entry.id === failedId);
77
+ if (index < 0)
78
+ return undefined;
79
+ return chain.all[index + 1]?.id;
80
+ }
81
+ //# sourceMappingURL=fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback.js","sourceRoot":"","sources":["../../src/routing/fallback.ts"],"names":[],"mappings":"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"}