Repository navigation
BYOK Responses custom endpoints drop conversationId, preventing prompt_cache_key from being sent #332031
Description
Type: Bug
Description
When using a BYOK Custom Endpoint configured to use the OpenAI Responses API, prompt_cache_key is not included in the outgoing request even when github.copilot.chat.responsesApi.promptCacheKey.enabled is enabled.
The Responses API request builder itself supports prompt_cache_key, but the conversationId required to generate it is lost while the request passes through the extension-contributed language model / vscode.lm bridge used by BYOK models.
This appears to be a request-context forwarding gap rather than an issue with the prompt cache setting itself.
Expected behavior
For a normal agent chat request, DefaultToolCallingLoop.fetch() passes the current conversation ID:
return this.options.invocation.endpoint.makeChatRequest2({
...opts,
// ...
conversationId: this.options.conversation.sessionId,
// ...
}, token);The Responses API request builder then uses it when prompt cache keys are enabled:
const promptCacheKeyEnabled = configService.getExperimentBasedConfig(
ConfigKey.ResponsesApiPromptCacheKeyEnabled,
expService
);
if (promptCacheKeyEnabled && options.conversationId) {
body.prompt_cache_key = `${options.conversationId}:${endpoint.family}`;
}Therefore, a BYOK Responses request made from the same chat session should also contain a stable prompt_cache_key.
Actual behavior
For an extension-contributed/BYOK model, the request goes through:
DefaultToolCallingLoop
↓
ExtensionContributedChatEndpoint
↓
vscode.lm / LanguageModelChatProvider
↓
CustomEndpointBYOKModelProvider
↓
CopilotLanguageModelWrapper
↓
OpenAIEndpoint
↓
createResponsesRequestBody
DefaultToolCallingLoop supplies conversationId, but ExtensionContributedChatEndpoint.makeChatRequest2() does not destructure or forward it:
async makeChatRequest2({
debugName,
messages,
ignoreStatefulMarker,
summarizedAtRoundId,
requestOptions,
finishedCb,
location,
source,
telemetryProperties,
modelCapabilities,
}: IMakeChatRequestOptions, token: CancellationToken)The bridge already forwards several pieces of internal request context through modelOptions:
modelOptions: {
_capturingTokenCorrelationId: ourRequestId,
_otelTraceContext: activeTraceCtx ?? null,
...(telemetryTurn !== undefined
? { _telemetryTurn: telemetryTurn }
: {}),
...(modelCapabilities?.enableThinking !== undefined
? { _enableThinking: modelCapabilities.enableThinking }
: {}),
}but it does not forward conversationId.
On the provider side, CopilotLanguageModelWrapper restores these internal values and eventually calls the actual BYOK endpoint:
const makeRequest = () => endpoint.makeChatRequest2({
debugName: 'copilotLanguageModelWrapper',
messages,
finishedCb: callback,
location: ChatLocation.Other,
source: { extensionId },
requestOptions: options,
userInitiatedRequest: !!extensionId,
telemetryProperties,
modelCapabilities: {
enableThinking: internalModelOptions?._enableThinking,
reasoningEffort: typeof _options.modelConfiguration?.reasoningEffort === 'string'
? _options.modelConfiguration.reasoningEffort
: undefined,
},
}, token);At this point conversationId is no longer available, so createResponsesRequestBody() sees:
promptCacheKeyEnabled = true
options.conversationId = undefined
and consequently does not add prompt_cache_key.
The Chat Debug Raw Request confirms this: requests with debugName: "copilotLanguageModelWrapper" do not contain prompt_cache_key.
Reproduction
- Configure a BYOK Custom Endpoint with
"apiType": "responses". - Enable the Responses API prompt cache key setting.
- Start an Agent chat using that custom model.
- Open Chat Debug and inspect the Raw Request for
copilotLanguageModelWrapper. - Observe that the Responses request does not contain
prompt_cache_key.
The same request originates from a DefaultToolCallingLoop where a valid conversation.sessionId exists.
Suggested fix
Forward the conversation ID using the existing internal modelOptions bridge.
For example, extend ExtensionLanguageModelRequestOptions:
export interface ExtensionLanguageModelRequestOptions extends OTelModelOptions {
readonly _enableThinking?: boolean;
readonly _conversationId?: string;
}Then preserve it in ExtensionContributedChatEndpoint.makeChatRequest2():
async makeChatRequest2({
// ...
conversationId,
// ...
}: IMakeChatRequestOptions, token: CancellationToken) {and:
modelOptions: {
_capturingTokenCorrelationId: ourRequestId,
_otelTraceContext: activeTraceCtx ?? null,
_conversationId: conversationId,
// ...
}Finally restore it in CopilotLanguageModelWrapper:
const makeRequest = () => endpoint.makeChatRequest2({
// ...
conversationId: internalModelOptions?._conversationId,
// ...
}, token);This would preserve the existing behavior of:
body.prompt_cache_key = `${options.conversationId}:${endpoint.family}`;for BYOK Responses endpoints as well.
Note about CapturingToken.chatSessionId
The existing _capturingTokenCorrelationId bridge can restore a CapturingToken, which already contains a chatSessionId. It may therefore be possible to derive a cache key from:
capturingToken?.chatSessionIdHowever, explicitly forwarding the original conversationId seems preferable because the two values do not necessarily have identical semantics.
In particular, subagent invocations intentionally use the subagent invocation ID as the CapturingToken.chatSessionId, while conversationId is the conversation identifier used by the request layer.
Tests
extChatEndpoint.spec.ts already tests forwarding of internal request context such as:
_telemetryTurn_enableThinking
A regression test could verify that a supplied conversationId is forwarded through modelOptions.
An end-to-end/unit test covering:
ExtensionContributedChatEndpoint
→ CopilotLanguageModelWrapper
→ OpenAIEndpoint Responses body
could then assert that, when ResponsesApiPromptCacheKeyEnabled is enabled, the resulting request contains the expected prompt_cache_key.
Relevant files
extensions/copilot/src/extension/intents/node/defaultIntentRequestHandler.tsextensions/copilot/src/platform/endpoint/vscode-node/extChatEndpoint.tsextensions/copilot/src/extension/conversation/vscode-node/languageModelAccess.tsextensions/copilot/src/platform/endpoint/node/responsesApi.tsextensions/copilot/src/platform/endpoint/vscode-node/test/extChatEndpoint.spec.ts
VS Code version: Code - Insiders 1.135.0-insider (e1801a0, 2026-08-21T16:58:25Z)
OS version: Windows_NT x64 10.0.26200
Modes:
System Info
| Item | Value |
|---|---|
| CPUs | Intel(R) Core(TM) i7-14700F (28 x 2112) |
| GPU Status | 2d_canvas: enabled GPU0: VENDOR= 0x10de, DEVICE=0x2705 [NVIDIA GeForce RTX 4070 Ti SUPER], DRIVER_VENDOR=NVIDIA, DRIVER_VERSION=32.0.16.1062 ACTIVE GPU1: VENDOR= 0x1414, DEVICE=0x008c [Microsoft Basic Render Driver], DRIVER_VERSION=10.0.26100.8972 Machine model name: Machine model version: direct_rendering_display_compositor: disabled_off_ok gpu_compositing: enabled multiple_raster_threads: enabled_on opengl: enabled_on rasterization: enabled raw_draw: disabled_off_ok skia_graphite: disabled_off trees_in_viz: disabled_off video_decode: enabled video_encode: enabled webgl: enabled webgpu: enabled webnn: disabled_off |
| Load (avg) | undefined |
| Memory (System) | 63.84GB (33.54GB free) |
| Process Argv | --crash-reporter-id 2ec5f96c-c0f3-4a7f-a64c-d65afeffe46b |
| Screen Reader | no |
| VM | 0% |
Extensions (59)
| Name | Identifier | Author | Version |
|---|---|---|---|
| rust | 1yib.rust-bundle | 1YiB | 1.0.0 |
| Unity Shader | ashiqi.unityshader | ashiqi | 1.0.13 |
| Markdown Preview Github Styling | bierner.markdown-preview-github-styles | bierner | 2.2.0 |
| npm Intellisense | christian-kohler.npm-intellisense | christian-kohler | 1.4.5 |
| Path Intellisense | christian-kohler.path-intellisense | christian-kohler | 2.10.0 |
| Codacy | codacy-app.codacy | codacy-app | 1.16.0 |
| CSharpier - Code formatter | csharpier.csharpier-vscode | csharpier | 11.0.0 |
| markdownlint | davidanson.vscode-markdownlint | DavidAnson | 0.62.1 |
| ESLint | dbaeumer.vscode-eslint | dbaeumer | 3.0.34 |
| Rust Syntax | dustypomerleau.rust-syntax | dustypomerleau | 0.6.1 |
| EditorConfig | editorconfig.editorconfig | EditorConfig | 0.18.2 |
| Prettier - Code formatter | esbenp.prettier-vscode | esbenp | 12.4.0 |
| Dependi | fill-labs.dependi | fill-labs | 0.7.28 |
| GitHub リポジトリ | github.remotehub | GitHub | 0.64.0 |
| GitHub Actions | github.vscode-github-actions | github | 0.32.3 |
| GitHub pull request | github.vscode-pull-request-github | GitHub | 0.163.2026082104 |
| Discord Presence | icrawl.discord-vscode | icrawl | 5.9.2 |
| Markdown Live Editor | jishii1204.markdown-live-editor | jishii1204 | 0.6.4 |
| Zenkaku-Hankaku | masakit.zenkaku-hankaku | masakit | 1.0.0 |
| Copilot Auto-Retry | maximmazurok.vscode-copilot-auto-retry | MaximMazurok | 0.3.1 |
| GitHub Actions | me-dutour-mathieu.vscode-github-actions | me-dutour-mathieu | 3.0.1 |
| zenkaku | mosapride.zenkaku | mosapride | 0.0.3 |
| Container Tools | ms-azuretools.vscode-containers | ms-azuretools | 2.4.5 |
| Japanese Language Pack for Visual Studio Code | ms-ceintl.vscode-language-pack-ja | MS-CEINTL | 1.131.2026072717 |
| C# 開発キット | ms-dotnettools.csdevkit | ms-dotnettools | 3.20.199 |
| C# | ms-dotnettools.csharp | ms-dotnettools | 2.140.9 |
| .NET Install Tool | ms-dotnettools.vscode-dotnet-runtime | ms-dotnettools | 3.1.0 |
| Python Debugger | ms-python.debugpy | ms-python | 2026.7.12111009 |
| Python | ms-python.python | ms-python | 2026.7.2026080801 |
| Pylance | ms-python.vscode-pylance | ms-python | 2026.3.1 |
| Python Environments | ms-python.vscode-python-envs | ms-python | 1.37.2026082101 |
| 開発コンテナー | ms-vscode-remote.remote-containers | ms-vscode-remote | 0.467.0 |
| Remote - SSH | ms-vscode-remote.remote-ssh | ms-vscode-remote | 0.125.2026082115 |
| Remote - SSH: Editing Configuration Files | ms-vscode-remote.remote-ssh-edit | ms-vscode-remote | 0.87.0 |
| WSL | ms-vscode-remote.remote-wsl | ms-vscode-remote | 0.104.3 |
| Azure Repos | ms-vscode.azure-repos | ms-vscode | 0.40.0 |
| CMake Tools | ms-vscode.cmake-tools | ms-vscode | 1.23.52 |
| C/C++ DevTools | ms-vscode.cpp-devtools | ms-vscode | 0.5.14 |
| C/C++ | ms-vscode.cpptools | ms-vscode | 1.33.8 |
| C/C++ Extension Pack | ms-vscode.cpptools-extension-pack | ms-vscode | 1.5.1 |
| Extension Test Runner | ms-vscode.extension-test-runner | ms-vscode | 0.0.14 |
| PowerShell | ms-vscode.powershell | ms-vscode | 2025.4.0 |
| リモート エクスプローラー | ms-vscode.remote-explorer | ms-vscode | 0.6.2026031809 |
| リモート リポジトリ | ms-vscode.remote-repositories | ms-vscode | 0.42.0 |
| Chat Customizations Evaluations | ms-vscode.vscode-chat-customizations-evaluations | ms-vscode | 1.0.8 |
| GitHub Issue Notebooks | ms-vscode.vscode-github-issue-notebooks | ms-vscode | 0.0.134 |
| indent-rainbow | oderwat.indent-rainbow | oderwat | 8.3.1 |
| Fix JSON | oliversturm.fix-json | oliversturm | 0.2.0 |
| Codex – OpenAI’s coding agent | openai.chatgpt | openai | 26.818.32112 |
| Material Icon Theme | pkief.material-icon-theme | PKief | 5.37.0 |
| YAML | redhat.vscode-yaml | redhat | 1.25.2026082008 |
| rust-analyzer | rust-lang.rust-analyzer | rust-lang | 0.3.3016 |
| Trailing Spaces | shardulm94.trailing-spaces | shardulm94 | 0.4.4 |
| Shader languages support for VS Code | slevesque.shader | slevesque | 1.1.5 |
| Unify Chat Provider | smallmain.vscode-unify-chat-provider | SmallMain | 8.6.0 |
| vscode-pdf | tomoki1207.pdf | tomoki1207 | 1.2.2 |
| TypeScript 7 | typescriptteam.native-preview | TypeScriptTeam | 0.20260708.2 |
| Unity | visualstudiotoolsforunity.vstuc | visualstudiotoolsforunity | 1.3.1 |
| GPG Indicator | wdhongtw.gpg-indicator | wdhongtw | 0.7.5 |
A/B Experiments
vsliv368cf:30146710
pythonvspyt551:31249597
nativeloc1:31118317
dwcopilot:31158714
dwoutputs:31242946
copilot_t_ci:31333650
g012b348:31231168
pythonrdcb7:31268811
pythonpcpt1cf:31399617
6518g693:31302842
82j33506:31327384
envsactivate1:31349248
editstats-enabled:31346256
cloudbuttont:31366566
3efgi100_wstrepl:31403338
cp_cls_t_966_ss:31526232
4je02754:31455664
8hhj4413:31478653
ge8j1254_inline_auto_hint_haiku:31490507
cp_cls_c_1081:31454833
conptydll_true:31485575
e9c30283:31453065
test_treatment2:31471001
c9b86496:31447327
control_6dc23131:31555649
ei9d7968:31462942
nes-extended-on:31455475
89g7j272:31506658
7e884298:31462391
i2gc6536:31472020
52612955:31508042
h08i8180:31475367
23c7c724:31520045
ddid_c:31478205
hmra_i5g22:31518061
bjc72774_agent_sandbox:31538428
7df3h592:31491241
cp_cls_t_1082:31535311
logging_enabled_new:31490725
jb_cp_cls_t_632:31543129
32d76977:31503652
ha629193:31508444
a1ije391_t:31533808
jbcp_cls_pctr_t:31531130
cp_intellij_t_nes:31548657
gf14b233:31526830
hide-eh-duplicates:31543293
replace-eh-with-ah:31545853
ihg5j128:31534457
f412h606:31543414
enable_editor_pane_layout:31551200
52258b4d:31547953
36h42362:31560305
c7c27ce7:31551212
6577i413_copy:31558653
1h923230:31564177
0dg73464:31554309
treatment-23-1:31555779
unuse_dynamic_mcp:31555281
0c1h4866:31562347
vrbsty_fls:31561057
5b8j3302:31564600
mangle-name-treatment:31568054
signed-out-control:31566874
codex-agent-enabled:31566739
a9h1h725:31568527
9e5id457:31570526
permission_prompt_control:1332567
ccr_pr_nudge_adoption:1319471
vsc_wsm_c:1324224

Activity
PenguinDOOM commentedon Aug 21, 2026
I noticed this bridge also drops turnId, topLevelTurnId, and modeChanged
chat: preserve conversation ID for BYOK Responses