open-agents-ai 0.185.83 → 0.185.85

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 +167 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -65740,9 +65740,19 @@ async function sendMessage() {
65740
65740
 
65741
65741
  const msgDiv = addMessage('assistant', '');
65742
65742
  let fullContent = '';
65743
+ let chatTools = []; // tool calls collected during streaming
65744
+ let metaInfo = null; // completion metadata
65745
+
65746
+ // Tool calls container \u2014 shown live during streaming
65747
+ const toolsContainer = document.createElement('div');
65748
+ toolsContainer.style.cssText = 'margin:4px 0;font-size:0.7rem';
65749
+ msgDiv.appendChild(toolsContainer);
65750
+
65751
+ // Content container
65752
+ const contentDiv = document.createElement('div');
65753
+ msgDiv.appendChild(contentDiv);
65743
65754
 
65744
65755
  try {
65745
- // Use stateful /v1/chat endpoint (maintains OA identity + context)
65746
65756
  const body = {
65747
65757
  session_id: chatSessionId,
65748
65758
  model: modelSelect.value,
@@ -65757,7 +65767,6 @@ async function sendMessage() {
65757
65767
  body: JSON.stringify(body),
65758
65768
  });
65759
65769
 
65760
- // Capture session ID from response header
65761
65770
  const sid = response.headers.get('x-session-id');
65762
65771
  if (sid) chatSessionId = sid;
65763
65772
 
@@ -65779,10 +65788,38 @@ async function sendMessage() {
65779
65788
  if (data === '[DONE]') continue;
65780
65789
  try {
65781
65790
  const chunk = JSON.parse(data);
65791
+
65792
+ // Tool call event \u2014 show live
65793
+ if (chunk.type === 'tool_call') {
65794
+ chatTools.push(chunk);
65795
+ const toolEl = document.createElement('div');
65796
+ toolEl.style.cssText = 'background:#1e1e22;border-left:2px solid #b2920a;padding:4px 8px;margin:2px 0;color:#888';
65797
+ toolEl.textContent = '\\u25B8 ' + (chunk.tool || 'tool') + (chunk.args ? ': ' + JSON.stringify(chunk.args).slice(0,80) : '');
65798
+ toolsContainer.appendChild(toolEl);
65799
+ conv.scrollTop = conv.scrollHeight;
65800
+ continue;
65801
+ }
65802
+
65803
+ // Tool result
65804
+ if (chunk.type === 'tool_result') {
65805
+ const resultEl = document.createElement('div');
65806
+ resultEl.style.cssText = 'background:#1e1e22;padding:2px 8px 2px 18px;margin:0 0 2px 0;color:#555;font-size:0.65rem;max-height:60px;overflow:hidden';
65807
+ resultEl.textContent = (chunk.output || '').slice(0, 150);
65808
+ toolsContainer.appendChild(resultEl);
65809
+ continue;
65810
+ }
65811
+
65812
+ // Completion metadata
65813
+ if (chunk.type === 'complete') {
65814
+ metaInfo = chunk;
65815
+ continue;
65816
+ }
65817
+
65818
+ // Content delta
65782
65819
  const delta = chunk.choices?.[0]?.delta?.content || '';
65783
65820
  if (delta) {
65784
65821
  fullContent += delta;
65785
- msgDiv.innerHTML = renderMarkdown(fullContent);
65822
+ contentDiv.innerHTML = renderMarkdown(fullContent);
65786
65823
  conv.scrollTop = conv.scrollHeight;
65787
65824
  }
65788
65825
  } catch {}
@@ -65790,9 +65827,23 @@ async function sendMessage() {
65790
65827
  }
65791
65828
 
65792
65829
  messages.push({ role: 'assistant', content: fullContent });
65793
- updateTokenCounter(fullContent.split(/\\s+/).length * 1.3 | 0); // rough token estimate
65794
- // Re-render with copy button
65795
- msgDiv.innerHTML = renderMarkdown(fullContent);
65830
+ updateTokenCounter(fullContent.split(/\\s+/).length * 1.3 | 0);
65831
+
65832
+ // Final render: content + collapsible tools
65833
+ contentDiv.innerHTML = renderMarkdown(fullContent);
65834
+
65835
+ // Collapse tool calls into a dropdown after streaming completes
65836
+ if (chatTools.length > 0) {
65837
+ const details = document.createElement('details');
65838
+ details.style.cssText = 'margin:4px 0;font-size:0.65rem;color:#555';
65839
+ const summary = document.createElement('summary');
65840
+ summary.style.cssText = 'cursor:pointer;color:#b2920a;font-size:0.65rem';
65841
+ summary.textContent = chatTools.length + ' tool call' + (chatTools.length > 1 ? 's' : '') + (metaInfo?.tokens ? ' | ' + metaInfo.tokens + ' tokens' : '') + (metaInfo?.duration ? ' | ' + (metaInfo.duration/1000).toFixed(1) + 's' : '');
65842
+ details.appendChild(summary);
65843
+ // Move live tool elements into the details
65844
+ while (toolsContainer.firstChild) details.appendChild(toolsContainer.firstChild);
65845
+ toolsContainer.appendChild(details);
65846
+ }
65796
65847
  const actions = document.createElement('div');
65797
65848
  actions.className = 'msg-actions';
65798
65849
  const copyBtn = document.createElement('button');
@@ -67967,14 +68018,27 @@ Respond conversationally. Call task_complete with your final response.`;
67967
68018
  });
67968
68019
  let fullContent = "";
67969
68020
  let lastOutput = "";
68021
+ let toolCalls = [];
68022
+ let rawBuffer = "";
67970
68023
  child.stdout?.on("data", (chunk) => {
67971
- const text = chunk.toString();
67972
- for (const line of text.split("\n")) {
68024
+ rawBuffer += chunk.toString();
68025
+ const lines = rawBuffer.split("\n");
68026
+ rawBuffer = lines.pop() || "";
68027
+ for (const line of lines) {
67973
68028
  if (!line.trim())
67974
68029
  continue;
67975
68030
  try {
67976
68031
  const evt = JSON.parse(line);
67977
- if (evt.type === "assistant_text" || evt.type === "text") {
68032
+ if (evt.type === "tool_call" || evt.tool) {
68033
+ const toolInfo = { tool: evt.tool || evt.name || "unknown", args: evt.args };
68034
+ toolCalls.push(toolInfo);
68035
+ res.write("data: " + JSON.stringify({ type: "tool_call", ...toolInfo }) + "\n\n");
68036
+ } else if (evt.type === "tool_result") {
68037
+ const lastTool = toolCalls[toolCalls.length - 1];
68038
+ if (lastTool)
68039
+ lastTool.result = (evt.output || evt.result || "").slice(0, 500);
68040
+ res.write("data: " + JSON.stringify({ type: "tool_result", output: (evt.output || evt.result || "").slice(0, 200) }) + "\n\n");
68041
+ } else if (evt.type === "assistant_text" || evt.type === "text") {
67978
68042
  const delta = evt.content || evt.text || "";
67979
68043
  fullContent += delta;
67980
68044
  res.write("data: " + JSON.stringify({
@@ -67982,33 +68046,77 @@ Respond conversationally. Call task_complete with your final response.`;
67982
68046
  object: "chat.completion.chunk",
67983
68047
  choices: [{ index: 0, delta: { content: delta }, finish_reason: null }]
67984
68048
  }) + "\n\n");
