open-agents-ai 0.16.3 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +171 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9835,6 +9835,53 @@ async function fetchOllamaModels(baseUrl) {
9835
9835
  parameterSize: m.details?.parameter_size
9836
9836
  })).sort((a, b) => b.sizeBytes - a.sizeBytes);
9837
9837
  }
9838
+ async function fetchOpenAIModels(baseUrl, apiKey) {
9839
+ const normalized = normalizeBaseUrl(baseUrl);
9840
+ const url = `${normalized}/v1/models`;
9841
+ const headers = {};
9842
+ if (apiKey) {
9843
+ headers["Authorization"] = `Bearer ${apiKey}`;
9844
+ }
9845
+ const resp = await fetch(url, {
9846
+ headers,
9847
+ signal: AbortSignal.timeout(1e4)
9848
+ });
9849
+ if (!resp.ok) {
9850
+ throw new Error(`Failed to fetch models: HTTP ${resp.status}`);
9851
+ }
9852
+ const data = await resp.json();
9853
+ const models = data.data ?? [];
9854
+ return models.map((m) => ({
9855
+ name: m.id,
9856
+ size: m.context_length ? `${Math.round(m.context_length / 1024)}K ctx` : m.max_model_len ? `${Math.round(m.max_model_len / 1024)}K ctx` : "",
9857
+ sizeBytes: 0,
9858
+ modified: m.created ? formatRelativeTime(new Date(m.created * 1e3).toISOString()) : "",
9859
+ parameterSize: m.owned_by ?? void 0
9860
+ })).sort((a, b) => a.name.localeCompare(b.name));
9861
+ }
9862
+ async function fetchModels(baseUrl, apiKey) {
9863
+ const provider = detectProvider(baseUrl);
9864
+ if (provider.id === "ollama") {
9865
+ try {
9866
+ return await fetchOllamaModels(baseUrl);
9867
+ } catch {
9868
+ try {
9869
+ return await fetchOpenAIModels(baseUrl, apiKey);
9870
+ } catch {
9871
+ throw new Error("Cannot reach Ollama at " + baseUrl);
9872
+ }
9873
+ }
9874
+ }
9875
+ try {
9876
+ return await fetchOpenAIModels(baseUrl, apiKey);
9877
+ } catch {
9878
+ try {
9879
+ return await fetchOllamaModels(baseUrl);
9880
+ } catch {
9881
+ throw new Error(`Cannot fetch models from ${provider.label} at ${baseUrl}`);
9882
+ }
9883
+ }
9884
+ }
9838
9885
  function findModel(models, query) {
9839
9886
  const exact = models.find((m) => m.name === query);
9840
9887
  if (exact)
@@ -9907,6 +9954,84 @@ function getColorsEnabled() {
9907
9954
  function getTermWidth() {
9908
9955
  return process.stdout.columns ?? 80;
9909
9956
  }
9957
+ function formatMarkdownLine(line) {
9958
+ const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
9959
+ if (headingMatch) {
9960
+ const level = headingMatch[1].length;
9961
+ const text = headingMatch[2];
9962
+ const colors = [MD.heading1, MD.heading2, MD.heading3, MD.heading3, 183, 183];
9963
+ return c2.bold(fg256(colors[level - 1] ?? 147, formatInlineMarkdown(text)));
9964
+ }
9965
+ if (/^[-*_]{3,}\s*$/.test(line)) {
9966
+ const w = getTermWidth() - 10;
9967
+ return fg256(MD.hr, "\u2500".repeat(Math.min(w, 60)));
9968
+ }
9969
+ if (/^>\s?/.test(line)) {
9970
+ const content = line.replace(/^>\s?/, "");
9971
+ return fg256(MD.blockquote, "\u2502 ") + c2.italic(fg256(MD.blockquote, formatInlineMarkdown(content)));
9972
+ }
9973
+ if (/^\|(.+)\|/.test(line)) {
9974
+ if (/^\|[\s:_-]+\|/.test(line)) {
9975
+ return fg256(MD.tableBar, line);
9976
+ }
9977
+ return line.replace(/([^|]+)/g, (cell) => {
9978
+ const trimmed = cell.trim();
9979
+ if (!trimmed)
9980
+ return cell;
9981
+ const leading = cell.match(/^(\s*)/)?.[1] ?? "";
9982
+ const trailing = cell.match(/(\s*)$/)?.[1] ?? "";
9983
+ return leading + formatInlineMarkdown(trimmed) + trailing;
9984
+ });
9985
+ }
9986
+ const ulMatch = line.match(/^(\s*)([-*+])\s+(.*)/);
9987
+ if (ulMatch) {
9988
+ return ulMatch[1] + fg256(MD.listBullet, "\u2022") + " " + formatInlineMarkdown(ulMatch[3]);
9989
+ }
9990
+ const olMatch = line.match(/^(\s*)(\d+[.)])\s+(.*)/);
9991
+ if (olMatch) {
9992
+ return olMatch[1] + fg256(MD.listBullet, olMatch[2]) + " " + formatInlineMarkdown(olMatch[3]);
9993
+ }
9994
+ return formatInlineMarkdown(line);
9995
+ }
9996
+ function formatInlineMarkdown(text) {
9997
+ let result = text;
9998
+ result = result.replace(/`([^`]+)`/g, (_m, code) => fg256(MD.inlineCode, code));
9999
+ result = result.replace(/\*{3}([^*]+)\*{3}/g, (_m, t) => c2.bold(c2.italic(t)));
10000
+ result = result.replace(/\*{2}([^*]+)\*{2}/g, (_m, t) => c2.bold(t));
10001
+ result = result.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, (_m, t) => c2.italic(t));
10002
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => c2.bold(fg256(MD.link, label)) + " " + c2.dim(fg256(MD.link, `(${url})`)));
10003
+ result = result.replace(/__([^_]+)__/g, (_m, t) => c2.bold(t));
10004
+ result = result.replace(/(?<!_)_([^_]+)_(?!_)/g, (_m, t) => c2.italic(t));
10005
+ result = result.replace(/~~([^~]+)~~/g, (_m, t) => c2.dim(t));
10006
+ return result;
10007
+ }
10008
+ function formatMarkdownBlock(text) {
10009
+ const lines = text.split("\n");
10010
+ const result = [];
10011
+ let inCodeBlock = false;
10012
+ let codeLang = "";
10013
+ for (const line of lines) {
10014
+ const trimmedLine = line.trimStart();
10015
+ if (trimmedLine.startsWith("```")) {
10016
+ if (inCodeBlock) {
10017
+ result.push(c2.dim(" ```"));
10018
+ inCodeBlock = false;
10019
+ codeLang = "";
10020
+ } else {
10021
+ codeLang = trimmedLine.slice(3).trim();
10022
+ result.push(c2.dim(" ```" + codeLang));
10023
+ inCodeBlock = true;
10024
+ }
10025
+ continue;
10026
+ }
10027
+ if (inCodeBlock) {
10028
+ result.push(" " + c2.dim(line));
10029
+ } else {
10030
+ result.push(formatMarkdownLine(line));
10031
+ }
10032
+ }
10033
+ return result.join("\n");
10034
+ }
9910
10035
  function renderUserMessage(text) {
9911
10036
  process.stdout.write(`
9912
10037
  ${c2.bold(c2.blue("> "))}${c2.bold(text)}
@@ -9915,7 +10040,8 @@ ${c2.bold(c2.blue("> "))}${c2.bold(text)}
9915
10040
  function renderAssistantText(text) {
9916
10041
  if (!text.trim())
9917
10042
  return;
9918
- const lines = text.split("\n");
10043
+ const formatted = formatMarkdownBlock(text);
10044
+ const lines = formatted.split("\n");
9919
10045
  for (const line of lines) {
9920
10046
  process.stdout.write(` ${line}
9921
10047
  `);
@@ -10012,8 +10138,9 @@ function renderToolResult(toolName, success, output) {
10012
10138
  `);
10013
10139
  return;
10014
10140
  }
