micro-models-agent 0.30.0 → 0.31.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/main.js +172 -31
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2224,6 +2224,8 @@ var init_defaults = __esm(() => {
2224
2224
  enabled: true,
2225
2225
  headless: true,
2226
2226
  maxElements: 30,
2227
+ maxContentChars: 2500,
2228
+ maxConsoleEntries: 20,
2227
2229
  viewportWidth: 1280,
2228
2230
  viewportHeight: 720,
2229
2231
  navigationTimeout: 15000
@@ -2784,6 +2786,10 @@ Use this knowledge to answer the user's question.`,
2784
2786
  "browser.no_page_short": "No page",
2785
2787
  "browser.no_elements": "(no interactive elements on page)",
2786
2788
  "browser.more_elements": "... and more elements not shown. Use scroll or search to find others.",
2789
+ "browser.content_header": "Content:",
2790
+ "browser.console_header": "Console:",
2791
+ "browser.network_errors_header": "Network errors:",
2792
+ "browser.truncated": "... (truncated)",
2787
2793
  "pipeline.invalid": "Invalid pipeline: name and steps required",
2788
2794
  "pipeline.step_missing_fields": "Step missing required fields (id, agent, prompt): {step}",
2789
2795
  "pipeline.circular": "Circular dependency: {stepId}",
@@ -3357,6 +3363,10 @@ var init_ru = __esm(() => {
3357
3363
  "browser.no_page_short": "Нет страницы",
3358
3364
  "browser.no_elements": "(нет интерактивных элементов на странице)",
3359
3365
  "browser.more_elements": "... и другие элементы не показаны. Используйте прокрутку или поиск.",
3366
+ "browser.content_header": "Содержимое:",
3367
+ "browser.console_header": "Консоль:",
3368
+ "browser.network_errors_header": "Сетевые ошибки:",
3369
+ "browser.truncated": "... (обрезано)",
3360
3370
  "pipeline.invalid": "Невалидный пайплайн: требуются name и steps",
3361
3371
  "pipeline.step_missing_fields": "Шаг не содержит обязательных полей (id, agent, prompt): {step}",
3362
3372
  "pipeline.circular": "Циклическая зависимость: {stepId}",
@@ -13660,6 +13670,22 @@ var init_recall = __esm(() => {
13660
13670
  };
13661
13671
  });
13662
13672
 
13673
+ // src/modules/browser/types.ts
13674
+ var DEFAULT_BROWSER_CONFIG;
13675
+ var init_types = __esm(() => {
13676
+ DEFAULT_BROWSER_CONFIG = {
13677
+ headless: true,
13678
+ maxElements: 30,
13679
+ maxContentChars: 2500,
13680
+ maxConsoleEntries: 20,
13681
+ screenshotMaxWidth: 1280,
13682
+ cookieDir: "",
13683
+ viewportWidth: 1280,
13684
+ viewportHeight: 720,
13685
+ navigationTimeout: 15000
13686
+ };
13687
+ });
13688
+
13663
13689
  // src/modules/browser/snapshot.ts
13664
13690
  function inferRole(tag, type) {
13665
13691
  const t2 = tag.toLowerCase();
@@ -13747,35 +13773,69 @@ function extractInteractiveElements(html, maxElements = 30) {
13747
13773
  }
13748
13774
  return elements;
13749
13775
  }
13750
- function formatSnapshot(snapshot) {
13776
+ function truncateText(text, maxChars) {
13777
+ if (maxChars <= 0)
13778
+ return "";
13779
+ if (text.length <= maxChars)
13780
+ return text;
13781
+ const cut = text.slice(0, maxChars);
13782
+ const lastNewline = cut.lastIndexOf(`
13783
+ `);
13784
+ const safe = lastNewline > maxChars * 0.6 ? cut.slice(0, lastNewline) : cut;
13785
+ return `${safe}
13786
+ ${t("browser.truncated")}`;
13787
+ }
13788
+ function formatSnapshot(snapshot, maxContentChars = DEFAULT_BROWSER_CONFIG.maxContentChars) {
13751
13789
  const lines = [];
13752
13790
  lines.push(`Page: "${snapshot.title}"`);
13753
13791
  lines.push(`URL: ${snapshot.url}`);
13754
13792
  lines.push("");
13755
13793
  if (snapshot.elements.length === 0 && !snapshot.truncated) {
13756
13794
  lines.push(t("browser.no_elements"));
13757
- return lines.join(`
13758
- `);
13795
+ } else {
13796
+ for (const el of snapshot.elements) {
13797
+ let line = `[${el.index}] ${el.role}`;
13798
+ if (el.name)
13799
+ line += ` "${el.name}"`;
13800
+ if (el.href)
13801
+ line += ` → ${el.href}`;
13802
+ if (el.value)
13803
+ line += ` = "${el.value}"`;
13804
+ lines.push(line);
13805
+ }
13806
+ if (snapshot.truncated) {
13807
+ lines.push("");
13808
+ lines.push(t("browser.more_elements"));
13809
+ }
13810
+ }
13811
+ if (snapshot.content) {
13812
+ lines.push("");
13813
+ lines.push(t("browser.content_header"));
13814
+ for (const line of truncateText(snapshot.content, maxContentChars).split(`
13815
+ `)) {
13816
+ lines.push(`- ${line}`);
13817
+ }
13759
13818
  }
13760
- for (const el of snapshot.elements) {
13761
- let line = `[${el.index}] ${el.role}`;
13762
- if (el.name)
13763
- line += ` "${el.name}"`;
13764
- if (el.href)
13765
- line += ` → ${el.href}`;
13766
- if (el.value)
13767
- line += ` = "${el.value}"`;
13768
- lines.push(line);
13769
- }
13770
- if (snapshot.truncated) {
13819
+ if (snapshot.console.length > 0) {
13771
13820
  lines.push("");
13772
- lines.push(t("browser.more_elements"));
13821
+ lines.push(t("browser.console_header"));
13822
+ for (const entry of snapshot.console) {
13823
+ lines.push(`[${entry.type}] ${entry.text}`);
13824
+ }
13825
+ }
13826
+ if (snapshot.networkErrors.length > 0) {
13827
+ lines.push("");
13828
+ lines.push(t("browser.network_errors_header"));
13829
+ for (const err of snapshot.networkErrors) {
13830
+ lines.push(`${err.method} ${err.url} → ${err.error}`);
13831
+ }
13773
13832
  }
13774
13833
  return lines.join(`
13775
13834
  `);
13776
13835
  }
13777
13836
  var init_snapshot = __esm(() => {
13778
13837
  init_i18n();
13838
+ init_types();
13779
13839
  });
13780
13840
 
13781
13841
  // src/modules/browser/actions.ts
@@ -13822,6 +13882,36 @@ function buildIndexInjectionScript() {
13822
13882
  });
13823
13883
  `;
13824
13884
  }
13885
+ function buildTextExtractionScript() {
13886
+ return `
13887
+ const contentTags = new Set(['h1','h2','h3','h4','h5','h6','p','li','article','main','section','blockquote','pre','td','th','dt','dd','figcaption']);
13888
+ const out = [];
13889
+ const seen = new Set();
13890
+ const isHidden = (el) => {
13891
+ const st = window.getComputedStyle(el);
13892
+ return st.display === 'none' || st.visibility === 'hidden';
13893
+ };
13894
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
13895
+ acceptNode: (node) => {
13896
+ const tag = node.tagName ? node.tagName.toLowerCase() : '';
13897
+ if (!contentTags.has(tag)) return NodeFilter.FILTER_SKIP;
13898
+ if (isHidden(node)) return NodeFilter.FILTER_REJECT;
13899
+ return NodeFilter.FILTER_ACCEPT;
13900
+ }
13901
+ });
13902
+ let node;
13903
+ while ((node = walker.nextNode())) {
13904
+ const tag = node.tagName.toLowerCase();
13905
+ const text = (node.textContent || '').replace(/\\s+/g, ' ').trim();
13906
+ if (!text) continue;
13907
+ if (seen.has(text)) continue;
13908
+ seen.add(text);
13909
+ const line = text.length > 200 ? text.slice(0, 200) + '…' : text;
13910
+ out.push('[' + tag + '] ' + line);
13911
+ }
13912
+ return out.join('\\n');
13913
+ `;
13914
+ }
13825
13915
 
13826
13916
  // src/modules/browser/cookie-store.ts
13827
13917
  import { readFile, writeFile, mkdir } from "fs/promises";
@@ -13855,6 +13945,33 @@ import {
13855
13945
  chromium
13856
13946
  } from "playwright";
13857
13947
 
13948
+ class ConsoleBuffer {
13949
+ entries = [];
13950
+ maxEntries;
13951
+ constructor(maxEntries = 20) {
13952
+ this.maxEntries = maxEntries;
13953
+ }
13954
+ add(type, text) {
13955
+ const clean = String(text).replace(/\s+/g, " ").trim();
13956
+ if (!clean)
13957
+ return;
13958
+ const line = clean.length > CONSOLE_MAX_LINE ? clean.slice(0, CONSOLE_MAX_LINE) + "…" : clean;
13959
+ this.entries.push({ type, text: line });
13960
+ if (this.entries.length > this.maxEntries) {
13961
+ this.entries.splice(0, this.entries.length - this.maxEntries);
13962
+ }
13963
+ }
13964
+ clear() {
13965
+ this.entries = [];
13966
+ }
13967
+ getAll() {
13968
+ return [...this.entries];
13969
+ }
13970
+ get size() {
13971
+ return this.entries.length;
13972
+ }
13973
+ }
13974
+
13858
13975
  class BrowserActionTracker {
13859
13976
  history = [];
13860
13977
  threshold;
@@ -13893,9 +14010,12 @@ class BrowserSession {
13893
14010
  elementCount: 0
13894
14011
  };
13895
14012
  actionTracker = new BrowserActionTracker(3);
14013
+ consoleBuffer;
14014
+ networkErrors = [];
13896
14015
  constructor(config) {
13897
14016
  this.config = config;
13898
14017
  this.cookieStore = new CookieStore(config.cookieDir);
14018
+ this.consoleBuffer = new ConsoleBuffer(config.maxConsoleEntries);
13899
14019
  }
13900
14020
  getState() {
13901
14021
  return { ...this.state };
@@ -13981,6 +14101,20 @@ class BrowserSession {
13981
14101
  }
13982
14102
  this.page = await this.context.newPage();
13983
14103
  this.page.setDefaultTimeout(this.config.navigationTimeout);
14104
+ this.page.on("console", (msg) => {
14105
+ this.consoleBuffer.add(msg.type(), msg.text());
14106
+ });
14107
+ this.page.on("pageerror", (err) => {
14108
+ this.consoleBuffer.add("pageerror", `Page error: ${err.message}`);
14109
+ });
14110
+ this.page.on("requestfailed", (req) => {
14111
+ const failure = req.failure();
14112
+ this.networkErrors.push({
14113
+ method: req.method(),
14114
+ url: req.url(),
14115
+ error: failure?.errorText || "unknown"
14116
+ });
14117
+ });
13984
14118
  }
13985
14119
  async saveCookies() {
13986
14120
  if (!this.context)
@@ -13995,6 +14129,12 @@ class BrowserSession {
13995
14129
  const html = await this.page.content();
13996
14130
  const url = this.page.url();
13997
14131
  const title = await this.page.title();
14132
+ let content = "";
14133
+ try {
14134
+ content = await this.page.evaluate(buildTextExtractionScript());
14135
+ } catch {
14136
+ content = "";
14137
+ }
13998
14138
  const allElements = extractInteractiveElements(html, this.config.maxElements + 5);
13999
14139
  const truncated = allElements.length > this.config.maxElements;
14000
14140
  const elements = allElements.slice(0, this.config.maxElements);
@@ -14004,7 +14144,15 @@ class BrowserSession {
14004
14144
  title,
14005
14145
  elementCount: elements.length
14006
14146
  };
14007
- return formatSnapshot({ url, title, elements, truncated });
14147
+ return formatSnapshot({
14148
+ url,
14149
+ title,
14150
+ elements,
14151
+ content,
14152
+ console: this.consoleBuffer.getAll(),
14153
+ networkErrors: this.networkErrors.slice(-5),
14154
+ truncated
14155
+ });
14008
14156
  }
14009
14157
  async open(url) {
14010
14158
  if (!url)
@@ -14017,6 +14165,8 @@ class BrowserSession {
14017
14165
  if (!this.page)
14018
14166
  return { success: false, output: t("browser.create_page_failed") };
14019
14167
  this.actionTracker.reset();
14168
+ this.consoleBuffer.clear();
14169
+ this.networkErrors = [];
14020
14170
  try {
14021
14171
  await this.page.goto(url, {
14022
14172
  waitUntil: "domcontentloaded",
@@ -14173,26 +14323,13 @@ class BrowserSession {
14173
14323
  return { success: true, output: t("browser.closed") };
14174
14324
  }
14175
14325
  }
14326
+ var CONSOLE_MAX_LINE = 200;
14176
14327
  var init_session = __esm(() => {
14177
14328
  init_snapshot();
14178
14329
  init_cookie_store();
14179
14330
  init_i18n();
14180
14331
  });
14181
14332
 
14182
- // src/modules/browser/types.ts
14183
- var DEFAULT_BROWSER_CONFIG;
14184
- var init_types = __esm(() => {
14185
- DEFAULT_BROWSER_CONFIG = {
14186
- headless: true,
14187
- maxElements: 30,
14188
- screenshotMaxWidth: 1280,
14189
- cookieDir: "",
14190
- viewportWidth: 1280,
14191
- viewportHeight: 720,
14192
- navigationTimeout: 15000
14193
- };
14194
- });
14195
-
14196
14333
  // src/tools/browser.ts
14197
14334
  import { join as join18 } from "path";
14198
14335
  function getSession(ctx) {
@@ -14202,6 +14339,8 @@ function getSession(ctx) {
14202
14339
  ...DEFAULT_BROWSER_CONFIG,
14203
14340
  headless: ctx.config.browser?.headless ?? true,
14204
14341
  maxElements: ctx.config.browser?.maxElements ?? 30,
14342
+ maxContentChars: ctx.config.browser?.maxContentChars ?? 2500,
14343
+ maxConsoleEntries: ctx.config.browser?.maxConsoleEntries ?? 20,
14205
14344
  navigationTimeout: ctx.config.browser?.navigationTimeout ?? 15000,
14206
14345
  viewportWidth: ctx.config.browser?.viewportWidth ?? 1280,
14207
14346
  viewportHeight: ctx.config.browser?.viewportHeight ?? 720,
@@ -14230,7 +14369,8 @@ function createBrowserTool() {
14230
14369
  tags: ["browser", "vision"],
14231
14370
  description: [
14232
14371
  "Control a headless browser. Navigate pages, click elements, type text, scroll, take screenshots.",
14233
- "Returns a numbered list of interactive elements use element numbers as targets for click/type.",
14372
+ "Each snapshot returns: a numbered list of interactive elements, the visible page text (Content section), browser console messages, and network errors.",
14373
+ "Use the Content section to understand what the page says; use element numbers as targets for click/type.",
14234
14374
  "Actions: open (url), click (target), type (target, text), scroll (direction), back, forward, screenshot, snapshot, close, wait (ms)."
14235
14375
  ].join(" "),
14236
14376
  parameters: {
@@ -17002,6 +17142,7 @@ class BrowserModule {
17002
17142
  content: [
17003
17143
  "You have a headless browser tool. Use it to navigate websites, click links, fill forms, and read page content.",
17004
17144
  "Workflow: open(url) → read snapshot → click/type on element numbers → read updated snapshot.",
17145
+ 'Each snapshot includes a "Content" section with the visible page text, a "Console" section with browser messages, and network errors. Use these to understand the page, detect JS errors, and verify the result of your actions.',
17005
17146
  'Always start with "open" action. Use element numbers from snapshot for click/type targets.',
17006
17147
  'Use "screenshot" action only if the model supports vision. Otherwise rely on the text snapshot.'
17007
17148
  ].join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {