open-agents-ai 0.187.461 → 0.187.462
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 +214 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -254253,6 +254253,25 @@ var init_todo_write = __esm({
|
|
|
254253
254253
|
}
|
|
254254
254254
|
const sessionId = getTodoSessionId();
|
|
254255
254255
|
const oldTodos = readTodos(sessionId);
|
|
254256
|
+
const canonicalize = (todos) => JSON.stringify(todos.map((t2) => ({
|
|
254257
|
+
content: t2.content,
|
|
254258
|
+
status: t2.status,
|
|
254259
|
+
parentId: t2.parentId ?? null,
|
|
254260
|
+
blocker: t2.blocker ?? null
|
|
254261
|
+
})));
|
|
254262
|
+
const oldKey = canonicalize(oldTodos);
|
|
254263
|
+
const newKey = canonicalize(incoming);
|
|
254264
|
+
if (oldKey === newKey && oldTodos.length > 0) {
|
|
254265
|
+
return {
|
|
254266
|
+
success: true,
|
|
254267
|
+
output: JSON.stringify({
|
|
254268
|
+
reminder: "[NO-OP] You called todo_write with the same plan you already have. The list is unchanged. Use todo_write ONLY to add new tasks, mark a task in_progress / completed, or record a blocker — not as a way to re-read your plan (use todo_read for that, but the current plan is also surfaced automatically in your context). Proceed with the current in_progress task.",
|
|
254269
|
+
todos: oldTodos,
|
|
254270
|
+
noop: true
|
|
254271
|
+
}),
|
|
254272
|
+
durationMs: performance.now() - start2
|
|
254273
|
+
};
|
|
254274
|
+
}
|
|
254256
254275
|
const result = writeTodos(sessionId, incoming);
|
|
254257
254276
|
const closedCount = result.newTodos.filter((t2) => t2.status === "completed").length;
|
|
254258
254277
|
const oldClosedCount = oldTodos.filter((t2) => t2.status === "completed").length;
|
|
@@ -518395,6 +518414,115 @@ ${body}`;
|
|
|
518395
518414
|
* Returns null when the disable knob is set or the backend is missing the
|
|
518396
518415
|
* chatCompletion method.
|
|
518397
518416
|
*/
|
|
518417
|
+
/**
|
|
518418
|
+
* REG-3: Render the current todo list as a compact transient block so the
|
|
518419
|
+
* agent can read its own plan without calling todo_read or re-emitting
|
|
518420
|
+
* todo_write as a scratchpad. Returns null when there are no todos yet.
|
|
518421
|
+
*/
|
|
518422
|
+
_renderTodoStateBlock(turn) {
|
|
518423
|
+
try {
|
|
518424
|
+
const { readTodos: readTodos2 } = __require("@open-agents/execution");
|
|
518425
|
+
const { getTodoSessionId: getTodoSessionId2 } = __require("@open-agents/execution");
|
|
518426
|
+
const sessionId = getTodoSessionId2();
|
|
518427
|
+
const todos = readTodos2(sessionId);
|
|
518428
|
+
if (!todos || todos.length === 0)
|
|
518429
|
+
return null;
|
|
518430
|
+
const lines = ["[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]"];
|
|
518431
|
+
const inProg = todos.filter((t2) => t2.status === "in_progress");
|
|
518432
|
+
const pending = todos.filter((t2) => t2.status === "pending");
|
|
518433
|
+
const done = todos.filter((t2) => t2.status === "completed");
|
|
518434
|
+
const blocked = todos.filter((t2) => t2.status === "blocked");
|
|
518435
|
+
if (inProg.length > 0) {
|
|
518436
|
+
lines.push(`▶ in_progress (${inProg.length}):`);
|
|
518437
|
+
for (const t2 of inProg)
|
|
518438
|
+
lines.push(` • ${t2.content}`);
|
|
518439
|
+
}
|
|
518440
|
+
if (pending.length > 0) {
|
|
518441
|
+
lines.push(`◯ pending (${pending.length}):`);
|
|
518442
|
+
for (const t2 of pending.slice(0, 8))
|
|
518443
|
+
lines.push(` • ${t2.content}`);
|
|
518444
|
+
if (pending.length > 8)
|
|
518445
|
+
lines.push(` … +${pending.length - 8} more`);
|
|
518446
|
+
}
|
|
518447
|
+
if (blocked.length > 0) {
|
|
518448
|
+
lines.push(`✕ blocked (${blocked.length}):`);
|
|
518449
|
+
for (const t2 of blocked)
|
|
518450
|
+
lines.push(` • ${t2.content}${t2.blocker ? ` — ${t2.blocker}` : ""}`);
|
|
518451
|
+
}
|
|
518452
|
+
if (done.length > 0) {
|
|
518453
|
+
lines.push(`✓ completed (${done.length}): ${done.map((t2) => t2.content.slice(0, 40)).join(" | ")}`);
|
|
518454
|
+
}
|
|
518455
|
+
lines.push(`(turn ${turn} — call todo_write ONLY to update state, never to re-read this plan)`);
|
|
518456
|
+
return lines.join("\n");
|
|
518457
|
+
} catch {
|
|
518458
|
+
return null;
|
|
518459
|
+
}
|
|
518460
|
+
}
|
|
518461
|
+
/**
|
|
518462
|
+
* REG-2: Render a compact "files known to me" block from `_worldFacts`.
|
|
518463
|
+
* Goal: tell the model what it has already touched this run so it stops
|
|
518464
|
+
* re-running `find src -type f` and `list_directory("...")` to confirm
|
|
518465
|
+
* its own outputs.
|
|
518466
|
+
*
|
|
518467
|
+
* Returns null when there is nothing useful to surface yet.
|
|
518468
|
+
*/
|
|
518469
|
+
_renderFilesystemStateBlock(turn) {
|
|
518470
|
+
const wf = this._worldFacts;
|
|
518471
|
+
if (!wf)
|
|
518472
|
+
return null;
|
|
518473
|
+
const files = [...wf.files.entries()];
|
|
518474
|
+
const lists = [...wf.lastLists.entries()];
|
|
518475
|
+
if (files.length === 0 && lists.length === 0 && !wf.lastTest?.summary)
|
|
518476
|
+
return null;
|
|
518477
|
+
const writes = files.filter(([, v]) => (v.writeCount ?? 0) > 0);
|
|
518478
|
+
const reads = files.filter(([, v]) => (v.writeCount ?? 0) === 0);
|
|
518479
|
+
const groupByDir = (entries) => {
|
|
518480
|
+
const m2 = /* @__PURE__ */ new Map();
|
|
518481
|
+
for (const [p2] of entries) {
|
|
518482
|
+
const slash = p2.lastIndexOf("/");
|
|
518483
|
+
const dir = slash > 0 ? p2.slice(0, slash) : ".";
|
|
518484
|
+
const arr = m2.get(dir) ?? [];
|
|
518485
|
+
arr.push(p2);
|
|
518486
|
+
m2.set(dir, arr);
|
|
518487
|
+
}
|
|
518488
|
+
return m2;
|
|
518489
|
+
};
|
|
518490
|
+
const renderGroup = (m2, cap) => {
|
|
518491
|
+
const lines = [];
|
|
518492
|
+
const sorted = [...m2.entries()].sort((a2, b) => b[1].length - a2[1].length);
|
|
518493
|
+
let total = 0;
|
|
518494
|
+
for (const [dir, paths] of sorted) {
|
|
518495
|
+
if (total >= cap) {
|
|
518496
|
+
lines.push(` ... and ${sorted.slice(lines.length).reduce((s2, [, p2]) => s2 + p2.length, 0)} more files in other dirs`);
|
|
518497
|
+
break;
|
|
518498
|
+
}
|
|
518499
|
+
const show = paths.slice(0, 6);
|
|
518500
|
+
lines.push(` ${dir}/ → ${show.map((p2) => p2.slice(dir.length + 1)).join(", ")}${paths.length > show.length ? ` (+${paths.length - show.length} more)` : ""}`);
|
|
518501
|
+
total += paths.length;
|
|
518502
|
+
}
|
|
518503
|
+
return lines.join("\n");
|
|
518504
|
+
};
|
|
518505
|
+
const sections = [];
|
|
518506
|
+
sections.push("[FILES KNOWN — already touched this run; do not re-discover via find/list_directory unless filesystem may have changed externally]");
|
|
518507
|
+
if (writes.length > 0) {
|
|
518508
|
+
sections.push(`Files YOU WROTE this run (${writes.length}):`);
|
|
518509
|
+
sections.push(renderGroup(groupByDir(writes), 40));
|
|
518510
|
+
}
|
|
518511
|
+
if (reads.length > 0) {
|
|
518512
|
+
sections.push(`Files YOU READ this run (${reads.length}):`);
|
|
518513
|
+
sections.push(renderGroup(groupByDir(reads), 20));
|
|
518514
|
+
}
|
|
518515
|
+
if (lists.length > 0) {
|
|
518516
|
+
const recentLists = lists.sort((a2, b) => b[1].lastSeenTurn - a2[1].lastSeenTurn).slice(0, 8);
|
|
518517
|
+
sections.push(`Directories you've listed (${lists.length}):`);
|
|
518518
|
+
sections.push(recentLists.map(([dir, info]) => ` ${dir} (${info.entriesCount} entries, turn ${info.lastSeenTurn})`).join("\n"));
|
|
518519
|
+
}
|
|
518520
|
+
if (wf.lastTest?.summary) {
|
|
518521
|
+
sections.push(`Last test outcome: ${wf.lastTest.passed ? "PASSED" : "FAILED"} (turn ${wf.lastTest.turn ?? "?"})`);
|
|
518522
|
+
}
|
|
518523
|
+
sections.push(`(turn ${turn} — this block is regenerated every turn from your tool history)`);
|
|
518524
|
+
return sections.join("\n");
|
|
518525
|
+
}
|
|
518398
518526
|
makePhaseSummarizer() {
|
|
518399
518527
|
if (process.env["OA_DISABLE_PHASE_SUMMARIZER"] === "1")
|
|
518400
518528
|
return null;
|
|
@@ -519095,7 +519223,7 @@ TASK: ${task}` : task;
|
|
|
519095
519223
|
const recentToolResults = /* @__PURE__ */ new Map();
|
|
519096
519224
|
const toolCallBudget = /* @__PURE__ */ new Map();
|
|
519097
519225
|
const loopTier = this.options.modelTier ?? "large";
|
|
519098
|
-
const toolBudgets = loopTier === "small" ? { web_search: 6, web_fetch: 4, list_directory:
|
|
519226
|
+
const toolBudgets = loopTier === "small" ? { web_search: 6, web_fetch: 4, list_directory: 12, find_files: 10, grep_search: 12 } : loopTier === "medium" ? { web_search: 10, web_fetch: 8, list_directory: 18, find_files: 14, grep_search: 18 } : { web_search: 20, web_fetch: 15, list_directory: 30, find_files: 20, grep_search: 30 };
|
|
519099
519227
|
for (const [tool, budget] of Object.entries(toolBudgets)) {
|
|
519100
519228
|
toolCallBudget.set(tool, budget);
|
|
519101
519229
|
}
|
|
@@ -519462,6 +519590,22 @@ ${memoryLines.join("\n")}`
|
|
|
519462
519590
|
}
|
|
519463
519591
|
});
|
|
519464
519592
|
}
|
|
519593
|
+
const _injections = [];
|
|
519594
|
+
const fsBlock = this._renderFilesystemStateBlock(turn);
|
|
519595
|
+
if (fsBlock)
|
|
519596
|
+
_injections.push(fsBlock);
|
|
519597
|
+
const todoBlock = this._renderTodoStateBlock(turn);
|
|
519598
|
+
if (todoBlock)
|
|
519599
|
+
_injections.push(todoBlock);
|
|
519600
|
+
if (_injections.length > 0) {
|
|
519601
|
+
const reqMsgs = chatRequest.messages;
|
|
519602
|
+
if (Array.isArray(reqMsgs)) {
|
|
519603
|
+
const insertAt = Math.max(0, reqMsgs.length - 1);
|
|
519604
|
+
for (const blk of _injections) {
|
|
519605
|
+
reqMsgs.splice(insertAt, 0, { role: "system", content: blk });
|
|
519606
|
+
}
|
|
519607
|
+
}
|
|
519608
|
+
}
|
|
519465
519609
|
let response;
|
|
519466
519610
|
try {
|
|
519467
519611
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
@@ -519741,14 +519885,56 @@ ${memoryLines.join("\n")}`
|
|
|
519741
519885
|
content: `Phase contraction: ${contracted.join(", ")} → contracted (${summarizer ? "LLM-summarized" : "stub-summarized"}, anchors retained)`,
|
|
519742
519886
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519743
519887
|
});
|
|
519888
|
+
try {
|
|
519889
|
+
const archDir = __require("node:path").join(process.cwd(), ".oa", "phases");
|
|
519890
|
+
__require("node:fs").mkdirSync(archDir, { recursive: true });
|
|
519891
|
+
for (const phaseName of contracted) {
|
|
519892
|
+
const node = this._contextTree.getSnapshot().phases[phaseName];
|
|
519893
|
+
if (!node)
|
|
519894
|
+
continue;
|
|
519895
|
+
const stamp = `${phaseName}-${Date.now().toString(36)}-turn${turn}`;
|
|
519896
|
+
const archPath = __require("node:path").join(archDir, `${stamp}.jsonl`);
|
|
519897
|
+
const archived = {
|
|
519898
|
+
phase: phaseName,
|
|
519899
|
+
contractedAtTurn: turn,
|
|
519900
|
+
contractedAtIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
519901
|
+
anchors: node.anchors,
|
|
519902
|
+
summary: node.summary ?? null,
|
|
519903
|
+
messages: node.messages ?? []
|
|
519904
|
+
};
|
|
519905
|
+
__require("node:fs").writeFileSync(archPath, JSON.stringify(archived) + "\n", "utf-8");
|
|
519906
|
+
this._contextTree.archive(phaseName, archPath);
|
|
519907
|
+
}
|
|
519908
|
+
this.emit({
|
|
519909
|
+
type: "status",
|
|
519910
|
+
content: `Phase archive: ${contracted.length} phase(s) written to .oa/phases/`,
|
|
519911
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519912
|
+
});
|
|
519913
|
+
} catch (archErr) {
|
|
519914
|
+
this.emit({
|
|
519915
|
+
type: "status",
|
|
519916
|
+
content: `Phase archive failed (non-fatal): ${archErr instanceof Error ? archErr.message : String(archErr)}`,
|
|
519917
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519918
|
+
});
|
|
519919
|
+
}
|
|
519744
519920
|
}
|
|
519745
519921
|
this._phaseMessageStartIdx = messages2.length;
|
|
519746
519922
|
this._taskState.phase = transition.to;
|
|
519747
519923
|
this._taskState.phaseSince = turn;
|
|
519924
|
+
for (const [tool2, budget] of Object.entries(toolBudgets)) {
|
|
519925
|
+
toolCallBudget.set(tool2, budget);
|
|
519926
|
+
}
|
|
519927
|
+
this.emit({
|
|
519928
|
+
type: "status",
|
|
519929
|
+
content: `Tool budgets reset for new phase (${Object.keys(toolBudgets).length} tools)`,
|
|
519930
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519931
|
+
});
|
|
519748
519932
|
}
|
|
519749
519933
|
}
|
|
519934
|
+
const _argsKeyForBudget = `${tc.name}:${argsKey}`;
|
|
519935
|
+
const _isCachedHit = recentToolResults.has(_argsKeyForBudget);
|
|
519750
519936
|
const budgetRemaining = toolCallBudget.get(tc.name);
|
|
519751
|
-
if (budgetRemaining !== void 0) {
|
|
519937
|
+
if (budgetRemaining !== void 0 && !_isCachedHit) {
|
|
519752
519938
|
if (budgetRemaining <= 0) {
|
|
519753
519939
|
this.emit({
|
|
519754
519940
|
type: "tool_call",
|
|
@@ -519757,7 +519943,7 @@ ${memoryLines.join("\n")}`
|
|
|
519757
519943
|
turn,
|
|
519758
519944
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519759
519945
|
});
|
|
519760
|
-
const budgetMsg = `[BUDGET EXHAUSTED] You have used all ${toolBudgets[tc.name]} allowed ${tc.name} calls for
|
|
519946
|
+
const budgetMsg = `[BUDGET EXHAUSTED] You have used all ${toolBudgets[tc.name]} allowed ${tc.name} calls for the current phase. You ALREADY have enough information from previous calls. DO NOT try to call ${tc.name} again — it will be blocked. If your todo list shows more phases pending: mark the current phase completed via todo_write so a new budget allowance kicks in. If all phases are done: call task_complete with your final summary.`;
|
|
519761
519947
|
this.emit({
|
|
519762
519948
|
type: "tool_result",
|
|
519763
519949
|
toolName: tc.name,
|
|
@@ -519939,10 +520125,33 @@ ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed thi
|
|
|
519939
520125
|
updated.lastOutcomeTurn = turn;
|
|
519940
520126
|
this._argCohorts.set(cohortKey, updated);
|
|
519941
520127
|
try {
|
|
520128
|
+
if (tc.name === "file_write" || tc.name === "file_edit" || tc.name === "edit_block") {
|
|
520129
|
+
const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file_path"] ?? tc.arguments?.["file"] ?? "");
|
|
520130
|
+
if (p2 && result.success) {
|
|
520131
|
+
const prev = this._worldFacts.files.get(p2);
|
|
520132
|
+
this._worldFacts.files.set(p2, {
|
|
520133
|
+
exists: true,
|
|
520134
|
+
size: prev?.size,
|
|
520135
|
+
hashSample: prev?.hashSample,
|
|
520136
|
+
lastSeenTurn: turn,
|
|
520137
|
+
lastWriteTurn: turn,
|
|
520138
|
+
writeCount: (prev?.writeCount ?? 0) + 1
|
|
520139
|
+
});
|
|
520140
|
+
}
|
|
520141
|
+
}
|
|
519942
520142
|
if (tc.name === "file_read") {
|
|
519943
520143
|
const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
|
|
519944
|
-
if (p2)
|
|
519945
|
-
this._worldFacts.files.
|
|
520144
|
+
if (p2) {
|
|
520145
|
+
const prev = this._worldFacts.files.get(p2);
|
|
520146
|
+
this._worldFacts.files.set(p2, {
|
|
520147
|
+
exists: result.success,
|
|
520148
|
+
size: (result.output || "").length,
|
|
520149
|
+
hashSample: (result.output || "").slice(0, 32),
|
|
520150
|
+
lastSeenTurn: turn,
|
|
520151
|
+
lastWriteTurn: prev?.lastWriteTurn,
|
|
520152
|
+
writeCount: prev?.writeCount
|
|
520153
|
+
});
|
|
520154
|
+
}
|
|
519946
520155
|
if (this._fileSummaryStore && result.success && result.output && result.output.length > 100) {
|
|
519947
520156
|
try {
|
|
519948
520157
|
const existing = this._fileSummaryStore.get(p2);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-agents-ai",
|
|
3
|
-
"version": "0.187.
|
|
3
|
+
"version": "0.187.462",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "open-agents-ai",
|
|
9
|
-
"version": "0.187.
|
|
9
|
+
"version": "0.187.462",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED