open-agents-ai 0.180.0 → 0.182.0

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 +127 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25840,6 +25840,38 @@ Now call file_write with YOUR skeleton for this task.`
25840
25840
  });
25841
25841
  }
25842
25842
  }
25843
+ if (turn === 0 && (turnTier === "small" || turnTier === "medium")) {
25844
+ const taskGoal = this._taskState.goal || "";
25845
+ const taskLower = taskGoal.toLowerCase();
25846
+ const taskTokens = new Set(taskLower.split(/\s+/).filter((w) => w.length > 2));
25847
+ const CORE = /* @__PURE__ */ new Set(["file_read", "file_write", "file_edit", "shell", "task_complete", "grep_search", "find_files", "list_directory", "file_explore"]);
25848
+ const toolHints = [];
25849
+ for (const tool of this.tools.values()) {
25850
+ if (CORE.has(tool.name))
25851
+ continue;
25852
+ const toolWords = `${tool.name.replace(/_/g, " ")} ${tool.description}`.toLowerCase().split(/\s+/);
25853
+ let score = 0;
25854
+ for (const tw of toolWords) {
25855
+ if (taskTokens.has(tw))
25856
+ score += 2;
25857
+ for (const qt of taskTokens) {
25858
+ if (tw.length > 3 && qt.length > 3 && (tw.includes(qt) || qt.includes(tw)))
25859
+ score += 1;
25860
+ }
25861
+ }
25862
+ if (score > 2)
25863
+ toolHints.push({ name: tool.name, desc: tool.description.slice(0, 80), score });
25864
+ }
25865
+ if (toolHints.length > 0) {
25866
+ toolHints.sort((a, b) => b.score - a.score);
25867
+ const top = toolHints.slice(0, 5);
25868
+ messages.push({
25869
+ role: "system",
25870
+ content: `[Relevant tools for this task]
25871
+ ${top.map((t) => `- ${t.name}: ${t.desc}`).join("\n")}`
25872
+ });
25873
+ }
25874
+ }
25843
25875
  const turnBudget = turnTier === "small" ? 5 : turnTier === "medium" ? 8 : 0;
25844
25876
  if (turnBudget > 0 && turn > 0 && turn % turnBudget === 0) {
25845
25877
  const repetitionRatio = this.detectRepetition(toolCallLog);
@@ -27833,14 +27865,79 @@ ${transcript}`
27833
27865
  // -------------------------------------------------------------------------
27834
27866
  // Tool definition builder
27835
27867
  // -------------------------------------------------------------------------
