omnexx 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/dist/{chat-context-SP5XSAF7.js → chat-context-P4ZON7M4.js} +7 -7
- package/dist/{chat-server-NKLX3WTV.js → chat-server-FMF26CBV.js} +16 -14
- package/dist/chat-server-FMF26CBV.js.map +1 -0
- package/dist/{chat-settings-K5643AXQ.js → chat-settings-4XUKDH6H.js} +10 -10
- package/dist/chunk-23MT7K6X.js +209 -0
- package/dist/chunk-23MT7K6X.js.map +1 -0
- package/dist/{chunk-UACCTB6B.js → chunk-3OILFLAA.js} +130 -93
- package/dist/chunk-3OILFLAA.js.map +1 -0
- package/dist/{chunk-P6HRCAYP.js → chunk-ET6OMKAS.js} +4 -2
- package/dist/chunk-ET6OMKAS.js.map +1 -0
- package/dist/chunk-FSA52KQB.js +569 -0
- package/dist/chunk-FSA52KQB.js.map +1 -0
- package/dist/{chunk-5XMZIGYS.js → chunk-GBFAEDOD.js} +20 -6
- package/dist/chunk-GBFAEDOD.js.map +1 -0
- package/dist/chunk-H4XHEBFQ.js +257 -0
- package/dist/chunk-H4XHEBFQ.js.map +1 -0
- package/dist/{chunk-C2RB5YRZ.js → chunk-KJ5SPE6X.js} +675 -113
- package/dist/chunk-KJ5SPE6X.js.map +1 -0
- package/dist/{chunk-4C3ZA5OG.js → chunk-L2YBK4AY.js} +14 -5
- package/dist/chunk-L2YBK4AY.js.map +1 -0
- package/dist/{chunk-MHH66U5Y.js → chunk-MC4NBIIA.js} +6 -6
- package/dist/{chunk-HWL2XISD.js → chunk-PRAOJIKH.js} +108 -215
- package/dist/chunk-PRAOJIKH.js.map +1 -0
- package/dist/{chunk-SFNARMV4.js → chunk-RSQGFSCA.js} +8 -8
- package/dist/{chunk-DMJLZWAR.js → chunk-V5RPCSON.js} +25 -10
- package/dist/{chunk-DMJLZWAR.js.map → chunk-V5RPCSON.js.map} +1 -1
- package/dist/{chunk-RYK3WVH4.js → chunk-XKO2GYOF.js} +1031 -814
- package/dist/chunk-XKO2GYOF.js.map +1 -0
- package/dist/chunk-XP4J622W.js +35 -0
- package/dist/chunk-XP4J622W.js.map +1 -0
- package/dist/{chunk-Q2B5FUSA.js → chunk-YJ7BPHUB.js} +7 -7
- package/dist/cli.js +41 -27
- package/dist/cli.js.map +1 -1
- package/dist/{list-TZWF7XUG.js → list-V6A7DKXF.js} +2 -2
- package/dist/{model-picker-G6EVIQP7.js → model-picker-IR7QMEWU.js} +8 -8
- package/dist/ollama-setup-EJY37RBS.js +31 -0
- package/dist/ollama-start-EBZJFMNR.js +72 -0
- package/dist/ollama-start-EBZJFMNR.js.map +1 -0
- package/dist/{print-HSFNJOYV.js → print-HXC5CFGD.js} +12 -10
- package/dist/{print-HSFNJOYV.js.map → print-HXC5CFGD.js.map} +1 -1
- package/dist/{session-MNF52NG4.js → session-2YQYN6VU.js} +18 -15
- package/dist/session-2YQYN6VU.js.map +1 -0
- package/dist/{start-MFBIM4KW.js → start-KMBA2W6F.js} +28 -19
- package/dist/start-KMBA2W6F.js.map +1 -0
- package/package.json +2 -1
- package/dist/chat-server-NKLX3WTV.js.map +0 -1
- package/dist/chunk-4C3ZA5OG.js.map +0 -1
- package/dist/chunk-5XMZIGYS.js.map +0 -1
- package/dist/chunk-C2RB5YRZ.js.map +0 -1
- package/dist/chunk-HWL2XISD.js.map +0 -1
- package/dist/chunk-P6HRCAYP.js.map +0 -1
- package/dist/chunk-RYK3WVH4.js.map +0 -1
- package/dist/chunk-UACCTB6B.js.map +0 -1
- package/dist/ollama-2BG63S2L.js +0 -72
- package/dist/ollama-2BG63S2L.js.map +0 -1
- package/dist/start-MFBIM4KW.js.map +0 -1
- /package/dist/{chat-context-SP5XSAF7.js.map → chat-context-P4ZON7M4.js.map} +0 -0
- /package/dist/{chat-settings-K5643AXQ.js.map → chat-settings-4XUKDH6H.js.map} +0 -0
- /package/dist/{chunk-MHH66U5Y.js.map → chunk-MC4NBIIA.js.map} +0 -0
- /package/dist/{chunk-SFNARMV4.js.map → chunk-RSQGFSCA.js.map} +0 -0
- /package/dist/{chunk-Q2B5FUSA.js.map → chunk-YJ7BPHUB.js.map} +0 -0
- /package/dist/{list-TZWF7XUG.js.map → list-V6A7DKXF.js.map} +0 -0
- /package/dist/{model-picker-G6EVIQP7.js.map → model-picker-IR7QMEWU.js.map} +0 -0
- /package/dist/{session-MNF52NG4.js.map → ollama-setup-EJY37RBS.js.map} +0 -0
package/README.md
CHANGED
|
@@ -121,14 +121,27 @@ Optional: an advisory **fast judge** (Nimble on Ollama, usually on your Mac over
|
|
|
121
121
|
|
|
122
122
|
## Free and local with Ollama
|
|
123
123
|
|
|
124
|
+
If Ollama is running, `omnexx` (or `omnexx --ollama`, or the VS Code panel) just works. With no
|
|
125
|
+
provider set up, it:
|
|
126
|
+
|
|
127
|
+
- finds Ollama on `localhost:11434` (or `OLLAMA_HOST`) and lists the models you've pulled;
|
|
128
|
+
- keeps only models that can call tools (`/api/show` capabilities), skips `:cloud` models, and
|
|
129
|
+
ranks coding models first (qwen3-coder, devstral, gpt-oss, qwen3.x, qwen2.5-coder, ...), then
|
|
130
|
+
bigger, then longer context;
|
|
131
|
+
- makes a copy with a usable context window (`omnexx-<model>`, `num_ctx` 32k, or 16k under 16 GB
|
|
132
|
+
of RAM, never more than the model supports), since Ollama's default window is too small;
|
|
133
|
+
- saves it as the chat, planner, worker and cheap model, and says so in one line:
|
|
134
|
+
`using Ollama's qwen3-coder:30b (local, free, tools, 32k context) for chat, planning and work`.
|
|
135
|
+
|
|
136
|
+
No usable model yet? It suggests one for your machine (`ollama pull qwen3-coder`, or
|
|
137
|
+
`qwen2.5-coder:7b` under 32 GB) and offers to pull it: `y` in the terminal, **Pull it now** in
|
|
138
|
+
VS Code. Ollama not running? It says how to install (https://ollama.com/download) or start it.
|
|
139
|
+
|
|
124
140
|
```bash
|
|
125
|
-
|
|
126
|
-
npx omnexx --ollama # finds Ollama on localhost:11434, picks a coding model, opens the chat
|
|
141
|
+
npx omnexx --ollama # set up as above, then open the chat
|
|
127
142
|
npx omnexx --ollama llama3.3 # or name the model
|
|
128
143
|
```
|
|
129
144
|
|
|
130
|
-
No key and no config: with no provider set up, omnexx also connects a running Ollama by itself.
|
|
131
|
-
|
|
132
145
|
## From the plain terminal
|
|
133
146
|
|
|
134
147
|
```bash
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listRunIds,
|
|
5
5
|
repoMemoryFile,
|
|
6
6
|
repoRoot
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GBFAEDOD.js";
|
|
8
8
|
import {
|
|
9
9
|
SECTION_IDS,
|
|
10
10
|
SECTION_INFO,
|
|
@@ -13,15 +13,15 @@ import {
|
|
|
13
13
|
loadConfig,
|
|
14
14
|
readSectionModes,
|
|
15
15
|
sectionsFile
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-27GOEUTN.js";
|
|
18
|
-
import {
|
|
19
|
-
UsageError
|
|
20
|
-
} from "./chunk-7PNGHZYH.js";
|
|
16
|
+
} from "./chunk-V5RPCSON.js";
|
|
21
17
|
import "./chunk-FR5DUUJ4.js";
|
|
22
18
|
import {
|
|
23
19
|
resolvePaths
|
|
24
20
|
} from "./chunk-Q3MDYD6K.js";
|
|
21
|
+
import "./chunk-27GOEUTN.js";
|
|
22
|
+
import {
|
|
23
|
+
UsageError
|
|
24
|
+
} from "./chunk-7PNGHZYH.js";
|
|
25
25
|
import "./chunk-2H7UOFLK.js";
|
|
26
26
|
|
|
27
27
|
// src/cli/chat-context.ts
|
|
@@ -118,4 +118,4 @@ export {
|
|
|
118
118
|
contextFiles,
|
|
119
119
|
setSectionMode
|
|
120
120
|
};
|
|
121
|
-
//# sourceMappingURL=chat-context-
|
|
121
|
+
//# sourceMappingURL=chat-context-P4ZON7M4.js.map
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
println
|
|
4
4
|
} from "./chunk-7PC4SSYS.js";
|
|
5
|
-
import {
|
|
6
|
-
describeError
|
|
7
|
-
} from "./chunk-7PNGHZYH.js";
|
|
8
5
|
import {
|
|
9
6
|
resolvePaths
|
|
10
7
|
} from "./chunk-Q3MDYD6K.js";
|
|
8
|
+
import {
|
|
9
|
+
describeError
|
|
10
|
+
} from "./chunk-7PNGHZYH.js";
|
|
11
11
|
import "./chunk-2H7UOFLK.js";
|
|
12
12
|
|
|
13
13
|
// src/cli/chat-server.ts
|
|
@@ -39,7 +39,7 @@ function rawText(c, key) {
|
|
|
39
39
|
return v;
|
|
40
40
|
}
|
|
41
41
|
async function serveChat(io, runCli, opts) {
|
|
42
|
-
const { Session } = await import("./session-
|
|
42
|
+
const { Session } = await import("./session-2YQYN6VU.js");
|
|
43
43
|
const session = new Session(io, runCli);
|
|
44
44
|
const write = (msg) => {
|
|
45
45
|
println(io.stdout, JSON.stringify(msg));
|
|
@@ -77,6 +77,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
77
77
|
live: session.live,
|
|
78
78
|
todos: session.todos,
|
|
79
79
|
pending: session.pending?.question ?? null,
|
|
80
|
+
pendingLabels: session.pending?.labels ?? null,
|
|
80
81
|
mode: session.mode,
|
|
81
82
|
busy: session.busy !== void 0 || session.chatBusy,
|
|
82
83
|
paused: session.chatPaused,
|
|
@@ -95,6 +96,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
95
96
|
run: session.runId ? { id: session.runId, alive: session.runAlive, ...session.info } : null,
|
|
96
97
|
helpers: session.helpers,
|
|
97
98
|
waiting: session.waiting,
|
|
99
|
+
estimate: session.estimate,
|
|
98
100
|
browser: session.browserFrame ? {
|
|
99
101
|
seq: session.browserFrame.seq,
|
|
100
102
|
url: session.browserFrame.url,
|
|
@@ -110,7 +112,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
110
112
|
};
|
|
111
113
|
session.onChange(schedule);
|
|
112
114
|
const sendModels = async () => {
|
|
113
|
-
const { loadModelChoices } = await import("./model-picker-
|
|
115
|
+
const { loadModelChoices } = await import("./model-picker-IR7QMEWU.js");
|
|
114
116
|
const { items, unreachable } = await loadModelChoices(io);
|
|
115
117
|
write({
|
|
116
118
|
type: "models",
|
|
@@ -120,15 +122,15 @@ async function serveChat(io, runCli, opts) {
|
|
|
120
122
|
});
|
|
121
123
|
};
|
|
122
124
|
const sendSettings = async () => {
|
|
123
|
-
const { providerSettings } = await import("./chat-settings-
|
|
125
|
+
const { providerSettings } = await import("./chat-settings-4XUKDH6H.js");
|
|
124
126
|
write({ type: "settings", ...await providerSettings(io) });
|
|
125
127
|
};
|
|
126
128
|
const sendBrowser = async () => {
|
|
127
|
-
const { browserSettings } = await import("./chat-settings-
|
|
129
|
+
const { browserSettings } = await import("./chat-settings-4XUKDH6H.js");
|
|
128
130
|
write({ type: "browser", ...await browserSettings(io) });
|
|
129
131
|
};
|
|
130
132
|
const sendContextFiles = async () => {
|
|
131
|
-
const { contextFiles } = await import("./chat-context-
|
|
133
|
+
const { contextFiles } = await import("./chat-context-P4ZON7M4.js");
|
|
132
134
|
write({ type: "contextFiles", ...await contextFiles(io) });
|
|
133
135
|
};
|
|
134
136
|
const sendContext = () => {
|
|
@@ -207,7 +209,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
207
209
|
return typeof v === "string" ? v : void 0;
|
|
208
210
|
};
|
|
209
211
|
run(
|
|
210
|
-
import("./chat-settings-
|
|
212
|
+
import("./chat-settings-4XUKDH6H.js").then(async ({ addProvider }) => {
|
|
211
213
|
await providersChanged(
|
|
212
214
|
await addProvider(io, {
|
|
213
215
|
provider: str("provider"),
|
|
@@ -221,7 +223,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
221
223
|
}
|
|
222
224
|
case "testProvider":
|
|
223
225
|
run(
|
|
224
|
-
import("./chat-settings-
|
|
226
|
+
import("./chat-settings-4XUKDH6H.js").then(async ({ testProvider }) => {
|
|
225
227
|
write({ type: "providerTest", ...await testProvider(io, text(c, "name")) });
|
|
226
228
|
})
|
|
227
229
|
);
|
|
@@ -231,7 +233,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
231
233
|
return;
|
|
232
234
|
case "setSectionMode":
|
|
233
235
|
run(
|
|
234
|
-
import("./chat-context-
|
|
236
|
+
import("./chat-context-P4ZON7M4.js").then(async ({ setSectionMode }) => {
|
|
235
237
|
await setSectionMode(io, text(c, "id"), text(c, "mode"));
|
|
236
238
|
await sendContextFiles();
|
|
237
239
|
})
|
|
@@ -275,7 +277,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
275
277
|
return;
|
|
276
278
|
case "setBrowser":
|
|
277
279
|
run(
|
|
278
|
-
import("./chat-settings-
|
|
280
|
+
import("./chat-settings-4XUKDH6H.js").then(async ({ setBrowserSettings }) => {
|
|
279
281
|
await setBrowserSettings(io, c);
|
|
280
282
|
session.push("system", "browser settings saved; new runs use them");
|
|
281
283
|
await sendBrowser();
|
|
@@ -296,7 +298,7 @@ async function serveChat(io, runCli, opts) {
|
|
|
296
298
|
return;
|
|
297
299
|
case "removeProvider":
|
|
298
300
|
run(
|
|
299
|
-
import("./chat-settings-
|
|
301
|
+
import("./chat-settings-4XUKDH6H.js").then(async ({ removeProvider }) => {
|
|
300
302
|
await providersChanged(await removeProvider(io, text(c, "name")));
|
|
301
303
|
})
|
|
302
304
|
);
|
|
@@ -341,4 +343,4 @@ async function serveChat(io, runCli, opts) {
|
|
|
341
343
|
export {
|
|
342
344
|
serveChat
|
|
343
345
|
};
|
|
344
|
-
//# sourceMappingURL=chat-server-
|
|
346
|
+
//# sourceMappingURL=chat-server-FMF26CBV.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} · contextList ·\n * contextUpdate {id, text} · contextDelete {id} · contextReset · chats · resumeChat {id} · browser ·\n * setBrowser {engine, profile?, sessionName?, headless}.\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} · contextItems {items, busy} · chats {chats} · browser {engine, profile, sessionName, headless} ·\n * 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 /** Button names when the question is an offer (Pull it now / Not now) rather than a guard. */\n pendingLabels: { yes: string; no: 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 /** A model request in flight: when it went out and how long it usually takes (null: unknown). */\n waiting: { startedAt: number; estimateMs: number | null } | null;\n /** \"est. ~3 min, ~40k tokens, ~$0.02\" before work, \"~2 min left\" during it, or null. */\n estimate: string | null;\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\n/** A string that may be empty (an edit can clear a block's text). */\nfunction rawText(c: Command, key: string): string {\n const v = c[key];\n if (typeof v !== 'string') 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 pendingLabels: session.pending?.labels ?? 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 waiting: session.waiting,\n estimate: session.estimate,\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 sendBrowser = async (): Promise<void> => {\n const { browserSettings } = await import('./chat-settings.js');\n write({ type: 'browser', ...(await browserSettings(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 /** The context inspector's items: what the next request sends, with token counts. */\n const sendContext = (): void => {\n write({ type: 'contextItems', items: session.contextItems(), busy: session.chatBusy });\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 'chats':\n run(\n session.savedChats().then((chats) => {\n write({ type: 'chats', chats });\n }),\n );\n return;\n case 'resumeChat':\n run(\n (async () => {\n // Mark the panel's start first, so a reload shows only the reopened chat.\n clearedAt = session.entries.at(-1)?.id ?? clearedAt;\n sentUpTo = clearedAt;\n await session.resumeChat(text(c, 'id'));\n write({ type: 'ready', version: opts.version });\n emit();\n })(),\n );\n return;\n case 'contextList':\n sendContext();\n return;\n case 'contextUpdate':\n session.changeContext({ op: 'edit', id: text(c, 'id'), text: rawText(c, 'text') });\n sendContext();\n return;\n case 'contextDelete':\n session.changeContext({ op: 'delete', id: text(c, 'id') });\n sendContext();\n return;\n case 'contextReset':\n session.changeContext({ op: 'reset' });\n sendContext();\n return;\n case 'browser':\n run(sendBrowser());\n return;\n case 'setBrowser':\n run(\n import('./chat-settings.js').then(async ({ setBrowserSettings }) => {\n await setBrowserSettings(io, c);\n session.push('system', 'browser settings saved; new runs use them');\n await sendBrowser();\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":[]}
|
|
@@ -5,30 +5,30 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
connect,
|
|
7
7
|
describeConnect
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RSQGFSCA.js";
|
|
9
9
|
import {
|
|
10
10
|
PROVIDER_TEMPLATES,
|
|
11
11
|
removeEndpointBlock
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MC4NBIIA.js";
|
|
13
13
|
import {
|
|
14
14
|
clearKey,
|
|
15
15
|
findProviderKey,
|
|
16
16
|
maskKey
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-L2YBK4AY.js";
|
|
18
18
|
import {
|
|
19
19
|
loadConfig
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-V5RPCSON.js";
|
|
21
|
+
import "./chunk-FR5DUUJ4.js";
|
|
21
22
|
import "./chunk-7PC4SSYS.js";
|
|
23
|
+
import {
|
|
24
|
+
resolvePaths,
|
|
25
|
+
userConfigFile
|
|
26
|
+
} from "./chunk-Q3MDYD6K.js";
|
|
22
27
|
import "./chunk-27GOEUTN.js";
|
|
23
28
|
import {
|
|
24
29
|
UsageError
|
|
25
30
|
} from "./chunk-7PNGHZYH.js";
|
|
26
31
|
import "./chunk-UX4MF6V4.js";
|
|
27
|
-
import "./chunk-FR5DUUJ4.js";
|
|
28
|
-
import {
|
|
29
|
-
resolvePaths,
|
|
30
|
-
userConfigFile
|
|
31
|
-
} from "./chunk-Q3MDYD6K.js";
|
|
32
32
|
import "./chunk-2H7UOFLK.js";
|
|
33
33
|
|
|
34
34
|
// src/cli/chat-settings.ts
|
|
@@ -228,4 +228,4 @@ export {
|
|
|
228
228
|
setBrowserSettings,
|
|
229
229
|
testProvider
|
|
230
230
|
};
|
|
231
|
-
//# sourceMappingURL=chat-settings-
|
|
231
|
+
//# sourceMappingURL=chat-settings-4XUKDH6H.js.map
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveModelLenient
|
|
4
|
+
} from "./chunk-XP4J622W.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveRunDeps
|
|
7
|
+
} from "./chunk-FSA52KQB.js";
|
|
8
|
+
import {
|
|
9
|
+
connect,
|
|
10
|
+
describeConnect
|
|
11
|
+
} from "./chunk-RSQGFSCA.js";
|
|
12
|
+
import {
|
|
13
|
+
findProviderKey
|
|
14
|
+
} from "./chunk-L2YBK4AY.js";
|
|
15
|
+
import {
|
|
16
|
+
loadConfig
|
|
17
|
+
} from "./chunk-V5RPCSON.js";
|
|
18
|
+
import {
|
|
19
|
+
resolvePaths
|
|
20
|
+
} from "./chunk-Q3MDYD6K.js";
|
|
21
|
+
import {
|
|
22
|
+
describeError
|
|
23
|
+
} from "./chunk-7PNGHZYH.js";
|
|
24
|
+
import {
|
|
25
|
+
discoverModels
|
|
26
|
+
} from "./chunk-UX4MF6V4.js";
|
|
27
|
+
|
|
28
|
+
// src/tui/chat.ts
|
|
29
|
+
var SYSTEM = `You are omnexx's setup assistant, talking to the user in their terminal.
|
|
30
|
+
Your job: help them connect model providers and custom OpenAI-compatible endpoints.
|
|
31
|
+
Use the tools; never invent results. Keys the user pastes reach you as placeholders like
|
|
32
|
+
<key-1>: pass the placeholder as the key argument and omnexx swaps in the real key.
|
|
33
|
+
Never ask the user to paste a key into anything but this chat. Be brief: plain text, no
|
|
34
|
+
markdown headings. When a provider is connected, tell them the model ref to use.`;
|
|
35
|
+
var TOOLS = [
|
|
36
|
+
{
|
|
37
|
+
name: "list_providers",
|
|
38
|
+
description: "Configured providers, their base URLs and whether a key is set.",
|
|
39
|
+
inputSchema: { type: "object", properties: {} }
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "connect_provider",
|
|
43
|
+
description: "Add or update a provider. target is a known name (openai, openrouter, groq, deepseek, together, fireworks, mistral, gemini, xai, ollama, lmstudio, vllm, litellm, anthropic) or a base URL of any OpenAI-compatible endpoint. Lists its models to prove it works.",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
target: { type: "string" },
|
|
48
|
+
key: { type: "string", description: "API key or a <key-N> placeholder" },
|
|
49
|
+
name: { type: "string", description: "name for a URL endpoint (optional)" }
|
|
50
|
+
},
|
|
51
|
+
required: ["target"]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "list_models",
|
|
56
|
+
description: "Models a configured provider serves.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: { provider: { type: "string" } },
|
|
60
|
+
required: ["provider"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
var KEYISH = /\b(sk-ant-|sk-or-|sk-|gsk_|xai-|AIza|fw_)[A-Za-z0-9_\-.]{16,}/g;
|
|
65
|
+
var Chat = class _Chat {
|
|
66
|
+
constructor(io, ref, provider, route, model) {
|
|
67
|
+
this.io = io;
|
|
68
|
+
this.ref = ref;
|
|
69
|
+
this.provider = provider;
|
|
70
|
+
this.route = route;
|
|
71
|
+
this.model = model;
|
|
72
|
+
}
|
|
73
|
+
io;
|
|
74
|
+
ref;
|
|
75
|
+
provider;
|
|
76
|
+
route;
|
|
77
|
+
model;
|
|
78
|
+
messages = [];
|
|
79
|
+
keys = [];
|
|
80
|
+
static async open(io, ref) {
|
|
81
|
+
const { config, deps } = await resolveRunDeps(io, io.cwd, {
|
|
82
|
+
models: { planner: ref, worker: ref, cheap: ref }
|
|
83
|
+
});
|
|
84
|
+
const m = resolveModelLenient(ref, config);
|
|
85
|
+
return new _Chat(io, ref, deps.provider, m.provider, m.id);
|
|
86
|
+
}
|
|
87
|
+
/** Replace pasted keys with placeholders; the real values stay here. */
|
|
88
|
+
redact(text) {
|
|
89
|
+
return text.replace(KEYISH, (k) => {
|
|
90
|
+
let i = this.keys.indexOf(k);
|
|
91
|
+
if (i === -1) i = this.keys.push(k) - 1;
|
|
92
|
+
return `<key-${i + 1}>`;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
unredact(text) {
|
|
96
|
+
return text?.replace(/<key-(\d+)>/g, (m, n) => this.keys[Number(n) - 1] ?? m);
|
|
97
|
+
}
|
|
98
|
+
/** One user turn: loops through tool calls until the model answers. `say` gets each line. */
|
|
99
|
+
async send(text, say, maxSteps = 8) {
|
|
100
|
+
this.messages.push({ role: "user", content: [{ type: "text", text: this.redact(text) }] });
|
|
101
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
102
|
+
const res = await this.provider.complete({
|
|
103
|
+
model: this.model,
|
|
104
|
+
route: this.route,
|
|
105
|
+
system: [{ text: SYSTEM }],
|
|
106
|
+
tools: TOOLS,
|
|
107
|
+
messages: this.messages,
|
|
108
|
+
maxTokens: 2048,
|
|
109
|
+
messageBreakpoints: []
|
|
110
|
+
});
|
|
111
|
+
this.messages.push({ role: "assistant", content: res.content });
|
|
112
|
+
const said = res.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
|
|
113
|
+
if (said) say(said);
|
|
114
|
+
const calls = res.content.filter(
|
|
115
|
+
(b) => b.type === "tool_use"
|
|
116
|
+
);
|
|
117
|
+
if (!calls.length) return;
|
|
118
|
+
const results = [];
|
|
119
|
+
for (const c of calls) {
|
|
120
|
+
say(`\xB7 ${c.name}`);
|
|
121
|
+
try {
|
|
122
|
+
results.push({
|
|
123
|
+
type: "tool_result",
|
|
124
|
+
toolUseId: c.id,
|
|
125
|
+
content: await this.tool(c.name, c.input ?? {})
|
|
126
|
+
});
|
|
127
|
+
} catch (err) {
|
|
128
|
+
results.push({
|
|
129
|
+
type: "tool_result",
|
|
130
|
+
toolUseId: c.id,
|
|
131
|
+
content: describeError(err),
|
|
132
|
+
isError: true
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.messages.push({ role: "user", content: results });
|
|
137
|
+
}
|
|
138
|
+
say("(stopped after too many tool calls)");
|
|
139
|
+
}
|
|
140
|
+
async tool(name, input) {
|
|
141
|
+
const str = (k) => typeof input[k] === "string" ? input[k] : void 0;
|
|
142
|
+
switch (name) {
|
|
143
|
+
case "list_providers": {
|
|
144
|
+
const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });
|
|
145
|
+
const paths = resolvePaths(this.io.env);
|
|
146
|
+
const rows = [
|
|
147
|
+
`anthropic (built-in) key: ${await findProviderKey(paths, this.io.env, "anthropic") ? "yes" : "no"}`
|
|
148
|
+
];
|
|
149
|
+
for (const [n, ep] of Object.entries(config.providers.endpoints)) {
|
|
150
|
+
const key = await findProviderKey(paths, this.io.env, n, ep.api_key_env);
|
|
151
|
+
rows.push(`${n} ${ep.base_url} key: ${key ? "yes" : ep.free ? "not needed" : "no"}`);
|
|
152
|
+
}
|
|
153
|
+
return rows.join("\n");
|
|
154
|
+
}
|
|
155
|
+
case "connect_provider": {
|
|
156
|
+
const target = this.unredact(str("target")) ?? "";
|
|
157
|
+
const key = this.unredact(str("key"));
|
|
158
|
+
const nm = str("name");
|
|
159
|
+
const r = await connect(this.io, target, key, nm ? { name: nm } : {});
|
|
160
|
+
return this.redact(describeConnect(r));
|
|
161
|
+
}
|
|
162
|
+
case "list_models": {
|
|
163
|
+
const p = str("provider") ?? "";
|
|
164
|
+
const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });
|
|
165
|
+
const ep = config.providers.endpoints[p];
|
|
166
|
+
if (!ep) return `unknown provider "${p}"`;
|
|
167
|
+
const apiKey = (await findProviderKey(resolvePaths(this.io.env), this.io.env, p, ep.api_key_env))?.key;
|
|
168
|
+
const models = await discoverModels(
|
|
169
|
+
{ baseUrl: ep.base_url, ...apiKey ? { apiKey } : {} },
|
|
170
|
+
this.io.fetch ? { fetch: this.io.fetch } : {}
|
|
171
|
+
);
|
|
172
|
+
return models.length ? models.map((m) => m.id).join("\n") : "no models listed";
|
|
173
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
return `unknown tool ${name}`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
async function defaultChatRef(io) {
|
|
180
|
+
const paths = resolvePaths(io.env);
|
|
181
|
+
if (await findProviderKey(paths, io.env, "anthropic")) return "anthropic:sonnet";
|
|
182
|
+
const { config } = await loadConfig({ cwd: io.cwd, env: io.env });
|
|
183
|
+
for (const [n, ep] of Object.entries(config.providers.endpoints)) {
|
|
184
|
+
const apiKey = (await findProviderKey(paths, io.env, n, ep.api_key_env))?.key;
|
|
185
|
+
if (!apiKey && !ep.free) continue;
|
|
186
|
+
const models = await discoverModels(
|
|
187
|
+
{ baseUrl: ep.base_url, ...apiKey ? { apiKey } : {} },
|
|
188
|
+
io.fetch ? { fetch: io.fetch } : {}
|
|
189
|
+
);
|
|
190
|
+
if (models[0]) return `${n}:${models[0].id}`;
|
|
191
|
+
}
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
async function hasProvider(io) {
|
|
195
|
+
const paths = resolvePaths(io.env);
|
|
196
|
+
if (await findProviderKey(paths, io.env, "anthropic")) return true;
|
|
197
|
+
const { config } = await loadConfig({ cwd: io.cwd, env: io.env });
|
|
198
|
+
for (const [n, ep] of Object.entries(config.providers.endpoints)) {
|
|
199
|
+
if (ep.free || await findProviderKey(paths, io.env, n, ep.api_key_env)) return true;
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export {
|
|
205
|
+
Chat,
|
|
206
|
+
defaultChatRef,
|
|
207
|
+
hasProvider
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=chunk-23MT7K6X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui/chat.ts"],"sourcesContent":["import { findProviderKey } from '../auth/keys.js';\nimport { connect, describeConnect } from '../cli/connect.js';\nimport type { CliIO } from '../cli/io.js';\nimport { resolveRunDeps } from '../cli/run-deps.js';\nimport { loadConfig } from '../config/load.js';\nimport { resolvePaths } from '../core/paths.js';\nimport { describeError } from '../errors.js';\nimport { discoverModels } from '../providers/discovery.js';\nimport { resolveModelLenient } from '../providers/profiles.js';\nimport type { ContentBlock, Message, Provider, ToolSpec } from '../providers/types.js';\n\nconst SYSTEM = `You are omnexx's setup assistant, talking to the user in their terminal.\nYour job: help them connect model providers and custom OpenAI-compatible endpoints.\nUse the tools; never invent results. Keys the user pastes reach you as placeholders like\n<key-1>: pass the placeholder as the key argument and omnexx swaps in the real key.\nNever ask the user to paste a key into anything but this chat. Be brief: plain text, no\nmarkdown headings. When a provider is connected, tell them the model ref to use.`;\n\nconst TOOLS: ToolSpec[] = [\n {\n name: 'list_providers',\n description: 'Configured providers, their base URLs and whether a key is set.',\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'connect_provider',\n description:\n 'Add or update a provider. target is a known name (openai, openrouter, groq, deepseek, ' +\n 'together, fireworks, mistral, gemini, xai, ollama, lmstudio, vllm, litellm, anthropic) ' +\n 'or a base URL of any OpenAI-compatible endpoint. Lists its models to prove it works.',\n inputSchema: {\n type: 'object',\n properties: {\n target: { type: 'string' },\n key: { type: 'string', description: 'API key or a <key-N> placeholder' },\n name: { type: 'string', description: 'name for a URL endpoint (optional)' },\n },\n required: ['target'],\n },\n },\n {\n name: 'list_models',\n description: 'Models a configured provider serves.',\n inputSchema: {\n type: 'object',\n properties: { provider: { type: 'string' } },\n required: ['provider'],\n },\n },\n];\n\nconst KEYISH = /\\b(sk-ant-|sk-or-|sk-|gsk_|xai-|AIza|fw_)[A-Za-z0-9_\\-.]{16,}/g;\n\n/**\n * A direct conversation with one model (`/chat openrouter:some-model`). The model can connect\n * further providers through tools; pasted keys never reach it, only `<key-N>` placeholders.\n */\nexport class Chat {\n private messages: Message[] = [];\n private keys: string[] = [];\n\n private constructor(\n private readonly io: CliIO,\n readonly ref: string,\n private readonly provider: Provider,\n private readonly route: string,\n private readonly model: string,\n ) {}\n\n static async open(io: CliIO, ref: string): Promise<Chat> {\n const { config, deps } = await resolveRunDeps(io, io.cwd, {\n models: { planner: ref, worker: ref, cheap: ref },\n });\n const m = resolveModelLenient(ref, config);\n return new Chat(io, ref, deps.provider, m.provider, m.id);\n }\n\n /** Replace pasted keys with placeholders; the real values stay here. */\n redact(text: string): string {\n return text.replace(KEYISH, (k) => {\n let i = this.keys.indexOf(k);\n if (i === -1) i = this.keys.push(k) - 1;\n return `<key-${i + 1}>`;\n });\n }\n\n private unredact(text: string | undefined): string | undefined {\n return text?.replace(/<key-(\\d+)>/g, (m, n: string) => this.keys[Number(n) - 1] ?? m);\n }\n\n /** One user turn: loops through tool calls until the model answers. `say` gets each line. */\n async send(text: string, say: (line: string) => void, maxSteps = 8): Promise<void> {\n this.messages.push({ role: 'user', content: [{ type: 'text', text: this.redact(text) }] });\n for (let step = 0; step < maxSteps; step++) {\n const res = await this.provider.complete({\n model: this.model,\n route: this.route,\n system: [{ text: SYSTEM }],\n tools: TOOLS,\n messages: this.messages,\n maxTokens: 2048,\n messageBreakpoints: [],\n });\n this.messages.push({ role: 'assistant', content: res.content });\n const said = res.content\n .filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')\n .map((b) => b.text)\n .join('')\n .trim();\n if (said) say(said);\n const calls = res.content.filter(\n (b): b is Extract<ContentBlock, { type: 'tool_use' }> => b.type === 'tool_use',\n );\n if (!calls.length) return;\n const results: ContentBlock[] = [];\n for (const c of calls) {\n say(`· ${c.name}`);\n try {\n results.push({\n type: 'tool_result',\n toolUseId: c.id,\n content: await this.tool(c.name, (c.input ?? {}) as Record<string, unknown>),\n });\n } catch (err) {\n results.push({\n type: 'tool_result',\n toolUseId: c.id,\n content: describeError(err),\n isError: true,\n });\n }\n }\n this.messages.push({ role: 'user', content: results });\n }\n say('(stopped after too many tool calls)');\n }\n\n private async tool(name: string, input: Record<string, unknown>): Promise<string> {\n const str = (k: string): string | undefined =>\n typeof input[k] === 'string' ? input[k] : undefined;\n switch (name) {\n case 'list_providers': {\n const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });\n const paths = resolvePaths(this.io.env);\n const rows = [\n `anthropic (built-in) key: ${(await findProviderKey(paths, this.io.env, 'anthropic')) ? 'yes' : 'no'}`,\n ];\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n const key = await findProviderKey(paths, this.io.env, n, ep.api_key_env);\n rows.push(`${n} ${ep.base_url} key: ${key ? 'yes' : ep.free ? 'not needed' : 'no'}`);\n }\n return rows.join('\\n');\n }\n case 'connect_provider': {\n const target = this.unredact(str('target')) ?? '';\n const key = this.unredact(str('key'));\n const nm = str('name');\n // A model that passes the key as the target still works.\n const r = await connect(this.io, target, key, nm ? { name: nm } : {});\n return this.redact(describeConnect(r));\n }\n case 'list_models': {\n const p = str('provider') ?? '';\n const { config } = await loadConfig({ cwd: this.io.cwd, env: this.io.env });\n const ep = config.providers.endpoints[p];\n if (!ep) return `unknown provider \"${p}\"`;\n const apiKey = (\n await findProviderKey(resolvePaths(this.io.env), this.io.env, p, ep.api_key_env)\n )?.key;\n const models = await discoverModels(\n { baseUrl: ep.base_url, ...(apiKey ? { apiKey } : {}) },\n this.io.fetch ? { fetch: this.io.fetch } : {},\n );\n return models.length ? models.map((m) => m.id).join('\\n') : 'no models listed';\n }\n default:\n return `unknown tool ${name}`;\n }\n }\n}\n\n/** The model to chat with when `/chat` has no argument: Anthropic if keyed, else any endpoint. */\nexport async function defaultChatRef(io: CliIO): Promise<string | undefined> {\n const paths = resolvePaths(io.env);\n if (await findProviderKey(paths, io.env, 'anthropic')) return 'anthropic:sonnet';\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n const apiKey = (await findProviderKey(paths, io.env, n, ep.api_key_env))?.key;\n if (!apiKey && !ep.free) continue;\n const models = await discoverModels(\n { baseUrl: ep.base_url, ...(apiKey ? { apiKey } : {}) },\n io.fetch ? { fetch: io.fetch } : {},\n );\n if (models[0]) return `${n}:${models[0].id}`;\n }\n return undefined;\n}\n\n/** Whether any provider can be called at all (no network): a key, or a free endpoint. */\nexport async function hasProvider(io: CliIO): Promise<boolean> {\n const paths = resolvePaths(io.env);\n if (await findProviderKey(paths, io.env, 'anthropic')) return true;\n const { config } = await loadConfig({ cwd: io.cwd, env: io.env });\n for (const [n, ep] of Object.entries(config.providers.endpoints)) {\n if (ep.free || (await findProviderKey(paths, io.env, n, ep.api_key_env))) return true;\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAOf,IAAM,QAAoB;AAAA,EACxB;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE;AAAA,EAChD;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IAGF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,QAAQ,EAAE,MAAM,SAAS;AAAA,QACzB,KAAK,EAAE,MAAM,UAAU,aAAa,mCAAmC;AAAA,QACvE,MAAM,EAAE,MAAM,UAAU,aAAa,qCAAqC;AAAA,MAC5E;AAAA,MACA,UAAU,CAAC,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,EAAE;AAAA,MAC3C,UAAU,CAAC,UAAU;AAAA,IACvB;AAAA,EACF;AACF;AAEA,IAAM,SAAS;AAMR,IAAM,OAAN,MAAM,MAAK;AAAA,EAIR,YACW,IACR,KACQ,UACA,OACA,OACjB;AALiB;AACR;AACQ;AACA;AACA;AAAA,EAChB;AAAA,EALgB;AAAA,EACR;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EARX,WAAsB,CAAC;AAAA,EACvB,OAAiB,CAAC;AAAA,EAU1B,aAAa,KAAK,IAAW,KAA4B;AACvD,UAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,eAAe,IAAI,GAAG,KAAK;AAAA,MACxD,QAAQ,EAAE,SAAS,KAAK,QAAQ,KAAK,OAAO,IAAI;AAAA,IAClD,CAAC;AACD,UAAM,IAAI,oBAAoB,KAAK,MAAM;AACzC,WAAO,IAAI,MAAK,IAAI,KAAK,KAAK,UAAU,EAAE,UAAU,EAAE,EAAE;AAAA,EAC1D;AAAA;AAAA,EAGA,OAAO,MAAsB;AAC3B,WAAO,KAAK,QAAQ,QAAQ,CAAC,MAAM;AACjC,UAAI,IAAI,KAAK,KAAK,QAAQ,CAAC;AAC3B,UAAI,MAAM,GAAI,KAAI,KAAK,KAAK,KAAK,CAAC,IAAI;AACtC,aAAO,QAAQ,IAAI,CAAC;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEQ,SAAS,MAA8C;AAC7D,WAAO,MAAM,QAAQ,gBAAgB,CAAC,GAAG,MAAc,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;AAAA,EACtF;AAAA;AAAA,EAGA,MAAM,KAAK,MAAc,KAA6B,WAAW,GAAkB;AACjF,SAAK,SAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;AACzF,aAAS,OAAO,GAAG,OAAO,UAAU,QAAQ;AAC1C,YAAM,MAAM,MAAM,KAAK,SAAS,SAAS;AAAA,QACvC,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK;AAAA,QACZ,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,QACzB,OAAO;AAAA,QACP,UAAU,KAAK;AAAA,QACf,WAAW;AAAA,QACX,oBAAoB,CAAC;AAAA,MACvB,CAAC;AACD,WAAK,SAAS,KAAK,EAAE,MAAM,aAAa,SAAS,IAAI,QAAQ,CAAC;AAC9D,YAAM,OAAO,IAAI,QACd,OAAO,CAAC,MAAoD,EAAE,SAAS,MAAM,EAC7E,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE,EACP,KAAK;AACR,UAAI,KAAM,KAAI,IAAI;AAClB,YAAM,QAAQ,IAAI,QAAQ;AAAA,QACxB,CAAC,MAAwD,EAAE,SAAS;AAAA,MACtE;AACA,UAAI,CAAC,MAAM,OAAQ;AACnB,YAAM,UAA0B,CAAC;AACjC,iBAAW,KAAK,OAAO;AACrB,YAAI,QAAK,EAAE,IAAI,EAAE;AACjB,YAAI;AACF,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,WAAW,EAAE;AAAA,YACb,SAAS,MAAM,KAAK,KAAK,EAAE,MAAO,EAAE,SAAS,CAAC,CAA6B;AAAA,UAC7E,CAAC;AAAA,QACH,SAAS,KAAK;AACZ,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,WAAW,EAAE;AAAA,YACb,SAAS,cAAc,GAAG;AAAA,YAC1B,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAAA,MACF;AACA,WAAK,SAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAAA,IACvD;AACA,QAAI,qCAAqC;AAAA,EAC3C;AAAA,EAEA,MAAc,KAAK,MAAc,OAAiD;AAChF,UAAM,MAAM,CAAC,MACX,OAAO,MAAM,CAAC,MAAM,WAAW,MAAM,CAAC,IAAI;AAC5C,YAAQ,MAAM;AAAA,MACZ,KAAK,kBAAkB;AACrB,cAAM,EAAE,OAAO,IAAI,MAAM,WAAW,EAAE,KAAK,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG,IAAI,CAAC;AAC1E,cAAM,QAAQ,aAAa,KAAK,GAAG,GAAG;AACtC,cAAM,OAAO;AAAA,UACX,6BAA8B,MAAM,gBAAgB,OAAO,KAAK,GAAG,KAAK,WAAW,IAAK,QAAQ,IAAI;AAAA,QACtG;AACA,mBAAW,CAAC,GAAG,EAAE,KAAK,OAAO,QAAQ,OAAO,UAAU,SAAS,GAAG;AAChE,gBAAM,MAAM,MAAM,gBAAgB,OAAO,KAAK,GAAG,KAAK,GAAG,GAAG,WAAW;AACvE,eAAK,KAAK,GAAG,CAAC,IAAI,GAAG,QAAQ,SAAS,MAAM,QAAQ,GAAG,OAAO,eAAe,IAAI,EAAE;AAAA,QACrF;AACA,eAAO,KAAK,KAAK,IAAI;AAAA,MACvB;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,SAAS,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK;AAC/C,cAAM,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC;AACpC,cAAM,KAAK,IAAI,MAAM;AAErB,cAAM,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAK,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AACpE,eAAO,KAAK,OAAO,gBAAgB,CAAC,CAAC;AAAA,MACvC;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,IAAI,IAAI,UAAU,KAAK;AAC7B,cAAM,EAAE,OAAO,IAAI,MAAM,WAAW,EAAE,KAAK,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG,IAAI,CAAC;AAC1E,cAAM,KAAK,OAAO,UAAU,UAAU,CAAC;AACvC,YAAI,CAAC,GAAI,QAAO,qBAAqB,CAAC;AACtC,cAAM,UACJ,MAAM,gBAAgB,aAAa,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,WAAW,IAC9E;AACH,cAAM,SAAS,MAAM;AAAA,UACnB,EAAE,SAAS,GAAG,UAAU,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG;AAAA,UACtD,KAAK,GAAG,QAAQ,EAAE,OAAO,KAAK,GAAG,MAAM,IAAI,CAAC;AAAA,QAC9C;AACA,eAAO,OAAO,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,IAAI;AAAA,MAC9D;AAAA,MACA;AACE,eAAO,gBAAgB,IAAI;AAAA,IAC/B;AAAA,EACF;AACF;AAGA,eAAsB,eAAe,IAAwC;AAC3E,QAAM,QAAQ,aAAa,GAAG,GAAG;AACjC,MAAI,MAAM,gBAAgB,OAAO,GAAG,KAAK,WAAW,EAAG,QAAO;AAC9D,QAAM,EAAE,OAAO,IAAI,MAAM,WAAW,EAAE,KAAK,GAAG,KAAK,KAAK,GAAG,IAAI,CAAC;AAChE,aAAW,CAAC,GAAG,EAAE,KAAK,OAAO,QAAQ,OAAO,UAAU,SAAS,GAAG;AAChE,UAAM,UAAU,MAAM,gBAAgB,OAAO,GAAG,KAAK,GAAG,GAAG,WAAW,IAAI;AAC1E,QAAI,CAAC,UAAU,CAAC,GAAG,KAAM;AACzB,UAAM,SAAS,MAAM;AAAA,MACnB,EAAE,SAAS,GAAG,UAAU,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG;AAAA,MACtD,GAAG,QAAQ,EAAE,OAAO,GAAG,MAAM,IAAI,CAAC;AAAA,IACpC;AACA,QAAI,OAAO,CAAC,EAAG,QAAO,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,EAAE;AAAA,EAC5C;AACA,SAAO;AACT;AAGA,eAAsB,YAAY,IAA6B;AAC7D,QAAM,QAAQ,aAAa,GAAG,GAAG;AACjC,MAAI,MAAM,gBAAgB,OAAO,GAAG,KAAK,WAAW,EAAG,QAAO;AAC9D,QAAM,EAAE,OAAO,IAAI,MAAM,WAAW,EAAE,KAAK,GAAG,KAAK,KAAK,GAAG,IAAI,CAAC;AAChE,aAAW,CAAC,GAAG,EAAE,KAAK,OAAO,QAAQ,OAAO,UAAU,SAAS,GAAG;AAChE,QAAI,GAAG,QAAS,MAAM,gBAAgB,OAAO,GAAG,KAAK,GAAG,GAAG,WAAW,EAAI,QAAO;AAAA,EACnF;AACA,SAAO;AACT;","names":[]}
|