@hasna/testers 0.0.35 → 0.0.36
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 +88 -48
- package/dist/index.js +45 -24
- package/dist/lib/ai-client.d.ts +8 -2
- package/dist/lib/ai-client.d.ts.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/crawl-and-generate.d.ts +1 -1
- package/dist/lib/crawl-and-generate.d.ts.map +1 -1
- package/dist/lib/generator.d.ts.map +1 -1
- package/dist/lib/healer.d.ts.map +1 -1
- package/dist/lib/hybrid-runner.d.ts.map +1 -1
- package/dist/lib/judge.d.ts +3 -3
- package/dist/lib/judge.d.ts.map +1 -1
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/session-converter.d.ts.map +1 -1
- package/dist/mcp/index.js +72 -33
- package/dist/server/index.js +46 -25
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -13983,6 +13983,10 @@ function loadConfig() {
|
|
|
13983
13983
|
if (envApiKey) {
|
|
13984
13984
|
config.anthropicApiKey = envApiKey;
|
|
13985
13985
|
}
|
|
13986
|
+
const envSelfHeal = process.env["TESTERS_SELF_HEAL"];
|
|
13987
|
+
if (envSelfHeal !== undefined) {
|
|
13988
|
+
config.selfHeal = ["1", "true", "yes", "on"].includes(envSelfHeal.toLowerCase());
|
|
13989
|
+
}
|
|
13986
13990
|
return config;
|
|
13987
13991
|
}
|
|
13988
13992
|
var CONFIG_DIR3, CONFIG_PATH2;
|
|
@@ -14019,12 +14023,11 @@ Original selector that failed: "${request.failedSelector}"
|
|
|
14019
14023
|
Please identify the correct selector from the screenshot.`;
|
|
14020
14024
|
let rawResponse = "";
|
|
14021
14025
|
try {
|
|
14022
|
-
if (provider
|
|
14023
|
-
const
|
|
14024
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
14026
|
+
if (provider !== "anthropic") {
|
|
14027
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
14025
14028
|
const resp = await callOpenAICompatible({
|
|
14026
|
-
baseUrl,
|
|
14027
|
-
apiKey,
|
|
14029
|
+
baseUrl: compat.baseUrl,
|
|
14030
|
+
apiKey: compat.apiKey,
|
|
14028
14031
|
model,
|
|
14029
14032
|
system: HEAL_SYSTEM,
|
|
14030
14033
|
messages: [{ role: "user", content: userMessage }],
|
|
@@ -14118,9 +14121,11 @@ var init_healer = __esm(() => {
|
|
|
14118
14121
|
var exports_ai_client = {};
|
|
14119
14122
|
__export(exports_ai_client, {
|
|
14120
14123
|
runAgentLoop: () => runAgentLoop,
|
|
14124
|
+
resolveProviderApiKeyForModel: () => resolveProviderApiKeyForModel,
|
|
14121
14125
|
resolveModel: () => resolveModel,
|
|
14122
14126
|
executeTool: () => executeTool,
|
|
14123
14127
|
detectProvider: () => detectProvider,
|
|
14128
|
+
createOpenAICompatibleConfig: () => createOpenAICompatibleConfig,
|
|
14124
14129
|
createClientForModel: () => createClientForModel,
|
|
14125
14130
|
createClient: () => createClient,
|
|
14126
14131
|
callOpenAICompatible: () => callOpenAICompatible,
|
|
@@ -14943,10 +14948,17 @@ function detectProvider(model) {
|
|
|
14943
14948
|
return "openai";
|
|
14944
14949
|
if (model.startsWith("gemini-"))
|
|
14945
14950
|
return "google";
|
|
14951
|
+
if (model.startsWith("glm-") || model.startsWith("zai/") || model.startsWith("zai-"))
|
|
14952
|
+
return "zai";
|
|
14946
14953
|
if (model.startsWith("llama-") || model.startsWith("qwen-") || model.includes("cerebras"))
|
|
14947
14954
|
return "cerebras";
|
|
14948
14955
|
return "anthropic";
|
|
14949
14956
|
}
|
|
14957
|
+
function resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
14958
|
+
if (explicitApiKey)
|
|
14959
|
+
return explicitApiKey;
|
|
14960
|
+
return detectProvider(model) === "anthropic" ? configuredAnthropicApiKey : undefined;
|
|
14961
|
+
}
|
|
14950
14962
|
function createClient(apiKey) {
|
|
14951
14963
|
const key = apiKey ?? process.env["ANTHROPIC_API_KEY"];
|
|
14952
14964
|
if (!key) {
|
|
@@ -15024,26 +15036,34 @@ async function callOpenAICompatible(options) {
|
|
|
15024
15036
|
const usage = { input_tokens: data.usage?.prompt_tokens ?? 0, output_tokens: data.usage?.completion_tokens ?? 0 };
|
|
15025
15037
|
return { content, stop_reason: stopReason, usage };
|
|
15026
15038
|
}
|
|
15027
|
-
function
|
|
15028
|
-
const provider = detectProvider(model);
|
|
15039
|
+
function createOpenAICompatibleConfig(provider, apiKey) {
|
|
15029
15040
|
if (provider === "openai") {
|
|
15030
|
-
const
|
|
15031
|
-
if (!
|
|
15041
|
+
const key2 = apiKey ?? process.env["OPENAI_API_KEY"];
|
|
15042
|
+
if (!key2)
|
|
15032
15043
|
throw new AIClientError("No OpenAI API key. Set OPENAI_API_KEY or pass it explicitly.");
|
|
15033
|
-
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey:
|
|
15044
|
+
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
|
|
15034
15045
|
}
|
|
15035
15046
|
if (provider === "google") {
|
|
15036
|
-
const
|
|
15037
|
-
if (!
|
|
15047
|
+
const key2 = apiKey ?? process.env["GOOGLE_API_KEY"];
|
|
15048
|
+
if (!key2)
|
|
15038
15049
|
throw new AIClientError("No Google API key. Set GOOGLE_API_KEY or pass it explicitly.");
|
|
15039
|
-
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey:
|
|
15050
|
+
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
|
|
15040
15051
|
}
|
|
15041
15052
|
if (provider === "cerebras") {
|
|
15042
|
-
const
|
|
15043
|
-
if (!
|
|
15053
|
+
const key2 = apiKey ?? process.env["CEREBRAS_API_KEY"];
|
|
15054
|
+
if (!key2)
|
|
15044
15055
|
throw new AIClientError("No Cerebras API key. Set CEREBRAS_API_KEY or pass it explicitly.");
|
|
15045
|
-
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey:
|
|
15056
|
+
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey: key2 };
|
|
15046
15057
|
}
|
|
15058
|
+
const key = apiKey ?? process.env["ZAI_API_KEY"];
|
|
15059
|
+
if (!key)
|
|
15060
|
+
throw new AIClientError("No Z.AI API key. Set ZAI_API_KEY or pass it explicitly.");
|
|
15061
|
+
return { provider: "zai", baseUrl: "https://api.z.ai/api/paas/v4", apiKey: key };
|
|
15062
|
+
}
|
|
15063
|
+
function createClientForModel(model, apiKey) {
|
|
15064
|
+
const provider = detectProvider(model);
|
|
15065
|
+
if (provider !== "anthropic")
|
|
15066
|
+
return createOpenAICompatibleConfig(provider, apiKey);
|
|
15047
15067
|
return createClient(apiKey);
|
|
15048
15068
|
}
|
|
15049
15069
|
var activeHARs, activeCoverage, BROWSER_TOOLS;
|
|
@@ -15620,22 +15640,22 @@ function resolveJudgeModel(config) {
|
|
|
15620
15640
|
apiKey = process.env["GOOGLE_API_KEY"];
|
|
15621
15641
|
else if (provider === "cerebras")
|
|
15622
15642
|
apiKey = process.env["CEREBRAS_API_KEY"];
|
|
15643
|
+
else if (provider === "zai")
|
|
15644
|
+
apiKey = process.env["ZAI_API_KEY"];
|
|
15623
15645
|
}
|
|
15624
15646
|
if (!apiKey) {
|
|
15625
|
-
|
|
15626
|
-
if (!apiKey)
|
|
15627
|
-
throw new AIClientError("No API key found for judge. Set ANTHROPIC_API_KEY, CEREBRAS_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY.");
|
|
15647
|
+
throw new AIClientError(`No API key found for ${provider} judge provider.`);
|
|
15628
15648
|
}
|
|
15629
15649
|
return { model, provider, apiKey };
|
|
15630
15650
|
}
|
|
15631
15651
|
async function callJudge(prompt, config) {
|
|
15632
15652
|
const { model, provider, apiKey } = resolveJudgeModel(config);
|
|
15633
15653
|
const threshold = 0.7;
|
|
15634
|
-
if (provider
|
|
15635
|
-
const
|
|
15654
|
+
if (provider !== "anthropic") {
|
|
15655
|
+
const compat = createOpenAICompatibleConfig(provider, apiKey);
|
|
15636
15656
|
const resp2 = await callOpenAICompatible({
|
|
15637
|
-
baseUrl,
|
|
15638
|
-
apiKey,
|
|
15657
|
+
baseUrl: compat.baseUrl,
|
|
15658
|
+
apiKey: compat.apiKey,
|
|
15639
15659
|
model,
|
|
15640
15660
|
system: LLM_SYSTEM,
|
|
15641
15661
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -18117,6 +18137,7 @@ __export(exports_runner, {
|
|
|
18117
18137
|
runByFilter: () => runByFilter,
|
|
18118
18138
|
runBatch: () => runBatch,
|
|
18119
18139
|
resolveScenariosForRun: () => resolveScenariosForRun,
|
|
18140
|
+
resolveAgentApiKeyForModel: () => resolveAgentApiKeyForModel,
|
|
18120
18141
|
onRunEvent: () => onRunEvent,
|
|
18121
18142
|
applyStructuredAssertionsToResult: () => applyStructuredAssertionsToResult
|
|
18122
18143
|
});
|
|
@@ -18130,6 +18151,9 @@ function emit(event) {
|
|
|
18130
18151
|
if (eventHandler)
|
|
18131
18152
|
eventHandler(event);
|
|
18132
18153
|
}
|
|
18154
|
+
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
18155
|
+
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
18156
|
+
}
|
|
18133
18157
|
function assertionDescription(result) {
|
|
18134
18158
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
18135
18159
|
}
|
|
@@ -18238,7 +18262,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
18238
18262
|
});
|
|
18239
18263
|
}
|
|
18240
18264
|
}
|
|
18241
|
-
const client = createClientForModel(model, effectiveOptions.apiKey
|
|
18265
|
+
const client = createClientForModel(model, resolveAgentApiKeyForModel(model, effectiveOptions.apiKey, config.anthropicApiKey));
|
|
18242
18266
|
const screenshotter = new Screenshotter({
|
|
18243
18267
|
baseDir: effectiveOptions.screenshotDir ?? config.screenshots.dir
|
|
18244
18268
|
});
|
|
@@ -26313,12 +26337,28 @@ Rules:
|
|
|
26313
26337
|
];
|
|
26314
26338
|
const messages = [{ role: "user", content: contentParts }];
|
|
26315
26339
|
try {
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26340
|
+
let text;
|
|
26341
|
+
const provider = detectProvider(model);
|
|
26342
|
+
if (provider !== "anthropic") {
|
|
26343
|
+
const compat = client;
|
|
26344
|
+
const response = await callOpenAICompatible({
|
|
26345
|
+
baseUrl: compat.baseUrl,
|
|
26346
|
+
apiKey: compat.apiKey,
|
|
26347
|
+
model,
|
|
26348
|
+
system: "You are a QA engineer.",
|
|
26349
|
+
messages: [{ role: "user", content: prompt }],
|
|
26350
|
+
tools: [],
|
|
26351
|
+
maxTokens: 2048
|
|
26352
|
+
});
|
|
26353
|
+
text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
26354
|
+
} else {
|
|
26355
|
+
const response = await anthropicClient.messages.create({
|
|
26356
|
+
model,
|
|
26357
|
+
max_tokens: 2048,
|
|
26358
|
+
messages
|
|
26359
|
+
});
|
|
26360
|
+
text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
26361
|
+
}
|
|
26322
26362
|
const match = text.match(/\[[\s\S]*\]/);
|
|
26323
26363
|
if (!match)
|
|
26324
26364
|
return [];
|
|
@@ -26346,7 +26386,7 @@ async function crawlAndGenerate(options) {
|
|
|
26346
26386
|
} = options;
|
|
26347
26387
|
const config = loadConfig();
|
|
26348
26388
|
const model = resolveModel(options.model ?? config.defaultModel ?? "thorough");
|
|
26349
|
-
const client =
|
|
26389
|
+
const client = createClientForModel(model, resolveProviderApiKeyForModel(model, options.apiKey, config.anthropicApiKey));
|
|
26350
26390
|
const rootOrigin = new URL(url).origin;
|
|
26351
26391
|
const visited = new Set;
|
|
26352
26392
|
const queue = [url];
|
|
@@ -26426,7 +26466,6 @@ var init_crawl_and_generate = __esm(() => {
|
|
|
26426
26466
|
init_scenarios();
|
|
26427
26467
|
init_ai_client();
|
|
26428
26468
|
init_config2();
|
|
26429
|
-
init_ai_client();
|
|
26430
26469
|
DEFAULT_SKIP_PATTERNS = [
|
|
26431
26470
|
"/logout",
|
|
26432
26471
|
"/sign-out",
|
|
@@ -57815,12 +57854,11 @@ APP STRUCTURE:
|
|
|
57815
57854
|
${summary}`;
|
|
57816
57855
|
let rawText = "";
|
|
57817
57856
|
let tokensUsed = 0;
|
|
57818
|
-
if (provider
|
|
57819
|
-
const
|
|
57820
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
57857
|
+
if (provider !== "anthropic") {
|
|
57858
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
57821
57859
|
const resp = await callOpenAICompatible({
|
|
57822
|
-
baseUrl,
|
|
57823
|
-
apiKey,
|
|
57860
|
+
baseUrl: compat.baseUrl,
|
|
57861
|
+
apiKey: compat.apiKey,
|
|
57824
57862
|
model,
|
|
57825
57863
|
system: GENERATOR_SYSTEM,
|
|
57826
57864
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -93415,9 +93453,9 @@ async function convertSessionToScenario(events, options) {
|
|
|
93415
93453
|
const name21 = options?.name ?? `Recorded session ${new Date().toISOString().slice(0, 10)}`;
|
|
93416
93454
|
const targetPath = extractTargetPath(events);
|
|
93417
93455
|
let steps;
|
|
93418
|
-
if (options?.model && (process.env["ANTHROPIC_API_KEY"] || process.env["OPENAI_API_KEY"] || process.env["GOOGLE_API_KEY"])) {
|
|
93456
|
+
if (options?.model && (process.env["ANTHROPIC_API_KEY"] || process.env["OPENAI_API_KEY"] || process.env["GOOGLE_API_KEY"] || process.env["CEREBRAS_API_KEY"] || process.env["ZAI_API_KEY"])) {
|
|
93419
93457
|
try {
|
|
93420
|
-
const { callOpenAICompatible: callOpenAICompatible2, detectProvider: detectProvider2 } = await Promise.resolve().then(() => (init_ai_client(), exports_ai_client));
|
|
93458
|
+
const { callOpenAICompatible: callOpenAICompatible2, createOpenAICompatibleConfig: createOpenAICompatibleConfig2, detectProvider: detectProvider2 } = await Promise.resolve().then(() => (init_ai_client(), exports_ai_client));
|
|
93421
93459
|
const model = options.model;
|
|
93422
93460
|
const provider = detectProvider2(model);
|
|
93423
93461
|
const condensed = events.filter((e2) => e2.type !== "network").map((e2) => `[${e2.type}] ${e2.url ?? e2.selector ?? e2.value ?? ""}`).slice(0, 100).join(`
|
|
@@ -93427,10 +93465,9 @@ async function convertSessionToScenario(events, options) {
|
|
|
93427
93465
|
Events:
|
|
93428
93466
|
${condensed}`;
|
|
93429
93467
|
let rawText = "";
|
|
93430
|
-
if (provider
|
|
93431
|
-
const
|
|
93432
|
-
const
|
|
93433
|
-
const resp = await callOpenAICompatible2({ baseUrl, apiKey, model, system: "You are a QA engineer.", messages: [{ role: "user", content: prompt }], tools: [], maxTokens: 1024 });
|
|
93468
|
+
if (provider !== "anthropic") {
|
|
93469
|
+
const compat2 = createOpenAICompatibleConfig2(provider);
|
|
93470
|
+
const resp = await callOpenAICompatible2({ baseUrl: compat2.baseUrl, apiKey: compat2.apiKey, model, system: "You are a QA engineer.", messages: [{ role: "user", content: prompt }], tools: [], maxTokens: 1024 });
|
|
93434
93471
|
const block = resp.content.find((b2) => b2.type === "text");
|
|
93435
93472
|
rawText = block?.text ?? "";
|
|
93436
93473
|
} else {
|
|
@@ -93826,7 +93863,7 @@ async function runHybridScenario(scenario, options) {
|
|
|
93826
93863
|
const stepStart = Date.now();
|
|
93827
93864
|
if (step.type === "ai" || step.type === "ai_verify") {
|
|
93828
93865
|
const model = resolveModel(step.model ?? scenario.model ?? config2.defaultModel);
|
|
93829
|
-
const client = createClientForModel(model, options?.apiKey
|
|
93866
|
+
const client = createClientForModel(model, resolveProviderApiKeyForModel(model, options?.apiKey, config2.anthropicApiKey));
|
|
93830
93867
|
const instruction = step.type === "ai_verify" ? `Verify the following assertion about the current page state: "${step.assertion}". Do NOT navigate. Just inspect the page and call report_result with pass or fail.` : step.instruction;
|
|
93831
93868
|
const syntheticScenario = {
|
|
93832
93869
|
id: `hybrid-step-${i2}`,
|
|
@@ -93943,7 +93980,7 @@ import chalk6 from "chalk";
|
|
|
93943
93980
|
// package.json
|
|
93944
93981
|
var package_default = {
|
|
93945
93982
|
name: "@hasna/testers",
|
|
93946
|
-
version: "0.0.
|
|
93983
|
+
version: "0.0.36",
|
|
93947
93984
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
93948
93985
|
type: "module",
|
|
93949
93986
|
main: "dist/index.js",
|
|
@@ -97284,8 +97321,9 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97284
97321
|
const hasOpenAI = Boolean(process.env["OPENAI_API_KEY"]);
|
|
97285
97322
|
const hasGoogle = Boolean(process.env["GOOGLE_API_KEY"]);
|
|
97286
97323
|
const hasCerebras = Boolean(process.env["CEREBRAS_API_KEY"]);
|
|
97287
|
-
|
|
97288
|
-
|
|
97324
|
+
const hasZai = Boolean(process.env["ZAI_API_KEY"]);
|
|
97325
|
+
if (!hasAnthropic && !hasOpenAI && !hasGoogle && !hasCerebras && !hasZai) {
|
|
97326
|
+
logError(chalk6.red("No AI API key found. Set ANTHROPIC_API_KEY (recommended), or OPENAI_API_KEY / GOOGLE_API_KEY / CEREBRAS_API_KEY / ZAI_API_KEY."));
|
|
97289
97327
|
logError(chalk6.red("For GitHub Actions, add ANTHROPIC_API_KEY to your repo secrets and pass it via: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}"));
|
|
97290
97328
|
process.exit(2);
|
|
97291
97329
|
}
|
|
@@ -99813,11 +99851,13 @@ program2.command("doctor").description("Check system setup and configuration").a
|
|
|
99813
99851
|
const openaiKey = !!process.env["OPENAI_API_KEY"];
|
|
99814
99852
|
const googleKey = !!process.env["GOOGLE_API_KEY"];
|
|
99815
99853
|
const cerebrasKey = !!process.env["CEREBRAS_API_KEY"];
|
|
99854
|
+
const zaiKey = !!process.env["ZAI_API_KEY"];
|
|
99816
99855
|
log((anthropicKey ? chalk6.green(" \u2713") : chalk6.red(" \u2717")) + ` Anthropic (ANTHROPIC_API_KEY)${!anthropicKey ? " \u2014 required for default model" : ""}`);
|
|
99817
99856
|
log((openaiKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` OpenAI (OPENAI_API_KEY) \u2014 optional, enables gpt-* models`);
|
|
99818
99857
|
log((googleKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Google Gemini (GOOGLE_API_KEY) \u2014 optional, enables gemini-* models`);
|
|
99819
99858
|
log((cerebrasKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Cerebras (CEREBRAS_API_KEY) \u2014 optional, enables llama-*/qwen-* at ~20x faster inference`);
|
|
99820
|
-
|
|
99859
|
+
log((zaiKey ? chalk6.green(" \u2713") : chalk6.dim(" \u25CB")) + ` Z.AI (ZAI_API_KEY) \u2014 optional, enables glm-* models such as glm-5.1`);
|
|
99860
|
+
if (!anthropicKey && !openaiKey && !googleKey && !cerebrasKey && !zaiKey) {
|
|
99821
99861
|
log(chalk6.red(" \u2717") + " No AI provider API keys found \u2014 at least one is required");
|
|
99822
99862
|
allPassed = false;
|
|
99823
99863
|
}
|
package/dist/index.js
CHANGED
|
@@ -10735,6 +10735,10 @@ function loadConfig() {
|
|
|
10735
10735
|
if (envApiKey) {
|
|
10736
10736
|
config.anthropicApiKey = envApiKey;
|
|
10737
10737
|
}
|
|
10738
|
+
const envSelfHeal = process.env["TESTERS_SELF_HEAL"];
|
|
10739
|
+
if (envSelfHeal !== undefined) {
|
|
10740
|
+
config.selfHeal = ["1", "true", "yes", "on"].includes(envSelfHeal.toLowerCase());
|
|
10741
|
+
}
|
|
10738
10742
|
return config;
|
|
10739
10743
|
}
|
|
10740
10744
|
function resolveModel(nameOrId) {
|
|
@@ -11652,12 +11656,11 @@ Original selector that failed: "${request.failedSelector}"
|
|
|
11652
11656
|
Please identify the correct selector from the screenshot.`;
|
|
11653
11657
|
let rawResponse = "";
|
|
11654
11658
|
try {
|
|
11655
|
-
if (provider
|
|
11656
|
-
const
|
|
11657
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
11659
|
+
if (provider !== "anthropic") {
|
|
11660
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
11658
11661
|
const resp = await callOpenAICompatible({
|
|
11659
|
-
baseUrl,
|
|
11660
|
-
apiKey,
|
|
11662
|
+
baseUrl: compat.baseUrl,
|
|
11663
|
+
apiKey: compat.apiKey,
|
|
11661
11664
|
model,
|
|
11662
11665
|
system: HEAL_SYSTEM,
|
|
11663
11666
|
messages: [{ role: "user", content: userMessage }],
|
|
@@ -12564,10 +12567,17 @@ function detectProvider(model) {
|
|
|
12564
12567
|
return "openai";
|
|
12565
12568
|
if (model.startsWith("gemini-"))
|
|
12566
12569
|
return "google";
|
|
12570
|
+
if (model.startsWith("glm-") || model.startsWith("zai/") || model.startsWith("zai-"))
|
|
12571
|
+
return "zai";
|
|
12567
12572
|
if (model.startsWith("llama-") || model.startsWith("qwen-") || model.includes("cerebras"))
|
|
12568
12573
|
return "cerebras";
|
|
12569
12574
|
return "anthropic";
|
|
12570
12575
|
}
|
|
12576
|
+
function resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
12577
|
+
if (explicitApiKey)
|
|
12578
|
+
return explicitApiKey;
|
|
12579
|
+
return detectProvider(model) === "anthropic" ? configuredAnthropicApiKey : undefined;
|
|
12580
|
+
}
|
|
12571
12581
|
function createClient(apiKey) {
|
|
12572
12582
|
const key = apiKey ?? process.env["ANTHROPIC_API_KEY"];
|
|
12573
12583
|
if (!key) {
|
|
@@ -12645,26 +12655,34 @@ async function callOpenAICompatible(options) {
|
|
|
12645
12655
|
const usage = { input_tokens: data.usage?.prompt_tokens ?? 0, output_tokens: data.usage?.completion_tokens ?? 0 };
|
|
12646
12656
|
return { content, stop_reason: stopReason, usage };
|
|
12647
12657
|
}
|
|
12648
|
-
function
|
|
12649
|
-
const provider = detectProvider(model);
|
|
12658
|
+
function createOpenAICompatibleConfig(provider, apiKey) {
|
|
12650
12659
|
if (provider === "openai") {
|
|
12651
|
-
const
|
|
12652
|
-
if (!
|
|
12660
|
+
const key2 = apiKey ?? process.env["OPENAI_API_KEY"];
|
|
12661
|
+
if (!key2)
|
|
12653
12662
|
throw new AIClientError("No OpenAI API key. Set OPENAI_API_KEY or pass it explicitly.");
|
|
12654
|
-
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey:
|
|
12663
|
+
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
|
|
12655
12664
|
}
|
|
12656
12665
|
if (provider === "google") {
|
|
12657
|
-
const
|
|
12658
|
-
if (!
|
|
12666
|
+
const key2 = apiKey ?? process.env["GOOGLE_API_KEY"];
|
|
12667
|
+
if (!key2)
|
|
12659
12668
|
throw new AIClientError("No Google API key. Set GOOGLE_API_KEY or pass it explicitly.");
|
|
12660
|
-
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey:
|
|
12669
|
+
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
|
|
12661
12670
|
}
|
|
12662
12671
|
if (provider === "cerebras") {
|
|
12663
|
-
const
|
|
12664
|
-
if (!
|
|
12672
|
+
const key2 = apiKey ?? process.env["CEREBRAS_API_KEY"];
|
|
12673
|
+
if (!key2)
|
|
12665
12674
|
throw new AIClientError("No Cerebras API key. Set CEREBRAS_API_KEY or pass it explicitly.");
|
|
12666
|
-
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey:
|
|
12675
|
+
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey: key2 };
|
|
12667
12676
|
}
|
|
12677
|
+
const key = apiKey ?? process.env["ZAI_API_KEY"];
|
|
12678
|
+
if (!key)
|
|
12679
|
+
throw new AIClientError("No Z.AI API key. Set ZAI_API_KEY or pass it explicitly.");
|
|
12680
|
+
return { provider: "zai", baseUrl: "https://api.z.ai/api/paas/v4", apiKey: key };
|
|
12681
|
+
}
|
|
12682
|
+
function createClientForModel(model, apiKey) {
|
|
12683
|
+
const provider = detectProvider(model);
|
|
12684
|
+
if (provider !== "anthropic")
|
|
12685
|
+
return createOpenAICompatibleConfig(provider, apiKey);
|
|
12668
12686
|
return createClient(apiKey);
|
|
12669
12687
|
}
|
|
12670
12688
|
var activeHARs, activeCoverage, BROWSER_TOOLS;
|
|
@@ -14103,11 +14121,11 @@ function resolveJudgeModel(config) {
|
|
|
14103
14121
|
apiKey = process.env["GOOGLE_API_KEY"];
|
|
14104
14122
|
else if (provider === "cerebras")
|
|
14105
14123
|
apiKey = process.env["CEREBRAS_API_KEY"];
|
|
14124
|
+
else if (provider === "zai")
|
|
14125
|
+
apiKey = process.env["ZAI_API_KEY"];
|
|
14106
14126
|
}
|
|
14107
14127
|
if (!apiKey) {
|
|
14108
|
-
|
|
14109
|
-
if (!apiKey)
|
|
14110
|
-
throw new AIClientError("No API key found for judge. Set ANTHROPIC_API_KEY, CEREBRAS_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY.");
|
|
14128
|
+
throw new AIClientError(`No API key found for ${provider} judge provider.`);
|
|
14111
14129
|
}
|
|
14112
14130
|
return { model, provider, apiKey };
|
|
14113
14131
|
}
|
|
@@ -14122,11 +14140,11 @@ reason: 1-2 sentences max`;
|
|
|
14122
14140
|
async function callJudge(prompt, config) {
|
|
14123
14141
|
const { model, provider, apiKey } = resolveJudgeModel(config);
|
|
14124
14142
|
const threshold = 0.7;
|
|
14125
|
-
if (provider
|
|
14126
|
-
const
|
|
14143
|
+
if (provider !== "anthropic") {
|
|
14144
|
+
const compat = createOpenAICompatibleConfig(provider, apiKey);
|
|
14127
14145
|
const resp2 = await callOpenAICompatible({
|
|
14128
|
-
baseUrl,
|
|
14129
|
-
apiKey,
|
|
14146
|
+
baseUrl: compat.baseUrl,
|
|
14147
|
+
apiKey: compat.apiKey,
|
|
14130
14148
|
model,
|
|
14131
14149
|
system: LLM_SYSTEM,
|
|
14132
14150
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -16413,6 +16431,9 @@ function emit(event) {
|
|
|
16413
16431
|
if (eventHandler)
|
|
16414
16432
|
eventHandler(event);
|
|
16415
16433
|
}
|
|
16434
|
+
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
16435
|
+
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
16436
|
+
}
|
|
16416
16437
|
function assertionDescription(result) {
|
|
16417
16438
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
16418
16439
|
}
|
|
@@ -16521,7 +16542,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
16521
16542
|
});
|
|
16522
16543
|
}
|
|
16523
16544
|
}
|
|
16524
|
-
const client = createClientForModel(model, effectiveOptions.apiKey
|
|
16545
|
+
const client = createClientForModel(model, resolveAgentApiKeyForModel(model, effectiveOptions.apiKey, config.anthropicApiKey));
|
|
16525
16546
|
const screenshotter = new Screenshotter({
|
|
16526
16547
|
baseDir: effectiveOptions.screenshotDir ?? config.screenshots.dir
|
|
16527
16548
|
});
|
package/dist/lib/ai-client.d.ts
CHANGED
|
@@ -96,9 +96,13 @@ export declare function runAgentLoop(options: AgentLoopOptions): Promise<AgentLo
|
|
|
96
96
|
* Detects the AI provider from a model name.
|
|
97
97
|
* - "gpt-*" or "o1-*" / "o3-*" → openai
|
|
98
98
|
* - "gemini-*" → google
|
|
99
|
+
* - "glm-*" / "zai/*" / "zai-*" → Z.AI
|
|
100
|
+
* - "llama-*" / "qwen-*" / names containing "cerebras" → Cerebras
|
|
99
101
|
* - everything else → anthropic (default)
|
|
100
102
|
*/
|
|
101
|
-
export
|
|
103
|
+
export type AIProvider = "anthropic" | "openai" | "google" | "cerebras" | "zai";
|
|
104
|
+
export declare function detectProvider(model: string): AIProvider;
|
|
105
|
+
export declare function resolveProviderApiKeyForModel(model: string, explicitApiKey?: string, configuredAnthropicApiKey?: string): string | undefined;
|
|
102
106
|
/**
|
|
103
107
|
* Creates an Anthropic client instance. Uses the provided API key,
|
|
104
108
|
* or falls back to the ANTHROPIC_API_KEY environment variable.
|
|
@@ -128,11 +132,13 @@ export declare function callOpenAICompatible(options: {
|
|
|
128
132
|
* Creates the right client/config for a given model. Returns either an Anthropic
|
|
129
133
|
* client or a config object for the OpenAI-compatible path.
|
|
130
134
|
*/
|
|
135
|
+
export type OpenAICompatProvider = Exclude<AIProvider, "anthropic">;
|
|
131
136
|
export type OpenAICompatConfig = {
|
|
132
|
-
provider:
|
|
137
|
+
provider: OpenAICompatProvider;
|
|
133
138
|
baseUrl: string;
|
|
134
139
|
apiKey: string;
|
|
135
140
|
};
|
|
141
|
+
export declare function createOpenAICompatibleConfig(provider: OpenAICompatProvider, apiKey?: string): OpenAICompatConfig;
|
|
136
142
|
export declare function createClientForModel(model: string, apiKey?: string): Anthropic | OpenAICompatConfig;
|
|
137
143
|
export {};
|
|
138
144
|
//# sourceMappingURL=ai-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/lib/ai-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/lib/ai-client.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAgD/D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKzD;AAID,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,IAAI,EA8gBzC,CAAC;AAIF,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,CAAA;KAAE,CAAC;CACjD;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CA6mB9B;AAID,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE;IACrC,IAAI,EAAE,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,KAAK,IAAI,CAAC;AAEX,UAAU,gBAAgB;IACxB,MAAM,EAAE,SAAS,GAAG,kBAAkB,CAAC;IACvC,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,GAAG,IAAI,CAAC;IACT,IAAI,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,GAAG,KAAK,CAAA;KAAE,CAAC;CACjD;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,KAAK,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC,CAAC;CACJ;AAUD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BrF;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA4N1B;AAID;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,CAAC;AAEhF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAOxD;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,EACvB,yBAAyB,CAAC,EAAE,MAAM,GACjC,MAAM,GAAG,SAAS,CAGpB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAQvD;AAiCD;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC;IACnC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CA8D9H;AAED;;;GAGG;AAIH,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErG,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,oBAAoB,EAC9B,MAAM,CAAC,EAAE,MAAM,GACd,kBAAkB,CAoBpB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CAInG"}
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,mBAAmB,CAAC;AAOpE;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAiBhD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,mBAAmB,CAAC;AAOpE;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAiBhD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,aAAa,CAuD1C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKrD"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Given any URL:
|
|
5
5
|
* 1. Crawls the app with a headless browser to discover pages
|
|
6
6
|
* 2. Visits each page, captures a screenshot + simplified HTML
|
|
7
|
-
* 3. Sends
|
|
7
|
+
* 3. Sends the page context to the configured model to write test scenarios
|
|
8
8
|
* 4. Creates the scenarios in the DB under the given project
|
|
9
9
|
*
|
|
10
10
|
* Works for any web app — no manual setup required.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crawl-and-generate.d.ts","sourceRoot":"","sources":["../../src/lib/crawl-and-generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"crawl-and-generate.d.ts","sourceRoot":"","sources":["../../src/lib/crawl-and-generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA2KD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA0GxG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/lib/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAoB,MAAM,mBAAmB,CAAC;AAI/E,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/lib/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAoB,MAAM,mBAAmB,CAAC;AAI/E,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAyKD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAoD3F"}
|
package/dist/lib/healer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healer.d.ts","sourceRoot":"","sources":["../../src/lib/healer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQvC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,IAAI,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAmBD,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"healer.d.ts","sourceRoot":"","sources":["../../src/lib/healer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQvC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,IAAI,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAmBD,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAyG5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-runner.d.ts","sourceRoot":"","sources":["../../src/lib/hybrid-runner.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"hybrid-runner.d.ts","sourceRoot":"","sources":["../../src/lib/hybrid-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/judge.d.ts
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* Provider resolution order:
|
|
8
8
|
* 1. config.model (explicit) → detectProvider()
|
|
9
9
|
* 2. ANTHROPIC_API_KEY env
|
|
10
|
-
* 3. OPENAI_API_KEY env
|
|
11
|
-
* 4. GOOGLE_API_KEY env
|
|
10
|
+
* 3. OPENAI_API_KEY / GOOGLE_API_KEY / CEREBRAS_API_KEY / ZAI_API_KEY env
|
|
12
11
|
*/
|
|
13
|
-
|
|
12
|
+
import { type AIProvider } from "./ai-client.js";
|
|
13
|
+
export type JudgeProvider = AIProvider | "auto";
|
|
14
14
|
export interface JudgeConfig {
|
|
15
15
|
model?: string;
|
|
16
16
|
provider?: JudgeProvider;
|
package/dist/lib/judge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"judge.d.ts","sourceRoot":"","sources":["../../src/lib/judge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"judge.d.ts","sourceRoot":"","sources":["../../src/lib/judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAIL,KAAK,UAAU,EAEhB,MAAM,gBAAgB,CAAC;AAOxB,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAkID,wBAAsB,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAwCzF;AAID,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAMpG"}
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export interface RunEvent {
|
|
|
46
46
|
}
|
|
47
47
|
export type RunEventHandler = (event: RunEvent) => void;
|
|
48
48
|
export declare function onRunEvent(handler: RunEventHandler): void;
|
|
49
|
+
export declare function resolveAgentApiKeyForModel(model: string, explicitApiKey?: string, configuredAnthropicApiKey?: string): string | undefined;
|
|
49
50
|
type AgentScenarioStatus = Extract<ResultStatus, "passed" | "failed" | "error">;
|
|
50
51
|
export interface StructuredAssertionOutcome {
|
|
51
52
|
status: AgentScenarioStatus;
|
package/dist/lib/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-converter.d.ts","sourceRoot":"","sources":["../../src/lib/session-converter.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,CAqDnE;AAkBD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,EAAE,CAqD5D;AAsDD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,YAAY,EAAE,EACtB,OAAO,CAAC,EAAE;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"session-converter.d.ts","sourceRoot":"","sources":["../../src/lib/session-converter.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,CAqDnE;AAkBD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,EAAE,CAqD5D;AAsDD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,YAAY,EAAE,EACtB,OAAO,CAAC,EAAE;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,iBAAiB,CAAC,CAkE5B;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,iBAAiB,CAAC,CAoC5B;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiBnE"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "@hasna/testers",
|
|
55
|
-
version: "0.0.
|
|
55
|
+
version: "0.0.36",
|
|
56
56
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
57
57
|
type: "module",
|
|
58
58
|
main: "dist/index.js",
|
|
@@ -16600,6 +16600,10 @@ function loadConfig() {
|
|
|
16600
16600
|
if (envApiKey) {
|
|
16601
16601
|
config.anthropicApiKey = envApiKey;
|
|
16602
16602
|
}
|
|
16603
|
+
const envSelfHeal = process.env["TESTERS_SELF_HEAL"];
|
|
16604
|
+
if (envSelfHeal !== undefined) {
|
|
16605
|
+
config.selfHeal = ["1", "true", "yes", "on"].includes(envSelfHeal.toLowerCase());
|
|
16606
|
+
}
|
|
16603
16607
|
return config;
|
|
16604
16608
|
}
|
|
16605
16609
|
function resolveModel(nameOrId) {
|
|
@@ -16642,12 +16646,11 @@ Original selector that failed: "${request.failedSelector}"
|
|
|
16642
16646
|
Please identify the correct selector from the screenshot.`;
|
|
16643
16647
|
let rawResponse = "";
|
|
16644
16648
|
try {
|
|
16645
|
-
if (provider
|
|
16646
|
-
const
|
|
16647
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
16649
|
+
if (provider !== "anthropic") {
|
|
16650
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
16648
16651
|
const resp = await callOpenAICompatible({
|
|
16649
|
-
baseUrl,
|
|
16650
|
-
apiKey,
|
|
16652
|
+
baseUrl: compat.baseUrl,
|
|
16653
|
+
apiKey: compat.apiKey,
|
|
16651
16654
|
model,
|
|
16652
16655
|
system: HEAL_SYSTEM,
|
|
16653
16656
|
messages: [{ role: "user", content: userMessage }],
|
|
@@ -16741,9 +16744,11 @@ var init_healer = __esm(() => {
|
|
|
16741
16744
|
var exports_ai_client = {};
|
|
16742
16745
|
__export(exports_ai_client, {
|
|
16743
16746
|
runAgentLoop: () => runAgentLoop,
|
|
16747
|
+
resolveProviderApiKeyForModel: () => resolveProviderApiKeyForModel,
|
|
16744
16748
|
resolveModel: () => resolveModel2,
|
|
16745
16749
|
executeTool: () => executeTool,
|
|
16746
16750
|
detectProvider: () => detectProvider,
|
|
16751
|
+
createOpenAICompatibleConfig: () => createOpenAICompatibleConfig,
|
|
16747
16752
|
createClientForModel: () => createClientForModel,
|
|
16748
16753
|
createClient: () => createClient,
|
|
16749
16754
|
callOpenAICompatible: () => callOpenAICompatible,
|
|
@@ -17566,10 +17571,17 @@ function detectProvider(model) {
|
|
|
17566
17571
|
return "openai";
|
|
17567
17572
|
if (model.startsWith("gemini-"))
|
|
17568
17573
|
return "google";
|
|
17574
|
+
if (model.startsWith("glm-") || model.startsWith("zai/") || model.startsWith("zai-"))
|
|
17575
|
+
return "zai";
|
|
17569
17576
|
if (model.startsWith("llama-") || model.startsWith("qwen-") || model.includes("cerebras"))
|
|
17570
17577
|
return "cerebras";
|
|
17571
17578
|
return "anthropic";
|
|
17572
17579
|
}
|
|
17580
|
+
function resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
17581
|
+
if (explicitApiKey)
|
|
17582
|
+
return explicitApiKey;
|
|
17583
|
+
return detectProvider(model) === "anthropic" ? configuredAnthropicApiKey : undefined;
|
|
17584
|
+
}
|
|
17573
17585
|
function createClient(apiKey) {
|
|
17574
17586
|
const key = apiKey ?? process.env["ANTHROPIC_API_KEY"];
|
|
17575
17587
|
if (!key) {
|
|
@@ -17647,26 +17659,34 @@ async function callOpenAICompatible(options) {
|
|
|
17647
17659
|
const usage = { input_tokens: data.usage?.prompt_tokens ?? 0, output_tokens: data.usage?.completion_tokens ?? 0 };
|
|
17648
17660
|
return { content, stop_reason: stopReason, usage };
|
|
17649
17661
|
}
|
|
17650
|
-
function
|
|
17651
|
-
const provider = detectProvider(model);
|
|
17662
|
+
function createOpenAICompatibleConfig(provider, apiKey) {
|
|
17652
17663
|
if (provider === "openai") {
|
|
17653
|
-
const
|
|
17654
|
-
if (!
|
|
17664
|
+
const key2 = apiKey ?? process.env["OPENAI_API_KEY"];
|
|
17665
|
+
if (!key2)
|
|
17655
17666
|
throw new AIClientError("No OpenAI API key. Set OPENAI_API_KEY or pass it explicitly.");
|
|
17656
|
-
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey:
|
|
17667
|
+
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
|
|
17657
17668
|
}
|
|
17658
17669
|
if (provider === "google") {
|
|
17659
|
-
const
|
|
17660
|
-
if (!
|
|
17670
|
+
const key2 = apiKey ?? process.env["GOOGLE_API_KEY"];
|
|
17671
|
+
if (!key2)
|
|
17661
17672
|
throw new AIClientError("No Google API key. Set GOOGLE_API_KEY or pass it explicitly.");
|
|
17662
|
-
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey:
|
|
17673
|
+
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
|
|
17663
17674
|
}
|
|
17664
17675
|
if (provider === "cerebras") {
|
|
17665
|
-
const
|
|
17666
|
-
if (!
|
|
17676
|
+
const key2 = apiKey ?? process.env["CEREBRAS_API_KEY"];
|
|
17677
|
+
if (!key2)
|
|
17667
17678
|
throw new AIClientError("No Cerebras API key. Set CEREBRAS_API_KEY or pass it explicitly.");
|
|
17668
|
-
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey:
|
|
17679
|
+
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey: key2 };
|
|
17669
17680
|
}
|
|
17681
|
+
const key = apiKey ?? process.env["ZAI_API_KEY"];
|
|
17682
|
+
if (!key)
|
|
17683
|
+
throw new AIClientError("No Z.AI API key. Set ZAI_API_KEY or pass it explicitly.");
|
|
17684
|
+
return { provider: "zai", baseUrl: "https://api.z.ai/api/paas/v4", apiKey: key };
|
|
17685
|
+
}
|
|
17686
|
+
function createClientForModel(model, apiKey) {
|
|
17687
|
+
const provider = detectProvider(model);
|
|
17688
|
+
if (provider !== "anthropic")
|
|
17689
|
+
return createOpenAICompatibleConfig(provider, apiKey);
|
|
17670
17690
|
return createClient(apiKey);
|
|
17671
17691
|
}
|
|
17672
17692
|
var activeHARs, activeCoverage, BROWSER_TOOLS;
|
|
@@ -18243,22 +18263,22 @@ function resolveJudgeModel(config) {
|
|
|
18243
18263
|
apiKey = process.env["GOOGLE_API_KEY"];
|
|
18244
18264
|
else if (provider === "cerebras")
|
|
18245
18265
|
apiKey = process.env["CEREBRAS_API_KEY"];
|
|
18266
|
+
else if (provider === "zai")
|
|
18267
|
+
apiKey = process.env["ZAI_API_KEY"];
|
|
18246
18268
|
}
|
|
18247
18269
|
if (!apiKey) {
|
|
18248
|
-
|
|
18249
|
-
if (!apiKey)
|
|
18250
|
-
throw new AIClientError("No API key found for judge. Set ANTHROPIC_API_KEY, CEREBRAS_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY.");
|
|
18270
|
+
throw new AIClientError(`No API key found for ${provider} judge provider.`);
|
|
18251
18271
|
}
|
|
18252
18272
|
return { model, provider, apiKey };
|
|
18253
18273
|
}
|
|
18254
18274
|
async function callJudge(prompt, config) {
|
|
18255
18275
|
const { model, provider, apiKey } = resolveJudgeModel(config);
|
|
18256
18276
|
const threshold = 0.7;
|
|
18257
|
-
if (provider
|
|
18258
|
-
const
|
|
18277
|
+
if (provider !== "anthropic") {
|
|
18278
|
+
const compat = createOpenAICompatibleConfig(provider, apiKey);
|
|
18259
18279
|
const resp2 = await callOpenAICompatible({
|
|
18260
|
-
baseUrl,
|
|
18261
|
-
apiKey,
|
|
18280
|
+
baseUrl: compat.baseUrl,
|
|
18281
|
+
apiKey: compat.apiKey,
|
|
18262
18282
|
model,
|
|
18263
18283
|
system: LLM_SYSTEM,
|
|
18264
18284
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -21159,6 +21179,7 @@ __export(exports_runner, {
|
|
|
21159
21179
|
runByFilter: () => runByFilter,
|
|
21160
21180
|
runBatch: () => runBatch,
|
|
21161
21181
|
resolveScenariosForRun: () => resolveScenariosForRun,
|
|
21182
|
+
resolveAgentApiKeyForModel: () => resolveAgentApiKeyForModel,
|
|
21162
21183
|
onRunEvent: () => onRunEvent,
|
|
21163
21184
|
applyStructuredAssertionsToResult: () => applyStructuredAssertionsToResult
|
|
21164
21185
|
});
|
|
@@ -21172,6 +21193,9 @@ function emit(event) {
|
|
|
21172
21193
|
if (eventHandler)
|
|
21173
21194
|
eventHandler(event);
|
|
21174
21195
|
}
|
|
21196
|
+
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
21197
|
+
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
21198
|
+
}
|
|
21175
21199
|
function assertionDescription(result) {
|
|
21176
21200
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
21177
21201
|
}
|
|
@@ -21280,7 +21304,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
21280
21304
|
});
|
|
21281
21305
|
}
|
|
21282
21306
|
}
|
|
21283
|
-
const client = createClientForModel(model, effectiveOptions.apiKey
|
|
21307
|
+
const client = createClientForModel(model, resolveAgentApiKeyForModel(model, effectiveOptions.apiKey, config.anthropicApiKey));
|
|
21284
21308
|
const screenshotter = new Screenshotter({
|
|
21285
21309
|
baseDir: effectiveOptions.screenshotDir ?? config.screenshots.dir
|
|
21286
21310
|
});
|
|
@@ -85705,12 +85729,28 @@ Rules:
|
|
|
85705
85729
|
];
|
|
85706
85730
|
const messages = [{ role: "user", content: contentParts }];
|
|
85707
85731
|
try {
|
|
85708
|
-
|
|
85709
|
-
|
|
85710
|
-
|
|
85711
|
-
|
|
85712
|
-
|
|
85713
|
-
|
|
85732
|
+
let text2;
|
|
85733
|
+
const provider = detectProvider(model);
|
|
85734
|
+
if (provider !== "anthropic") {
|
|
85735
|
+
const compat2 = client;
|
|
85736
|
+
const response = await callOpenAICompatible({
|
|
85737
|
+
baseUrl: compat2.baseUrl,
|
|
85738
|
+
apiKey: compat2.apiKey,
|
|
85739
|
+
model,
|
|
85740
|
+
system: "You are a QA engineer.",
|
|
85741
|
+
messages: [{ role: "user", content: prompt }],
|
|
85742
|
+
tools: [],
|
|
85743
|
+
maxTokens: 2048
|
|
85744
|
+
});
|
|
85745
|
+
text2 = response.content.filter((b2) => b2.type === "text").map((b2) => b2.text).join("");
|
|
85746
|
+
} else {
|
|
85747
|
+
const response = await anthropicClient.messages.create({
|
|
85748
|
+
model,
|
|
85749
|
+
max_tokens: 2048,
|
|
85750
|
+
messages
|
|
85751
|
+
});
|
|
85752
|
+
text2 = response.content.filter((b2) => b2.type === "text").map((b2) => b2.text).join("");
|
|
85753
|
+
}
|
|
85714
85754
|
const match = text2.match(/\[[\s\S]*\]/);
|
|
85715
85755
|
if (!match)
|
|
85716
85756
|
return [];
|
|
@@ -85738,7 +85778,7 @@ async function crawlAndGenerate(options) {
|
|
|
85738
85778
|
} = options;
|
|
85739
85779
|
const config2 = loadConfig();
|
|
85740
85780
|
const model = resolveModel2(options.model ?? config2.defaultModel ?? "thorough");
|
|
85741
|
-
const client =
|
|
85781
|
+
const client = createClientForModel(model, resolveProviderApiKeyForModel(model, options.apiKey, config2.anthropicApiKey));
|
|
85742
85782
|
const rootOrigin = new URL(url2).origin;
|
|
85743
85783
|
const visited = new Set;
|
|
85744
85784
|
const queue = [url2];
|
|
@@ -85818,7 +85858,6 @@ var init_crawl_and_generate = __esm(() => {
|
|
|
85818
85858
|
init_scenarios();
|
|
85819
85859
|
init_ai_client();
|
|
85820
85860
|
init_config2();
|
|
85821
|
-
init_ai_client();
|
|
85822
85861
|
DEFAULT_SKIP_PATTERNS = [
|
|
85823
85862
|
"/logout",
|
|
85824
85863
|
"/sign-out",
|
package/dist/server/index.js
CHANGED
|
@@ -15319,6 +15319,10 @@ function loadConfig() {
|
|
|
15319
15319
|
if (envApiKey) {
|
|
15320
15320
|
config.anthropicApiKey = envApiKey;
|
|
15321
15321
|
}
|
|
15322
|
+
const envSelfHeal = process.env["TESTERS_SELF_HEAL"];
|
|
15323
|
+
if (envSelfHeal !== undefined) {
|
|
15324
|
+
config.selfHeal = ["1", "true", "yes", "on"].includes(envSelfHeal.toLowerCase());
|
|
15325
|
+
}
|
|
15322
15326
|
return config;
|
|
15323
15327
|
}
|
|
15324
15328
|
var CONFIG_DIR3, CONFIG_PATH2;
|
|
@@ -15355,12 +15359,11 @@ Original selector that failed: "${request.failedSelector}"
|
|
|
15355
15359
|
Please identify the correct selector from the screenshot.`;
|
|
15356
15360
|
let rawResponse = "";
|
|
15357
15361
|
try {
|
|
15358
|
-
if (provider
|
|
15359
|
-
const
|
|
15360
|
-
const apiKey = provider === "openai" ? process.env["OPENAI_API_KEY"] ?? "" : process.env["GOOGLE_API_KEY"] ?? "";
|
|
15362
|
+
if (provider !== "anthropic") {
|
|
15363
|
+
const compat = createOpenAICompatibleConfig(provider);
|
|
15361
15364
|
const resp = await callOpenAICompatible({
|
|
15362
|
-
baseUrl,
|
|
15363
|
-
apiKey,
|
|
15365
|
+
baseUrl: compat.baseUrl,
|
|
15366
|
+
apiKey: compat.apiKey,
|
|
15364
15367
|
model,
|
|
15365
15368
|
system: HEAL_SYSTEM,
|
|
15366
15369
|
messages: [{ role: "user", content: userMessage }],
|
|
@@ -16267,10 +16270,17 @@ function detectProvider(model) {
|
|
|
16267
16270
|
return "openai";
|
|
16268
16271
|
if (model.startsWith("gemini-"))
|
|
16269
16272
|
return "google";
|
|
16273
|
+
if (model.startsWith("glm-") || model.startsWith("zai/") || model.startsWith("zai-"))
|
|
16274
|
+
return "zai";
|
|
16270
16275
|
if (model.startsWith("llama-") || model.startsWith("qwen-") || model.includes("cerebras"))
|
|
16271
16276
|
return "cerebras";
|
|
16272
16277
|
return "anthropic";
|
|
16273
16278
|
}
|
|
16279
|
+
function resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
16280
|
+
if (explicitApiKey)
|
|
16281
|
+
return explicitApiKey;
|
|
16282
|
+
return detectProvider(model) === "anthropic" ? configuredAnthropicApiKey : undefined;
|
|
16283
|
+
}
|
|
16274
16284
|
function createClient(apiKey) {
|
|
16275
16285
|
const key = apiKey ?? process.env["ANTHROPIC_API_KEY"];
|
|
16276
16286
|
if (!key) {
|
|
@@ -16348,26 +16358,34 @@ async function callOpenAICompatible(options) {
|
|
|
16348
16358
|
const usage = { input_tokens: data.usage?.prompt_tokens ?? 0, output_tokens: data.usage?.completion_tokens ?? 0 };
|
|
16349
16359
|
return { content, stop_reason: stopReason, usage };
|
|
16350
16360
|
}
|
|
16351
|
-
function
|
|
16352
|
-
const provider = detectProvider(model);
|
|
16361
|
+
function createOpenAICompatibleConfig(provider, apiKey) {
|
|
16353
16362
|
if (provider === "openai") {
|
|
16354
|
-
const
|
|
16355
|
-
if (!
|
|
16363
|
+
const key2 = apiKey ?? process.env["OPENAI_API_KEY"];
|
|
16364
|
+
if (!key2)
|
|
16356
16365
|
throw new AIClientError("No OpenAI API key. Set OPENAI_API_KEY or pass it explicitly.");
|
|
16357
|
-
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey:
|
|
16366
|
+
return { provider: "openai", baseUrl: "https://api.openai.com/v1", apiKey: key2 };
|
|
16358
16367
|
}
|
|
16359
16368
|
if (provider === "google") {
|
|
16360
|
-
const
|
|
16361
|
-
if (!
|
|
16369
|
+
const key2 = apiKey ?? process.env["GOOGLE_API_KEY"];
|
|
16370
|
+
if (!key2)
|
|
16362
16371
|
throw new AIClientError("No Google API key. Set GOOGLE_API_KEY or pass it explicitly.");
|
|
16363
|
-
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey:
|
|
16372
|
+
return { provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: key2 };
|
|
16364
16373
|
}
|
|
16365
16374
|
if (provider === "cerebras") {
|
|
16366
|
-
const
|
|
16367
|
-
if (!
|
|
16375
|
+
const key2 = apiKey ?? process.env["CEREBRAS_API_KEY"];
|
|
16376
|
+
if (!key2)
|
|
16368
16377
|
throw new AIClientError("No Cerebras API key. Set CEREBRAS_API_KEY or pass it explicitly.");
|
|
16369
|
-
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey:
|
|
16378
|
+
return { provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", apiKey: key2 };
|
|
16370
16379
|
}
|
|
16380
|
+
const key = apiKey ?? process.env["ZAI_API_KEY"];
|
|
16381
|
+
if (!key)
|
|
16382
|
+
throw new AIClientError("No Z.AI API key. Set ZAI_API_KEY or pass it explicitly.");
|
|
16383
|
+
return { provider: "zai", baseUrl: "https://api.z.ai/api/paas/v4", apiKey: key };
|
|
16384
|
+
}
|
|
16385
|
+
function createClientForModel(model, apiKey) {
|
|
16386
|
+
const provider = detectProvider(model);
|
|
16387
|
+
if (provider !== "anthropic")
|
|
16388
|
+
return createOpenAICompatibleConfig(provider, apiKey);
|
|
16371
16389
|
return createClient(apiKey);
|
|
16372
16390
|
}
|
|
16373
16391
|
var activeHARs, activeCoverage, BROWSER_TOOLS;
|
|
@@ -46892,7 +46910,7 @@ import { join as join14 } from "path";
|
|
|
46892
46910
|
// package.json
|
|
46893
46911
|
var package_default = {
|
|
46894
46912
|
name: "@hasna/testers",
|
|
46895
|
-
version: "0.0.
|
|
46913
|
+
version: "0.0.36",
|
|
46896
46914
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
46897
46915
|
type: "module",
|
|
46898
46916
|
main: "dist/index.js",
|
|
@@ -47471,11 +47489,11 @@ function resolveJudgeModel(config) {
|
|
|
47471
47489
|
apiKey = process.env["GOOGLE_API_KEY"];
|
|
47472
47490
|
else if (provider === "cerebras")
|
|
47473
47491
|
apiKey = process.env["CEREBRAS_API_KEY"];
|
|
47492
|
+
else if (provider === "zai")
|
|
47493
|
+
apiKey = process.env["ZAI_API_KEY"];
|
|
47474
47494
|
}
|
|
47475
47495
|
if (!apiKey) {
|
|
47476
|
-
|
|
47477
|
-
if (!apiKey)
|
|
47478
|
-
throw new AIClientError("No API key found for judge. Set ANTHROPIC_API_KEY, CEREBRAS_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY.");
|
|
47496
|
+
throw new AIClientError(`No API key found for ${provider} judge provider.`);
|
|
47479
47497
|
}
|
|
47480
47498
|
return { model, provider, apiKey };
|
|
47481
47499
|
}
|
|
@@ -47490,11 +47508,11 @@ reason: 1-2 sentences max`;
|
|
|
47490
47508
|
async function callJudge(prompt, config) {
|
|
47491
47509
|
const { model, provider, apiKey } = resolveJudgeModel(config);
|
|
47492
47510
|
const threshold = 0.7;
|
|
47493
|
-
if (provider
|
|
47494
|
-
const
|
|
47511
|
+
if (provider !== "anthropic") {
|
|
47512
|
+
const compat = createOpenAICompatibleConfig(provider, apiKey);
|
|
47495
47513
|
const resp2 = await callOpenAICompatible({
|
|
47496
|
-
baseUrl,
|
|
47497
|
-
apiKey,
|
|
47514
|
+
baseUrl: compat.baseUrl,
|
|
47515
|
+
apiKey: compat.apiKey,
|
|
47498
47516
|
model,
|
|
47499
47517
|
system: LLM_SYSTEM,
|
|
47500
47518
|
messages: [{ role: "user", content: prompt }],
|
|
@@ -49382,6 +49400,9 @@ function emit(event) {
|
|
|
49382
49400
|
if (eventHandler)
|
|
49383
49401
|
eventHandler(event);
|
|
49384
49402
|
}
|
|
49403
|
+
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
49404
|
+
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
49405
|
+
}
|
|
49385
49406
|
function assertionDescription(result) {
|
|
49386
49407
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
49387
49408
|
}
|
|
@@ -49490,7 +49511,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
49490
49511
|
});
|
|
49491
49512
|
}
|
|
49492
49513
|
}
|
|
49493
|
-
const client = createClientForModel(model, effectiveOptions.apiKey
|
|
49514
|
+
const client = createClientForModel(model, resolveAgentApiKeyForModel(model, effectiveOptions.apiKey, config.anthropicApiKey));
|
|
49494
49515
|
const screenshotter = new Screenshotter({
|
|
49495
49516
|
baseDir: effectiveOptions.screenshotDir ?? config.screenshots.dir
|
|
49496
49517
|
});
|