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.
- package/dist/index.js +161 -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(
|
|
23355
|
+
const task = startTask(taskInput, currentConfig, repoRoot, voiceEngine, {
|
|
23197
23356
|
enabled: streamEnabled,
|
|
23198
23357
|
renderer: streamRenderer
|
|
23199
23358
|
}, {
|
package/package.json
CHANGED