agentic-browser 2.1.0 → 2.3.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.
package/AGENTS.md CHANGED
@@ -108,7 +108,7 @@ AgenticBrowserCore → ControlApi → SessionManager → BrowserController (CDP)
108
108
 
109
109
  ## Environment Variables
110
110
 
111
- - `AGENTIC_BROWSER_LOG_DIR` — base dir for sessions/memory/events (default: `.agentic-browser`)
111
+ - `AGENTIC_BROWSER_DIR` — base dir for sessions/memory/events (default: `.agentic-browser`)
112
112
  - `AGENTIC_BROWSER_CHROME_EXECUTABLE_PATH` — explicit Chrome path (auto-discovered if not set)
113
113
  - `AGENTIC_BROWSER_CDP_URL` — connect to an already-running Chrome via CDP (e.g. `http://127.0.0.1:9222`)
114
114
  - `AGENTIC_BROWSER_USER_PROFILE` — use real Chrome profile (`default`, `true`, or absolute path)
package/README.md CHANGED
@@ -113,7 +113,7 @@ agentic-browser agent start --user-agent "MyBot/1.0"
113
113
  agentic-browser agent status
114
114
  agentic-browser agent navigate https://example.com
115
115
  agentic-browser agent click "#login"
116
- agentic-browser agent content --mode text
116
+ agentic-browser agent content --mode summary
117
117
  agentic-browser agent content --mode html --selector main
118
118
  agentic-browser agent elements
119
119
  agentic-browser agent elements --roles button,link --limit 20
@@ -156,6 +156,8 @@ MCP responses are compact — `visible`, `actions`, and `tagName` are omitted to
156
156
 
157
157
  When an element lives inside an open shadow root or a same-origin iframe, discovery returns a composed locator using `>>>` to cross boundaries, for example `iframe[name="checkout"] >>> button[aria-label="Pay"]`. The same locator string works with `agent click`, `agent type`, MCP `browser_interact`, and fallback selectors.
158
158
 
159
+ `agent content` and MCP `browser_get_content` now default to `summary`, which returns a low-token overview with `title`, `headings`, `landmarks`, `primaryActions`, `inputs`, `alerts`, and iframe metadata. Use `a11y` when you need the deeper accessibility structure, and `text` or `html` only when you need raw content.
160
+
159
161
  ````
160
162
 
161
163
  ## MCP Server
@@ -225,8 +227,8 @@ More `interact` actions:
225
227
  ### 4. Read Page Content
226
228
 
227
229
  ```bash
230
+ agentic-browser page:content <sessionId> --mode summary
228
231
  agentic-browser page:content <sessionId> --mode title
229
- agentic-browser page:content <sessionId> --mode text
230
232
  agentic-browser page:content <sessionId> --mode html --selector main
231
233
  ```
232
234
 
@@ -265,7 +267,7 @@ agentic-browser memory:stats
265
267
  ## Important Notes for LLMs
266
268
 
267
269
  - Exactly **one** managed session is supported at a time.
268
- - Session state is persisted in `.agentic-browser/`.
270
+ - Session state is persisted in `~/.agentic-browser/` (override with `AGENTIC_BROWSER_DIR`).
269
271
  - All commands print exactly one JSON line to `stdout`.
270
272
  - The typed `agent` commands are the preferred interface for LLMs. Use low-level `command:run` only when you need raw JSON payload control.
271
273
  - Parse only `stdout` as result object and use exit code for success/failure.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as createCliRuntime } from "../runtime-CEvs2yzE.mjs";
2
+ import { r as createCliRuntime } from "../runtime-BCGndjhR.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import crypto from "node:crypto";
@@ -7,7 +7,7 @@ import { Command } from "commander";
7
7
  //#region src/cli/commands/agent.ts
8
8
  const STATE_FILE_NAME = "agent-state.json";
9
9
  function stateFilePath(runtime) {
10
- return path.join(runtime.context.config.logDir, STATE_FILE_NAME);
10
+ return path.join(runtime.context.config.dataDir, STATE_FILE_NAME);
11
11
  }
12
12
  function loadState(runtime) {
13
13
  const filePath = stateFilePath(runtime);
@@ -151,7 +151,8 @@ async function agentContent(runtime, input) {
151
151
  action: "content",
152
152
  ...await runtime.api.getContent(sessionId, {
153
153
  mode: input.mode,
154
- selector: input.selector
154
+ selector: input.selector,
155
+ maxChars: input.maxChars
155
156
  })
156
157
  };
157
158
  }
@@ -249,7 +250,8 @@ async function runCommand(runtime, input) {
249
250
  async function runPageContent(runtime, input) {
250
251
  return await runtime.api.getContent(input.sessionId, {
251
252
  mode: input.mode,
252
- selector: input.selector
253
+ selector: input.selector,
254
+ maxChars: input.maxChars
253
255
  });
254
256
  }
255
257
  //#endregion
@@ -322,11 +324,12 @@ async function main() {
322
324
  });
