@nuanu-ai/agentbrowse 0.2.1 → 0.2.3

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/README.md CHANGED
@@ -27,7 +27,7 @@ agentbrowse launch https://example.com
27
27
 
28
28
  - Node.js 18+
29
29
  - a Chrome-compatible browser runtime available on the machine
30
- - an Anthropic API key for browsing commands
30
+ - an AgentPay API key for CLI startup and browsing commands
31
31
 
32
32
  ## Commands
33
33
 
@@ -76,26 +76,23 @@ agentbrowse close
76
76
 
77
77
  ## Configure
78
78
 
79
- Browsing commands use Anthropic via Stagehand:
79
+ `agentbrowse` uses the AgentPay backend for browser reasoning and gateway-backed
80
+ operations:
80
81
 
81
82
  ```bash
82
- export ANTHROPIC_API_KEY=...
83
+ export AGENTPAY_API_KEY=...
83
84
  ```
84
85
 
85
- Optional model override:
86
+ Optional API base URL override:
86
87
 
87
88
  ```bash
88
- export AGENTBROWSE_MODEL=anthropic/claude-haiku-4-5-20251001
89
+ export AGENTPAY_API_URL=https://durcottggsiesxxqzvbb.supabase.co/functions/v1/api
89
90
  ```
90
91
 
91
- `solve-captcha` is separate and uses AgentPay gateway credentials only when
92
- that command is invoked.
93
-
94
92
  ## Runtime model
95
93
 
96
94
  - `agentbrowse` persists the active browser session under `~/.agentpay`
97
- - browsing commands require `ANTHROPIC_API_KEY`
98
- - normal browsing commands do not require `AGENTPAY_API_KEY`
95
+ - all commands require `AGENTPAY_API_KEY`
99
96
  - `solve-captcha` requires both:
100
97
  - a session with captcha-solving capability
101
98
  - AgentPay gateway configuration
