microsoft / microsoft/vscode

Bundled Anthropic BYOK rejects stable vscode.lm User-only requests with empty system block

Open
#333,765 0 comments 0 reactions 1 assignee Claimed by @vritant24 View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

- Copilot Chat Extension Version: Built-in `github.copilot-chat` 0.63.0
- VS Code Version: 1.135.0 (`08d4889f9ec4a1685d257b9b95de036c8e1ce1e5`)
- OS Version: Arch Linux x64, Wayland (Hyprland)
- Feature: Third-party Language Model API consumer using the built-in Anthropic BYOK provider
- Selected model: `anthropic/claude-haiku-4-5-20251001` (the provider exposed 10 Anthropic models)
- Logs:

```text
request: LanguageModelChatMessage.User("Reply with exactly OK."), no tools, no history
roster: 10 anthropic model(s)
model: anthropic/claude-haiku-4-5-20251001
RESULT: FAILURE — 400 {"type":"error","error":{"type":"invalid_request_error","message":"system: text content blocks must be non-empty"},"request_id":"req_011CecqAgwTSd1VaLu2aLUUv"}
```

## Steps to reproduce

1. Start VS Code with no GitHub/Copilot authentication. In **Chat: Manage Language Models**, configure the built-in **Anthropic** provider with a workspace-scoped Anthropic Console API key.
2. From a third-party extension command, make the smallest stable `vscode.lm` request:

```js
const models = await vscode.lm.selectChatModels({ vendor: 'anthropic' });
const model = models.find(candidate => /haiku/i.test(candidate.id)) ?? models[0];
const response = await model.sendRequest(
[vscode.LanguageModelChatMessage.User('Reply with exactly OK.')],
{ justification: 'Minimal Anthropic BYOK provider reproduction.' },
new vscode.CancellationTokenSource().token,
);
for await (const text of response.text) {
console.log(text);
}
```

3. Observe that model discovery succeeds, but `sendRequest` fails upstream with HTTP 400 before producing a response.

This was reproduced from a copied profile whose `vscode.github-authentication` secret was removed. The UI showed **Sign In**. The credential was a workspace-scoped key, not an identity-linked key. As a control, the same key listed 10 models and the same Haiku model answered a direct Anthropic SDK request successfully.

## Expected

A non-empty stable-API User message should reach the selected Anthropic model and stream its answer. A missing system message should be omitted from the Anthropic request.

## Actual and owning layer

The third-party request contains one non-empty User text part, but the bundled provider adds an empty Anthropic system text block.

At the 1.135.0 product commit, [`apiMessageToAnthropicMessage`](https://github.com/microsoft/vscode/blob/08d4889f9ec4a1685d257b9b95de036c8e1ce1e5/extensions/copilot/src/extension/byok/common/anthropicMessageConverter.ts#L104-L148) initializes `{ type: 'text', text: '' }` and returns it even when all input messages have the stable User/Assistant roles. [`AnthropicLMProvider`](https://github.com/microsoft/vscode/blob/08d4889f9ec4a1685d257b9b95de036c8e1ce1e5/extensions/copilot/src/extension/byok/vscode-node/anthropicProvider.ts#L265-L276) then unconditionally sends `system: [system]`.

The same two shapes are still present on current `main` at `22f76d2e5fbf22b786986e2f7debf7446af7b4ad`.

This makes every stable third-party User/Assistant-only request hit the same invalid empty system block. A consumer cannot work around it by changing User text, and the System role remains a proposed API that Marketplace extensions cannot use.

One possible provider-side fix is to omit `system` when `system.text` is empty and it has no cache control, with a regression test for a single non-empty User message:

```ts
system: system.text || system.cache_control ? [system] : undefined,
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.