diff --git a/README.md b/README.md index 74cc431..f9c5581 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,6 @@ All models support tool calling. GLM-5.2, GLM-5.1, and Claude (Fable 5, Opus, So | Setting | Default | Description | | -------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `opencode-for-copilot.opencodePlan` | `go` | Active OpenCode plan (`go` subscription or `zen` pay-as-you-go). Picks your default endpoint; the picker always lists the full Go+Zen catalog, prefixed `go/…` or `zen/…` by billing path | | `opencode-for-copilot.endpoint` | `opencode-go` | Single-value endpoint selector. `opencode-go` / `opencode-go-anthropic` serve OpenCode Go subscription models; `opencode-zen` / `opencode-zen-anthropic` serve OpenCode Zen pay-as-you-go models (including Claude and free models) | | `opencode-for-copilot.baseUrl` | empty | Optional API endpoint override. When non-empty, overrides the `endpoint` preset. | | `opencode-for-copilot.maxTokens` | `0` | Max output tokens (`0` = no limit). Useful for cost control | @@ -293,7 +292,7 @@ This fork originated from *GLM for VSCode Copilot* and reused its identifiers. I Key features introduced along the way: -- **Full model catalog** — the `opencode-for-copilot.opencodePlan` setting (`go`, default, or `zen`) picks your default endpoint; every Go and Zen model is listed either way, each prefixed with its billing path (`go/GLM-5.2`, `zen/Claude Sonnet 5`). Picking a `zen/…` model without credits fails with a clear message instead of a cryptic 401. +- **Full model catalog** — every Go and Zen model is listed in the picker, each prefixed with its billing path (`go/GLM-5.2`, `zen/Claude Sonnet 5`). Use `opencode-for-copilot.endpoint` for your default endpoint. Picking a `zen/…` model without credits fails with a clear message instead of a cryptic 401. - **Live model catalog** — the list is fetched from the official OpenCode endpoints and re-fetched when stale: opening the picker past the TTL refreshes in the background, failed fetches retry after 60 s instead of serving the static fallback for 5 minutes (covers starting VS Code before your VPN is up), and **OpenCode: Refresh Model List** forces an immediate re-fetch. - **Clearer errors** — a Zen-only-model billing failure explains that the *model choice* is the problem, not the API key. - **Agent swarm participant** moved to `opencode-for-copilot.pipeline` (re-type `@swarm` once after updating). diff --git a/README.zh-cn.md b/README.zh-cn.md index 084144c..046122f 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -194,7 +194,6 @@ API Key 存储在 VS Code 的 `SecretStorage` 中(macOS 钥匙串 / Windows | 设置项 | 默认值 | 说明 | | -------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `opencode-for-copilot.opencodePlan` | `go` | 当前使用的 OpenCode 套餐(`go` 订阅或 `zen` 按量付费)。决定默认端点;模型选择器始终列出完整的 Go+Zen 目录,并以 `go/…` 或 `zen/…` 前缀标明计费路径 | | `opencode-for-copilot.endpoint` | `opencode-go` | 单值端点选择器。`opencode-go` / `opencode-go-anthropic` 使用 OpenCode Go 订阅模型;`opencode-zen` / `opencode-zen-anthropic` 使用 OpenCode Zen 按量付费模型(含 Claude 和免费模型) | | `opencode-for-copilot.baseUrl` | 留空 | 可选 API endpoint 覆盖项。任何非空值都会优先覆盖 `endpoint` preset。 | | `opencode-for-copilot.maxTokens` | `0` | 最大输出 Token 数(`0` = 不限制)。可用于成本控制 | diff --git a/package.json b/package.json index 8e65e15..cac3aa7 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "opencode-for-copilot", - "displayName": "OpenCode for Copilot", + "displayName": "%opencode-for-copilot.displayName%", "description": "Use OpenCode Go & Zen coding models (GLM, Kimi, DeepSeek, Claude, Grok, Qwen, free models) in the Copilot Chat model picker. Vision, thinking mode, agent tools — zero config, BYOK.", "icon": "resources/icon.png", - "version": "3.11.13", + "version": "3.11.14", "packageManager": "pnpm@11.7.0", "publisher": "abbalochdev", "license": "MIT", @@ -152,15 +152,6 @@ "configuration": { "title": "%opencode-for-copilot.config.title%", "properties": { - "opencode-for-copilot.opencodePlan": { - "type": "string", - "enum": [ - "go", - "zen" - ], - "default": "go", - "markdownDescription": "%opencode-for-copilot.config.opencodePlan.description%" - }, "opencode-for-copilot.agentRoles": { "type": "object", "default": {}, diff --git a/package.nls.json b/package.nls.json index 23b8e43..bb0d8f3 100644 --- a/package.nls.json +++ b/package.nls.json @@ -1,4 +1,5 @@ { + "opencode-for-copilot.displayName": "OpenCode for Copilot", "opencode-for-copilot.command.setApiKey": "OpenCode: Set Go/Zen API Key", "opencode-for-copilot.command.getApiKey": "OpenCode: Open API Key Page", "opencode-for-copilot.command.queryUsage": "OpenCode: Query Usage", @@ -22,7 +23,6 @@ "opencode-for-copilot.walkthrough.advancedSettings.title": "Try advanced settings", "opencode-for-copilot.walkthrough.advancedSettings.description": "Customize providers and model names, configure the vision proxy, enable experimental settings, and more in the extension settings.\n[Open settings](command:opencode-for-copilot.openSettings)", "opencode-for-copilot.config.title": "OpenCode for Copilot", - "opencode-for-copilot.config.opencodePlan.description": "Which OpenCode plan to use: `go` (subscription; GLM, Kimi, MiniMax, Grok 4.5) or `zen` (pay-as-you-go; also serves Claude and free models). Determines the model list, default endpoint, and which secret the \"Set API Key\" command writes. The two keys are stored separately — use [Set API Key](command:opencode-for-copilot.setApiKey).", "opencode-for-copilot.config.baseUrl.description": "Optional API base URL override. When non-empty, this value has the highest priority and overrides the `endpoint` preset. Leave empty to use the selected OpenCode endpoint preset.", "opencode-for-copilot.config.endpoint.description": "OpenCode endpoint selector. Each option resolves to a base URL and wire protocol (OpenAI `/chat/completions` or Anthropic `/v1/messages`). Go serves the curated subscription catalogue; Zen serves pay-as-you-go models. A non-empty `baseUrl` overrides this preset.", "opencode-for-copilot.config.endpoint.opencodeGo.label": "OpenCode Go (OpenAI)", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 49ece37..672e1ae 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -1,4 +1,5 @@ { + "opencode-for-copilot.displayName": "OpenCode for Copilot", "opencode-for-copilot.command.setApiKey": "OpenCode: 设置 Go/Zen API Key", "opencode-for-copilot.command.getApiKey": "OpenCode: 打开 API Key 页面", "opencode-for-copilot.command.queryUsage": "OpenCode: 查询用量", @@ -8,7 +9,6 @@ "opencode-for-copilot.command.openSettings": "OpenCode: 打开设置", "opencode-for-copilot.command.showLogs": "OpenCode: 显示日志", "opencode-for-copilot.command.showDiagnostics": "OpenCode: 显示运行时诊断", - "opencode-for-copilot.config.opencodePlan.description": "使用哪个 OpenCode 套餐:`go`(订阅,含 GLM、Kimi、MiniMax、Grok 4.5)或 `zen`(按量付费,额外提供 Claude 与免费模型)。决定模型列表、默认端点,以及“设置 API Key”写入哪个密钥。两个密钥分开存储——使用[设置 API Key](command:opencode-for-copilot.setApiKey)。", "opencode-for-copilot.config.showProviderPrefix.description": "在模型选择器中为模型名称添加提供商前缀(例如 `Kimi · Kimi K3`),窄面板中也能一眼辨认模型归属。", "opencode-for-copilot.command.openRequestDumpsFolder": "OpenCode: 打开请求 Dump 目录", "opencode-for-copilot.command.setPonytailMode": "OpenCode: 设置 Ponytail 模式", @@ -22,7 +22,7 @@ "opencode-for-copilot.walkthrough.showModels.description": "如果模型被隐藏,打开 VS Code 的语言模型管理器并显示 OpenCode 模型。\n[打开语言模型管理](command:workbench.action.chat.manage)", "opencode-for-copilot.walkthrough.advancedSettings.title": "尝试高级设置", "opencode-for-copilot.walkthrough.advancedSettings.description": "可以在插件设置中自定义提供方与模型名称、自定义视觉代理、开启实验性设置等。\n[打开设置](command:opencode-for-copilot.openSettings)", - "opencode-for-copilot.config.title": "OpenCode for Copilot", + "opencode-for-copilot.config.title": "OpenCode 助手", "opencode-for-copilot.config.baseUrl.description": "可选的 API 基础 URL 覆盖项。非空时优先级最高,会覆盖 `endpoint` 预设;留空时使用选定的 OpenCode endpoint 预设。", "opencode-for-copilot.config.endpoint.description": "OpenCode endpoint 选择器。每个选项对应一个基础 URL 和线路协议(OpenAI `/chat/completions` 或 Anthropic `/v1/messages`)。Go 提供订阅精选模型;Zen 提供按量付费模型。`baseUrl` 非空时仍会覆盖此预设。", "opencode-for-copilot.config.endpoint.opencodeGo.label": "OpenCode Go(OpenAI)", diff --git a/src/config.ts b/src/config.ts index db435f0..37b47be 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,9 +4,7 @@ import { normalizeBaseUrl, resolveEndpointApiKeyUrl, resolveEndpointBaseUrl, - resolveEndpointProtocol, - resolvePlanDefaultEndpoint, - type OpencodePlan + resolveEndpointProtocol } from './endpoint'; import { getDynamicModels @@ -31,7 +29,7 @@ const CUSTOM_MODEL_MAX_OUTPUT_TOKENS = 131_072; * Resolution order: * 1. `baseUrl` override (highest priority — covers advanced/proxy use cases) * 2. `endpoint` preset - * 3. The active OpenCode plan's default endpoint (`opencode-go` / `opencode-zen`) + * 3. `opencode-go` when the endpoint preset is unset or invalid */ export function getBaseUrl(): string { const override = getBaseUrlOverride(); @@ -56,24 +54,17 @@ export function getBaseUrlOverride(): string | undefined { * * Resolution order: * 1. Explicit `endpoint` setting (always wins) - * 2. The active OpenCode plan's default endpoint (`opencode-go` / `opencode-zen`) + * 2. `opencode-go` when the endpoint preset is unset or invalid */ export function getEndpoint(): EndpointPreset { const config = vscode.workspace.getConfiguration(CONFIG_SECTION); const explicit = normalizeEndpointPreset(config.get('endpoint')); - return explicit ?? resolvePlanDefaultEndpoint(getOpencodePlan()); -} - -/** Which OpenCode plan's key and model catalog to use — `opencodePlan` setting. */ -export function getOpencodePlan(): OpencodePlan { - const config = vscode.workspace.getConfiguration(CONFIG_SECTION); - return config.get('opencodePlan') === 'zen' ? 'zen' : 'go'; + return explicit ?? 'opencode-go'; } // ---- One-time legacy settings migration (glm-copilot -> opencode-for-copilot) ---- const LEGACY_SETTING_KEYS = [ - 'opencodePlan', 'agentRoles', 'baseUrl', 'endpoint', diff --git a/src/provider/index.ts b/src/provider/index.ts index 28a98fb..5f39720 100644 --- a/src/provider/index.ts +++ b/src/provider/index.ts @@ -130,7 +130,8 @@ export class GLMChatProvider implements vscode.LanguageModelChatProvider { if ( e.affectsConfiguration(`${CONFIG_SECTION}.apiKey`) || e.affectsConfiguration(`${CONFIG_SECTION}.baseUrl`) || - e.affectsConfiguration(`${CONFIG_SECTION}.endpoint`) || e.affectsConfiguration(`${CONFIG_SECTION}.opencodePlan`) || e.affectsConfiguration(`${CONFIG_SECTION}.customModels`) || + e.affectsConfiguration(`${CONFIG_SECTION}.endpoint`) || + e.affectsConfiguration(`${CONFIG_SECTION}.customModels`) || e.affectsConfiguration(`${CONFIG_SECTION}.modelIdOverrides`) ) { // Discard stale GLMClient instances whose baseUrl/apiKey/protocol may have changed. diff --git a/src/runtime/diagnostics.ts b/src/runtime/diagnostics.ts index 14e48d5..7449de8 100644 --- a/src/runtime/diagnostics.ts +++ b/src/runtime/diagnostics.ts @@ -6,7 +6,6 @@ import { getCodeSimplifierEnabled, getDebugMode, getEndpoint, - getOpencodePlan, getPonytailMode, } from '../config'; import { CONFIG_SECTION } from '../consts'; @@ -61,7 +60,6 @@ export function buildRuntimeDiagnosticsReport(context: vscode.ExtensionContext): '', '## Configuration', `- Endpoint preset: ${getEndpoint()}`, - `- OpenCode plan: ${getOpencodePlan()}`, `- Base URL: ${getBaseUrl()}`, `- API protocol: ${getApiProtocol()}`, `- Debug mode: ${getDebugMode()}`, diff --git a/test/config.test.ts b/test/config.test.ts index 23179a2..f81af86 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -15,8 +15,7 @@ import { MODELS } from '../src/consts'; import { OPENCODE_GO_ANTHROPIC_BASE_URL, OPENCODE_GO_API_KEY_URL, - OPENCODE_GO_OPENAI_BASE_URL, - OPENCODE_ZEN_OPENAI_BASE_URL + OPENCODE_GO_OPENAI_BASE_URL } from '../src/endpoint'; import { __clearConfigurationValues, __setConfigurationValue } from './support/vscode.mock'; @@ -70,20 +69,13 @@ describe('endpoint preset selection', () => { __clearConfigurationValues(); }); - it('defaults to opencode-go when nothing is configured (plan default)', () => { + it('defaults to opencode-go when nothing is configured', () => { expect(getEndpoint()).toBe('opencode-go'); expect(getBaseUrl()).toBe(OPENCODE_GO_OPENAI_BASE_URL); expect(getApiProtocol()).toBe('openai'); expect(getApiKeyUrl()).toBe(OPENCODE_GO_API_KEY_URL); }); - it('defaults to opencode-zen when opencodePlan is zen', () => { - __setConfigurationValue('opencode-for-copilot.opencodePlan', 'zen'); - - expect(getEndpoint()).toBe('opencode-zen'); - expect(getBaseUrl()).toBe(OPENCODE_ZEN_OPENAI_BASE_URL); - }); - it('respects an explicit endpoint preset', () => { __setConfigurationValue('opencode-for-copilot.endpoint', 'opencode-zen-anthropic'); @@ -91,7 +83,7 @@ describe('endpoint preset selection', () => { expect(getApiProtocol()).toBe('anthropic'); }); - it('ignores unknown preset values and falls back to the plan default', () => { + it('ignores unknown preset values and falls back to opencode-go', () => { // Presets removed with the Zhipu/Z.ai endpoint layer must not crash // users who still carry them in settings.json. __setConfigurationValue('opencode-for-copilot.endpoint', 'china-coding'); diff --git a/test/provider/models.test.ts b/test/provider/models.test.ts index f3b5358..3601fd2 100644 --- a/test/provider/models.test.ts +++ b/test/provider/models.test.ts @@ -49,8 +49,8 @@ describe('offline fallback baseline', () => { expect(presets.some((p) => p.startsWith('opencode-zen'))).toBe(true); }); - it('serves the whole baseline regardless of the plan toggle', () => { - __setConfigurationValue('opencode-for-copilot.opencodePlan', 'go'); + it('serves the whole baseline regardless of endpoint preset', () => { + __setConfigurationValue('opencode-for-copilot.endpoint', 'opencode-go'); const infos = listProviderModels().map((m) => toChatInfo(m, true)); expect(infos.every((m) => m.isUserSelectable)).toBe(true); }); diff --git a/test/runtime/commands.test.ts b/test/runtime/commands.test.ts index d63f196..6f659e0 100644 --- a/test/runtime/commands.test.ts +++ b/test/runtime/commands.test.ts @@ -19,10 +19,10 @@ describe('runtime commands', () => { }); it.each([ - ['go', OPENCODE_GO_API_KEY_URL], - ['zen', OPENCODE_ZEN_API_KEY_URL], - ])('opens the API key page for the %s plan', async (plan, expectedUrl) => { - __setConfigurationValue('opencode-for-copilot.opencodePlan', plan); + ['opencode-go', OPENCODE_GO_API_KEY_URL], + ['opencode-zen', OPENCODE_ZEN_API_KEY_URL], + ])('opens the API key page for the %s endpoint', async (endpoint, expectedUrl) => { + __setConfigurationValue('opencode-for-copilot.endpoint', endpoint); registerCommands({ subscriptions: [] } as unknown as vscode.ExtensionContext); await vscode.commands.executeCommand('opencode-for-copilot.getApiKey');