fix(voice-call): wrap guarded api json parse · openclaw/openclaw@79bd018
vincentkoc
·
2026-05-14
·
via Recent Commits to openclaw:main
File tree
extensions/voice-call/src/providers/shared
| Original file line number | Diff line number | Diff line change |
|---|
@@ -50,6 +50,7 @@ Docs: https://docs.openclaw.ai
|
50 | 50 | - Google Meet: report malformed node-host params JSON with plugin-owned errors instead of leaking raw JSON parser failures. |
51 | 51 | - CLI/export-trajectory: report malformed encoded request JSON with a stable CLI error instead of leaking raw parser output. |
52 | 52 | - Twilio voice-call: report malformed successful API JSON responses with provider-owned errors instead of leaking raw parser failures. |
| 53 | +- Voice-call provider APIs: report malformed successful guarded JSON responses with provider-prefixed errors instead of leaking raw parser failures. |
53 | 54 | - Models config/auth: stop inferring provider env-var markers from broad `^[A-Z_][A-Z0-9_]*$` strings, and resolve config-backed provider `apiKey` values only through structured env SecretRefs (`secrets.providers[id]` / `secrets.defaults`), so unrelated env vars cannot accidentally become provider credentials. Thanks @sallyom. |
54 | 55 | - Media fetch: skip allocating and buffering the response body for bodyless media responses (HEAD probes and 204-style empty bodies), avoiding wasted heap on streams that carry no payload. Thanks @shakkernerd. |
55 | 56 | - CLI/onboarding: forward provider-specific auth flags (e.g. `--openai-api-key`) through the onboarding wizard so they reach provider auth methods via `ctx.opts`, letting `--openai-api-key "$OPENAI_API_KEY"` skip the redundant "use existing env var?" prompt in non-interactive harnesses. (#81669) Thanks @sjf. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -103,4 +103,25 @@ describe("guardedJsonApiRequest", () => {
|
103 | 103 | |
104 | 104 | expect(release).toHaveBeenCalledTimes(1); |
105 | 105 | }); |
| 106 | + |
| 107 | +it("throws prefixed errors for malformed json success responses", async () => { |
| 108 | +const release = vi.fn(async () => {}); |
| 109 | +fetchWithSsrFGuardMock.mockResolvedValue({ |
| 110 | +response: new Response("{not json", { status: 200 }), |
| 111 | + release, |
| 112 | +}); |
| 113 | + |
| 114 | +await expect( |
| 115 | +guardedJsonApiRequest({ |
| 116 | +url: "https://api.example.com/v1/calls/4", |
| 117 | +method: "GET", |
| 118 | +headers: {}, |
| 119 | +allowedHostnames: ["api.example.com"], |
| 120 | +auditContext: "voice-call:test", |
| 121 | +errorPrefix: "provider error", |
| 122 | +}), |
| 123 | +).rejects.toThrow("provider error: malformed JSON response"); |
| 124 | + |
| 125 | +expect(release).toHaveBeenCalledTimes(1); |
| 126 | +}); |
106 | 127 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -35,7 +35,14 @@ export async function guardedJsonApiRequest<T = unknown>(
|
35 | 35 | } |
36 | 36 | |
37 | 37 | const text = await response.text(); |
38 | | -return text ? (JSON.parse(text) as T) : (undefined as T); |
| 38 | +if (!text) { |
| 39 | +return undefined as T; |
| 40 | +} |
| 41 | +try { |
| 42 | +return JSON.parse(text) as T; |
| 43 | +} catch { |
| 44 | +throw new Error(`${params.errorPrefix}: malformed JSON response`); |
| 45 | +} |
39 | 46 | } finally { |
40 | 47 | await release(); |
41 | 48 | } |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。