open-agents-ai 0.186.3 → 0.186.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 +110 -74
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -65572,6 +65572,9 @@ body {
65572
65572
  <button class="tab" onclick="switchTab('jobs')" id="tab-jobs" style="background:none;border:none;border-bottom:2px solid transparent;color:#555;padding:6px 16px;font-family:inherit;font-size:0.7rem;cursor:pointer">dashboard</button>
65573
65573
  <button class="tab" onclick="switchTab('config')" id="tab-config" style="background:none;border:none;border-bottom:2px solid transparent;color:#555;padding:6px 16px;font-family:inherit;font-size:0.7rem;cursor:pointer">config</button>
65574
65574
  <button class="tab" onclick="switchTab('activity')" id="tab-activity" style="background:none;border:none;border-bottom:2px solid transparent;color:#555;padding:6px 16px;font-family:inherit;font-size:0.7rem;cursor:pointer">activity</button>
65575
+ <select id="session-select" onchange="switchSession(this.value)" style="background:#2a2a30;border:1px solid #3a3a42;color:#b0b0b0;padding:2px 6px;border-radius:3px;font-family:inherit;font-size:0.6rem;max-width:140px" title="Chat sessions">
65576
+ <option value="">new session</option>
65577
+ </select>
65575
65578
  <span id="sys-metrics" style="margin-left:auto;font-size:0.6rem;color:#555"></span>
65576
65579
  <span id="token-counter" style="font-size:0.6rem;color:#555">0 tokens</span>
65577
65580
  </div>
@@ -65637,6 +65640,7 @@ body {
65637
65640
  <span id="system-prompt-toggle" onclick="toggleSystemPrompt()">sys</span>
65638
65641
  <textarea id="input-area" placeholder="Type a message..." rows="1"></textarea>
65639
65642
  <button id="send-btn" onclick="sendMessage()">send</button>
65643
+ <button id="stop-btn" onclick="stopChat()" style="display:none;background:#2a2a30;border:1px solid #ff4444;color:#ff4444;padding:8px 16px;border-radius:3px;font-family:inherit;font-size:0.75rem;cursor:pointer;flex-shrink:0">stop</button>
65640
65644
  </div>
65641
65645
 
65642
65646
  <div id="key-modal">
@@ -65660,7 +65664,8 @@ const statusEl = document.getElementById('status');
65660
65664
  let apiKey = localStorage.getItem('oa-api-key') || '';
65661
65665
  let streaming = false;
65662
65666
  let messages = [];
65663
- let chatSessionId = null; // stateful session for /v1/chat
65667
+ let chatSessionId = null;
65668
+ let chatAbortController = null; // for stop button
65664
65669
 
65665
65670
  // Auto-resize textarea
65666
65671
  input.addEventListener('input', () => {
@@ -65759,8 +65764,9 @@ async function sendMessage() {
65759
65764
  const sysPrompt = document.getElementById('system-prompt').value.trim();
65760
65765
 
65761
65766
  streaming = true;
65762
- sendBtn.disabled = true;
65763
- sendBtn.textContent = '...';
65767
+ chatAbortController = new AbortController();
65768
+ document.getElementById('send-btn').style.display = 'none';
65769
+ document.getElementById('stop-btn').style.display = 'inline-block';
65764
65770
 
65765
65771
  const msgDiv = addMessage('assistant', '');
65766
65772
  let fullContent = '';
@@ -65789,6 +65795,7 @@ async function sendMessage() {
65789
65795
  method: 'POST',
65790
65796
  headers: headers(),
65791
65797
  body: JSON.stringify(body),
65798
+ signal: chatAbortController.signal,
65792
65799
  });
65793
65800
 
65794
65801
  const sid = response.headers.get('x-session-id');
@@ -65852,6 +65859,7 @@ async function sendMessage() {
65852
65859
 
65853
65860
  messages.push({ role: 'assistant', content: fullContent });
65854
65861
  updateTokenCounter(fullContent.split(/\\s+/).length * 1.3 | 0);
65862
+ saveSessions(); // persist to localStorage
65855
65863
 
65856
65864
  // Final render: content + collapsible tools + metadata
65857
65865
  contentDiv.innerHTML = renderMarkdown(fullContent);
@@ -65894,8 +65902,9 @@ async function sendMessage() {
65894
65902
  }
65895
65903
 
65896
65904
  streaming = false;
65897
- sendBtn.disabled = false;
65898
- sendBtn.textContent = 'send';
65905
+ chatAbortController = null;
65906
+ document.getElementById('send-btn').style.display = 'inline-block';
65907
+ document.getElementById('stop-btn').style.display = 'none';
65899
65908
  conv.scrollTop = conv.scrollHeight;
65900
65909
  }
65901
65910
 
@@ -66251,6 +66260,73 @@ async function loadJobs() {
66251
66260
  } catch { list.innerHTML = '<div style="color:#ff4444">Failed to load jobs</div>'; }
66252
66261
  }
66253
66262
 
66263
+ // Session storage (localStorage for persistence across page reloads)
66264
+ function saveSessions() {
66265
+ const saved = JSON.parse(localStorage.getItem('oa-sessions') || '{}');
66266
+ if (chatSessionId) {
66267
+ saved[chatSessionId] = {
66268
+ id: chatSessionId,
66269
+ messages: messages,
66270
+ model: modelSelect.value,
66271
+ updatedAt: new Date().toISOString(),
66272
+ preview: messages.slice(-1)[0]?.content?.slice(0, 50) || 'empty',
66273
+ };
66274
+ }
66275
+ localStorage.setItem('oa-sessions', JSON.stringify(saved));
66276
+ updateSessionSelect();
66277
+ }
66278
+
66279
+ function updateSessionSelect() {
66280
+ const sel = document.getElementById('session-select');
66281
+ const saved = JSON.parse(localStorage.getItem('oa-sessions') || '{}');
66282
+ sel.innerHTML = '<option value="">+ new session</option>';
66283
+ for (const [id, s] of Object.entries(saved).sort((a,b) => (b[1].updatedAt || '').localeCompare(a[1].updatedAt || '')).slice(0, 10)) {
66284
+ const opt = document.createElement('option');
66285
+ opt.value = id;
66286
+ opt.textContent = (s.preview || 'session').slice(0, 30);
66287
+ if (id === chatSessionId) opt.selected = true;
66288
+ sel.appendChild(opt);
66289
+ }
66290
+ }
66291
+
66292
+ function switchSession(id) {
66293
+ // Save current session first
66294
+ saveSessions();
66295
+ if (!id) {
66296
+ // New session
66297
+ chatSessionId = null;
66298
+ messages = [];
66299
+ document.getElementById('conversation').innerHTML = '';
66300
+ return;
66301
+ }
66302
+ const saved = JSON.parse(localStorage.getItem('oa-sessions') || '{}');
66303
+ const s = saved[id];
66304
+ if (s) {
66305
+ chatSessionId = id;
66306
+ messages = s.messages || [];
66307
+ // Re-render messages
66308
+ const conv = document.getElementById('conversation');
66309
+ conv.innerHTML = '';
66310
+ for (const m of messages) {
66311
+ addMessage(m.role, m.content);
66312
+ }
66313
+ }
66314
+ }
66315
+
66316
+ // Auto-save after each message
66317
+ const origAddAssistant = null; // will hook into message flow
66318
+
66319
+ // Stop running chat
66320
+ function stopChat() {
66321
+ if (chatAbortController) {
66322
+ chatAbortController.abort();
66323
+ chatAbortController = null;
66324
+ }
66325
+ streaming = false;
66326
+ document.getElementById('send-btn').style.display = 'inline-block';
66327
+ document.getElementById('stop-btn').style.display = 'none';
66328
+ }
66329
+
66254
66330
  // Workspace sidebar
66255
66331
  function toggleWorkspace() {
66256
66332
  const sb = document.getElementById('workspace-sidebar');
@@ -66314,6 +66390,7 @@ function doUpdate() {
66314
66390
  checkHealth();
66315
66391
  loadModels();
66316
66392
  pollMetrics();
66393
+ updateSessionSelect();
66317
66394
  setInterval(checkHealth, 30000);
66318
66395
  setInterval(pollMetrics, 10000);
66319
66396
  input.focus();
@@ -68116,89 +68193,46 @@ Respond conversationally. Call task_complete with your final response.`;
68116
68193
  "X-Session-ID": session.id
68117
68194
  });
68118
68195
  let fullContent = "";
68119
- let lastOutput = "";
68120
- let toolCalls = [];
68121
- let rawBuffer = "";
68196
+ let rawOutput = "";
68122
68197
  child.stdout?.on("data", (chunk) => {
68123
- rawBuffer += chunk.toString();
68124
- const lines = rawBuffer.split("\n");
68125
- rawBuffer = lines.pop() || "";
68126
- for (const line of lines) {
68127
- if (!line.trim())
68128
- continue;
68129
- try {
68130
- const evt = JSON.parse(line);
68131
- if (evt.type === "tool_call" || evt.tool) {
68132
- const toolInfo = { tool: evt.tool || evt.name || "unknown", args: evt.args };
68133
- toolCalls.push(toolInfo);
68134
- res.write("data: " + JSON.stringify({ type: "tool_call", ...toolInfo }) + "\n\n");
68135
- } else if (evt.type === "tool_result") {
68136
- const lastTool = toolCalls[toolCalls.length - 1];
68137
- if (lastTool)
68138
- lastTool.result = (evt.output || evt.result || "").slice(0, 500);
68139
- res.write("data: " + JSON.stringify({ type: "tool_result", output: (evt.output || evt.result || "").slice(0, 200) }) + "\n\n");
68140
- } else if (evt.type === "assistant_text" || evt.type === "text") {
68141
- const delta = evt.content || evt.text || "";
68142
- fullContent += delta;
68143
- res.write("data: " + JSON.stringify({
68144
- id: `chatcmpl-${session.id.slice(0, 8)}`,
68145
- object: "chat.completion.chunk",
68146
- choices: [{ index: 0, delta: { content: delta }, finish_reason: null }]
68147
- }) + "\n\n");
68148
- } else if (evt.status === "completed" || evt.type === "task_complete") {
68149
- const summary = evt.summary || evt.content || "";
68150
- const contentMatch = summary.match(/Tokens:\s*[\d,]+\s+(.*)/s);
68151
- const cleanContent = contentMatch ? contentMatch[1].trim() : summary;
68152
- if (cleanContent && cleanContent.length > 5) {
68153
- fullContent = cleanContent;
68154
- res.write("data: " + JSON.stringify({
68155
- id: `chatcmpl-${session.id.slice(0, 8)}`,
68156
- object: "chat.completion.chunk",
68157
- choices: [{ index: 0, delta: { content: cleanContent }, finish_reason: null }]
68158
- }) + "\n\n");
68159
- }
68160
- res.write("data: " + JSON.stringify({
68161
- type: "complete",
68162
- turns: evt.turns || summary.match(/(\d+) turns/)?.[1],
68163
- toolCalls: toolCalls.length,
68164
- tokens: evt.tokens || summary.match(/Tokens:\s*([\d,]+)/)?.[1],
68165
- duration: evt.durationMs || evt.duration
68166
- }) + "\n\n");
68167
- }
68168
- } catch {
68169
- }
68170
- }
68198
+ rawOutput += chunk.toString();
68171
68199
  });
68172
68200
  child.stderr?.on("data", () => {
68173
68201
  });
68174
- child.on("close", () => {
68175
- if (!fullContent) {
68176
- const allOutput = rawBuffer.trim();
68202
+ await new Promise((resolve36) => {
68203
+ child.on("close", () => {
68177
68204
  try {
68178
- const result = JSON.parse(allOutput);
68205
+ const result = JSON.parse(rawOutput.trim());
68179
68206
  let content = result.assistant_text || "";
68180
68207
  if (!content) {
68181
68208
  const summary = result.summary || "";
68182
- const summaryMatch = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
68183
- content = summaryMatch ? summaryMatch[1].trim() : summary;
68209
+ const match = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
68210
+ content = match ? match[1].trim() : summary;
68184
68211
  }
68185
68212
  fullContent = content;
68186
- res.write("data: " + JSON.stringify({
68187
- id: `chatcmpl-${session.id.slice(0, 8)}`,
68188
- object: "chat.completion.chunk",
68189
- choices: [{ index: 0, delta: { content }, finish_reason: null }]
68190
- }) + "\n\n");
68213
+ if (content) {
68214
+ res.write("data: " + JSON.stringify({
68215
+ id: `chatcmpl-${session.id.slice(0, 8)}`,
68216
+ object: "chat.completion.chunk",
68217
+ choices: [{ index: 0, delta: { content }, finish_reason: null }]
68218
+ }) + "\n\n");
68219
+ }
68220
+ if (result.tool_calls?.length) {
68221
+ for (const tc of result.tool_calls) {
68222
+ res.write("data: " + JSON.stringify({ type: "tool_call", tool: tc.tool, args: tc.args }) + "\n\n");
68223
+ }
68224
+ }
68191
68225
  const meta = result.summary || "";
68192
68226
  res.write("data: " + JSON.stringify({
68193
68227
  type: "complete",
68194
68228
  turns: meta.match(/(\d+) turns/)?.[1],
68195
68229
  tokens: meta.match(/Tokens:\s*([\d,]+)/)?.[1],
68196
- toolCalls: parseInt(meta.match(/(\d+) tool calls/)?.[1] || "0", 10),
68230
+ toolCalls: result.tool_calls?.length || 0,
68197
68231
  duration: result.durationMs
68198
68232
  }) + "\n\n");
68199
68233
  } catch {
68200
- if (allOutput) {
68201
- fullContent = allOutput.slice(0, 500);
68234
+ if (rawOutput.trim()) {
68235
+ fullContent = rawOutput.trim().slice(0, 500);
68202
68236
  res.write("data: " + JSON.stringify({
68203
68237
  id: `chatcmpl-${session.id.slice(0, 8)}`,
68204
68238
  object: "chat.completion.chunk",
@@ -68206,11 +68240,13 @@ Respond conversationally. Call task_complete with your final response.`;
68206
68240
  }) + "\n\n");
68207
68241
  }
68208
68242
  }
68209
- }
68210
- addAssistantMessage(session, fullContent);
68211
- res.write("data: [DONE]\n\n");
68212
- res.end();
68243
+ addAssistantMessage(session, fullContent);
68244
+ res.write("data: [DONE]\n\n");
68245
+ res.end();
68246
+ resolve36();
68247
+ });
68213
68248
  });
68249
+ return;
68214
68250
  } else {
68215
68251
  let output = "";
68216
68252
  child.stdout?.on("data", (chunk) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.186.3",
3
+ "version": "0.186.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",