Skip to content

fix: stop refetching inspector metadata on every poll - #112

Open
HEOJUNFO wants to merge 1 commit into
CopilotKit:mainfrom
HEOJUNFO:fix/stable-copilotkit-headers
Open

HEOJUNFO wants to merge 1 commit into
CopilotKit:mainfrom
HEOJUNFO:fix/stable-copilotkit-headers

Conversation

@HEOJUNFO

@HEOJUNFO HEOJUNFO commented Oct 7, 2026

Copy link
Copy Markdown

Part of #70 (third point: the inspector-metadata 403 polling).

authHeaders() returned a new object on every call, and App passes it to CopilotKitProvider on every render (headers={authHeaders()}). The provider memoizes its headers on that object's identity, so each render ran its setup effect again. That called copilotkit.setHeaders(), and the runtime client then refetched /api/copilotkit/inspector-metadata. App re-renders on its two 3 s polls (/state and the capture poll). With an Intelligence runtime, /info advertises inspectorMetadata: true, so the page sent that request every few seconds, and validateRuntimeScope answered each one with 403.

authHeaders() now returns the same object until setToken() changes the token. The useVoice and setup-telemetry callers spread it into their own headers, so they are unaffected.

The single request on page load still gets a 403, because the server keeps that route closed on purpose (runtime-scope.test.ts). I left the server alone. If you'd rather it answered 204, the SDK treats that as "no metadata" and logs nothing; I can add that here.

Checked locally:

  • A new test, tests/auth-headers.test.ts: the same object is returned until the token changes. It fails on main.

  • npm run check-format, npm run lint, npm run typecheck, npm test (49 files, 303 tests) and npm run build all pass.

  • A throwaway test (not committed) rendered the real CopilotKitProvider 6 times with a mocked runtime that advertises inspector metadata:

    • a fresh headers object on each render sent 9 inspector-metadata requests;
    • authHeaders() sent 1.

    It needs @copilotkit/* inlined in Vitest because of the package's CSS import, which is why it isn't in this PR.

  • I did not run the Docker setup with an Intelligence key, so I haven't watched the network tab in a real browser.

Prepared with AI assistance (Claude Code).

🤖 Generated with Claude Code

authHeaders() built a new object on each call, and App passes it to
CopilotKitProvider on every render. The provider pushes each new headers
object to the runtime client, which refetches /inspector-metadata. App
re-renders on its 3 s polls, so a production page sent that request
(answered 403) every few seconds.

Return the same headers object until the token changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@NathanTarbert NathanTarbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @HEOJUNFO, this is a great find. The trace is exactly right: a new headers object on every render goes through the provider's memo into setHeaders, and each of those refreshes inspector metadata. Keeping one object until the token changes fixes it at the source. In a quick check over 20 seconds, inspector-metadata requests dropped from 13 to 1. Login still swaps in the new headers, since setToken builds a fresh object and App re-renders.

Whether the one remaining 403 should become a 204 seems like a call for the maintainers, so keeping it out of this PR makes sense.

Looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants