open-agents-ai 0.187.573 → 0.187.574

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
@@ -252600,7 +252600,9 @@ async function probeService() {
252600
252600
  try {
252601
252601
  const controller = new AbortController();
252602
252602
  const timeout2 = setTimeout(() => controller.abort(), 3e3);
252603
- const res = await fetch(`${BASE_URL}/health`, { signal: controller.signal });
252603
+ const res = await fetch(`${BASE_URL}/health`, {
252604
+ signal: controller.signal
252605
+ });
252604
252606
  clearTimeout(timeout2);
252605
252607
  return res.ok;
252606
252608
  } catch {
@@ -252610,7 +252612,10 @@ async function probeService() {
252610
252612
  function findPython3() {
252611
252613
  for (const cmd of ["python3", "python"]) {
252612
252614
  try {
252613
- const ver = execSync19(`${cmd} --version 2>&1`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
252615
+ const ver = execSync19(`${cmd} --version 2>&1`, {
252616
+ stdio: "pipe",
252617
+ timeout: 5e3
252618
+ }).toString().trim();
252614
252619
  if (ver.includes("Python 3"))
252615
252620
  return cmd;
252616
252621
  } catch {
@@ -252682,7 +252687,10 @@ async function ensureSession() {
252682
252687
  });
252683
252688
  const data = await res.json();
252684
252689
  if (!data.ok)
252685
- return { error: String(data.message ?? "Failed to start browser session"), sessionId: "" };
252690
+ return {
252691
+ error: String(data.message ?? "Failed to start browser session"),
252692
+ sessionId: ""
252693
+ };
252686
252694
  activeSessionId = data.session_id;
252687
252695
  return { sessionId: activeSessionId };
252688
252696
  }
@@ -252828,7 +252836,22 @@ var init_browser_action = __esm({
252828
252836
  properties: {
252829
252837
  action: {
252830
252838
  type: "string",
252831
- enum: ["navigate", "click", "click_xy", "type", "screenshot", "dom", "dom_summary", "vision_click", "scroll", "scroll_up", "scroll_down", "back", "forward", "close"],
252839
+ enum: [
252840
+ "navigate",
252841
+ "click",
252842
+ "click_xy",
252843
+ "type",
252844
+ "screenshot",
252845
+ "dom",
252846
+ "dom_summary",
252847
+ "vision_click",
252848
+ "scroll",
252849
+ "scroll_up",
252850
+ "scroll_down",
252851
+ "back",
252852
+ "forward",
252853
+ "close"
252854
+ ],
252832
252855
  description: "Browser action to perform. Key actions:\n- 'dom_summary': compact view of interactive elements (~1KB vs 200KB raw DOM)\n- 'vision_click': screenshot the page, use Moondream vision to find an element by description, then click it. Pass the element description in 'text' parameter (e.g. text='the login button'). This is the visual grounding loop from SeeAct.\n- 'click': click by CSS selector (fastest when you know the selector)\n- 'click_xy': click at pixel coordinates (when you have exact coords)"
252833
252856
  },
252834
252857
  url: {
@@ -252858,12 +252881,44 @@ var init_browser_action = __esm({
252858
252881
  },
252859
252882
  required: ["action"]
252860
252883
  };
252884
+ /** TASK-CLEANUP: gracefully close the browser session when the task completes. */
252885
+ async cleanup() {
252886
+ if (activeSessionId) {
252887
+ try {
252888
+ const res = await fetch(`${BASE_URL}/session/close`, {
252889
+ method: "POST",
252890
+ headers: { "Content-Type": "application/json" },
252891
+ body: JSON.stringify({ sid: activeSessionId }),
252892
+ signal: AbortSignal.timeout(5e3)
252893
+ });
252894
+ await res.json();
252895
+ } catch {
252896
+ }
252897
+ activeSessionId = null;
252898
+ }
252899
+ if (serviceProcess && serviceProcess.pid && !serviceProcess.killed) {
252900
+ try {
252901
+ process.kill(-serviceProcess.pid, "SIGKILL");
252902
+ } catch {
252903
+ }
252904
+ try {
252905
+ serviceProcess.kill("SIGKILL");
252906
+ } catch {
252907
+ }
252908
+ serviceProcess = null;
252909
+ }
252910
+ }
252861
252911
  async execute(args) {
252862
252912
  const start2 = Date.now();
252863
252913
  const action = args.action;
252864
252914
  const launchErr = await launchService();
252865
252915
  if (launchErr) {
252866
- return { success: false, output: "", error: launchErr, durationMs: Date.now() - start2 };
252916
+ return {
252917
+ success: false,
252918
+ output: "",
252919
+ error: launchErr,
252920
+ durationMs: Date.now() - start2
252921
+ };
252867
252922
  }
252868
252923
  if (action === "close") {
252869
252924
  if (activeSessionId) {
@@ -252873,21 +252928,41 @@ var init_browser_action = __esm({
252873
252928
  }
252874
252929
  activeSessionId = null;
252875
252930
  }
252876
- return { success: true, output: "Browser session closed.", durationMs: Date.now() - start2 };
252931
+ return {
252932
+ success: true,
252933
+ output: "Browser session closed.",
252934
+ durationMs: Date.now() - start2
252935
+ };
252877
252936
  }
252878
252937
  const session = await ensureSession();
252879
252938
  if (session.error) {
252880
- return { success: false, output: "", error: session.error, durationMs: Date.now() - start2 };
252939
+ return {
252940
+ success: false,
252941
+ output: "",
252942
+ error: session.error,
252943
+ durationMs: Date.now() - start2
252944
+ };
252881
252945
  }
252882
252946
  try {
252883
252947
  let result;
252884
252948
  switch (action) {
252885
252949
  case "navigate": {
252886
252950
  if (!args.url)
252887
- return { success: false, output: "", error: "url is required for navigate action", durationMs: Date.now() - start2 };
252888
- result = await apiCall("/navigate", "POST", { url: args.url });
252951
+ return {
252952
+ success: false,
252953
+ output: "",
252954
+ error: "url is required for navigate action",
252955
+ durationMs: Date.now() - start2
252956
+ };
252957
+ result = await apiCall("/navigate", "POST", {
252958
+ url: args.url
252959
+ });
252889
252960
  if (result.ok) {
252890
- return { success: true, output: `Navigated to ${args.url}`, durationMs: Date.now() - start2 };
252961
+ return {
252962
+ success: true,
252963
+ output: `Navigated to ${args.url}`,
252964
+ durationMs: Date.now() - start2
252965
+ };
252891
252966
  }
252892
252967
  const navMsg = String(result.message ?? "Navigation failed");
252893
252968
  const navHint = navMsg.toLowerCase().includes("connection") || navMsg.toLowerCase().includes("refused") || navMsg.toLowerCase().includes("err_connection") ? " (the URL appears unreachable — check if the target server is running and accepting connections)" : navMsg.toLowerCase().includes("timeout") ? " (page load timed out — try again or use a different URL)" : "";
@@ -252900,10 +252975,21 @@ var init_browser_action = __esm({
252900
252975
  }
252901
252976
  case "click": {
252902
252977
  if (!args.selector)
252903
- return { success: false, output: "", error: "selector is required for click action", durationMs: Date.now() - start2 };
252904
- result = await apiCall("/click", "POST", { selector: args.selector });
252978
+ return {
252979
+ success: false,
252980
+ output: "",
252981
+ error: "selector is required for click action",
252982
+ durationMs: Date.now() - start2
252983
+ };
252984
+ result = await apiCall("/click", "POST", {
252985
+ selector: args.selector
252986
+ });
252905
252987
  if (result.ok) {
252906
- return { success: true, output: `Clicked element: ${args.selector}`, durationMs: Date.now() - start2 };
252988
+ return {
252989
+ success: true,
252990
+ output: `Clicked element: ${args.selector}`,
252991
+ durationMs: Date.now() - start2
252992
+ };
252907
252993
  }
252908
252994
  const clickMsg = String(result.message ?? "Click failed");
252909
252995
  return {
@@ -252915,10 +253001,19 @@ var init_browser_action = __esm({
252915
253001
  }
252916
253002
  case "click_xy": {
252917
253003
  if (args.x == null || args.y == null)
252918
- return { success: false, output: "", error: "x and y are required for click_xy action", durationMs: Date.now() - start2 };
253004
+ return {
253005
+ success: false,
253006
+ output: "",
253007
+ error: "x and y are required for click_xy action",
253008
+ durationMs: Date.now() - start2
253009
+ };
252919
253010
  result = await apiCall("/click_xy", "POST", { x: args.x, y: args.y });
252920
253011
  if (result.ok) {
252921
- return { success: true, output: `Clicked at (${args.x}, ${args.y})`, durationMs: Date.now() - start2 };
253012
+ return {
253013
+ success: true,
253014
+ output: `Clicked at (${args.x}, ${args.y})`,
253015
+ durationMs: Date.now() - start2
253016
+ };
252922
253017
  }
252923
253018
  const xyMsg = String(result.message ?? "Click failed");
252924
253019
  return {
@@ -252930,10 +253025,22 @@ var init_browser_action = __esm({
252930
253025
  }
252931
253026
  case "type": {
252932
253027
  if (!args.selector || !args.text)
252933
- return { success: false, output: "", error: "selector and text are required for type action", durationMs: Date.now() - start2 };
252934
- result = await apiCall("/type", "POST", { selector: args.selector, text: args.text });
253028
+ return {
253029
+ success: false,
253030
+ output: "",
253031
+ error: "selector and text are required for type action",
253032
+ durationMs: Date.now() - start2
253033
+ };
253034
+ result = await apiCall("/type", "POST", {
253035
+ selector: args.selector,
253036
+ text: args.text
253037
+ });
252935
253038
  if (result.ok) {
252936
- return { success: true, output: `Typed "${args.text.slice(0, 50)}" into ${args.selector}`, durationMs: Date.now() - start2 };
253039
+ return {
253040
+ success: true,
253041
+ output: `Typed "${args.text.slice(0, 50)}" into ${args.selector}`,
253042
+ durationMs: Date.now() - start2
253043
+ };
252937
253044
  }
252938
253045
  const typeMsg = String(result.message ?? "Type failed");
252939
253046
  return {
@@ -252981,16 +253088,30 @@ var init_browser_action = __esm({
252981
253088
  durationMs: Date.now() - start2
252982
253089
  };
252983
253090
  }
252984
- return { success: false, output: "", error: "Screenshot failed", durationMs: Date.now() - start2 };
253091
+ return {
253092
+ success: false,
253093
+ output: "",
253094
+ error: "Screenshot failed",
253095
+ durationMs: Date.now() - start2
253096
+ };
252985
253097
  }
252986
253098
  case "dom": {
252987
253099
  result = await apiCall("/dom", "GET");
252988
253100
  const dom = result.dom;
252989
253101
  if (dom) {
252990
253102
  const truncated = dom.length > 5e4 ? dom.slice(0, 5e4) + "\n... (truncated)" : dom;
252991
- return { success: true, output: truncated, durationMs: Date.now() - start2 };
253103
+ return {
253104
+ success: true,
253105
+ output: truncated,
253106
+ durationMs: Date.now() - start2
253107
+ };
252992
253108
  }
252993
- return { success: false, output: "", error: "DOM capture failed", durationMs: Date.now() - start2 };
253109
+ return {
253110
+ success: false,
253111
+ output: "",
253112
+ error: "DOM capture failed",
253113
+ durationMs: Date.now() - start2
253114
+ };
252994
253115
  }
252995
253116
  // dom_summary: Research-grounded DOM downsampling
252996
253117
  // Paper: AgentOccam (arXiv:2410.13825, ICLR 2025) — pivotal node extraction
@@ -253004,9 +253125,18 @@ var init_browser_action = __esm({
253004
253125
  result = await apiCall("/dom", "GET");
253005
253126
  const rawDom = result.dom;
253006
253127
  if (!rawDom)
253007
- return { success: false, output: "", error: "DOM capture failed", durationMs: Date.now() - start2 };
253128
+ return {
253129
+ success: false,
253130
+ output: "",
253131
+ error: "DOM capture failed",
253132
+ durationMs: Date.now() - start2
253133
+ };
253008
253134
  const summary = downsampleDom(rawDom);
253009
- return { success: true, output: summary, durationMs: Date.now() - start2 };
253135
+ return {
253136
+ success: true,
253137
+ output: summary,
253138
+ durationMs: Date.now() - start2
253139
+ };
253010
253140
  }
253011
253141
  // vision_click: Screenshot → Moondream point detection → Click
253012
253142
  // Paper: SeeAct (arXiv:2401.01614) — visual grounding for web agents
@@ -253019,14 +253149,24 @@ var init_browser_action = __esm({
253019
253149
  case "vision_click": {
253020
253150
  const target = args.text;
253021
253151
  if (!target)
253022
- return { success: false, output: "", error: "text parameter is required for vision_click — describe what to click (e.g. 'the login button')", durationMs: Date.now() - start2 };
253152
+ return {
253153
+ success: false,
253154
+ output: "",
253155
+ error: "text parameter is required for vision_click — describe what to click (e.g. 'the login button')",
253156
+ durationMs: Date.now() - start2
253157
+ };
253023
253158
  const ssResult = await apiCall("/screenshot", "GET");
253024
253159
  const ssB64 = ssResult.b64;
253025
253160
  const ssWidth = ssResult.width || 1280;
253026
253161
  const ssHeight = ssResult.height || 720;
253027
253162
  const ssFile = ssResult.file;
253028
253163
  if (!ssB64 && !ssFile) {
253029
- return { success: false, output: "", error: "Screenshot failed — cannot perform vision click", durationMs: Date.now() - start2 };
253164
+ return {
253165
+ success: false,
253166
+ output: "",
253167
+ error: "Screenshot failed — cannot perform vision click",
253168
+ durationMs: Date.now() - start2
253169
+ };
253030
253170
  }
253031
253171
  let imagePath = "";
253032
253172
  if (ssFile) {
@@ -253038,7 +253178,12 @@ var init_browser_action = __esm({
253038
253178
  wfs(tmpPath, fileBuffer);
253039
253179
  imagePath = tmpPath;
253040
253180
  } catch (e2) {
253041
- return { success: false, output: "", error: `Failed to save screenshot: ${e2}`, durationMs: Date.now() - start2 };
253181
+ return {
253182
+ success: false,
253183
+ output: "",
253184
+ error: `Failed to save screenshot: ${e2}`,
253185
+ durationMs: Date.now() - start2
253186
+ };
253042
253187
  }
253043
253188
  } else if (ssB64) {
253044
253189
  const tmpPath = join41(process.env["TMPDIR"] || "/tmp", `oa-vision-click-${Date.now()}.png`);
@@ -253056,7 +253201,12 @@ var init_browser_action = __esm({
253056
253201
  prompt: target
253057
253202
  });
253058
253203
  if (!visionResult.success) {
253059
- return { success: false, output: `Vision could not find "${target}" on the page. Try using dom_summary to find the CSS selector instead.`, error: visionResult.error, durationMs: Date.now() - start2 };
253204
+ return {
253205
+ success: false,
253206
+ output: `Vision could not find "${target}" on the page. Try using dom_summary to find the CSS selector instead.`,
253207
+ error: visionResult.error,
253208
+ durationMs: Date.now() - start2
253209
+ };
253060
253210
  }
253061
253211
  const coordMatch = visionResult.output.match(/\((\d+\.?\d*),\s*(\d+\.?\d*)\)/);
253062
253212
  if (coordMatch) {
@@ -253066,10 +253216,19 @@ var init_browser_action = __esm({
253066
253216
  pointY = Math.round(normY * ssHeight);
253067
253217
  }
253068
253218
  } catch (e2) {
253069
- return { success: false, output: "", error: `Vision detection failed: ${e2}`, durationMs: Date.now() - start2 };
253219
+ return {
253220
+ success: false,
253221
+ output: "",
253222
+ error: `Vision detection failed: ${e2}`,
253223
+ durationMs: Date.now() - start2
253224
+ };
253070
253225
  }
253071
253226
  if (pointX < 0 || pointY < 0) {
253072
- return { success: false, output: `Could not determine click coordinates for "${target}". Vision returned no valid points.`, durationMs: Date.now() - start2 };
253227
+ return {
253228
+ success: false,
253229
+ output: `Could not determine click coordinates for "${target}". Vision returned no valid points.`,
253230
+ durationMs: Date.now() - start2
253231
+ };
253073
253232
  }
253074
253233
  const clickResult = await apiCall("/click_xy", "POST", {
253075
253234
  x: pointX,
@@ -253092,22 +253251,49 @@ var init_browser_action = __esm({
253092
253251
  };
253093
253252
  }
253094
253253
  case "scroll":
253095
- result = await apiCall("/scroll", "POST", { amount: args.amount ?? 600 });
253096
- return { success: !!result.ok, output: `Scrolled ${args.amount ?? 600}px`, durationMs: Date.now() - start2 };
253254
+ result = await apiCall("/scroll", "POST", {
253255
+ amount: args.amount ?? 600
253256
+ });
253257
+ return {
253258
+ success: !!result.ok,
253259
+ output: `Scrolled ${args.amount ?? 600}px`,
253260
+ durationMs: Date.now() - start2
253261
+ };
253097
253262
  case "scroll_up":
253098
253263
  result = await apiCall("/scroll/up", "POST");
253099
- return { success: !!result.ok, output: "Scrolled up", durationMs: Date.now() - start2 };
253264
+ return {
253265
+ success: !!result.ok,
253266
+ output: "Scrolled up",
253267
+ durationMs: Date.now() - start2
253268
+ };
253100
253269
  case "scroll_down":
253101
253270
  result = await apiCall("/scroll/down", "POST");
253102
- return { success: !!result.ok, output: "Scrolled down", durationMs: Date.now() - start2 };
253271
+ return {
253272
+ success: !!result.ok,
253273
+ output: "Scrolled down",
253274
+ durationMs: Date.now() - start2
253275
+ };
253103
253276
  case "back":
253104
253277
  result = await apiCall("/history/back", "POST");
253105
- return { success: !!result.ok, output: "Navigated back", durationMs: Date.now() - start2 };
253278
+ return {
253279
+ success: !!result.ok,
253280
+ output: "Navigated back",
253281
+ durationMs: Date.now() - start2
253282
+ };
253106
253283
  case "forward":
253107
253284
  result = await apiCall("/history/forward", "POST");
253108
- return { success: !!result.ok, output: "Navigated forward", durationMs: Date.now() - start2 };
253285
+ return {
253286
+ success: !!result.ok,
253287
+ output: "Navigated forward",
253288
+ durationMs: Date.now() - start2
253289
+ };
253109
253290
  default:
253110
- return { success: false, output: "", error: `Unknown action: ${action}. Available: navigate, click, click_xy, type, screenshot, dom, scroll, scroll_up, scroll_down, back, forward, close`, durationMs: Date.now() - start2 };
253291
+ return {
253292
+ success: false,
253293
+ output: "",
253294
+ error: `Unknown action: ${action}. Available: navigate, click, click_xy, type, screenshot, dom, scroll, scroll_up, scroll_down, back, forward, close`,
253295
+ durationMs: Date.now() - start2
253296
+ };
253111
253297
  }
253112
253298
  } catch (err) {
253113
253299
  return {
@@ -534893,6 +535079,14 @@ ${sr.result.output}`;
534893
535079
  } else {
534894
535080
  completed = true;
534895
535081
  summary = extractTaskCompleteSummary(r2.tc.arguments);
535082
+ for (const tool of this.tools.values()) {
535083
+ if (tool.cleanup) {
535084
+ try {
535085
+ await tool.cleanup();
535086
+ } catch {
535087
+ }
535088
+ }
535089
+ }
534896
535090
  if (summary && !this._assistantTextEmitted) {
534897
535091
  this.emit({
534898
535092
  type: "assistant_text",
@@ -613853,7 +614047,9 @@ function adaptTool6(tool) {
613853
614047
  output: result.output,
613854
614048
  error: result.error
613855
614049
  };
613856
- }
614050
+ },
614051
+ // Pass through lifecycle hooks from the underlying Tool implementation
614052
+ cleanup: tool.cleanup
613857
614053
  };
613858
614054
  }
613859
614055
  function scanForSessionSignals(toolOutput) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.573",
3
+ "version": "0.187.574",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.573",
9
+ "version": "0.187.574",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.573",
3
+ "version": "0.187.574",
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",