libretto 0.6.7 → 0.6.9

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.
@@ -1,6 +1,6 @@
1
1
  import type { LanguageModel } from "ai";
2
2
 
3
- export type Provider = "google" | "vertex" | "anthropic" | "openai";
3
+ export type Provider = "google" | "vertex" | "anthropic" | "openai" | "openrouter";
4
4
 
5
5
  const GEMINI_API_KEY_ENV_VARS = [
6
6
  "GEMINI_API_KEY",
@@ -19,6 +19,7 @@ const SUPPORTED_PROVIDER_ALIASES = {
19
19
  anthropic: "anthropic",
20
20
  codex: "openai",
21
21
  openai: "openai",
22
+ openrouter: "openrouter",
22
23
  } as const satisfies Record<string, Provider>;
23
24
 
24
25
  function readFirstEnvValue(
@@ -51,7 +52,7 @@ export function parseModel(model: string): {
51
52
 
52
53
  if (!provider) {
53
54
  throw new Error(
54
- `Unsupported provider "${providerInput}". Supported providers: openai/codex, anthropic, google (Gemini API), and vertex.`,
55
+ `Unsupported provider "${providerInput}". Supported providers: openai/codex, anthropic, google (Gemini API), vertex, and openrouter.`,
55
56
  );
56
57
  }
57
58
 
@@ -71,6 +72,8 @@ export function hasProviderCredentials(
71
72
  return Boolean(env.ANTHROPIC_API_KEY?.trim());
72
73
  case "openai":
73
74
  return Boolean(env.OPENAI_API_KEY?.trim());
75
+ case "openrouter":
76
+ return Boolean(env.OPENROUTER_API_KEY?.trim());
74
77
  }
75
78
  }
76
79
 
@@ -86,6 +89,9 @@ export function missingProviderCredentialsMessage(provider: Provider): string {
86
89
  case "openai": {
87
90
  return "OpenAI API key is missing. Set OPENAI_API_KEY.";
88
91
  }
92
+ case "openrouter": {
93
+ return "OpenRouter API key is missing. Set OPENROUTER_API_KEY.";
94
+ }
89
95
  }
90
96
  }
91
97
 
@@ -133,6 +139,18 @@ async function getProviderModel(
133
139
  const openai = createOpenAI({ apiKey });
134
140
  return openai(modelId);
135
141
  }
142
+ case "openrouter": {
143
+ const apiKey = process.env.OPENROUTER_API_KEY?.trim();
144
+ if (!apiKey) {
145
+ throw new Error(missingProviderCredentialsMessage(provider));
146
+ }
147
+ const { createOpenAI } = await import("@ai-sdk/openai");
148
+ const openrouter = createOpenAI({
149
+ apiKey,
150
+ baseURL: "https://openrouter.ai/api/v1",
151
+ });
152
+ return openrouter(modelId);
153
+ }
136
154
  }
137
155
  }
138
156
 
@@ -269,6 +269,16 @@ async function runIntegrationInternal(
269
269
  },
270
270
  });
271
271
 
272
+ // tsx/esbuild injects __name() wrappers when keepNames is true. Playwright
273
+ // serializes callbacks via Function#toString() into the browser context which
274
+ // lacks __name, causing ReferenceError. Inject a no-op polyfill into every page.
275
+ await browserSession.context.addInitScript(() => {
276
+ (globalThis as Record<string, unknown>).__name = (
277
+ target: unknown,
278
+ value: string,
279
+ ) => Object.defineProperty(target as object, "name", { value, configurable: true });
280
+ });
281
+
272
282
  const workflowContext: LibrettoWorkflowContext = {
273
283
  session: args.session,
274
284
  page: browserSession.page,
@@ -58,7 +58,6 @@ export function isObfuscatedClass(cls: string): boolean {
58
58
  if (cls.length > 80) return true;
59
59
  if (/^_?[0-9a-f]{6,}$/i.test(cls)) return true;
60
60
  if (/^[a-z]+_[0-9a-f]{4,}$/i.test(cls)) return true;
61
- if (/^[a-z]{1,2}[0-9]{2,}$/i.test(cls)) return true;
62
61
 
63
62
  const digits = (cls.match(/[0-9]/g) || []).length;
64
63
  const letters = (cls.match(/[a-zA-Z]/g) || []).length;