67985
- } else if (evt.type === "tool_call") {
68049
+ } else if (evt.status === "completed" || evt.type === "task_complete") {
68050
+ const summary = evt.summary || evt.content || "";
68051
+ const contentMatch = summary.match(/Tokens:\s*[\d,]+\s+(.*)/s);
68052
+ const cleanContent = contentMatch ? contentMatch[1].trim() : summary;
68053
+ if (cleanContent && cleanContent.length > 5) {
68054
+ fullContent = cleanContent;
68055
+ res.write("data: " + JSON.stringify({
68056
+ id: `chatcmpl-${session.id.slice(0, 8)}`,
68057
+ object: "chat.completion.chunk",
68058
+ choices: [{ index: 0, delta: { content: cleanContent }, finish_reason: null }]
68059
+ }) + "\n\n");
68060
+ }
67986
68061
  res.write("data: " + JSON.stringify({
67987
- type: "tool_call",
67988
- tool: evt.tool || evt.name,
67989
- args: evt.args
68062
+ type: "complete",
68063
+ turns: evt.turns || summary.match(/(\d+) turns/)?.[1],
68064
+ toolCalls: toolCalls.length,
68065
+ tokens: evt.tokens || summary.match(/Tokens:\s*([\d,]+)/)?.[1],
68066
+ duration: evt.durationMs || evt.duration
67990
68067
  }) + "\n\n");
67991
- } else if (evt.type === "task_complete") {
67992
- const summary = evt.summary || evt.content || "";
67993
- if (summary && !fullContent.includes(summary))
67994
- fullContent += summary;
67995
68068
  }
