open-agents-ai 0.187.206 → 0.187.207
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 +100 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -268905,6 +268905,36 @@ function getSystemPromptForTier(tier) {
|
|
|
268905
268905
|
return SYSTEM_PROMPT;
|
|
268906
268906
|
}
|
|
268907
268907
|
}
|
|
268908
|
+
function computeTodoReminder(input) {
|
|
268909
|
+
const turnsSinceWriteThreshold = input.turnsSinceWriteThreshold ?? 10;
|
|
268910
|
+
const turnsBetweenReminders = input.turnsBetweenReminders ?? 10;
|
|
268911
|
+
if (!input.todos || input.todos.length === 0) {
|
|
268912
|
+
return { shouldInject: false, content: null, reason: "no_todos" };
|
|
268913
|
+
}
|
|
268914
|
+
if (input.lastTodoWriteTurn >= 0) {
|
|
268915
|
+
const turnsSinceWrite = input.currentTurn - input.lastTodoWriteTurn;
|
|
268916
|
+
if (turnsSinceWrite < turnsSinceWriteThreshold) {
|
|
268917
|
+
return { shouldInject: false, content: null, reason: "recent_write" };
|
|
268918
|
+
}
|
|
268919
|
+
} else if (input.currentTurn < turnsSinceWriteThreshold) {
|
|
268920
|
+
return { shouldInject: false, content: null, reason: "too_early" };
|
|
268921
|
+
}
|
|
268922
|
+
if (input.lastReminderTurn >= 0) {
|
|
268923
|
+
const turnsSinceReminder = input.currentTurn - input.lastReminderTurn;
|
|
268924
|
+
if (turnsSinceReminder < turnsBetweenReminders) {
|
|
268925
|
+
return { shouldInject: false, content: null, reason: "recent_reminder" };
|
|
268926
|
+
}
|
|
268927
|
+
}
|
|
268928
|
+
const todoItems = input.todos.slice(0, 12).map((t2, i2) => `${i2 + 1}. [${t2.status}] ${t2.content}`).join("\n");
|
|
268929
|
+
const content = `<system-reminder>
|
|
268930
|
+
The todo_write tool hasn't been used recently. If you're working on tasks that would benefit from tracking progress, consider using todo_write to track your progress. Mark the current task in_progress and future tasks pending. When you complete a task, mark it completed immediately \u2014 don't batch completions. Also consider cleaning up the todo list if it has become stale and no longer matches what you are working on. Only use it if it's relevant to the current work. This is just a gentle reminder \u2014 ignore if not applicable. Make sure that you NEVER mention this reminder to the user.
|
|
268931
|
+
|
|
268932
|
+
Here are the existing contents of your todo list:
|
|
268933
|
+
|
|
268934
|
+
${todoItems}
|
|
268935
|
+
</system-reminder>`;
|
|
268936
|
+
return { shouldInject: true, content, reason: "injected" };
|
|
268937
|
+
}
|
|
268908
268938
|
var SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, AgenticRunner, OllamaAgenticBackend;
|
|
268909
268939
|
var init_agenticRunner = __esm({
|
|
268910
268940
|
"packages/orchestrator/dist/agenticRunner.js"() {
|
|
@@ -269227,30 +269257,65 @@ ${graphSummary}`,
|
|
|
269227
269257
|
*
|
|
269228
269258
|
* Max ~300 tokens to avoid context bloat.
|
|
269229
269259
|
*/
|
|
269230
|
-
|
|
269231
|
-
|
|
269232
|
-
|
|
269260
|
+
/**
|
|
269261
|
+
* WO-META-TRACK — Read the authoritative todo list from disk.
|
|
269262
|
+
* Returns null if no session id OR no file. Used by buildPlanSkeleton
|
|
269263
|
+
* and by the turn-counter reminder.
|
|
269264
|
+
*/
|
|
269265
|
+
readSessionTodos() {
|
|
269233
269266
|
try {
|
|
269234
269267
|
const sid = process.env["OA_SESSION_ID"] || this._sessionId || "default";
|
|
269235
269268
|
const safe = sid.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
269236
269269
|
const fp = _pathJoin(_osHomedir(), ".open-agents", "todos", `${safe}.json`);
|
|
269237
|
-
if (_fsExistsSync(fp))
|
|
269238
|
-
|
|
269239
|
-
|
|
269240
|
-
|
|
269241
|
-
|
|
269242
|
-
|
|
269243
|
-
|
|
269244
|
-
|
|
269245
|
-
|
|
269246
|
-
|
|
269247
|
-
|
|
269248
|
-
|
|
269249
|
-
|
|
269250
|
-
|
|
269270
|
+
if (!_fsExistsSync(fp))
|
|
269271
|
+
return null;
|
|
269272
|
+
const parsed = JSON.parse(_fsReadFileSync(fp, "utf-8"));
|
|
269273
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
269274
|
+
} catch {
|
|
269275
|
+
return null;
|
|
269276
|
+
}
|
|
269277
|
+
}
|
|
269278
|
+
/** Track the turn index of the last todo_write call so the reminder
|
|
269279
|
+
* path can compute `turnsSinceLastTodoWrite` cheaply without walking
|
|
269280
|
+
* the entire messages array. Reset on run(). */
|
|
269281
|
+
_lastTodoWriteTurn = -1;
|
|
269282
|
+
_lastTodoReminderTurn = -1;
|
|
269283
|
+
/**
|
|
269284
|
+
* WO-META-TRACK — Hannover-style turn-counter reminder.
|
|
269285
|
+
*
|
|
269286
|
+
* Delegates to the pure `computeTodoReminder` function so the gating
|
|
269287
|
+
* logic is independently testable without instantiating a backend.
|
|
269288
|
+
* Mutates `_lastTodoReminderTurn` when a reminder is produced.
|
|
269289
|
+
*/
|
|
269290
|
+
getTodoReminderContent(currentTurn) {
|
|
269291
|
+
const todos = this.readSessionTodos();
|
|
269292
|
+
const result = computeTodoReminder({
|
|
269293
|
+
currentTurn,
|
|
269294
|
+
lastTodoWriteTurn: this._lastTodoWriteTurn,
|
|
269295
|
+
lastReminderTurn: this._lastTodoReminderTurn,
|
|
269296
|
+
todos
|
|
269297
|
+
});
|
|
269298
|
+
if (result.shouldInject) {
|
|
269299
|
+
this._lastTodoReminderTurn = currentTurn;
|
|
269300
|
+
return result.content;
|
|
269301
|
+
}
|
|
269302
|
+
return null;
|
|
269303
|
+
}
|
|
269304
|
+
buildPlanSkeleton() {
|
|
269305
|
+
const ts = this._taskState;
|
|
269306
|
+
const parts = [];
|
|
269307
|
+
const todos = this.readSessionTodos();
|
|
269308
|
+
if (todos && todos.length > 0) {
|
|
269309
|
+
const current = todos.find((t2) => t2.status === "in_progress");
|
|
269310
|
+
const completedN = todos.filter((t2) => t2.status === "completed").length;
|
|
269311
|
+
if (current) {
|
|
269312
|
+
parts.push(`[plan: ${completedN}/${todos.length} complete \xB7 currently: ${current.content.slice(0, 80)}]`);
|
|
269313
|
+
} else {
|
|
269314
|
+
const nextPending = todos.find((t2) => t2.status === "pending");
|
|
269315
|
+
if (nextPending) {
|
|
269316
|
+
parts.push(`[plan: ${completedN}/${todos.length} complete \xB7 next: ${nextPending.content.slice(0, 80)}]`);
|
|
269251
269317
|
}
|
|
269252
269318
|
}
|
|
269253
|
-
} catch {
|
|
269254
269319
|
}
|
|
269255
269320
|
if (ts.goal || ts.completedSteps.length > 0) {
|
|
269256
269321
|
const done = ts.completedSteps.slice(-5).map((s2) => s2.slice(0, 60));
|
|
@@ -269731,6 +269796,8 @@ TASK: ${task}` : task;
|
|
|
269731
269796
|
this._selfConsistencyVotes = 0;
|
|
269732
269797
|
this._retrievalContextCache = null;
|
|
269733
269798
|
this._loopBlockedTools = void 0;
|
|
269799
|
+
this._lastTodoWriteTurn = -1;
|
|
269800
|
+
this._lastTodoReminderTurn = -1;
|
|
269734
269801
|
let pendingConstraintWarnings = [];
|
|
269735
269802
|
let consecutiveTextOnly = 0;
|
|
269736
269803
|
let loopInterventionCount = 0;
|
|
@@ -269813,6 +269880,17 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
269813
269880
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
269814
269881
|
});
|
|
269815
269882
|
}
|
|
269883
|
+
{
|
|
269884
|
+
const maybeReminder = this.getTodoReminderContent(turn);
|
|
269885
|
+
if (maybeReminder) {
|
|
269886
|
+
messages2.push({ role: "user", content: maybeReminder });
|
|
269887
|
+
this.emit({
|
|
269888
|
+
type: "status",
|
|
269889
|
+
content: `todo_reminder injected (turn ${turn}, last todo_write turn ${this._lastTodoWriteTurn})`,
|
|
269890
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
269891
|
+
});
|
|
269892
|
+
}
|
|
269893
|
+
}
|
|
269816
269894
|
const turnTier = this.options.modelTier ?? "large";
|
|
269817
269895
|
if (turn === 0 && (turnTier === "small" || turnTier === "medium")) {
|
|
269818
269896
|
const goal = this._taskState.goal || "";
|
|
@@ -270564,6 +270642,9 @@ ${memoryLines.join("\n")}`
|
|
|
270564
270642
|
this._taskState.toolCallCount++;
|
|
270565
270643
|
const filePath = typeof tc.arguments?.path === "string" ? tc.arguments.path : "";
|
|
270566
270644
|
recordToolExecution(this._appState, tc.name, performance.now() - toolStart, result.success, filePath || void 0);
|
|
270645
|
+
if (tc.name === "todo_write") {
|
|
270646
|
+
this._lastTodoWriteTurn = turn;
|
|
270647
|
+
}
|
|
270567
270648
|
if (tc.name === "file_read" || tc.name === "list_directory" || tc.name === "find_files" || tc.name === "grep_search") {
|
|
270568
270649
|
this._taskState.currentStep = `exploring: ${filePath || String(tc.arguments?.pattern ?? tc.arguments?.path ?? "").slice(0, 60)}`;
|
|
270569
270650
|
} else if (tc.name === "file_write" || tc.name === "file_edit" || tc.name === "batch_edit") {
|
|
@@ -276281,6 +276362,7 @@ __export(dist_exports4, {
|
|
|
276281
276362
|
cleanScaffolding: () => cleanScaffolding,
|
|
276282
276363
|
clearTurnState: () => clearTurnState,
|
|
276283
276364
|
compilePersonalityPrompt: () => compilePersonalityPrompt,
|
|
276365
|
+
computeTodoReminder: () => computeTodoReminder,
|
|
276284
276366
|
createAppState: () => createAppState,
|
|
276285
276367
|
createChildAbortController: () => createChildAbortController,
|
|
276286
276368
|
deleteAgentTaskSidecar: () => deleteAgentTaskSidecar,
|
package/package.json
CHANGED