open-agents-ai 0.187.13 → 0.187.14

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 CHANGED
@@ -260278,6 +260278,49 @@ ${this.options.dynamicContext}`,
260278
260278
  repetitionWindow
260279
260279
  };
260280
260280
  }
260281
+ /**
260282
+ * WO-CE-02: Microcompact — lightweight per-turn function result clearing.
260283
+ *
260284
+ * Scans messages array and replaces old tool results with a compact marker.
260285
+ * Keeps the most recent K results intact (K scales by model tier).
260286
+ * This is NOT summarization — just replacement. No LLM call needed.
260287
+ *
260288
+ * Hannover reference: services/compact/apiMicrocompact.ts
260289
+ * Research: arXiv:2307.03172 (Lost in the Middle — recent context matters most)
260290
+ */
260291
+ microcompact(messages2) {
260292
+ const tier = this.options.modelTier ?? "large";
260293
+ const keepResults = tier === "small" ? 6 : tier === "medium" ? 10 : 20;
260294
+ const toolResultIndices = [];
260295
+ for (let i2 = 0; i2 < messages2.length; i2++) {
260296
+ if (messages2[i2].role === "tool") {
260297
+ toolResultIndices.push(i2);
260298
+ }
260299
+ }
260300
+ if (toolResultIndices.length <= keepResults)
260301
+ return;
260302
+ const clearCount = toolResultIndices.length - keepResults;
260303
+ const toClear = toolResultIndices.slice(0, clearCount);
260304
+ let cleared = 0;
260305
+ for (const idx of toClear) {
260306
+ const msg = messages2[idx];
260307
+ const content = typeof msg.content === "string" ? msg.content : "";
260308
+ if (content.startsWith("[Tool result cleared") || content.length < 100)
260309
+ continue;
260310
+ messages2[idx] = {
260311
+ ...msg,
260312
+ content: `[Tool result cleared \u2014 write down important findings from earlier results as they may be cleared]`
260313
+ };
260314
+ cleared++;
260315
+ }
260316
+ if (cleared > 0) {
260317
+ this.emit({
260318
+ type: "status",
260319
+ content: `Microcompact: cleared ${cleared} old tool result(s), keeping ${keepResults} recent`,
260320
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
260321
+ });
260322
+ }
260323
+ }
260281
260324
  /** Register a tool for the agent to use */
260282
260325
  registerTool(tool) {
260283
260326
  this.tools.set(tool.name, tool);
@@ -260751,6 +260794,7 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
260751
260794
  } catch {
260752
260795
  }
260753
260796
  }
260797
+ this.microcompact(compacted);
260754
260798
  const { maxOutputTokens: effectiveMaxTokens } = this.contextLimits();
260755
260799
  const chatRequest = {
260756
260800
  messages: compacted,
@@ -261530,6 +261574,7 @@ Integrate this guidance into your current approach. Continue working on the task
261530
261574
  } else {
261531
261575
  compactedMsgs = await this.compactMessages(messages2, this._skillCompactionStrategy ?? "default");
261532
261576
  }
261577
+ this.microcompact(compactedMsgs);
261533
261578
  const chatRequest = { messages: compactedMsgs, tools: toolDefs, temperature: this.options.temperature, maxTokens: this.options.maxTokens, timeoutMs: this.options.requestTimeoutMs };
261534
261579
  let response;
261535
261580
  try {
@@ -262897,7 +262942,13 @@ ${transcript}`
262897
262942
  "grep_search",
262898
262943
  "find_files",
262899
262944
  "list_directory",
262900
- "file_explore"
262945
+ "file_explore",
262946
+ "web_search",
262947
+ "web_fetch",
262948
+ "memory_read",
262949
+ "memory_write",
262950
+ "working_notes",
262951
+ "batch_edit"
262901
262952
  ]);
262902
262953
  const taskText = (this._taskState.goal || "").toLowerCase();
262903
262954
  const taskWords = new Set(taskText.split(/\s+/).filter((w) => w.length > 2));
