open-agents-ai 0.187.469 → 0.187.470

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
@@ -250490,6 +250490,11 @@ import { execSync as execSync20, exec } from "node:child_process";
250490
250490
  import { existsSync as existsSync24, writeFileSync as writeFileSync9, mkdirSync as mkdirSync8 } from "node:fs";
250491
250491
  import { join as join37, dirname as dirname11 } from "node:path";
250492
250492
  import { homedir as homedir9 } from "node:os";
250493
+ function pushBounded(buf, item) {
250494
+ buf.push(item);
250495
+ if (buf.length > MAX_BUFFER)
250496
+ buf.splice(0, buf.length - MAX_BUFFER);
250497
+ }
250493
250498
  async function ensurePlaywright() {
250494
250499
  if (pw)
250495
250500
  return null;
@@ -250529,28 +250534,78 @@ async function ensureBrowser() {
250529
250534
  userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
250530
250535
  });
250531
250536
  page = await context.newPage();
250532
- page.on("dialog", async (dialog) => {
250533
- try {
250534
- await dialog.dismiss();
250535
- } catch {
250536
- }
250537
- });
250537
+ attachDiagnosticListeners(page);
250538
250538
  } catch (err) {
250539
250539
  return `Failed to launch browser: ${err instanceof Error ? err.message : String(err)}`;
250540
250540
  }
250541
250541
  }
250542
250542
  if (!page || page.isClosed?.()) {
250543
250543
  page = await context.newPage();
250544
+ attachDiagnosticListeners(page);
250544
250545
  }
250545
250546
  return null;
250546
250547
  }
250548
+ function attachDiagnosticListeners(p2) {
250549
+ p2.on("dialog", async (dialog) => {
250550
+ try {
250551
+ await dialog.dismiss();
250552
+ } catch {
250553
+ }
250554
+ });
250555
+ p2.on("console", (msg) => {
250556
+ try {
250557
+ const loc = msg.location?.();
250558
+ pushBounded(consoleBuffer, {
250559
+ ts: Date.now(),
250560
+ type: String(msg.type?.() ?? "log"),
250561
+ text: String(msg.text?.() ?? "").slice(0, 600),
250562
+ loc: loc?.url ? `${loc.url}:${loc.lineNumber ?? 0}:${loc.columnNumber ?? 0}` : void 0
250563
+ });
250564
+ } catch {
250565
+ }
250566
+ });
250567
+ p2.on("pageerror", (err) => {
250568
+ pushBounded(errorBuffer, {
250569
+ ts: Date.now(),
250570
+ message: String(err?.message ?? err).slice(0, 600),
250571
+ stack: typeof err?.stack === "string" ? err.stack.slice(0, 1500) : void 0
250572
+ });
250573
+ });
250574
+ p2.on("requestfailed", (req2) => {
250575
+ pushBounded(networkBuffer, {
250576
+ ts: Date.now(),
250577
+ method: String(req2.method?.() ?? "GET"),
250578
+ url: String(req2.url?.() ?? "").slice(0, 600),
250579
+ failure: String(req2.failure?.()?.errorText ?? "request failed").slice(0, 200),
250580
+ ok: false
250581
+ });
250582
+ });
250583
+ p2.on("response", (resp) => {
250584
+ try {
250585
+ const status = Number(resp.status?.() ?? 0);
250586
+ pushBounded(networkBuffer, {
250587
+ ts: Date.now(),
250588
+ method: String(resp.request?.()?.method?.() ?? "GET"),
250589
+ url: String(resp.url?.() ?? "").slice(0, 600),
250590
+ status,
250591
+ ok: status >= 200 && status < 400
250592
+ });
250593
+ } catch {
250594
+ }
250595
+ });
250596
+ }
250597
+ function clearDiagnosticBuffers() {
250598
+ consoleBuffer = [];
250599
+ networkBuffer = [];
250600
+ errorBuffer = [];
250601
+ }
250547
250602
  function ok(output, start2) {
250548
250603
  return { success: true, output, durationMs: Date.now() - start2 };
250549
250604
  }
250550
250605
  function fail(error, start2) {
250551
250606
  return { success: false, output: "", error, durationMs: Date.now() - start2 };
250552
250607
  }
