Unknown model ID silently falls back to another model without an error or model-change event
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 48/100
- Issue 類型
- 缺陷
- 描述清晰度
- 描述清楚
- 活躍度
- 活躍
- 技術堆疊
- node.js, typescript
研究方向
Start by reading createSession() model selection and validation, then trace when the effective model is resolved and how session.warning and session.model_change events are emitted. Check existing model fallback tests and the related discussion in issue #250. Done means an unavailable explicitly requested model can be rejected or its fallback is observable, with behavior covered by tests and matching documentation.
由索引模型根據 Issue 內容生成。
描述
An explicitly requested, nonexistent model ID is accepted by createSession(). The first turn then runs on a different model without an exception, session.warning, or session.model_change event.
This prevents an SDK caller from relying on an explicit model selection. Checking session.rpc.model.getCurrent() immediately after creation does not detect the problem: it initially reports the invalid ID and only reports the fallback model after the turn.
This was reproduced on Copilot SDK 1.0.15 with runtime 1.0.89. The observation is based on SDK-reported per-API-call usage, not on asking the model to identify itself.
Environment
| Component | Version / configuration |
|---|---|
| SDK | @github/copilot-sdk 1.0.15 |
Actual runtime, from client.getStatus() |
1.0.89 |
| Protocol version | 3 |
| Node.js | 24.22.0 |
| OS | Windows |
| Mode | copilot-cli |
| Authentication | Authenticated Copilot client; no BYOK provider |
| Requested model | invalid-model |
| Reasoning effort | medium |
| Automatic routing | Usage events reported isAuto: false |
| BYOK | Usage events reported isByok: false |
| Observation date | 2026-10-19 |
The SDK model catalog contained 16 models. invalid-model was absent. A valid control model, gpt-5.6-terra, was present and executed without substitution.
Steps to reproduce
Use an empty directory outside a source repository and an existing valid Copilot login. No repository files or external tools are needed. Ensure that no BYOK provider override is configured.
Install the observed SDK version:
npm init -y
npm install @github/[email protected] [email protected]
Save the following as repro.mjs, then run node repro.mjs.
Standalone SDK reproduction
import { randomUUID } from 'node:crypto';
import { CopilotClient, defineTool } from '@github/copilot-sdk';
import { z } from 'zod';
const requestedModel = 'invalid-model';
const usage = [];
const notices = [];
const modelChanges = [];
let verdict;
const client = new CopilotClient({ mode: 'copilot-cli' });
try {
await client.start();
const models = await client.listModels();
console.log({
requestedModel,
advertised: models.some((model) => model.id === requestedModel),
});
const session = await client.createSession({
sessionId: randomUUID(),
model: requestedModel,
reasoningEffort: 'medium',
systemMessage: {
mode: 'replace',
content: 'Call submit_verdict with passed set to true. Do not use other tools.',
},
tools: [defineTool('submit_verdict', {
description: 'Submit the probe verdict.',
parameters: z.object({ passed: z.boolean() }),
skipPermission: true,
handler(args) {
verdict = args;
return 'Grade submitted. Do not respond further.';
},
})],
availableTools: ['submit_verdict'],
onPermissionRequest: () => ({
kind: 'reject',
feedback: 'The probe denies other tool and file access.',
}),
infiniteSessions: { enabled: false },
enableSessionStore: false,
enableSessionTelemetry: false,
skipCustomInstructions: true,
enableConfigDiscovery: false,
enableSkills: false,
enableFileHooks: false,
onEvent(event) {
if (event.type === 'assistant.usage') {
const { model, isAuto, isByok } = event.data;
usage.push({ model, isAuto, isByok });
}
if (event.type === 'session.warning' || event.type === 'session.error') {
notices.push({ type: event.type, message: event.data.message });
}
if (event.type === 'session.model_change') {
modelChanges.push(event.data);
}
},
});
const selectedAfterCreate = (await session.rpc.model.getCurrent()).modelId;
await session.sendAndWait({ prompt: 'Submit the verdict now.' }, 45_000);
console.log(JSON.stringify({
requestedModel,
selectedAfterCreate,
selectedAfterTurn: (await session.rpc.model.getCurrent()).modelId,
usage,
notices,
modelChanges,
verdict,
}, null, 2));
} finally {
const errors = await client.stop();
if (errors.length) throw new AggregateError(errors, 'SDK cleanup failed.');
}
The observer is provided in createSession({ onEvent }), with an explicit session ID, so it is installed before session creation completes. The absence of a warning is not explained by attaching an observer after the turn.
For a control, replace invalid-model with a model ID returned by listModels() for the account.
Expected behavior
For applications that explicitly pin a model, there should be a supported way to reject an unavailable model rather than execute on a different one. A strict-model / no-fallback option would address this without necessarily changing the default behavior for existing applications.
If fallback remains enabled, it should be observable:
- Emit a warning and/or a model-change event identifying the requested and effective models and the reason.
- Document when the effective model is resolved and why the initial
getCurrent()value may not represent the model that will execute. - Make it possible to enforce the requested model without relying on a successful inference call on the wrong model.
Actual behavior and captured evidence
The live capture produced the following relevant fields:
{
"requestedModel": "invalid-model",
"sdkRequestModel": "invalid-model",
"selectedAfterCreate": "invalid-model",
"selectedAfterTurn": "claude-sonnet-5",
"usage": [
{ "model": "claude-sonnet-5", "isAuto": false, "isByok": false },
{ "model": "claude-sonnet-5", "isAuto": false, "isByok": false }
],
"notices": [],
"modelChanges": [],
"verdict": { "passed": true }
}
listModels() did not advertise invalid-model. Nevertheless, both API calls used claude-sonnet-5, the tool submitted a successful verdict, and the SDK did not report a session warning, session error, or model-change event.
claude-sonnet-5 is the fallback observed in this environment for this particular execution, not a claim about a universal or hard-coded default.
Impact
- Evaluations can execute on a different judge model while appearing to honor an explicit configuration.
- A typo or removed model ID can change model behavior, cost, and reproducibility without a configuration error.
- Inspecting only the initial selected model is insufficient to enforce model identity.
- Consumers may incorrectly attribute usage to the requested ID unless they independently capture per-call usage.
Related reports and documentation
- github/copilot-sdk#250: Allow disabling model fallback.
- github/copilot-sdk#378, a proposed model-validation change linked from that discussion, is closed and was not merged.
- The SDK usage documentation defines
assistant.usage.modelas the model identifier for the individual API call.
- 主要語言
- Java
- 星號
- 10.7k
- 分支
- 1.5k
- PR 合併指標
- 30 天內沒有已合併 PR
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 沒有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
github/copilot-sdk 的其他 Issue
-
Rust: ElicitationRequest drops the tool call id from elicitation.requested可能重新可做 關聯的 PR 已關閉且未合併。 未關閉
難度 2/5 1-3 小時 新手友好度 78/100
github/copilot-sdk#2900 ·
-
難度 1/5 1 小時以內 新手友好度 84/100
github/copilot-sdk#2876 · 1 則留言 · 1 個 reaction ·
-
Python ModelLimits drops max_output_tokens from model metadata可能重新可做 關聯的 PR 已關閉且未合併。 未關閉bug
難度 2/5 1-3 小時 新手友好度 78/100
github/copilot-sdk#2798 · 1 則留言 ·
-
難度 2/5 1-3 小時 新手友好度 65/100
github/copilot-sdk#2759 ·
-
docs/AGENTS.md is repo authoring guidance, but everything in docs/ gets published可能重新可做 關聯的 PR 已關閉且未合併。 未關閉documentation
難度 1/5 1 小時以內 新手友好度 85/100
github/copilot-sdk#2758 ·
查看 github/copilot-sdk 的全部 Issue
相似的 Issue
-
難度 2/5 1-3 小時 新手友好度 72/100
aws/serverless-java-container#1729 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 75/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 75/100
ls1intum/thesis-management#1473 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 76/100
LunaDeerMC/Dominion#301 · 1 則留言 ·
-
[FEATURE] Expose external refresh, node-level translog and warmer stats可能已有人在做 關聯的 PR 仍在進行中或已合併。 未關閉untriaged
難度 2/5 1-3 小時 新手友好度 68/100
opensearch-project/opensearch-prometheus-exporter#680 ·
維護者通常 2 天內回覆