27868
+ /**
27869
+ * Build tool definitions with task-aware filtering for small models.
27870
+ *
27871
+ * Research basis:
27872
+ * - Gorilla (arXiv:2305.15334): RAG-for-tools, 7B outperforms GPT-4 with tool retrieval
27873
+ * - EASYTOOL (arXiv:2401.06201): Minimal tool descriptions reduce tokens 40-70%
27874
+ * - ToolLLM (arXiv:2307.16789): Progressive tool discovery improves small model accuracy
27875
+ *
27876
+ * For small/medium models: only include core tools + task-relevant tools.
27877
+ * For large models: include everything (they can handle the context).
27878
+ */
27836
27879
  buildToolDefinitions() {
27837
- return Array.from(this.tools.values()).map((tool) => ({
27838
- type: "function",
27839
- function: {
27840
- name: tool.name,
27841
- description: tool.description,
27842
- parameters: tool.parameters
27880
+ const allTools = Array.from(this.tools.values());
27881
+ const tier = this.options.modelTier;
27882
+ if (tier === "large") {
27883
+ return allTools.map((tool) => ({
27884
+ type: "function",
27885
+ function: { name: tool.name, description: tool.description, parameters: tool.parameters }
27886
+ }));
27887
+ }
27888
+ const CORE_TOOLS = /* @__PURE__ */ new Set([
27889
+ "file_read",
27890
+ "file_write",
27891
+ "file_edit",
27892
+ "shell",
27893
+ "task_complete",
27894
+ "grep_search",
27895
+ "find_files",
27896
+ "list_directory",
27897
+ "file_explore"
27898
+ ]);
27899
+ const taskText = (this._taskState.goal || "").toLowerCase();
27900
+ const taskWords = new Set(taskText.split(/\s+/).filter((w) => w.length > 2));
27901
+ const scored = [];
27902
+ for (const tool of allTools) {
27903
+ if (CORE_TOOLS.has(tool.name))
27904
+ continue;
27905
+ const toolText = `${tool.name} ${tool.description}`.toLowerCase();
27906
+ const toolWords = toolText.split(/\s+/).filter((w) => w.length > 2);
27907
+ let score = 0;
27908
+ for (const tw of toolWords) {
27909
+ if (taskWords.has(tw))
27910
+ score += 2;
27911
+ for (const qw of taskWords) {
27912
+ if (tw.includes(qw) || qw.includes(tw))
27913
+ score += 1;
27914
+ }
27843
27915
  }
27916
+ if (taskText.includes(tool.name.replace(/_/g, " ")) || taskText.includes(tool.name)) {
27917
+ score += 10;
27918
+ }
27919
+ if (["web_search", "web_fetch", "memory_read", "memory_write", "memory_search"].includes(tool.name)) {
27920
+ score += 1;
27921
+ }
27922
+ scored.push({ tool, score });
27923
+ }
27924
+ scored.sort((a, b) => b.score - a.score);
27925
+ const maxExtra = tier === "small" ? 6 : 12;
27926
+ const relevantTools = scored.slice(0, maxExtra).filter((s) => s.score > 0);
27927
+ const selectedTools = [
27928
+ ...allTools.filter((t) => CORE_TOOLS.has(t.name)),
27929
+ ...relevantTools.map((s) => s.tool)
27930
+ ];
27931
+ const seen = /* @__PURE__ */ new Set();
27932
+ const deduped = selectedTools.filter((t) => {
27933
+ if (seen.has(t.name))
27934
+ return false;
27935
+ seen.add(t.name);
27936
+ return true;
27937
+ });
27938
+ return deduped.map((tool) => ({
27939
+ type: "function",
27940
+ function: { name: tool.name, description: tool.description, parameters: tool.parameters }
27844
27941
  }));
27845
27942
  }
27846
27943
  // -------------------------------------------------------------------------
@@ -51373,10 +51470,32 @@ var init_stream_renderer = __esm({
51373
51470
  * Feed a streamed token into the renderer.
51374
51471
  * Tokens are buffered per-line and flushed with syntax highlighting.
51375
51472
  */
51473
+ /** Track whether we've shown the thinking indicator */
51474
+ thinkingIndicatorShown = false;
51475
+ thinkingTokenCount = 0;
51376
51476
  write(token, kind) {
51377
51477
  if (!this.enabled)
51378
51478
  return;
51379
51479
  this.tokenCount++;
51480
+ if (kind === "thinking") {
51481
+ this.thinkingTokenCount++;
51482
+ if (!this.thinkingIndicatorShown) {
51483
+ this.thinkingIndicatorShown = true;
51484
+ this.writeRaw(dimText(" \u23BF ") + dimItalic("thinking...") + "\n");
51485
+ this.lineStarted = false;
51486
+ }
51487
+ if (this.thinkingTokenCount % 50 === 0) {
51488
+ process.stdout.write(`\x1B[1A\x1B[2K${dimText(" \u23BF ")}${dimItalic(`thinking... (${this.thinkingTokenCount} tokens)`)}
51489
+ `);
51490
+ }
51491
+ return;
51492
+ }
51493
+ if (this.thinkingIndicatorShown && kind === "content") {
51494
+ this.thinkingIndicatorShown = false;
51495
+ process.stdout.write(`\x1B[1A\x1B[2K${dimText(" \u23BF ")}${dimItalic(`thought for ${this.thinkingTokenCount} tokens`)}
51496
+ `);
51497
+ this.thinkingTokenCount = 0;
51498
+ }
51380
51499
  if (kind === "tool_args" && !this.inToolArgs) {
51381
51500
  this.flushPartial(kind);
51382
51501
  this.inToolArgs = true;
@@ -57427,8 +57546,8 @@ var init_status_bar = __esm({
57427
57546
  /** Mouse tracking state — disabled when idle to allow native text selection */
57428
57547
  _mouseTrackingEnabled = true;
57429
57548
  _mouseIdleTimer = null;
57430
- static MOUSE_IDLE_MS = 1500;
57431
- // disable after 1.5s idle
57549
+ static MOUSE_IDLE_MS = 500;
57550
+ // disable after 0.5s idle — fast enough for text selection
57432
57551
  /** Text selection state — tracks click-drag selection for copy */
57433
57552
  _textSelection = new TextSelection({
57434
57553
  getContentLines: () => this._contentLines,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.180.0",
3
+ "version": "0.182.0",
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",