omnexx 0.8.0 → 0.9.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 (52) hide show
  1. package/dist/{chat-context-OL7LLKBT.js → chat-context-37IAD72P.js} +5 -5
  2. package/dist/{chat-server-HUYEZGT7.js → chat-server-RMR3QGFJ.js} +11 -11
  3. package/dist/chat-server-RMR3QGFJ.js.map +1 -0
  4. package/dist/{chat-settings-4OW4MUSE.js → chat-settings-AMSAWVT6.js} +5 -5
  5. package/dist/{chunk-ANSOFQ32.js → chunk-27GOEUTN.js} +41 -11
  6. package/dist/chunk-27GOEUTN.js.map +1 -0
  7. package/dist/{chunk-UCIHYU6B.js → chunk-3S4ULH6B.js} +3 -3
  8. package/dist/{chunk-O75OQQDP.js → chunk-EDB7FXDP.js} +2 -2
  9. package/dist/{chunk-CNUYDXSI.js → chunk-FNHEOL3X.js} +14 -10
  10. package/dist/chunk-FNHEOL3X.js.map +1 -0
  11. package/dist/{chunk-KC7YVX2B.js → chunk-IXTUJETQ.js} +81 -33
  12. package/dist/chunk-IXTUJETQ.js.map +1 -0
  13. package/dist/{chunk-JEHAJ45I.js → chunk-IZYY3NPJ.js} +385 -299
  14. package/dist/chunk-IZYY3NPJ.js.map +1 -0
  15. package/dist/{chunk-263JZDVT.js → chunk-LU3LFPGQ.js} +23 -6
  16. package/dist/chunk-LU3LFPGQ.js.map +1 -0
  17. package/dist/{chunk-7T24V7UU.js → chunk-NV4LO7BY.js} +28 -5
  18. package/dist/chunk-NV4LO7BY.js.map +1 -0
  19. package/dist/{chunk-6OQWQDGP.js → chunk-NVDO3QO5.js} +20 -3
  20. package/dist/chunk-NVDO3QO5.js.map +1 -0
  21. package/dist/{chunk-L43V7MUO.js → chunk-STU6YIQJ.js} +3 -3
  22. package/dist/{chunk-YEUB2OJI.js → chunk-T2NUPPUG.js} +2 -2
  23. package/dist/cli.js +15 -14
  24. package/dist/cli.js.map +1 -1
  25. package/dist/{model-picker-M2ZETIKE.js → model-picker-QX6NHUGJ.js} +6 -6
  26. package/dist/{ollama-HHDVJRPX.js → ollama-USDNXHTB.js} +5 -5
  27. package/dist/{print-WTEHAUQ6.js → print-K4HFWHCL.js} +6 -6
  28. package/dist/{roles-PPNR2ECT.js → roles-IHKWWYJL.js} +2 -4
  29. package/dist/session-QGVKS2YJ.js +32 -0
  30. package/dist/{start-3JFBG6PM.js → start-NBU4UITZ.js} +12 -12
  31. package/package.json +3 -2
  32. package/dist/chat-server-HUYEZGT7.js.map +0 -1
  33. package/dist/chunk-263JZDVT.js.map +0 -1
  34. package/dist/chunk-6OQWQDGP.js.map +0 -1
  35. package/dist/chunk-7T24V7UU.js.map +0 -1
  36. package/dist/chunk-ANSOFQ32.js.map +0 -1
  37. package/dist/chunk-CNUYDXSI.js.map +0 -1
  38. package/dist/chunk-JEHAJ45I.js.map +0 -1
  39. package/dist/chunk-KC7YVX2B.js.map +0 -1
  40. package/dist/session-GUDTYRZ5.js +0 -32
  41. /package/dist/{chat-context-OL7LLKBT.js.map → chat-context-37IAD72P.js.map} +0 -0
  42. /package/dist/{chat-settings-4OW4MUSE.js.map → chat-settings-AMSAWVT6.js.map} +0 -0
  43. /package/dist/{chunk-UCIHYU6B.js.map → chunk-3S4ULH6B.js.map} +0 -0
  44. /package/dist/{chunk-O75OQQDP.js.map → chunk-EDB7FXDP.js.map} +0 -0
  45. /package/dist/{chunk-L43V7MUO.js.map → chunk-STU6YIQJ.js.map} +0 -0
  46. /package/dist/{chunk-YEUB2OJI.js.map → chunk-T2NUPPUG.js.map} +0 -0
  47. /package/dist/{model-picker-M2ZETIKE.js.map → model-picker-QX6NHUGJ.js.map} +0 -0
  48. /package/dist/{ollama-HHDVJRPX.js.map → ollama-USDNXHTB.js.map} +0 -0
  49. /package/dist/{print-WTEHAUQ6.js.map → print-K4HFWHCL.js.map} +0 -0
  50. /package/dist/{roles-PPNR2ECT.js.map → roles-IHKWWYJL.js.map} +0 -0
  51. /package/dist/{session-GUDTYRZ5.js.map → session-QGVKS2YJ.js.map} +0 -0
  52. /package/dist/{start-3JFBG6PM.js.map → start-NBU4UITZ.js.map} +0 -0
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  repoRoot
4
- } from "./chunk-YEUB2OJI.js";
4
+ } from "./chunk-T2NUPPUG.js";
5
5
  import {
6
6
  RunStore,
7
7
  listRunIds,
8
8
  repoMemoryFile
9
- } from "./chunk-7T24V7UU.js";
9
+ } from "./chunk-NV4LO7BY.js";
10
10
  import {
11
11
  SECTION_IDS,
12
12
  SECTION_INFO,
@@ -15,12 +15,12 @@ import {
15
15
  loadConfig,
16
16
  readSectionModes,
17
17
  sectionsFile
18
- } from "./chunk-6OQWQDGP.js";
18
+ } from "./chunk-NVDO3QO5.js";
19
19
  import {
20
20
  UsageError,
21
21
  resolvePaths
22
22
  } from "./chunk-XQTM3SWX.js";
