open-agents-ai 0.16.2 → 0.16.4
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 +42 -0
- package/dist/index.js +268 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -276,6 +276,48 @@ oa --backend vllm --backend-url http://localhost:8000/v1 "add tests"
|
|
|
276
276
|
oa --backend-url http://10.0.0.5:11434 "refactor auth"
|
|
277
277
|
```
|
|
278
278
|
|
|
279
|
+
## Supported Inference Providers
|
|
280
|
+
|
|
281
|
+
Open Agents auto-detects your provider from the endpoint URL and configures auth + health checks accordingly. All providers use standard `Authorization: Bearer <key>` authentication.
|
|
282
|
+
|
|
283
|
+
| Provider | Endpoint URL | API Key | Notes |
|
|
284
|
+
|----------|-------------|---------|-------|
|
|
285
|
+
| **Ollama** (local) | `http://localhost:11434` | None | Default. Auto-detects, auto-expands context window |
|
|
286
|
+
| **vLLM** (local) | `http://localhost:8000` | Optional | Self-hosted OpenAI-compatible server |
|
|
287
|
+
| **LM Studio** (local) | `http://localhost:1234` | None | Local model server with GUI |
|
|
288
|
+
| **Chutes AI** | `https://llm.chutes.ai` | `cpk_...` | Bearer auth. Fast cloud inference |
|
|
289
|
+
| **Together AI** | `https://api.together.xyz` | Required | Large model catalog |
|
|
290
|
+
| **Groq** | `https://api.groq.com/openai` | `gsk_...` | Ultra-fast LPU inference |
|
|
291
|
+
| **OpenRouter** | `https://openrouter.ai/api` | `sk-or-...` | Multi-provider routing |
|
|
292
|
+
| **Fireworks AI** | `https://api.fireworks.ai/inference` | `fw_...` | Fast serverless inference |
|
|
293
|
+
| **DeepInfra** | `https://api.deepinfra.com` | Required | Cost-effective inference |
|
|
294
|
+
| **Mistral AI** | `https://api.mistral.ai` | Required | Mistral models |
|
|
295
|
+
| **Cerebras** | `https://api.cerebras.ai` | `csk-...` | Wafer-scale inference |
|
|
296
|
+
| **SambaNova** | `https://api.sambanova.ai` | Required | RDU-accelerated inference |
|
|
297
|
+
| **NVIDIA NIM** | `https://integrate.api.nvidia.com` | `nvapi-...` | NVIDIA cloud inference |
|
|
298
|
+
| **Hyperbolic** | `https://api.hyperbolic.xyz` | Required | GPU cloud inference |
|
|
299
|
+
| **OpenAI** | `https://api.openai.com` | `sk-...` | GPT models (tool calling) |
|
|
300
|
+
|
|
301
|
+
### Connecting to a Provider
|
|
302
|
+
|
|
303
|
+
Use `/endpoint` in the TUI or pass via CLI:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Chutes AI
|
|
307
|
+
/endpoint https://llm.chutes.ai --auth cpk_your_key_here
|
|
308
|
+
|
|
309
|
+
# Groq
|
|
310
|
+
/endpoint https://api.groq.com/openai --auth gsk_your_key_here
|
|
311
|
+
|
|
312
|
+
# Together AI
|
|
313
|
+
/endpoint https://api.together.xyz --auth your_key_here
|
|
314
|
+
|
|
315
|
+
# Self-hosted vLLM on LAN
|
|
316
|
+
/endpoint http://10.0.0.5:8000
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The agent auto-detects the provider, normalizes the URL (strips `/v1/chat/completions` if pasted), tests connectivity, and saves the configuration. You can paste full endpoint URLs — they'll be cleaned up automatically.
|
|
320
|
+
|
|
279
321
|
## Evaluation Suite
|
|
280
322
|
|
|
281
323
|
23 evaluation tasks test the agent's autonomous capabilities across coding, web research, SDLC analysis, and tool creation:
|
package/dist/index.js
CHANGED
|
@@ -497,13 +497,100 @@ var init_sleep = __esm({
|
|
|
497
497
|
function normalizeBaseUrl(url) {
|
|
498
498
|
let u = url.trim();
|
|
499
499
|
u = u.replace(/\/+$/, "");
|
|
500
|
-
u = u.replace(/\/
|
|
500
|
+
u = u.replace(/\/chat\/completions$/, "");
|
|
501
|
+
u = u.replace(/\/completions$/, "");
|
|
502
|
+
u = u.replace(/\/embeddings$/, "");
|
|
503
|
+
u = u.replace(/\/models(?:\/.*)?$/, "");
|
|
504
|
+
u = u.replace(/\/+$/, "");
|
|
505
|
+
u = u.replace(/\/v1\/openai$/, "");
|
|
506
|
+
u = u.replace(/\/+$/, "");
|
|
507
|
+
u = u.replace(/\/v1$/, "");
|
|
501
508
|
u = u.replace(/\/+$/, "");
|
|
502
509
|
return u;
|
|
503
510
|
}
|
|
511
|
+
function detectProvider(url) {
|
|
512
|
+
const normalized = url.trim().toLowerCase();
|
|
513
|
+
for (const { match, info } of PROVIDERS) {
|
|
514
|
+
if (match(normalized))
|
|
515
|
+
return info;
|
|
516
|
+
}
|
|
517
|
+
const isLocal = /localhost|127\.0\.0\.1|0\.0\.0\.0/i.test(normalized);
|
|
518
|
+
return {
|
|
519
|
+
id: "unknown",
|
|
520
|
+
label: isLocal ? "Local OpenAI-compatible" : "OpenAI-compatible",
|
|
521
|
+
local: isLocal,
|
|
522
|
+
authRequired: !isLocal,
|
|
523
|
+
modelsPath: isLocal ? "/v1/models" : "/v1/models"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
var PROVIDERS;
|
|
504
527
|
var init_normalizeUrl = __esm({
|
|
505
528
|
"packages/backend-vllm/dist/normalizeUrl.js"() {
|
|
506
529
|
"use strict";
|
|
530
|
+
PROVIDERS = [
|
|
531
|
+
// --- Cloud providers (specific domains) ---
|
|
532
|
+
{
|
|
533
|
+
match: (u) => /api\.openai\.com/i.test(u),
|
|
534
|
+
info: { id: "openai", label: "OpenAI", local: false, authRequired: true, keyPrefix: "sk-", modelsPath: "/v1/models" }
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
match: (u) => /api\.together\.xyz/i.test(u),
|
|
538
|
+
info: { id: "together", label: "Together AI", local: false, authRequired: true, modelsPath: "/v1/models" }
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
match: (u) => /api\.groq\.com/i.test(u),
|
|
542
|
+
info: { id: "groq", label: "Groq", local: false, authRequired: true, keyPrefix: "gsk_", modelsPath: "/v1/models" }
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
match: (u) => /openrouter\.ai/i.test(u),
|
|
546
|
+
info: { id: "openrouter", label: "OpenRouter", local: false, authRequired: true, keyPrefix: "sk-or-", modelsPath: "/v1/models" }
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
match: (u) => /api\.fireworks\.ai/i.test(u),
|
|
550
|
+
info: { id: "fireworks", label: "Fireworks AI", local: false, authRequired: true, keyPrefix: "fw_", modelsPath: "/v1/models" }
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
match: (u) => /api\.deepinfra\.com/i.test(u),
|
|
554
|
+
info: { id: "deepinfra", label: "DeepInfra", local: false, authRequired: true, modelsPath: "/v1/models" }
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
match: (u) => /api\.mistral\.ai/i.test(u),
|
|
558
|
+
info: { id: "mistral", label: "Mistral AI", local: false, authRequired: true, modelsPath: "/v1/models" }
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
match: (u) => /llm\.chutes\.ai|chutes\.ai/i.test(u),
|
|
562
|
+
info: { id: "chutes", label: "Chutes AI", local: false, authRequired: true, keyPrefix: "cpk_", modelsPath: "/v1/models" }
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
match: (u) => /api\.cerebras\.ai/i.test(u),
|
|
566
|
+
info: { id: "cerebras", label: "Cerebras", local: false, authRequired: true, keyPrefix: "csk-", modelsPath: "/v1/models" }
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
match: (u) => /api\.sambanova\.ai/i.test(u),
|
|
570
|
+
info: { id: "sambanova", label: "SambaNova", local: false, authRequired: true, modelsPath: "/v1/models" }
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
match: (u) => /integrate\.api\.nvidia\.com/i.test(u),
|
|
574
|
+
info: { id: "nvidia", label: "NVIDIA NIM", local: false, authRequired: true, keyPrefix: "nvapi-", modelsPath: "/v1/models" }
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
match: (u) => /api\.hyperbolic\.xyz/i.test(u),
|
|
578
|
+
info: { id: "hyperbolic", label: "Hyperbolic", local: false, authRequired: true, modelsPath: "/v1/models" }
|
|
579
|
+
},
|
|
580
|
+
// --- Local providers (port-based detection) ---
|
|
581
|
+
{
|
|
582
|
+
match: (u) => /(?:localhost|127\.0\.0\.1|0\.0\.0\.0):11434/i.test(u),
|
|
583
|
+
info: { id: "ollama", label: "Ollama (local)", local: true, authRequired: false, modelsPath: "/api/tags" }
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
match: (u) => /(?:localhost|127\.0\.0\.1|0\.0\.0\.0):1234/i.test(u),
|
|
587
|
+
info: { id: "lmstudio", label: "LM Studio (local)", local: true, authRequired: false, modelsPath: "/v1/models" }
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
match: (u) => /(?:localhost|127\.0\.0\.1|0\.0\.0\.0):8000/i.test(u),
|
|
591
|
+
info: { id: "vllm", label: "vLLM (local)", local: true, authRequired: false, modelsPath: "/v1/models" }
|
|
592
|
+
}
|
|
593
|
+
];
|
|
507
594
|
}
|
|
508
595
|
});
|
|
509
596
|
|
|
@@ -9094,11 +9181,11 @@ ${newerSummary}` : newerSummary;
|
|
|
9094
9181
|
this.model = model;
|
|
9095
9182
|
this.apiKey = apiKey ?? "";
|
|
9096
9183
|
}
|
|
9097
|
-
/** Build auth headers —
|
|
9184
|
+
/** Build auth headers — all providers use standard Bearer token auth. */
|
|
9098
9185
|
authHeaders() {
|
|
9099
9186
|
const headers = { "Content-Type": "application/json" };
|
|
9100
9187
|
if (this.apiKey) {
|
|
9101
|
-
headers["Authorization"] =
|
|
9188
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
9102
9189
|
}
|
|
9103
9190
|
return headers;
|
|
9104
9191
|
}
|
|
@@ -9820,6 +9907,84 @@ function getColorsEnabled() {
|
|
|
9820
9907
|
function getTermWidth() {
|
|
9821
9908
|
return process.stdout.columns ?? 80;
|
|
9822
9909
|
}
|
|
9910
|
+
function formatMarkdownLine(line) {
|
|
9911
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
|
|
9912
|
+
if (headingMatch) {
|
|
9913
|
+
const level = headingMatch[1].length;
|
|
9914
|
+
const text = headingMatch[2];
|
|
9915
|
+
const colors = [MD.heading1, MD.heading2, MD.heading3, MD.heading3, 183, 183];
|
|
9916
|
+
return c2.bold(fg256(colors[level - 1] ?? 147, formatInlineMarkdown(text)));
|
|
9917
|
+
}
|
|
9918
|
+
if (/^[-*_]{3,}\s*$/.test(line)) {
|
|
9919
|
+
const w = getTermWidth() - 10;
|
|
9920
|
+
return fg256(MD.hr, "\u2500".repeat(Math.min(w, 60)));
|
|
9921
|
+
}
|
|
9922
|
+
if (/^>\s?/.test(line)) {
|
|
9923
|
+
const content = line.replace(/^>\s?/, "");
|
|
9924
|
+
return fg256(MD.blockquote, "\u2502 ") + c2.italic(fg256(MD.blockquote, formatInlineMarkdown(content)));
|
|
9925
|
+
}
|
|
9926
|
+
if (/^\|(.+)\|/.test(line)) {
|
|
9927
|
+
if (/^\|[\s:_-]+\|/.test(line)) {
|
|
9928
|
+
return fg256(MD.tableBar, line);
|
|
9929
|
+
}
|
|
9930
|
+
return line.replace(/([^|]+)/g, (cell) => {
|
|
9931
|
+
const trimmed = cell.trim();
|
|
9932
|
+
if (!trimmed)
|
|
9933
|
+
return cell;
|
|
9934
|
+
const leading = cell.match(/^(\s*)/)?.[1] ?? "";
|
|
9935
|
+
const trailing = cell.match(/(\s*)$/)?.[1] ?? "";
|
|
9936
|
+
return leading + formatInlineMarkdown(trimmed) + trailing;
|
|
9937
|
+
});
|
|
9938
|
+
}
|
|
9939
|
+
const ulMatch = line.match(/^(\s*)([-*+])\s+(.*)/);
|
|
9940
|
+
if (ulMatch) {
|
|
9941
|
+
return ulMatch[1] + fg256(MD.listBullet, "\u2022") + " " + formatInlineMarkdown(ulMatch[3]);
|
|
9942
|
+
}
|
|
9943
|
+
const olMatch = line.match(/^(\s*)(\d+[.)])\s+(.*)/);
|
|
9944
|
+
if (olMatch) {
|
|
9945
|
+
return olMatch[1] + fg256(MD.listBullet, olMatch[2]) + " " + formatInlineMarkdown(olMatch[3]);
|
|
9946
|
+
}
|
|
9947
|
+
return formatInlineMarkdown(line);
|
|
9948
|
+
}
|
|
9949
|
+
function formatInlineMarkdown(text) {
|
|
9950
|
+
let result = text;
|
|
9951
|
+
result = result.replace(/`([^`]+)`/g, (_m, code) => fg256(MD.inlineCode, code));
|
|
9952
|
+
result = result.replace(/\*{3}([^*]+)\*{3}/g, (_m, t) => c2.bold(c2.italic(t)));
|
|
9953
|
+
result = result.replace(/\*{2}([^*]+)\*{2}/g, (_m, t) => c2.bold(t));
|
|
9954
|
+
result = result.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, (_m, t) => c2.italic(t));
|
|
9955
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => c2.bold(fg256(MD.link, label)) + " " + c2.dim(fg256(MD.link, `(${url})`)));
|
|
9956
|
+
result = result.replace(/__([^_]+)__/g, (_m, t) => c2.bold(t));
|
|
9957
|
+
result = result.replace(/(?<!_)_([^_]+)_(?!_)/g, (_m, t) => c2.italic(t));
|
|
9958
|
+
result = result.replace(/~~([^~]+)~~/g, (_m, t) => c2.dim(t));
|
|
9959
|
+
return result;
|
|
9960
|
+
}
|
|
9961
|
+
function formatMarkdownBlock(text) {
|
|
9962
|
+
const lines = text.split("\n");
|
|
9963
|
+
const result = [];
|
|
9964
|
+
let inCodeBlock = false;
|
|
9965
|
+
let codeLang = "";
|
|
9966
|
+
for (const line of lines) {
|
|
9967
|
+
const trimmedLine = line.trimStart();
|
|
9968
|
+
if (trimmedLine.startsWith("```")) {
|
|
9969
|
+
if (inCodeBlock) {
|
|
9970
|
+
result.push(c2.dim(" ```"));
|
|
9971
|
+
inCodeBlock = false;
|
|
9972
|
+
codeLang = "";
|
|
9973
|
+
} else {
|
|
9974
|
+
codeLang = trimmedLine.slice(3).trim();
|
|
9975
|
+
result.push(c2.dim(" ```" + codeLang));
|
|
9976
|
+
inCodeBlock = true;
|
|
9977
|
+
}
|
|
9978
|
+
continue;
|
|
9979
|
+
}
|
|
9980
|
+
if (inCodeBlock) {
|
|
9981
|
+
result.push(" " + c2.dim(line));
|
|
9982
|
+
} else {
|
|
9983
|
+
result.push(formatMarkdownLine(line));
|
|
9984
|
+
}
|
|
9985
|
+
}
|
|
9986
|
+
return result.join("\n");
|
|
9987
|
+
}
|
|
9823
9988
|
function renderUserMessage(text) {
|
|
9824
9989
|
process.stdout.write(`
|
|
9825
9990
|
${c2.bold(c2.blue("> "))}${c2.bold(text)}
|
|
@@ -9828,7 +9993,8 @@ ${c2.bold(c2.blue("> "))}${c2.bold(text)}
|
|
|
9828
9993
|
function renderAssistantText(text) {
|
|
9829
9994
|
if (!text.trim())
|
|
9830
9995
|
return;
|
|
9831
|
-
const
|
|
9996
|
+
const formatted = formatMarkdownBlock(text);
|
|
9997
|
+
const lines = formatted.split("\n");
|
|
9832
9998
|
for (const line of lines) {
|
|
9833
9999
|
process.stdout.write(` ${line}
|
|
9834
10000
|
`);
|
|
@@ -9925,8 +10091,9 @@ function renderToolResult(toolName, success, output) {
|
|
|
9925
10091
|
`);
|
|
9926
10092
|
return;
|
|
9927
10093
|
}
|
|
9928
|
-
const
|
|
9929
|
-
|
|
10094
|
+
const cropped = line.length > maxW ? line.slice(0, maxW - 3) + "..." : line;
|
|
10095
|
+
const formatted = formatMarkdownLine(cropped);
|
|
10096
|
+
process.stdout.write(`${prefix}${formatted === cropped ? highlightToolOutput(cropped) : formatted}
|
|
9930
10097
|
`);
|
|
9931
10098
|
}
|
|
9932
10099
|
if (lines.length > maxLines) {
|
|
@@ -10010,6 +10177,9 @@ function highlightToolOutput(line) {
|
|
|
10010
10177
|
return c2.green(line);
|
|
10011
10178
|
if (/\bfail(ed|ing|ure)?\b/i.test(line))
|
|
10012
10179
|
return c2.red(line);
|
|
10180
|
+
const formatted = formatInlineMarkdown(line);
|
|
10181
|
+
if (formatted !== line)
|
|
10182
|
+
return formatted;
|
|
10013
10183
|
return c2.dim(line);
|
|
10014
10184
|
}
|
|
10015
10185
|
function renderTaskComplete(summary, turns, toolCalls, durationMs, tokens) {
|
|
@@ -10023,7 +10193,8 @@ ${c2.green("\u2714")} ${c2.bold("Task completed")} ${c2.dim(`(${turns} turns, ${
|
|
|
10023
10193
|
`);
|
|
10024
10194
|
}
|
|
10025
10195
|
if (summary) {
|
|
10026
|
-
const
|
|
10196
|
+
const formatted = formatMarkdownBlock(summary);
|
|
10197
|
+
const lines = formatted.split("\n");
|
|
10027
10198
|
for (const line of lines) {
|
|
10028
10199
|
process.stdout.write(` ${line}
|
|
10029
10200
|
`);
|
|
@@ -10234,13 +10405,14 @@ function renderConfig(config) {
|
|
|
10234
10405
|
process.stdout.write("\n");
|
|
10235
10406
|
}
|
|
10236
10407
|
function formatToolArgs(toolName, args) {
|
|
10408
|
+
const maxArg = Math.max(40, getTermWidth() - 20);
|
|
10237
10409
|
switch (toolName) {
|
|
10238
10410
|
case "file_read":
|
|
10239
10411
|
case "file_write":
|
|
10240
10412
|
case "file_edit":
|
|
10241
10413
|
return String(args["path"] ?? "");
|
|
10242
10414
|
case "shell": {
|
|
10243
|
-
const cmd = truncStr(String(args["command"] ?? ""),
|
|
10415
|
+
const cmd = truncStr(String(args["command"] ?? ""), maxArg);
|
|
10244
10416
|
return args["stdin"] ? `${cmd} ${c2.dim("(with stdin)")}` : cmd;
|
|
10245
10417
|
}
|
|
10246
10418
|
case "grep_search":
|
|
@@ -10250,21 +10422,21 @@ function formatToolArgs(toolName, args) {
|
|
|
10250
10422
|
case "list_directory":
|
|
10251
10423
|
return String(args["path"] ?? ".");
|
|
10252
10424
|
case "web_search":
|
|
10253
|
-
return `"${truncStr(String(args["query"] ?? ""),
|
|
10425
|
+
return `"${truncStr(String(args["query"] ?? ""), maxArg - 2)}"`;
|
|
10254
10426
|
case "web_fetch":
|
|
10255
|
-
return truncStr(String(args["url"] ?? ""),
|
|
10427
|
+
return truncStr(String(args["url"] ?? ""), maxArg);
|
|
10256
10428
|
case "memory_read":
|
|
10257
10429
|
return `${args["topic"]}${args["key"] ? "." + args["key"] : ""}`;
|
|
10258
10430
|
case "memory_write":
|
|
10259
10431
|
return `${args["topic"]}.${args["key"]}`;
|
|
10260
10432
|
case "task_complete":
|
|
10261
|
-
return truncStr(String(args["summary"] ?? ""),
|
|
10433
|
+
return truncStr(String(args["summary"] ?? ""), maxArg);
|
|
10262
10434
|
case "aiwg_setup":
|
|
10263
10435
|
return String(args["framework"] ?? "sdlc");
|
|
10264
10436
|
case "aiwg_health":
|
|
10265
10437
|
return args["detailed"] ? "detailed" : "summary";
|
|
10266
10438
|
case "aiwg_workflow":
|
|
10267
|
-
return truncStr(String(args["command"] ?? ""),
|
|
10439
|
+
return truncStr(String(args["command"] ?? ""), maxArg);
|
|
10268
10440
|
case "batch_edit": {
|
|
10269
10441
|
const edits = args["edits"];
|
|
10270
10442
|
return edits ? `${edits.length} edit(s)` : "";
|
|
@@ -10278,14 +10450,14 @@ function formatToolArgs(toolName, args) {
|
|
|
10278
10450
|
case "git_info":
|
|
10279
10451
|
return args["show_diff"] ? "with diff" : "summary";
|
|
10280
10452
|
case "background_run":
|
|
10281
|
-
return truncStr(String(args["command"] ?? ""),
|
|
10453
|
+
return truncStr(String(args["command"] ?? ""), maxArg);
|
|
10282
10454
|
case "task_status":
|
|
10283
10455
|
case "task_output":
|
|
10284
10456
|
case "task_stop":
|
|
10285
10457
|
return String(args["task_id"] ?? "all");
|
|
10286
10458
|
case "sub_agent": {
|
|
10287
10459
|
const bg = args["background"] ? " (background)" : "";
|
|
10288
|
-
return truncStr(String(args["task"] ?? ""),
|
|
10460
|
+
return truncStr(String(args["task"] ?? ""), maxArg - 15) + bg;
|
|
10289
10461
|
}
|
|
10290
10462
|
case "image_read":
|
|
10291
10463
|
return String(args["path"] ?? "");
|
|
@@ -10296,9 +10468,9 @@ function formatToolArgs(toolName, args) {
|
|
|
10296
10468
|
case "transcribe_file":
|
|
10297
10469
|
return `${args["path"] ?? ""}${args["model"] ? ` (${args["model"]})` : ""}`;
|
|
10298
10470
|
case "transcribe_url":
|
|
10299
|
-
return truncStr(String(args["url"] ?? ""),
|
|
10471
|
+
return truncStr(String(args["url"] ?? ""), maxArg);
|
|
10300
10472
|
default:
|
|
10301
|
-
return Object.entries(args).map(([k, v]) => `${k}=${truncStr(String(v), 30)}`).join(", ");
|
|
10473
|
+
return Object.entries(args).map(([k, v]) => `${k}=${truncStr(String(v), Math.max(30, maxArg / 3))}`).join(", ");
|
|
10302
10474
|
}
|
|
10303
10475
|
}
|
|
10304
10476
|
function truncStr(s, max) {
|
|
@@ -10314,7 +10486,7 @@ function formatDuration2(ms) {
|
|
|
10314
10486
|
const secs = Math.floor(totalSecs % 60);
|
|
10315
10487
|
return `${mins}m ${secs}s`;
|
|
10316
10488
|
}
|
|
10317
|
-
var isTTY2, c2, pastel, _emojisEnabled, _colorsEnabled, TOOL_ICONS, TOOL_LABELS, TOOL_COLORS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
|
|
10489
|
+
var isTTY2, c2, pastel, _emojisEnabled, _colorsEnabled, MD, TOOL_ICONS, TOOL_LABELS, TOOL_COLORS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
|
|
10318
10490
|
var init_render = __esm({
|
|
10319
10491
|
"packages/cli/dist/tui/render.js"() {
|
|
10320
10492
|
"use strict";
|
|
@@ -10347,6 +10519,26 @@ var init_render = __esm({
|
|
|
10347
10519
|
};
|
|
10348
10520
|
_emojisEnabled = true;
|
|
10349
10521
|
_colorsEnabled = true;
|
|
10522
|
+
MD = {
|
|
10523
|
+
heading1: 75,
|
|
10524
|
+
// blue
|
|
10525
|
+
heading2: 117,
|
|
10526
|
+
// sky blue
|
|
10527
|
+
heading3: 147,
|
|
10528
|
+
// light blue
|
|
10529
|
+
inlineCode: 223,
|
|
10530
|
+
// light peach
|
|
10531
|
+
link: 111,
|
|
10532
|
+
// periwinkle
|
|
10533
|
+
blockquote: 245,
|
|
10534
|
+
// grey
|
|
10535
|
+
hr: 240,
|
|
10536
|
+
// dark grey
|
|
10537
|
+
listBullet: 245,
|
|
10538
|
+
// grey
|
|
10539
|
+
tableBar: 245
|
|
10540
|
+
// grey
|
|
10541
|
+
};
|
|
10350
10542
|
TOOL_ICONS = {
|
|
10351
10543
|
file_read: "\u{1F4C4}",
|
|
10352
10544
|
file_write: "\u{1F4DD}",
|
|
@@ -11054,15 +11246,18 @@ async function promptForCustomEndpoint(config, rl) {
|
|
|
11054
11246
|
`);
|
|
11055
11247
|
const modelName = await ask(rl, ` ${c2.bold("Model name")} (Enter for ${c2.dim(config.model)}): `);
|
|
11056
11248
|
const chosenModel = modelName || config.model;
|
|
11249
|
+
const provider = detectProvider(endpoint);
|
|
11057
11250
|
process.stdout.write(`
|
|
11058
|
-
${c2.cyan("\u25CF")}
|
|
11251
|
+
${c2.cyan("\u25CF")} Detected provider: ${c2.bold(provider.label)}
|
|
11252
|
+
`);
|
|
11253
|
+
process.stdout.write(` ${c2.cyan("\u25CF")} Testing endpoint ${c2.bold(cleanUrl)}...
|
|
11059
11254
|
`);
|
|
11060
11255
|
let testOk = false;
|
|
11061
11256
|
try {
|
|
11062
|
-
const testUrl = `${cleanUrl}
|
|
11257
|
+
const testUrl = `${cleanUrl}${provider.modelsPath}`;
|
|
11063
11258
|
const headers = { "Content-Type": "application/json" };
|
|
11064
11259
|
if (apiKey) {
|
|
11065
|
-
headers["Authorization"] =
|
|
11260
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
11066
11261
|
}
|
|
11067
11262
|
const resp = await fetch(testUrl, { headers, signal: AbortSignal.timeout(1e4) });
|
|
11068
11263
|
if (resp.ok) {
|
|
@@ -11070,14 +11265,16 @@ async function promptForCustomEndpoint(config, rl) {
|
|
|
11070
11265
|
`);
|
|
11071
11266
|
testOk = true;
|
|
11072
11267
|
} else {
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11268
|
+
if (provider.id !== "ollama") {
|
|
11269
|
+
try {
|
|
11270
|
+
const ollamaResp = await fetch(`${cleanUrl}/api/tags`, { signal: AbortSignal.timeout(1e4) });
|
|
11271
|
+
if (ollamaResp.ok) {
|
|
11272
|
+
process.stdout.write(` ${c2.green("\u2714")} Ollama endpoint detected.
|
|
11077
11273
|
`);
|
|
11078
|
-
|
|
11274
|
+
testOk = true;
|
|
11275
|
+
}
|
|
11276
|
+
} catch {
|
|
11079
11277
|
}
|
|
11080
|
-
} catch {
|
|
11081
11278
|
}
|
|
11082
11279
|
if (!testOk) {
|
|
11083
11280
|
process.stdout.write(` ${c2.yellow("\u26A0")} Endpoint returned HTTP ${resp.status}
|
|
@@ -11089,6 +11286,10 @@ async function promptForCustomEndpoint(config, rl) {
|
|
|
11089
11286
|
`);
|
|
11090
11287
|
}
|
|
11091
11288
|
if (!testOk) {
|
|
11289
|
+
if (provider.authRequired && !apiKey) {
|
|
11290
|
+
process.stdout.write(` ${c2.dim(`${provider.label} typically requires an API key.`)}
|
|
11291
|
+
`);
|
|
11292
|
+
}
|
|
11092
11293
|
const startAnyway = await ask(rl, `
|
|
11093
11294
|
${c2.bold("Endpoint unreachable. Start anyway?")} (y/n) `);
|
|
11094
11295
|
if (startAnyway.toLowerCase() !== "y" && startAnyway.toLowerCase() !== "yes") {
|
|
@@ -11103,11 +11304,12 @@ async function promptForCustomEndpoint(config, rl) {
|
|
|
11103
11304
|
if (apiKey) {
|
|
11104
11305
|
setConfigValue("apiKey", apiKey);
|
|
11105
11306
|
}
|
|
11106
|
-
const
|
|
11107
|
-
const backendType = isLocalOllama ? "ollama" : "vllm";
|
|
11307
|
+
const backendType = provider.id === "ollama" ? "ollama" : "vllm";
|
|
11108
11308
|
setConfigValue("backendType", backendType);
|
|
11109
11309
|
process.stdout.write(`
|
|
11110
11310
|
${c2.green("\u2714")} Configured: ${c2.bold(chosenModel)} at ${c2.bold(cleanUrl)}
|
|
11311
|
+
`);
|
|
11312
|
+
process.stdout.write(` ${c2.green("\u2714")} Provider: ${c2.bold(provider.label)}
|
|
11111
11313
|
`);
|
|
11112
11314
|
if (apiKey)
|
|
11113
11315
|
process.stdout.write(` ${c2.green("\u2714")} API key saved.
|
|
@@ -11728,9 +11930,12 @@ async function showModelPicker(ctx) {
|
|
|
11728
11930
|
}
|
|
11729
11931
|
async function handleEndpoint(arg, ctx, local = false) {
|
|
11730
11932
|
if (!arg) {
|
|
11933
|
+
const currentProvider = detectProvider(ctx.config.backendUrl);
|
|
11731
11934
|
process.stdout.write(`
|
|
11732
11935
|
${c2.bold("Current endpoint:")}
|
|
11733
11936
|
|
|
11937
|
+
`);
|
|
11938
|
+
process.stdout.write(` ${c2.cyan("Provider".padEnd(12))} ${currentProvider.label}
|
|
11734
11939
|
`);
|
|
11735
11940
|
process.stdout.write(` ${c2.cyan("URL".padEnd(12))} ${ctx.config.backendUrl}
|
|
11736
11941
|
`);
|
|
@@ -11741,11 +11946,15 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
11741
11946
|
process.stdout.write(`
|
|
11742
11947
|
${c2.dim("Usage: /endpoint <url> [--auth <token>]")}
|
|
11743
11948
|
`);
|
|
11744
|
-
process.stdout.write(` ${c2.dim(" /endpoint http://localhost:11434
|
|
11949
|
+
process.stdout.write(` ${c2.dim(" /endpoint http://localhost:11434 Ollama")}
|
|
11950
|
+
`);
|
|
11951
|
+
process.stdout.write(` ${c2.dim(" /endpoint https://llm.chutes.ai --auth cpk_... Chutes AI")}
|
|
11745
11952
|
`);
|
|
11746
|
-
process.stdout.write(` ${c2.dim(" /endpoint
|
|
11953
|
+
process.stdout.write(` ${c2.dim(" /endpoint https://api.groq.com/openai --auth gsk_... Groq")}
|
|
11747
11954
|
`);
|
|
11748
|
-
process.stdout.write(` ${c2.dim(" /endpoint
|
|
11955
|
+
process.stdout.write(` ${c2.dim(" /endpoint https://api.together.xyz --auth ... Together AI")}
|
|
11956
|
+
`);
|
|
11957
|
+
process.stdout.write(` ${c2.dim(" /endpoint http://localhost:8000 vLLM")}
|
|
11749
11958
|
|
|
11750
11959
|
`);
|
|
11751
11960
|
return;
|
|
@@ -11764,15 +11973,17 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
11764
11973
|
return;
|
|
11765
11974
|
}
|
|
11766
11975
|
const normalizedUrl = normalizeBaseUrl(url);
|
|
11767
|
-
const
|
|
11768
|
-
|
|
11976
|
+
const provider = detectProvider(url);
|
|
11977
|
+
const backendType = provider.id === "ollama" ? "ollama" : "vllm";
|
|
11769
11978
|
process.stdout.write(`
|
|
11770
|
-
${c2.dim("
|
|
11979
|
+
${c2.dim("Detected:")} ${c2.bold(provider.label)}
|
|
11980
|
+
`);
|
|
11981
|
+
process.stdout.write(` ${c2.dim("Testing connection...")} `);
|
|
11771
11982
|
try {
|
|
11772
|
-
const healthUrl =
|
|
11983
|
+
const healthUrl = `${normalizedUrl}${provider.modelsPath}`;
|
|
11773
11984
|
const headers = {};
|
|
11774
11985
|
if (apiKey) {
|
|
11775
|
-
headers["Authorization"] =
|
|
11986
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
11776
11987
|
}
|
|
11777
11988
|
const resp = await fetch(healthUrl, {
|
|
11778
11989
|
headers,
|
|
@@ -11786,6 +11997,9 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
11786
11997
|
process.stdout.write(`${c2.yellow("\u26A0")} Could not verify
|
|
11787
11998
|
`);
|
|
11788
11999
|
renderWarning(`Endpoint may not be reachable: ${err instanceof Error ? err.message : String(err)}`);
|
|
12000
|
+
if (provider.authRequired && !apiKey) {
|
|
12001
|
+
renderInfo(`${provider.label} typically requires an API key. Use: /endpoint ${url} --auth <key>`);
|
|
12002
|
+
}
|
|
11789
12003
|
renderInfo("Setting endpoint anyway \u2014 it may come online later.");
|
|
11790
12004
|
}
|
|
11791
12005
|
ctx.setEndpoint(normalizedUrl, backendType, apiKey);
|
|
@@ -11803,15 +12017,17 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
11803
12017
|
process.stdout.write(`
|
|
11804
12018
|
${c2.green("\u2714")} Endpoint updated and saved${local ? " (project-local)" : ""}:
|
|
11805
12019
|
`);
|
|
11806
|
-
process.stdout.write(` ${c2.cyan("
|
|
12020
|
+
process.stdout.write(` ${c2.cyan("Provider".padEnd(12))} ${provider.label}
|
|
12021
|
+
`);
|
|
12022
|
+
process.stdout.write(` ${c2.cyan("URL".padEnd(12))} ${normalizedUrl}
|
|
11807
12023
|
`);
|
|
11808
|
-
process.stdout.write(` ${c2.cyan("Type".padEnd(
|
|
12024
|
+
process.stdout.write(` ${c2.cyan("Type".padEnd(12))} ${backendType}
|
|
11809
12025
|
`);
|
|
11810
12026
|
if (apiKey) {
|
|
11811
|
-
process.stdout.write(` ${c2.cyan("Auth".padEnd(
|
|
12027
|
+
process.stdout.write(` ${c2.cyan("Auth".padEnd(12))} Bearer ${apiKey.slice(0, 8)}...
|
|
11812
12028
|
`);
|
|
11813
12029
|
} else {
|
|
11814
|
-
process.stdout.write(` ${c2.cyan("Auth".padEnd(
|
|
12030
|
+
process.stdout.write(` ${c2.cyan("Auth".padEnd(12))} ${provider.authRequired ? c2.yellow("none (may be required)") : "none"}
|
|
11815
12031
|
`);
|
|
11816
12032
|
}
|
|
11817
12033
|
process.stdout.write("\n");
|
|
@@ -15587,17 +15803,19 @@ async function startInteractive(config, repoPath) {
|
|
|
15587
15803
|
if (!isResumed) {
|
|
15588
15804
|
try {
|
|
15589
15805
|
const baseUrl = normalizeBaseUrl(config.backendUrl);
|
|
15590
|
-
const
|
|
15806
|
+
const provider = detectProvider(config.backendUrl);
|
|
15807
|
+
const healthUrl = `${baseUrl}${provider.modelsPath}`;
|
|
15591
15808
|
const headers = {};
|
|
15592
15809
|
if (config.apiKey) {
|
|
15593
|
-
headers["Authorization"] =
|
|
15810
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
15594
15811
|
}
|
|
15595
15812
|
const resp = await fetch(healthUrl, { headers, signal: AbortSignal.timeout(1e4) });
|
|
15596
15813
|
if (!resp.ok)
|
|
15597
15814
|
throw new Error(`HTTP ${resp.status}`);
|
|
15598
15815
|
} catch {
|
|
15599
|
-
|
|
15600
|
-
|
|
15816
|
+
const provider = detectProvider(config.backendUrl);
|
|
15817
|
+
renderWarning(`Cannot reach ${provider.label} at ${config.backendUrl}`);
|
|
15818
|
+
if (provider.id === "ollama") {
|
|
15601
15819
|
renderInfo("Start Ollama with: ollama serve");
|
|
15602
15820
|
}
|
|
15603
15821
|
renderInfo("Use /endpoint to configure a different backend. Starting anyway...");
|
|
@@ -16205,17 +16423,19 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
16205
16423
|
}
|
|
16206
16424
|
try {
|
|
16207
16425
|
const baseUrl2 = normalizeBaseUrl(config.backendUrl);
|
|
16208
|
-
const
|
|
16426
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
16427
|
+
const healthUrl = `${baseUrl2}${provider2.modelsPath}`;
|
|
16209
16428
|
const headers = {};
|
|
16210
16429
|
if (config.apiKey) {
|
|
16211
|
-
headers["Authorization"] =
|
|
16430
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
16212
16431
|
}
|
|
16213
16432
|
const resp = await fetch(healthUrl, { headers, signal: AbortSignal.timeout(1e4) });
|
|
16214
16433
|
if (!resp.ok)
|
|
16215
16434
|
throw new Error(`HTTP ${resp.status}`);
|
|
16216
16435
|
} catch {
|
|
16217
|
-
|
|
16218
|
-
|
|
16436
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
16437
|
+
renderWarning(`Cannot reach ${provider2.label} at ${config.backendUrl}`);
|
|
16438
|
+
if (provider2.id === "ollama") {
|
|
16219
16439
|
renderInfo("Start Ollama with: ollama serve");
|
|
16220
16440
|
}
|
|
16221
16441
|
renderInfo("The agent will retry when you submit a task. Use /endpoint to reconfigure.");
|
package/package.json
CHANGED