open-agents-ai 0.22.3 → 0.23.1

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 +204 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6961,20 +6961,45 @@ var init_desktop_click = __esm({
6961
6961
  durationMs: performance.now() - start
6962
6962
  };
6963
6963
  }
6964
- const { vl } = await import("moondream");
6965
- const apiKey = process.env["MOONDREAM_API_KEY"];
6966
- const endpoint = process.env["MOONDREAM_ENDPOINT"];
6967
- let client;
6968
- if (apiKey) {
6969
- client = new vl({ apiKey });
6970
- } else if (endpoint) {
6971
- client = new vl({ endpoint });
6972
- } else {
6973
- client = new vl({ endpoint: "http://localhost:2020/v1" });
6964
+ let points = [];
6965
+ let visionWorked = false;
6966
+ try {
6967
+ const { vl } = await import("moondream");
6968
+ const apiKey = process.env["MOONDREAM_API_KEY"];
6969
+ const endpoint = process.env["MOONDREAM_ENDPOINT"];
6970
+ let client;
6971
+ if (apiKey) {
6972
+ client = new vl({ apiKey });
6973
+ } else if (endpoint) {
6974
+ client = new vl({ endpoint });
6975
+ } else {
6976
+ client = new vl({ endpoint: "http://localhost:2020/v1" });
6977
+ }
6978
+ const imageBuffer = readFileSync11(screenshotPath);
6979
+ const pointResult = await client.point({ image: imageBuffer, object: target });
6980
+ points = pointResult.points ?? [];
6981
+ visionWorked = true;
6982
+ } catch {
6983
+ }
6984
+ if (!visionWorked) {
6985
+ const hints = [
6986
+ `(Moondream vision not available \u2014 cannot locate "${target}" on screen)`,
6987
+ `Screenshot saved: ${screenshotPath}`,
6988
+ `Screen: ${dims.width}x${dims.height}`,
6989
+ "",
6990
+ "Use shell commands to interact with the desktop instead:",
6991
+ " xdotool search --name 'pattern' \u2014 find windows by title",
6992
+ " xdotool key 'ctrl+s' \u2014 send keyboard shortcuts",
6993
+ " xdotool mousemove X Y click 1 \u2014 click at known coordinates",
6994
+ " wmctrl -a 'window title' \u2014 activate a window by name",
6995
+ " xdg-open <url> \u2014 open a URL in the default browser"
6996
+ ];
6997
+ return {
6998
+ success: true,
6999
+ output: hints.join("\n"),
7000
+ durationMs: performance.now() - start
7001
+ };
6974
7002
  }
6975
- const imageBuffer = readFileSync11(screenshotPath);
6976
- const pointResult = await client.point({ image: imageBuffer, object: target });
6977
- const points = pointResult.points ?? [];
6978
7003
  if (points.length === 0) {
6979
7004
  return {
6980
7005
  success: false,
@@ -7066,37 +7091,62 @@ Screenshot: ${screenshotPath}`,
7066
7091
  captureScreenshot(screenshotPath);
7067
7092
  const dims = getImageDimensions2(screenshotPath);
7068
7093
  const imageBuffer = readFileSync11(screenshotPath);
7069
- const { vl } = await import("moondream");
7070
- const apiKey = process.env["MOONDREAM_API_KEY"];
7071
- const endpoint = process.env["MOONDREAM_ENDPOINT"];
7072
- let client;
7073
- if (apiKey) {
7074
- client = new vl({ apiKey });
7075
- } else if (endpoint) {
7076
- client = new vl({ endpoint });
7077
- } else {
7078
- client = new vl({ endpoint: "http://localhost:2020/v1" });
7079
- }
7080
7094
  const parts = [];
7081
- if (question) {
7082
- const result = await client.query({ image: imageBuffer, question });
7083
- const answer = typeof result.answer === "string" ? result.answer : "(streaming not supported)";
7084
- parts.push(`Q: ${question}`);
7085
- parts.push(`A: ${answer}`);
7086
- } else {
7087
- const result = await client.caption({ image: imageBuffer, length });
7088
- const caption = typeof result.caption === "string" ? result.caption : "(streaming not supported)";
7089
- parts.push(`Desktop description:
7095
+ let visionWorked = false;
7096
+ try {
7097
+ const { vl } = await import("moondream");
7098
+ const apiKey = process.env["MOONDREAM_API_KEY"];
7099
+ const endpoint = process.env["MOONDREAM_ENDPOINT"];
7100
+ let client;
7101
+ if (apiKey) {
7102
+ client = new vl({ apiKey });
7103
+ } else if (endpoint) {
7104
+ client = new vl({ endpoint });
7105
+ } else {
7106
+ client = new vl({ endpoint: "http://localhost:2020/v1" });
7107
+ }
7108
+ if (question) {
7109
+ const result = await client.query({ image: imageBuffer, question });
7110
+ const answer = typeof result.answer === "string" ? result.answer : "(streaming not supported)";
7111
+ parts.push(`Q: ${question}`);
7112
+ parts.push(`A: ${answer}`);
7113
+ } else {
7114
+ const result = await client.caption({ image: imageBuffer, length });
7115
+ const caption = typeof result.caption === "string" ? result.caption : "(streaming not supported)";
7116
+ parts.push(`Desktop description:
7090
7117
  ${caption}`);
7118
+ }
7119
+ visionWorked = true;
7120
+ } catch {
7121
+ }
7122
+ if (!visionWorked) {
7123
+ let ocrText = "";
7124
+ try {
7125
+ ocrText = execSync11(`tesseract ${JSON.stringify(screenshotPath)} stdout 2>/dev/null`, {
7126
+ encoding: "utf8",
7127
+ timeout: 15e3
7128
+ }).trim();
7129
+ } catch {
7130
+ }
7131
+ if (ocrText) {
7132
+ parts.push("(Moondream vision not available \u2014 using OCR text extraction)");
7133
+ parts.push(`
7134
+ Visible text on screen:
7135
+ ${ocrText}`);
7136
+ } else {
7137
+ parts.push("(Moondream vision not available, OCR failed)");
7138
+ parts.push("Screenshot captured but cannot describe contents.");
7139
+ parts.push("Use shell commands to check window state instead:");
7140
+ parts.push(" xdotool getactivewindow getwindowname \u2014 get active window title");
7141
+ parts.push(" wmctrl -l \u2014 list all open windows");
7142
+ parts.push(" xdg-open <url> \u2014 open a URL in the default browser");
7143
+ }
7091
7144
  }
7092
7145
  if (dims) {
7093
7146
  parts.push(`
7094
7147
  Screen: ${dims.width}x${dims.height}`);
7095
7148
  }
7096
7149
  parts.push(`Screenshot: ${screenshotPath}`);
7097
- const base64 = imageBuffer.toString("base64");
7098
- parts.push(`
7099
- [IMAGE_BASE64:image/png:${base64}]`);
7100
7150
  return {
7101
7151
  success: true,
7102
7152
  output: parts.join("\n"),
@@ -9851,7 +9901,17 @@ var init_ralphLoop = __esm({
9851
9901
  });
9852
9902
 
9853
9903
  // packages/orchestrator/dist/agenticRunner.js
9854
- var SYSTEM_PROMPT, AgenticRunner, OllamaAgenticBackend;
9904
+ function getSystemPromptForTier(tier) {
9905
+ switch (tier) {
9906
+ case "small":
9907
+ return SYSTEM_PROMPT_SMALL;
9908
+ case "medium":
9909
+ return SYSTEM_PROMPT_MEDIUM;
9910
+ default:
9911
+ return SYSTEM_PROMPT;
9912
+ }
9913
+ }
9914
+ var SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, AgenticRunner, OllamaAgenticBackend;
9855
9915
  var init_agenticRunner = __esm({
9856
9916
  "packages/orchestrator/dist/agenticRunner.js"() {
9857
9917
  "use strict";
@@ -10051,6 +10111,63 @@ If you notice you're performing the SAME multi-step sequence for the 3rd time or
10051
10111
  - batch_edit to apply multiple edits across files in one call (reduces turns)
10052
10112
  - Focus on error messages in shell output \u2014 skip verbose build logs
10053
10113
  - Don't read files you don't need to modify`;
10114
+ SYSTEM_PROMPT_MEDIUM = `You are Open Agent, an AI coding agent with access to the local machine. You can read/write files, execute shell commands, search the web, and interact with any software. You solve tasks by using tools iteratively until complete.
10115
+
10116
+ ## NEVER REFUSE \u2014 ALWAYS ATTEMPT
10117
+
10118
+ NEVER say "I can't do that". ALWAYS attempt the task using your tools. If a tool fails, try a different approach.
10119
+
10120
+ ## Tools
10121
+
10122
+ - file_read: Read file contents (always read before editing)
10123
+ - file_write: Create or overwrite a file
10124
+ - file_edit: Precise string replacement (preferred over rewriting). old_string must be unique.
10125
+ - file_patch: Edit specific line ranges in large files
10126
+ - find_files: Find files by glob pattern
10127
+ - grep_search: Search file contents with regex
10128
+ - shell: Execute any shell command (tests, builds, git, npm, etc.)
10129
+ - list_directory: List files in a directory
10130
+ - web_search: Search the web
10131
+ - web_fetch: Fetch a web page's text
10132
+ - memory_read / memory_write: Persistent memory across sessions
10133
+ - task_complete: Signal task completion
10134
+ - batch_edit: Multiple edits across files in one call
10135
+ - skill_list / skill_execute: Discover and load specialized skills (use on-demand)
10136
+
10137
+ ## Workflow
10138
+
10139
+ 1. EXPLORE: Use find_files, grep_search, file_read to understand the codebase
10140
+ 2. IMPLEMENT: Make changes with file_edit (preferred) or file_write
10141
+ 3. VALIDATE: Run tests/build with shell. Read FULL output.
10142
+ 4. FIX: If validation fails, fix the specific issue and re-validate
10143
+ 5. ITERATE: Repeat until all tests pass. Do NOT give up.
10144
+ 6. COMPLETE: Call task_complete when done
10145
+
10146
+ ## Rules
10147
+
10148
+ - ALWAYS read a file before modifying it
10149
+ - ALWAYS run validation after changes
10150
+ - If tests fail, read the FULL error. Fix the exact issue.
10151
+ - Do NOT give up after failure. Iterate until it passes.
10152
+ - Use file_edit for small changes, not full file rewrites
10153
+ - You MUST call task_complete when done
10154
+ - Do NOT output long explanations. Focus on tool calls.`;
10155
+ SYSTEM_PROMPT_SMALL = `You are a coding agent. You MUST call tools in EVERY response. NEVER reply with only text.
10156
+
10157
+ Tools: file_read, file_write, file_edit, shell, task_complete, find_files, grep_search, web_search, web_fetch
10158
+
10159
+ Steps:
10160
+ 1. file_read the source files AND test files
10161
+ 2. file_edit or file_write to make changes
10162
+ 3. shell to run tests (npm test, etc.)
10163
+ 4. If tests fail: read error, fix, retest
10164
+ 5. task_complete when tests pass
10165
+
10166
+ Rules:
10167
+ - ALWAYS call tools. NEVER just write text.
10168
+ - Read files before editing them.
10169
+ - Run tests after every change.
10170
+ - Call task_complete when done.`;
10054
10171
  AgenticRunner = class {
10055
10172
  backend;
10056
10173
  tools = /* @__PURE__ */ new Map();
@@ -10073,7 +10190,8 @@ If you notice you're performing the SAME multi-step sequence for the 3rd time or
10073
10190
  dynamicContext: options?.dynamicContext ?? "",
10074
10191
  streamEnabled: options?.streamEnabled ?? false,
10075
10192
  bruteForce: options?.bruteForce ?? true,
10076
- bruteForceMaxCycles: options?.bruteForceMaxCycles ?? 100
10193
+ bruteForceMaxCycles: options?.bruteForceMaxCycles ?? 100,
10194
+ modelTier: options?.modelTier ?? "large"
10077
10195
  };
10078
10196
  }
10079
10197
  /** Register a tool for the agent to use */
@@ -10151,9 +10269,10 @@ Respond with your assessment, then take action. Do NOT just say you'll continue
10151
10269
  const toolCallLog = [];
10152
10270
  this.aborted = false;
10153
10271
  this.pendingUserMessages.length = 0;
10154
- const systemPrompt = this.options.dynamicContext ? `${SYSTEM_PROMPT}
10272
+ const basePrompt = getSystemPromptForTier(this.options.modelTier);
10273
+ const systemPrompt = this.options.dynamicContext ? `${basePrompt}
10155
10274
 
10156
- ${this.options.dynamicContext}` : SYSTEM_PROMPT;
10275
+ ${this.options.dynamicContext}` : basePrompt;
10157
10276
  const messages = [
10158
10277
  { role: "system", content: systemPrompt },
10159
10278
  { role: "user", content: context ? `${context}
@@ -15147,6 +15266,21 @@ import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync
15147
15266
  import { join as join23, basename as basename6 } from "node:path";
15148
15267
  import { execSync as execSync14 } from "node:child_process";
15149
15268
  import { homedir as homedir9, platform, release } from "node:os";
15269
+ function getModelTier(modelName) {
15270
+ const m = modelName.toLowerCase();
15271
+ const sizeMatch = m.match(/\b(\d+)b\b/);
15272
+ if (sizeMatch) {
15273
+ const size = parseInt(sizeMatch[1], 10);
15274
+ if (size >= 30)
15275
+ return "large";
15276
+ if (size >= 8)
15277
+ return "medium";
15278
+ return "small";
15279
+ }
15280
+ if (/\b(small|mini|nano|tiny)\b/.test(m))
15281
+ return "small";
15282
+ return "large";
15283
+ }
15150
15284
  function loadProjectFiles(repoRoot) {
15151
15285
  const discovered = discoverContextFiles(repoRoot);
15152
15286
  if (discovered.length === 0)
@@ -15361,7 +15495,7 @@ function buildProjectContext(repoRoot, stores) {
15361
15495
  skillsSummary: buildSkillsSummary(discoverSkills(repoRoot))
15362
15496
  };
15363
15497
  }
15364
- function formatContextForPrompt(ctx) {
15498
+ function formatContextForPrompt(ctx, modelTier = "large") {
15365
15499
  const sections = [];
15366
15500
  if (ctx.environment) {
15367
15501
  sections.push(`## Environment
@@ -15374,9 +15508,17 @@ ${ctx.environment}`);
15374
15508
  ${ctx.gitInfo}`);
15375
15509
  }
15376
15510
  if (ctx.projectMap) {
15377
- sections.push(`## Project Map
15511
+ if (modelTier === "small") {
15512
+ } else if (modelTier === "medium" && ctx.projectMap.length > 2e3) {
15513
+ sections.push(`## Project Map (truncated)
15514
+
15515
+ ${ctx.projectMap.slice(0, 2e3)}
15516
+ ...(use find_files/list_directory for full listing)`);
15517
+ } else {
15518
+ sections.push(`## Project Map
15378
15519
 
15379
15520
  ${ctx.projectMap}`);
15521
+ }
15380
15522
  }
15381
15523
  if (ctx.projectInstructions) {
15382
15524
  sections.push(ctx.projectInstructions);
@@ -15388,17 +15530,19 @@ ${ctx.memoryContext}
15388
15530
 
15389
15531
  Use this context to avoid re-learning known patterns. Update with memory_write if you discover new insights.`);
15390
15532
  }
15391
- if (ctx.sessionHistory) {
15392
- sections.push(`## Session History
15533
+ if (modelTier !== "small") {
15534
+ if (ctx.sessionHistory) {
15535
+ sections.push(`## Session History
15393
15536
 
15394
15537
  ${ctx.sessionHistory}`);
15395
- }
15396
- if (ctx.taskMemories) {
15397
- sections.push(`## Cross-Session Task Memory
15538
+ }
15539
+ if (ctx.taskMemories) {
15540
+ sections.push(`## Cross-Session Task Memory
15398
15541
 
15399
15542
  ${ctx.taskMemories}
15400
15543
 
15401
15544
  Use this history to avoid re-doing completed work and to learn from past approaches.`);
15545
+ }
15402
15546
  }
15403
15547
  if (ctx.failurePatterns) {
15404
15548
  sections.push(`## Known Failure Patterns
@@ -15407,14 +15551,14 @@ ${ctx.failurePatterns}
15407
15551
 
15408
15552
  Avoid approaches that led to these failures. If you encounter these errors, try a different strategy.`);
15409
15553
  }
15410
- if (ctx.patternSuggestions) {
15554
+ if (modelTier === "large" && ctx.patternSuggestions) {
15411
15555
  sections.push(`## Tool Creation Suggestions
15412
15556
 
15413
15557
  ${ctx.patternSuggestions}
15414
15558
 
15415
15559
  These patterns have been repeated 3+ times. Consider using create_tool to automate them.`);
15416
15560
  }
15417
- if (ctx.skillsSummary) {
15561
+ if (modelTier === "large" && ctx.skillsSummary) {
15418
15562
  sections.push(ctx.skillsSummary);
15419
15563
  }
15420
15564
  return sections.join("\n\n");
@@ -17813,8 +17957,9 @@ ${result.summary}`;
17813
17957
  /** Run a dream agent with appropriate tools */
17814
17958
  async runDreamAgent(prompt, toolMode, onEvent) {
17815
17959
  const backend = new OllamaAgenticBackend(this.config.backendUrl, this.config.model, this.config.apiKey);
17960
+ const modelTier = getModelTier(this.config.model);
17816
17961
  const projectCtx = buildProjectContext(this.repoRoot);
17817
- const dynamicContext = formatContextForPrompt(projectCtx);
17962
+ const dynamicContext = formatContextForPrompt(projectCtx, modelTier);
17818
17963
  const runner = new AgenticRunner(backend, {
17819
17964
  maxTurns: 20,
17820
17965
  maxTokens: 16384,
@@ -17822,8 +17967,9 @@ ${result.summary}`;
17822
17967
  // Slightly creative temperature for dreaming
17823
17968
  requestTimeoutMs: this.config.timeoutMs,
17824
17969
  taskTimeoutMs: this.config.timeoutMs * 3,
17825
- compactionThreshold: 4e4,
17826
- dynamicContext
17970
+ compactionThreshold: modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4,
17971
+ dynamicContext,
17972
+ modelTier
17827
17973
  });
17828
17974
  const tools = this.buildDreamTools(toolMode);
17829
17975
  runner.registerTools(tools);
@@ -18769,12 +18915,14 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
18769
18915
  };
18770
18916
  }
18771
18917
  function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType) {
18918
+ const modelTier = getModelTier(config.model);
18772
18919
  const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
18773
- let dynamicContext = formatContextForPrompt(projectCtx);
18774
- if (taskType) {
18920
+ let dynamicContext = formatContextForPrompt(projectCtx, modelTier);
18921
+ if (taskType && modelTier !== "small") {
18775
18922
  dynamicContext += "\n\n" + buildTaskContext(taskType);
18776
18923
  }
18777
18924
  const backend = new OllamaAgenticBackend(config.backendUrl, config.model, config.apiKey);
18925
+ const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
18778
18926
  const runner = new AgenticRunner(backend, {
18779
18927
  maxTurns: 60,
18780
18928
  maxTokens: 16384,
@@ -18782,8 +18930,9 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
18782
18930
  requestTimeoutMs: config.timeoutMs,
18783
18931
  taskTimeoutMs: 36e5,
18784
18932
  // 60 minutes — never give up prematurely
18785
- compactionThreshold: 4e4,
18933
+ compactionThreshold,
18786
18934
  dynamicContext,
18935
+ modelTier,
18787
18936
  streamEnabled: stream?.enabled ?? false,
18788
18937
  bruteForce: bruteForce ?? true,
18789
18938
  bruteForceMaxCycles: 100
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.22.3",
3
+ "version": "0.23.1",
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",