open-agents-ai 0.187.276 → 0.187.277

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.
Files changed (2) hide show
  1. package/dist/index.js +99 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -269758,6 +269758,10 @@ var init_agenticRunner = __esm({
269758
269758
  // WO-KG-15
269759
269759
  _retrievalContextCache = null;
269760
269760
  // WO-KG-15: cache per-run
269761
+ // Observer world-model and cohort stats
269762
+ _observerMode = "both";
269763
+ _worldFacts = { files: /* @__PURE__ */ new Map(), lastTest: {}, lastLists: /* @__PURE__ */ new Map() };
269764
+ _argCohorts = /* @__PURE__ */ new Map();
269761
269765
  // ── WO-NC-07: Error pattern learning → pre-action guidance injection ──
269762
269766
  // Records error patterns (tool + error signature → learned guidance).
269763
269767
  // When the same tool+context is about to be called again, injects the
@@ -269839,8 +269843,10 @@ var init_agenticRunner = __esm({
269839
269843
  contextWindowSize: options2?.contextWindowSize ?? 0,
269840
269844
  personality: options2?.personality ?? PERSONALITY_PRESETS.balanced,
269841
269845
  personalityName: options2?.personalityName ?? "",
269842
- finalVarResolver: options2?.finalVarResolver ?? void 0
269846
+ finalVarResolver: options2?.finalVarResolver ?? void 0,
269847
+ observerMode: options2?.observerMode ?? "both"
269843
269848
  };
269849
+ this._observerMode = this.options.observerMode;
269844
269850
  }
269845
269851
  /** Update context window size (e.g. after querying Ollama /api/show) */
269846
269852
  setContextWindowSize(size) {
@@ -270206,6 +270212,27 @@ ${body}`;
270206
270212
  }
270207
270213
  }
270208
270214
  }
270215
+ /** Build a light fingerprint for arg cohort learning */
270216
+ buildArgCohortKey(tool, args) {
270217
+ const keys = Object.keys(args || {}).sort();
270218
+ const parts = [tool];
270219
+ for (const k of keys) {
270220
+ const v = args[k];
270221
+ if (typeof v === "string")
270222
+ parts.push(`${k}:${v.slice(0, 64)}`);
270223
+ else if (typeof v === "number" || typeof v === "boolean")
270224
+ parts.push(`${k}:${String(v)}`);
270225
+ else
270226
+ parts.push(`${k}:${JSON.stringify(v).slice(0, 64)}`);
270227
+ }
270228
+ let h = 2166136261;
270229
+ const s2 = parts.join("|");
270230
+ for (let i2 = 0; i2 < s2.length; i2++) {
270231
+ h ^= s2.charCodeAt(i2);
270232
+ h = Math.imul(h, 16777619);
270233
+ }
270234
+ return `${tool}#${(h >>> 0).toString(16)}`;
270235
+ }
270209
270236
  /** Register a tool for the agent to use */
270210
270237
  registerTool(tool) {
270211
270238
  this.tools.set(tool.name, tool);
@@ -270540,6 +270567,9 @@ TASK: ${task}` : task;
270540
270567
  this._hookDenyHintCount = 0;
270541
270568
  this._selfConsistencyVotes = 0;
270542
270569
  this._retrievalContextCache = null;
270570
+ this._observerMode = this.options.observerMode ?? "both";
270571
+ this._worldFacts = { files: /* @__PURE__ */ new Map(), lastTest: {}, lastLists: /* @__PURE__ */ new Map() };
270572
+ this._argCohorts.clear();
270543
270573
  this._lastTodoWriteTurn = -1;
270544
270574
  this._lastTodoReminderTurn = -1;
270545
270575
  let pendingConstraintWarnings = [];
@@ -271114,6 +271144,14 @@ ${memoryLines.join("\n")}`
271114
271144
  const executeSingle = async (tc) => {
271115
271145
  if (this.aborted)
271116
271146
  return null;
271147
+ const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
271148
+ const cohort = this._argCohorts.get(cohortKey);
271149
+ if (cohort && cohort.failure >= 3 && cohort.success === 0) {
271150
+ this.emit({ type: "observer_reaction", timestamp: (/* @__PURE__ */ new Date()).toISOString(), observer: { class: "arg_cohort_risk", shortText: `${tc.name} with similar args has failed ${cohort.failure}× recently`, confidence: 0.85 } });
271151
+ if (this._observerMode === "skillcoach" || this._observerMode === "both") {
271152
+ this.pendingUserMessages.push(`[LITTLEMAN] ${tc.name} with similar arguments has failed ${cohort.failure}× recently. Try a different approach first: read relevant files, adjust arguments, or verify prerequisites.`);
271153
+ }
271154
+ }
271117
271155
  if (this._errorPatterns.size > 0) {
271118
271156
  for (const [sig, pattern] of this._errorPatterns) {
271119
271157
  if (pattern.tool === tc.name && pattern.count >= 2 && !this._errorGuidanceInjected.has(sig)) {
@@ -271298,6 +271336,35 @@ ${memoryLines.join("\n")}`
271298
271336
  }
271299
271337
  }
271300
271338
  }
271339
+ const updated = this._argCohorts.get(cohortKey) || { success: 0, failure: 0, lastOutcomeTurn: turn };
271340
+ if (result.success)
271341
+ updated.success++;
271342
+ else
271343
+ updated.failure++;
271344
+ updated.lastOutcomeTurn = turn;
271345
+ this._argCohorts.set(cohortKey, updated);
271346
+ try {
271347
+ if (tc.name === "file_read") {
271348
+ const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
271349
+ if (p2)
271350
+ this._worldFacts.files.set(p2, { exists: result.success, size: (result.output || "").length, hashSample: (result.output || "").slice(0, 32), lastSeenTurn: turn });
271351
+ } else if (tc.name === "list_directory") {
271352
+ const dir = String(tc.arguments?.["path"] ?? ".");
271353
+ this._worldFacts.lastLists.set(dir, { entriesCount: (result.output.match(/\n/g) || []).length + 1, lastSeenTurn: turn });
271354
+ } else if (tc.name === "shell") {
271355
+ const cmd = String(tc.arguments?.["command"] ?? "");
271356
+ if (/\b(npm|pnpm|yarn)\s+test\b|\bjest\b|\bvitest\b/i.test(cmd)) {
271357
+ const passed = /PASS|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
271358
+ this._worldFacts.lastTest = { passed, summary: result.output.slice(0, 200), turn };
271359
+ }
271360
+ if (/^cd\s+/.test(cmd)) {
271361
+ const m2 = cmd.match(/^cd\s+([^&;\n]+)/);
271362
+ if (m2)
271363
+ this._worldFacts.lastCwd = m2[1];
271364
+ }
271365
+ }
271366
+ } catch {
271367
+ }
271301
271368
  if (this._episodeStore) {
271302
271369
  try {
271303
271370
  const episodeContent = result.success ? `${tc.name}: ${(result.output ?? "").slice(0, 500)}` : `${tc.name} ERROR: ${(result.error ?? result.output ?? "").slice(0, 500)}`;
@@ -273086,6 +273153,9 @@ ${trimmedNew}`;
273086
273153
  }
273087
273154
  while (this._littlemanToolOutcomes.length > 20)
273088
273155
  this._littlemanToolOutcomes.shift();
273156
+ const emitReaction = (cls, shortText, confidence, details2) => {
273157
+ this.emit({ type: "observer_reaction", timestamp: (/* @__PURE__ */ new Date()).toISOString(), observer: { class: cls, shortText, confidence, details: details2 } });
273158
+ };
273089
273159
  const lastAssistant = [...recent].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
273090
273160
  if (lastAssistant && typeof lastAssistant.content === "string") {
273091
273161
  const text = lastAssistant.content.toLowerCase();
@@ -273095,9 +273165,10 @@ ${trimmedNew}`;
273095
273165
  const successes = recentOutcomes.filter((o2) => o2.succeeded);
273096
273166
  if (successes.length >= 1) {
273097
273167
  const successList = successes.map((o2) => `${o2.tool}: ${o2.preview.slice(0, 60)}`).join("; ");
273098
- this.pendingUserMessages.push(`[LITTLEMAN] Correction: your recent tools DID succeed. Do not retry them.
273099
- Successful results: ${successList}
273100
- Build on these results instead of retrying. What is your NEXT step toward the goal?`);
273168
+ emitReaction("false_failure", `Claimed failure, but recent tools succeeded (${successes.length})`, 0.9, successList);
273169
+ if (this._observerMode === "skillcoach" || this._observerMode === "both") {
273170
+ this.pendingUserMessages.push(`[LITTLEMAN] Correction: recent tools DID succeed. Do not retry them. Successful results: ${successList}. Use them to advance the task.`);
273171
+ }
273101
273172
  this.emit({
273102
273173
  type: "status",
273103
273174
  content: `Littleman: corrected false failure claim (${successes.length} tools succeeded)`,
@@ -273106,6 +273177,22 @@ Build on these results instead of retrying. What is your NEXT step toward the go
273106
273177
  }
273107
273178
  }
273108
273179
  }
273180
+ if (lastAssistant && typeof lastAssistant.content === "string") {
273181
+ const text = lastAssistant.content.toLowerCase();
273182
+ const claimsSuccess = /(done|fixed|success|passed|complete)/i.test(text);
273183
+ if (claimsSuccess) {
273184
+ const recentOutcomes = this._littlemanToolOutcomes.slice(-4);
273185
+ const failures = recentOutcomes.filter((o2) => !o2.succeeded);
273186
+ const successes = recentOutcomes.filter((o2) => o2.succeeded);
273187
+ if (failures.length > 0 && successes.length === 0) {
273188
+ const failList = failures.map((o2) => `${o2.tool}: ${o2.preview.slice(0, 60)}`).join("; ");
273189
+ emitReaction("false_success", `Claimed success, but recent tools failed (${failures.length})`, 0.9, failList);
273190
+ if (this._observerMode === "skillcoach" || this._observerMode === "both") {
273191
+ this.pendingUserMessages.push(`[LITTLEMAN] Your recent tools show errors (${failures.length}). Verify the last tool output and correct the issue before claiming success.`);
273192
+ }
273193
+ }
273194
+ }
273195
+ }
273109
273196
  const lastToolCalls = recent.filter((m2) => m2.role === "assistant" && m2.tool_calls?.length).flatMap((m2) => m2.tool_calls ?? []);
273110
273197
  for (const tc of lastToolCalls) {
273111
273198
  const name10 = tc.function.name;
@@ -273117,8 +273204,10 @@ Build on these results instead of retrying. What is your NEXT step toward the go
273117
273204
  const argsKey = name10 === "shell" ? String(args.command ?? "").slice(0, 60) : name10 === "web_fetch" ? String(args.url ?? "").slice(0, 80) : String(args.path ?? args.url ?? args.query ?? "").slice(0, 60);
273118
273205
  const prior = this._littlemanToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.preview.includes(argsKey.slice(0, 30)) && o2.turn < turn);
273119
273206
  if (prior) {
273120
- this.pendingUserMessages.push(`[LITTLEMAN] You already ran ${name10} successfully on turn ${prior.turn} with similar arguments. Result was: ${prior.preview.slice(0, 100)}
273121
- Do NOT re-run it. Use the result you already have and proceed to the next step.`);
273207
+ emitReaction("redundant_action", `Already ran ${name10} successfully on turn ${prior.turn}`, 0.8, prior.preview);
273208
+ if (this._observerMode === "skillcoach" || this._observerMode === "both") {
273209
+ this.pendingUserMessages.push(`[LITTLEMAN] You already ran ${name10} successfully on turn ${prior.turn} with similar arguments. Do NOT re-run it. Use the existing result and proceed.`);
273210
+ }
273122
273211
  this.emit({
273123
273212
  type: "status",
273124
273213
  content: `Littleman: prevented redundant ${name10} call (succeeded on turn ${prior.turn})`,
@@ -273140,7 +273229,10 @@ Do NOT re-run it. Use the result you already have and proceed to the next step.`
273140
273229
  }
273141
273230
  }
273142
273231
  if (consecutiveShortResults >= 3) {
273143
- this.pendingUserMessages.push(`[LITTLEMAN] You have sent ${consecutiveShortResults} consecutive outputs without reading any input. In an interactive session, you MUST alternate: receive input, then respond, then receive again. STOP sending and call your input/listening tool NOW to hear what the other side said.`);
273232
+ emitReaction("idle_think", `Consecutive output without input: ${consecutiveShortResults}`, 0.7);
273233
+ if (this._observerMode === "skillcoach" || this._observerMode === "both") {
273234
+ this.pendingUserMessages.push(`[LITTLEMAN] You have sent ${consecutiveShortResults} consecutive outputs without reading any input. Alternate: receive input, then respond. Call your input tool now.`);
273235
+ }
273144
273236
  this.emit({
273145
273237
  type: "status",
273146
273238
  content: `Littleman: blocked runaway output (${consecutiveShortResults} consecutive sends without receive)`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.276",
3
+ "version": "0.187.277",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",