惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
人人都是产品经理
人人都是产品经理
V
Visual Studio Blog
Last Week in AI
Last Week in AI
V
V2EX
博客园_首页
IT之家
IT之家
Jina AI
Jina AI
博客园 - 叶小钗
The Cloudflare Blog
T
Tailwind CSS Blog
腾讯CDC
B
Blog
D
Docker
L
LangChain Blog
博客园 - 司徒正美
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: guard xai mock fetch calls · openclaw/openclaw@b3b6928
steipete · 2026-05-12 · via Recent Commits to openclaw:main

@@ -30,9 +30,37 @@ function installXSearchFetch(payload?: Record<string, unknown>) {

3030

return mockFetch;

3131

}

323233+

function firstFetchCall(mockFetch: ReturnType<typeof installXSearchFetch>) {

34+

const [call] = mockFetch.mock.calls;

35+

if (!call) {

36+

throw new Error("expected x_search fetch call");

37+

}

38+

return call;

39+

}

40+41+

function firstFetchUrl(mockFetch: ReturnType<typeof installXSearchFetch>) {

42+

const [url] = firstFetchCall(mockFetch);

43+

return String(url);

44+

}

45+46+

function firstFetchInit(mockFetch: ReturnType<typeof installXSearchFetch>): RequestInit {

47+

const [, init] = firstFetchCall(mockFetch);

48+

if (!init || typeof init !== "object" || Array.isArray(init)) {

49+

throw new Error("expected x_search fetch init");

50+

}

51+

return init as RequestInit;

52+

}

53+54+

function firstAuthorizationHeader(mockFetch: ReturnType<typeof installXSearchFetch>) {

55+

const headers = firstFetchInit(mockFetch).headers;

56+

if (!headers || typeof headers !== "object" || Array.isArray(headers)) {

57+

throw new Error("expected x_search request headers");

58+

}

59+

return (headers as Record<string, string>).Authorization;

60+

}

61+3362

function parseFirstRequestBody(mockFetch: ReturnType<typeof installXSearchFetch>) {

34-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

35-

const requestBody = request?.body;

63+

const requestBody = firstFetchInit(mockFetch).body;

3664

return JSON.parse(typeof requestBody === "string" ? requestBody : "{}") as Record<

3765

string,

3866

unknown

@@ -81,10 +109,7 @@ describe("xai x_search tool", () => {

81109

query: "auth profile search",

82110

});

8311184-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

85-

expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(

86-

"Bearer xai-profile-key",

87-

);

112+

expect(firstAuthorizationHeader(mockFetch)).toBe("Bearer xai-profile-key");

88113

});

8911490115

it("enables x_search when the xAI plugin web search key is configured", () => {

@@ -139,7 +164,7 @@ describe("xai x_search tool", () => {

139164

});

140165141166

expect(mockFetch).toHaveBeenCalled();

142-

expect(String(mockFetch.mock.calls[0]?.[0])).toContain("api.x.ai/v1/responses");

167+

expect(firstFetchUrl(mockFetch)).toContain("api.x.ai/v1/responses");

143168

const body = parseFirstRequestBody(mockFetch);

144169

expect(body.model).toBe("grok-4-1-fast-non-reasoning");

145170

expect(body.max_turns).toBe(2);

@@ -184,7 +209,7 @@ describe("xai x_search tool", () => {

184209

query: "base url route",

185210

});

186211187-

expect(String(mockFetch.mock.calls[0]?.[0])).toBe("https://api.x.ai/xai-search/v1/responses");

212+

expect(firstFetchUrl(mockFetch)).toBe("https://api.x.ai/xai-search/v1/responses");

188213

});

189214190215

it("falls back to Grok web search baseUrl for x_search", async () => {

@@ -208,7 +233,7 @@ describe("xai x_search tool", () => {

208233

query: "legacy base url route",

209234

});

210235211-

expect(String(mockFetch.mock.calls[0]?.[0])).toBe("https://api.x.ai/legacy/v1/responses");

236+

expect(firstFetchUrl(mockFetch)).toBe("https://api.x.ai/legacy/v1/responses");

212237

});

213238214239

it("shares plugin webSearch.baseUrl with x_search when xSearch.baseUrl is unset", async () => {

@@ -237,7 +262,7 @@ describe("xai x_search tool", () => {

237262

query: "shared base url route",

238263

});

239264240-

expect(String(mockFetch.mock.calls[0]?.[0])).toBe("https://api.x.ai/shared/v1/responses");

265+

expect(firstFetchUrl(mockFetch)).toBe("https://api.x.ai/shared/v1/responses");

241266

});

242267243268

it("reuses the xAI plugin web search key for x_search requests", async () => {

@@ -262,10 +287,7 @@ describe("xai x_search tool", () => {

262287

query: "latest post from huntharo",

263288

});

264289265-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

266-

expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(

267-

"Bearer xai-plugin-key",

268-

);

290+

expect(firstAuthorizationHeader(mockFetch)).toBe("Bearer xai-plugin-key");

269291

});

270292271293

it("prefers the active runtime config for shared xAI keys", async () => {

@@ -303,10 +325,7 @@ describe("xai x_search tool", () => {

303325

query: "runtime key search",

304326

});

305327306-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

307-

expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(

308-

"Bearer x-search-runtime-key",

309-

);

328+

expect(firstAuthorizationHeader(mockFetch)).toBe("Bearer x-search-runtime-key");

310329

});

311330312331

it("reuses the legacy grok web search key for x_search requests", async () => {

@@ -329,10 +348,7 @@ describe("xai x_search tool", () => {

329348

query: "latest legacy-key post from huntharo",

330349

});

331350332-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

333-

expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(

334-

"Bearer xai-legacy-key",

335-

);

351+

expect(firstAuthorizationHeader(mockFetch)).toBe("Bearer xai-legacy-key");

336352

});

337353338354

it("uses migrated runtime auth when the source config still carries legacy x_search apiKey", async () => {

@@ -367,10 +383,7 @@ describe("xai x_search tool", () => {

367383

query: "migrated runtime auth",

368384

});

369385370-

const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

371-

expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(

372-

"Bearer migrated-runtime-key",

373-

);

386+

expect(firstAuthorizationHeader(mockFetch)).toBe("Bearer migrated-runtime-key");

374387

});

375388376389

it("rejects invalid date ordering before calling xAI", async () => {