@@ -5,4 +5,5 @@ export interface AgentpayGatewayConfig {
5
5
  export declare function tryResolveAgentpayGatewayConfig(): AgentpayGatewayConfig | null;
6
6
  export declare function resolveAgentpayGatewayConfig(): AgentpayGatewayConfig;
7
7
  export declare function applyAgentpayGatewayEnv(gateway: AgentpayGatewayConfig): void;
8
+ export declare function preflightAgentpayGateway(): Promise<AgentpayGatewayConfig>;
8
9
  //# sourceMappingURL=agentpay-gateway.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agentpay-gateway.d.ts","sourceRoot":"","sources":["../src/agentpay-gateway.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAiCD,wBAAgB,+BAA+B,IAAI,qBAAqB,GAAG,IAAI,CAoB9E;AAED,wBAAgB,4BAA4B,IAAI,qBAAqB,CAMpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAG5E"}
1
+ {"version":3,"file":"agentpay-gateway.d.ts","sourceRoot":"","sources":["../src/agentpay-gateway.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAiCD,wBAAgB,+BAA+B,IAAI,qBAAqB,GAAG,IAAI,CAoB9E;AAED,wBAAgB,4BAA4B,IAAI,qBAAqB,CAMpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAG5E;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAI/E"}
@@ -48,7 +48,7 @@ export function tryResolveAgentpayGatewayConfig() {
48
48
  export function resolveAgentpayGatewayConfig() {
49
49
  const gateway = tryResolveAgentpayGatewayConfig();
50
50
  if (!gateway) {
51
- throw new Error('Captcha solving requires API key configuration.');
51
+ throw new Error('AgentPay API key is required.');
52
52
  }
53
53
  return gateway;
54
54
  }
@@ -56,3 +56,8 @@ export function applyAgentpayGatewayEnv(gateway) {
56
56
  process.env.AGENTPAY_API_KEY = gateway.apiKey;
57
57
  process.env.AGENTPAY_API_URL = gateway.apiUrl;
58
58
  }
59
+ export async function preflightAgentpayGateway() {
60
+ const gateway = resolveAgentpayGatewayConfig();
61
+ applyAgentpayGatewayEnv(gateway);
62
+ return gateway;
63
+ }
@@ -0,0 +1,19 @@
1
+ import { LLMClient, toJsonSchema, type CreateChatCompletionOptions, type LLMParsedResponse, type LLMResponse } from '@browserbasehq/stagehand';
2
+ import type { AgentpayGatewayConfig } from './agentpay-gateway.js';
3
+ export declare class AgentpayStagehandLlmClient extends LLMClient {
4
+ private readonly gateway;
5
+ type: "agentpay";
6
+ clientOptions: {};
7
+ constructor(gateway: AgentpayGatewayConfig);
8
+ createChatCompletion<T>(args: CreateChatCompletionOptions & {
9
+ options: {
10
+ response_model: {
11
+ name: string;
12
+ schema: Parameters<typeof toJsonSchema>[0];
13
+ };
14
+ };
15
+ }): Promise<LLMParsedResponse<T>>;
16
+ createChatCompletion<T = LLMResponse>(args: CreateChatCompletionOptions): Promise<T>;
17
+ }
18
+ export declare function createAgentpayStagehandLlmClient(gateway: AgentpayGatewayConfig): AgentpayStagehandLlmClient;
19
+ //# sourceMappingURL=agentpay-stagehand-llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentpay-stagehand-llm.d.ts","sourceRoot":"","sources":["../src/agentpay-stagehand-llm.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAiDnE,qBAAa,0BAA2B,SAAQ,SAAS;IAI3C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,IAAI,EAAG,UAAU,CAAU;IAC3B,aAAa,KAAM;gBAEU,OAAO,EAAE,qBAAqB;IAKrD,oBAAoB,CAAC,CAAC,EAC1B,IAAI,EAAE,2BAA2B,GAAG;QAClC,OAAO,EAAE;YACP,cAAc,EAAE;gBACd,IAAI,EAAE,MAAM,CAAC;gBACb,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;aAC5C,CAAC;SACH,CAAC;KACH,GACA,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC1B,oBAAoB,CAAC,CAAC,GAAG,WAAW,EACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,CAAC,CAAC;CA4Fd;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,qBAAqB,GAC7B,0BAA0B,CAE5B"}
@@ -0,0 +1,128 @@
1
+ import { LLMClient, toJsonSchema, } from '@browserbasehq/stagehand';
2
+ function gatewayBaseUrl(gateway) {
3
+ return gateway.apiUrl.replace(/\/$/, '');
4
+ }
5
+ function isRetryableStatus(status) {
6
+ return status === 429 || status === 502 || status === 503 || status === 504 || status >= 500;
7
+ }
8
+ function resolvePurpose(options) {
9
+ const modelName = options.response_model?.name?.trim().toLowerCase();
10
+ switch (modelName) {
11
+ case 'observation':
12
+ return 'browse.observe';
13
+ case 'extraction':
14
+ return 'browse.extract';
15
+ case 'metadata':
16
+ return 'browse.extract.metadata';
17
+ case 'act':
18
+ return 'browse.act';
19
+ default:
20
+ return 'browse.stagehand';
21
+ }
22
+ }
23
+ async function withRetry(fn, retries = 1) {
24
+ for (let attempt = 0;; attempt += 1) {
25
+ try {
26
+ return await fn();
27
+ }
28
+ catch (err) {
29
+ const retryable = err instanceof Error &&
30
+ (err.name === 'RetryableHttpError' || err.name === 'RetryableNetworkError');
31
+ if (!retryable || attempt >= retries) {
32
+ throw err;
33
+ }
34
+ await new Promise((resolve) => setTimeout(resolve, 2_000 * (attempt + 1)));
35
+ }
36
+ }
37
+ }
38
+ export class AgentpayStagehandLlmClient extends LLMClient {
39
+ gateway;
40
+ type = 'agentpay';
41
+ clientOptions = {};
42
+ constructor(gateway) {
43
+ super('agentpay/backend');
44
+ this.gateway = gateway;
45
+ this.modelName = 'agentpay/backend';
46
+ }
47
+ async createChatCompletion({ options, logger }) {
48
+ if (!options.response_model) {
49
+ logger({
50
+ category: 'llm',
51
+ message: 'agentpay backend llm client received unsupported non-structured completion',
52
+ level: 0,
53
+ });
54
+ throw new Error('AgentPay Stagehand LLM client currently requires response_model');
55
+ }
56
+ const url = `${gatewayBaseUrl(this.gateway)}/tools/llm/structured-chat`;
57
+ const body = {
58
+ purpose: resolvePurpose(options),
59
+ messages: options.messages,
60
+ response_model: {
61
+ name: options.response_model.name,
62
+ schema: toJsonSchema(options.response_model.schema),
63
+ },
64
+ image: options.image
65
+ ? {
66
+ media_type: 'image/jpeg',
67
+ data_base64: options.image.buffer.toString('base64'),
68
+ description: options.image.description,
69
+ }
70
+ : undefined,
71
+ temperature: options.temperature,
72
+ max_output_tokens: options.maxOutputTokens,
73
+ };
74
+ const result = await withRetry(async () => {
75
+ let response;
76
+ try {
77
+ response = await fetch(url, {
78
+ method: 'POST',
79
+ headers: {
80
+ Authorization: `Bearer ${this.gateway.apiKey}`,
81
+ Accept: 'application/json',
82
+ 'Content-Type': 'application/json',
83
+ },
84
+ body: JSON.stringify(body),
85
+ signal: AbortSignal.timeout(45_000),
86
+ });
87
+ }
88
+ catch (err) {
89
+ const error = new Error(`AgentPay LLM gateway network error: ${err instanceof Error ? err.message : String(err)}`);
90
+ error.name = 'RetryableNetworkError';
91
+ throw error;
92
+ }
93
+ let json;
94
+ try {
95
+ json = (await response.json());
96
+ }
97
+ catch {
98
+ const parseError = new Error(`AgentPay LLM gateway returned non-JSON response (${response.status})`);
99
+ parseError.name = isRetryableStatus(response.status) ? 'RetryableHttpError' : 'HttpError';
100
+ throw parseError;
101
+ }
102
+ if (!response.ok) {
103
+ const message = typeof json.error === 'string' ? json.error : `HTTP ${response.status}`;
104
+ const error = new Error(`AgentPay LLM gateway error (${response.status}): ${message}`);
105
+ error.name = isRetryableStatus(response.status) ? 'RetryableHttpError' : 'HttpError';
106
+ throw error;
107
+ }
108
+ return json;
109
+ });
110
+ logger({
111
+ category: 'llm',
112
+ message: 'agentpay backend structured completion finished',
113
+ level: 2,
114
+ auxiliary: {
115
+ provider: { value: result.provider, type: 'string' },
116
+ model: { value: result.model, type: 'string' },
117
+ purpose: { value: resolvePurpose(options), type: 'string' },
118
+ },
119
+ });
120
+ return {
121
+ data: result.data,
122
+ usage: result.usage,
123
+ };
124
+ }
125
+ }
126
+ export function createAgentpayStagehandLlmClient(gateway) {
127
+ return new AgentpayStagehandLlmClient(gateway);
128
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ declare function main(argv?: string[]): Promise<void>;
3
+ export { main };
4
+ export declare function isDirectExecution(metaUrl: string, argv?: string[]): boolean;
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA8KA,iBAAe,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsGhE;AAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAWzF"}
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { config as loadEnv } from 'dotenv';
3
+ import { realpathSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
3
5
  loadEnv();
6
+ import { preflightAgentpayGateway } from './agentpay-gateway.js';
4
7
  import { browseCommand, browseCommandName } from './command-name.js';
5
8
  import { loadSession } from './session.js';
6
9
  import { outputError, fatal, info } from './output.js';
@@ -30,10 +33,8 @@ Options:
30
33
  --help Show this help message
31
34
 
32
35
  Environment:
33
- ANTHROPIC_API_KEY Required for browsing commands
34
- AGENTBROWSE_MODEL Optional model override for browsing commands
35
- AGENTPAY_API_KEY Required only for solve-captcha / gateway-backed solve
36
- AGENTPAY_API_URL Optional API base URL override for solve-captcha`;
36
+ AGENTPAY_API_KEY Required for CLI start and browsing commands
37
+ AGENTPAY_API_URL Optional API base URL override`;
37
38
  }
38
39
  const KNOWN_COMMANDS = new Set([
39
40
  'launch',
@@ -46,8 +47,8 @@ const KNOWN_COMMANDS = new Set([
46
47
  'status',
47
48
  'close',
48
49
  ]);
49
- function getCommand() {
50
- const rawArgs = process.argv.slice(2);
50
+ function getCommand(argv = process.argv) {
51
+ const rawArgs = argv.slice(2);
51
52
  if (rawArgs.length === 0 || rawArgs[0] === '--help') {
52
53
  info(usageText());
53
54
  process.exit(0);
@@ -137,14 +138,20 @@ function requireSession() {
137
138
  // Caller will handle connection errors.
138
139
  return 'ws://localhost:9222';
139
140
  }
140
- async function main() {
141
- const parsed = getCommand();
141
+ async function main(argv = process.argv) {
142
+ const parsed = getCommand(argv);
142
143
  if (!parsed)
143
144
  process.exit(1);
144
145
  const { command, args } = parsed;
145
146
  if (!KNOWN_COMMANDS.has(command)) {
146
147
  outputError(`Unknown command: ${command}\n\n${usageText()}`);
147
148
  }
149
+ try {
150
+ await preflightAgentpayGateway();
151
+ }
152
+ catch (err) {
153
+ outputError(err instanceof Error ? err.message : String(err));
154
+ }
148
155
  switch (command) {
149
156
  case 'launch': {
150
157
  const { launch } = await import('./commands/launch.js');
@@ -225,6 +232,21 @@ async function main() {
225
232
  }
226
233
  }
227
234
  }
228
- main().catch((err) => {
229
- fatal(err instanceof Error ? err.message : String(err));
230
- });
235
+ export { main };
236
+ export function isDirectExecution(metaUrl, argv = process.argv) {
237
+ const entry = argv[1];
238
+ if (!entry) {
239
+ return false;
240
+ }
241
+ try {
242
+ return realpathSync(entry) === realpathSync(fileURLToPath(metaUrl));
243
+ }
244
+ catch {
245
+ return false;
246
+ }
247
+ }
248
+ if (isDirectExecution(import.meta.url)) {
249
+ main().catch((err) => {
250
+ fatal(err instanceof Error ? err.message : String(err));
251
+ });
252
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAUrD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kDAAkD;AAClD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAczE;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,SAAmB,GAAG,MAAM,GAAG,IAAI,CAQpE;AAED,qDAAqD;AACrD,wBAAsB,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAI/F"}
1
+ {"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAMrD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kDAAkD;AAClD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAezE;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,SAAmB,GAAG,MAAM,GAAG,IAAI,CAQpE;AAED,qDAAqD;AACrD,wBAAsB,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAI/F"}
package/dist/stagehand.js CHANGED
@@ -6,17 +6,15 @@
6
6
  */
7
7
  import { execSync } from 'node:child_process';
8
8
  import { Stagehand } from '@browserbasehq/stagehand';
9
+ import { createAgentpayStagehandLlmClient } from './agentpay-stagehand-llm.js';
10
+ import { resolveAgentpayGatewayConfig } from './agentpay-gateway.js';
9
11
  const DEFAULT_CDP_PORT = 9222;
10
- const DEFAULT_MODEL = 'anthropic/claude-haiku-4-5-20251001';
11
- function resolveStagehandModel() {
12
- const override = process.env.AGENTBROWSE_MODEL?.trim();
13
- return override && override.length > 0 ? override : DEFAULT_MODEL;
14
- }
15
12
  /** Connect to an existing browser via CDP URL. */
16
13
  export async function connectStagehand(cdpUrl) {
14
+ const gateway = resolveAgentpayGatewayConfig();
17
15
  const stagehand = new Stagehand({
18
16
  env: 'LOCAL',
19
- model: resolveStagehandModel(),
17
+ llmClient: createAgentpayStagehandLlmClient(gateway),
20
18
  localBrowserLaunchOptions: {
21
19
  cdpUrl,
22
20
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuanu-ai/agentbrowse",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "description": "Standalone browser automation CLI for AI agents: launch, observe, act, extract, and solve captcha",
6
6
  "keywords": [