You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Interactions API transport (#1014, epic #1013) ships a workaround that routes the @google/genaiNext-Gen / Interactions client through Obsidian's requestUrl instead of the renderer's global fetch. This is necessary because the Interactions client currently can't be called directly from a browser-like environment (Obsidian's Electron renderer) due to a CORS preflight failure. This issue tracks removing the workaround once the upstream bug is fixed.
Background: why the workaround exists
The Next-Gen client (behind client.interactions.*) adds an Api-Revision request header to every call.
In a browser/renderer, that custom header triggers a CORS preflight (OPTIONS). generativelanguage.googleapis.com does not list api-revision in its Access-Control-Allow-Headers, so the preflight returns 403 with no Access-Control-Allow-Origin and the real request never goes out. The plugin surfaces this as:
[GeminiClient] Error creating interaction: TypeError: Failed to fetch
at ...fetchWithTimeout ... Error: Connection error. at ...makeRequest
models.generateContent is unaffected (it never sets Api-Revision) — which is why the legacy transport works in Obsidian but the Interactions transport did not.
In Node there is no preflight, so the Interactions API works server-side. This is a browser-only bug.
The SDK exposes no public hook to inject a custom fetch into the Next-Gen client, so the workaround patches fetch onto the lazily-constructed client instance via the SDK-internal getNextGenClient().
src/api/providers/gemini/obsidian-fetch.ts — a requestUrl-backed fetch adapter (obsidianFetch) and an idempotent, defensive installer (installObsidianFetch).
src/api/providers/gemini/client.ts — generateViaInteractions() calls installObsidianFetch(this.ai) before each Interactions call.
Tests: test/api/providers/gemini/obsidian-fetch.test.ts, plus the routing assertion in client.test.ts.
How to check whether Google has fixed it
A. Has the SDK dropped the Api-Revision header? Bump @google/genai, then check whether the Next-Gen client still sets it:
B. Has the server added the header to its CORS allowlist? (from #1723) — the preflight should return 200 with Api-Revision echoed:
# Should now return HTTP/2 200 with access-control-allow-origin when api-revision is requested
curl -si -X OPTIONS \
-H 'Origin: http://localhost' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-goog-api-key,api-revision' \
https://generativelanguage.googleapis.com/v1beta/interactions | grep -i '^HTTP/\|access-control-allow'
C. Has the SDK added a public custom-fetch hook? (tracking #999 / #1215) — if GoogleGenAIOptions / httpOptions gains a supported fetch field, we can stop reaching into getNextGenClient() and pass our adapter through the public API instead.
D. End-to-end check in Obsidian: turn off the workaround (or temporarily make installObsidianFetch a no-op), enable Use Interactions API, and send an agent message. If it succeeds without Failed to fetch, the upstream issue is resolved.
What to do once fixed
If A (header removed) or B (server allowlist updated): the renderer fetch works again — the requestUrl routing becomes optional. Decide whether to remove it or keep it as belt-and-suspenders (it's harmless and consistent with the plugin's other network calls; streaming in Interactions API — Phase 2: streaming rewrite (step-based events) #1015 may still benefit from requestUrl for SSE handling — evaluate then).
If C (public fetch hook): replace the getNextGenClient() instance-patch with the supported option to drop the dependency on SDK internals, even if we keep using requestUrl.
Acceptance
Verified upstream status via the checks above and recorded the result here.
Workaround removed or deliberately retained with a documented rationale; obsidian-fetch.ts comment + this issue updated accordingly.
Related: #1013 (epic), #1014 (Phase 1), #1015 (Phase 2 streaming — re-evaluate requestUrl need for SSE).
Summary
The Interactions API transport (#1014, epic #1013) ships a workaround that routes the
@google/genaiNext-Gen / Interactions client through Obsidian'srequestUrlinstead of the renderer's globalfetch. This is necessary because the Interactions client currently can't be called directly from a browser-like environment (Obsidian's Electron renderer) due to a CORS preflight failure. This issue tracks removing the workaround once the upstream bug is fixed.Background: why the workaround exists
client.interactions.*) adds anApi-Revisionrequest header to every call.OPTIONS).generativelanguage.googleapis.comdoes not listapi-revisionin itsAccess-Control-Allow-Headers, so the preflight returns 403 with noAccess-Control-Allow-Originand the real request never goes out. The plugin surfaces this as:models.generateContentis unaffected (it never setsApi-Revision) — which is why the legacy transport works in Obsidian but the Interactions transport did not.fetchinto the Next-Gen client, so the workaround patchesfetchonto the lazily-constructed client instance via the SDK-internalgetNextGenClient().Upstream references:
Api-Revisionrequest header fails CORS preflight googleapis/js-genai#1723 (a Google maintainer proposed simply removing theApi-Revisionheader from the SDK)Current workaround (to be removed/simplified)
src/api/providers/gemini/obsidian-fetch.ts— arequestUrl-backedfetchadapter (obsidianFetch) and an idempotent, defensive installer (installObsidianFetch).src/api/providers/gemini/client.ts—generateViaInteractions()callsinstallObsidianFetch(this.ai)before each Interactions call.test/api/providers/gemini/obsidian-fetch.test.ts, plus the routing assertion inclient.test.ts.How to check whether Google has fixed it
A. Has the SDK dropped the
Api-Revisionheader? Bump@google/genai, then check whether the Next-Gen client still sets it:grep -rn "Api-Revision\|api-revision" node_modules/@google/genai/dist/If gone, the preflight trigger is removed.
B. Has the server added the header to its CORS allowlist? (from #1723) — the preflight should return
200withApi-Revisionechoed:C. Has the SDK added a public custom-fetch hook? (tracking #999 / #1215) — if
GoogleGenAIOptions/httpOptionsgains a supportedfetchfield, we can stop reaching intogetNextGenClient()and pass our adapter through the public API instead.D. End-to-end check in Obsidian: turn off the workaround (or temporarily make
installObsidianFetcha no-op), enable Use Interactions API, and send an agent message. If it succeeds withoutFailed to fetch, the upstream issue is resolved.What to do once fixed
fetchworks again — therequestUrlrouting becomes optional. Decide whether to remove it or keep it as belt-and-suspenders (it's harmless and consistent with the plugin's other network calls; streaming in Interactions API — Phase 2: streaming rewrite (step-based events) #1015 may still benefit fromrequestUrlfor SSE handling — evaluate then).getNextGenClient()instance-patch with the supported option to drop the dependency on SDK internals, even if we keep usingrequestUrl.Acceptance
obsidian-fetch.tscomment + this issue updated accordingly.Related: #1013 (epic), #1014 (Phase 1), #1015 (Phase 2 streaming — re-evaluate
requestUrlneed for SSE).