10015
- const trimmed = line.length > maxW ? line.slice(0, maxW - 3) + "..." : line;
10016
- process.stdout.write(`${prefix}${highlightToolOutput(trimmed)}
10141
+ const cropped = line.length > maxW ? line.slice(0, maxW - 3) + "..." : line;
10142
+ const formatted = formatMarkdownLine(cropped);
10143
+ process.stdout.write(`${prefix}${formatted === cropped ? highlightToolOutput(cropped) : formatted}
10017
10144
  `);
10018
10145
  }
10019
10146
  if (lines.length > maxLines) {
@@ -10097,6 +10224,9 @@ function highlightToolOutput(line) {
10097
10224
  return c2.green(line);
10098
10225
  if (/\bfail(ed|ing|ure)?\b/i.test(line))
10099
10226
  return c2.red(line);
10227
+ const formatted = formatInlineMarkdown(line);
10228
+ if (formatted !== line)
10229
+ return formatted;
10100
10230
  return c2.dim(line);
10101
10231
  }
10102
10232
  function renderTaskComplete(summary, turns, toolCalls, durationMs, tokens) {
@@ -10110,7 +10240,8 @@ ${c2.green("\u2714")} ${c2.bold("Task completed")} ${c2.dim(`(${turns} turns, ${
10110
10240
  `);
10111
10241
  }
10112
10242
  if (summary) {
10113
- const lines = summary.split("\n");
10243
+ const formatted = formatMarkdownBlock(summary);
10244
+ const lines = formatted.split("\n");
10114
10245
  for (const line of lines) {
10115
10246
  process.stdout.write(` ${line}
10116
10247
  `);
@@ -10321,13 +10452,14 @@ function renderConfig(config) {
10321
10452
  process.stdout.write("\n");
10322
10453
  }
10323
10454
  function formatToolArgs(toolName, args) {
10455
+ const maxArg = Math.max(40, getTermWidth() - 20);
10324
10456
  switch (toolName) {
10325
10457
  case "file_read":
10326
10458
  case "file_write":
10327
10459
  case "file_edit":
10328
10460
  return String(args["path"] ?? "");
10329
10461
  case "shell": {
10330
- const cmd = truncStr(String(args["command"] ?? ""), 60);
10462
+ const cmd = truncStr(String(args["command"] ?? ""), maxArg);
10331
10463
  return args["stdin"] ? `${cmd} ${c2.dim("(with stdin)")}` : cmd;
10332
10464
  }
10333
10465
  case "grep_search":
@@ -10337,21 +10469,21 @@ function formatToolArgs(toolName, args) {
10337
10469
  case "list_directory":
10338
10470
  return String(args["path"] ?? ".");
10339
10471
  case "web_search":
10340
- return `"${truncStr(String(args["query"] ?? ""), 50)}"`;
10472
+ return `"${truncStr(String(args["query"] ?? ""), maxArg - 2)}"`;
10341
10473
  case "web_fetch":
10342
- return truncStr(String(args["url"] ?? ""), 60);
10474
+ return truncStr(String(args["url"] ?? ""), maxArg);
10343
10475
  case "memory_read":
10344
10476
  return `${args["topic"]}${args["key"] ? "." + args["key"] : ""}`;
10345
10477
  case "memory_write":
10346
10478
  return `${args["topic"]}.${args["key"]}`;
10347
10479
  case "task_complete":
10348
- return truncStr(String(args["summary"] ?? ""), 60);
10480
+ return truncStr(String(args["summary"] ?? ""), maxArg);
10349
10481
  case "aiwg_setup":
10350
10482
  return String(args["framework"] ?? "sdlc");
10351
10483
  case "aiwg_health":
10352
10484
  return args["detailed"] ? "detailed" : "summary";
10353
10485
  case "aiwg_workflow":
10354
- return truncStr(String(args["command"] ?? ""), 60);
10486
+ return truncStr(String(args["command"] ?? ""), maxArg);
10355
10487
  case "batch_edit": {
10356
10488
  const edits = args["edits"];
10357
10489
  return edits ? `${edits.length} edit(s)` : "";
@@ -10365,14 +10497,14 @@ function formatToolArgs(toolName, args) {
10365
10497
  case "git_info":
10366
10498
  return args["show_diff"] ? "with diff" : "summary";
10367
10499
  case "background_run":
10368
- return truncStr(String(args["command"] ?? ""), 60);
10500
+ return truncStr(String(args["command"] ?? ""), maxArg);
10369
10501
  case "task_status":
10370
10502
  case "task_output":
10371
10503
  case "task_stop":
10372
10504
  return String(args["task_id"] ?? "all");
10373
10505
  case "sub_agent": {
10374
10506
  const bg = args["background"] ? " (background)" : "";
10375
- return truncStr(String(args["task"] ?? ""), 50) + bg;
10507
+ return truncStr(String(args["task"] ?? ""), maxArg - 15) + bg;
10376
10508
  }
10377
10509
  case "image_read":
10378
10510
  return String(args["path"] ?? "");
@@ -10383,9 +10515,9 @@ function formatToolArgs(toolName, args) {
10383
10515
  case "transcribe_file":
10384
10516
  return `${args["path"] ?? ""}${args["model"] ? ` (${args["model"]})` : ""}`;
10385
10517
  case "transcribe_url":
10386
- return truncStr(String(args["url"] ?? ""), 60);
10518
+ return truncStr(String(args["url"] ?? ""), maxArg);
10387
10519
  default:
10388
- return Object.entries(args).map(([k, v]) => `${k}=${truncStr(String(v), 30)}`).join(", ");
10520
+ return Object.entries(args).map(([k, v]) => `${k}=${truncStr(String(v), Math.max(30, maxArg / 3))}`).join(", ");
10389
10521
  }
10390
10522
  }
10391
10523
  function truncStr(s, max) {
@@ -10401,7 +10533,7 @@ function formatDuration2(ms) {
10401
10533
  const secs = Math.floor(totalSecs % 60);
10402
10534
  return `${mins}m ${secs}s`;
10403
10535
  }
10404
- var isTTY2, c2, pastel, _emojisEnabled, _colorsEnabled, TOOL_ICONS, TOOL_LABELS, TOOL_COLORS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
10536
+ var isTTY2, c2, pastel, _emojisEnabled, _colorsEnabled, MD, TOOL_ICONS, TOOL_LABELS, TOOL_COLORS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
10405
10537
  var init_render = __esm({
10406
10538
  "packages/cli/dist/tui/render.js"() {
10407
10539
  "use strict";
@@ -10434,6 +10566,26 @@ var init_render = __esm({
10434
10566
  };
10435
10567
  _emojisEnabled = true;
10436
10568
  _colorsEnabled = true;
10569
+ MD = {
10570
+ heading1: 75,
10571
+ // blue
10572
+ heading2: 117,
10573
+ // sky blue
10574
+ heading3: 147,
10575
+ // light blue
10576
+ inlineCode: 223,
10577
+ // light peach
10578
+ link: 111,
10579
+ // periwinkle
10580
+ blockquote: 245,
10581
+ // grey
10582
+ hr: 240,
10583
+ // dark grey
10584
+ listBullet: 245,
10585
+ // grey
10586
+ tableBar: 245
10587
+ // grey
10588
+ };
10437
10589
  TOOL_ICONS = {
10438
10590
  file_read: "\u{1F4C4}",
10439
10591
  file_write: "\u{1F4DD}",
@@ -11430,7 +11582,7 @@ async function doSetup(config, rl) {
11430
11582
  }
11431
11583
  async function isModelAvailable(config) {
11432
11584
  try {
11433
- const models = await fetchOllamaModels(config.backendUrl);
11585
+ const models = await fetchModels(config.backendUrl, config.apiKey);
11434
11586
  return !!findModel(models, config.model);
11435
11587
  } catch {
11436
11588
  return false;
@@ -11805,7 +11957,7 @@ async function handleSlashCommand(input, ctx) {
11805
11957
  }
11806
11958
  async function listModels(ctx) {
11807
11959
  try {
11808
- const models = await fetchOllamaModels(ctx.config.backendUrl);
11960
+ const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
11809
11961
  renderModelList(models.map((m) => ({ name: m.name, size: m.size, modified: m.modified })), ctx.config.model);
11810
11962
  } catch (err) {
11811
11963
  renderError(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
@@ -11813,9 +11965,9 @@ async function listModels(ctx) {
11813
11965
  }
11814
11966
  async function showModelPicker(ctx) {
11815
11967
  try {
11816
- const models = await fetchOllamaModels(ctx.config.backendUrl);
11968
+ const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
11817
11969
  if (models.length === 0) {
11818
- renderWarning("No models found. Pull a model with: ollama pull <model>");
11970
+ renderWarning("No models found.");
11819
11971
  return;
11820
11972
  }
11821
11973
  renderModelList(models.map((m) => ({ name: m.name, size: m.size, modified: m.modified })), ctx.config.model);
@@ -12009,7 +12161,7 @@ async function handleUpdate(subcommand, ctx) {
12009
12161
  }
12010
12162
  async function switchModel(query, ctx, local = false) {
12011
12163
  try {
12012
- const models = await fetchOllamaModels(ctx.config.backendUrl);
12164
+ const models = await fetchModels(ctx.config.backendUrl, ctx.config.apiKey);
12013
12165
  const match = findModel(models, query);
12014
12166
  if (!match) {
12015
12167
  renderError(`Model not found: "${query}"`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.16.3",
3
+ "version": "0.16.5",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",