@testdriverai/mcp 7.11.180-test → 7.11.181-test
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.
|
@@ -6,8 +6,8 @@ const require = createRequire(import.meta.url);
|
|
|
6
6
|
const { createSDK, withRetry } = require("./sdk.js");
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* A team's
|
|
10
|
-
* configured. The API reports that as a 400 carrying
|
|
9
|
+
* A team's Google (Gemini) key can be revoked, run out of quota, or never be
|
|
10
|
+
* configured. The API reports that as a 400 carrying a GOOGLE_* code.
|
|
11
11
|
* Two things have to hold for the user to ever see it: the request layer must
|
|
12
12
|
* not retry it into a two-minute stall, and it must arrive as a real error with
|
|
13
13
|
* `isConfigError` set — that flag is what stops find()/findAll() from folding it
|
|
@@ -21,12 +21,12 @@ const axiosError = (status, data) =>
|
|
|
21
21
|
|
|
22
22
|
const KEY_ERROR_BODY = {
|
|
23
23
|
error:
|
|
24
|
-
"Your team's
|
|
25
|
-
code: "
|
|
26
|
-
details: {
|
|
24
|
+
"Your team's Google API key has no quota remaining — HTTP 429. Check your quota at https://aistudio.google.com/apikey.",
|
|
25
|
+
code: "GOOGLE_KEY_ERROR",
|
|
26
|
+
details: { geminiStatus: 429, source: "testdriver-locate" },
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
describe("
|
|
29
|
+
describe("Google key errors are not retried", () => {
|
|
30
30
|
it("fails a rejected key on the first attempt", async () => {
|
|
31
31
|
let attempts = 0;
|
|
32
32
|
await expect(
|
|
@@ -44,8 +44,8 @@ describe("OpenRouter key errors are not retried", () => {
|
|
|
44
44
|
withRetry(async () => {
|
|
45
45
|
attempts++;
|
|
46
46
|
throw axiosError(400, {
|
|
47
|
-
error: "
|
|
48
|
-
code: "
|
|
47
|
+
error: "Google API key is required for self-hosted plans.",
|
|
48
|
+
code: "GOOGLE_KEY_REQUIRED",
|
|
49
49
|
});
|
|
50
50
|
}),
|
|
51
51
|
).rejects.toThrow();
|
|
@@ -81,7 +81,7 @@ describe("OpenRouter key errors are not retried", () => {
|
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
describe("
|
|
84
|
+
describe("Google key errors reach the caller", () => {
|
|
85
85
|
/** Serve one 400 with the given body, then hand back its origin. */
|
|
86
86
|
const serve = async (body) => {
|
|
87
87
|
const server = http.createServer((req, res) => {
|
|
@@ -112,7 +112,7 @@ describe("OpenRouter key errors reach the caller", () => {
|
|
|
112
112
|
|
|
113
113
|
expect(error).toBeTruthy();
|
|
114
114
|
expect(error.isConfigError).toBe(true);
|
|
115
|
-
expect(error.code).toBe("
|
|
115
|
+
expect(error.code).toBe("GOOGLE_KEY_ERROR");
|
|
116
116
|
expect(error.message).toBe(KEY_ERROR_BODY.error);
|
|
117
117
|
expect(error.details).toEqual(KEY_ERROR_BODY.details);
|
|
118
118
|
|
package/agent/lib/sdk.js
CHANGED
|
@@ -36,6 +36,9 @@ const DEFAULT_RETRY_CONFIG = {
|
|
|
36
36
|
* retrying only delays the message the user needs to read.
|
|
37
37
|
*/
|
|
38
38
|
const CONFIG_ERROR_CODES = [
|
|
39
|
+
"GOOGLE_KEY_ERROR",
|
|
40
|
+
"GOOGLE_KEY_REQUIRED",
|
|
41
|
+
// Kept for backward compatibility with older API deployments.
|
|
39
42
|
"OPENROUTER_KEY_ERROR",
|
|
40
43
|
"OPENROUTER_KEY_REQUIRED",
|
|
41
44
|
];
|
|
@@ -58,7 +61,7 @@ function apiErrorCode(error) {
|
|
|
58
61
|
* @returns {boolean} Whether the request should be retried
|
|
59
62
|
*/
|
|
60
63
|
function isRetryableError(error, config = DEFAULT_RETRY_CONFIG) {
|
|
61
|
-
// A rejected
|
|
64
|
+
// A rejected Google key (or a missing one) is not going to start working
|
|
62
65
|
// on attempt two — surface it now instead of after ten backoffs.
|
|
63
66
|
if (CONFIG_ERROR_CODES.includes(apiErrorCode(error))) {
|
|
64
67
|
return false;
|
|
@@ -607,7 +610,7 @@ const createSDK = (emitter, config, sessionInstance) => {
|
|
|
607
610
|
const status = error.response?.status;
|
|
608
611
|
|
|
609
612
|
// Configuration errors (400 + a known code) — the API rejected the call
|
|
610
|
-
// for a reason the user can fix, most often
|
|
613
|
+
// for a reason the user can fix, most often a Google key that was
|
|
611
614
|
// revoked, ran out of credit, or was never configured. These used to
|
|
612
615
|
// arrive as a bare "Request failed with status code 400" and get folded
|
|
613
616
|
// into "element not found", so the real cause never reached the user.
|
package/docs/self-hosted.mdx
CHANGED
|
@@ -46,6 +46,10 @@ Run test sandboxes on your AWS infrastructure while using TestDriver's hosted da
|
|
|
46
46
|
- **Your AI keys** — control costs with your own OpenAI, Anthropic, or other provider
|
|
47
47
|
- **Custom AMIs** — install specific software, configure networking
|
|
48
48
|
|
|
49
|
+
<Note>
|
|
50
|
+
**Bring your own Gemini API key.** TestDriver uses Google Gemini for vision and reasoning. When supplying your own Gemini key, it must be a [Gemini Enterprise Agent Platform express mode API key](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/start/api-keys?usertype=expressmode) — standard Google AI Studio (Generative Language API) keys are not supported for self-hosted deployments.
|
|
51
|
+
</Note>
|
|
52
|
+
|
|
49
53
|
<Card
|
|
50
54
|
title="AWS Setup Guide"
|
|
51
55
|
icon="aws"
|
package/package.json
CHANGED
package/sdk.js
CHANGED
|
@@ -623,7 +623,7 @@ class Element {
|
|
|
623
623
|
this.sdk.emitter.emit(events.log.log, notFoundMessage);
|
|
624
624
|
}
|
|
625
625
|
} catch (error) {
|
|
626
|
-
// A rejected or missing
|
|
626
|
+
// A rejected or missing Google key breaks every find the same way.
|
|
627
627
|
// Reporting it as "element not found" hides the one thing the user needs
|
|
628
628
|
// to know, so it escapes instead of being folded into the not-found path.
|
|
629
629
|
if (error.isConfigError) {
|
|
@@ -2671,7 +2671,7 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
2671
2671
|
} catch (error) {
|
|
2672
2672
|
const duration = Date.now() - startTime;
|
|
2673
2673
|
|
|
2674
|
-
// A rejected or missing
|
|
2674
|
+
// A rejected or missing Google key isn't "zero elements matched" —
|
|
2675
2675
|
// returning [] here would hide the only thing the user can act on.
|
|
2676
2676
|
if (error.isConfigError) {
|
|
2677
2677
|
this._lastPromiseSettled = true;
|