@@ -262919,29 +262970,88 @@ ${transcript}`
262919
262970
  if (taskText.includes(tool.name.replace(/_/g, " ")) || taskText.includes(tool.name)) {
262920
262971
  score += 10;
262921
262972
  }
262922
- if (["web_search", "web_fetch", "memory_read", "memory_write", "memory_search"].includes(tool.name)) {
262973
+ if (["explore_tools", "memory_search", "skill_list", "skill_execute", "agent", "sub_agent"].includes(tool.name)) {
262923
262974
  score += 1;
262924
262975
  }
262925
262976
  scored.push({ tool, score });
262926
262977
  }
262927
262978
  scored.sort((a2, b) => b.score - a2.score);
262928
- const maxExtra = tier === "small" ? 6 : 12;
262929
- const relevantTools = scored.slice(0, maxExtra).filter((s2) => s2.score > 0);
262930
- const selectedTools = [
262931
- ...allTools.filter((t2) => CORE_TOOLS2.has(t2.name)),
262932
- ...relevantTools.map((s2) => s2.tool)
262933
- ];
262979
+ const maxInlineExtra = tier === "small" ? 4 : 8;
262980
+ const inlineExtras = scored.slice(0, maxInlineExtra).filter((s2) => s2.score > 0);
262981
+ const inlineNames = /* @__PURE__ */ new Set([
262982
+ ...allTools.filter((t2) => CORE_TOOLS2.has(t2.name)).map((t2) => t2.name),
262983
+ ...inlineExtras.map((s2) => s2.tool.name)
262984
+ ]);
262985
+ const deferred = allTools.filter((t2) => !inlineNames.has(t2.name));
262986
+ const inlineTools = allTools.filter((t2) => inlineNames.has(t2.name));
262934
262987
  const seen = /* @__PURE__ */ new Set();
262935
- const deduped = selectedTools.filter((t2) => {
262988
+ const dedupedInline = inlineTools.filter((t2) => {
262936
262989
  if (seen.has(t2.name))
262937
262990
  return false;
262938
262991
  seen.add(t2.name);
262939
262992
  return true;
262940
262993
  });
262941
- return deduped.map((tool) => ({
262994
+ const defs = dedupedInline.map((tool) => ({
262942
262995
  type: "function",
262943
262996
  function: { name: tool.name, description: tool.description, parameters: tool.parameters }
262944
262997
  }));
262998
+ if (deferred.length > 0) {
262999
+ const catalog = deferred.map((t2) => {
263000
+ const shortDesc = t2.description.split(/\.\s/)[0]?.slice(0, 80) ?? t2.description.slice(0, 80);
263001
+ return `- ${t2.name}: ${shortDesc}`;
263002
+ }).join("\n");
263003
+ defs.push({
263004
+ type: "function",
263005
+ function: {
263006
+ name: "tool_search",
263007
+ description: `Search for and activate additional tools not in your current tool list. Call this when your task needs a tool you don't have. Pass a search query describing what you need.
263008
+
263009
+ Available tools (${deferred.length}):
263010
+ ${catalog}`,
263011
+ parameters: {
263012
+ type: "object",
263013
+ properties: {
263014
+ query: { type: "string", description: "Search query (tool name or capability description)" }
263015
+ },
263016
+ required: ["query"]
263017
+ }
263018
+ }
263019
+ });
263020
+ if (!this.tools.has("tool_search")) {
263021
+ this.tools.set("tool_search", {
263022
+ name: "tool_search",
263023
+ description: "Search for deferred tools",
263024
+ parameters: {},
263025
+ execute: async (args) => {
263026
+ const query = String(args["query"] ?? "").toLowerCase();
263027
+ const matches = deferred.filter((t2) => t2.name.toLowerCase().includes(query) || t2.description.toLowerCase().includes(query)).slice(0, 5);
263028
+ if (matches.length === 0) {
263029
+ return { success: false, output: "", error: `No tools matching "${query}". Try a broader search.` };
263030
+ }
263031
+ const result = matches.map((t2) => {
263032
+ const paramsStr = JSON.stringify(t2.parameters, null, 2);
263033
+ return `## ${t2.name}
263034
+ ${t2.description}
263035
+
263036
+ Parameters:
263037
+ ${paramsStr}`;
263038
+ }).join("\n\n---\n\n");
263039
+ return {
263040
+ success: true,
263041
+ output: `Found ${matches.length} tool(s). You can now call them directly:
263042
+
263043
+ ${result}`
263044
+ };
263045
+ }
263046
+ });
263047
+ }
263048
+ }
263049
+ this.emit({
263050
+ type: "status",
263051
+ content: `Tool deferral: ${dedupedInline.length} inline + ${deferred.length} deferred (${tier} tier)`,
263052
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
263053
+ });
263054
+ return defs;
262945
263055
  }
262946
263056
  // -------------------------------------------------------------------------
262947
263057
  // Transient error recovery — retry on 502, fetch failed, timeouts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.13",
3
+ "version": "0.187.14",
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",
@@ -103,6 +103,8 @@ When asked "how do you work?" or "what can you do?", answer from this list and u
103
103
 
104
104
  The <environment> block contains LIVE hardware metrics updated every turn. When asked about system specs, hardware, battery, CPU, RAM, GPU, disk space, or processes — read and report those values directly. You CAN see them.
105
105
 
106
+ When working with tool results, write down any important information you might need later in your response, as older tool results may be cleared to save context space.
107
+
106
108
  ## Calculations — Always Execute, Never Guess
107
109
 
108
110
  For ANY numerical calculation involving 2+ operations, write Python and execute it with `repl_exec` or `shell`. In-head arithmetic is error-prone across all model sizes. Python is exact.
@@ -33,6 +33,8 @@ Rules:
33
33
  - When asked "what can you do?", use explore_tools() and skill_list() to discover and report your actual capabilities. Do NOT hallucinate.
34
34
  - The <environment> block contains LIVE system metrics. When asked about hardware, battery, CPU, RAM, GPU, disk, or system info — read and report those values directly.
35
35
 
36
+ When working with tool results, write down any important information you might need later in your response, as older tool results may be cleared to save context space.
37
+
36
38
  Calculations — EXECUTE, never guess:
37
39
  - For ANY math with 2+ operations: use `repl_exec(code="print(847.50 * 0.15)")` or `shell`. Python is exact. In-head arithmetic is not.
38
40
  - Currency, percentages, statistics, dates — ALWAYS execute code. If execution fails, reason step-by-step and mark [ESTIMATED].