323
325
  console.log(JSON.stringify(result));
324
326
  });
325
- program.command("page:content").argument("<sessionId>").option("--mode <mode>", "title|text|html|a11y", "text").option("--selector <selector>", "optional CSS selector").action(async (sessionId, options) => {
327
+ program.command("page:content").argument("<sessionId>").option("--mode <mode>", "title|text|html|a11y|summary", "summary").option("--selector <selector>", "optional CSS selector").option("--max-chars <n>", "max characters for text/html/a11y modes").action(async (sessionId, options) => {
326
328
  const result = await runPageContent(runtime, {
327
329
  sessionId,
328
330
  mode: options.mode,
329
- selector: options.selector
331
+ selector: options.selector,
332
+ maxChars: options.maxChars ? Number.parseInt(options.maxChars, 10) : void 0
330
333
  });
331
334
  console.log(JSON.stringify(result));
332
335
  });
@@ -470,8 +473,12 @@ async function main() {
470
473
  const result = await agentTerminate(runtime);
471
474
  console.log(JSON.stringify(result));
472
475
  });
473
- agent.command("content").option("--mode <mode>", "title|text|html|a11y", "text").option("--selector <selector>", "optional CSS selector").action(async (options) => {
474
- const result = await agentContent(runtime, options);
476
+ agent.command("content").option("--mode <mode>", "title|text|html|a11y|summary", "summary").option("--selector <selector>", "optional CSS selector").option("--max-chars <n>", "max characters for text/html/a11y modes").action(async (options) => {
477
+ const result = await agentContent(runtime, {
478
+ mode: options.mode,
479
+ selector: options.selector,
480
+ maxChars: options.maxChars ? Number.parseInt(options.maxChars, 10) : void 0
481
+ });
475
482
  console.log(JSON.stringify(result));
476
483
  });
477
484
  agent.command("elements").description("List interactive elements on the current page").option("--roles <roles>", "comma-separated roles filter", (v) => v.split(",")).option("--visible-only", "only visible elements", true).option("--no-visible-only", "include hidden elements").option("--limit <n>", "max elements", "50").option("--selector <selector>", "scope to CSS selector subtree").action(async (options) => {
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-CEvs2yzE.mjs";
2
+ import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-BCGndjhR.mjs";
3
3
  export { AgenticBrowserCore, createAgenticBrowserCore, createMockAgenticBrowserCore };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as createAgenticBrowserCore } from "../runtime-CEvs2yzE.mjs";
2
+ import { n as createAgenticBrowserCore } from "../runtime-BCGndjhR.mjs";
3
3
  import { z } from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -22,10 +22,27 @@ function truncateContent(content, limit) {
22
22
  };
23
23
  const originalLength = content.length;
24
24
  return {
25
- content: content.slice(0, limit) + `\n\n[Truncated — showing first ${limit} of ${originalLength} characters. Use a CSS selector to scope the content.]`,
25
+ content: content.slice(0, limit) + `\n\n[Truncated - showing first ${limit} of ${originalLength} characters. Use a CSS selector to scope the content, or use mode="summary" for a lower-token overview.]`,
26
26
  truncated: true
27
27
  };
28
28
  }
29
+ function resolveCompactedContent(result, limit) {
30
+ if (result.truncated) return {
31
+ content: result.content,
32
+ truncated: true
33
+ };
34
+ return truncateContent(result.content, limit);
35
+ }
36
+ function parseStructuredSummary(result) {
37
+ if (result.structuredContent) return result.structuredContent;
38
+ if (!result.content) return;
39
+ try {
40
+ const parsed = JSON.parse(result.content);
41
+ return parsed && typeof parsed === "object" ? parsed : void 0;
42
+ } catch {
43
+ return;
44
+ }
45
+ }
29
46
  function summarizeTextContent(content) {
30
47
  const lines = uniqueLines(content);
31
48
  return {
@@ -68,9 +85,23 @@ function compactPageContent(result, maxChars) {
68
85
  text: 8e3,
69
86
  a11y: 1e4,
70
87
  html: 4e3,
71
- title: void 0
88
+ title: void 0,
89
+ summary: void 0
72
90
  }[result.mode];
73
- const truncated = truncateContent(result.content, limit);
91
+ if (result.mode === "summary") {
92
+ const structured = parseStructuredSummary(result);
93
+ if (structured) return {
94
+ mode: "summary",
95
+ ...structured,
96
+ truncated: false
97
+ };
98
+ return {
99
+ mode: "summary",
100
+ content: result.content,
101
+ truncated: false
102
+ };
103
+ }
104
+ const truncated = resolveCompactedContent(result, limit);
74
105
  if (result.mode === "title") return {
75
106
  ...result,
76
107
  truncated: false
@@ -81,6 +112,7 @@ function compactPageContent(result, maxChars) {
81
112
  mode: result.mode,
82
113
  content: truncated.content,
83
114
  truncated: truncated.truncated,
115
+ originalLength: result.originalLength,
84
116
  summaryLines: summary.summaryLines,
85
117
  previewLines: summary.previewLines
86
118
  };
@@ -91,6 +123,7 @@ function compactPageContent(result, maxChars) {
91
123
  mode: result.mode,
92
124
  content: truncated.content,
93
125
  truncated: truncated.truncated,
126
+ originalLength: result.originalLength,
94
127
  headings: summary.headings,
95
128
  landmarks: summary.landmarks,
96
129
  actions: summary.actions,
@@ -101,7 +134,8 @@ function compactPageContent(result, maxChars) {
101
134
  return {
102
135
  mode: result.mode,
103
136
  content: truncated.content,
104
- truncated: truncated.truncated
137
+ truncated: truncated.truncated,
138
+ originalLength: result.originalLength
105
139
  };
106
140
  }
107
141
  function summarizeElements(elements) {
@@ -152,6 +186,14 @@ function compactMemoryResults(results) {
152
186
  if (Array.isArray(compactAlias.fallbackSelectors) && compactAlias.fallbackSelectors.length === 0) delete compactAlias.fallbackSelectors;
153
187
  return compactAlias;
154
188
  });
189
+ if (compact.siteProfile) {
190
+ const profile = compact.siteProfile;
191
+ compact.siteProfile = {
192
+ selectorPatterns: (profile.selectorPatterns ?? []).map((p) => `${p.pattern} (x${p.frequency})`),
193
+ cookieBanner: profile.cookieBanner,
194
+ visitCount: profile.visitCount
195
+ };
196
+ }
155
197
  return compact;
156
198
  }) };
157
199
  }
@@ -159,6 +201,13 @@ function compactMemoryResults(results) {
159
201
  //#region src/mcp/index.ts
160
202
  let core;
161
203
  let activeSessionId;
204
+ const DEFAULT_MCP_MAX_CHARS = {
205
+ summary: void 0,
206
+ title: void 0,
207
+ text: 8e3,
208
+ a11y: 1e4,
209
+ html: 4e3
210
+ };
162
211
  function getCore() {
163
212
  if (!core) core = createAgenticBrowserCore();
164
213
  return core;
@@ -265,26 +314,29 @@ server.tool("browser_interact", "Interact with a page element or perform browser
265
314
  text: JSON.stringify(compact)
266
315
  }] };
267
316
  });
268
- server.tool("browser_get_content", "Get the current page content. Modes: \"text\" (readable text), \"a11y\" (accessibility tree — best for understanding page structure), \"title\" (page title only), \"html\" (raw HTML). Use \"a11y\" to see the full page hierarchy with roles, names, and states. A session is auto-started if needed.", {
317
+ server.tool("browser_get_content", "Get the current page content. Modes: \"summary\" (recommended low-token overview with headings, actions, inputs, alerts, and iframe awareness), \"text\" (readable text), \"a11y\" (accessibility tree for deeper structure), \"title\" (page title only), \"html\" (raw HTML). A session is auto-started if needed.", {
269
318
  mode: z.enum([
270
319
  "title",
271
320
  "text",
272
321
  "html",
273
- "a11y"
274
- ]).default("text").describe("Content extraction mode"),
322
+ "a11y",
323
+ "summary"
324
+ ]).default("summary").describe("Content extraction mode"),
275
325
  selector: z.string().optional().describe("CSS selector to scope content (e.g. \"main\", \"#content\")"),
276
- maxChars: z.number().optional().describe("Maximum characters to return (default: 12000 for text/a11y, 6000 for html, no cap for title). Use a CSS selector to scope content instead of raising this limit."),
326
+ maxChars: z.number().optional().describe("Maximum characters to return (default: 8000 for text, 10000 for a11y, 4000 for html, ignored for summary/title). Use a CSS selector to scope content instead of raising this limit."),
277
327
  sessionId: z.string().optional().describe("Session ID (auto-resolved if omitted)")
278
328
  }, async ({ mode, selector, maxChars, sessionId }) => {
279
329
  const sid = await resolveSession(sessionId);
330
+ const effectiveMaxChars = maxChars ?? DEFAULT_MCP_MAX_CHARS[mode];
280
331
  const result = await getCore().getPageContent({
281
332
  sessionId: sid,
282
333
  mode,
283
- selector
334
+ selector,
335
+ maxChars: effectiveMaxChars
284
336
  });
285
337
  return { content: [{
286
338
  type: "text",
287
- text: JSON.stringify(compactPageContent(result, maxChars))
339
+ text: JSON.stringify(compactPageContent(result))
288
340
  }] };
289
341
  });
290
342
  server.tool("browser_get_elements", "Discover all interactive elements on the current page (buttons, links, inputs, etc.). Returns CSS selectors and fallbackSelectors you can use with browser_interact. Pass fallbackSelectors to browser_interact for automatic retry when the primary selector breaks. Actions are derived from role: link/button/custom→click, input/textarea/contenteditable→click+type+press, select→click+select, checkbox/radio→toggle. A session is auto-started if needed.", {