open-agents-ai 0.187.559 → 0.187.560
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 +1278 -214
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -516767,6 +516767,160 @@ var init_stuck_meta_analyzer = __esm({
|
|
|
516767
516767
|
}
|
|
516768
516768
|
});
|
|
516769
516769
|
|
|
516770
|
+
// packages/orchestrator/dist/thinking-mode-collapse.js
|
|
516771
|
+
function renderModeCollapsePrompt(inputs) {
|
|
516772
|
+
const lines = [];
|
|
516773
|
+
lines.push("# THINKING STREAM MODE-COLLAPSE ANALYSIS");
|
|
516774
|
+
lines.push("");
|
|
516775
|
+
lines.push("You are a META-ANALYSIS sub-agent. A model (the generator) has been");
|
|
516776
|
+
lines.push("producing internal reasoning tokens for an extended period without");
|
|
516777
|
+
lines.push("emitting any visible output or tool calls. A sample of its reasoning");
|
|
516778
|
+
lines.push("stream is provided below.");
|
|
516779
|
+
lines.push("");
|
|
516780
|
+
lines.push("Your job: classify whether the generator is experiencing a MODE COLLAPSE");
|
|
516781
|
+
lines.push("(a reasoning loop where it repeats the same idea, goes in circles, or");
|
|
516782
|
+
lines.push("degrades into noise) or is still PRODUCTIVELY REASONING (making linear");
|
|
516783
|
+
lines.push("progress toward a conclusion).");
|
|
516784
|
+
lines.push("");
|
|
516785
|
+
lines.push("## Collapse categories");
|
|
516786
|
+
lines.push("");
|
|
516787
|
+
lines.push("- mode_collapse_exact_repeat: The model emits the exact same sentence or");
|
|
516788
|
+
lines.push(" paragraph 2+ times. The text is verbatim identical.");
|
|
516789
|
+
lines.push("");
|
|
516790
|
+
lines.push("- mode_collapse_semantic_loop: The model rephrases the same idea");
|
|
516791
|
+
lines.push(" repeatedly with different wording. Same concept, new sentences.");
|
|
516792
|
+
lines.push(" No new reasoning steps or conclusions.");
|
|
516793
|
+
lines.push("");
|
|
516794
|
+
lines.push("- mode_collapse_circular: The model alternates between two or more");
|
|
516795
|
+
lines.push(" positions/approaches without converging. A -> B -> A -> B pattern.");
|
|
516796
|
+
lines.push("");
|
|
516797
|
+
lines.push("- mode_collapse_degraded: The reasoning quality is visibly degrading —");
|
|
516798
|
+
lines.push(" sentences get shorter, less coherent, fragmented, or trail off.");
|
|
516799
|
+
lines.push(" The model is losing the thread.");
|
|
516800
|
+
lines.push("");
|
|
516801
|
+
lines.push("- mode_collapse_stuck_at_start: The model keeps restating the problem or");
|
|
516802
|
+
lines.push(" the first step but never moves to subsequent steps. Stuck in a");
|
|
516803
|
+
lines.push(" preamble loop.");
|
|
516804
|
+
lines.push("");
|
|
516805
|
+
lines.push("- healthy: The reasoning is making linear progress. Each sentence builds");
|
|
516806
|
+
lines.push(" on or advances from the previous one. The model is analyzing,");
|
|
516807
|
+
lines.push(" comparing, planning, or synthesizing in a productive direction.");
|
|
516808
|
+
lines.push("");
|
|
516809
|
+
lines.push("## Context");
|
|
516810
|
+
lines.push(`Goal: ${inputs.goal.slice(0, 500)}`);
|
|
516811
|
+
lines.push(`Total thinking produced: ${inputs.totalThinkingChars} characters over ${(inputs.thinkingDurationMs / 1e3).toFixed(0)}s`);
|
|
516812
|
+
if (inputs.lastToolNames.length > 0) {
|
|
516813
|
+
lines.push(`Recent tool calls before thinking: ${inputs.lastToolNames.join(", ")}`);
|
|
516814
|
+
}
|
|
516815
|
+
lines.push("");
|
|
516816
|
+
lines.push("## Thinking sample (most recent portion)");
|
|
516817
|
+
lines.push("");
|
|
516818
|
+
lines.push("```");
|
|
516819
|
+
lines.push(inputs.thinkingSample.slice(0, 3e3));
|
|
516820
|
+
lines.push("```");
|
|
516821
|
+
lines.push("");
|
|
516822
|
+
lines.push("## Output format");
|
|
516823
|
+
lines.push("");
|
|
516824
|
+
lines.push("Emit a SINGLE JSON code block with this exact shape:");
|
|
516825
|
+
lines.push("");
|
|
516826
|
+
lines.push("```json");
|
|
516827
|
+
lines.push("{");
|
|
516828
|
+
lines.push(' "category": "<one of the categories above>",');
|
|
516829
|
+
lines.push(' "diagnosis": "<1-2 sentence diagnosis>",');
|
|
516830
|
+
lines.push(' "confidence": <0.0-1.0>,');
|
|
516831
|
+
lines.push(' "suggested_action": "<one of: none, abort_and_retry_no_think, abort_and_nudge, abort_and_force_tool_call>"');
|
|
516832
|
+
lines.push("}");
|
|
516833
|
+
lines.push("```");
|
|
516834
|
+
lines.push("");
|
|
516835
|
+
lines.push("Only flag as collapse if confidence > 0.7. When unsure, classify as healthy");
|
|
516836
|
+
lines.push("with low confidence — false positives (aborting productive reasoning) are");
|
|
516837
|
+
lines.push("more harmful than false negatives (letting a collapse continue briefly).");
|
|
516838
|
+
return lines.join("\n");
|
|
516839
|
+
}
|
|
516840
|
+
function parseModeCollapseVerdict(rawResponse) {
|
|
516841
|
+
const fallback = (msg) => ({
|
|
516842
|
+
category: "healthy",
|
|
516843
|
+
diagnosis: `(sub-agent parse failed: ${msg})`,
|
|
516844
|
+
confidence: 0,
|
|
516845
|
+
suggested_action: "none",
|
|
516846
|
+
raw: rawResponse,
|
|
516847
|
+
parseFallback: true
|
|
516848
|
+
});
|
|
516849
|
+
if (!rawResponse || typeof rawResponse !== "string" || rawResponse.trim().length === 0) {
|
|
516850
|
+
return fallback("empty response");
|
|
516851
|
+
}
|
|
516852
|
+
const fenceMatch = rawResponse.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
516853
|
+
let jsonText = null;
|
|
516854
|
+
if (fenceMatch) {
|
|
516855
|
+
jsonText = fenceMatch[1].trim();
|
|
516856
|
+
} else {
|
|
516857
|
+
const first2 = rawResponse.indexOf("{");
|
|
516858
|
+
const last2 = rawResponse.lastIndexOf("}");
|
|
516859
|
+
if (first2 !== -1 && last2 > first2)
|
|
516860
|
+
jsonText = rawResponse.slice(first2, last2 + 1);
|
|
516861
|
+
}
|
|
516862
|
+
if (!jsonText)
|
|
516863
|
+
return fallback("no JSON block found");
|
|
516864
|
+
let parsed;
|
|
516865
|
+
try {
|
|
516866
|
+
parsed = JSON.parse(jsonText);
|
|
516867
|
+
} catch (e2) {
|
|
516868
|
+
return fallback(`JSON parse: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
516869
|
+
}
|
|
516870
|
+
if (!parsed || typeof parsed !== "object")
|
|
516871
|
+
return fallback("not an object");
|
|
516872
|
+
const validCategories = [
|
|
516873
|
+
"healthy",
|
|
516874
|
+
"mode_collapse_exact_repeat",
|
|
516875
|
+
"mode_collapse_semantic_loop",
|
|
516876
|
+
"mode_collapse_circular",
|
|
516877
|
+
"mode_collapse_degraded",
|
|
516878
|
+
"mode_collapse_stuck_at_start"
|
|
516879
|
+
];
|
|
516880
|
+
const category = typeof parsed.category === "string" && validCategories.includes(parsed.category) ? parsed.category : "healthy";
|
|
516881
|
+
const diagnosis = typeof parsed.diagnosis === "string" && parsed.diagnosis.trim().length > 0 ? parsed.diagnosis.slice(0, 500) : "(no diagnosis)";
|
|
516882
|
+
const confidence = typeof parsed.confidence === "number" ? Math.max(0, Math.min(1, parsed.confidence)) : 0;
|
|
516883
|
+
const validActions = [
|
|
516884
|
+
"none",
|
|
516885
|
+
"abort_and_retry_no_think",
|
|
516886
|
+
"abort_and_nudge",
|
|
516887
|
+
"abort_and_force_tool_call"
|
|
516888
|
+
];
|
|
516889
|
+
const suggested_action = typeof parsed.suggested_action === "string" && validActions.includes(parsed.suggested_action) ? parsed.suggested_action : "none";
|
|
516890
|
+
return {
|
|
516891
|
+
category,
|
|
516892
|
+
diagnosis,
|
|
516893
|
+
confidence,
|
|
516894
|
+
suggested_action,
|
|
516895
|
+
raw: rawResponse,
|
|
516896
|
+
parseFallback: false
|
|
516897
|
+
};
|
|
516898
|
+
}
|
|
516899
|
+
async function runModeCollapseAnalysis(opts) {
|
|
516900
|
+
const startMs = Date.now();
|
|
516901
|
+
const prompt = renderModeCollapsePrompt(opts.inputs);
|
|
516902
|
+
const promptBytes = Buffer.byteLength(prompt, "utf-8");
|
|
516903
|
+
let raw = "";
|
|
516904
|
+
try {
|
|
516905
|
+
raw = await opts.callable(prompt);
|
|
516906
|
+
} catch {
|
|
516907
|
+
raw = "";
|
|
516908
|
+
}
|
|
516909
|
+
const responseBytes = Buffer.byteLength(raw, "utf-8");
|
|
516910
|
+
const verdict = parseModeCollapseVerdict(raw);
|
|
516911
|
+
return {
|
|
516912
|
+
verdict,
|
|
516913
|
+
promptBytes,
|
|
516914
|
+
responseBytes,
|
|
516915
|
+
durationMs: Date.now() - startMs
|
|
516916
|
+
};
|
|
516917
|
+
}
|
|
516918
|
+
var init_thinking_mode_collapse = __esm({
|
|
516919
|
+
"packages/orchestrator/dist/thinking-mode-collapse.js"() {
|
|
516920
|
+
"use strict";
|
|
516921
|
+
}
|
|
516922
|
+
});
|
|
516923
|
+
|
|
516770
516924
|
// packages/orchestrator/dist/problem-frame-validator.js
|
|
516771
516925
|
function renderFrameValidatorPrompt(inputs) {
|
|
516772
516926
|
const lines = [];
|
|
@@ -527223,6 +527377,7 @@ var init_agenticRunner = __esm({
|
|
|
527223
527377
|
init_backward_pass_runner();
|
|
527224
527378
|
init_world_state_plan_reconciler();
|
|
527225
527379
|
init_stuck_meta_analyzer();
|
|
527380
|
+
init_thinking_mode_collapse();
|
|
527226
527381
|
init_problem_frame_validator();
|
|
527227
527382
|
init_pressure_gate();
|
|
527228
527383
|
init_dist5();
|
|
@@ -527241,9 +527396,22 @@ var init_agenticRunner = __esm({
|
|
|
527241
527396
|
init_modelProfile();
|
|
527242
527397
|
TOOL_SUBSETS = {
|
|
527243
527398
|
web: ["web_search", "web_fetch", "web_crawl"],
|
|
527244
|
-
code: [
|
|
527399
|
+
code: [
|
|
527400
|
+
"file_patch",
|
|
527401
|
+
"file_explore",
|
|
527402
|
+
"batch_edit",
|
|
527403
|
+
"file_read",
|
|
527404
|
+
"file_write",
|
|
527405
|
+
"file_edit"
|
|
527406
|
+
],
|
|
527245
527407
|
agent: ["agent", "sub_agent", "background_run"],
|
|
527246
|
-
memory: [
|
|
527408
|
+
memory: [
|
|
527409
|
+
"memory_search",
|
|
527410
|
+
"memory_read",
|
|
527411
|
+
"memory_write",
|
|
527412
|
+
"memex_retrieve",
|
|
527413
|
+
"working_notes"
|
|
527414
|
+
],
|
|
527247
527415
|
shell: ["shell", "shell_async", "kill_proc", "run_tests"],
|
|
527248
527416
|
graph: ["graph_query", "graph_traverse", "code_graph"],
|
|
527249
527417
|
skill: ["skill_list", "skill_execute", "skill_search"]
|
|
@@ -527252,11 +527420,48 @@ var init_agenticRunner = __esm({
|
|
|
527252
527420
|
SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
|
|
527253
527421
|
SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
|
|
527254
527422
|
SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
|
|
527255
|
-
VISUAL_TOOLS = /* @__PURE__ */ new Set([
|
|
527256
|
-
|
|
527257
|
-
|
|
527258
|
-
|
|
527259
|
-
|
|
527423
|
+
VISUAL_TOOLS = /* @__PURE__ */ new Set([
|
|
527424
|
+
"vision",
|
|
527425
|
+
"camera_capture",
|
|
527426
|
+
"image_read",
|
|
527427
|
+
"screenshot",
|
|
527428
|
+
"ocr",
|
|
527429
|
+
"ocr_image_advanced",
|
|
527430
|
+
"visual_memory",
|
|
527431
|
+
"desktop_describe",
|
|
527432
|
+
"ocr_pdf",
|
|
527433
|
+
"generate_image"
|
|
527434
|
+
]);
|
|
527435
|
+
AUDIO_TOOLS = /* @__PURE__ */ new Set([
|
|
527436
|
+
"audio_capture",
|
|
527437
|
+
"audio_analyze",
|
|
527438
|
+
"asr_listen",
|
|
527439
|
+
"transcribe_file",
|
|
527440
|
+
"transcribe_url",
|
|
527441
|
+
"audio_playback",
|
|
527442
|
+
"youtube_download"
|
|
527443
|
+
]);
|
|
527444
|
+
SOCIAL_TOOLS = /* @__PURE__ */ new Set([
|
|
527445
|
+
"multimodal_memory",
|
|
527446
|
+
"send_message",
|
|
527447
|
+
"jibberlink"
|
|
527448
|
+
]);
|
|
527449
|
+
SPATIAL_TOOLS = /* @__PURE__ */ new Set([
|
|
527450
|
+
"gps_location",
|
|
527451
|
+
"bluetooth_scan",
|
|
527452
|
+
"wifi_control",
|
|
527453
|
+
"sdr_scan",
|
|
527454
|
+
"meshtastic"
|
|
527455
|
+
]);
|
|
527456
|
+
CODE_TOOLS = /* @__PURE__ */ new Set([
|
|
527457
|
+
"file_write",
|
|
527458
|
+
"file_edit",
|
|
527459
|
+
"file_patch",
|
|
527460
|
+
"batch_edit",
|
|
527461
|
+
"code_sandbox",
|
|
527462
|
+
"repl_exec",
|
|
527463
|
+
"notebook_edit"
|
|
527464
|
+
]);
|
|
527260
527465
|
AgenticRunner = class {
|
|
527261
527466
|
backend;
|
|
527262
527467
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -527879,7 +528084,11 @@ ${graphSummary}`,
|
|
|
527879
528084
|
try {
|
|
527880
528085
|
const _allLessons = readAll(this._workingDirectory || void 0);
|
|
527881
528086
|
if (_allLessons.length > 0) {
|
|
527882
|
-
const _selected = select2({
|
|
528087
|
+
const _selected = select2({
|
|
528088
|
+
goal: task,
|
|
528089
|
+
lessons: _allLessons,
|
|
528090
|
+
k: 5
|
|
528091
|
+
});
|
|
527883
528092
|
if (_selected.length > 0) {
|
|
527884
528093
|
const _lessonsBody = renderLessonsAsContext(_selected);
|
|
527885
528094
|
sections.push({
|
|
@@ -527895,7 +528104,10 @@ ${graphSummary}`,
|
|
|
527895
528104
|
const totalTokenEstimate = sections.reduce((sum, s2) => sum + s2.tokenEstimate, 0);
|
|
527896
528105
|
return {
|
|
527897
528106
|
assembled,
|
|
527898
|
-
sections: sections.map((s2) => ({
|
|
528107
|
+
sections: sections.map((s2) => ({
|
|
528108
|
+
label: s2.label,
|
|
528109
|
+
tokenEstimate: s2.tokenEstimate
|
|
528110
|
+
})),
|
|
527899
528111
|
totalTokenEstimate
|
|
527900
528112
|
};
|
|
527901
528113
|
}
|
|
@@ -528130,7 +528342,12 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
|
|
|
528130
528342
|
return null;
|
|
528131
528343
|
if (process.env["OA_DISABLE_DECOMP2"] === "1")
|
|
528132
528344
|
return null;
|
|
528133
|
-
const _editTools = /* @__PURE__ */ new Set([
|
|
528345
|
+
const _editTools = /* @__PURE__ */ new Set([
|
|
528346
|
+
"file_write",
|
|
528347
|
+
"file_edit",
|
|
528348
|
+
"batch_edit",
|
|
528349
|
+
"file_patch"
|
|
528350
|
+
]);
|
|
528134
528351
|
if (!_editTools.has(tc.name))
|
|
528135
528352
|
return null;
|
|
528136
528353
|
const _editPaths = this._extractToolTargetPaths(tc.name, tc.arguments);
|
|
@@ -528272,7 +528489,12 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
|
|
|
528272
528489
|
const window2 = toolCallLog.slice(-WINDOW);
|
|
528273
528490
|
if (window2.length < SHELL_REPEAT_THRESHOLD)
|
|
528274
528491
|
return { detected: false };
|
|
528275
|
-
const _editClasses = /* @__PURE__ */ new Set([
|
|
528492
|
+
const _editClasses = /* @__PURE__ */ new Set([
|
|
528493
|
+
"file_write",
|
|
528494
|
+
"file_edit",
|
|
528495
|
+
"batch_edit",
|
|
528496
|
+
"file_patch"
|
|
528497
|
+
]);
|
|
528276
528498
|
for (const c9 of window2) {
|
|
528277
528499
|
if (_editClasses.has(c9.name) && c9.success !== false)
|
|
528278
528500
|
return { detected: false };
|
|
@@ -528305,10 +528527,20 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
|
|
|
528305
528527
|
bestRead = [k, n2];
|
|
528306
528528
|
}
|
|
528307
528529
|
if (bestShell) {
|
|
528308
|
-
return {
|
|
528530
|
+
return {
|
|
528531
|
+
detected: true,
|
|
528532
|
+
repeatedSample: bestShell[0],
|
|
528533
|
+
count: bestShell[1],
|
|
528534
|
+
kind: "shell"
|
|
528535
|
+
};
|
|
528309
528536
|
}
|
|
528310
528537
|
if (bestRead) {
|
|
528311
|
-
return {
|
|
528538
|
+
return {
|
|
528539
|
+
detected: true,
|
|
528540
|
+
repeatedSample: bestRead[0],
|
|
528541
|
+
count: bestRead[1],
|
|
528542
|
+
kind: "read"
|
|
528543
|
+
};
|
|
528312
528544
|
}
|
|
528313
528545
|
return { detected: false };
|
|
528314
528546
|
}
|
|
@@ -528482,7 +528714,10 @@ Do NOT call task_complete until all items are marked completed via todo_write.`;
|
|
|
528482
528714
|
try {
|
|
528483
528715
|
const resp = await _backend.chatCompletion({
|
|
528484
528716
|
messages: [
|
|
528485
|
-
{
|
|
528717
|
+
{
|
|
528718
|
+
role: "system",
|
|
528719
|
+
content: "You are a CRITIC sub-agent. Audit the implementation and emit a structured JSON verdict."
|
|
528720
|
+
},
|
|
528486
528721
|
{ role: "user", content: prompt }
|
|
528487
528722
|
],
|
|
528488
528723
|
tools: [],
|
|
@@ -528499,7 +528734,14 @@ Do NOT call task_complete until all items are marked completed via todo_write.`;
|
|
|
528499
528734
|
verdict: "request_changes",
|
|
528500
528735
|
rationale: `Critic backend call failed: ${e2 instanceof Error ? e2.message : String(e2)}`,
|
|
528501
528736
|
pass: [],
|
|
528502
|
-
issues: [
|
|
528737
|
+
issues: [
|
|
528738
|
+
{
|
|
528739
|
+
severity: "high",
|
|
528740
|
+
file: "(critic-runner)",
|
|
528741
|
+
problem: "Backend call failed.",
|
|
528742
|
+
suggested_fix: "Retry; if persistent, set OA_BACKWARD_PASS=off."
|
|
528743
|
+
}
|
|
528744
|
+
],
|
|
528503
528745
|
tests_missing: []
|
|
528504
528746
|
});
|
|
528505
528747
|
}
|
|
@@ -529019,7 +529261,7 @@ ${body}`;
|
|
|
529019
529261
|
* converging — particularly common when a build error names a specific
|
|
529020
529262
|
* file the agent thinks needs more work.
|
|
529021
529263
|
*
|
|
529022
|
-
|
|
529264
|
+
* Suggests targeted alternatives (file_edit/file_patch) and "good enough"
|
|
529023
529265
|
* recognition. Returns null when no churn is happening.
|
|
529024
529266
|
*/
|
|
529025
529267
|
_renderWriteChurnBlock(turn) {
|
|
@@ -529039,7 +529281,9 @@ ${body}`;
|
|
|
529039
529281
|
return null;
|
|
529040
529282
|
churners.sort((a2, b) => b.writes - a2.writes);
|
|
529041
529283
|
const top = churners.slice(0, 5);
|
|
529042
|
-
const lines = [
|
|
529284
|
+
const lines = [
|
|
529285
|
+
"[WRITE-LOOP DETECTED — you are rewriting the same file(s) repeatedly]"
|
|
529286
|
+
];
|
|
529043
529287
|
for (const c9 of top) {
|
|
529044
529288
|
lines.push(` • ${c9.path} — ${c9.writes} writes (most recent ${c9.ageTurns} turn${c9.ageTurns === 1 ? "" : "s"} ago)`);
|
|
529045
529289
|
}
|
|
@@ -529501,7 +529745,9 @@ ${latest.output || ""}`.trim();
|
|
|
529501
529745
|
const todos = this.readSessionTodos();
|
|
529502
529746
|
if (!todos || todos.length === 0)
|
|
529503
529747
|
return null;
|
|
529504
|
-
const lines = [
|
|
529748
|
+
const lines = [
|
|
529749
|
+
"[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]"
|
|
529750
|
+
];
|
|
529505
529751
|
const inProg = todos.filter((t2) => t2.status === "in_progress");
|
|
529506
529752
|
const pending = todos.filter((t2) => t2.status === "pending");
|
|
529507
529753
|
const done = todos.filter((t2) => t2.status === "completed");
|
|
@@ -529644,7 +529890,10 @@ ${blob}
|
|
|
529644
529890
|
try {
|
|
529645
529891
|
const response = await this.backend.chatCompletion({
|
|
529646
529892
|
messages: [
|
|
529647
|
-
{
|
|
529893
|
+
{
|
|
529894
|
+
role: "system",
|
|
529895
|
+
content: "You write extremely concise phase summaries for agent context management."
|
|
529896
|
+
},
|
|
529648
529897
|
{ role: "user", content: prompt }
|
|
529649
529898
|
],
|
|
529650
529899
|
tools: [],
|
|
@@ -529715,7 +529964,9 @@ ${blob}
|
|
|
529715
529964
|
const newMemex = memexMatches.filter((m2) => !this._lastSurfacedAnchorIds.has(m2.id)).slice(0, 2);
|
|
529716
529965
|
if (newAnchors.length === 0 && newMemex.length === 0)
|
|
529717
529966
|
return;
|
|
529718
|
-
const lines = [
|
|
529967
|
+
const lines = [
|
|
529968
|
+
`[Anchor surface] Relevant archived context for the current activity:`
|
|
529969
|
+
];
|
|
529719
529970
|
for (const a2 of newAnchors) {
|
|
529720
529971
|
lines.push(` - [${a2.type}] ${a2.summary}`);
|
|
529721
529972
|
}
|
|
@@ -529775,7 +530026,10 @@ ${blob}
|
|
|
529775
530026
|
if (msg.role === "assistant" && typeof msg.content === "string" && msg.content.length > 200) {
|
|
529776
530027
|
const stripped = msg.content.replace(/<think>[\s\S]*?<\/think>/gi, "").replace(/<reasoning>[\s\S]*?<\/reasoning>/gi, "").replace(/\[THINKING\][\s\S]*?\[\/THINKING\]/gi, "").trim();
|
|
529777
530028
|
if (stripped.length < msg.content.length * 0.8) {
|
|
529778
|
-
messages2[i2] = {
|
|
530029
|
+
messages2[i2] = {
|
|
530030
|
+
...msg,
|
|
530031
|
+
content: stripped || "[thinking stripped]"
|
|
530032
|
+
};
|
|
529779
530033
|
thinkStripped++;
|
|
529780
530034
|
}
|
|
529781
530035
|
}
|
|
@@ -529905,7 +530159,11 @@ ${blob}
|
|
|
529905
530159
|
getToolCatalog() {
|
|
529906
530160
|
const list = [];
|
|
529907
530161
|
for (const t2 of this.tools.values()) {
|
|
529908
|
-
list.push({
|
|
530162
|
+
list.push({
|
|
530163
|
+
name: t2.name,
|
|
530164
|
+
description: t2.description,
|
|
530165
|
+
parameters: t2.parameters
|
|
530166
|
+
});
|
|
529909
530167
|
}
|
|
529910
530168
|
return list;
|
|
529911
530169
|
}
|
|
@@ -529923,7 +530181,11 @@ ${blob}
|
|
|
529923
530181
|
tool.inputSchema.parse(args);
|
|
529924
530182
|
}
|
|
529925
530183
|
} catch (e2) {
|
|
529926
|
-
return {
|
|
530184
|
+
return {
|
|
530185
|
+
success: false,
|
|
530186
|
+
output: "",
|
|
530187
|
+
error: `Invalid args for ${name10}: ${e2?.message || String(e2)}`
|
|
530188
|
+
};
|
|
529927
530189
|
}
|
|
529928
530190
|
try {
|
|
529929
530191
|
const result = await tool.execute(args);
|
|
@@ -529972,7 +530234,11 @@ ${blob}
|
|
|
529972
530234
|
pause() {
|
|
529973
530235
|
if (!this._paused) {
|
|
529974
530236
|
this._paused = true;
|
|
529975
|
-
this.emit({
|
|
530237
|
+
this.emit({
|
|
530238
|
+
type: "status",
|
|
530239
|
+
content: "Task paused by user.",
|
|
530240
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530241
|
+
});
|
|
529976
530242
|
}
|
|
529977
530243
|
}
|
|
529978
530244
|
/**
|
|
@@ -529981,7 +530247,11 @@ ${blob}
|
|
|
529981
530247
|
resume() {
|
|
529982
530248
|
if (this._paused) {
|
|
529983
530249
|
this._paused = false;
|
|
529984
|
-
this.emit({
|
|
530250
|
+
this.emit({
|
|
530251
|
+
type: "status",
|
|
530252
|
+
content: "Task resumed by user.",
|
|
530253
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530254
|
+
});
|
|
529985
530255
|
if (this._pauseResolve) {
|
|
529986
530256
|
this._pauseResolve();
|
|
529987
530257
|
this._pauseResolve = null;
|
|
@@ -530287,7 +530557,11 @@ Respond with your assessment, then take action.`;
|
|
|
530287
530557
|
const snapshot = preflightMod.capturePreflightSnapshot(this._workingDirectory ?? void 0);
|
|
530288
530558
|
const formatted = preflightMod.formatPreflightStatus(snapshot);
|
|
530289
530559
|
if (formatted) {
|
|
530290
|
-
this.emit({
|
|
530560
|
+
this.emit({
|
|
530561
|
+
type: "status",
|
|
530562
|
+
content: formatted,
|
|
530563
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530564
|
+
});
|
|
530291
530565
|
}
|
|
530292
530566
|
if (this._episodeStore) {
|
|
530293
530567
|
const hasError = snapshot.warnings.some((w) => w.severity === "error");
|
|
@@ -530342,7 +530616,10 @@ Respond with your assessment, then take action.`;
|
|
|
530342
530616
|
const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
530343
530617
|
const currentModel = process.env["OA_EMBEDDING_MODEL"] || "default";
|
|
530344
530618
|
const currentDim = parseInt(process.env["OA_EMBEDDING_DIM"] || "0", 10) || 768;
|
|
530345
|
-
const drift = memMod.checkEmbeddingDrift(this._episodeStore.getDb(), {
|
|
530619
|
+
const drift = memMod.checkEmbeddingDrift(this._episodeStore.getDb(), {
|
|
530620
|
+
model: currentModel,
|
|
530621
|
+
dim: currentDim
|
|
530622
|
+
});
|
|
530346
530623
|
if (drift.driftDetected && drift.previous) {
|
|
530347
530624
|
this.emit({
|
|
530348
530625
|
type: "status",
|
|
@@ -530350,7 +530627,10 @@ Respond with your assessment, then take action.`;
|
|
|
530350
530627
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530351
530628
|
});
|
|
530352
530629
|
} else if (!drift.previous) {
|
|
530353
|
-
memMod.recordEmbeddingMeta(this._episodeStore.getDb(), {
|
|
530630
|
+
memMod.recordEmbeddingMeta(this._episodeStore.getDb(), {
|
|
530631
|
+
model: currentModel,
|
|
530632
|
+
dim: currentDim
|
|
530633
|
+
});
|
|
530354
530634
|
}
|
|
530355
530635
|
} catch {
|
|
530356
530636
|
}
|
|
@@ -530361,7 +530641,10 @@ Respond with your assessment, then take action.`;
|
|
|
530361
530641
|
let commitSha = "no-commit";
|
|
530362
530642
|
try {
|
|
530363
530643
|
const { execSync: execSync59 } = await import("node:child_process");
|
|
530364
|
-
commitSha = execSync59("git rev-parse HEAD", {
|
|
530644
|
+
commitSha = execSync59("git rev-parse HEAD", {
|
|
530645
|
+
cwd: this._workingDirectory,
|
|
530646
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
530647
|
+
}).toString().trim().slice(0, 12) || "no-commit";
|
|
530365
530648
|
} catch {
|
|
530366
530649
|
}
|
|
530367
530650
|
const cm = new memMod.CodebaseMap(this._episodeStore.getDb(), this._workingDirectory, commitSha);
|
|
@@ -530443,7 +530726,9 @@ TASK: ${task}` : task;
|
|
|
530443
530726
|
if (process.env["OA_FRESH_SESSION"] === "1")
|
|
530444
530727
|
throw "skip-handoff-fresh";
|
|
530445
530728
|
const oaDir = this._workingDirectory ? _pathJoin(this._workingDirectory, ".oa") : _pathJoin(process.cwd(), ".oa");
|
|
530446
|
-
const chainPairs = loadMessagePairsFromLog(oaDir, {
|
|
530729
|
+
const chainPairs = loadMessagePairsFromLog(oaDir, {
|
|
530730
|
+
currentTask: cleanedTask
|
|
530731
|
+
});
|
|
530447
530732
|
if (chainPairs.length > 0) {
|
|
530448
530733
|
messages2.splice(1, 0, ...chainPairs);
|
|
530449
530734
|
this.emit({
|
|
@@ -530552,7 +530837,25 @@ TASK: ${task}` : task;
|
|
|
530552
530837
|
const DEDUP_ESCALATION_THRESHOLD = 3;
|
|
530553
530838
|
const toolCallBudget = /* @__PURE__ */ new Map();
|
|
530554
530839
|
const loopTier = this.options.modelTier ?? "large";
|
|
530555
|
-
const toolBudgets = loopTier === "small" ? {
|
|
530840
|
+
const toolBudgets = loopTier === "small" ? {
|
|
530841
|
+
web_search: 6,
|
|
530842
|
+
web_fetch: 4,
|
|
530843
|
+
list_directory: 12,
|
|
530844
|
+
find_files: 10,
|
|
530845
|
+
grep_search: 12
|
|
530846
|
+
} : loopTier === "medium" ? {
|
|
530847
|
+
web_search: 10,
|
|
530848
|
+
web_fetch: 8,
|
|
530849
|
+
list_directory: 18,
|
|
530850
|
+
find_files: 14,
|
|
530851
|
+
grep_search: 18
|
|
530852
|
+
} : {
|
|
530853
|
+
web_search: 20,
|
|
530854
|
+
web_fetch: 15,
|
|
530855
|
+
list_directory: 30,
|
|
530856
|
+
find_files: 20,
|
|
530857
|
+
grep_search: 30
|
|
530858
|
+
};
|
|
530556
530859
|
for (const [tool, budget] of Object.entries(toolBudgets)) {
|
|
530557
530860
|
toolCallBudget.set(tool, budget);
|
|
530558
530861
|
}
|
|
@@ -530587,12 +530890,20 @@ TASK: ${task}` : task;
|
|
|
530587
530890
|
if (this._paused) {
|
|
530588
530891
|
const shouldContinue = await this.waitIfPaused();
|
|
530589
530892
|
if (!shouldContinue) {
|
|
530590
|
-
this.emit({
|
|
530893
|
+
this.emit({
|
|
530894
|
+
type: "error",
|
|
530895
|
+
content: "Task aborted by user",
|
|
530896
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530897
|
+
});
|
|
530591
530898
|
break;
|
|
530592
530899
|
}
|
|
530593
530900
|
}
|
|
530594
530901
|
if (this.aborted) {
|
|
530595
|
-
this.emit({
|
|
530902
|
+
this.emit({
|
|
530903
|
+
type: "error",
|
|
530904
|
+
content: "Task aborted by user",
|
|
530905
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530906
|
+
});
|
|
530596
530907
|
break;
|
|
530597
530908
|
}
|
|
530598
530909
|
const REG35_CHECKPOINT_EVERY = 10;
|
|
@@ -530691,7 +531002,10 @@ TASK: ${task}` : task;
|
|
|
530691
531002
|
todos: _wsTodos,
|
|
530692
531003
|
recentFailures: _wsFailures,
|
|
530693
531004
|
maxFiles: WORLD_STATE_MAX_FILES,
|
|
530694
|
-
lastBuildSuccess: this._lastBuildSuccessTurn >= 0 ? {
|
|
531005
|
+
lastBuildSuccess: this._lastBuildSuccessTurn >= 0 ? {
|
|
531006
|
+
command: this._lastBuildSuccessCommand,
|
|
531007
|
+
turn: this._lastBuildSuccessTurn
|
|
531008
|
+
} : void 0
|
|
530695
531009
|
});
|
|
530696
531010
|
for (let _i = 0; _i < messages2.length; _i++) {
|
|
530697
531011
|
const _m = messages2[_i];
|
|
@@ -530856,7 +531170,10 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
530856
531170
|
errClusters.push(...this._runErrorPatterns.slice(0, 3));
|
|
530857
531171
|
}
|
|
530858
531172
|
const stuckTool = this._toolSequence.length > 0 ? this._toolSequence[this._toolSequence.length - 1] : null;
|
|
530859
|
-
const fingerprint = {
|
|
531173
|
+
const fingerprint = {
|
|
531174
|
+
errorClusters: errClusters.slice(0, 3),
|
|
531175
|
+
stuckTool
|
|
531176
|
+
};
|
|
530860
531177
|
this._pendingStagnationEntry = {
|
|
530861
531178
|
fingerprint,
|
|
530862
531179
|
cooldownExpiresAtTurn: turn + 5,
|
|
@@ -531062,7 +531379,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531062
531379
|
try {
|
|
531063
531380
|
const _r = await this.backend.chatCompletion({
|
|
531064
531381
|
messages: [
|
|
531065
|
-
{
|
|
531382
|
+
{
|
|
531383
|
+
role: "system",
|
|
531384
|
+
content: "You are a META-ANALYSIS sub-agent. Audit the implementer's stuck state and emit a structured JSON directive."
|
|
531385
|
+
},
|
|
531066
531386
|
{ role: "user", content: prompt }
|
|
531067
531387
|
],
|
|
531068
531388
|
tools: [],
|
|
@@ -531117,7 +531437,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531117
531437
|
callable: _smaCallable
|
|
531118
531438
|
}).then((_smaResult) => {
|
|
531119
531439
|
if (_smaResult.injection && !_smaResult.directive.parseFallback) {
|
|
531120
|
-
messages2.push({
|
|
531440
|
+
messages2.push({
|
|
531441
|
+
role: "system",
|
|
531442
|
+
content: _smaResult.injection
|
|
531443
|
+
});
|
|
531121
531444
|
this.emit({
|
|
531122
531445
|
type: "status",
|
|
531123
531446
|
content: `REG-49 stuck-meta-analyzer fired at turn ${turn} — diagnosis="${_smaResult.directive.diagnosis.slice(0, 80)}", next=${_smaResult.directive.next_action.tool}, ${_smaResult.durationMs}ms`,
|
|
@@ -531225,7 +531548,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531225
531548
|
try {
|
|
531226
531549
|
const _r = await this.backend.chatCompletion({
|
|
531227
531550
|
messages: [
|
|
531228
|
-
{
|
|
531551
|
+
{
|
|
531552
|
+
role: "system",
|
|
531553
|
+
content: "You are a META-ANALYSIS sub-agent. Audit the implementer's stuck state and emit a structured JSON directive."
|
|
531554
|
+
},
|
|
531229
531555
|
{ role: "user", content: prompt }
|
|
531230
531556
|
],
|
|
531231
531557
|
tools: [],
|
|
@@ -531274,7 +531600,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531274
531600
|
callable: _smaCallable50
|
|
531275
531601
|
}).then((_smaResult) => {
|
|
531276
531602
|
if (_smaResult.injection && !_smaResult.directive.parseFallback) {
|
|
531277
|
-
messages2.push({
|
|
531603
|
+
messages2.push({
|
|
531604
|
+
role: "system",
|
|
531605
|
+
content: _smaResult.injection
|
|
531606
|
+
});
|
|
531278
531607
|
this.emit({
|
|
531279
531608
|
type: "status",
|
|
531280
531609
|
content: `REG-50 → SSMA fired at turn ${turn} — diagnosis="${_smaResult.directive.diagnosis.slice(0, 80)}", next=${_smaResult.directive.next_action.tool}, ${_smaResult.durationMs}ms`,
|
|
@@ -531367,7 +531696,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531367
531696
|
try {
|
|
531368
531697
|
const _r = await this.backend.chatCompletion({
|
|
531369
531698
|
messages: [
|
|
531370
|
-
{
|
|
531699
|
+
{
|
|
531700
|
+
role: "system",
|
|
531701
|
+
content: "You are a META-STRATEGY VALIDATOR. Audit the implementer's frame-vs-goal alignment and emit a structured JSON verdict."
|
|
531702
|
+
},
|
|
531371
531703
|
{ role: "user", content: prompt }
|
|
531372
531704
|
],
|
|
531373
531705
|
tools: [],
|
|
@@ -531416,7 +531748,10 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531416
531748
|
callable: _pfvCallable
|
|
531417
531749
|
}).then((_pfvResult) => {
|
|
531418
531750
|
if (_pfvResult.injection && !_pfvResult.verdict.parseFallback && _pfvResult.verdict.verdict !== "continue") {
|
|
531419
|
-
messages2.push({
|
|
531751
|
+
messages2.push({
|
|
531752
|
+
role: "system",
|
|
531753
|
+
content: _pfvResult.injection
|
|
531754
|
+
});
|
|
531420
531755
|
this.emit({
|
|
531421
531756
|
type: "status",
|
|
531422
531757
|
content: `REG-51 PFV fired at turn ${turn} — verdict=${_pfvResult.verdict.verdict}, trigger=${_pfvTriggerReason}, ssmaCount=${this._ssmaFiredCount}, ${_pfvResult.durationMs}ms`,
|
|
@@ -531556,10 +531891,7 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531556
531891
|
recentSuccesses,
|
|
531557
531892
|
recentFailures: recentOutcomes.length - recentSuccesses,
|
|
531558
531893
|
intervention: `Extended maxTurns to ${this.options.maxTurns}`,
|
|
531559
|
-
details: [
|
|
531560
|
-
`Recent outcomes:`,
|
|
531561
|
-
...detailsLines
|
|
531562
|
-
].join("\n")
|
|
531894
|
+
details: [`Recent outcomes:`, ...detailsLines].join("\n")
|
|
531563
531895
|
}
|
|
531564
531896
|
});
|
|
531565
531897
|
}
|
|
@@ -531574,13 +531906,22 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
531574
531906
|
const textContent = userMsg.replace(imagePattern, "").trim();
|
|
531575
531907
|
const parts = [];
|
|
531576
531908
|
if (textContent) {
|
|
531577
|
-
parts.push({
|
|
531909
|
+
parts.push({
|
|
531910
|
+
type: "text",
|
|
531911
|
+
text: `[User added context]: ${textContent}
|
|
531578
531912
|
|
|
531579
|
-
Describe what you see and integrate this into your current approach.`
|
|
531913
|
+
Describe what you see and integrate this into your current approach.`
|
|
531914
|
+
});
|
|
531580
531915
|
} else {
|
|
531581
|
-
parts.push({
|
|
531916
|
+
parts.push({
|
|
531917
|
+
type: "text",
|
|
531918
|
+
text: "[User shared an image]. Describe what you see and integrate this into your current approach."
|
|
531919
|
+
});
|
|
531582
531920
|
}
|
|
531583
|
-
parts.push({
|
|
531921
|
+
parts.push({
|
|
531922
|
+
type: "image_url",
|
|
531923
|
+
image_url: { url: `data:${mime};base64,${base642}` }
|
|
531924
|
+
});
|
|
531584
531925
|
messages2.push({ role: "user", content: parts });
|
|
531585
531926
|
} else {
|
|
531586
531927
|
messages2.push({
|
|
@@ -531672,7 +532013,17 @@ Now call file_write with YOUR skeleton for this task.`
|
|
|
531672
532013
|
const taskGoal = this._taskState.goal || "";
|
|
531673
532014
|
const taskLower = taskGoal.toLowerCase();
|
|
531674
532015
|
const taskTokens = new Set(taskLower.split(/\s+/).filter((w) => w.length > 2));
|
|
531675
|
-
const CORE = /* @__PURE__ */ new Set([
|
|
532016
|
+
const CORE = /* @__PURE__ */ new Set([
|
|
532017
|
+
"file_read",
|
|
532018
|
+
"file_write",
|
|
532019
|
+
"file_edit",
|
|
532020
|
+
"shell",
|
|
532021
|
+
"task_complete",
|
|
532022
|
+
"grep_search",
|
|
532023
|
+
"find_files",
|
|
532024
|
+
"list_directory",
|
|
532025
|
+
"file_explore"
|
|
532026
|
+
]);
|
|
531676
532027
|
const toolHints = [];
|
|
531677
532028
|
for (const tool of this.tools.values()) {
|
|
531678
532029
|
if (CORE.has(tool.name))
|
|
@@ -531688,7 +532039,11 @@ Now call file_write with YOUR skeleton for this task.`
|
|
|
531688
532039
|
}
|
|
531689
532040
|
}
|
|
531690
532041
|
if (score > 2)
|
|
531691
|
-
toolHints.push({
|
|
532042
|
+
toolHints.push({
|
|
532043
|
+
name: tool.name,
|
|
532044
|
+
desc: tool.description.slice(0, 80),
|
|
532045
|
+
score
|
|
532046
|
+
});
|
|
531692
532047
|
}
|
|
531693
532048
|
if (toolHints.length > 0) {
|
|
531694
532049
|
toolHints.sort((a2, b) => b.score - a2.score);
|
|
@@ -531957,14 +532312,22 @@ ${memoryLines.join("\n")}`
|
|
|
531957
532312
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
531958
532313
|
} catch (reqErr) {
|
|
531959
532314
|
if (reqErr instanceof Error && reqErr.fatal) {
|
|
531960
|
-
this.emit({
|
|
532315
|
+
this.emit({
|
|
532316
|
+
type: "error",
|
|
532317
|
+
content: `Backend error: ${reqErr.message}`,
|
|
532318
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532319
|
+
});
|
|
531961
532320
|
break;
|
|
531962
532321
|
}
|
|
531963
532322
|
if (this.handleMaxTokensError(reqErr, chatRequest)) {
|
|
531964
532323
|
try {
|
|
531965
532324
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
531966
532325
|
} catch (retryErr) {
|
|
531967
|
-
this.emit({
|
|
532326
|
+
this.emit({
|
|
532327
|
+
type: "error",
|
|
532328
|
+
content: `Retry with reduced max_tokens also failed: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
|
532329
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532330
|
+
});
|
|
531968
532331
|
break;
|
|
531969
532332
|
}
|
|
531970
532333
|
} else {
|
|
@@ -531972,9 +532335,17 @@ ${memoryLines.join("\n")}`
|
|
|
531972
532335
|
if (!recovered) {
|
|
531973
532336
|
const errMsg = reqErr instanceof Error ? reqErr.message : String(reqErr);
|
|
531974
532337
|
const cause = reqErr instanceof Error && reqErr.cause ? ` (${reqErr.cause.message ?? ""} ${reqErr.cause?.code ?? ""})` : "";
|
|
531975
|
-
this.emit({
|
|
532338
|
+
this.emit({
|
|
532339
|
+
type: "error",
|
|
532340
|
+
content: `Backend error: ${errMsg}${cause}`,
|
|
532341
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532342
|
+
});
|
|
531976
532343
|
if (/HTTP 404|not found|model.*not found/i.test(errMsg)) {
|
|
531977
|
-
this.emit({
|
|
532344
|
+
this.emit({
|
|
532345
|
+
type: "error",
|
|
532346
|
+
content: `Model not available. Use /model to select a different model.`,
|
|
532347
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532348
|
+
});
|
|
531978
532349
|
break;
|
|
531979
532350
|
}
|
|
531980
532351
|
let imageRecovered = false;
|
|
@@ -531986,7 +532357,11 @@ ${memoryLines.join("\n")}`
|
|
|
531986
532357
|
response = imgRetry;
|
|
531987
532358
|
} catch (imgRetryErr) {
|
|
531988
532359
|
const msg2 = imgRetryErr instanceof Error ? imgRetryErr.message : String(imgRetryErr);
|
|
531989
|
-
this.emit({
|
|
532360
|
+
this.emit({
|
|
532361
|
+
type: "error",
|
|
532362
|
+
content: `Retry after image fallback also failed: ${msg2}`,
|
|
532363
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532364
|
+
});
|
|
531990
532365
|
imageRecovered = false;
|
|
531991
532366
|
break;
|
|
531992
532367
|
}
|
|
@@ -532027,7 +532402,10 @@ ${memoryLines.join("\n")}`
|
|
|
532027
532402
|
const tool = this.tools.get(parsed.tool);
|
|
532028
532403
|
const result = await tool.execute(parsed.args ?? {});
|
|
532029
532404
|
messages2.push({ role: "assistant", content });
|
|
532030
|
-
messages2.push({
|
|
532405
|
+
messages2.push({
|
|
532406
|
+
role: "user",
|
|
532407
|
+
content: `Tool result (${parsed.tool}): ${result.output.slice(0, 2e3)}`
|
|
532408
|
+
});
|
|
532031
532409
|
if (parsed.tool === "task_complete") {
|
|
532032
532410
|
completed = true;
|
|
532033
532411
|
summary = String(parsed.args?.summary ?? content);
|
|
@@ -532042,7 +532420,11 @@ ${memoryLines.join("\n")}`
|
|
|
532042
532420
|
continue;
|
|
532043
532421
|
} catch (retryErr2) {
|
|
532044
532422
|
const msg2 = retryErr2 instanceof Error ? retryErr2.message : String(retryErr2);
|
|
532045
|
-
this.emit({
|
|
532423
|
+
this.emit({
|
|
532424
|
+
type: "error",
|
|
532425
|
+
content: `Prompt-injected tool mode also failed: ${msg2}`,
|
|
532426
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532427
|
+
});
|
|
532046
532428
|
break;
|
|
532047
532429
|
}
|
|
532048
532430
|
}
|
|
@@ -532102,7 +532484,13 @@ ${memoryLines.join("\n")}`
|
|
|
532102
532484
|
}
|
|
532103
532485
|
}
|
|
532104
532486
|
const firstToolCall = response.choices[0]?.message?.toolCalls?.[0];
|
|
532105
|
-
const HIGH_STAKE_TOOLS = /* @__PURE__ */ new Set([
|
|
532487
|
+
const HIGH_STAKE_TOOLS = /* @__PURE__ */ new Set([
|
|
532488
|
+
"file_write",
|
|
532489
|
+
"file_edit",
|
|
532490
|
+
"batch_edit",
|
|
532491
|
+
"file_patch",
|
|
532492
|
+
"shell"
|
|
532493
|
+
]);
|
|
532106
532494
|
const selfConsistencyK = this.options.selfConsistencyK ?? 0;
|
|
532107
532495
|
const shouldVote = selfConsistencyK >= 2 && this._selfConsistencyVotes < 2 && (this.options.modelTier === "small" || this.options.modelTier === "medium") && firstToolCall && HIGH_STAKE_TOOLS.has(firstToolCall.name) && turn <= 3;
|
|
532108
532496
|
if (shouldVote && firstToolCall) {
|
|
@@ -532197,7 +532585,10 @@ ${memoryLines.join("\n")}`
|
|
|
532197
532585
|
tool_calls: msg.toolCalls.map((tc) => ({
|
|
532198
532586
|
id: tc.id,
|
|
532199
532587
|
type: "function",
|
|
532200
|
-
function: {
|
|
532588
|
+
function: {
|
|
532589
|
+
name: tc.name,
|
|
532590
|
+
arguments: JSON.stringify(tc.arguments)
|
|
532591
|
+
}
|
|
532201
532592
|
}))
|
|
532202
532593
|
});
|
|
532203
532594
|
if (_capDeferredCount > 0) {
|
|
@@ -532221,7 +532612,15 @@ ${memoryLines.join("\n")}`
|
|
|
532221
532612
|
const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
|
|
532222
532613
|
const cohort = this._argCohorts.get(cohortKey);
|
|
532223
532614
|
if (cohort && cohort.failure >= 3 && cohort.success === 0) {
|
|
532224
|
-
this.emit({
|
|
532615
|
+
this.emit({
|
|
532616
|
+
type: "observer_reaction",
|
|
532617
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
532618
|
+
observer: {
|
|
532619
|
+
class: "arg_cohort_risk",
|
|
532620
|
+
shortText: `${tc.name} with similar args has failed ${cohort.failure}× recently`,
|
|
532621
|
+
confidence: 0.85
|
|
532622
|
+
}
|
|
532623
|
+
});
|
|
532225
532624
|
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
532226
532625
|
this.pendingUserMessages.push(`⚠ ${tc.name} with similar arguments has failed ${cohort.failure}× recently. Try a different approach first: read relevant files, adjust arguments, or verify prerequisites.`);
|
|
532227
532626
|
}
|
|
@@ -532239,7 +532638,9 @@ ${memoryLines.join("\n")}`
|
|
|
532239
532638
|
try {
|
|
532240
532639
|
const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
532241
532640
|
if (!this._predictionStore) {
|
|
532242
|
-
this._predictionStore = new memMod.PredictionStore({
|
|
532641
|
+
this._predictionStore = new memMod.PredictionStore({
|
|
532642
|
+
capacity: 256
|
|
532643
|
+
});
|
|
532243
532644
|
this._toolDurationAvg = /* @__PURE__ */ new Map();
|
|
532244
532645
|
try {
|
|
532245
532646
|
if (this._episodeStore && process.env["OA_DISABLE_PREDICTION_PERSISTENCE"] !== "1") {
|
|
@@ -532267,7 +532668,12 @@ ${memoryLines.join("\n")}`
|
|
|
532267
532668
|
} catch {
|
|
532268
532669
|
}
|
|
532269
532670
|
const argsKey = this._buildExactArgsKey(tc.arguments ?? {});
|
|
532270
|
-
toolCallLog.push({
|
|
532671
|
+
toolCallLog.push({
|
|
532672
|
+
name: tc.name,
|
|
532673
|
+
argsKey,
|
|
532674
|
+
turn,
|
|
532675
|
+
timestampMs: Date.now()
|
|
532676
|
+
});
|
|
532271
532677
|
const _toolLogTailIdx = toolCallLog.length - 1;
|
|
532272
532678
|
this._toolLastUsedTurn.set(tc.name, turn);
|
|
532273
532679
|
if (this._contextTree) {
|
|
@@ -532287,7 +532693,7 @@ ${memoryLines.join("\n")}`
|
|
|
532287
532693
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532288
532694
|
});
|
|
532289
532695
|
const summarizer = this.makePhaseSummarizer();
|
|
532290
|
-
const contracted = this._contextTree.contractInactive(turn, summarizer ? (
|
|
532696
|
+
const contracted = this._contextTree.contractInactive(turn, summarizer ? (msgs) => summarizer(transition.from, msgs) : void 0);
|
|
532291
532697
|
if (contracted.length > 0) {
|
|
532292
532698
|
this.emit({
|
|
532293
532699
|
type: "status",
|
|
@@ -532447,7 +532853,13 @@ ${memoryLines.join("\n")}`
|
|
|
532447
532853
|
{
|
|
532448
532854
|
const _decomp2Block = this._maybeDecomp2Block(tc, turn);
|
|
532449
532855
|
if (_decomp2Block) {
|
|
532450
|
-
this.emit({
|
|
532856
|
+
this.emit({
|
|
532857
|
+
type: "tool_call",
|
|
532858
|
+
toolName: tc.name,
|
|
532859
|
+
toolArgs: tc.arguments,
|
|
532860
|
+
turn,
|
|
532861
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532862
|
+
});
|
|
532451
532863
|
this.emit({
|
|
532452
532864
|
type: "tool_result",
|
|
532453
532865
|
toolName: tc.name,
|
|
@@ -532620,11 +533032,24 @@ ${memoryLines.join("\n")}`
|
|
|
532620
533032
|
observerRedundantBlock
|
|
532621
533033
|
});
|
|
532622
533034
|
if (criticDecision.decision === "observer_block") {
|
|
532623
|
-
this.emit({
|
|
533035
|
+
this.emit({
|
|
533036
|
+
type: "tool_call",
|
|
533037
|
+
toolName: tc.name,
|
|
533038
|
+
toolArgs: tc.arguments,
|
|
533039
|
+
turn,
|
|
533040
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533041
|
+
});
|
|
532624
533042
|
const blockMsg = criticDecision.cachedResult ? `[BLOCKED — this tool+args already succeeded. Re-served from cache:]
|
|
532625
533043
|
|
|
532626
533044
|
${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confirmed this tool already succeeded with these arguments on a prior turn. Do NOT re-run. Use your prior findings to proceed.]`;
|
|
532627
|
-
this.emit({
|
|
533045
|
+
this.emit({
|
|
533046
|
+
type: "tool_result",
|
|
533047
|
+
toolName: tc.name,
|
|
533048
|
+
success: true,
|
|
533049
|
+
content: blockMsg.slice(0, 100),
|
|
533050
|
+
turn,
|
|
533051
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533052
|
+
});
|
|
532628
533053
|
this._tagSyntheticFailure({
|
|
532629
533054
|
mode: "step_repetition",
|
|
532630
533055
|
rationale: `observer-block on ${tc.name} fingerprint flagged redundant`
|
|
@@ -532638,7 +533063,13 @@ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confi
|
|
|
532638
533063
|
recentToolResults.delete(toolFingerprint);
|
|
532639
533064
|
recentToolResults.set(toolFingerprint, _existingFp);
|
|
532640
533065
|
}
|
|
532641
|
-
this.emit({
|
|
533066
|
+
this.emit({
|
|
533067
|
+
type: "tool_call",
|
|
533068
|
+
toolName: tc.name,
|
|
533069
|
+
toolArgs: tc.arguments,
|
|
533070
|
+
turn,
|
|
533071
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533072
|
+
});
|
|
532642
533073
|
this.emit({
|
|
532643
533074
|
type: "tool_result",
|
|
532644
533075
|
toolName: tc.name,
|
|
@@ -532702,7 +533133,11 @@ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confi
|
|
|
532702
533133
|
error: `Your tool call had malformed JSON arguments that could not be parsed: "${rawStr}". Please call ${tc.name} again with valid JSON arguments. Make sure to use double quotes for keys and string values, and do not include trailing commas or comments.`
|
|
532703
533134
|
};
|
|
532704
533135
|
} else if (!tool) {
|
|
532705
|
-
result = {
|
|
533136
|
+
result = {
|
|
533137
|
+
success: false,
|
|
533138
|
+
output: "",
|
|
533139
|
+
error: `Unknown tool: ${tc.name}`
|
|
533140
|
+
};
|
|
532706
533141
|
} else {
|
|
532707
533142
|
let validationError = null;
|
|
532708
533143
|
if (tool.inputSchema) {
|
|
@@ -532729,18 +533164,34 @@ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confi
|
|
|
532729
533164
|
const violations = checkConstraints(tc.name, tc.arguments);
|
|
532730
533165
|
const blockViolations = violations.filter((v) => v.constraint.action === "block");
|
|
532731
533166
|
if (blockViolations.length > 0) {
|
|
532732
|
-
result = {
|
|
532733
|
-
|
|
533167
|
+
result = {
|
|
533168
|
+
success: false,
|
|
533169
|
+
output: "",
|
|
533170
|
+
error: `BLOCKED by constraint: ${formatViolationWarning(blockViolations)}`
|
|
533171
|
+
};
|
|
533172
|
+
this.emit({
|
|
533173
|
+
type: "status",
|
|
533174
|
+
content: `Constraint blocked: ${blockViolations[0].constraint.message}`,
|
|
533175
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533176
|
+
});
|
|
532734
533177
|
} else {
|
|
532735
533178
|
const warnViolations = violations.filter((v) => v.constraint.action === "warn");
|
|
532736
533179
|
if (warnViolations.length > 0) {
|
|
532737
533180
|
const warning = formatViolationWarning(warnViolations);
|
|
532738
|
-
this.emit({
|
|
532739
|
-
|
|
532740
|
-
|
|
533181
|
+
this.emit({
|
|
533182
|
+
type: "status",
|
|
533183
|
+
content: `⚠️ ${warning}`,
|
|
533184
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533185
|
+
});
|
|
533186
|
+
pendingConstraintWarnings.push(warning);
|
|
533187
|
+
}
|
|
532741
533188
|
const hookCheck = this._hookManager.runPreToolUse(tc.name, tc.arguments, this._sessionId);
|
|
532742
533189
|
if (!hookCheck.allowed) {
|
|
532743
|
-
result = {
|
|
533190
|
+
result = {
|
|
533191
|
+
success: false,
|
|
533192
|
+
output: "",
|
|
533193
|
+
error: `Blocked by hook: ${hookCheck.reason}`
|
|
533194
|
+
};
|
|
532744
533195
|
recordToolDecision(this._appState, {
|
|
532745
533196
|
toolName: tc.name,
|
|
532746
533197
|
decision: "deny",
|
|
@@ -532764,7 +533215,11 @@ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confi
|
|
|
532764
533215
|
this._lastForecastTurn = turn;
|
|
532765
533216
|
const fc = `[FORECAST] historical success rate for tool "${tc.name}" in domain "${fdomain}" is ${Math.round(recent.rate * 100)}% over ${recent.n} recent calls. Consider an alternative approach or break the task down before retrying.`;
|
|
532766
533217
|
messages2.push({ role: "system", content: fc });
|
|
532767
|
-
this.emit({
|
|
533218
|
+
this.emit({
|
|
533219
|
+
type: "status",
|
|
533220
|
+
content: fc,
|
|
533221
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533222
|
+
});
|
|
532768
533223
|
}
|
|
532769
533224
|
} catch {
|
|
532770
533225
|
}
|
|
@@ -532832,7 +533287,10 @@ ${criticDecision.cachedResult.slice(0, 500)}` : `[BLOCKED — the observer confi
|
|
|
532832
533287
|
const obs = tracker.observe(((result.output ?? "") + "\n" + (result.error ?? "")).slice(0, 1e5), scope);
|
|
532833
533288
|
if (obs.summaryLine) {
|
|
532834
533289
|
if (obs.hasCritical) {
|
|
532835
|
-
messages2.push({
|
|
533290
|
+
messages2.push({
|
|
533291
|
+
role: "system",
|
|
533292
|
+
content: obs.summaryLine
|
|
533293
|
+
});
|
|
532836
533294
|
if (process.env["OA_DISABLE_REG59"] !== "1") {
|
|
532837
533295
|
const _errCtx59 = this._buildErrorContextPreamble();
|
|
532838
533296
|
messages2.push({
|
|
@@ -532868,7 +533326,11 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
532868
533326
|
}
|
|
532869
533327
|
this._hookManager.runPostToolUse(tc.name, finalArgs, (result.output ?? "").slice(0, 2e3), this._sessionId);
|
|
532870
533328
|
} catch (err) {
|
|
532871
|
-
result = {
|
|
533329
|
+
result = {
|
|
533330
|
+
success: false,
|
|
533331
|
+
output: "",
|
|
533332
|
+
error: err instanceof Error ? err.message : String(err)
|
|
533333
|
+
};
|
|
532872
533334
|
this._hookManager.runPostToolUseFailure(tc.name, finalArgs, result.error ?? "", this._sessionId);
|
|
532873
533335
|
}
|
|
532874
533336
|
}
|
|
@@ -532885,7 +533347,11 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
532885
533347
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
532886
533348
|
});
|
|
532887
533349
|
}
|
|
532888
|
-
const updated = this._argCohorts.get(cohortKey) || {
|
|
533350
|
+
const updated = this._argCohorts.get(cohortKey) || {
|
|
533351
|
+
success: 0,
|
|
533352
|
+
failure: 0,
|
|
533353
|
+
lastOutcomeTurn: turn
|
|
533354
|
+
};
|
|
532889
533355
|
if (result.success)
|
|
532890
533356
|
updated.success++;
|
|
532891
533357
|
else
|
|
@@ -532962,12 +533428,19 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
532962
533428
|
}
|
|
532963
533429
|
} else if (tc.name === "list_directory") {
|
|
532964
533430
|
const dir = String(tc.arguments?.["path"] ?? ".");
|
|
532965
|
-
this._worldFacts.lastLists.set(dir, {
|
|
533431
|
+
this._worldFacts.lastLists.set(dir, {
|
|
533432
|
+
entriesCount: (result.output.match(/\n/g) || []).length + 1,
|
|
533433
|
+
lastSeenTurn: turn
|
|
533434
|
+
});
|
|
532966
533435
|
} else if (tc.name === "shell") {
|
|
532967
533436
|
const cmd = String(tc.arguments?.["command"] ?? "");
|
|
532968
533437
|
if (/\b(npm|pnpm|yarn)\s+test\b|\bjest\b|\bvitest\b/i.test(cmd)) {
|
|
532969
533438
|
const passed = /PASS|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
|
|
532970
|
-
this._worldFacts.lastTest = {
|
|
533439
|
+
this._worldFacts.lastTest = {
|
|
533440
|
+
passed,
|
|
533441
|
+
summary: result.output.slice(0, 200),
|
|
533442
|
+
turn
|
|
533443
|
+
};
|
|
532971
533444
|
}
|
|
532972
533445
|
if (/^cd\s+/.test(cmd)) {
|
|
532973
533446
|
const m2 = cmd.match(/^cd\s+([^&;\n]+)/);
|
|
@@ -533041,7 +533514,12 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533041
533514
|
toolName: "prediction_error",
|
|
533042
533515
|
content: `prediction error on ${err.prediction.action} (axis=${err.dominantAxis}): predicted ${err.prediction.predictedSuccess ? "success" : "failure"}, got ${err.actualSuccess ? "success" : "failure"}`,
|
|
533043
533516
|
importance: Math.min(10, 7 + Math.round(err.errorMagnitude * 3)),
|
|
533044
|
-
metadata: {
|
|
533517
|
+
metadata: {
|
|
533518
|
+
predictionError: {
|
|
533519
|
+
magnitude: err.errorMagnitude,
|
|
533520
|
+
axis: err.dominantAxis
|
|
533521
|
+
}
|
|
533522
|
+
}
|
|
533045
533523
|
});
|
|
533046
533524
|
if (process.env["OA_DISABLE_SOCIAL_MEMORY"] !== "1") {
|
|
533047
533525
|
if (!this._socialMemory) {
|
|
@@ -533058,7 +533536,12 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533058
533536
|
}
|
|
533059
533537
|
}
|
|
533060
533538
|
if (process.env["OA_DISABLE_SOCIAL_MEMORY"] !== "1") {
|
|
533061
|
-
const SUB_AGENT_TOOLS = /* @__PURE__ */ new Set([
|
|
533539
|
+
const SUB_AGENT_TOOLS = /* @__PURE__ */ new Set([
|
|
533540
|
+
"sub_agent",
|
|
533541
|
+
"background_run",
|
|
533542
|
+
"priority_delegate",
|
|
533543
|
+
"skill_execute"
|
|
533544
|
+
]);
|
|
533062
533545
|
if (SUB_AGENT_TOOLS.has(tc.name)) {
|
|
533063
533546
|
try {
|
|
533064
533547
|
if (!this._socialMemory) {
|
|
@@ -533066,7 +533549,11 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533066
533549
|
}
|
|
533067
533550
|
const social = this._socialMemory;
|
|
533068
533551
|
const otherId = `${tc.name}:${String(tc.arguments?.["agent_id"] ?? tc.arguments?.["name"] ?? tc.arguments?.["target"] ?? "anonymous").slice(0, 60)}`;
|
|
533069
|
-
social.upsertAgent({
|
|
533552
|
+
social.upsertAgent({
|
|
533553
|
+
id: otherId,
|
|
533554
|
+
name: otherId,
|
|
533555
|
+
type: "agent"
|
|
533556
|
+
});
|
|
533070
533557
|
social.recordRelationshipEvent("self", otherId, {
|
|
533071
533558
|
event: groundTruthSuccess ? "successful collaboration" : "failed collaboration",
|
|
533072
533559
|
impactOnStrength: 0.05,
|
|
@@ -533117,7 +533604,10 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533117
533604
|
// upstream LLM confidence not surfaced here yet
|
|
533118
533605
|
contextTokensUsed: ctxTokens,
|
|
533119
533606
|
contextTokensMax: ctxMax,
|
|
533120
|
-
affect: this._homeostat?.current ?? {
|
|
533607
|
+
affect: this._homeostat?.current ?? {
|
|
533608
|
+
valence: 0,
|
|
533609
|
+
arousal: 0
|
|
533610
|
+
},
|
|
533121
533611
|
timeOfDay: (/* @__PURE__ */ new Date()).getHours(),
|
|
533122
533612
|
sessionDurationMin: typeof this._sessionStartMs === "number" ? Math.round((Date.now() - this._sessionStartMs) / 6e4) : 0,
|
|
533123
533613
|
consecutiveActions: typeof this._consecutiveToolCalls === "number" ? this._consecutiveToolCalls : 0
|
|
@@ -533139,7 +533629,13 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533139
533629
|
} catch {
|
|
533140
533630
|
}
|
|
533141
533631
|
}
|
|
533142
|
-
const isHighValue = [
|
|
533632
|
+
const isHighValue = [
|
|
533633
|
+
"file_write",
|
|
533634
|
+
"file_edit",
|
|
533635
|
+
"file_patch",
|
|
533636
|
+
"batch_edit",
|
|
533637
|
+
"task_complete"
|
|
533638
|
+
].includes(tc.name) || episodeModality === "reflection" || episodeModality === "gist" || episodeModality === "social";
|
|
533143
533639
|
this._toolSequence.push(tc.name);
|
|
533144
533640
|
let episodeId;
|
|
533145
533641
|
if (this._crlMemoryStore && isHighValue) {
|
|
@@ -533161,7 +533657,10 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533161
533657
|
});
|
|
533162
533658
|
}
|
|
533163
533659
|
if (this._embeddingAvailable && episodeContent.length > 20) {
|
|
533164
|
-
this._pendingEmbeddings.push({
|
|
533660
|
+
this._pendingEmbeddings.push({
|
|
533661
|
+
id: episodeId,
|
|
533662
|
+
content: episodeContent.slice(0, 500)
|
|
533663
|
+
});
|
|
533165
533664
|
}
|
|
533166
533665
|
if (this._temporalGraph) {
|
|
533167
533666
|
try {
|
|
@@ -533175,7 +533674,12 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533175
533674
|
text: filePath2,
|
|
533176
533675
|
nodeType: "file"
|
|
533177
533676
|
});
|
|
533178
|
-
const relation = [
|
|
533677
|
+
const relation = [
|
|
533678
|
+
"file_write",
|
|
533679
|
+
"file_edit",
|
|
533680
|
+
"file_patch",
|
|
533681
|
+
"batch_edit"
|
|
533682
|
+
].includes(tc.name) ? "modified_by" : "related_to";
|
|
533179
533683
|
this._temporalGraph.addEdge({
|
|
533180
533684
|
srcId: fileNodeId,
|
|
533181
533685
|
dstId: toolNodeId,
|
|
@@ -533258,7 +533762,13 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533258
533762
|
default:
|
|
533259
533763
|
guidance = `This tool failed previously with a similar error. Review the error message carefully and adjust your approach before retrying.`;
|
|
533260
533764
|
}
|
|
533261
|
-
this._errorPatterns.set(sig, {
|
|
533765
|
+
this._errorPatterns.set(sig, {
|
|
533766
|
+
count,
|
|
533767
|
+
guidance,
|
|
533768
|
+
lastSeen: Date.now(),
|
|
533769
|
+
tool: tc.name,
|
|
533770
|
+
errorType
|
|
533771
|
+
});
|
|
533262
533772
|
if (this._failureStore) {
|
|
533263
533773
|
try {
|
|
533264
533774
|
this._failureStore.insert({
|
|
@@ -533412,7 +533922,10 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533412
533922
|
}
|
|
533413
533923
|
}
|
|
533414
533924
|
if (isReadLike && result.success) {
|
|
533415
|
-
recentToolResults.set(toolFingerprint, {
|
|
533925
|
+
recentToolResults.set(toolFingerprint, {
|
|
533926
|
+
result: (result.output ?? "").slice(0, 2e3),
|
|
533927
|
+
compacted: false
|
|
533928
|
+
});
|
|
533416
533929
|
if (recentToolResults.size > 500) {
|
|
533417
533930
|
const firstKey = recentToolResults.keys().next().value;
|
|
533418
533931
|
if (firstKey !== void 0) {
|
|
@@ -533544,7 +534057,11 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533544
534057
|
try {
|
|
533545
534058
|
result = await tool.execute(tc.arguments);
|
|
533546
534059
|
} catch (err) {
|
|
533547
|
-
result = {
|
|
534060
|
+
result = {
|
|
534061
|
+
success: false,
|
|
534062
|
+
output: "",
|
|
534063
|
+
error: err instanceof Error ? err.message : String(err)
|
|
534064
|
+
};
|
|
533548
534065
|
}
|
|
533549
534066
|
}
|
|
533550
534067
|
}
|
|
@@ -533552,9 +534069,16 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533552
534069
|
const unlockName = result.output.slice("UNLOCK_TOOL:".length).trim();
|
|
533553
534070
|
const existingTool = this.tools.get(unlockName);
|
|
533554
534071
|
if (existingTool) {
|
|
533555
|
-
result = {
|
|
534072
|
+
result = {
|
|
534073
|
+
success: true,
|
|
534074
|
+
output: `Tool '${unlockName}' is now unlocked and available. You can use it in your next response.`
|
|
534075
|
+
};
|
|
533556
534076
|
} else {
|
|
533557
|
-
result = {
|
|
534077
|
+
result = {
|
|
534078
|
+
success: false,
|
|
534079
|
+
output: "",
|
|
534080
|
+
error: `Unknown tool '${unlockName}'. Call explore_tools() with no args to see available tools.`
|
|
534081
|
+
};
|
|
533558
534082
|
}
|
|
533559
534083
|
}
|
|
533560
534084
|
let output = this.normalizeToolOutput(result, tc.name, tc.arguments, turn);
|
|
@@ -533597,7 +534121,10 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
533597
534121
|
try {
|
|
533598
534122
|
if (process.env["OA_DISABLE_MIDTURN_RETRIEVAL"] !== "1" && this._episodeStore && stagnationCooldownUntilTurn <= turn && typeof errMsg === "string" && errMsg.length >= 8) {
|
|
533599
534123
|
const query = `${tc.name} ${errMsg}`.slice(0, 240);
|
|
533600
|
-
const past = this._episodeStore.search({
|
|
534124
|
+
const past = this._episodeStore.search({
|
|
534125
|
+
query,
|
|
534126
|
+
limit: 2
|
|
534127
|
+
});
|
|
533601
534128
|
const useful = past.filter((p2) => p2.content && p2.content.length > 10).slice(0, 1);
|
|
533602
534129
|
if (useful.length > 0) {
|
|
533603
534130
|
const u = useful[0];
|
|
@@ -533779,7 +534306,11 @@ Do NOT retry ${tc.name} with similar arguments.`);
|
|
|
533779
534306
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533780
534307
|
});
|
|
533781
534308
|
}
|
|
533782
|
-
const enoentTools = /* @__PURE__ */ new Set([
|
|
534309
|
+
const enoentTools = /* @__PURE__ */ new Set([
|
|
534310
|
+
"file_read",
|
|
534311
|
+
"list_directory",
|
|
534312
|
+
"find_files"
|
|
534313
|
+
]);
|
|
533783
534314
|
const fsErrorStr = result.error ?? result.output;
|
|
533784
534315
|
const isEnoent = !result.success && enoentTools.has(tc.name) && /ENOENT|no such file|does not exist|not found/i.test(fsErrorStr);
|
|
533785
534316
|
const isEisdir = !result.success && tc.name === "file_read" && /EISDIR|illegal operation on a directory|is a directory/i.test(fsErrorStr);
|
|
@@ -533822,7 +534353,13 @@ Then use file_read on individual FILES inside it.`);
|
|
|
533822
534353
|
messages2.push({
|
|
533823
534354
|
role: "assistant",
|
|
533824
534355
|
content: null,
|
|
533825
|
-
tool_calls: [
|
|
534356
|
+
tool_calls: [
|
|
534357
|
+
{
|
|
534358
|
+
id: synthId,
|
|
534359
|
+
type: "function",
|
|
534360
|
+
function: { name: name10, arguments: JSON.stringify(args) }
|
|
534361
|
+
}
|
|
534362
|
+
]
|
|
533826
534363
|
});
|
|
533827
534364
|
}
|
|
533828
534365
|
const tcToRun = matchTc;
|
|
@@ -533830,7 +534367,11 @@ Then use file_read on individual FILES inside it.`);
|
|
|
533830
534367
|
if (!r2)
|
|
533831
534368
|
return { success: false, output: "", error: "aborted" };
|
|
533832
534369
|
const isError2 = r2.output.startsWith("Error:");
|
|
533833
|
-
return {
|
|
534370
|
+
return {
|
|
534371
|
+
success: !isError2,
|
|
534372
|
+
output: r2.output,
|
|
534373
|
+
error: isError2 ? r2.output : void 0
|
|
534374
|
+
};
|
|
533834
534375
|
});
|
|
533835
534376
|
await this._streamingExecutor.waitAll();
|
|
533836
534377
|
const streamResults = this._streamingExecutor.drainCompleted();
|
|
@@ -533860,7 +534401,12 @@ ${sr.result.output}`;
|
|
|
533860
534401
|
completed = true;
|
|
533861
534402
|
summary = extractTaskCompleteSummary(matchTc.arguments);
|
|
533862
534403
|
if (summary && !this._assistantTextEmitted) {
|
|
533863
|
-
this.emit({
|
|
534404
|
+
this.emit({
|
|
534405
|
+
type: "assistant_text",
|
|
534406
|
+
content: summary,
|
|
534407
|
+
turn,
|
|
534408
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534409
|
+
});
|
|
533864
534410
|
this._assistantTextEmitted = true;
|
|
533865
534411
|
}
|
|
533866
534412
|
break;
|
|
@@ -533895,7 +534441,12 @@ ${sr.result.output}`;
|
|
|
533895
534441
|
completed = true;
|
|
533896
534442
|
summary = extractTaskCompleteSummary(r2.tc.arguments);
|
|
533897
534443
|
if (summary && !this._assistantTextEmitted) {
|
|
533898
|
-
this.emit({
|
|
534444
|
+
this.emit({
|
|
534445
|
+
type: "assistant_text",
|
|
534446
|
+
content: summary,
|
|
534447
|
+
turn,
|
|
534448
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534449
|
+
});
|
|
533899
534450
|
this._assistantTextEmitted = true;
|
|
533900
534451
|
}
|
|
533901
534452
|
break;
|
|
@@ -533934,7 +534485,10 @@ ${sr.result.output}`;
|
|
|
533934
534485
|
const cloned = await inflight;
|
|
533935
534486
|
if (!cloned)
|
|
533936
534487
|
return null;
|
|
533937
|
-
return {
|
|
534488
|
+
return {
|
|
534489
|
+
tc: { ...cloned.tc, id: call.id },
|
|
534490
|
+
output: cloned.output
|
|
534491
|
+
};
|
|
533938
534492
|
}
|
|
533939
534493
|
}
|
|
533940
534494
|
const promise = executeSingle(originalTc);
|
|
@@ -533962,7 +534516,12 @@ ${sr.result.output}`;
|
|
|
533962
534516
|
completed = true;
|
|
533963
534517
|
summary = extractTaskCompleteSummary(r2.tc.arguments);
|
|
533964
534518
|
if (summary && !this._assistantTextEmitted) {
|
|
533965
|
-
this.emit({
|
|
534519
|
+
this.emit({
|
|
534520
|
+
type: "assistant_text",
|
|
534521
|
+
content: summary,
|
|
534522
|
+
turn,
|
|
534523
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534524
|
+
});
|
|
533966
534525
|
this._assistantTextEmitted = true;
|
|
533967
534526
|
}
|
|
533968
534527
|
break;
|
|
@@ -534052,7 +534611,10 @@ Call task_complete(summary="...") NOW with whatever you have.`
|
|
|
534052
534611
|
try {
|
|
534053
534612
|
const _r = await this.backend.chatCompletion({
|
|
534054
534613
|
messages: [
|
|
534055
|
-
{
|
|
534614
|
+
{
|
|
534615
|
+
role: "system",
|
|
534616
|
+
content: "You are a META-ANALYSIS sub-agent. Audit the implementer's stuck state and emit a structured JSON directive."
|
|
534617
|
+
},
|
|
534056
534618
|
{ role: "user", content: prompt }
|
|
534057
534619
|
],
|
|
534058
534620
|
tools: [],
|
|
@@ -534084,7 +534646,11 @@ Call task_complete(summary="...") NOW with whatever you have.`
|
|
|
534084
534646
|
return [];
|
|
534085
534647
|
}
|
|
534086
534648
|
})();
|
|
534087
|
-
const _smaFailures = Array.from(this._failureReflections.entries()).map(([stem, entry]) => ({
|
|
534649
|
+
const _smaFailures = Array.from(this._failureReflections.entries()).map(([stem, entry]) => ({
|
|
534650
|
+
stem,
|
|
534651
|
+
attempts: entry.attempts,
|
|
534652
|
+
preview: (entry.wentWrong || "").slice(0, 200)
|
|
534653
|
+
})).sort((a2, b) => b.attempts - a2.attempts).slice(0, 5);
|
|
534088
534654
|
const _smaTools = Array.from(this.tools.keys());
|
|
534089
534655
|
this._ssmaFiredCount++;
|
|
534090
534656
|
runStuckAnalyzer({
|
|
@@ -534102,7 +534668,10 @@ Call task_complete(summary="...") NOW with whatever you have.`
|
|
|
534102
534668
|
callable: _smaCallable
|
|
534103
534669
|
}).then((_smaResult) => {
|
|
534104
534670
|
if (_smaResult.injection && !_smaResult.directive.parseFallback) {
|
|
534105
|
-
messages2.push({
|
|
534671
|
+
messages2.push({
|
|
534672
|
+
role: "system",
|
|
534673
|
+
content: _smaResult.injection
|
|
534674
|
+
});
|
|
534106
534675
|
this.emit({
|
|
534107
534676
|
type: "status",
|
|
534108
534677
|
content: `REG-49 stuck-meta-analyzer fired (loop-intervention path) at turn ${turn} — diagnosis="${_smaResult.directive.diagnosis.slice(0, 80)}", next=${_smaResult.directive.next_action.tool}, ${_smaResult.durationMs}ms`,
|
|
@@ -534146,7 +534715,12 @@ Call task_complete(summary="...") NOW with whatever you have.`
|
|
|
534146
534715
|
});
|
|
534147
534716
|
const cleanNonStream = content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
534148
534717
|
if (cleanNonStream) {
|
|
534149
|
-
this.emit({
|
|
534718
|
+
this.emit({
|
|
534719
|
+
type: "assistant_text",
|
|
534720
|
+
content: cleanNonStream,
|
|
534721
|
+
turn,
|
|
534722
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534723
|
+
});
|
|
534150
534724
|
}
|
|
534151
534725
|
if (/task.?complete|all tests pass/i.test(content)) {
|
|
534152
534726
|
completed = true;
|
|
@@ -534192,15 +534766,22 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
|
|
|
534192
534766
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534193
534767
|
});
|
|
534194
534768
|
try {
|
|
534195
|
-
const shellResult = await shellTool.execute({
|
|
534769
|
+
const shellResult = await shellTool.execute({
|
|
534770
|
+
command: shellCommands
|
|
534771
|
+
});
|
|
534196
534772
|
messages2.push({
|
|
534197
534773
|
role: "assistant",
|
|
534198
534774
|
content: null,
|
|
534199
|
-
tool_calls: [
|
|
534200
|
-
|
|
534201
|
-
|
|
534202
|
-
|
|
534203
|
-
|
|
534775
|
+
tool_calls: [
|
|
534776
|
+
{
|
|
534777
|
+
id: `auto-${Date.now()}`,
|
|
534778
|
+
type: "function",
|
|
534779
|
+
function: {
|
|
534780
|
+
name: "shell",
|
|
534781
|
+
arguments: JSON.stringify({ command: shellCommands })
|
|
534782
|
+
}
|
|
534783
|
+
}
|
|
534784
|
+
]
|
|
534204
534785
|
});
|
|
534205
534786
|
messages2.push({
|
|
534206
534787
|
role: "tool",
|
|
@@ -534326,12 +534907,20 @@ You have ${this.options.maxTurns} more turns. Continue making progress. Call tas
|
|
|
534326
534907
|
if (this._paused) {
|
|
534327
534908
|
const shouldContinue = await this.waitIfPaused();
|
|
534328
534909
|
if (!shouldContinue) {
|
|
534329
|
-
this.emit({
|
|
534910
|
+
this.emit({
|
|
534911
|
+
type: "error",
|
|
534912
|
+
content: "Task aborted by user",
|
|
534913
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534914
|
+
});
|
|
534330
534915
|
break;
|
|
534331
534916
|
}
|
|
534332
534917
|
}
|
|
534333
534918
|
if (this.aborted) {
|
|
534334
|
-
this.emit({
|
|
534919
|
+
this.emit({
|
|
534920
|
+
type: "error",
|
|
534921
|
+
content: "Task aborted by user",
|
|
534922
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534923
|
+
});
|
|
534335
534924
|
break;
|
|
534336
534925
|
}
|
|
534337
534926
|
this._runReg61Check(turn, toolCallLog, messages2, `bf-cycle ${bruteForceCycle}`);
|
|
@@ -534361,20 +534950,37 @@ You have ${this.options.maxTurns} more turns. Continue making progress. Call tas
|
|
|
534361
534950
|
const textContent = userMsg.replace(imagePattern, "").trim();
|
|
534362
534951
|
const parts = [];
|
|
534363
534952
|
if (textContent) {
|
|
534364
|
-
parts.push({
|
|
534953
|
+
parts.push({
|
|
534954
|
+
type: "text",
|
|
534955
|
+
text: `[User added context]: ${textContent}
|
|
534365
534956
|
|
|
534366
|
-
Describe what you see and integrate this into your current approach.`
|
|
534957
|
+
Describe what you see and integrate this into your current approach.`
|
|
534958
|
+
});
|
|
534367
534959
|
} else {
|
|
534368
|
-
parts.push({
|
|
534960
|
+
parts.push({
|
|
534961
|
+
type: "text",
|
|
534962
|
+
text: "[User shared an image]. Describe what you see and integrate this into your current approach."
|
|
534963
|
+
});
|
|
534369
534964
|
}
|
|
534370
|
-
parts.push({
|
|
534965
|
+
parts.push({
|
|
534966
|
+
type: "image_url",
|
|
534967
|
+
image_url: { url: `data:${mime};base64,${base642}` }
|
|
534968
|
+
});
|
|
534371
534969
|
messages2.push({ role: "user", content: parts });
|
|
534372
534970
|
} else {
|
|
534373
|
-
messages2.push({
|
|
534971
|
+
messages2.push({
|
|
534972
|
+
role: "user",
|
|
534973
|
+
content: `[User added context]: ${userMsg}
|
|
534374
534974
|
|
|
534375
|
-
Integrate this guidance into your current approach. Continue working on the task.`
|
|
534975
|
+
Integrate this guidance into your current approach. Continue working on the task.`
|
|
534976
|
+
});
|
|
534376
534977
|
}
|
|
534377
|
-
this.emit({
|
|
534978
|
+
this.emit({
|
|
534979
|
+
type: "user_interrupt",
|
|
534980
|
+
content: userMsg.replace(/\[IMAGE_BASE64:[^\]]+\]/, "[image]").slice(0, 200),
|
|
534981
|
+
turn,
|
|
534982
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534983
|
+
});
|
|
534378
534984
|
}
|
|
534379
534985
|
let compactedMsgs;
|
|
534380
534986
|
if (this._pendingCompaction) {
|
|
@@ -534387,20 +534993,34 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
534387
534993
|
this.proactivePrune(compactedMsgs, this._taskState.toolCallCount);
|
|
534388
534994
|
this.microcompact(compactedMsgs);
|
|
534389
534995
|
this.surfaceAnchors(compactedMsgs);
|
|
534390
|
-
const chatRequest = {
|
|
534996
|
+
const chatRequest = {
|
|
534997
|
+
messages: compactedMsgs,
|
|
534998
|
+
tools: toolDefs,
|
|
534999
|
+
temperature: this.options.temperature,
|
|
535000
|
+
maxTokens: this.options.maxTokens,
|
|
535001
|
+
timeoutMs: this.options.requestTimeoutMs
|
|
535002
|
+
};
|
|
534391
535003
|
let response;
|
|
534392
535004
|
try {
|
|
534393
535005
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
534394
535006
|
} catch (reqErr) {
|
|
534395
535007
|
if (this.aborted || reqErr instanceof Error && reqErr.name === "AbortError") {
|
|
534396
|
-
this.emit({
|
|
535008
|
+
this.emit({
|
|
535009
|
+
type: "error",
|
|
535010
|
+
content: "Task aborted by user",
|
|
535011
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535012
|
+
});
|
|
534397
535013
|
break;
|
|
534398
535014
|
}
|
|
534399
535015
|
if (this.handleMaxTokensError(reqErr, chatRequest)) {
|
|
534400
535016
|
try {
|
|
534401
535017
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
534402
535018
|
} catch (retryErr) {
|
|
534403
|
-
this.emit({
|
|
535019
|
+
this.emit({
|
|
535020
|
+
type: "error",
|
|
535021
|
+
content: `Retry with reduced max_tokens also failed: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
|
535022
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535023
|
+
});
|
|
534404
535024
|
break;
|
|
534405
535025
|
}
|
|
534406
535026
|
} else {
|
|
@@ -534408,8 +535028,16 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
534408
535028
|
if (!recovered) {
|
|
534409
535029
|
const errMsg2 = reqErr instanceof Error ? reqErr.message : String(reqErr);
|
|
534410
535030
|
const cause2 = reqErr instanceof Error && reqErr.cause ? ` (${reqErr.cause.message ?? ""} ${reqErr.cause?.code ?? ""})` : "";
|
|
534411
|
-
this.emit({
|
|
534412
|
-
|
|
535031
|
+
this.emit({
|
|
535032
|
+
type: "error",
|
|
535033
|
+
content: `Backend error: ${errMsg2}${cause2}`,
|
|
535034
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535035
|
+
});
|
|
535036
|
+
this.emit({
|
|
535037
|
+
type: "error",
|
|
535038
|
+
content: `Backend unavailable — stopping task.`,
|
|
535039
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535040
|
+
});
|
|
534413
535041
|
break;
|
|
534414
535042
|
}
|
|
534415
535043
|
response = recovered;
|
|
@@ -534455,7 +535083,18 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
534455
535083
|
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
534456
535084
|
consecutiveTextOnly = 0;
|
|
534457
535085
|
consecutiveThinkOnly = 0;
|
|
534458
|
-
messages2.push({
|
|
535086
|
+
messages2.push({
|
|
535087
|
+
role: "assistant",
|
|
535088
|
+
content: msg.content || null,
|
|
535089
|
+
tool_calls: msg.toolCalls.map((tc) => ({
|
|
535090
|
+
id: tc.id,
|
|
535091
|
+
type: "function",
|
|
535092
|
+
function: {
|
|
535093
|
+
name: tc.name,
|
|
535094
|
+
arguments: JSON.stringify(tc.arguments)
|
|
535095
|
+
}
|
|
535096
|
+
}))
|
|
535097
|
+
});
|
|
534459
535098
|
for (const tc of msg.toolCalls) {
|
|
534460
535099
|
if (this.aborted)
|
|
534461
535100
|
break;
|
|
@@ -534480,7 +535119,7 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
534480
535119
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
534481
535120
|
});
|
|
534482
535121
|
const summarizer = this.makePhaseSummarizer();
|
|
534483
|
-
const contracted = this._contextTree.contractInactive(turn, summarizer ? (
|
|
535122
|
+
const contracted = this._contextTree.contractInactive(turn, summarizer ? (msgs) => summarizer(transition.from, msgs) : void 0);
|
|
534484
535123
|
if (contracted.length > 0) {
|
|
534485
535124
|
this.emit({
|
|
534486
535125
|
type: "status",
|
|
@@ -534493,32 +535132,61 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
534493
535132
|
this._taskState.phaseSince = turn;
|
|
534494
535133
|
}
|
|
534495
535134
|
}
|
|
534496
|
-
this.emit({
|
|
535135
|
+
this.emit({
|
|
535136
|
+
type: "tool_call",
|
|
535137
|
+
toolName: tc.name,
|
|
535138
|
+
toolArgs: tc.arguments,
|
|
535139
|
+
turn,
|
|
535140
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535141
|
+
});
|
|
534497
535142
|
const _decomp2BFBlock = this._maybeDecomp2Block(tc, turn);
|
|
534498
535143
|
if (_decomp2BFBlock) {
|
|
534499
|
-
this.emit({
|
|
535144
|
+
this.emit({
|
|
535145
|
+
type: "tool_result",
|
|
535146
|
+
toolName: tc.name,
|
|
535147
|
+
content: _decomp2BFBlock.slice(0, 200),
|
|
535148
|
+
success: false,
|
|
535149
|
+
turn,
|
|
535150
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535151
|
+
});
|
|
534500
535152
|
messages2.push(this.buildToolMessage(_decomp2BFBlock, tc.id, tc.name));
|
|
534501
535153
|
continue;
|
|
534502
535154
|
}
|
|
534503
535155
|
const tool = this.tools.get(tc.name);
|
|
534504
535156
|
let result;
|
|
534505
535157
|
if (!tool) {
|
|
534506
|
-
result = {
|
|
535158
|
+
result = {
|
|
535159
|
+
success: false,
|
|
535160
|
+
output: "",
|
|
535161
|
+
error: `Unknown tool: ${tc.name}`
|
|
535162
|
+
};
|
|
534507
535163
|
} else {
|
|
534508
535164
|
try {
|
|
534509
535165
|
result = await tool.execute(tc.arguments);
|
|
534510
535166
|
} catch (err) {
|
|
534511
|
-
result = {
|
|
535167
|
+
result = {
|
|
535168
|
+
success: false,
|
|
535169
|
+
output: "",
|
|
535170
|
+
error: err instanceof Error ? err.message : String(err)
|
|
535171
|
+
};
|
|
534512
535172
|
}
|
|
534513
535173
|
}
|
|
534514
535174
|
if (!result.success && tc.name === "shell" && /\[PERMISSION_ERROR\]/.test(result.error ?? "")) {
|
|
534515
|
-
this.emit({
|
|
535175
|
+
this.emit({
|
|
535176
|
+
type: "sudo_request",
|
|
535177
|
+
content: `Command requires elevated privileges: ${tc.arguments.command?.slice(0, 100) ?? ""}`,
|
|
535178
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535179
|
+
});
|
|
534516
535180
|
const pw2 = await this.waitForSudoPassword(12e4);
|
|
534517
535181
|
if (pw2 && tool) {
|
|
534518
535182
|
try {
|
|
534519
535183
|
result = await tool.execute(tc.arguments);
|
|
534520
535184
|
} catch (err) {
|
|
534521
|
-
result = {
|
|
535185
|
+
result = {
|
|
535186
|
+
success: false,
|
|
535187
|
+
output: "",
|
|
535188
|
+
error: err instanceof Error ? err.message : String(err)
|
|
535189
|
+
};
|
|
534522
535190
|
}
|
|
534523
535191
|
}
|
|
534524
535192
|
}
|
|
@@ -534547,9 +535215,20 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534547
535215
|
} else {
|
|
534548
535216
|
output = modelContent2;
|
|
534549
535217
|
}
|
|
534550
|
-
this.emit({
|
|
535218
|
+
this.emit({
|
|
535219
|
+
type: "tool_result",
|
|
535220
|
+
toolName: tc.name,
|
|
535221
|
+
content: output.slice(0, 200),
|
|
535222
|
+
success: result.success,
|
|
535223
|
+
turn,
|
|
535224
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535225
|
+
});
|
|
534551
535226
|
this._trackDecomp2(tc, result, turn);
|
|
534552
|
-
const enoentTools2 = /* @__PURE__ */ new Set([
|
|
535227
|
+
const enoentTools2 = /* @__PURE__ */ new Set([
|
|
535228
|
+
"file_read",
|
|
535229
|
+
"list_directory",
|
|
535230
|
+
"find_files"
|
|
535231
|
+
]);
|
|
534553
535232
|
if (!result.success && enoentTools2.has(tc.name) && /ENOENT|no such file|does not exist|not found/i.test(result.error ?? result.output)) {
|
|
534554
535233
|
this._consecutiveEnoent++;
|
|
534555
535234
|
if (this._consecutiveEnoent >= 2) {
|
|
@@ -534584,7 +535263,12 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534584
535263
|
completed = true;
|
|
534585
535264
|
summary = extractTaskCompleteSummary(tc.arguments);
|
|
534586
535265
|
if (summary && !this._assistantTextEmitted) {
|
|
534587
|
-
this.emit({
|
|
535266
|
+
this.emit({
|
|
535267
|
+
type: "assistant_text",
|
|
535268
|
+
content: summary,
|
|
535269
|
+
turn,
|
|
535270
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535271
|
+
});
|
|
534588
535272
|
this._assistantTextEmitted = true;
|
|
534589
535273
|
}
|
|
534590
535274
|
break;
|
|
@@ -534603,7 +535287,12 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534603
535287
|
consecutiveTextOnly++;
|
|
534604
535288
|
consecutiveThinkOnly = 0;
|
|
534605
535289
|
}
|
|
534606
|
-
this.emit({
|
|
535290
|
+
this.emit({
|
|
535291
|
+
type: "model_response",
|
|
535292
|
+
content: content.slice(0, 200),
|
|
535293
|
+
turn,
|
|
535294
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535295
|
+
});
|
|
534607
535296
|
if (/task.?complete|all tests pass/i.test(content)) {
|
|
534608
535297
|
const open2 = this.getOpenTodoItems();
|
|
534609
535298
|
if (open2.length > 0) {
|
|
@@ -534627,7 +535316,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534627
535316
|
if (varValue !== null) {
|
|
534628
535317
|
completed = true;
|
|
534629
535318
|
summary = varValue;
|
|
534630
|
-
this.emit({
|
|
535319
|
+
this.emit({
|
|
535320
|
+
type: "status",
|
|
535321
|
+
content: `FINAL_VAR(${varName}): resolved ${varValue.length} chars from REPL`,
|
|
535322
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535323
|
+
});
|
|
534631
535324
|
break;
|
|
534632
535325
|
}
|
|
534633
535326
|
}
|
|
@@ -534650,7 +535343,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534650
535343
|
});
|
|
534651
535344
|
break;
|
|
534652
535345
|
}
|
|
534653
|
-
messages2.push({
|
|
535346
|
+
messages2.push({
|
|
535347
|
+
role: "user",
|
|
535348
|
+
content: "Continue working. Use tools to read files, make changes, and run validation. Call task_complete when done."
|
|
535349
|
+
});
|
|
534654
535350
|
}
|
|
534655
535351
|
}
|
|
534656
535352
|
}
|
|
@@ -534695,10 +535391,12 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534695
535391
|
}
|
|
534696
535392
|
try {
|
|
534697
535393
|
const extractPaths = (entries, toolNames) => {
|
|
534698
|
-
return [
|
|
534699
|
-
|
|
534700
|
-
|
|
534701
|
-
|
|
535394
|
+
return [
|
|
535395
|
+
...new Set(entries.filter((tc) => toolNames.includes(tc.name)).map((tc) => {
|
|
535396
|
+
const pathMatch = tc.argsKey.match(/path=([^,]+)/);
|
|
535397
|
+
return pathMatch?.[1] || "";
|
|
535398
|
+
}).filter(Boolean))
|
|
535399
|
+
];
|
|
534702
535400
|
};
|
|
534703
535401
|
const consolidation = {
|
|
534704
535402
|
sessionId: this._sessionId,
|
|
@@ -534706,7 +535404,12 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534706
535404
|
outcome: completed ? "success" : this.aborted ? "aborted" : "timeout",
|
|
534707
535405
|
turns: messages2.filter((m2) => m2.role === "assistant").length,
|
|
534708
535406
|
toolsUsed: [...new Set(toolCallLog.map((tc) => tc.name))],
|
|
534709
|
-
filesModified: extractPaths(toolCallLog, [
|
|
535407
|
+
filesModified: extractPaths(toolCallLog, [
|
|
535408
|
+
"file_write",
|
|
535409
|
+
"file_edit",
|
|
535410
|
+
"file_patch",
|
|
535411
|
+
"batch_edit"
|
|
535412
|
+
]),
|
|
534710
535413
|
filesRead: extractPaths(toolCallLog, ["file_read"]),
|
|
534711
535414
|
totalToolCalls: toolCallLog.length,
|
|
534712
535415
|
durationMs,
|
|
@@ -534764,7 +535467,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534764
535467
|
};
|
|
534765
535468
|
const provPath = path11.join(provenanceDir, `${this._sessionId}.json`);
|
|
534766
535469
|
fs10.writeFileSync(provPath, JSON.stringify(provenanceGraph, null, 2));
|
|
534767
|
-
this.emit({
|
|
535470
|
+
this.emit({
|
|
535471
|
+
type: "status",
|
|
535472
|
+
content: `Provenance saved: ${provPath}`,
|
|
535473
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535474
|
+
});
|
|
534768
535475
|
if (completed && this.tools.has("memory_write")) {
|
|
534769
535476
|
const memTool = this.tools.get("memory_write");
|
|
534770
535477
|
const lessonContent = `Task "${cleanedTask.slice(0, 100)}" completed successfully. Tools: ${consolidation.toolsUsed.join(", ")}. Files: ${consolidation.filesModified.slice(0, 3).join(", ")}. Duration: ${Math.round(durationMs / 1e3)}s, ${consolidation.turns} turns.`;
|
|
@@ -534851,7 +535558,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534851
535558
|
}
|
|
534852
535559
|
const pruned = this._episodeStore.pruneExpired();
|
|
534853
535560
|
if (pruned > 0) {
|
|
534854
|
-
this.emit({
|
|
535561
|
+
this.emit({
|
|
535562
|
+
type: "status",
|
|
535563
|
+
content: `Pruned ${pruned} expired session episodes`,
|
|
535564
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535565
|
+
});
|
|
534855
535566
|
}
|
|
534856
535567
|
if (process.env["OA_DISABLE_SELF_MODEL"] !== "1") {
|
|
534857
535568
|
try {
|
|
@@ -534985,7 +535696,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
534985
535696
|
}
|
|
534986
535697
|
const social = this._socialMemory;
|
|
534987
535698
|
const userId = this.options.subAgent ? `sub-agent:${this._sessionId}` : "user";
|
|
534988
|
-
social.upsertAgent({
|
|
535699
|
+
social.upsertAgent({
|
|
535700
|
+
id: userId,
|
|
535701
|
+
name: userId,
|
|
535702
|
+
type: this.options.subAgent ? "agent" : "human"
|
|
535703
|
+
});
|
|
534989
535704
|
const wasSuccess = !!completed;
|
|
534990
535705
|
const counts = /* @__PURE__ */ new Map();
|
|
534991
535706
|
for (const t2 of this._toolSequence) {
|
|
@@ -535054,13 +535769,21 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
535054
535769
|
this.stopEmbeddingPipeline();
|
|
535055
535770
|
const gist = compressAndStore(this._episodeStore, this._sessionId, task, 10);
|
|
535056
535771
|
if (gist) {
|
|
535057
|
-
this.emit({
|
|
535772
|
+
this.emit({
|
|
535773
|
+
type: "status",
|
|
535774
|
+
content: `Gist compressed: "${gist.gist.slice(0, 100)}..."`,
|
|
535775
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535776
|
+
});
|
|
535058
535777
|
}
|
|
535059
535778
|
if (this._temporalGraph) {
|
|
535060
535779
|
try {
|
|
535061
535780
|
const linkResult = batchLink(this._episodeStore, this._temporalGraph);
|
|
535062
535781
|
if (linkResult.linksCreated > 0) {
|
|
535063
|
-
this.emit({
|
|
535782
|
+
this.emit({
|
|
535783
|
+
type: "status",
|
|
535784
|
+
content: `Zettelkasten: ${linkResult.linksCreated} associative links created`,
|
|
535785
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535786
|
+
});
|
|
535064
535787
|
}
|
|
535065
535788
|
} catch {
|
|
535066
535789
|
}
|
|
@@ -535087,7 +535810,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
535087
535810
|
taskId: this._sessionId,
|
|
535088
535811
|
sessionId: this._sessionId,
|
|
535089
535812
|
repoRoot: process.cwd(),
|
|
535090
|
-
sequence: this._toolSequence.map((tool) => ({
|
|
535813
|
+
sequence: this._toolSequence.map((tool) => ({
|
|
535814
|
+
tool,
|
|
535815
|
+
argKeys: []
|
|
535816
|
+
}))
|
|
535091
535817
|
});
|
|
535092
535818
|
} catch {
|
|
535093
535819
|
}
|
|
@@ -535123,7 +535849,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
535123
535849
|
const nodes = this._temporalGraph.nodeCount();
|
|
535124
535850
|
const edges = this._temporalGraph.activeEdgeCount();
|
|
535125
535851
|
if (nodes > 0) {
|
|
535126
|
-
this.emit({
|
|
535852
|
+
this.emit({
|
|
535853
|
+
type: "status",
|
|
535854
|
+
content: `Knowledge graph: ${nodes} nodes, ${edges} active edges`,
|
|
535855
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535856
|
+
});
|
|
535127
535857
|
try {
|
|
535128
535858
|
const { mkdirSync: mkdirSync72, writeFileSync: writeFileSync65 } = __require("node:fs");
|
|
535129
535859
|
const { join: join134 } = __require("node:path");
|
|
@@ -535177,7 +535907,11 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
535177
535907
|
}
|
|
535178
535908
|
const epCount = this._episodeStore.count(this._sessionId);
|
|
535179
535909
|
if (epCount > 0) {
|
|
535180
|
-
this.emit({
|
|
535910
|
+
this.emit({
|
|
535911
|
+
type: "status",
|
|
535912
|
+
content: `Episodes captured: ${epCount} this session`,
|
|
535913
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535914
|
+
});
|
|
535181
535915
|
}
|
|
535182
535916
|
} catch {
|
|
535183
535917
|
}
|
|
@@ -535213,7 +535947,17 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
535213
535947
|
fs10.appendFileSync(path11.join(trajDir, `trajectories.jsonl`), JSON.stringify(trajectory) + "\n", "utf-8");
|
|
535214
535948
|
} catch {
|
|
535215
535949
|
}
|
|
535216
|
-
return {
|
|
535950
|
+
return {
|
|
535951
|
+
completed,
|
|
535952
|
+
turns: messages2.filter((m2) => m2.role === "assistant").length,
|
|
535953
|
+
toolCalls: toolCallCount,
|
|
535954
|
+
totalTokens,
|
|
535955
|
+
promptTokens,
|
|
535956
|
+
completionTokens,
|
|
535957
|
+
estimatedTokens,
|
|
535958
|
+
summary,
|
|
535959
|
+
durationMs
|
|
535960
|
+
};
|
|
535217
535961
|
}
|
|
535218
535962
|
// -------------------------------------------------------------------------
|
|
535219
535963
|
// Sudo / privilege escalation support
|
|
@@ -535866,19 +536610,27 @@ ${fullSummary}
|
|
|
535866
536610
|
this.persistCheckpoint(fullSummary);
|
|
535867
536611
|
let narrowedHead = [...head];
|
|
535868
536612
|
if (tier === "small" && head.length > 0 && typeof head[0].content === "string") {
|
|
535869
|
-
narrowedHead = [
|
|
535870
|
-
|
|
535871
|
-
|
|
536613
|
+
narrowedHead = [
|
|
536614
|
+
{
|
|
536615
|
+
...head[0],
|
|
536616
|
+
content: `You are a coding agent. ALWAYS call tools — NEVER reply with only text.
|
|
535872
536617
|
Rules: Read before edit. Run tests after changes. Call task_complete when done.
|
|
535873
536618
|
If ENOENT: call list_directory("."). Entries are RELATIVE to the listed directory.
|
|
535874
536619
|
System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
|
|
535875
|
-
|
|
536620
|
+
},
|
|
536621
|
+
...head.slice(1)
|
|
536622
|
+
];
|
|
535876
536623
|
} else if (tier === "medium" && head.length > 0 && typeof head[0].content === "string") {
|
|
535877
536624
|
const sysContent = head[0].content;
|
|
535878
536625
|
const stripped = sysContent.replace(/\n\n<project-context>[\s\S]*?<\/project-context>/g, "").replace(/\n\n<memory-context>[\s\S]*?<\/memory-context>/g, "").replace(/\n\n<git-state>[\s\S]*?<\/git-state>/g, "");
|
|
535879
536626
|
narrowedHead = [{ ...head[0], content: stripped }, ...head.slice(1)];
|
|
535880
536627
|
}
|
|
535881
|
-
let result = [
|
|
536628
|
+
let result = [
|
|
536629
|
+
...narrowedHead,
|
|
536630
|
+
compactionMsg,
|
|
536631
|
+
...stickyToKeep,
|
|
536632
|
+
...filteredRecent
|
|
536633
|
+
];
|
|
535882
536634
|
const fileRecoveryBudget = Math.floor((this.options.contextWindowSize || 32768) * 0.15);
|
|
535883
536635
|
const maxRecoverFiles = tier === "small" ? 3 : tier === "medium" ? 4 : 5;
|
|
535884
536636
|
const recoveredFiles = [];
|
|
@@ -536060,14 +536812,25 @@ ${trimmedNew}`;
|
|
|
536060
536812
|
const argsKey = toolArgs ? this._buildExactArgsKey(toolArgs) : void 0;
|
|
536061
536813
|
const fingerprint = toolArgs ? this._buildToolFingerprint(toolName, toolArgs) : void 0;
|
|
536062
536814
|
if (!this._littlemanToolOutcomes.some((o2) => o2.turn === turn && o2.tool === toolName && o2.fingerprint === fingerprint)) {
|
|
536063
|
-
this._littlemanToolOutcomes.push({
|
|
536815
|
+
this._littlemanToolOutcomes.push({
|
|
536816
|
+
turn,
|
|
536817
|
+
tool: toolName,
|
|
536818
|
+
argsKey,
|
|
536819
|
+
fingerprint,
|
|
536820
|
+
succeeded,
|
|
536821
|
+
preview
|
|
536822
|
+
});
|
|
536064
536823
|
}
|
|
536065
536824
|
}
|
|
536066
536825
|
}
|
|
536067
536826
|
while (this._littlemanToolOutcomes.length > 20)
|
|
536068
536827
|
this._littlemanToolOutcomes.shift();
|
|
536069
536828
|
const emitReaction = (cls, shortText, confidence, details2) => {
|
|
536070
|
-
this.emit({
|
|
536829
|
+
this.emit({
|
|
536830
|
+
type: "observer_reaction",
|
|
536831
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
536832
|
+
observer: { class: cls, shortText, confidence, details: details2 }
|
|
536833
|
+
});
|
|
536071
536834
|
};
|
|
536072
536835
|
const lastAssistant = [...recent].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
|
|
536073
536836
|
if (lastAssistant && typeof lastAssistant.content === "string") {
|
|
@@ -536301,43 +537064,61 @@ Do NOT rewrite the entire function. Patch the specific fault, then re-run tests.
|
|
|
536301
537064
|
case "file_read": {
|
|
536302
537065
|
const headKeep = contentLines.slice(0, 8).join("\n");
|
|
536303
537066
|
const tailKeep = lines > 12 ? "\n...\n" + contentLines.slice(-3).join("\n") : "";
|
|
536304
|
-
return {
|
|
536305
|
-
|
|
537067
|
+
return {
|
|
537068
|
+
...msg,
|
|
537069
|
+
content: `[file content: ${lines} lines — structural excerpt preserved]
|
|
537070
|
+
${headKeep}${tailKeep}`
|
|
537071
|
+
};
|
|
536306
537072
|
}
|
|
536307
537073
|
case "grep_search": {
|
|
536308
537074
|
const matchKeep = contentLines.slice(0, 5).join("\n");
|
|
536309
537075
|
const omitted = lines > 5 ? `
|
|
536310
537076
|
[... ${lines - 5} more matches omitted]` : "";
|
|
536311
|
-
return {
|
|
536312
|
-
|
|
537077
|
+
return {
|
|
537078
|
+
...msg,
|
|
537079
|
+
content: `[grep results: ${lines} matches — top results preserved]
|
|
537080
|
+
${matchKeep}${omitted}`
|
|
537081
|
+
};
|
|
536313
537082
|
}
|
|
536314
537083
|
case "find_files": {
|
|
536315
537084
|
const pathKeep = contentLines.slice(0, 8).join("\n");
|
|
536316
537085
|
const omitted = lines > 8 ? `
|
|
536317
537086
|
[... ${lines - 8} more files omitted]` : "";
|
|
536318
|
-
return {
|
|
536319
|
-
|
|
537087
|
+
return {
|
|
537088
|
+
...msg,
|
|
537089
|
+
content: `[find results: ${lines} files — top results preserved]
|
|
537090
|
+
${pathKeep}${omitted}`
|
|
537091
|
+
};
|
|
536320
537092
|
}
|
|
536321
537093
|
case "list_directory": {
|
|
536322
537094
|
const dirKeep = contentLines.slice(0, 10).join("\n");
|
|
536323
537095
|
const omitted = lines > 10 ? `
|
|
536324
537096
|
[... ${lines - 10} more entries omitted]` : "";
|
|
536325
|
-
return {
|
|
536326
|
-
|
|
537097
|
+
return {
|
|
537098
|
+
...msg,
|
|
537099
|
+
content: `[directory listing: ${lines} entries — top entries preserved]
|
|
537100
|
+
${dirKeep}${omitted}`
|
|
537101
|
+
};
|
|
536327
537102
|
}
|
|
536328
537103
|
case "web_fetch": {
|
|
536329
537104
|
const webPreview = contentLines.slice(0, 5).join("\n");
|
|
536330
537105
|
const webOmitted = lines > 5 ? `
|
|
536331
537106
|
[... ${lines - 5} more lines omitted for compaction]` : "";
|
|
536332
|
-
return {
|
|
536333
|
-
|
|
537107
|
+
return {
|
|
537108
|
+
...msg,
|
|
537109
|
+
content: `[web_fetch succeeded: ${content.length} chars, ${lines} lines — preview preserved]
|
|
537110
|
+
${webPreview}${webOmitted}`
|
|
537111
|
+
};
|
|
536334
537112
|
}
|
|
536335
537113
|
case "web_search": {
|
|
536336
537114
|
const searchPreview = contentLines.slice(0, 5).join("\n");
|
|
536337
537115
|
const searchOmitted = lines > 5 ? `
|
|
536338
537116
|
[... ${lines - 5} more results omitted]` : "";
|
|
536339
|
-
return {
|
|
536340
|
-
|
|
537117
|
+
return {
|
|
537118
|
+
...msg,
|
|
537119
|
+
content: `[web_search succeeded: ${lines} results — top results preserved]
|
|
537120
|
+
${searchPreview}${searchOmitted}`
|
|
537121
|
+
};
|
|
536341
537122
|
}
|
|
536342
537123
|
case "shell":
|
|
536343
537124
|
case "background_run": {
|
|
@@ -536346,16 +537127,22 @@ ${searchPreview}${searchOmitted}` };
|
|
|
536346
537127
|
const cmdPreview = contentLines.slice(0, 5).join("\n");
|
|
536347
537128
|
const cmdOmitted = lines > 5 ? `
|
|
536348
537129
|
[... ${lines - 5} more lines omitted for compaction]` : "";
|
|
536349
|
-
return {
|
|
536350
|
-
|
|
537130
|
+
return {
|
|
537131
|
+
...msg,
|
|
537132
|
+
content: `[shell succeeded: ${lines} lines, ${content.length} chars — preview preserved]
|
|
537133
|
+
${cmdPreview}${cmdOmitted}`
|
|
537134
|
+
};
|
|
536351
537135
|
}
|
|
536352
537136
|
default:
|
|
536353
537137
|
if (content.length > 2e3) {
|
|
536354
537138
|
const genPreview = contentLines.slice(0, 3).join("\n");
|
|
536355
537139
|
const genOmitted = lines > 3 ? `
|
|
536356
537140
|
[... ${lines - 3} more lines omitted]` : "";
|
|
536357
|
-
return {
|
|
536358
|
-
|
|
537141
|
+
return {
|
|
537142
|
+
...msg,
|
|
537143
|
+
content: `[${toolName ?? "tool"} succeeded: ${content.length} chars — preview preserved]
|
|
537144
|
+
${genPreview}${genOmitted}`
|
|
537145
|
+
};
|
|
536359
537146
|
}
|
|
536360
537147
|
return msg;
|
|
536361
537148
|
}
|
|
@@ -536478,7 +537265,10 @@ ${headContent}${sigLines ? "\n[key signatures]: " + sigLines : ""}`;
|
|
|
536478
537265
|
commandResults.push({ cmd: `web_fetch ${url}`, outcome: errMsg });
|
|
536479
537266
|
} else {
|
|
536480
537267
|
const preview = content.split("\n").slice(0, 3).join(" ").trim().slice(0, 150);
|
|
536481
|
-
commandResults.push({
|
|
537268
|
+
commandResults.push({
|
|
537269
|
+
cmd: `web_fetch ${url}`,
|
|
537270
|
+
outcome: `succeeded: ${preview || `${content.length} chars`}`
|
|
537271
|
+
});
|
|
536482
537272
|
}
|
|
536483
537273
|
break;
|
|
536484
537274
|
}
|
|
@@ -536486,11 +537276,17 @@ ${headContent}${sigLines ? "\n[key signatures]: " + sigLines : ""}`;
|
|
|
536486
537276
|
const query = String(tc.args.query || "").slice(0, 80);
|
|
536487
537277
|
if (content.startsWith("Error:")) {
|
|
536488
537278
|
errors.push(`web_search "${query}": ${content.slice(0, 200)}`);
|
|
536489
|
-
commandResults.push({
|
|
537279
|
+
commandResults.push({
|
|
537280
|
+
cmd: `web_search "${query}"`,
|
|
537281
|
+
outcome: content.slice(0, 200)
|
|
537282
|
+
});
|
|
536490
537283
|
} else {
|
|
536491
537284
|
const resultCount = (content.match(/\n/g) || []).length;
|
|
536492
537285
|
const preview = content.split("\n").slice(0, 2).join(" ").trim().slice(0, 100);
|
|
536493
|
-
commandResults.push({
|
|
537286
|
+
commandResults.push({
|
|
537287
|
+
cmd: `web_search "${query}"`,
|
|
537288
|
+
outcome: `${resultCount} results: ${preview}`
|
|
537289
|
+
});
|
|
536494
537290
|
}
|
|
536495
537291
|
break;
|
|
536496
537292
|
}
|
|
@@ -537158,7 +537954,14 @@ ${transcript}`
|
|
|
537158
537954
|
if (taskText.includes(tool.name.replace(/_/g, " ")) || taskText.includes(tool.name)) {
|
|
537159
537955
|
score += 10;
|
|
537160
537956
|
}
|
|
537161
|
-
if ([
|
|
537957
|
+
if ([
|
|
537958
|
+
"explore_tools",
|
|
537959
|
+
"memory_search",
|
|
537960
|
+
"skill_list",
|
|
537961
|
+
"skill_execute",
|
|
537962
|
+
"agent",
|
|
537963
|
+
"sub_agent"
|
|
537964
|
+
].includes(tool.name)) {
|
|
537162
537965
|
score += 1;
|
|
537163
537966
|
}
|
|
537164
537967
|
scored.push({ tool, score });
|
|
@@ -537229,7 +538032,10 @@ ${catalog}`,
|
|
|
537229
538032
|
parameters: {
|
|
537230
538033
|
type: "object",
|
|
537231
538034
|
properties: {
|
|
537232
|
-
query: {
|
|
538035
|
+
query: {
|
|
538036
|
+
type: "string",
|
|
538037
|
+
description: "Search query (tool name or capability description)"
|
|
538038
|
+
}
|
|
537233
538039
|
},
|
|
537234
538040
|
required: ["query"]
|
|
537235
538041
|
}
|
|
@@ -537389,13 +538195,21 @@ ${result}`
|
|
|
537389
538195
|
for (let pi = 0; pi < msg.content.length; pi++) {
|
|
537390
538196
|
const part = msg.content[pi];
|
|
537391
538197
|
if (part.type === "image_url" && part.image_url?.url) {
|
|
537392
|
-
imageEntries.push({
|
|
538198
|
+
imageEntries.push({
|
|
538199
|
+
msgIdx: mi,
|
|
538200
|
+
partIdx: pi,
|
|
538201
|
+
dataUrl: part.image_url.url
|
|
538202
|
+
});
|
|
537393
538203
|
}
|
|
537394
538204
|
}
|
|
537395
538205
|
}
|
|
537396
538206
|
if (imageEntries.length === 0)
|
|
537397
538207
|
return false;
|
|
537398
|
-
this.emit({
|
|
538208
|
+
this.emit({
|
|
538209
|
+
type: "status",
|
|
538210
|
+
content: `Image rejected — trying downconversion (${imageEntries.length} image(s))...`,
|
|
538211
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538212
|
+
});
|
|
537399
538213
|
let downconverted = false;
|
|
537400
538214
|
try {
|
|
537401
538215
|
for (const entry of imageEntries) {
|
|
@@ -537435,7 +538249,10 @@ ${result}`
|
|
|
537435
538249
|
if (resizedBase64) {
|
|
537436
538250
|
const msg = messages2[entry.msgIdx];
|
|
537437
538251
|
const parts = msg.content;
|
|
537438
|
-
parts[entry.partIdx] = {
|
|
538252
|
+
parts[entry.partIdx] = {
|
|
538253
|
+
type: "image_url",
|
|
538254
|
+
image_url: { url: resizedBase64 }
|
|
538255
|
+
};
|
|
537439
538256
|
downconverted = true;
|
|
537440
538257
|
}
|
|
537441
538258
|
}
|
|
@@ -537443,10 +538260,18 @@ ${result}`
|
|
|
537443
538260
|
}
|
|
537444
538261
|
if (downconverted) {
|
|
537445
538262
|
chatRequest.messages = messages2;
|
|
537446
|
-
this.emit({
|
|
538263
|
+
this.emit({
|
|
538264
|
+
type: "status",
|
|
538265
|
+
content: `Downconverted images to 512px JPEG — retrying`,
|
|
538266
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538267
|
+
});
|
|
537447
538268
|
return true;
|
|
537448
538269
|
}
|
|
537449
|
-
this.emit({
|
|
538270
|
+
this.emit({
|
|
538271
|
+
type: "status",
|
|
538272
|
+
content: `Downconversion failed — trying vision model fallback...`,
|
|
538273
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538274
|
+
});
|
|
537450
538275
|
const ollamaHost = process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
537451
538276
|
let described = false;
|
|
537452
538277
|
for (const entry of imageEntries) {
|
|
@@ -537471,10 +538296,17 @@ ${result}`
|
|
|
537471
538296
|
signal: AbortSignal.timeout(6e4)
|
|
537472
538297
|
});
|
|
537473
538298
|
if (!res.ok && model === "moondream" && res.status === 404) {
|
|
537474
|
-
this.emit({
|
|
538299
|
+
this.emit({
|
|
538300
|
+
type: "status",
|
|
538301
|
+
content: `Pulling moondream vision model...`,
|
|
538302
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538303
|
+
});
|
|
537475
538304
|
try {
|
|
537476
538305
|
const { execSync: execSync59 } = await import("node:child_process");
|
|
537477
|
-
execSync59("ollama pull moondream", {
|
|
538306
|
+
execSync59("ollama pull moondream", {
|
|
538307
|
+
timeout: 3e5,
|
|
538308
|
+
stdio: "pipe"
|
|
538309
|
+
});
|
|
537478
538310
|
res = await fetch(`${ollamaHost}/api/generate`, {
|
|
537479
538311
|
method: "POST",
|
|
537480
538312
|
headers: { "Content-Type": "application/json" },
|
|
@@ -537501,7 +538333,11 @@ ${result}`
|
|
|
537501
538333
|
${description}`
|
|
537502
538334
|
};
|
|
537503
538335
|
described = true;
|
|
537504
|
-
this.emit({
|
|
538336
|
+
this.emit({
|
|
538337
|
+
type: "status",
|
|
538338
|
+
content: `Image described (${description.length} chars) — replacing inline`,
|
|
538339
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538340
|
+
});
|
|
537505
538341
|
}
|
|
537506
538342
|
}
|
|
537507
538343
|
} catch {
|
|
@@ -537518,10 +538354,18 @@ ${description}`
|
|
|
537518
538354
|
}
|
|
537519
538355
|
}
|
|
537520
538356
|
chatRequest.messages = messages2;
|
|
537521
|
-
this.emit({
|
|
538357
|
+
this.emit({
|
|
538358
|
+
type: "status",
|
|
538359
|
+
content: `Images replaced with descriptions — retrying`,
|
|
538360
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538361
|
+
});
|
|
537522
538362
|
return true;
|
|
537523
538363
|
}
|
|
537524
|
-
this.emit({
|
|
538364
|
+
this.emit({
|
|
538365
|
+
type: "status",
|
|
538366
|
+
content: `Image could not be processed — stripping images (text context preserved)`,
|
|
538367
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538368
|
+
});
|
|
537525
538369
|
for (const msg of messages2) {
|
|
537526
538370
|
if (Array.isArray(msg.content)) {
|
|
537527
538371
|
const textParts = msg.content.filter((p2) => p2.type !== "image_url");
|
|
@@ -537622,9 +538466,35 @@ ${description}`
|
|
|
537622
538466
|
let inThinkTag = false;
|
|
537623
538467
|
const toolCallAccumulators = /* @__PURE__ */ new Map();
|
|
537624
538468
|
let streamUsage;
|
|
537625
|
-
this.emit({
|
|
538469
|
+
this.emit({
|
|
538470
|
+
type: "stream_start",
|
|
538471
|
+
turn,
|
|
538472
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538473
|
+
});
|
|
537626
538474
|
this._streamingExecutor.reset();
|
|
537627
538475
|
let lastFinalizedIdx = -1;
|
|
538476
|
+
let firstThinkingTime = 0;
|
|
538477
|
+
let watchdogTripped = false;
|
|
538478
|
+
let thinkingSample = "";
|
|
538479
|
+
let watchdogMs = backend.getThinkingWatchdogMs();
|
|
538480
|
+
if (watchdogMs > 15e3) {
|
|
538481
|
+
let estimatedHistoryTokens = 0;
|
|
538482
|
+
for (const m2 of request.messages) {
|
|
538483
|
+
const c9 = typeof m2.content === "string" ? m2.content : "";
|
|
538484
|
+
estimatedHistoryTokens += c9.length;
|
|
538485
|
+
if (m2.tool_calls) {
|
|
538486
|
+
for (const tc of m2.tool_calls) {
|
|
538487
|
+
estimatedHistoryTokens += tc.function?.arguments?.length ?? 0;
|
|
538488
|
+
}
|
|
538489
|
+
}
|
|
538490
|
+
}
|
|
538491
|
+
estimatedHistoryTokens = Math.round(estimatedHistoryTokens / 4);
|
|
538492
|
+
if (estimatedHistoryTokens > 28e3) {
|
|
538493
|
+
watchdogMs = Math.min(watchdogMs, 3e4);
|
|
538494
|
+
} else if (estimatedHistoryTokens > 24e3) {
|
|
538495
|
+
watchdogMs = Math.min(watchdogMs, 45e3);
|
|
538496
|
+
}
|
|
538497
|
+
}
|
|
537628
538498
|
for await (const chunk of backend.chatCompletionStream(request)) {
|
|
537629
538499
|
if (this.aborted)
|
|
537630
538500
|
break;
|
|
@@ -537655,6 +538525,25 @@ ${description}`
|
|
|
537655
538525
|
} else {
|
|
537656
538526
|
thinkingContent += fragment;
|
|
537657
538527
|
}
|
|
538528
|
+
if (kind === "thinking") {
|
|
538529
|
+
if (firstThinkingTime === 0)
|
|
538530
|
+
firstThinkingTime = Date.now();
|
|
538531
|
+
if (!watchdogTripped) {
|
|
538532
|
+
const elapsed = Date.now() - firstThinkingTime;
|
|
538533
|
+
if (elapsed >= watchdogMs) {
|
|
538534
|
+
watchdogTripped = true;
|
|
538535
|
+
thinkingSample = thinkingContent.slice(-3e3);
|
|
538536
|
+
this.emit({
|
|
538537
|
+
type: "status",
|
|
538538
|
+
content: `Thinking watchdog tripped after ${Math.round(elapsed / 1e3)}s (threshold=${(watchdogMs / 1e3).toFixed(0)}s) — model may be in a reasoning loop`,
|
|
538539
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538540
|
+
});
|
|
538541
|
+
break;
|
|
538542
|
+
}
|
|
538543
|
+
}
|
|
538544
|
+
} else {
|
|
538545
|
+
firstThinkingTime = 0;
|
|
538546
|
+
}
|
|
537658
538547
|
const buf = kind === "content" ? content : thinkingContent;
|
|
537659
538548
|
if (buf.length > 200 && buf.length % 100 < fragment.length) {
|
|
537660
538549
|
const tail = buf.slice(-600);
|
|
@@ -537750,13 +538639,23 @@ ${description}`
|
|
|
537750
538639
|
}
|
|
537751
538640
|
}
|
|
537752
538641
|
}
|
|
537753
|
-
this.emit({
|
|
538642
|
+
this.emit({
|
|
538643
|
+
type: "stream_end",
|
|
538644
|
+
content,
|
|
538645
|
+
turn,
|
|
538646
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538647
|
+
});
|
|
537754
538648
|
const modelName = this.backend.model ?? "";
|
|
537755
538649
|
const modelProfile = resolveModelProfile(modelName);
|
|
537756
538650
|
const textToolParse = parseTextToolCalls(content.replace(/<think>[\s\S]*?<\/think>/g, "").trim(), modelProfile);
|
|
537757
538651
|
const cleanContent = stripXmlControlBlocks(textToolParse.content, modelProfile);
|
|
537758
538652
|
if (cleanContent) {
|
|
537759
|
-
this.emit({
|
|
538653
|
+
this.emit({
|
|
538654
|
+
type: "assistant_text",
|
|
538655
|
+
content: cleanContent,
|
|
538656
|
+
turn,
|
|
538657
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538658
|
+
});
|
|
537760
538659
|
this._assistantTextEmitted = true;
|
|
537761
538660
|
}
|
|
537762
538661
|
const hadThinking = content.includes("<think>") && content.includes("</think>");
|
|
@@ -537773,20 +538672,93 @@ ${description}`
|
|
|
537773
538672
|
}) : void 0;
|
|
537774
538673
|
const toolCalls = structuredStreamToolCalls && structuredStreamToolCalls.length > 0 ? structuredStreamToolCalls : textToolParse.toolCalls.length > 0 ? textToolParse.toolCalls : void 0;
|
|
537775
538674
|
const resp = {
|
|
537776
|
-
choices: [
|
|
537777
|
-
|
|
537778
|
-
|
|
537779
|
-
|
|
537780
|
-
|
|
537781
|
-
|
|
538675
|
+
choices: [
|
|
538676
|
+
{
|
|
538677
|
+
message: {
|
|
538678
|
+
// For think-only responses, include a marker so the model knows it already
|
|
538679
|
+
// thought about this (prevents infinite think loops without visible output)
|
|
538680
|
+
content: thinkOnlyResponse ? "[Your previous response was internal reasoning only. Now respond with visible text or a tool call.]" : cleanContent || null,
|
|
538681
|
+
toolCalls
|
|
538682
|
+
}
|
|
537782
538683
|
}
|
|
537783
|
-
|
|
538684
|
+
],
|
|
537784
538685
|
usage: streamUsage
|
|
537785
538686
|
};
|
|
537786
538687
|
if (thinkOnlyResponse)
|
|
537787
538688
|
resp._thinkOnly = true;
|
|
538689
|
+
if (watchdogTripped)
|
|
538690
|
+
resp._watchdogTripped = true;
|
|
538691
|
+
if (watchdogTripped && thinkingSample.length > 0) {
|
|
538692
|
+
this._fireModeCollapseAnalysis(backend, thinkingSample, thinkingContent.length, Date.now() - (firstThinkingTime || Date.now()), turn);
|
|
538693
|
+
}
|
|
537788
538694
|
return resp;
|
|
537789
538695
|
}
|
|
538696
|
+
/**
|
|
538697
|
+
* Fire-and-forget mode-collapse analysis. Called when the streaming
|
|
538698
|
+
* watchdog detects extended thinking without visible output. Fires a
|
|
538699
|
+
* sub-agent to classify the thinking pattern and updates the backend's
|
|
538700
|
+
* elevated scrutiny state for future turns.
|
|
538701
|
+
*
|
|
538702
|
+
* The sub-agent call runs asynchronously and does NOT block the current
|
|
538703
|
+
* response — the watchdog already aborted it. This is purely diagnostic
|
|
538704
|
+
* and adjusts thresholds for subsequent turns.
|
|
538705
|
+
*
|
|
538706
|
+
* Gated behind OA_MODE_COLLAPSE_ANALYZER env (default "on") so users
|
|
538707
|
+
* who want zero extra round-trips can disable it.
|
|
538708
|
+
*/
|
|
538709
|
+
_fireModeCollapseAnalysis(backend, thinkingSample, totalThinkingChars, thinkingDurationMs, turn) {
|
|
538710
|
+
const gate = (process.env["OA_MODE_COLLAPSE_ANALYZER"] || "on").toLowerCase();
|
|
538711
|
+
if (gate !== "on" && gate !== "1" && gate !== "true")
|
|
538712
|
+
return;
|
|
538713
|
+
const goal = this._taskState?.originalGoal || this._taskState?.goal || "";
|
|
538714
|
+
const callable = async (prompt) => {
|
|
538715
|
+
try {
|
|
538716
|
+
const r2 = await backend.chatCompletion({
|
|
538717
|
+
messages: [
|
|
538718
|
+
{
|
|
538719
|
+
role: "system",
|
|
538720
|
+
content: "You are a META-ANALYSIS sub-agent. Classify the generator's thinking stream and emit a structured JSON verdict."
|
|
538721
|
+
},
|
|
538722
|
+
{ role: "user", content: prompt }
|
|
538723
|
+
],
|
|
538724
|
+
tools: [],
|
|
538725
|
+
temperature: 0,
|
|
538726
|
+
maxTokens: parseInt(process.env["OA_MODE_COLLAPSE_MAX_TOKENS"] || "1024", 10) || 1024,
|
|
538727
|
+
timeoutMs: parseInt(process.env["OA_MODE_COLLAPSE_TIMEOUT_MS"] || "30000", 10) || 3e4
|
|
538728
|
+
});
|
|
538729
|
+
const c9 = r2?.choices?.[0]?.message?.content;
|
|
538730
|
+
return typeof c9 === "string" ? c9 : "";
|
|
538731
|
+
} catch {
|
|
538732
|
+
return "";
|
|
538733
|
+
}
|
|
538734
|
+
};
|
|
538735
|
+
runModeCollapseAnalysis({
|
|
538736
|
+
inputs: {
|
|
538737
|
+
thinkingSample,
|
|
538738
|
+
totalThinkingChars,
|
|
538739
|
+
thinkingDurationMs,
|
|
538740
|
+
goal: goal.slice(0, 500),
|
|
538741
|
+
lastToolNames: []
|
|
538742
|
+
},
|
|
538743
|
+
callable
|
|
538744
|
+
}).then((result) => {
|
|
538745
|
+
if (result.verdict.category !== "healthy" && result.verdict.confidence >= 0.7) {
|
|
538746
|
+
backend.recordModeCollapse();
|
|
538747
|
+
this.emit({
|
|
538748
|
+
type: "status",
|
|
538749
|
+
content: `Mode-collapse analysis: ${result.verdict.category} (conf=${result.verdict.confidence.toFixed(2)}) — ${result.verdict.diagnosis.slice(0, 120)}. Collapse #${backend.getModeCollapseCount()}, scrutiny level ${backend.getElevatedScrutinyLevel()}`,
|
|
538750
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538751
|
+
});
|
|
538752
|
+
} else {
|
|
538753
|
+
this.emit({
|
|
538754
|
+
type: "status",
|
|
538755
|
+
content: `Thinking analysis: ${result.verdict.category} (conf=${result.verdict.confidence.toFixed(2)}) — thinking was healthy, continuing`,
|
|
538756
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
538757
|
+
});
|
|
538758
|
+
}
|
|
538759
|
+
}).catch(() => {
|
|
538760
|
+
});
|
|
538761
|
+
}
|
|
537790
538762
|
};
|
|
537791
538763
|
OllamaAgenticBackend = class _OllamaAgenticBackend {
|
|
537792
538764
|
baseUrl;
|
|
@@ -537805,6 +538777,23 @@ ${description}`
|
|
|
537805
538777
|
_thinkSuppressedNotified = false;
|
|
537806
538778
|
static _thinkFailThreshold = 2;
|
|
537807
538779
|
static _thinkRecoveryThreshold = 6;
|
|
538780
|
+
// ── Mode-collapse elevated scrutiny (0.188.x) ──────────────────────
|
|
538781
|
+
// When the thinking-stream watchdog fires and the sub-agent confirms
|
|
538782
|
+
// mode collapse, this counter increments. At each threshold, detection
|
|
538783
|
+
// tightens to prevent recurring runaway reasoning loops.
|
|
538784
|
+
// Level 0 (normal): watchdog fires at 60s
|
|
538785
|
+
// Level 1 (elevated): watchdog fires at 30s
|
|
538786
|
+
// Level 2 (forced off): think=false unless user explicitly opted in
|
|
538787
|
+
_modeCollapseCount = 0;
|
|
538788
|
+
_elevatedScrutinyLevel = 0;
|
|
538789
|
+
/** Consecutive healthy (no-collapse) thinking responses since last collapse */
|
|
538790
|
+
_cleanStreakAfterCollapse = 0;
|
|
538791
|
+
static _ELEVATED_SCRUTINY_THRESHOLD = 2;
|
|
538792
|
+
// collapses to reach level 1
|
|
538793
|
+
static _FORCED_OFF_THRESHOLD = 4;
|
|
538794
|
+
// collapses to reach level 2
|
|
538795
|
+
static _RECOVERY_CLEAN_COUNT = 10;
|
|
538796
|
+
// clean responses to de-escalate one level
|
|
537808
538797
|
/** Multi-key pool — round-robin rotation per request for load distribution */
|
|
537809
538798
|
_keyPool = [];
|
|
537810
538799
|
_keyIndex = 0;
|
|
@@ -537851,6 +538840,9 @@ ${description}`
|
|
|
537851
538840
|
this._thinkSuccessStreak = 0;
|
|
537852
538841
|
this._thinkSuppressed = false;
|
|
537853
538842
|
this._thinkSuppressedNotified = false;
|
|
538843
|
+
this._modeCollapseCount = 0;
|
|
538844
|
+
this._elevatedScrutinyLevel = 0;
|
|
538845
|
+
this._cleanStreakAfterCollapse = 0;
|
|
537854
538846
|
}
|
|
537855
538847
|
/**
|
|
537856
538848
|
* Feed a completed assistant response into the loop-guard. We only
|
|
@@ -537896,10 +538888,72 @@ ${description}`
|
|
|
537896
538888
|
}
|
|
537897
538889
|
return false;
|
|
537898
538890
|
}
|
|
538891
|
+
// ── Mode-collapse elevated scrutiny ────────────────────────────────
|
|
538892
|
+
/** Record a confirmed mode collapse. Tightens detection thresholds. */
|
|
538893
|
+
recordModeCollapse() {
|
|
538894
|
+
this._modeCollapseCount++;
|
|
538895
|
+
this._cleanStreakAfterCollapse = 0;
|
|
538896
|
+
if (this._modeCollapseCount >= _OllamaAgenticBackend._FORCED_OFF_THRESHOLD) {
|
|
538897
|
+
this._elevatedScrutinyLevel = 2;
|
|
538898
|
+
} else if (this._modeCollapseCount >= _OllamaAgenticBackend._ELEVATED_SCRUTINY_THRESHOLD) {
|
|
538899
|
+
this._elevatedScrutinyLevel = 1;
|
|
538900
|
+
}
|
|
538901
|
+
}
|
|
538902
|
+
/** Record a clean (no-collapse) streaming response toward recovery. */
|
|
538903
|
+
recordCleanStreamTurn() {
|
|
538904
|
+
if (this._elevatedScrutinyLevel > 0) {
|
|
538905
|
+
this._cleanStreakAfterCollapse++;
|
|
538906
|
+
if (this._cleanStreakAfterCollapse >= _OllamaAgenticBackend._RECOVERY_CLEAN_COUNT) {
|
|
538907
|
+
this._elevatedScrutinyLevel = Math.max(0, this._elevatedScrutinyLevel - 1);
|
|
538908
|
+
this._cleanStreakAfterCollapse = 0;
|
|
538909
|
+
if (this._elevatedScrutinyLevel < 2 && this._thinkSuppressed) {
|
|
538910
|
+
this._thinkSuppressed = false;
|
|
538911
|
+
this._thinkSuppressedNotified = false;
|
|
538912
|
+
}
|
|
538913
|
+
}
|
|
538914
|
+
}
|
|
538915
|
+
}
|
|
538916
|
+
/** Get the current elevated-scrutiny level. */
|
|
538917
|
+
getElevatedScrutinyLevel() {
|
|
538918
|
+
return this._elevatedScrutinyLevel;
|
|
538919
|
+
}
|
|
538920
|
+
/** Get the total mode-collapse count for this session. */
|
|
538921
|
+
getModeCollapseCount() {
|
|
538922
|
+
return this._modeCollapseCount;
|
|
538923
|
+
}
|
|
538924
|
+
/**
|
|
538925
|
+
* Get the watchdog threshold in ms for the current scrutiny level.
|
|
538926
|
+
* Level 0: 60s (normal)
|
|
538927
|
+
* Level 1: 30s (elevated — shorter leash)
|
|
538928
|
+
* Level 2: 15s (tight — barely any thinking allowed)
|
|
538929
|
+
*/
|
|
538930
|
+
getThinkingWatchdogMs() {
|
|
538931
|
+
if (this._elevatedScrutinyLevel >= 2)
|
|
538932
|
+
return 15e3;
|
|
538933
|
+
if (this._elevatedScrutinyLevel >= 1)
|
|
538934
|
+
return 3e4;
|
|
538935
|
+
return 6e4;
|
|
538936
|
+
}
|
|
538937
|
+
/**
|
|
538938
|
+
* When elevated scrutiny is active, the callers should consider
|
|
538939
|
+
* whether the next request should force think=false. Level 2 means
|
|
538940
|
+
* think is auto-forced-off (unless the user explicitly opted in).
|
|
538941
|
+
* Level 1 leaves the decision to the caller. Returns -1 (no override)
|
|
538942
|
+
* or a boolean to force as think value.
|
|
538943
|
+
*/
|
|
538944
|
+
getElevatedThinkOverride(requestThink) {
|
|
538945
|
+
if (this._elevatedScrutinyLevel >= 2) {
|
|
538946
|
+
if (requestThink !== true)
|
|
538947
|
+
return false;
|
|
538948
|
+
}
|
|
538949
|
+
return -1;
|
|
538950
|
+
}
|
|
537899
538951
|
/** Build auth headers — adapts to provider (Bearer for most, x-api-key for Anthropic).
|
|
537900
538952
|
* When a key pool is set, round-robins through keys per request. */
|
|
537901
538953
|
authHeaders() {
|
|
537902
|
-
const headers = {
|
|
538954
|
+
const headers = {
|
|
538955
|
+
"Content-Type": "application/json"
|
|
538956
|
+
};
|
|
537903
538957
|
let key = this.apiKey;
|
|
537904
538958
|
if (this._keyPool.length > 0) {
|
|
537905
538959
|
key = this._keyPool[this._keyIndex % this._keyPool.length];
|
|
@@ -537920,13 +538974,16 @@ ${description}`
|
|
|
537920
538974
|
return this._anthropicChatCompletion(request);
|
|
537921
538975
|
}
|
|
537922
538976
|
const cleanedMessages = normalizeMessagesForStrictOpenAI(sanitizeHistoryThink(request.messages));
|
|
537923
|
-
|
|
538977
|
+
let effectiveThink = computeEffectiveThink({
|
|
537924
538978
|
requestThink: request.think,
|
|
537925
538979
|
defaultThink: this.thinking,
|
|
537926
538980
|
hasTools: Array.isArray(request.tools) && request.tools.length > 0,
|
|
537927
538981
|
messages: cleanedMessages,
|
|
537928
538982
|
suppressed: this._thinkSuppressed
|
|
537929
538983
|
});
|
|
538984
|
+
const elevatedOverride = this.getElevatedThinkOverride(request.think);
|
|
538985
|
+
if (elevatedOverride !== -1)
|
|
538986
|
+
effectiveThink = elevatedOverride;
|
|
537930
538987
|
let effectiveMaxTokens = request.maxTokens;
|
|
537931
538988
|
if (effectiveThink === true && (effectiveMaxTokens ?? 0) < 4096) {
|
|
537932
538989
|
effectiveMaxTokens = 4096;
|
|
@@ -538029,11 +539086,13 @@ ${description}`
|
|
|
538029
539086
|
if (msg.role === "tool") {
|
|
538030
539087
|
anthropicMessages.push({
|
|
538031
539088
|
role: "user",
|
|
538032
|
-
content: [
|
|
538033
|
-
|
|
538034
|
-
|
|
538035
|
-
|
|
538036
|
-
|
|
539089
|
+
content: [
|
|
539090
|
+
{
|
|
539091
|
+
type: "tool_result",
|
|
539092
|
+
tool_use_id: msg.tool_call_id ?? "",
|
|
539093
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
539094
|
+
}
|
|
539095
|
+
]
|
|
538037
539096
|
});
|
|
538038
539097
|
} else if (msg.role === "assistant" && msg.tool_calls?.length > 0) {
|
|
538039
539098
|
const blocks = [];
|
|
@@ -538106,12 +539165,14 @@ ${description}`
|
|
|
538106
539165
|
}
|
|
538107
539166
|
}
|
|
538108
539167
|
return {
|
|
538109
|
-
choices: [
|
|
538110
|
-
|
|
538111
|
-
|
|
538112
|
-
|
|
539168
|
+
choices: [
|
|
539169
|
+
{
|
|
539170
|
+
message: {
|
|
539171
|
+
content: textContent || null,
|
|
539172
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
539173
|
+
}
|
|
538113
539174
|
}
|
|
538114
|
-
|
|
539175
|
+
],
|
|
538115
539176
|
usage: usage ? {
|
|
538116
539177
|
totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
|
|
538117
539178
|
promptTokens: usage.input_tokens,
|
|
@@ -538126,13 +539187,16 @@ ${description}`
|
|
|
538126
539187
|
*/
|
|
538127
539188
|
async *chatCompletionStream(request) {
|
|
538128
539189
|
const cleanedMessages = normalizeMessagesForStrictOpenAI(request.messages.map((m2) => m2.role === "assistant" && typeof m2.content === "string" ? { ...m2, content: stripThinkBlocks(m2.content) } : m2));
|
|
538129
|
-
|
|
539190
|
+
let effectiveThink = computeEffectiveThink({
|
|
538130
539191
|
requestThink: request.think,
|
|
538131
539192
|
defaultThink: this.thinking,
|
|
538132
539193
|
hasTools: Array.isArray(request.tools) && request.tools.length > 0,
|
|
538133
539194
|
messages: cleanedMessages,
|
|
538134
539195
|
suppressed: this._thinkSuppressed
|
|
538135
539196
|
});
|
|
539197
|
+
const elevatedOverride = this.getElevatedThinkOverride(request.think);
|
|
539198
|
+
if (elevatedOverride !== -1)
|
|
539199
|
+
effectiveThink = elevatedOverride;
|
|
538136
539200
|
let effectiveMaxTokens = request.maxTokens;
|
|
538137
539201
|
if (effectiveThink === true && (effectiveMaxTokens ?? 0) < 4096) {
|
|
538138
539202
|
effectiveMaxTokens = 4096;
|