open-agents-ai 0.31.7 → 0.31.8

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 +161 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15002,6 +15002,9 @@ function renderSlashHelp() {
15002
15002
  ["/stop", "Kill current inference immediately and save state (/resume to continue)"],
15003
15003
  ["/resume", "Resume a paused or stopped task"],
15004
15004
  ["/destroy", "Remove .oa folder, kill all tasks, clear console, and exit"],
15005
+ ["/context save", "Force-save session context to .oa/context/"],
15006
+ ["/context restore", "Restore context from previous sessions into next task"],
15007
+ ["/context show", "Show saved session context status"],
15005
15008
  ["/compact", "Force context compaction now (default strategy)"],
15006
15009
  ["/compact <strategy>", "Compact with strategy: aggressive, decisions, errors, summary, structured"],
15007
15010
  ["/bruteforce", "Toggle brute-force mode (auto re-engage on turn limit)"],
@@ -15793,6 +15796,61 @@ function loadPendingTask(repoRoot) {
15793
15796
  return null;
15794
15797
  }
15795
15798
  }
15799
+ function saveSessionContext(repoRoot, entry) {
15800
+ const contextDir = join24(repoRoot, OA_DIR, "context");
15801
+ mkdirSync6(contextDir, { recursive: true });
15802
+ const filePath = join24(contextDir, CONTEXT_SAVE_FILE);
15803
+ let ctx;
15804
+ try {
15805
+ if (existsSync18(filePath)) {
15806
+ ctx = JSON.parse(readFileSync13(filePath, "utf-8"));
15807
+ } else {
15808
+ ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
15809
+ }
15810
+ } catch {
15811
+ ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
15812
+ }
15813
+ ctx.entries.push(entry);
15814
+ if (ctx.entries.length > ctx.maxEntries) {
15815
+ ctx.entries = ctx.entries.slice(-ctx.maxEntries);
15816
+ }
15817
+ ctx.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
15818
+ writeFileSync6(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
15819
+ }
15820
+ function loadSessionContext(repoRoot) {
15821
+ const filePath = join24(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
15822
+ try {
15823
+ if (!existsSync18(filePath))
15824
+ return null;
15825
+ return JSON.parse(readFileSync13(filePath, "utf-8"));
15826
+ } catch {
15827
+ return null;
15828
+ }
15829
+ }
15830
+ function buildContextRestorePrompt(repoRoot) {
15831
+ const ctx = loadSessionContext(repoRoot);
15832
+ if (!ctx || ctx.entries.length === 0)
15833
+ return null;
15834
+ const lines = [
15835
+ "[RESTORED SESSION CONTEXT] Previous session history for this project:",
15836
+ ""
15837
+ ];
15838
+ const recentEntries = ctx.entries.slice(-10);
15839
+ for (const entry of recentEntries) {
15840
+ const status = entry.completed ? "COMPLETED" : "INCOMPLETE";
15841
+ const date = new Date(entry.savedAt).toLocaleString();
15842
+ lines.push(`[${status}] ${date} \u2014 ${entry.task.slice(0, 200)}`);
15843
+ if (entry.summary) {
15844
+ lines.push(` Summary: ${entry.summary.slice(0, 300)}`);
15845
+ }
15846
+ if (entry.filesModified.length > 0) {
15847
+ lines.push(` Files: ${entry.filesModified.slice(0, 10).join(", ")}`);
15848
+ }
15849
+ lines.push("");
15850
+ }
15851
+ lines.push("Use this context to understand what has been done previously. Do not repeat completed work.");
15852
+ return lines.join("\n");
15853
+ }
15796
15854
  function detectManifests(repoRoot) {
15797
15855
  const manifests = [];
15798
15856
  const checks = [
@@ -15886,7 +15944,7 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
15886
15944
  }
15887
15945
  return result;
15888
15946
  }
15889
- var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, SKIP_DIRS;
15947
+ var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SKIP_DIRS;
15890
15948
  var init_oa_directory = __esm({
15891
15949
  "packages/cli/dist/tui/oa-directory.js"() {
15892
15950
  "use strict";
@@ -15903,6 +15961,8 @@ var init_oa_directory = __esm({
15903
15961
  "AGENTS.md"
15904
15962
  ];
15905
15963
  PENDING_TASK_FILE = "pending-task.json";
15964
+ CONTEXT_SAVE_FILE = "session-context.json";
15965
+ MAX_CONTEXT_ENTRIES = 20;
15906
15966
  SKIP_DIRS = /* @__PURE__ */ new Set([
15907
15967
  "node_modules",
15908
15968
  ".git",
@@ -17502,6 +17562,53 @@ async function handleSlashCommand(input, ctx) {
17502
17562
  ctx.destroyProject?.();
17503
17563
  return "exit";
17504
17564
  }
17565
+ case "context": {
17566
+ const subCmd = arg?.toLowerCase().split(/\s+/)[0] || "";
17567
+ switch (subCmd) {
17568
+ case "save": {
17569
+ const ok = ctx.contextSave?.() ?? false;
17570
+ if (ok) {
17571
+ renderInfo("Session context saved to .oa/context/. Will auto-restore on next /context restore.");
17572
+ } else {
17573
+ renderWarning("Could not save session context.");
17574
+ }
17575
+ break;
17576
+ }
17577
+ case "restore": {
17578
+ if (ctx.hasActiveTask?.()) {
17579
+ renderWarning("Cannot restore context while a task is running.");
17580
+ break;
17581
+ }
17582
+ const prompt = ctx.contextRestore?.();
17583
+ if (prompt) {
17584
+ const info = ctx.contextShow?.();
17585
+ renderInfo(`Context restored from ${info?.entries ?? 0} saved session(s). Will be injected into your next task.`);
17586
+ ctx.setRestoredContext?.(prompt);
17587
+ } else {
17588
+ renderWarning("No saved session context found. Complete a task first, or use /context save.");
17589
+ }
17590
+ break;
17591
+ }
17592
+ case "show":
17593
+ case "status": {
17594
+ const info = ctx.contextShow?.();
17595
+ if (info && info.entries > 0) {
17596
+ renderInfo(`Session context: ${info.entries} entries saved. Last saved: ${info.lastSaved ? new Date(info.lastSaved).toLocaleString() : "unknown"}`);
17597
+ } else {
17598
+ renderInfo("No session context saved yet. Context auto-saves on task completion.");
17599
+ }
17600
+ break;
17601
+ }
17602
+ default:
17603
+ renderInfo("Usage: /context save | /context restore | /context show");
17604
+ renderInfo(" save \u2014 Force-save current session context");
17605
+ renderInfo(" restore \u2014 Load previous session context into next task");
17606
+ renderInfo(" show \u2014 Show saved context status");
17607
+ renderInfo("Context auto-saves on every task completion.");
17608
+ break;
17609
+ }
17610
+ return "handled";
17611
+ }
17505
17612
  case "compact":
17506
17613
  case "gc": {
17507
17614
  if (!ctx.hasActiveTask?.()) {
@@ -22340,6 +22447,18 @@ ${entry.fullContent}`
22340
22447
  });
22341
22448
  } catch {
22342
22449
  }
22450
+ try {
22451
+ saveSessionContext(repoRoot, {
22452
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
22453
+ task: task.slice(0, 500),
22454
+ summary: result.summary.slice(0, 500),
22455
+ filesModified: Array.from(filesTouched).slice(0, 30),
22456
+ toolCalls: result.toolCalls,
22457
+ completed: result.completed,
22458
+ model: config.model
22459
+ });
22460
+ } catch {
22461
+ }
22343
22462
  if (taskStores?.taskMemoryStore) {
22344
22463
  try {
22345
22464
  taskStores.taskMemoryStore.insert({
@@ -22571,6 +22690,7 @@ async function startInteractive(config, repoPath) {
22571
22690
  let currentTaskType;
22572
22691
  let sessionFilesTouched = [];
22573
22692
  let sessionToolCallCount = 0;
22693
+ let restoredSessionContext = null;
22574
22694
  let sessionSudoPassword = null;
22575
22695
  let sudoPromptPending = false;
22576
22696
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
@@ -22962,6 +23082,36 @@ async function startInteractive(config, repoPath) {
22962
23082
  writeContent(() => renderInfo(`No ${OA_DIR}/ directory found.`));
22963
23083
  }
22964
23084
  process.stdout.write("\x1Bc");
23085
+ },
23086
+ contextSave() {
23087
+ try {
23088
+ const entry = {
23089
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
23090
+ task: lastSubmittedPrompt || "(manual save)",
23091
+ summary: `Manual context save. ${sessionToolCallCount} tool calls, ${sessionFilesTouched.length} files modified.`,
23092
+ filesModified: [...sessionFilesTouched],
23093
+ toolCalls: sessionToolCallCount,
23094
+ completed: false,
23095
+ model: currentConfig.model
23096
+ };
23097
+ saveSessionContext(repoRoot, entry);
23098
+ return true;
23099
+ } catch {
23100
+ return false;
23101
+ }
23102
+ },
23103
+ contextRestore() {
23104
+ return buildContextRestorePrompt(repoRoot);
23105
+ },
23106
+ setRestoredContext(ctx) {
23107
+ restoredSessionContext = ctx;
23108
+ },
23109
+ contextShow() {
23110
+ const ctx = loadSessionContext(repoRoot);
23111
+ if (!ctx || ctx.entries.length === 0) {
23112
+ return { entries: 0, lastSaved: null };
23113
+ }
23114
+ return { entries: ctx.entries.length, lastSaved: ctx.updatedAt };
22965
23115
  }
22966
23116
  };
22967
23117
  showPrompt();
@@ -23191,9 +23341,18 @@ Summarize or analyze this transcription as appropriate.`;
23191
23341
  const displayText = isImage ? `[Image: ${cleanPath}]` : inputLineCount > 1 ? `[pasted ${inputLineCount} lines]` : fullInput;
23192
23342
  writeContent(() => renderUserMessage(displayText));
23193
23343
  lastSubmittedPrompt = fullInput;
23344
+ let taskInput = fullInput;
23345
+ if (restoredSessionContext) {
23346
+ taskInput = `${restoredSessionContext}
23347
+
23348
+ ---
23349
+
23350
+ NEW TASK: ${fullInput}`;
23351
+ restoredSessionContext = null;
23352
+ }
23194
23353
  try {
23195
23354
  statusBar.setProcessing(true);
23196
- const task = startTask(fullInput, currentConfig, repoRoot, voiceEngine, {
23355
+ const task = startTask(taskInput, currentConfig, repoRoot, voiceEngine, {
23197
23356
  enabled: streamEnabled,
23198
23357
  renderer: streamRenderer
23199
23358
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.31.7",
3
+ "version": "0.31.8",
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",