agentic-assistant 0.1.0 → 0.2.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/dist/cli.d.ts CHANGED
@@ -1,4 +1,29 @@
1
1
  #!/usr/bin/env node
2
- declare function runCli(argv: string[], out?: (line: string) => void, err?: (line: string) => void): number;
2
+ import { C as ChatConfig } from './chat-pBg4wRjQ.js';
3
+ import './loop-42giKLVa.js';
4
+ import './types-DGH8FS56.js';
3
5
 
4
- export { runCli };
6
+ declare class UsageError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ interface Parsed {
10
+ command: "chat" | "mcp" | "help" | "version";
11
+ config?: ChatConfig;
12
+ message?: string;
13
+ json: boolean;
14
+ }
15
+ declare function parseCli(argv: string[]): Parsed;
16
+ interface CliIo {
17
+ /** Final answer text and JSON events go here. */
18
+ out(text: string): void;
19
+ /** Progress, tool lines, and the summary go here. */
20
+ err(line: string): void;
21
+ env: Record<string, string | undefined>;
22
+ readFile(path: string): string;
23
+ readStdin(): Promise<string>;
24
+ isTTY: boolean;
25
+ ask(question: string): Promise<string>;
26
+ }
27
+ declare function runCli(argv: string[], io?: CliIo): Promise<number>;
28
+
29
+ export { type CliIo, type Parsed, UsageError, parseCli, runCli };
package/dist/cli.js CHANGED
@@ -1,30 +1,306 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- VERSION
4
- } from "./chunk-4QE7E5UQ.js";
3
+ ConfigError,
4
+ buildSetup,
5
+ readTextFile,
6
+ runChat
7
+ } from "./chunk-BDXAUNMR.js";
8
+ import "./chunk-HYT732TN.js";
9
+ import {
10
+ TOOL_RISKS,
11
+ VERSION,
12
+ printable,
13
+ provenanceLabel
14
+ } from "./chunk-T4ZMDOB4.js";
5
15
 
6
16
  // src/cli.ts
7
17
  import { realpathSync } from "fs";
18
+ import { createInterface } from "readline/promises";
8
19
  import { pathToFileURL } from "url";
