open-agents-ai 0.31.7 → 0.31.9
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.
- package/dist/index.js +165 -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?.()) {
|
|
@@ -17726,6 +17833,7 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
17726
17833
|
process.stdout.write(` ${c2.green("\u2714")} Installed v${info.latestVersion}. Reloading...
|
|
17727
17834
|
|
|
17728
17835
|
`);
|
|
17836
|
+
ctx.contextSave?.();
|
|
17729
17837
|
const hadActiveTask = ctx.savePendingTaskState?.() ?? false;
|
|
17730
17838
|
const resumeFlag = hadActiveTask ? "1" : "update-only";
|
|
17731
17839
|
const { execPath, argv } = process;
|
|
@@ -22340,6 +22448,18 @@ ${entry.fullContent}`
|
|
|
22340
22448
|
});
|
|
22341
22449
|
} catch {
|
|
22342
22450
|
}
|
|
22451
|
+
try {
|
|
22452
|
+
saveSessionContext(repoRoot, {
|
|
22453
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22454
|
+
task: task.slice(0, 500),
|
|
22455
|
+
summary: result.summary.slice(0, 500),
|
|
22456
|
+
filesModified: Array.from(filesTouched).slice(0, 30),
|
|
22457
|
+
toolCalls: result.toolCalls,
|
|
22458
|
+
completed: result.completed,
|
|
22459
|
+
model: config.model
|
|
22460
|
+
});
|
|
22461
|
+
} catch {
|
|
22462
|
+
}
|
|
22343
22463
|
if (taskStores?.taskMemoryStore) {
|
|
22344
22464
|
try {
|
|
22345
22465
|
taskStores.taskMemoryStore.insert({
|
|
@@ -22571,6 +22691,7 @@ async function startInteractive(config, repoPath) {
|
|
|
22571
22691
|
let currentTaskType;
|
|
22572
22692
|
let sessionFilesTouched = [];
|
|
22573
22693
|
let sessionToolCallCount = 0;
|
|
22694
|
+
let restoredSessionContext = null;
|
|
22574
22695
|
let sessionSudoPassword = null;
|
|
22575
22696
|
let sudoPromptPending = false;
|
|
22576
22697
|
const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
|
|
@@ -22962,6 +23083,36 @@ async function startInteractive(config, repoPath) {
|
|
|
22962
23083
|
writeContent(() => renderInfo(`No ${OA_DIR}/ directory found.`));
|
|
22963
23084
|
}
|
|
22964
23085
|
process.stdout.write("\x1Bc");
|
|
23086
|
+
},
|
|
23087
|
+
contextSave() {
|
|
23088
|
+
try {
|
|
23089
|
+
const entry = {
|
|
23090
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23091
|
+
task: lastSubmittedPrompt || "(manual save)",
|
|
23092
|
+
summary: `Manual context save. ${sessionToolCallCount} tool calls, ${sessionFilesTouched.length} files modified.`,
|
|
23093
|
+
filesModified: [...sessionFilesTouched],
|
|
23094
|
+
toolCalls: sessionToolCallCount,
|
|
23095
|
+
completed: false,
|
|
23096
|
+
model: currentConfig.model
|
|
23097
|
+
};
|
|
23098
|
+
saveSessionContext(repoRoot, entry);
|
|
23099
|
+
return true;
|
|
23100
|
+
} catch {
|
|
23101
|
+
return false;
|
|
23102
|
+
}
|
|
23103
|
+
},
|
|
23104
|
+
contextRestore() {
|
|
23105
|
+
return buildContextRestorePrompt(repoRoot);
|
|
23106
|
+
},
|
|
23107
|
+
setRestoredContext(ctx) {
|
|
23108
|
+
restoredSessionContext = ctx;
|
|
23109
|
+
},
|
|
23110
|
+
contextShow() {
|
|
23111
|
+
const ctx = loadSessionContext(repoRoot);
|
|
23112
|
+
if (!ctx || ctx.entries.length === 0) {
|
|
23113
|
+
return { entries: 0, lastSaved: null };
|
|
23114
|
+
}
|
|
23115
|
+
return { entries: ctx.entries.length, lastSaved: ctx.updatedAt };
|
|
22965
23116
|
}
|
|
22966
23117
|
};
|
|
22967
23118
|
showPrompt();
|
|
@@ -22969,7 +23120,10 @@ async function startInteractive(config, repoPath) {
|
|
|
22969
23120
|
const pendingTask = loadPendingTask(repoRoot);
|
|
22970
23121
|
if (pendingTask) {
|
|
22971
23122
|
setTimeout(() => {
|
|
23123
|
+
const sessionCtx = buildContextRestorePrompt(repoRoot);
|
|
22972
23124
|
const resumeContext = [
|
|
23125
|
+
sessionCtx ? `[SESSION CONTEXT RESTORED]
|
|
23126
|
+
${sessionCtx}` : "",
|
|
22973
23127
|
`[RESUMED AFTER UPDATE] Original task: ${pendingTask.prompt}`,
|
|
22974
23128
|
pendingTask.progressSummary ? `Progress so far: ${pendingTask.progressSummary}` : "",
|
|
22975
23129
|
pendingTask.filesModified.length > 0 ? `Files modified before update: ${pendingTask.filesModified.join(", ")}` : "",
|
|
@@ -23191,9 +23345,18 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
23191
23345
|
const displayText = isImage ? `[Image: ${cleanPath}]` : inputLineCount > 1 ? `[pasted ${inputLineCount} lines]` : fullInput;
|
|
23192
23346
|
writeContent(() => renderUserMessage(displayText));
|
|
23193
23347
|
lastSubmittedPrompt = fullInput;
|
|
23348
|
+
let taskInput = fullInput;
|
|
23349
|
+
if (restoredSessionContext) {
|
|
23350
|
+
taskInput = `${restoredSessionContext}
|
|
23351
|
+
|
|
23352
|
+
---
|
|
23353
|
+
|
|
23354
|
+
NEW TASK: ${fullInput}`;
|
|
23355
|
+
restoredSessionContext = null;
|
|
23356
|
+
}
|
|
23194
23357
|
try {
|
|
23195
23358
|
statusBar.setProcessing(true);
|
|
23196
|
-
const task = startTask(
|
|
23359
|
+
const task = startTask(taskInput, currentConfig, repoRoot, voiceEngine, {
|
|
23197
23360
|
enabled: streamEnabled,
|
|
23198
23361
|
renderer: streamRenderer
|
|
23199
23362
|
}, {
|
package/package.json
CHANGED