open-agents-ai 0.187.381 → 0.187.383

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 +198 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -529838,6 +529838,92 @@ function loadPendingTask(repoRoot) {
529838
529838
  return null;
529839
529839
  }
529840
529840
  }
529841
+ function normalizeSessionText(raw, maxLen = 500) {
529842
+ if (!raw) return "";
529843
+ return String(raw).replace(/\s+/g, " ").trim().slice(0, maxLen);
529844
+ }
529845
+ function normalizeList(items, maxItems) {
529846
+ if (!items || items.length === 0) return void 0;
529847
+ const seen = /* @__PURE__ */ new Set();
529848
+ const out = [];
529849
+ for (const item of items) {
529850
+ const clean3 = normalizeSessionText(item, 300);
529851
+ if (!clean3 || seen.has(clean3)) continue;
529852
+ seen.add(clean3);
529853
+ out.push(clean3);
529854
+ if (out.length >= maxItems) break;
529855
+ }
529856
+ return out.length > 0 ? out : void 0;
529857
+ }
529858
+ function normalizeSessionContextEntry(entry) {
529859
+ const normalized = {
529860
+ ...entry,
529861
+ savedAt: entry.savedAt || (/* @__PURE__ */ new Date()).toISOString(),
529862
+ task: cleanPromptForDiary(entry.task).slice(0, 500),
529863
+ summary: normalizeSessionText(entry.summary, 500),
529864
+ filesModified: normalizeList(entry.filesModified, 30) ?? [],
529865
+ toolCalls: Math.max(0, entry.toolCalls ?? 0),
529866
+ completed: Boolean(entry.completed),
529867
+ model: normalizeSessionText(entry.model, 160)
529868
+ };
529869
+ const toolsUsed = normalizeList(entry.toolsUsed, 12);
529870
+ if (toolsUsed) normalized.toolsUsed = toolsUsed;
529871
+ const provenance = normalizeSessionText(entry.provenance, 300);
529872
+ if (provenance) normalized.provenance = provenance;
529873
+ const assistantResponse = normalizeSessionText(entry.assistantResponse, 1200);
529874
+ if (assistantResponse) normalized.assistantResponse = assistantResponse;
529875
+ if (entry.source) normalized.source = entry.source;
529876
+ return normalized;
529877
+ }
529878
+ function sameStringArray(a2, b) {
529879
+ const left = a2 ?? [];
529880
+ const right = b ?? [];
529881
+ if (left.length !== right.length) return false;
529882
+ for (let i2 = 0; i2 < left.length; i2++) {
529883
+ if (left[i2] !== right[i2]) return false;
529884
+ }
529885
+ return true;
529886
+ }
529887
+ function lastMatchingIndex(items, predicate) {
529888
+ for (let i2 = items.length - 1; i2 >= 0; i2--) {
529889
+ if (predicate(items[i2])) return i2;
529890
+ }
529891
+ return -1;
529892
+ }
529893
+ function sameTask(a2, b) {
529894
+ return cleanPromptForDiary(a2.task) === cleanPromptForDiary(b.task);
529895
+ }
529896
+ function parseIsoMs(value2) {
529897
+ if (!value2) return null;
529898
+ const ms = Date.parse(value2);
529899
+ return Number.isFinite(ms) ? ms : null;
529900
+ }
529901
+ function isWithinReplaceWindow(a2, b) {
529902
+ const left = parseIsoMs(a2.savedAt);
529903
+ const right = parseIsoMs(b.savedAt);
529904
+ if (left == null || right == null) return true;
529905
+ return Math.abs(right - left) <= SAME_TASK_REPLACE_WINDOW_MS;
529906
+ }
529907
+ function isExactSessionDuplicate(a2, b) {
529908
+ return sameTask(a2, b) && a2.summary === b.summary && (a2.assistantResponse ?? "") === (b.assistantResponse ?? "") && sameStringArray(a2.filesModified, b.filesModified) && sameStringArray(a2.toolsUsed, b.toolsUsed) && (a2.provenance ?? "") === (b.provenance ?? "") && a2.toolCalls === b.toolCalls && a2.completed === b.completed && a2.model === b.model;
529909
+ }
529910
+ function mergeSessionContextEntry(previous, incoming) {
529911
+ return {
529912
+ ...previous,
529913
+ ...incoming,
529914
+ savedAt: incoming.savedAt || previous.savedAt,
529915
+ task: incoming.task || previous.task,
529916
+ summary: incoming.summary || previous.summary,
529917
+ assistantResponse: incoming.assistantResponse || previous.assistantResponse || incoming.summary || previous.summary,
529918
+ filesModified: incoming.filesModified.length > 0 ? incoming.filesModified : previous.filesModified,
529919
+ toolCalls: Math.max(previous.toolCalls ?? 0, incoming.toolCalls ?? 0),
529920
+ toolsUsed: incoming.toolsUsed && incoming.toolsUsed.length > 0 ? incoming.toolsUsed : previous.toolsUsed,
529921
+ provenance: incoming.provenance || previous.provenance,
529922
+ completed: previous.completed || incoming.completed,
529923
+ model: incoming.model || previous.model,
529924
+ source: incoming.source || previous.source
529925
+ };
529926
+ }
529841
529927
  function saveSessionContext(repoRoot, entry) {
529842
529928
  const contextDir = join75(repoRoot, OA_DIR, "context");
529843
529929
  mkdirSync32(contextDir, { recursive: true });
@@ -529852,7 +529938,33 @@ function saveSessionContext(repoRoot, entry) {
529852
529938
  } catch {
529853
529939
  ctx3 = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
529854
529940
  }
529855
- ctx3.entries.push(entry);
529941
+ const normalizedEntry = normalizeSessionContextEntry(entry);
529942
+ const exactIndex = lastMatchingIndex(
529943
+ ctx3.entries,
529944
+ (existing) => isExactSessionDuplicate(normalizeSessionContextEntry(existing), normalizedEntry)
529945
+ );
529946
+ if (exactIndex >= 0) {
529947
+ ctx3.entries[exactIndex] = mergeSessionContextEntry(ctx3.entries[exactIndex], normalizedEntry);
529948
+ } else {
529949
+ const relatedIndex = lastMatchingIndex(ctx3.entries, (existing) => {
529950
+ const normalizedExisting = normalizeSessionContextEntry(existing);
529951
+ return sameTask(normalizedExisting, normalizedEntry) && isWithinReplaceWindow(normalizedExisting, normalizedEntry);
529952
+ });
529953
+ if (relatedIndex >= 0) {
529954
+ const previous = normalizeSessionContextEntry(ctx3.entries[relatedIndex]);
529955
+ const shouldDropPartialResave = previous.completed && !normalizedEntry.completed;
529956
+ const shouldReplaceExisting = !previous.completed || previous.completed === normalizedEntry.completed && normalizedEntry.source === "manual";
529957
+ if (!shouldDropPartialResave) {
529958
+ if (shouldReplaceExisting) {
529959
+ ctx3.entries[relatedIndex] = mergeSessionContextEntry(ctx3.entries[relatedIndex], normalizedEntry);
529960
+ } else {
529961
+ ctx3.entries.push(normalizedEntry);
529962
+ }
529963
+ }
529964
+ } else {
529965
+ ctx3.entries.push(normalizedEntry);
529966
+ }
529967
+ }
529856
529968
  if (ctx3.entries.length > ctx3.maxEntries) {
529857
529969
  ctx3.entries = ctx3.entries.slice(-ctx3.maxEntries);
529858
529970
  }
@@ -529912,6 +530024,9 @@ function renderSessionDiary(entries) {
529912
530024
  if (e2.provenance) {
529913
530025
  lines.push(`- **Provenance:** ${e2.provenance}`);
529914
530026
  }
530027
+ if (e2.assistantResponse) {
530028
+ lines.push(`- **Assistant:** ${e2.assistantResponse.replace(/\s+/g, " ").trim().slice(0, 280)}`);
530029
+ }
529915
530030
  if (e2.summary) {
529916
530031
  const summary = e2.summary.replace(/\s+/g, " ").trim().slice(0, 280);
529917
530032
  lines.push(`- **Summary:** ${summary}`);
@@ -529935,22 +530050,35 @@ function buildContextRestorePrompt(repoRoot) {
529935
530050
  const ctx3 = loadSessionContext(repoRoot);
529936
530051
  if (!ctx3 || ctx3.entries.length === 0) return null;
529937
530052
  const recent = ctx3.entries.slice(-5);
529938
- const lines = recent.map((e2) => {
530053
+ const chronology = recent.map((e2) => {
529939
530054
  const status = e2.completed ? "done" : "partial";
529940
- const summary = e2.summary ? e2.summary.slice(0, 120) : e2.task.slice(0, 120);
530055
+ const summary = normalizeSessionText(e2.assistantResponse || e2.summary || e2.task, 140);
529941
530056
  const tools = e2.toolsUsed && e2.toolsUsed.length > 0 ? ` | tools: ${e2.toolsUsed.slice(0, 4).join(", ")}` : "";
529942
530057
  const files = e2.filesModified && e2.filesModified.length > 0 ? ` | files: ${e2.filesModified.slice(0, 3).join(", ")}` : "";
529943
530058
  return `[${status}] ${summary}${tools}${files}`;
529944
530059
  });
529945
530060
  const last2 = ctx3.entries[ctx3.entries.length - 1];
530061
+ const lastCompleted = [...ctx3.entries].reverse().find((entry) => entry.completed);
530062
+ const latestCompleted = lastCompleted ? `Latest completed task: ${normalizeSessionText(lastCompleted.assistantResponse || lastCompleted.summary || lastCompleted.task, 180)}` : "";
530063
+ const recentDialogue = recent.slice(-3).map((entry) => {
530064
+ const assistant = normalizeSessionText(entry.assistantResponse || entry.summary, 320) || "(no assistant reply captured)";
530065
+ const user = cleanPromptForDiary(entry.task).slice(0, 220);
530066
+ return `User: ${user}
530067
+ Assistant: ${assistant}`;
530068
+ }).join("\n\n");
529946
530069
  const prov = last2.provenance ? `
529947
530070
  Provenance: ${last2.provenance} (file_read to expand)` : "";
529948
530071
  const kg = `
529949
530072
  KG summary: .oa/context/kg-summary-latest.md (file_read to expand)`;
529950
530073
  return `<session-recap>
529951
- Previous work in this project:
529952
- ${lines.join("\n")}
529953
- Do not repeat completed work.${prov}${kg}
530074
+ Project chronology (older to newer):
530075
+ ${chronology.join("\n")}
530076
+ ` + (latestCompleted ? `
530077
+ ${latestCompleted}
530078
+ ` : "\n") + `
530079
+ Most recent exchanges (older to newer):
530080
+ ${recentDialogue}
530081
+ Continue from the latest exchange and do not repeat completed work.${prov}${kg}
529954
530082
  </session-recap>`;
529955
530083
  }
529956
530084
  function getLastTaskSummary(repoRoot) {
@@ -530236,7 +530364,7 @@ function deleteUsageRecord(kind, value2, repoRoot) {
530236
530364
  remove(join75(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
530237
530365
  }
530238
530366
  }
530239
- var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS2, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
530367
+ var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SAME_TASK_REPLACE_WINDOW_MS, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS2, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
530240
530368
  var init_oa_directory = __esm({
530241
530369
  "packages/cli/src/tui/oa-directory.ts"() {
530242
530370
  "use strict";
@@ -530255,6 +530383,7 @@ var init_oa_directory = __esm({
530255
530383
  PENDING_TASK_FILE = "pending-task.json";
530256
530384
  CONTEXT_SAVE_FILE = "session-context.json";
530257
530385
  MAX_CONTEXT_ENTRIES = 20;
530386
+ SAME_TASK_REPLACE_WINDOW_MS = 12 * 60 * 60 * 1e3;
530258
530387
  SESSIONS_DIR = "sessions";
530259
530388
  SESSIONS_INDEX = "sessions-index.json";
530260
530389
  SKIP_DIRS2 = /* @__PURE__ */ new Set([
@@ -532003,6 +532132,9 @@ var init_status_bar = __esm({
532003
532132
  // Since we're in alternate screen buffer, there's no native scrollback.
532004
532133
  // NOTE: _contentLines is now a reference to the ACTIVE view's buffer.
532005
532134
  _contentLines = [];
532135
+ /** Last buffered visible-line fingerprint — suppresses accidental double inserts */
532136
+ _lastBufferedFingerprint = "";
532137
+ _lastBufferedAt = 0;
532006
532138
  _contentScrollOffset = 0;
532007
532139
  // 0 = live (bottom), >0 = scrolled back
532008
532140
  _contentMaxLines = 1e4;
@@ -532924,6 +533056,8 @@ var init_status_bar = __esm({
532924
533056
  this._contentLines.splice(0, this._contentLines.length);
532925
533057
  this._contentScrollOffset = 0;
532926
533058
  this._inProgressLine = "";
533059
+ this._lastBufferedFingerprint = "";
533060
+ this._lastBufferedAt = 0;
532927
533061
  this._autoScroll = true;
532928
533062
  this.fillContentArea();
532929
533063
  this.renderFooterAndPositionInput();
@@ -533615,9 +533749,10 @@ var init_status_bar = __esm({
533615
533749
  self2._inProgressLine = combined.slice(lastNl + 1);
533616
533750
  const completeLines = completed.split("\n");
533617
533751
  for (const line of completeLines) {
533618
- const visible = line.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "");
533619
- if (line.length === 0 || visible.length > 0) {
533620
- self2.bufferContentLine(line);
533752
+ const sanitized = self2.sanitizeBufferedContentLine(line);
533753
+ const visible = stripAnsi(sanitized);
533754
+ if (sanitized.length === 0 || visible.length > 0) {
533755
+ self2.bufferContentLine(sanitized);
533621
533756
  }
533622
533757
  }
533623
533758
  }
@@ -533653,8 +533788,9 @@ ${CONTENT_BG_SEQ}`);
533653
533788
  this.writeDepth = Math.max(0, this.writeDepth - 1);
533654
533789
  if (this.writeDepth === 0) {
533655
533790
  if (this._inProgressLine.length > 0) {
533656
- const visible = this._inProgressLine.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "");
533657
- if (visible.length > 0) this.bufferContentLine(this._inProgressLine);
533791
+ const sanitized = this.sanitizeBufferedContentLine(this._inProgressLine);
533792
+ const visible = stripAnsi(sanitized);
533793
+ if (visible.length > 0) this.bufferContentLine(sanitized);
533658
533794
  this._inProgressLine = "";
533659
533795
  }
533660
533796
  this._bufferContent = false;
@@ -533707,7 +533843,15 @@ ${CONTENT_BG_SEQ}`);
533707
533843
  this.renderFooterAndPositionInput();
533708
533844
  }
533709
533845
  bufferContentLine(line) {
533710
- this._contentLines.push(line);
533846
+ const sanitized = this.sanitizeBufferedContentLine(line);
533847
+ const fingerprint = stripAnsi(sanitized).trim();
533848
+ const now = Date.now();
533849
+ if (fingerprint && fingerprint === this._lastBufferedFingerprint && now - this._lastBufferedAt < 50) {
533850
+ return;
533851
+ }
533852
+ this._lastBufferedFingerprint = fingerprint;
533853
+ this._lastBufferedAt = now;
533854
+ this._contentLines.push(sanitized);
533711
533855
  if (this._contentLines.length > this._contentMaxLines) {
533712
533856
  this._contentLines.splice(0, this._contentLines.length - this._contentMaxLines);
533713
533857
  if (this._contentScrollOffset > 0) {
@@ -533719,6 +533863,10 @@ ${CONTENT_BG_SEQ}`);
533719
533863
  }
533720
533864
  if (this._autoScroll && !this._mouseSelecting) this._contentScrollOffset = 0;
533721
533865
  }
533866
+ /** Keep SGR styling, drop replay-unsafe terminal control sequences from scrollback storage. */
533867
+ sanitizeBufferedContentLine(line) {
533868
+ return line.replace(/\r/g, "").replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, (seq) => seq.endsWith("m") ? seq : "");
533869
+ }
533722
533870
  /**
533723
533871
  * Remove the last N lines from the content scrollback buffer and repaint.
533724
533872
  * Used by Esc-to-recall to erase the just-rendered user prompt.
@@ -544417,6 +544565,16 @@ async function handleSlashCommand(input, ctx3) {
544417
544565
  case "color":
544418
544566
  case "colors":
544419
544567
  case "theme": {
544568
+ const colorAction = arg.toLowerCase();
544569
+ if (cmd !== "theme" && ["toggle", "on", "off", "enable", "disable"].includes(colorAction)) {
544570
+ const current = ctx3.getColors?.() ?? true;
544571
+ const next = colorAction === "on" || colorAction === "enable" ? true : colorAction === "off" || colorAction === "disable" ? false : !current;
544572
+ ctx3.setColors?.(next);
544573
+ const save2 = hasLocal ? ctx3.saveLocalSettings.bind(ctx3) : ctx3.saveSettings.bind(ctx3);
544574
+ save2({ colors: next });
544575
+ renderInfo2(`Colors ${next ? "enabled" : "disabled"}.${hasLocal ? " (project-local)" : ""}`);
544576
+ return "handled";
544577
+ }
544420
544578
  await showColorMenu(ctx3);
544421
544579
  return "handled";
544422
544580
  }
@@ -547713,16 +547871,6 @@ sleep 1
547713
547871
  renderInfo2(`Emojis ${next ? "enabled" : "disabled"}.`);
547714
547872
  return "handled";
547715
547873
  }
547716
- case "colors":
547717
- case "color": {
547718
- const current = ctx3.getColors?.() ?? true;
547719
- const next = !current;
547720
- ctx3.setColors?.(next);
547721
- const save2 = hasLocal ? ctx3.saveLocalSettings.bind(ctx3) : ctx3.saveSettings.bind(ctx3);
547722
- save2({ colors: next });
547723
- renderInfo2(`Colors ${next ? "enabled" : "disabled"}.`);
547724
- return "handled";
547725
- }
547726
547874
  case "pause": {
547727
547875
  if (!ctx3.hasActiveTask?.()) {
547728
547876
  renderWarning2("No active task to pause.");
@@ -556995,7 +557143,6 @@ function loadMemoryContext(repoRoot) {
556995
557143
  }
556996
557144
  function loadSessionHistory2(repoRoot) {
556997
557145
  const sessions2 = loadRecentSessions(repoRoot, 5);
556998
- if (sessions2.length === 0) return "";
556999
557146
  const lines = ["Recent tasks in this project:"];
557000
557147
  for (const s2 of sessions2) {
557001
557148
  if (!s2.startedAt || !s2.task) continue;
@@ -557008,7 +557155,20 @@ function loadSessionHistory2(repoRoot) {
557008
557155
  lines.push(` Summary: ${cleanSummary.slice(0, 120)}`);
557009
557156
  }
557010
557157
  }
557011
- return lines.join("\n");
557158
+ const sessionCtx = loadSessionContext(repoRoot);
557159
+ const exchanges = sessionCtx?.entries.slice(-2) ?? [];
557160
+ if (exchanges.length > 0) {
557161
+ if (lines.length > 1) lines.push("");
557162
+ lines.push("Most recent user/assistant chronology:");
557163
+ for (const entry of exchanges) {
557164
+ const user = cleanForStorage(entry.task) || entry.task;
557165
+ const assistant = cleanForStorage(entry.assistantResponse || entry.summary) || entry.assistantResponse || entry.summary;
557166
+ if (!assistant) continue;
557167
+ lines.push(`- User: ${user.slice(0, 120)}`);
557168
+ lines.push(` Assistant: ${assistant.slice(0, 160)}`);
557169
+ }
557170
+ }
557171
+ return lines.length > 1 ? lines.join("\n") : "";
557012
557172
  }
557013
557173
  function getEnvironment(repoRoot) {
557014
557174
  return [
@@ -566858,11 +567018,13 @@ async function handleContextSave(ctx3) {
566858
567018
  savedAt: (/* @__PURE__ */ new Date()).toISOString(),
566859
567019
  task: typeof body?.task === "string" ? body.task : typeof body?.prompt === "string" ? body.prompt : typeof body?.task_id === "string" ? body.task_id : `manual-${Date.now()}`,
566860
567020
  summary: typeof body?.summary === "string" ? body.summary : "",
567021
+ assistantResponse: typeof body?.assistant_response === "string" ? body.assistant_response : "",
566861
567022
  filesModified: Array.isArray(body?.files_modified) ? body.files_modified : [],
566862
567023
  toolCalls: typeof body?.tool_calls === "number" ? body.tool_calls : 0,
566863
567024
  completed: body?.completed !== false,
566864
567025
  // default true
566865
- model: typeof body?.model === "string" ? body.model : ""
567026
+ model: typeof body?.model === "string" ? body.model : "",
567027
+ source: "api"
566866
567028
  };
566867
567029
  saveSessionContext(repoRoot, entry);
566868
567030
  publishEvent("session.created", { task: entry.task.slice(0, 80) }, {
@@ -579633,7 +579795,6 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
579633
579795
  const modelTier = getModelTier(config.model);
579634
579796
  const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
579635
579797
  let dynamicContext = formatContextForPrompt(projectCtx, modelTier);
579636
- let _autoJumpedThisStream = false;
579637
579798
  const environmentProvider = () => {
579638
579799
  try {
579639
579800
  let env2 = formatSnapshotForContext(collectSnapshot(repoRoot));
@@ -580247,6 +580408,7 @@ ${entry.fullContent}`
580247
580408
  let toolCallStartMs = 0;
580248
580409
  let streamStartMs = 0;
580249
580410
  let streamTextBuffer = "";
580411
+ let lastAssistantText = "";
580250
580412
  let lastProvenancePath = null;
580251
580413
  let showLittleman = false;
580252
580414
  const littlemanBuffer = [];
@@ -580283,25 +580445,9 @@ ${entry.fullContent}`
580283
580445
  }
580284
580446
  if (statusBar?.isActive) {
580285
580447
  statusBar.beginContentWrite();
580286
- const alreadyBuffered = process.stdout.write.__oa_buffer_lines === true;
580287
- let postInterceptWrite = null;
580288
- if (!alreadyBuffered) {
580289
- postInterceptWrite = process.stdout.write;
580290
- const boundWrite = postInterceptWrite.bind(process.stdout);
580291
- process.stdout.write = ((chunk, ...args) => {
580292
- const text = typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk);
580293
- for (const line of text.split("\n")) {
580294
- if (line.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").length > 0) {
580295
- statusBar.bufferContentLine(line);
580296
- }
580297
- }
580298
- return boundWrite(chunk, ...args);
580299
- });
580300
- }
580301
580448
  try {
580302
580449
  fn();
580303
580450
  } finally {
580304
- if (postInterceptWrite) process.stdout.write = postInterceptWrite;
580305
580451
  statusBar.endContentWrite();
580306
580452
  }
580307
580453
  } else {
@@ -580444,7 +580590,6 @@ ${entry.fullContent}`
580444
580590
  case "stream_start":
580445
580591
  streamStartMs = Date.now();
580446
580592
  streamTextBuffer = "";
580447
- _autoJumpedThisStream = false;
580448
580593
  if (!isNeovimActive()) {
580449
580594
  if (stream?.enabled) {
580450
580595
  if (statusBar?.isActive) statusBar.beginContentWrite();
@@ -580463,15 +580608,6 @@ ${entry.fullContent}`
580463
580608
  writeToNeovimOutput(event.content);
580464
580609
  }
580465
580610
  } else if (stream?.enabled) {
580466
- if (statusBar?.isActive && statusBar.isScrolledBack && !_autoJumpedThisStream) {
580467
- if ((event.streamKind ?? "content") === "thinking") {
580468
- try {
580469
- statusBar.jumpToLive();
580470
- } catch {
580471
- }
580472
- _autoJumpedThisStream = true;
580473
- }
580474
- }
580475
580611
  stream.renderer.write(
580476
580612
  event.content ?? "",
580477
580613
  event.streamKind ?? "content"
@@ -580584,6 +580720,10 @@ ${entry.fullContent}`
580584
580720
  if (sudoCallback) sudoCallback(event.content ?? "");
580585
580721
  break;
580586
580722
  case "assistant_text":
580723
+ if (event.content) {
580724
+ const cleanAssistantText = cleanForStorage(event.content).trim();
580725
+ if (cleanAssistantText) lastAssistantText = cleanAssistantText;
580726
+ }
580587
580727
  if (_apiCallbacks?.onAssistantText && event.content) {
580588
580728
  _apiCallbacks.onAssistantText(event.content, event.turn ?? 0);
580589
580729
  }
@@ -580792,14 +580932,17 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
580792
580932
  } catch {
580793
580933
  }
580794
580934
  try {
580935
+ const assistantResponse = cleanForStorage(lastAssistantText || result.summary).slice(0, 1200);
580795
580936
  saveSessionContext(repoRoot, {
580796
580937
  savedAt: (/* @__PURE__ */ new Date()).toISOString(),
580797
580938
  task: cleanPromptForDiary(task).slice(0, 500),
580798
580939
  summary: result.summary.slice(0, 500),
580940
+ assistantResponse,
580799
580941
  filesModified: Array.from(filesTouched).slice(0, 30),
580800
580942
  toolCalls: result.toolCalls,
580801
580943
  completed: result.completed,
580802
- model: config.model
580944
+ model: config.model,
580945
+ source: "task_complete"
580803
580946
  });
580804
580947
  } catch {
580805
580948
  }
@@ -581562,7 +581705,6 @@ ${opts.systemPromptAddition}` : `Working directory: ${repoRoot}`;
581562
581705
  let adminSessionKey = null;
581563
581706
  const callSubAgents = /* @__PURE__ */ new Map();
581564
581707
  const streamRenderer = new StreamRenderer();
581565
- let _autoJumpedThisStream = false;
581566
581708
  if (savedSettings.voice) {
581567
581709
  if (savedSettings.voiceModel) {
581568
581710
  voiceEngine.modelId = savedSettings.voiceModel;
@@ -583891,6 +584033,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
583891
584033
  summary: `Manual context save. ${sessionToolCallCount} tool calls, ${sessionFilesTouched.length} files modified.`,
583892
584034
  filesModified: [...sessionFilesTouched],
583893
584035
  toolCalls: sessionToolCallCount,
584036
+ source: "manual",
583894
584037
  completed: false,
583895
584038
  model: currentConfig.model
583896
584039
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.381",
3
+ "version": "0.187.383",
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",