67996
- lastOutput = line;
67997
68069
  } catch {
67998
- if (line.trim() && !line.startsWith("{")) {
67999
- fullContent += line;
68070
+ }
68071
+ }
68072
+ });
68073
+ child.stderr?.on("data", () => {
68074
+ });
68075
+ child.on("close", () => {
68076
+ if (rawBuffer.trim()) {
68077
+ for (const line of rawBuffer.split("\n")) {
68078
+ if (!line.trim())
68079
+ continue;
68080
+ try {
68081
+ const evt = JSON.parse(line);
68082
+ if (evt.type === "text" && evt.content && !fullContent.includes(evt.content)) {
68083
+ fullContent += evt.content + "\n";
68084
+ res.write("data: " + JSON.stringify({
68085
+ id: `chatcmpl-${session.id.slice(0, 8)}`,
68086
+ object: "chat.completion.chunk",
68087
+ choices: [{ index: 0, delta: { content: evt.content + "\n" }, finish_reason: null }]
68088
+ }) + "\n\n");
68089
+ }
68090
+ } catch {
68091
+ }
68092
+ }
68093
+ }
68094
+ if (!fullContent) {
68095
+ try {
68096
+ const result = JSON.parse(rawBuffer.trim().split("\n").pop() || "{}");
68097
+ const summary = result.summary || result.text || "";
68098
+ const match = summary.match ? summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/) : null;
68099
+ const cleanContent = match ? match[1].trim() : result.text || summary;
68100
+ if (cleanContent) {
68101
+ fullContent = cleanContent;
68000
68102
  res.write("data: " + JSON.stringify({
68001
68103
  id: `chatcmpl-${session.id.slice(0, 8)}`,
68002
68104
  object: "chat.completion.chunk",
68003
- choices: [{ index: 0, delta: { content: line }, finish_reason: null }]
68105
+ choices: [{ index: 0, delta: { content: cleanContent }, finish_reason: null }]
68106
+ }) + "\n\n");
68107
+ const turns = summary.match(/(\d+) turns/)?.[1];
68108
+ const tokens = summary.match(/Tokens:\s*([\d,]+)/)?.[1];
68109
+ res.write("data: " + JSON.stringify({
68110
+ type: "complete",
68111
+ turns,
68112
+ tokens,
68113
+ duration: result.durationMs,
68114
+ toolCalls: parseInt(summary.match(/(\d+) tool calls/)?.[1] || "0", 10)
68004
68115
  }) + "\n\n");
68005
68116
  }
68117
+ } catch {
68006
68118
  }
68007
68119
  }
68008
- });
68009
- child.stderr?.on("data", () => {
68010
- });
68011
- child.on("close", () => {
68012
68120
  addAssistantMessage(session, fullContent);
68013
68121
  res.write("data: [DONE]\n\n");
68014
68122
  res.end();
@@ -68022,18 +68130,28 @@ Respond conversationally. Call task_complete with your final response.`;
68022
68130
  });
68023
68131
  await new Promise((resolve36) => child.on("close", resolve36));
68024
68132
  let content = "";
68133
+ let summaryContent = "";
68025
68134
  for (const line of output.split("\n")) {
68135
+ if (!line.trim())
68136
+ continue;
68026
68137
  try {
68027
68138
  const evt = JSON.parse(line);
68028
- if (evt.type === "assistant_text" || evt.type === "text")
68029
- content += evt.content || evt.text || "";
68030
- else if (evt.type === "task_complete")
68031
- content += evt.summary || evt.content || "";
68139
+ if (evt.type === "text" && evt.content) {
68140
+ content += evt.content + "\n";
68141
+ } else if (evt.status === "completed" || evt.status === "failed") {
68142
+ if (evt.text)
68143
+ content = evt.text;
68144
+ if (!content.trim()) {
68145
+ const summary = evt.summary || "";
68146
+ const match = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
68147
+ summaryContent = match ? match[1].trim() : summary;
68148
+ }
68149
+ }
68032
68150
  } catch {
68033
- if (line.trim() && !line.startsWith("{"))
68034
- content += line + "\n";
68035
68151
  }
68036
68152
  }
68153
+ if (!content.trim())
68154
+ content = summaryContent;
68037
68155
  addAssistantMessage(session, content.trim());
68038
68156
  jsonResponse(res, 200, {
68039
68157
  session_id: session.id,
@@ -73520,12 +73638,25 @@ async function runCommand(opts, config) {
73520
73638
  async function runJson(task, config, repoPath) {
73521
73639
  const startTime = Date.now();
73522
73640
  const origWrite = process.stdout.write.bind(process.stdout);
73641
+ const origStderr = process.stderr.write.bind(process.stderr);
73523
73642
  const captured = [];
73643
+ let assistantText = "";
73644
+ let textBuffer = "";
73524
73645
  process.stdout.write = ((chunk, ...args) => {
73525
- if (typeof chunk === "string")
73646
+ if (typeof chunk === "string") {
73526
73647
  captured.push(chunk);
73648
+ const clean = chunk.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").replace(/\x1B\].*?\x07/g, "").replace(/\x1B[78]/g, "");
73649
+ if (clean.trim()) {
73650
+ const stripped = clean.replace(/[▸▹⎿]/g, "").trim();
73651
+ if (stripped.length > 0 && !stripped.startsWith("\x1B") && stripped.length < 5e3) {
73652
+ textBuffer += stripped + "\n";
73653
+ origWrite(JSON.stringify({ type: "text", content: stripped }) + "\n");
73654
+ }
73655
+ }
73656
+ }
73527
73657
  return true;
73528
73658
  });
73659
+ process.stderr.write = (() => true);
73529
73660
  let result;
73530
73661
  try {
73531
73662
  await runWithTUI(task, config, repoPath);
@@ -73544,6 +73675,10 @@ async function runJson(task, config, repoPath) {
73544
73675
  };
73545
73676
  }
73546
73677
  process.stdout.write = origWrite;
73678
+ process.stderr.write = origStderr;
73679
+ if (textBuffer.trim()) {
73680
+ result.text = textBuffer.trim();
73681
+ }
73547
73682
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
73548
73683
  if (result.exitCode !== 0)
73549
73684
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.185.83",
3
+ "version": "0.185.85",
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",