23
- import "./chunk-ANSOFQ32.js";
23
+ import "./chunk-27GOEUTN.js";
24
24
  import "./chunk-2H7UOFLK.js";
25
25
 
26
26
  // src/cli/chat-context.ts
@@ -117,4 +117,4 @@ export {
117
117
  contextFiles,
118
118
  setSectionMode
119
119
  };
120
- //# sourceMappingURL=chat-context-OL7LLKBT.js.map
120
+ //# sourceMappingURL=chat-context-37IAD72P.js.map
@@ -32,7 +32,7 @@ function text(c, key) {
32
32
  return v;
33
33
  }
34
34
  async function serveChat(io, runCli, opts) {
35
- const { Session } = await import("./session-GUDTYRZ5.js");
35
+ const { Session } = await import("./session-QGVKS2YJ.js");
36
36
  const session = new Session(io, runCli);
37
37
  const write = (msg) => {
38
38
  println(io.stdout, JSON.stringify(msg));
@@ -102,7 +102,7 @@ async function serveChat(io, runCli, opts) {
102
102
  };
103
103
  session.onChange(schedule);
104
104
  const sendModels = async () => {
105
- const { loadModelChoices } = await import("./model-picker-M2ZETIKE.js");
105
+ const { loadModelChoices } = await import("./model-picker-QX6NHUGJ.js");
106
106
  const { items, unreachable } = await loadModelChoices(io);
107
107
  write({
108
108
  type: "models",
@@ -112,15 +112,15 @@ async function serveChat(io, runCli, opts) {
112
112
  });
113
113
  };
114
114
  const sendSettings = async () => {
115
- const { providerSettings } = await import("./chat-settings-4OW4MUSE.js");
115
+ const { providerSettings } = await import("./chat-settings-AMSAWVT6.js");
116
116
  write({ type: "settings", ...await providerSettings(io) });
117
117
  };
118
118
  const sendContextFiles = async () => {
119
- const { contextFiles } = await import("./chat-context-OL7LLKBT.js");
119
+ const { contextFiles } = await import("./chat-context-37IAD72P.js");
120
120
  write({ type: "contextFiles", ...await contextFiles(io) });
121
121
  };
122
122
  const sendRoles = async () => {
123
- const { readRoles } = await import("./roles-PPNR2ECT.js");
123
+ const { readRoles } = await import("./roles-IHKWWYJL.js");
124
124
  const { QuotaLedger } = await import("./quota-ledger-7F6QTZAM.js");
125
125
  const paths = resolvePaths(io.env);
126
126
  write({
@@ -192,7 +192,7 @@ async function serveChat(io, runCli, opts) {
192
192
  return typeof v === "string" ? v : void 0;
193
193
  };
194
194
  run(
195
- import("./chat-settings-4OW4MUSE.js").then(async ({ addProvider }) => {
195
+ import("./chat-settings-AMSAWVT6.js").then(async ({ addProvider }) => {
196
196
  await providersChanged(
197
197
  await addProvider(io, {
198
198
  provider: str("provider"),
@@ -206,7 +206,7 @@ async function serveChat(io, runCli, opts) {
206
206
  }
207
207
  case "testProvider":
208
208
  run(
209
- import("./chat-settings-4OW4MUSE.js").then(async ({ testProvider }) => {
209
+ import("./chat-settings-AMSAWVT6.js").then(async ({ testProvider }) => {
210
210
  write({ type: "providerTest", ...await testProvider(io, text(c, "name")) });
211
211
  })
212
212
  );
@@ -216,7 +216,7 @@ async function serveChat(io, runCli, opts) {
216
216
  return;
217
217
  case "setSectionMode":
218
218
  run(
219
- import("./chat-context-OL7LLKBT.js").then(async ({ setSectionMode }) => {
219
+ import("./chat-context-37IAD72P.js").then(async ({ setSectionMode }) => {
220
220
  await setSectionMode(io, text(c, "id"), text(c, "mode"));
221
221
  await sendContextFiles();
222
222
  })
@@ -227,7 +227,7 @@ async function serveChat(io, runCli, opts) {
227
227
  return;
228
228
  case "setRoles":
229
229
  run(
230
- import("./roles-PPNR2ECT.js").then(async ({ parseRoles, writeRoles }) => {
230
+ import("./roles-IHKWWYJL.js").then(async ({ parseRoles, writeRoles }) => {
231
231
  await writeRoles(resolvePaths(io.env), parseRoles(c.roles));
232
232
  session.push("system", "model roles saved; new chats and runs use them");
233
233
  await sendRoles();
@@ -236,7 +236,7 @@ async function serveChat(io, runCli, opts) {
236
236
  return;
237
237
  case "removeProvider":
238
238
  run(
239
- import("./chat-settings-4OW4MUSE.js").then(async ({ removeProvider }) => {
239
+ import("./chat-settings-AMSAWVT6.js").then(async ({ removeProvider }) => {
240
240
  await providersChanged(await removeProvider(io, text(c, "name")));
241
241
  })
242
242
  );
@@ -281,4 +281,4 @@ async function serveChat(io, runCli, opts) {
281
281
  export {
282
282
  serveChat
283
283
  };
284
- //# sourceMappingURL=chat-server-HUYEZGT7.js.map
284
+ //# sourceMappingURL=chat-server-RMR3QGFJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/chat-server.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { resolvePaths } from '../core/paths.js';\nimport { readFile } from 'node:fs/promises';\nimport { createInterface } from 'node:readline';\nimport { describeError } from '../errors.js';\nimport type { Telemetry } from '../telemetry/aggregate.js';\nimport type { TodoItem } from '../tools/todo.js';\nimport type { Entry, Helper, Mode, RunCli } from '../tui/session.js';\nimport { println, type CliIO } from './io.js';\n\n/**\n * `omnexx chat-server`: the interactive session behind a JSON-lines protocol on stdin/stdout, for\n * editor panels (the VS Code chat). It drives the same Session as the terminal UI, so slash\n * commands, approvals, model switching and plan mode behave the same way.\n *\n * In (one JSON object per line): send {text} · answer {yes} · stop · pause · resume · mode {mode} ·\n * yolo {on} ·\n * model {ref} · models · connect {value, name?} · undo · clear · compact · sync (resend all) ·\n * settings · addProvider {provider?, key?, url?} · removeProvider {name} · testProvider {name} ·\n * roles · setRoles {roles} · contextFiles · setSectionMode {id, mode}.\n * Out: ready {version} · state (below; `entries` holds only lines not sent before) · models\n * {items, unreachable, current} · settings {catalog, connected} · providerTest {name, ok, models,\n * detail} · error {message}.\n */\n\nexport interface ChatUsage {\n /** When the chat's first event happened (epoch ms), for an uptime clock. */\n startedAt: number | null;\n tokens: Telemetry['tokens'];\n usd: number;\n turns: number;\n toolCalls: number;\n toolErrors: number;\n compactions: number;\n}\n\nexport interface ChatState {\n type: 'state';\n entries: Entry[];\n /** The reply as it streams in; empty once it lands in `entries`. */\n live: string;\n todos: TodoItem[];\n /** A question waiting for allow / deny, or null. */\n pending: string | null;\n mode: Mode;\n busy: boolean;\n paused: boolean;\n autoApprove: boolean;\n model: string | null;\n /** Tokens in use, the compaction limit, and what they are made of. */\n context: {\n used: number;\n limit: number;\n parts?: { system: number; tools: number; conversation: number };\n } | null;\n usage: ChatUsage | null;\n run: { id: string; alive: boolean; phase?: string; done?: number; tasks?: number } | null;\n /** Helpers (subagents) for the current message. */\n helpers: Helper[];\n /** The latest browser frame's number and page; the image comes as a `browserFrame` message. */\n browser: { seq: number; url: string; action: string; at: number } | null;\n}\n\n/** Frames larger than this are skipped rather than pushed through the pipe. */\nconst MAX_FRAME_BYTES = 4 * 1024 * 1024;\n\nconst MODES = new Set<Mode>(['chat', 'plan', 'run']);\n/** Coalesce bursts of changes (a streaming reply fires one per token) into one state line. */\nconst EMIT_EVERY_MS = 40;\n\ntype Command = { type: string } & Record<string, unknown>;\n\nfunction parseCommand(line: string): Command {\n let data: unknown;\n try {\n data = JSON.parse(line);\n } catch {\n throw new Error('expected one JSON object per line');\n }\n if (typeof data !== 'object' || data === null || typeof (data as Command).type !== 'string')\n throw new Error('expected an object with a \"type\"');\n return data as Command;\n}\n\nfunction text(c: Command, key: string): string {\n const v = c[key];\n if (typeof v !== 'string' || !v.trim()) throw new Error(`\"${c.type}\" needs a \"${key}\" string`);\n return v;\n}\n\nexport async function serveChat(\n io: CliIO,\n runCli: RunCli,\n opts: { version: string },\n): Promise<number> {\n const { Session } = await import('../tui/session.js');\n const session = new Session(io, runCli);\n const write = (msg: object): void => {\n println(io.stdout, JSON.stringify(msg));\n };\n const fail = (err: unknown): void => {\n write({ type: 'error', message: describeError(err) });\n };\n\n let sentUpTo = -1;\n let sentFrame = 0;\n /** Send the browser's latest screenshot once per new frame. */\n const sendFrame = async (): Promise<void> => {\n const f = session.browserFrame;\n if (!f || f.seq === sentFrame) return;\n sentFrame = f.seq;\n const data = await readFile(f.path).catch(() => undefined);\n if (!data || data.length > MAX_FRAME_BYTES) return;\n write({\n type: 'browserFrame',\n seq: f.seq,\n mime: f.mime,\n url: f.url,\n action: f.action,\n data: data.toString('base64'),\n });\n };\n /** The last entry before the latest new chat; a reloaded panel starts after it. */\n let clearedAt = -1;\n let timer: NodeJS.Timeout | undefined;\n const emit = (): void => {\n timer = undefined;\n const fresh = session.entries.filter((e) => e.id > sentUpTo);\n sentUpTo = session.entries.at(-1)?.id ?? sentUpTo;\n const t = session.chatTelemetry;\n const state: ChatState = {\n type: 'state',\n entries: fresh,\n live: session.live,\n todos: session.todos,\n pending: session.pending?.question ?? null,\n mode: session.mode,\n busy: session.busy !== undefined || session.chatBusy,\n paused: session.chatPaused,\n autoApprove: session.autoApprove,\n model: session.chatModelName ?? null,\n context: session.context ?? null,\n usage: t\n ? {\n startedAt: t.startedAt ?? null,\n tokens: t.tokens,\n usd: t.usd,\n turns: t.turns,\n toolCalls: t.toolCalls,\n toolErrors: t.toolErrors,\n compactions: t.compactions,\n }\n : null,\n run: session.runId ? { id: session.runId, alive: session.runAlive, ...session.info } : null,\n helpers: session.helpers,\n browser: session.browserFrame\n ? {\n seq: session.browserFrame.seq,\n url: session.browserFrame.url,\n action: session.browserFrame.action,\n at: session.browserFrame.at,\n }\n : null,\n };\n write(state);\n void sendFrame();\n };\n const schedule = (): void => {\n timer ??= setTimeout(emit, EMIT_EVERY_MS);\n };\n session.onChange(schedule);\n\n const sendModels = async (): Promise<void> => {\n const { loadModelChoices } = await import('../tui/model-picker.js');\n const { items, unreachable } = await loadModelChoices(io);\n write({\n type: 'models',\n items: items.filter((i) => i.kind === 'model'),\n unreachable,\n current: session.chatModelName ?? null,\n });\n };\n const sendSettings = async (): Promise<void> => {\n const { providerSettings } = await import('./chat-settings.js');\n write({ type: 'settings', ...(await providerSettings(io)) });\n };\n const sendContextFiles = async (): Promise<void> => {\n const { contextFiles } = await import('./chat-context.js');\n write({ type: 'contextFiles', ...(await contextFiles(io)) });\n };\n /** Roles as saved, plus which models are out of quota right now (ref → when it ran out). */\n const sendRoles = async (): Promise<void> => {\n const { readRoles } = await import('../config/roles.js');\n const { QuotaLedger } = await import('../providers/quota-ledger.js');\n const paths = resolvePaths(io.env);\n write({\n type: 'roles',\n roles: await readRoles(paths),\n exhausted: new QuotaLedger(join(paths.configHome, 'quota.json')).all(),\n });\n };\n /** After a provider change: say what happened, then refresh the settings page and models. */\n const providersChanged = async (message: string): Promise<void> => {\n session.push('system', message);\n await sendSettings();\n await sendModels();\n };\n\n /** Commands still running, so a closed pipe lets them finish before the process exits. */\n const inflight = new Set<Promise<unknown>>();\n const run = (p: Promise<unknown>): void => {\n const tracked = p.catch(fail).finally(() => {\n inflight.delete(tracked);\n schedule();\n });\n inflight.add(tracked);\n };\n\n const handle = (c: Command): void => {\n switch (c.type) {\n case 'send':\n run(session.submit(text(c, 'text')));\n return;\n case 'answer':\n if (!session.pending) throw new Error('nothing is waiting for an answer');\n run(session.submit(c.yes === true ? 'y' : 'n'));\n return;\n case 'stop':\n case 'pause':\n case 'resume':\n case 'undo':\n case 'compact':\n run(session.command(c.type));\n return;\n case 'clear':\n run(\n session.command('clear').then(() => {\n // A new chat starts the panel over: nothing from before the clear is sent again.\n clearedAt = session.entries.at(-1)?.id ?? clearedAt;\n sentUpTo = clearedAt;\n write({ type: 'ready', version: opts.version });\n emit();\n }),\n );\n return;\n case 'mode': {\n const mode = c.mode as Mode;\n if (!MODES.has(mode)) throw new Error('mode is one of chat, plan, run');\n if (session.mode !== mode) session.setMode(mode);\n return;\n }\n case 'yolo':\n // /yolo toggles; only run it when the state differs from what was asked, and without\n // echoing it as a message.\n if ((c.on === true) !== session.autoApprove) run(session.command('yolo'));\n return;\n case 'model':\n run(session.switchModel(text(c, 'ref')));\n return;\n case 'models':\n run(sendModels());\n return;\n case 'settings':\n run(sendSettings());\n return;\n case 'addProvider': {\n const str = (k: string): string | undefined => {\n const v = c[k];\n return typeof v === 'string' ? v : undefined;\n };\n run(\n import('./chat-settings.js').then(async ({ addProvider }) => {\n await providersChanged(\n await addProvider(io, {\n provider: str('provider'),\n key: str('key'),\n url: str('url'),\n }),\n );\n }),\n );\n return;\n }\n case 'testProvider':\n run(\n import('./chat-settings.js').then(async ({ testProvider }) => {\n write({ type: 'providerTest', ...(await testProvider(io, text(c, 'name'))) });\n }),\n );\n return;\n case 'contextFiles':\n run(sendContextFiles());\n return;\n case 'setSectionMode':\n run(\n import('./chat-context.js').then(async ({ setSectionMode }) => {\n await setSectionMode(io, text(c, 'id'), text(c, 'mode'));\n await sendContextFiles();\n }),\n );\n return;\n case 'roles':\n run(sendRoles());\n return;\n case 'setRoles':\n run(\n import('../config/roles.js').then(async ({ parseRoles, writeRoles }) => {\n await writeRoles(resolvePaths(io.env), parseRoles(c.roles));\n session.push('system', 'model roles saved; new chats and runs use them');\n await sendRoles();\n }),\n );\n return;\n case 'removeProvider':\n run(\n import('./chat-settings.js').then(async ({ removeProvider }) => {\n await providersChanged(await removeProvider(io, text(c, 'name')));\n }),\n );\n return;\n case 'connect': {\n const name = typeof c.name === 'string' && c.name.trim() ? ` --name ${c.name.trim()}` : '';\n run(session.submit(`/model ${text(c, 'value')}${name}`));\n return;\n }\n case 'sync':\n // A reloaded panel: start it over with the conversation since the last new chat.\n sentUpTo = clearedAt;\n sentFrame = 0;\n write({ type: 'ready', version: opts.version });\n emit();\n return;\n default:\n throw new Error(`unknown command \"${c.type}\"`);\n }\n };\n\n await session.loadCommands();\n await session.continueChat().catch(fail);\n await session.greet(false).catch(fail);\n write({ type: 'ready', version: opts.version });\n emit();\n\n const lines = createInterface({ input: io.stdin, crlfDelay: Infinity });\n for await (const line of lines) {\n if (!line.trim()) continue;\n try {\n handle(parseCommand(line));\n } catch (err) {\n fail(err);\n }\n }\n // The editor closed the pipe: end any turn in progress, let running commands finish, then\n // flush the last state.\n if (session.chatBusy) await session.command('stop');\n await Promise.allSettled([...inflight]);\n if (timer) {\n clearTimeout(timer);\n emit();\n }\n return 0;\n}\n"],"mappings":"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","names":[]}
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  connect,
4
4
  describeConnect
5
- } from "./chunk-UCIHYU6B.js";
5
+ } from "./chunk-3S4ULH6B.js";
6
6
  import {
7
7
  PROVIDER_TEMPLATES,
8
8
  removeEndpointBlock
9
- } from "./chunk-O75OQQDP.js";
9
+ } from "./chunk-EDB7FXDP.js";
10
10
  import "./chunk-7PC4SSYS.js";
11
11
  import {
12
12
  clearKey,
@@ -15,13 +15,13 @@ import {
15
15
  } from "./chunk-TJWLF5MU.js";
16
16
  import {
17
17
  loadConfig
18
- } from "./chunk-6OQWQDGP.js";
18
+ } from "./chunk-NVDO3QO5.js";
19
19
  import {
20
20
  UsageError,
21
21
  resolvePaths,
22
22
  userConfigFile
23
23
  } from "./chunk-XQTM3SWX.js";
24
- import "./chunk-ANSOFQ32.js";
24
+ import "./chunk-27GOEUTN.js";
25
25
  import "./chunk-UX4MF6V4.js";
26
26
  import "./chunk-2H7UOFLK.js";
27
27
 
@@ -144,4 +144,4 @@ export {
144
144
  removeProvider,
145
145
  testProvider
146
146
  };
147
- //# sourceMappingURL=chat-settings-4OW4MUSE.js.map
147
+ //# sourceMappingURL=chat-settings-AMSAWVT6.js.map
@@ -1,5 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/config/routing.ts
4
+ var STRATEGIES = ["priority", "random", "least-busy", "smart"];
5
+ function orderForStrategy(chain, strategy, ctx = {}) {
6
+ const indexed = chain.map((m, i) => ({ m, i }));
7
+ switch (strategy) {
8
+ case "random": {
9
+ const rnd = ctx.random ?? Math.random;
10
+ const keys = new Map(indexed.map((x) => [x.i, rnd()]));
11
+ return indexed.sort((a, b) => (keys.get(a.i) ?? 0) - (keys.get(b.i) ?? 0)).map((x) => x.m);
12
+ }
13
+ case "least-busy": {
14
+ const busy = ctx.busy ?? /* @__PURE__ */ new Map();
15
+ return indexed.sort((a, b) => (busy.get(a.m.provider) ?? 0) - (busy.get(b.m.provider) ?? 0) || a.i - b.i).map((x) => x.m);
16
+ }
17
+ case "smart":
18
+ return indexed.sort((a, b) => (b.m.price?.output ?? 0) - (a.m.price?.output ?? 0) || a.i - b.i).map((x) => x.m);
19
+ default:
20
+ return [...chain];
21
+ }
22
+ }
23
+ function strategyFor(models, role) {
24
+ const set = models.routing?.[role];
25
+ if (set) return set;
26
+ return role === "helpers" && models.spread_helpers !== false ? "least-busy" : "priority";
27
+ }
28
+
3
29
  // src/config/roles.ts
4
30
  import { mkdir, readFile, writeFile } from "fs/promises";
5
31
  import { dirname, join } from "path";
@@ -20,13 +46,20 @@ function parseRoles(raw) {
20
46
  const list = cleanList(modelsIn[role]);
21
47
  if (list.length) models[role] = list;
22
48
  }
23
- return { models, spreadHelpers: obj.spreadHelpers !== false };
49
+ const strategiesIn = typeof obj.strategies === "object" && obj.strategies !== null ? obj.strategies : {};
50
+ const strategies = {};
51
+ for (const role of ROLE_NAMES) {
52
+ const s = strategiesIn[role];
53
+ if (typeof s === "string" && STRATEGIES.includes(s))
54
+ strategies[role] = s;
55
+ }
56
+ return { models, strategies, spreadHelpers: obj.spreadHelpers !== false };
24
57
  }
25
58
  async function readRoles(p) {
26
59
  try {
27
60
  return parseRoles(JSON.parse(await readFile(rolesFile(p), "utf8")));
28
61
  } catch {
29
- return { models: {}, spreadHelpers: true };
62
+ return { models: {}, strategies: {}, spreadHelpers: true };
30
63
  }
31
64
  }
32
65
  async function writeRoles(p, roles) {
@@ -46,22 +79,19 @@ function rolesLayer(r) {
46
79
  if (cheap?.length) models.cheap = cheap;
47
80
  if (helpers?.length) models.helpers = helpers;
48
81
  if (!r.spreadHelpers) models.spread_helpers = false;
82
+ if (Object.keys(r.strategies).length) models.routing = r.strategies;
49
83
  return Object.keys(models).length ? { models } : void 0;
50
84
  }
51
- function spreadAcrossProviders(chain, n) {
52
- const providers = [...new Set(chain.map((m) => m.provider))];
53
- if (providers.length < 2) return [...chain];
54
- const lead = providers[n % providers.length];
55
- return [...chain.filter((m) => m.provider === lead), ...chain.filter((m) => m.provider !== lead)];
56
- }
57
85
 
58
86
  export {
87
+ STRATEGIES,
88
+ orderForStrategy,
89
+ strategyFor,
59
90
  ROLE_NAMES,
60
91
  rolesFile,
61
92
  parseRoles,
62
93
  readRoles,
63
94
  writeRoles,
64
- rolesLayer,
65
- spreadAcrossProviders
95
+ rolesLayer
66
96
  };
67
- //# sourceMappingURL=chunk-ANSOFQ32.js.map
97
+ //# sourceMappingURL=chunk-27GOEUTN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/routing.ts","../src/config/roles.ts"],"sourcesContent":["/**\n * How a role's models are ordered before each use. The first model is tried first; the rest are\n * the failover chain, so every strategy keeps every model as a fallback.\n * - priority: as the person arranged them.\n * - random: a fresh shuffle each time, spreading load evenly.\n * - least-busy: providers with the fewest helpers running go first (parallel helpers spread out).\n * - smart: the most capable first, with output price as the stand-in for capability.\n */\nexport const STRATEGIES = ['priority', 'random', 'least-busy', 'smart'] as const;\nexport type Strategy = (typeof STRATEGIES)[number];\n\ninterface Routable {\n provider: string;\n price?: { output?: number } | undefined;\n}\n\nexport interface OrderContext {\n /** Helpers running per provider right now (least-busy). */\n busy?: ReadonlyMap<string, number>;\n /** Source of randomness (tests pass a fixed one). */\n random?: () => number;\n}\n\nexport function orderForStrategy<T extends Routable>(\n chain: readonly T[],\n strategy: Strategy,\n ctx: OrderContext = {},\n): T[] {\n const indexed = chain.map((m, i) => ({ m, i }));\n switch (strategy) {\n case 'random': {\n const rnd = ctx.random ?? Math.random;\n const keys = new Map(indexed.map((x) => [x.i, rnd()]));\n return indexed.sort((a, b) => (keys.get(a.i) ?? 0) - (keys.get(b.i) ?? 0)).map((x) => x.m);\n }\n case 'least-busy': {\n const busy = ctx.busy ?? new Map<string, number>();\n return indexed\n .sort((a, b) => (busy.get(a.m.provider) ?? 0) - (busy.get(b.m.provider) ?? 0) || a.i - b.i)\n .map((x) => x.m);\n }\n case 'smart':\n return indexed\n .sort((a, b) => (b.m.price?.output ?? 0) - (a.m.price?.output ?? 0) || a.i - b.i)\n .map((x) => x.m);\n default:\n return [...chain];\n }\n}\n\n/** The strategy a role uses: its setting, else least-busy for helpers (when spreading) and priority. */\nexport function strategyFor(\n models: { routing?: Partial<Record<string, Strategy>>; spread_helpers?: boolean },\n role: string,\n): Strategy {\n const set = models.routing?.[role];\n if (set) return set;\n return role === 'helpers' && models.spread_helpers !== false ? 'least-busy' : 'priority';\n}\n","import { STRATEGIES, type Strategy } from './routing.js';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport type { OmnexxPaths } from '../core/paths.js';\n\n/**\n * Which models power which role, chosen in the editor's settings and kept next to the /models\n * pool (`roles.json`). A role left empty falls back to the pool and config.toml as before.\n * `helpers` powers subagents. Each role also has a routing strategy (see routing.ts): least-busy\n * helpers spread over providers, so several providers' quotas are used at once.\n */\nexport const ROLE_NAMES = ['chat', 'planner', 'worker', 'cheap', 'helpers'] as const;\nexport type Role = (typeof ROLE_NAMES)[number];\n\nexport interface Roles {\n models: Partial<Record<Role, string[]>>;\n /** How each role routes between its models; unset roles use the default. */\n strategies: Partial<Record<Role, Strategy>>;\n spreadHelpers: boolean;\n}\n\nconst REF = /^[a-z][a-z0-9_-]*:\\S+$/;\nconst MAX_PER_ROLE = 20;\n\nexport const rolesFile = (p: OmnexxPaths): string => join(p.configHome, 'roles.json');\n\n/** Keep only well-formed, distinct refs, in order. */\nfunction cleanList(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n const refs = value.filter((r): r is string => typeof r === 'string' && REF.test(r));\n return [...new Set(refs)].slice(0, MAX_PER_ROLE);\n}\n\nexport function parseRoles(raw: unknown): Roles {\n const obj = typeof raw === 'object' && raw !== null ? (raw as Record<string, unknown>) : {};\n const modelsIn =\n typeof obj.models === 'object' && obj.models !== null\n ? (obj.models as Record<string, unknown>)\n : {};\n const models: Partial<Record<Role, string[]>> = {};\n for (const role of ROLE_NAMES) {\n const list = cleanList(modelsIn[role]);\n if (list.length) models[role] = list;\n }\n const strategiesIn =\n typeof obj.strategies === 'object' && obj.strategies !== null\n ? (obj.strategies as Record<string, unknown>)\n : {};\n const strategies: Partial<Record<Role, Strategy>> = {};\n for (const role of ROLE_NAMES) {\n const s = strategiesIn[role];\n if (typeof s === 'string' && (STRATEGIES as readonly string[]).includes(s))\n strategies[role] = s as Strategy;\n }\n return { models, strategies, spreadHelpers: obj.spreadHelpers !== false };\n}\n\nexport async function readRoles(p: OmnexxPaths): Promise<Roles> {\n try {\n return parseRoles(JSON.parse(await readFile(rolesFile(p), 'utf8')));\n } catch {\n return { models: {}, strategies: {}, spreadHelpers: true };\n }\n}\n\nexport async function writeRoles(p: OmnexxPaths, roles: Roles): Promise<Roles> {\n const clean = parseRoles(roles);\n const file = rolesFile(p);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, `${JSON.stringify(clean, null, 2)}\\n`);\n return clean;\n}\n\n/** The roles as a config layer: only the roles that were set, so the rest fall through. */\nexport function rolesLayer(r: Roles): Record<string, unknown> | undefined {\n const models: Record<string, unknown> = {};\n const { chat, planner, worker, cheap, helpers } = r.models;\n if (chat?.[0]) models.chat = chat[0];\n if (planner?.length) models.planner = planner;\n if (worker?.length) models.worker = worker;\n if (cheap?.length) models.cheap = cheap;\n if (helpers?.length) models.helpers = helpers;\n if (!r.spreadHelpers) models.spread_helpers = false;\n if (Object.keys(r.strategies).length) models.routing = r.strategies;\n return Object.keys(models).length ? { models } : undefined;\n}\n"],"mappings":"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","names":[]}
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  PROVIDER_TEMPLATES,
4
4
  appendEndpointBlock
5
- } from "./chunk-O75OQQDP.js";
5
+ } from "./chunk-EDB7FXDP.js";
6
6
  import {
7
7
  findProviderKey,
8
8
  storeKey
9
9
  } from "./chunk-TJWLF5MU.js";
10
10
  import {
11
11
  loadConfig
12
- } from "./chunk-6OQWQDGP.js";
12
+ } from "./chunk-NVDO3QO5.js";
13
13
  import {
14
14
  UsageError,
15
15
  resolvePaths,
@@ -183,4 +183,4 @@ export {
183
183
  envKeys,
184
184
  connectFromEnv
185
185
  };
186
- //# sourceMappingURL=chunk-UCIHYU6B.js.map
186
+ //# sourceMappingURL=chunk-3S4ULH6B.js.map
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  loadConfig,
13
13
  parseDuration
14
- } from "./chunk-6OQWQDGP.js";
14
+ } from "./chunk-NVDO3QO5.js";
15
15
  import {
16
16
  UsageError,
17
17
  resolvePaths,
@@ -277,4 +277,4 @@ export {
277
277
  removeEndpointBlock,
278
278
  register
279
279
  };
280
- //# sourceMappingURL=chunk-O75OQQDP.js.map
280
+ //# sourceMappingURL=chunk-EDB7FXDP.js.map
@@ -6,26 +6,26 @@ import {
6
6
  humanize,
7
7
  pickRun,
8
8
  supervisorAlive
9
- } from "./chunk-KC7YVX2B.js";
9
+ } from "./chunk-IXTUJETQ.js";
10
10
  import {
11
11
  CodeChat,
12
12
  attachImages,
13
13
  resolveModelLenient
14
- } from "./chunk-263JZDVT.js";
14
+ } from "./chunk-LU3LFPGQ.js";
15
15
  import {
16
16
  emptyTelemetry,
17
17
  fold,
18
18
  parseFrontmatter,
19
19
  resolveRunDeps,
20
20
  todoItemsOf
21
- } from "./chunk-JEHAJ45I.js";
21
+ } from "./chunk-IZYY3NPJ.js";
22
22
  import {
23
23
  RunStore,
24
24
  compactPlanView,
25
25
  git,
26
26
  listRunIds,
27
27
  planCounts
28
- } from "./chunk-7T24V7UU.js";
28
+ } from "./chunk-NV4LO7BY.js";
29
29
  import {
30
30
  QuotaLedger
31
31
  } from "./chunk-DGKPM32R.js";
@@ -36,7 +36,7 @@ import {
36
36
  RED,
37
37
  filterChoices,
38
38
  loadModelChoices
39
- } from "./chunk-L43V7MUO.js";
39
+ } from "./chunk-STU6YIQJ.js";
40
40
  import {
41
41
  connect,
42
42
  connectFromEnv,
@@ -44,7 +44,7 @@ import {
44
44
  envKeys,
45
45
  findKeyInText,
46
46
  looksLikeKey
47
- } from "./chunk-UCIHYU6B.js";
47
+ } from "./chunk-3S4ULH6B.js";
48
48
  import {
49
49
  findProviderKey,
50
50
  maskKey
@@ -56,7 +56,7 @@ import {
56
56
  readRanking,
57
57
  writePoolMode,
58
58
  writeRanking
59
- } from "./chunk-6OQWQDGP.js";
59
+ } from "./chunk-NVDO3QO5.js";
60
60
  import {
61
61
  UsageError,
62
62
  describeError,
@@ -621,7 +621,7 @@ var Session = class {
621
621
  }
622
622
  /** No provider yet but Ollama is running locally: connect it, so the first chat just works. */
623
623
  async autoOllama() {
624
- const { ollamaModels, pickOllamaModel } = await import("./ollama-HHDVJRPX.js");
624
+ const { ollamaModels, pickOllamaModel } = await import("./ollama-USDNXHTB.js");
625
625
  const model = pickOllamaModel(await ollamaModels(this.io.fetch ?? fetch) ?? []);
626
626
  if (!model) return false;
627
627
  try {
@@ -1120,7 +1120,11 @@ var Session = class {
1120
1120
  }
1121
1121
  /** Context in use / the limit chat compacts at, once a chat is open. */
1122
1122
  get context() {
1123
- return this.code ? { used: this.code.contextUsed, limit: this.code.contextLimit } : void 0;
1123
+ return this.code ? {
1124
+ used: this.code.contextUsed,
1125
+ limit: this.code.contextLimit,
1126
+ parts: this.code.contextParts
1127
+ } : void 0;
1124
1128
  }
1125
1129
  /** True while /pause holds the chat at its next step. */
1126
1130
  get chatPaused() {
@@ -1628,4 +1632,4 @@ export {
1628
1632
  Session,
1629
1633
  helpText
1630
1634
  };
1631
- //# sourceMappingURL=chunk-CNUYDXSI.js.map
1635
+ //# sourceMappingURL=chunk-FNHEOL3X.js.map