250553
- var pw, browser2, context, page, dynamicImport, PlaywrightBrowserTool;
250608
+ var pw, browser2, context, page, MAX_BUFFER, consoleBuffer, networkBuffer, errorBuffer, dynamicImport, PlaywrightBrowserTool;
250554
250609
  var init_playwright_browser = __esm({
250555
250610
  "packages/execution/dist/tools/playwright-browser.js"() {
250556
250611
  "use strict";
@@ -250558,10 +250613,14 @@ var init_playwright_browser = __esm({
250558
250613
  browser2 = null;
250559
250614
  context = null;
250560
250615
  page = null;
250616
+ MAX_BUFFER = 200;
250617
+ consoleBuffer = [];
250618
+ networkBuffer = [];
250619
+ errorBuffer = [];
250561
250620
  dynamicImport = new Function("mod", "return import(mod)");
250562
250621
  PlaywrightBrowserTool = class {
250563
250622
  name = "playwright_browser";
250564
- description = "Full-scope Playwright browser automation. Launches a persistent headless Chromium session for interactive web tasks. Use this to: navigate pages, click elements, fill forms, take screenshots, evaluate JavaScript, wait for elements, extract content, and run end-to-end test assertions against live websites. Auto-installs Playwright + Chromium on first use. Actions: navigate, click, fill, type, press, screenshot, evaluate, content, select, check, wait, goto, title, url, pdf, close. Start with navigate, then use content/screenshot to see the page, then click/fill/type to interact.";
250623
+ description = "Full-scope Playwright browser automation + diagnostic capture. Launches a persistent headless Chromium session. Beyond navigation/interaction, this tool buffers everything the running app emits (console messages, network requests, JS exceptions, accessibility tree) so the agent can verify what is ACTUALLY happening not just what the build/test reports. Auto-installs Playwright + Chromium on first use. Diagnostic actions: console_logs, network_log, page_errors, a11y_snapshot, bounding_box, query_all, performance, cookies, storage, viewport, clear_diagnostics. Interaction actions: navigate, click, fill, type, press, select, check, hover. Capture actions: screenshot, pdf, content, innerText, innerHTML, getAttribute, evaluate. Workflow: navigate screenshot or content → console_logs/network_log/page_errors to verify state click/fill/type to drive UI → repeat.";
250565
250624
  parameters = {
250566
250625
  type: "object",
250567
250626
  properties: {
@@ -250593,6 +250652,18 @@ var init_playwright_browser = __esm({
250593
250652
  "goBack",
250594
250653
  "goForward",
250595
250654
  "reload",
250655
+ // FEAT-1: diagnostic capture actions
250656
+ "console_logs",
250657
+ "network_log",
250658
+ "page_errors",
250659
+ "a11y_snapshot",
250660
+ "bounding_box",
250661
+ "query_all",
250662
+ "performance",
250663
+ "cookies",
250664
+ "storage",
250665
+ "viewport",
250666
+ "clear_diagnostics",
250596
250667
  "close"
250597
250668
  ],
250598
250669
  description: "Action to perform:\n- navigate: go to a URL\n- click: click element by selector\n- fill: clear input and type text (for form fields)\n- type: type text character by character (simulates real typing)\n- press: press a key (Enter, Tab, Escape, etc.)\n- screenshot: capture page screenshot (saves to file)\n- evaluate: run JavaScript in page context\n- content: get page text content (readable, stripped)\n- innerText: get innerText of a specific element\n- select: select dropdown option by value\n- check/uncheck: toggle checkbox\n- hover: hover over element\n- wait: wait for a selector to appear\n- waitForNavigation: wait for page navigation to complete\n- waitForSelector: wait for element matching selector\n- title: get page title\n- url: get current URL\n- getAttribute: get element attribute value\n- innerHTML: get element's innerHTML\n- textContent: get element's textContent\n- goBack/goForward/reload: browser navigation\n- pdf: save page as PDF\n- close: close browser session"
@@ -250641,6 +250712,7 @@ var init_playwright_browser = __esm({
250641
250712
  page = null;
250642
250713
  context = null;
250643
250714
  browser2 = null;
250715
+ clearDiagnosticBuffers();
250644
250716
  return { success: true, output: "Browser closed.", durationMs: Date.now() - start2 };
250645
250717
  }
250646
250718
  const err = await ensureBrowser();
@@ -250831,6 +250903,171 @@ var init_playwright_browser = __esm({
250831
250903
  await page.pdf({ path: pdfPath, format: "A4" });
250832
250904
  return ok(`PDF saved to ${pdfPath}`, start2);
250833
250905
  }
250906
+ // ── FEAT-1: Diagnostic capture ────────────────────────────────────
250907
+ case "console_logs": {
250908
+ const filter2 = (text || "").toLowerCase();
250909
+ const entries = filter2 ? consoleBuffer.filter((e2) => e2.type.toLowerCase().includes(filter2)) : consoleBuffer;
250910
+ const tail = entries.slice(-50);
250911
+ if (tail.length === 0) {
250912
+ return ok(`No console messages buffered yet${filter2 ? ` (filter="${filter2}")` : ""}. Buffer holds last 200 messages.`, start2);
250913
+ }
250914
+ const lines = tail.map((e2) => {
250915
+ const at = new Date(e2.ts).toISOString().slice(11, 19);
250916
+ return `[${at}] ${e2.type.toUpperCase()}: ${e2.text}${e2.loc ? ` (${e2.loc})` : ""}`;
250917
+ });
250918
+ return ok(`Console messages (${tail.length}/${entries.length} shown${filter2 ? `, filter="${filter2}"` : ""}):
250919
+ ${lines.join("\n")}`, start2);
250920
+ }
250921
+ case "network_log": {
250922
+ const mode = (text || "").toLowerCase();
250923
+ let entries = networkBuffer;
250924
+ if (mode === "failed" || mode === "errors") {
250925
+ entries = entries.filter((e2) => e2.ok === false);
250926
+ }
250927
+ const tail = entries.slice(-50);
250928
+ if (tail.length === 0) {
250929
+ return ok(`No network entries buffered${mode ? ` (mode="${mode}")` : ""}. Navigate to a URL to populate.`, start2);
250930
+ }
250931
+ const lines = tail.map((e2) => {
250932
+ const at = new Date(e2.ts).toISOString().slice(11, 19);
250933
+ const tag = e2.failure ? `FAILED (${e2.failure})` : `${e2.status ?? "?"}`;
250934
+ return `[${at}] ${e2.method} ${tag} ${e2.url}`;
250935
+ });
250936
+ return ok(`Network log (${tail.length}/${entries.length} shown${mode ? `, mode="${mode}"` : ""}):
250937
+ ${lines.join("\n")}`, start2);
250938
+ }
250939
+ case "page_errors": {
250940
+ if (errorBuffer.length === 0) {
250941
+ return ok("No uncaught page errors recorded.", start2);
250942
+ }
250943
+ const lines = errorBuffer.map((e2) => {
250944
+ const at = new Date(e2.ts).toISOString().slice(11, 19);
250945
+ return `[${at}] ${e2.message}${e2.stack ? `
250946
+ ${e2.stack.split("\n").slice(0, 4).join("\n ")}` : ""}`;
250947
+ });
250948
+ return ok(`Uncaught page errors (${errorBuffer.length}):
250949
+ ${lines.join("\n\n")}`, start2);
250950
+ }
250951
+ case "a11y_snapshot": {
250952
+ const root = selector ? await page.locator(selector).first().elementHandle() : null;
250953
+ const tree2 = await page.accessibility.snapshot({ root: root ?? void 0, interestingOnly: true });
250954
+ if (!tree2)
250955
+ return ok("No accessibility tree (page may be empty).", start2);
250956
+ const render2 = (n2, depth = 0) => {
250957
+ const pad = " ".repeat(depth);
250958
+ const role = n2.role ?? "?";
250959
+ const name10 = n2.name ? ` "${String(n2.name).slice(0, 80)}"` : "";
250960
+ const value3 = n2.value ? ` value="${String(n2.value).slice(0, 60)}"` : "";
250961
+ const checked = n2.checked != null ? ` checked=${n2.checked}` : "";
250962
+ const lines = [`${pad}${role}${name10}${value3}${checked}`];
250963
+ for (const child of (n2.children ?? []).slice(0, 30)) {
250964
+ lines.push(render2(child, depth + 1));
250965
+ }
250966
+ return lines.join("\n");
250967
+ };
250968
+ const out = render2(tree2).slice(0, 6e3);
250969
+ return ok(`Accessibility snapshot:
250970
+ ${out}`, start2);
250971
+ }
250972
+ case "bounding_box": {
250973
+ if (!selector)
250974
+ return fail("selector is required", start2);
250975
+ const loc = page.locator(selector).first();
250976
+ const box = await loc.boundingBox();
250977
+ if (!box)
250978
+ return fail(`Element ${selector} has no bounding box (not rendered or detached)`, start2);
250979
+ return ok(JSON.stringify(box), start2);
250980
+ }
250981
+ case "query_all": {
250982
+ if (!selector)
250983
+ return fail("selector is required", start2);
250984
+ const handles = await page.locator(selector).all();
250985
+ if (handles.length === 0)
250986
+ return ok(`No elements matched ${selector}.`, start2);
250987
+ const max = Math.min(handles.length, 30);
250988
+ const lines = [];
250989
+ for (let i2 = 0; i2 < max; i2++) {
250990
+ try {
250991
+ const h = handles[i2];
250992
+ const txt = (await h.textContent())?.trim().slice(0, 120) ?? "";
250993
+ const tag = await h.evaluate((el) => (el.tagName || "?").toLowerCase());
250994
+ const id = await h.evaluate((el) => el.id || "");
250995
+ const cls = await h.evaluate((el) => (el.className || "").toString().slice(0, 80));
250996
+ lines.push(`[${i2}] <${tag}${id ? ` id="${id}"` : ""}${cls ? ` class="${cls}"` : ""}> ${txt}`);
250997
+ } catch (e2) {
250998
+ lines.push(`[${i2}] (error: ${e2 instanceof Error ? e2.message.slice(0, 80) : String(e2).slice(0, 80)})`);
250999
+ }
251000
+ }
251001
+ if (handles.length > max)
251002
+ lines.push(`... +${handles.length - max} more`);
251003
+ return ok(`Matched ${handles.length} element(s) for ${selector}:
251004
+ ${lines.join("\n")}`, start2);
251005
+ }
251006
+ case "performance": {
251007
+ const data = await page.evaluate(`(() => {
251008
+ const perf = window.performance;
251009
+ const nav = (perf.getEntriesByType('navigation') || [])[0];
251010
+ const paints = (perf.getEntriesByType('paint') || []);
251011
+ return {
251012
+ url: window.location.href,
251013
+ domContentLoaded: nav ? nav.domContentLoadedEventEnd : null,
251014
+ loadComplete: nav ? nav.loadEventEnd : null,
251015
+ firstPaint: (paints.find(p => p.name === 'first-paint') || {}).startTime || null,
251016
+ firstContentfulPaint: (paints.find(p => p.name === 'first-contentful-paint') || {}).startTime || null,
251017
+ transferSize: nav ? nav.transferSize : null,
251018
+ encodedBodySize: nav ? nav.encodedBodySize : null,
251019
+ decodedBodySize: nav ? nav.decodedBodySize : null,
251020
+ };
251021
+ })()`);
251022
+ return ok(`Performance metrics:
251023
+ ${JSON.stringify(data, null, 2)}`, start2);
251024
+ }
251025
+ case "cookies": {
251026
+ const ck = await context.cookies();
251027
+ if (!ck || ck.length === 0)
251028
+ return ok("No cookies set.", start2);
251029
+ const lines = ck.slice(0, 50).map((c9) => ` ${c9.name}=${String(c9.value).slice(0, 80)} (domain=${c9.domain}, path=${c9.path}${c9.httpOnly ? ", httpOnly" : ""}${c9.secure ? ", secure" : ""})`);
251030
+ return ok(`Cookies (${ck.length}):
251031
+ ${lines.join("\n")}`, start2);
251032
+ }
251033
+ case "storage": {
251034
+ const data = await page.evaluate(`(() => {
251035
+ const dump = function(s) {
251036
+ var o = {};
251037
+ for (var i = 0; i < s.length; i++) {
251038
+ var k = s.key(i);
251039
+ if (k) o[k] = String(s.getItem(k) || '').slice(0, 200);
251040
+ }
251041
+ return o;
251042
+ };
251043
+ return {
251044
+ localStorage: dump(window.localStorage),
251045
+ sessionStorage: dump(window.sessionStorage),
251046
+ };
251047
+ })()`);
251048
+ return ok(`Storage:
251049
+ ${JSON.stringify(data, null, 2)}`, start2);
251050
+ }
251051
+ case "viewport": {
251052
+ const v = (text || value2 || "").trim();
251053
+ const m2 = v.match(/^(\d+)\s*[x×]\s*(\d+)$/);
251054
+ if (m2) {
251055
+ const w = parseInt(m2[1], 10), h = parseInt(m2[2], 10);
251056
+ await page.setViewportSize({ width: w, height: h });
251057
+ return ok(`Viewport set to ${w}x${h}`, start2);
251058
+ }
251059
+ const dev = pw?.devices?.[v];
251060
+ if (dev) {
251061
+ await page.setViewportSize(dev.viewport);
251062
+ return ok(`Viewport set to ${v} (${dev.viewport.width}x${dev.viewport.height})`, start2);
251063
+ }
251064
+ return fail(`viewport: provide "WxH" (e.g. "375x667") or a Playwright device name (e.g. "iPhone 13")`, start2);
251065
+ }
251066
+ case "clear_diagnostics": {
251067
+ const sizes = `console=${consoleBuffer.length} network=${networkBuffer.length} errors=${errorBuffer.length}`;
251068
+ clearDiagnosticBuffers();
251069
+ return ok(`Cleared diagnostic buffers (${sizes}).`, start2);
251070
+ }
250834
251071
  default:
250835
251072
  return fail(`Unknown action: ${action}`, start2);
250836
251073
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.469",
3
+ "version": "0.187.470",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.469",
9
+ "version": "0.187.470",
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.469",
3
+ "version": "0.187.470",
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",