9
- var HELP = [
10
- `agentic-assistant ${VERSION}`,
11
- "An AI assistant that acts inside your apps with the user's own permissions.",
12
- "",
13
- "Usage: agentic-assistant [--help] [--version]"
14
- ].join("\n");
15
- function runCli(argv, out = console.log, err = console.error) {
16
- const [first] = argv;
17
- if (first === void 0 || first === "--help" || first === "-h") {
18
- out(HELP);
20
+ import { parseArgs } from "util";
21
+ var UsageError = class extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "UsageError";
25
+ }
26
+ };
27
+ var HELP = `agentic-assistant ${VERSION}
28
+ An AI assistant that acts inside your apps with the user's own permissions.
29
+
30
+ Usage:
31
+ agentic-assistant chat [flags] [message] Send a message. Read stdin when there is no message.
32
+ agentic-assistant mcp [flags] Start an MCP server with one tool, assistant_chat.
33
+
34
+ Flags for chat and mcp:
35
+ --tools <target> An https MCP URL, or a command that starts an MCP server on stdio. Required.
36
+ --tools-header-env <h=E> Send header h with the value of environment variable E (http only). Repeat it.
37
+ --scope <scope> A scope the assistant may hold, like notes:read. Repeat it. Required.
38
+ --tool-scope <scope> The scope each tool needs. Required.
39
+ --tool-risk <risk> safe, risky, or irreversible, for each tool. Default risky.
40
+ --approve-call <json> Approve one exact call before the run: {"tool":"...","input":{...}}. Repeat it.
41
+ --approve <ask|deny> ask: question a person on the terminal (chat only). Default deny.
42
+ --provider <name> anthropic (default), openai-compatible, or scripted (for tests).
43
+ --model <id> Model id. Default for anthropic: claude-sonnet-5-5.
44
+ --fallback-model <id> A second model on the same provider. It answers once when --model refuses or fails.
45
+ --base-url <url> Endpoint. Required for openai-compatible. https, or localhost.
46
+ --use-default-endpoint Call api.anthropic.com, a US-hosted endpoint. Anthropic only.
47
+ --api-key-env <NAME> Read the API key from this environment variable. Keys never go in arguments.
48
+ --price-in <n> --price-out <n> US dollars per million tokens, for the cost cap.
49
+ --script <file> Turns for --provider scripted.
50
+ --system <text> Extra system text.
51
+ --user <id> The person the assistant acts for. Default cli-user.
52
+ --max-turns <n> --max-tokens <n> --max-cost <usd> --max-tool-calls <n> Run limits.
53
+ --json Print one JSON event per line on stdout (chat).
54
+
55
+ Other:
56
+ --help, -h Print this help.
57
+ --version, -V Print the version.
58
+
59
+ Exit codes: 0 the run ended normally, 1 it stopped for another reason or failed, 2 bad usage.
60
+ `;
61
+ var OPTIONS = {
62
+ tools: { type: "string" },
63
+ "tools-header-env": { type: "string", multiple: true },
64
+ scope: { type: "string", multiple: true },
65
+ "tool-scope": { type: "string" },
66
+ "tool-risk": { type: "string" },
67
+ "approve-call": { type: "string", multiple: true },
68
+ approve: { type: "string" },
69
+ provider: { type: "string" },
70
+ model: { type: "string" },
71
+ "fallback-model": { type: "string" },
72
+ "base-url": { type: "string" },
73
+ "use-default-endpoint": { type: "boolean" },
74
+ "api-key-env": { type: "string" },
75
+ "price-in": { type: "string" },
76
+ "price-out": { type: "string" },
77
+ script: { type: "string" },
78
+ system: { type: "string" },
79
+ user: { type: "string" },
80
+ "max-turns": { type: "string" },
81
+ "max-tokens": { type: "string" },
82
+ "max-cost": { type: "string" },
83
+ "max-tool-calls": { type: "string" },
84
+ json: { type: "boolean" },
85
+ message: { type: "string" },
86
+ help: { type: "boolean", short: "h" },
87
+ version: { type: "boolean", short: "V" }
88
+ };
89
+ function number(name, value, integer) {
90
+ if (value === void 0) return void 0;
91
+ const parsed = Number(value);
92
+ if (!Number.isFinite(parsed) || parsed <= 0 || integer && !Number.isInteger(parsed)) {
93
+ throw new UsageError(`${name} needs a positive ${integer ? "whole " : ""}number, got "${value}"`);
94
+ }
95
+ return parsed;
96
+ }
97
+ function parseCli(argv) {
98
+ let parsed;
99
+ try {
100
+ parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
101
+ } catch (error) {
102
+ throw new UsageError(error instanceof Error ? error.message : String(error));
103
+ }
104
+ const { values, positionals } = parsed;
105
+ if (values.version) return { command: "version", json: false };
106
+ const [command, ...rest] = positionals;
107
+ if (values.help || command === void 0) return { command: "help", json: false };
108
+ if (command !== "chat" && command !== "mcp") throw new UsageError(`unknown command "${command}"`);
109
+ if (!values.tools) throw new UsageError("--tools is required");
110
+ if (!values["tool-scope"]) throw new UsageError("--tool-scope is required");
111
+ const risk = values["tool-risk"] ?? "risky";
112
+ if (!TOOL_RISKS.includes(risk)) throw new UsageError(`--tool-risk must be one of ${TOOL_RISKS.join(", ")}`);
113
+ const provider = values.provider ?? "anthropic";
114
+ if (provider !== "anthropic" && provider !== "openai-compatible" && provider !== "scripted") {
115
+ throw new UsageError("--provider must be anthropic, openai-compatible, or scripted");
116
+ }
117
+ const approve = values.approve ?? "deny";
118
+ if (approve !== "ask" && approve !== "deny") throw new UsageError("--approve must be ask or deny");
119
+ if (command === "mcp" && approve === "ask") throw new UsageError("--approve ask works with chat only");
120
+ const preApproved = (values["approve-call"] ?? []).map((text) => {
121
+ try {
122
+ const call = JSON.parse(text);
123
+ if (typeof call.tool !== "string" || typeof call.input !== "object" || call.input === null || Array.isArray(call.input)) throw new Error("shape");
124
+ return { tool: call.tool, input: call.input };
125
+ } catch {
126
+ throw new UsageError(`--approve-call needs JSON like {"tool":"name","input":{}}, got ${text.slice(0, 80)}`);
127
+ }
128
+ });
129
+ if (values["fallback-model"] === "") throw new UsageError("--fallback-model needs a model id");
130
+ const priceIn = number("--price-in", values["price-in"], false);
131
+ const priceOut = number("--price-out", values["price-out"], false);
132
+ if (priceIn === void 0 !== (priceOut === void 0)) throw new UsageError("--price-in and --price-out go together");
133
+ const pricing = priceIn !== void 0 && priceOut !== void 0 ? { inputPerMTok: priceIn, outputPerMTok: priceOut } : void 0;
134
+ const limits = {
135
+ maxTurns: number("--max-turns", values["max-turns"], true),
136
+ maxTotalTokens: number("--max-tokens", values["max-tokens"], true),
137
+ maxCostUsd: number("--max-cost", values["max-cost"], false),
138
+ maxToolCallsPerTurn: number("--max-tool-calls", values["max-tool-calls"], true)
139
+ };
140
+ for (const key of Object.keys(limits)) if (limits[key] === void 0) delete limits[key];
141
+ const config = {
142
+ tools: values.tools,
143
+ toolHeaderEnv: values["tools-header-env"] ?? [],
144
+ scopes: values.scope ?? [],
145
+ toolScope: values["tool-scope"],
146
+ toolRisk: risk,
147
+ provider,
148
+ model: values.model,
149
+ fallbackModel: values["fallback-model"],
150
+ baseUrl: values["base-url"],
151
+ useDefaultEndpoint: values["use-default-endpoint"] ?? false,
152
+ apiKeyEnv: values["api-key-env"],
153
+ pricing,
154
+ script: values.script,
155
+ system: values.system,
156
+ user: values.user ?? "cli-user",
157
+ limits,
158
+ preApproved,
159
+ approve
160
+ };
161
+ return { command, config, message: values.message ?? (rest.length > 0 ? rest.join(" ") : void 0), json: values.json ?? false };
162
+ }
163
+ function defaultIo() {
164
+ return {
165
+ out: (text) => void process.stdout.write(text),
166
+ err: (line) => console.error(line),
167
+ env: process.env,
168
+ readFile: readTextFile,
169
+ readStdin: async () => {
170
+ const chunks = [];
171
+ let size = 0;
172
+ for await (const chunk of process.stdin) {
173
+ size += chunk.length;
174
+ if (size > MAX_STDIN_BYTES) throw new UsageError(`the message on stdin is over ${MAX_STDIN_BYTES} bytes`);
175
+ chunks.push(chunk);
176
+ }
177
+ return Buffer.concat(chunks).toString("utf8");
178
+ },
179
+ isTTY: Boolean(process.stdin.isTTY),
180
+ ask: async (question) => {
181
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
182
+ try {
183
+ return await rl.question(question);
184
+ } finally {
185
+ rl.close();
186
+ }
187
+ }
188
+ };
189
+ }
190
+ var oneLine = (value, max = 200) => {
191
+ const text = printable(typeof value === "string" ? value : JSON.stringify(value) ?? "null").replace(/\s+/g, " ");
192
+ const points = Array.from(text);
193
+ return points.length > max ? `${points.slice(0, max).join("")}...` : text;
194
+ };
195
+ var MAX_STDIN_BYTES = 1e6;
196
+ var MAX_SKIPPED_LINES = 20;
197
+ function render(event, io, state) {
198
+ const endText = () => {
199
+ if (state.inText) io.out("\n");
200
+ state.inText = false;
201
+ };
202
+ switch (event.type) {
203
+ case "text_delta":
204
+ if (!state.inText) io.out("Assistant (machine-made): ");
205
+ state.inText = true;
206
+ io.out(printable(event.text));
207
+ break;
208
+ case "turn_end":
209
+ endText();
210
+ if (event.answeredBy.fallback) {
211
+ io.err(`fallback model answered: ${oneLine(event.answeredBy.model, 100)} (first model failed: ${event.answeredBy.fallbackFor ?? "unknown"})`);
212
+ }
213
+ break;
214
+ case "tool_call":
215
+ endText();
216
+ io.err(`[machine-made] tool call: ${oneLine(event.name, 100)} ${oneLine(event.input)}`);
217
+ break;
218
+ case "approval_request":
219
+ endText();
220
+ io.err(`[machine-made] approval needed: ${oneLine(event.request.tool, 100)} (${event.request.risk}) ${oneLine(event.request.input)}`);
221
+ break;
222
+ case "approval_decision":
223
+ io.err(`approval: ${event.approved ? `approved by ${oneLine(event.decidedBy ?? "unknown", 100)}` : `not approved (${oneLine(event.reason ?? "no reason", 200)})`}`);
224
+ break;
225
+ case "tool_result":
226
+ io.err(`tool result (${event.isError ? "error" : "ok"}${event.denied ? `, ${event.denied}` : ""}): ${oneLine(event.content)}`);
227
+ break;
228
+ case "done":
229
+ endText();
230
+ io.err(`done: ${event.reason}. tokens in ${event.totals.inputTokens}, out ${event.totals.outputTokens}. cost $${event.totals.costUsd.toFixed(6)} (estimate)${event.error ? `. error: ${oneLine(event.error)}` : ""}`);
231
+ if (event.provenance !== void 0) io.err(oneLine(provenanceLabel(event.provenance), 300));
232
+ break;
233
+ default:
234
+ break;
235
+ }
236
+ }
237
+ async function runOnce(setup, messages, json, io) {
238
+ const state = { inText: false };
239
+ let last;
240
+ for await (const event of runChat(setup, messages)) {
241
+ if (json) io.out(`${JSON.stringify(event)}
242
+ `);
243
+ else render(event, io, state);
244
+ if (event.type === "done") last = event;
245
+ }
246
+ return { code: last?.reason === "end_turn" ? 0 : 1, transcript: last?.messages ?? messages };
247
+ }
248
+ async function runCli(argv, io = defaultIo()) {
249
+ let parsed;
250
+ try {
251
+ parsed = parseCli(argv);
252
+ } catch (error) {
253
+ io.err(error instanceof Error ? error.message : String(error));
254
+ io.err('Run "agentic-assistant --help" for usage.');
255
+ return 2;
256
+ }
257
+ if (parsed.command === "help") {
258
+ io.out(HELP);
19
259
  return 0;
20
260
  }
21
- if (first === "--version" || first === "-V") {
22
- out(VERSION);
261
+ if (parsed.command === "version") {
262
+ io.out(`${VERSION}
263
+ `);
23
264
  return 0;
24
265
  }
25
- err(`unknown command "${first}"`);
26
- err('Run "agentic-assistant --help" for usage.');
27
- return 2;
266
+ const config = parsed.config;
267
+ const chatIo = { env: io.env, readFile: io.readFile, ...config.approve === "ask" && io.isTTY ? { ask: io.ask } : {} };
268
+ let setup;
269
+ try {
270
+ setup = await buildSetup(config, chatIo);
271
+ for (const skip of setup.skipped.slice(0, MAX_SKIPPED_LINES)) io.err(`skipped tool ${oneLine(skip.name, 100)}: ${oneLine(skip.reason, 200)}`);
272
+ if (setup.skipped.length > MAX_SKIPPED_LINES) io.err(`skipped ${setup.skipped.length - MAX_SKIPPED_LINES} more tools`);
273
+ if (parsed.command === "mcp") {
274
+ const { startAssistantMcp } = await import("./mcp-server-X5VTHZVM.js");
275
+ await startAssistantMcp(setup);
276
+ return 0;
277
+ }
278
+ const text = parsed.message ?? (io.isTTY ? void 0 : (await io.readStdin()).trim());
279
+ let transcript = [];
280
+ if (text !== void 0 && text !== "") {
281
+ const { code: code2 } = await runOnce(setup, [{ role: "user", content: [{ type: "text", text }] }], parsed.json, io);
282
+ return code2;
283
+ }
284
+ if (!io.isTTY) throw new UsageError("give a message as an argument, with --message, or on stdin");
285
+ let code = 0;
286
+ for (; ; ) {
287
+ const line = (await io.ask("> ").catch(() => "exit")).trim();
288
+ if (line === "" || line === "exit") return code;
289
+ transcript = [...transcript, { role: "user", content: [{ type: "text", text: line }] }];
290
+ const result = await runOnce(setup, transcript, parsed.json, io);
291
+ transcript = result.transcript;
292
+ code = result.code;
293
+ }
294
+ } catch (error) {
295
+ if (error instanceof ConfigError || error instanceof UsageError) {
296
+ io.err(`${error.name}: ${oneLine(error.message, 500)}`);
297
+ return 2;
298
+ }
299
+ io.err(`${error instanceof Error ? error.name : "Error"}: ${oneLine(error instanceof Error ? error.message : String(error), 500)}`);
300
+ return 1;
301
+ } finally {
302
+ await Promise.race([setup?.close().catch(() => void 0), new Promise((resolve) => setTimeout(resolve, 5e3).unref())]);
303
+ }
28
304
  }
29
305
  function isMainModule() {
30
306
  const invoked = process.argv[1];
@@ -36,9 +312,16 @@ function isMainModule() {
36
312
  }
37
313
  }
38
314
  if (isMainModule()) {
39
- const code = runCli(process.argv.slice(2));
40
- if (code !== 0) process.exit(code);
315
+ runCli(process.argv.slice(2)).then(
316
+ (code) => process.exit(code),
317
+ (error) => {
318
+ console.error(error instanceof Error ? error.message : String(error));
319
+ process.exit(1);
320
+ }
321
+ );
41
322
  }
42
323
  export {
324
+ UsageError,
325
+ parseCli,
43
326
  runCli
44
327
  };
package/dist/index.d.ts CHANGED
@@ -1,70 +1,16 @@
1
- import { S as Scope, T as ToolRisk, a as ToolDefinition } from './loop-CDbbDwSs.js';
2
- export { A as ACTIONS, b as Action, c as Actor, d as ApprovalDecision, e as ApprovalGate, f as ApprovalRequest, g as AssistantEvent, h as AssistantPrincipal, D as DATA_NOTICE, i as DeniedReason, j as DoneReason, P as PrincipalError, k as PrincipalInput, Q as QueueApprovalGate, R as RunLimits, l as RunOptions, m as RunTotals, n as TOOL_RISKS, o as ToolContext, p as ToolRegistry, q as actorOf, r as assertPrincipal, s as canonicalJson, t as createPrincipal, u as defineTool, v as digestCall, w as hasScope, x as parseScope, y as runAssistant, z as scopeCovers } from './loop-CDbbDwSs.js';
1
+ export { A as ACTIONS, a as Action, b as Actor, c as ApprovalDecision, d as ApprovalGate, e as ApprovalRequest, f as Approver, g as ApproverKind, h as AssistantEvent, i as AssistantPrincipal, D as DATA_NOTICE, j as DeniedReason, k as DoneReason, P as PrincipalError, l as PrincipalInput, m as Provenance, n as ProvenanceInput, Q as QueueApprovalGate, R as RunLimits, o as RunOptions, p as RunTotals, S as Scope, T as TOOL_RISKS, q as TRAINED_ALGORITHMIC_MEDIA, r as ToolContext, s as ToolDefinition, t as ToolRegistry, u as ToolRisk, v as actorOf, w as assertPrincipal, x as canonicalJson, y as createPrincipal, z as createProvenance, B as defineTool, C as digestCall, E as hasScope, F as parseScope, G as provenanceLabel, H as provenanceMarker, I as runAssistant, J as scopeCovers } from './loop-42giKLVa.js';
2
+ import { S as Setup } from './chat-pBg4wRjQ.js';
3
+ export { C as ChatConfig, a as ChatIo, b as ConfigError, c as ConnectMcpOptions, M as McpToolInfo, d as McpTools, e as McpTransportConfig, f as buildSetup, g as connectMcpTools, p as parseTarget, r as runChat } from './chat-pBg4wRjQ.js';
3
4
  import Anthropic from '@anthropic-ai/sdk';
4
- import { M as ModelProvider, P as Pricing, a as ModelRequest, b as ModelEvent } from './types-C47SyHH5.js';
5
- export { C as ContentBlock, J as JsonSchema, c as Message, d as ProviderError, S as StopReason, T as ToolSpec, U as Usage } from './types-C47SyHH5.js';
5
+ import { M as ModelProvider, P as Pricing, a as ModelRequest, b as ModelEvent } from './types-DGH8FS56.js';
6
+ export { A as AnsweredBy, C as ContentBlock, J as JsonSchema, c as Message, d as ProviderError, S as StopReason, T as ToolSpec, U as Usage } from './types-DGH8FS56.js';
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
8
 
7
9
  declare const VERSION: string;
8
10
 
9
- type McpTransportConfig = {
10
- type: "stdio";
11
- command: string;
12
- args?: string[];
13
- env?: Record<string, string>;
14
- cwd?: string;
15
- } | {
16
- type: "http";
17
- url: string;
18
- headers?: Record<string, string>;
19
- };
20
- interface McpToolInfo {
21
- name: string;
22
- description?: string;
23
- annotations?: {
24
- readOnlyHint?: boolean;
25
- destructiveHint?: boolean;
26
- idempotentHint?: boolean;
27
- openWorldHint?: boolean;
28
- };
29
- }
30
- interface ConnectMcpOptions {
31
- transport: McpTransportConfig;
32
- /** The scope each tool needs. There is no default. A function can choose per tool. */
33
- scope: Scope | ((tool: McpToolInfo) => Scope);
34
- /** How risky each tool is. There is no default. A function can choose per tool. Do not trust the server's hints. */
35
- risk: ToolRisk | ((tool: McpToolInfo) => ToolRisk);
36
- /** Put before each tool name, to keep names from two servers apart. */
37
- prefix?: string;
38
- /** Most characters of tool output to keep. Default 32768. */
39
- maxOutputChars?: number;
40
- /** Most tools to load. Default 200. */
41
- maxTools?: number;
42
- /** Longest tool description to pass to the model. Default 1000. */
43
- maxDescriptionChars?: number;
44
- /** Time to wait for one tool call. Default 30000. */
45
- callTimeoutMs?: number;
46
- /** Time to connect and list every tool, all pages together. Default 30000. */
47
- loadTimeoutMs?: number;
48
- /** Most bytes to read from one HTTP response. Default 4000000. Stdio is limited by the SDK. */
49
- maxResponseBytes?: number;
50
- }
51
- interface McpTools {
52
- tools: ToolDefinition[];
53
- /** Tools that were not loaded, with the reason. */
54
- skipped: {
55
- name: string;
56
- reason: string;
57
- }[];
58
- close(): Promise<void>;
59
- }
60
- /**
61
- * Connects to an MCP server and turns its tools into assistant tools. The host
62
- * names the scope each tool needs. Output text is capped, and non-text content is
63
- * left out. Tools with a bad name, schema, or scope are skipped, not loaded.
64
- */
65
- declare function connectMcpTools(options: ConnectMcpOptions): Promise<McpTools>;
66
-
67
11
  declare const DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-5-5";
12
+ /** The day someone last compared KNOWN_PRICING with the published model table. Update it with the table. */
13
+ declare const PRICING_CHECKED_ON = "2026-10-29";
68
14
  interface AnthropicProviderOptions {
69
15
  /** Read from ANTHROPIC_API_KEY when absent. */
70
16
  apiKey?: string;
@@ -111,4 +57,33 @@ declare class OpenAICompatibleProvider implements ModelProvider {
111
57
  stream(request: ModelRequest): AsyncGenerator<ModelEvent>;
112
58
  }
113
59
 
114
- export { AnthropicProvider, type AnthropicProviderOptions, type ConnectMcpOptions, DEFAULT_ANTHROPIC_MODEL, type McpToolInfo, type McpTools, type McpTransportConfig, ModelEvent, ModelProvider, ModelRequest, type OpenAICompatibleOptions, OpenAICompatibleProvider, Pricing, Scope, ToolDefinition, ToolRisk, VERSION, connectMcpTools };
60
+ /**
61
+ * Asks `primary`. When it refuses or fails, asks `fallback` once, with the same request.
62
+ * The final message says which model answered. The fallback gets no second fallback: its
63
+ * answer, its refusal, or its error is the result.
64
+ *
65
+ * Text from the first model is held until its turn ends, so a refused turn shows no text from
66
+ * it. A turn with a fallback model configured therefore streams after the turn ends, not word by word.
67
+ * Usage counts both asks. The price is the higher of the two, so a cost cap never counts too little.
68
+ * The loop sizes the output room of a turn for one ask. The fallback gets only what the first ask left of it,
69
+ * and the loop counts the input twice (`maxAsks`), so a cap holds. A first ask that failed after it streamed
70
+ * is counted by an estimate of three characters per token, and its whole input. One that failed before it
71
+ * streamed anything is not counted.
72
+ */
73
+ declare class FallbackProvider implements ModelProvider {
74
+ private readonly primary;
75
+ private readonly fallback;
76
+ readonly name: string;
77
+ readonly model: string;
78
+ readonly pricing?: Pricing;
79
+ readonly maxAsks: number;
80
+ constructor(primary: ModelProvider, fallback: ModelProvider);
81
+ stream(request: ModelRequest): AsyncGenerator<ModelEvent>;
82
+ }
83
+
84
+ /** An MCP server with one tool, `assistant_chat`. Each call starts a new conversation. */
85
+ declare function createAssistantMcpServer(setup: Setup, shutdown?: AbortSignal): Server;
86
+ /** Serves on stdio. Resolves when the client closes its input, or the transport closes. */
87
+ declare function startAssistantMcp(setup: Setup): Promise<void>;
88
+
89
+ export { AnthropicProvider, type AnthropicProviderOptions, DEFAULT_ANTHROPIC_MODEL, FallbackProvider, ModelEvent, ModelProvider, ModelRequest, type OpenAICompatibleOptions, OpenAICompatibleProvider, PRICING_CHECKED_ON, Pricing, Setup, VERSION, createAssistantMcpServer, startAssistantMcp };