@hasna/browser 0.2.5 → 0.2.6

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/cli/index.js CHANGED
@@ -12953,6 +12953,9 @@ async function runScript(script, page, overrides = {}, jobId) {
12953
12953
  case "extract":
12954
12954
  runExtractStep(step, vars);
12955
12955
  break;
12956
+ case "ai":
12957
+ await runAIStep(step, vars);
12958
+ break;
12956
12959
  case "wait":
12957
12960
  await new Promise((r) => setTimeout(r, (step.seconds ?? 3) * 1000));
12958
12961
  break;
@@ -13079,7 +13082,7 @@ async function runConnectorStep(step, vars) {
13079
13082
  if (!connectorName)
13080
13083
  throw new Error("Connector step missing connector name");
13081
13084
  const args = (step.args ?? []).map((a) => interpolate(a, vars));
13082
- let result;
13085
+ let stdout = "";
13083
13086
  try {
13084
13087
  const bin = `connect-${connectorName}`;
13085
13088
  const proc = Bun.spawn([bin, ...args], {
@@ -13087,18 +13090,20 @@ async function runConnectorStep(step, vars) {
13087
13090
  stderr: "pipe",
13088
13091
  env: { ...process.env, HOME: process.env.HOME ?? "" }
13089
13092
  });
13090
- const stdout = await new Response(proc.stdout).text();
13093
+ stdout = await new Response(proc.stdout).text();
13091
13094
  const stderr = await new Response(proc.stderr).text();
13092
13095
  const exitCode = await proc.exited;
13093
- result = { stdout, stderr, exitCode, success: exitCode === 0 };
13096
+ vars["last_success"] = String(exitCode === 0);
13097
+ vars["last_exit_code"] = String(exitCode);
13098
+ if (exitCode !== 0 && stderr)
13099
+ stdout = stderr;
13094
13100
  } catch (e) {
13095
- result = { stdout: "", stderr: e.message ?? String(e), exitCode: 1, success: false };
13101
+ vars["last_success"] = "false";
13102
+ throw new Error(`Connector ${connectorName} failed: ${e.message ?? String(e)}`);
13096
13103
  }
13097
- vars["last_output"] = result.stdout;
13098
- vars["last_success"] = String(result.success);
13099
- vars["last_exit_code"] = String(result.exitCode);
13104
+ vars["last_output"] = stdout;
13100
13105
  try {
13101
- const parsed = JSON.parse(result.stdout);
13106
+ const parsed = JSON.parse(stdout);
13102
13107
  if (typeof parsed === "object" && parsed !== null) {
13103
13108
  for (const [k, v] of Object.entries(parsed)) {
13104
13109
  if (typeof v === "string" || typeof v === "number") {
@@ -13108,7 +13113,64 @@ async function runConnectorStep(step, vars) {
13108
13113
  }
13109
13114
  } catch {}
13110
13115
  if (step.save_as) {
13111
- vars[step.save_as] = result.stdout;
13116
+ vars[step.save_as] = stdout;
13117
+ }
13118
+ }
13119
+ function getAIProvider(provider) {
13120
+ if (provider === "anthropic") {
13121
+ const apiKey2 = process.env["ANTHROPIC_API_KEY"];
13122
+ if (!apiKey2)
13123
+ throw new Error("ANTHROPIC_API_KEY not set");
13124
+ return {
13125
+ url: "https://api.anthropic.com/v1/messages",
13126
+ headers: { "content-type": "application/json", "x-api-key": apiKey2, "anthropic-version": "2023-06-01" },
13127
+ body: (model, prompt) => ({ model, max_tokens: 1024, messages: [{ role: "user", content: prompt }] }),
13128
+ extract: (data) => data.content?.[0]?.text ?? ""
13129
+ };
13130
+ }
13131
+ const apiKey = process.env["CEREBRAS_API_KEY"];
13132
+ if (!apiKey)
13133
+ throw new Error("CEREBRAS_API_KEY not set \u2014 required for AI steps (set CEREBRAS_API_KEY or use provider: 'anthropic')");
13134
+ return {
13135
+ url: "https://api.cerebras.ai/v1/chat/completions",
13136
+ headers: { "content-type": "application/json", Authorization: `Bearer ${apiKey}` },
13137
+ body: (model, prompt) => ({ model, max_tokens: 1024, messages: [{ role: "user", content: prompt }] }),
13138
+ extract: (data) => data.choices?.[0]?.message?.content ?? ""
13139
+ };
13140
+ }
13141
+ async function runAIStep(step, vars) {
13142
+ const prompt = interpolate(step.prompt ?? "", vars);
13143
+ if (!prompt)
13144
+ throw new Error("AI step missing prompt");
13145
+ const modelAlias = step.model ?? "fast";
13146
+ const resolved = MODEL_MAP[modelAlias] ?? { provider: "cerebras", model: modelAlias };
13147
+ const saveTo = step.save_as ?? "ai_response";
13148
+ const provider = getAIProvider(resolved.provider);
13149
+ const response = await fetch(provider.url, {
13150
+ method: "POST",
13151
+ headers: provider.headers,
13152
+ body: JSON.stringify(provider.body(resolved.model, prompt))
13153
+ });
13154
+ if (!response.ok) {
13155
+ const errBody = await response.text();
13156
+ throw new Error(`AI API error (${response.status}): ${errBody.slice(0, 200)}`);
13157
+ }
13158
+ const data = await response.json();
13159
+ const text = provider.extract(data);
13160
+ vars[saveTo] = text;
13161
+ vars["last_output"] = text;
13162
+ if (step.response_format === "json") {
13163
+ try {
13164
+ const jsonStr = text.replace(/```json?\n?/g, "").replace(/```/g, "").trim();
13165
+ const parsed = JSON.parse(jsonStr);
13166
+ if (typeof parsed === "object" && parsed !== null) {
13167
+ for (const [k, v] of Object.entries(parsed)) {
13168
+ if (typeof v === "string" || typeof v === "number") {
13169
+ vars[`${saveTo}.${k}`] = String(v);
13170
+ }
13171
+ }
13172
+ }
13173
+ } catch {}
13112
13174
  }
13113
13175
  }
13114
13176
  function decodeHtmlEntities(str) {
@@ -13160,10 +13222,18 @@ function createScriptFromFile(filePath) {
13160
13222
  throw new Error(`File not found: ${filePath}`);
13161
13223
  return createScriptFromJSON(readFileSync3(filePath, "utf8"));
13162
13224
  }
13163
- var activeJobs;
13225
+ var activeJobs, MODEL_MAP;
13164
13226
  var init_login_scripts = __esm(() => {
13165
13227
  init_schema();
13166
13228
  activeJobs = new Map;
13229
+ MODEL_MAP = {
13230
+ fast: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
13231
+ scout: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
13232
+ maverick: { provider: "cerebras", model: "llama-4-maverick-17b-128e-instruct" },
13233
+ haiku: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
13234
+ sonnet: { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
13235
+ opus: { provider: "anthropic", model: "claude-opus-4-6" }
13236
+ };
13167
13237
  });
13168
13238
 
13169
13239
  // src/lib/daemon-client.ts
@@ -5,7 +5,7 @@
5
5
  * Usage: save a script once, replay with `browser login-script <name>`
6
6
  */
7
7
  import type { Page } from "playwright";
8
- export type StepType = "browser" | "connector" | "extract" | "wait" | "condition" | "save_state";
8
+ export type StepType = "browser" | "connector" | "extract" | "wait" | "condition" | "save_state" | "ai";
9
9
  export interface ScriptStep {
10
10
  type: StepType;
11
11
  description?: string;
@@ -16,11 +16,15 @@ export interface ScriptStep {
16
16
  value?: string;
17
17
  timeout?: number;
18
18
  connector?: string;
19
+ operation?: string;
19
20
  args?: string[];
20
21
  format?: string;
21
22
  pattern?: string;
22
23
  json_path?: string;
23
24
  save_as?: string;
25
+ prompt?: string;
26
+ model?: string;
27
+ response_format?: "text" | "json";
24
28
  seconds?: number;
25
29
  check?: string;
26
30
  equals?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/login-scripts.ts"],"names":[],"mappings":"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"}
package/dist/mcp/index.js CHANGED
@@ -10710,6 +10710,9 @@ async function runScript(script, page, overrides = {}, jobId) {
10710
10710
  case "extract":
10711
10711
  runExtractStep(step, vars);
10712
10712
  break;
10713
+ case "ai":
10714
+ await runAIStep(step, vars);
10715
+ break;
10713
10716
  case "wait":
10714
10717
  await new Promise((r) => setTimeout(r, (step.seconds ?? 3) * 1000));
10715
10718
  break;
@@ -10836,7 +10839,7 @@ async function runConnectorStep(step, vars) {
10836
10839
  if (!connectorName)
10837
10840
  throw new Error("Connector step missing connector name");
10838
10841
  const args = (step.args ?? []).map((a) => interpolate(a, vars));
10839
- let result;
10842
+ let stdout = "";
10840
10843
  try {
10841
10844
  const bin = `connect-${connectorName}`;
10842
10845
  const proc = Bun.spawn([bin, ...args], {
@@ -10844,18 +10847,20 @@ async function runConnectorStep(step, vars) {
10844
10847
  stderr: "pipe",
10845
10848
  env: { ...process.env, HOME: process.env.HOME ?? "" }
10846
10849
  });
10847
- const stdout = await new Response(proc.stdout).text();
10850
+ stdout = await new Response(proc.stdout).text();
10848
10851
  const stderr = await new Response(proc.stderr).text();
10849
10852
  const exitCode = await proc.exited;
10850
- result = { stdout, stderr, exitCode, success: exitCode === 0 };
10853
+ vars["last_success"] = String(exitCode === 0);
10854
+ vars["last_exit_code"] = String(exitCode);
10855
+ if (exitCode !== 0 && stderr)
10856
+ stdout = stderr;
10851
10857
  } catch (e) {
10852
- result = { stdout: "", stderr: e.message ?? String(e), exitCode: 1, success: false };
10858
+ vars["last_success"] = "false";
10859
+ throw new Error(`Connector ${connectorName} failed: ${e.message ?? String(e)}`);
10853
10860
  }
10854
- vars["last_output"] = result.stdout;
10855
- vars["last_success"] = String(result.success);
10856
- vars["last_exit_code"] = String(result.exitCode);
10861
+ vars["last_output"] = stdout;
10857
10862
  try {
10858
- const parsed = JSON.parse(result.stdout);
10863
+ const parsed = JSON.parse(stdout);
10859
10864
  if (typeof parsed === "object" && parsed !== null) {
10860
10865
  for (const [k, v] of Object.entries(parsed)) {
10861
10866
  if (typeof v === "string" || typeof v === "number") {
@@ -10865,7 +10870,64 @@ async function runConnectorStep(step, vars) {
10865
10870
  }
10866
10871
  } catch {}
10867
10872
  if (step.save_as) {
10868
- vars[step.save_as] = result.stdout;
10873
+ vars[step.save_as] = stdout;
10874
+ }
10875
+ }
10876
+ function getAIProvider(provider) {
10877
+ if (provider === "anthropic") {
10878
+ const apiKey2 = process.env["ANTHROPIC_API_KEY"];
10879
+ if (!apiKey2)
10880
+ throw new Error("ANTHROPIC_API_KEY not set");
10881
+ return {
10882
+ url: "https://api.anthropic.com/v1/messages",
10883
+ headers: { "content-type": "application/json", "x-api-key": apiKey2, "anthropic-version": "2023-06-01" },
10884
+ body: (model, prompt) => ({ model, max_tokens: 1024, messages: [{ role: "user", content: prompt }] }),
10885
+ extract: (data) => data.content?.[0]?.text ?? ""
10886
+ };
10887
+ }
10888
+ const apiKey = process.env["CEREBRAS_API_KEY"];
10889
+ if (!apiKey)
10890
+ throw new Error("CEREBRAS_API_KEY not set \u2014 required for AI steps (set CEREBRAS_API_KEY or use provider: 'anthropic')");
10891
+ return {
10892
+ url: "https://api.cerebras.ai/v1/chat/completions",
10893
+ headers: { "content-type": "application/json", Authorization: `Bearer ${apiKey}` },
10894
+ body: (model, prompt) => ({ model, max_tokens: 1024, messages: [{ role: "user", content: prompt }] }),
10895
+ extract: (data) => data.choices?.[0]?.message?.content ?? ""
10896
+ };
10897
+ }
10898
+ async function runAIStep(step, vars) {
10899
+ const prompt = interpolate(step.prompt ?? "", vars);
10900
+ if (!prompt)
10901
+ throw new Error("AI step missing prompt");
10902
+ const modelAlias = step.model ?? "fast";
10903
+ const resolved = MODEL_MAP[modelAlias] ?? { provider: "cerebras", model: modelAlias };
10904
+ const saveTo = step.save_as ?? "ai_response";
10905
+ const provider = getAIProvider(resolved.provider);
10906
+ const response = await fetch(provider.url, {
10907
+ method: "POST",
10908
+ headers: provider.headers,
10909
+ body: JSON.stringify(provider.body(resolved.model, prompt))
10910
+ });
10911
+ if (!response.ok) {
10912
+ const errBody = await response.text();
10913
+ throw new Error(`AI API error (${response.status}): ${errBody.slice(0, 200)}`);
10914
+ }
10915
+ const data = await response.json();
10916
+ const text = provider.extract(data);
10917
+ vars[saveTo] = text;
10918
+ vars["last_output"] = text;
10919
+ if (step.response_format === "json") {
10920
+ try {
10921
+ const jsonStr = text.replace(/```json?\n?/g, "").replace(/```/g, "").trim();
10922
+ const parsed = JSON.parse(jsonStr);
10923
+ if (typeof parsed === "object" && parsed !== null) {
10924
+ for (const [k, v] of Object.entries(parsed)) {
10925
+ if (typeof v === "string" || typeof v === "number") {
10926
+ vars[`${saveTo}.${k}`] = String(v);
10927
+ }
10928
+ }
10929
+ }
10930
+ } catch {}
10869
10931
  }
10870
10932
  }
10871
10933
  function decodeHtmlEntities(str) {
@@ -10917,10 +10979,18 @@ function createScriptFromFile(filePath) {
10917
10979
  throw new Error(`File not found: ${filePath}`);
10918
10980
  return createScriptFromJSON(readFileSync3(filePath, "utf8"));
10919
10981
  }
10920
- var activeJobs;
10982
+ var activeJobs, MODEL_MAP;
10921
10983
  var init_login_scripts = __esm(() => {
10922
10984
  init_schema();
10923
10985
  activeJobs = new Map;
10986
+ MODEL_MAP = {
10987
+ fast: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
10988
+ scout: { provider: "cerebras", model: "llama-4-scout-17b-16e-instruct" },
10989
+ maverick: { provider: "cerebras", model: "llama-4-maverick-17b-128e-instruct" },
10990
+ haiku: { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
10991
+ sonnet: { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
10992
+ opus: { provider: "anthropic", model: "claude-opus-4-6" }
10993
+ };
10924
10994
  });
10925
10995
 
10926
10996
  // src/lib/api-detector.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/browser",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "General-purpose browser agent toolkit — Playwright, Chrome DevTools Protocol, Lightpanda with auto engine selection. CLI + MCP + REST + SDK.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",