# Install dependencies
npm install
# Compile
npm run compile
# Verify the Web bundle and VSIX allowlist
npm run test:vsix
# Lint
npm run lint
# Full extension tests (unit + VS Code Desktop)
npm test
# Run only the VS Code Desktop smoke tests
npm run test:desktop
# GitHub Pages smoke test
npm run test:pages
# Package the release build
npm run package:vsix
# Package the pre-release build
npm run package:vsix:pre| Command | Description |
|---|---|
npm run test:unit |
Runs the pure code regression tests in src/test/runTest.ts. |
npm run test:desktop |
Uses @vscode/test-cli to invoke @vscode/test-electron; on the first run it downloads the Stable VS Code Desktop into .vscode-test/, then launches an isolated test instance to run src/test/suite/**/*.test.ts. |
Run Web Extension |
VS Code debug entry that launches the browser extension host using out/extension.web.js. |
npm test |
Runs test:unit first, then test:desktop. |
Run Extension Tests |
VS Code debug entry; reads .vscode-test.js in the repository root. |
More test layers and execution chains: see docs/testing.md.
The extension package contains separate runtime entry points: out/extension.node.js for the Node.js extension host and out/extension.web.js for browser extension hosts. npm run compile and npm run package build both entries; npm run test:vsix verifies that both are packaged and that the browser bundle has no Node runtime imports.
In VS Code for the Web, configured upstream endpoints must support CORS. Commit-message generation can use a host-provided SCM/Git API, but recent-commit style sampling remains a desktop-only enhancement because it runs git log locally.
npm run package:vsixPackage a pre-release build:
npm run package:vsix:prePublish to the marketplace:
# Linux / macOS
export VSCE_PAT=your_pat
npm run publish:marketplace
# PowerShell
$env:VSCE_PAT="your_pat"
npm run publish:marketplacePublish a pre-release to the marketplace:
# Linux / macOS
export VSCE_PAT=your_pat
npm run publish:marketplace:pre
# PowerShell
$env:VSCE_PAT="your_pat"
npm run publish:marketplace:prePre-release channel conventions:
- This project uses the same extension
Pre-Releasechannel on the VS Code Marketplace; no separate extension ID. - Only after at least one pre-release version already exists on the Marketplace can users switch between
Switch to Pre-Release Version/Switch to Release Versionfrom the gear menu on the extension details page. - If that entry is missing from the details page, no switchable pre-release package exists on the marketplace yet; this is usually not a manifest issue but a missing one-time
publish --pre-release. - Pre-release and release must use different version numbers; the recommended convention is "odd minor for pre-release, even minor for release", e.g.
0.7.xis the preview channel and0.8.xis the release channel. npm run publish:marketplace:preonly publishes the currentpackage.jsonversion as pre-release; it does not bump the version number.
Configurable in VS Code settings.json:
{
"coding-plans.commitMessage.options": {
"prompt": "FORMAT REQUIREMENT:\nFollow the Conventional Commits format...",
"maxDiffLines": 3000,
"pipelineMode": "single",
"summaryTriggerLines": 1200,
"summaryChunkLines": 800,
"summaryMaxChunks": 12,
"maxBodyBulletCount": 7,
"subjectMaxLength": 72,
"requireConventionalType": true,
"warnOnValidationFailure": true,
"llmMaxPromptLength": 20000
}
}Run npm run pricing:fetch to fetch coding plan prices; results are written to:
assets/provider-pricing.json(the unified data source for the extension and GitHub Pages)
On GitHub Pages deployment, assets/provider-pricing.json is synced to pages/provider-pricing.json as a site build artifact (not committed).
Pricing fetches run with three provider workers. Each provider has a 120-second budget starting when its worker begins; queued providers do not consume that budget. HTTP requests retain their 15-second default. Rendered-page helpers allow 30 seconds for navigation by default and, when a content predicate is supplied, wait for navigation commit followed by the required pricing content. Provider-specific limits still apply. Timed-out tasks abort HTTP requests and close their browsers; subsequent browser launches are rejected. CUCloud failures retain both browser and HTTP error details.
Zhipu readiness depends on populated price cards, not marketing copy. The parser switches to the monthly tab before extracting prices. Run node --test tests/scripts/pricing-execution.test.js tests/scripts/fetch-provider-pricing.test.js for execution and parser regressions; acceptance scenarios are in docs/cases/provider-pricing-parser-regressions.md.
When fetching performance data, use the environment variable APIKEY as the OpenRouter API Key:
npm run metrics:fetchOptional environment variables:
OPENROUTER_BASE_URL: OpenRouter API Base URL (defaulthttps://openrouter.ai/api/v1).OPENROUTER_MODEL_ORGS: comma-separated list of organizations (defaultdeepseek,qwen,moonshotai,z-ai,minimax,bytedance,bytedance-seed,kwaipilot,meituan,mistralai,stepfun).OPENROUTER_MODEL_LIMIT: number of latest models to fetch per organization (default5).OPENROUTER_MODEL_MAX_AGE_DAYS: only fetch models released within the last N days (default180; set to0to skip the release-day filter).OPENROUTER_ENDPOINT_CONCURRENCY: concurrency for fetching endpoints (default4).OPENROUTER_REQUEST_TIMEOUT_MS: request timeout in milliseconds (default20000).
metrics:fetch uses a fail-closed strategy: if an endpoint request fails, no provider endpoint is captured, or the latency_last_30m / throughput_last_30m performance percentiles of all endpoints are empty, the script exits with a non-zero status and does not overwrite the existing assets/openrouter-provider-metrics.json. OpenRouter latency/throughput fields require an API Key that can view endpoint performance metrics; without auth or with insufficient permissions, usually only uptime/status is returned.
Fetch OpenRouter provider plan pages (for the Overseas Provider tab):
npm run openrouter:plans:fetchPreview the GitHub Pages dashboard locally (static server, default http://127.0.0.1:4173):
npm run serve:pageRun the GitHub Pages smoke tests (starts/reuses the local preview server automatically):
npm run test:pages- This extension no longer maintains an independent native Context Agent.
- Context display directly reuses Copilot Chat's built-in Context Window / context viewer.
- Related display capabilities and details follow the current built-in VS Code / Copilot Chat implementation.
- For the actual usage of the Context Window, context sources, and landing suggestions in this repo, see docs/copilot-chat-context-window.md.
- For the capability boundaries of the current public Chat API and follow-up items, see todo/vscode-chat-api-follow-up.md.
System Instructions: System-class inputs such as system prompt, mode descriptions, strategy prompts, and additional plugin-injected instructions; counts as prompt tokens.Tool Definitions: the schema footprint of the tool definitions themselves; counts as prompt tokens.Reserved Output: the token budget reserved for the model output, corresponding tooutputBuffer, shown separately in the UI.Context Window X / Y tokens: whencontextSizeis configured, the runtime splits the total window into an 80% input window and a 20% output window for VS Code Language Models to aggregate; whencontextSizeis not configured, explicitmaxInputTokens/maxOutputTokensare used, andYfollows the native custom endpoint Context Window convention as the sum of the two. The current public API only requires extensions to implementprovideTokenCountand provides no public interface to write upstream usage details back to the native Context Window, so this repo no longer maintainsX.- VS Code official docs: hovering over the context window control shows "exact token count / total context" and a per-category breakdown; compaction triggers when the context is full.
- In the current implementation,
provideTokenCount()always returns0; the previous round's real usage is no longer reused as the current request token count, to avoid premature conversation compaction during tool continuation. - If VS Code / Copilot Chat later adjusts the context display structure, follow its built-in behavior and update the docs accordingly.
- The current implementation has fully stopped local prompt token estimation and local token counting; if upstream does not return usage, only "no usage data" is shown, with no approximate compensation.
- To see the usage ratio and details of the most recent real request, rely on the unified status bar
CodingPlans: the body shows a concise percentage, and the tooltip combines plan usage and context details. - If the vendor has
coding-plans.vendors[].usageUrlconfigured,CodingPlansadditionally shows plan quota. Currently Zhipu coding plan usage is supported first, covering both 5-hour quota and MCP/request-count quota displays.
- Prefer the
Coding Plans: Manage Vendor Configurationcommand as the config entry. It generates a vendor QuickPick dynamically fromcoding-plans.vendors; after selecting a vendor you can set the API Key, refresh models, or open vendor settings. - API Keys should be stored in VS Code Secret Storage;
coding-plans.vendors[].apiKeyis kept as a deprecated field and takes precedence over Secret Storage when non-empty. If the current vendor has no key, it falls back to anothervendors[].apiKeywith the samebaseUrl. - Since VS Code 1.120, provider models are enumerated directly via the public
LanguageModelChatProviderinterface; the current implementation declares vendors through thelanguageModelChatProviderscontribution and registersregisterLanguageModelChatProvider('coding-plans', adapter)at runtime, without relying onmanagementCommand. - When debugging the request chain, set the
Coding Plansnative output channel level viacoding-plans.logLevel, or adjust it temporarily with Set Log Level in the Output panel. KeepInfofor daily use andDebugfor detailed diagnostics; onlyTracelogs the first 1,000 characters of system/user/assistant message text per message (tool content and image data are not logged), and logs may contain sensitive context. coding-plans.vendors[].defaultApiStyledeclares the vendor's default protocol style; models can override it individually viacoding-plans.vendors[].models[].apiStyle:openai-chat: requestsbaseUrl + /chat/completionsopenai-responses: requestsbaseUrl + /responsesanthropic: requestsbaseUrl + /messages
- When
coding-plans.vendors[].authTypeis omitted, default request headers match native Custom Endpoint:openai-chat/openai-responsessendAuthorization: Bearer;anthropicsendsx-api-keyplusanthropic-version: 2023-06-01and does not sendAuthorization. OptionalauthType: "bearer" | "x-api-key"overrides authentication for all three chat protocols and/modelsdiscovery, sending mutually exclusive auth headers. Anthropic always keeps its version header, including with Bearer. Normalization accepts only these exact values; invalid values behave as omitted. Omitted auth follows the actual model-level protocol for chat, anddefaultApiStylefor discovery. The discovery signature includesauthTypeso an auth change invalidates failed-discovery suppression and stale in-flight discovery writes. This does not change Secret Storage orusageUrlauthentication and adds no implicit retry. - The built-in
火山引擎template useshttps://ark.cn-beijing.volces.com/api/coding/v3,defaultApiStyle: "openai-responses",useModelsEndpoint: false, and ten static model IDs:doubao-seed-evolving,doubao-seed-2.1-turbo,doubao-seed-2.0-lite,minimax-m3,glm-5.3,glm-5.3-flash,deepseek-v4-flash,deepseek-v4-pro,kimi-k2.7-code,kimi-k3. The template only declares IDs, without unverified per-model vision/context/thinking metadata. The complete URL is/api/coding/v3/responses;/api/coding/v3/chat/completionsis also supported. Responses is recommended, not mandatory. Static models remain visible under the explicit vendor group and even forced discovery refresh must not request/modelswhen disabled. - For Volcano Engine Anthropic compatibility, use
defaultApiStyle: "anthropic",authType: "bearer", and extensionbaseUrl: "https://ark.cn-beijing.volces.com/api/coding/v1", keeping static models and discovery disabled. This extension only appends/messages, giving/api/coding/v1/messages; Claude Code's documented/api/codingbase is not interchangeable. ItsANTHROPIC_AUTH_TOKENsetting indicates Bearer auth; this extension instead uses its configured/stored key. Existing explicit vendor settings require manual endpoint/protocol/model updates;models[].apiStyleoverrides the vendor default and must also be removed or updated when switching protocols. Keep the vendor name to preserve the stored key association. Never fall back to general/api/v3, which may incur additional usage charges outside the Coding Plan. Discovery failure falls back to configured/cached models rather than necessarily clearing them. See issue #376 acceptance cases; upstream 401,/modelsavailability and model access are not independently verified without a real Volcano Engine key. - The request path is fixed to native Custom Endpoint behavior: thinking parameters and thinking-output display are kept; plugin extras such as temperature / topP / personality are not sent; there is no reasoning/tool-continuation cache; chat-path compatibility auto-fallbacks (
/v1, non-stream, missing max_tokens, unsupported reasoning) are not triggered./modelsdiscovery still useswithOptionalV1Retry. Real stream errors still calldisableStreamingForSession. coding-plans.vendors[].usageUrlis an optional plan usage API; currently it polls withAuthorization: Bearer <API Key>by default and shows recognized hourly, weekly, or request-count quotas as percentages in the status bar.coding-plans.vendors[].models[].contextSizeis the primary total context window field; automatic refresh takeslimit.contextfrom models.dev. When present it takes precedence overmaxInputTokens/maxOutputTokens; the runtime splits it intomaxInputTokens=80%andmaxOutputTokens=20%so VS Code Language Models does not display a context window exceeding the total.coding-plans.vendors[].models[].price.inputCost/cacheCost/outputCostare Copilot-style metadata read by the VS Code Manage Language Models cost column, in credits / 1M tokens.coding-plans.vendors[].models[].toolCalling/visionare Copilot-style capability aliases normalized tocapabilities.tools/capabilities.vision.- After a successful
/modelsrefresh, the extension prefershttps://models.dev/catalog.jsonand falls back tohttps://models.dev/api.json, matching by model ID/name only and enriching newly discovered models withdescription,capabilities,contextSize,price; matching ignores tags after:in the final model path segment (e.g.:free); thedescriptionformat isid | Lab | Family | Weights | ReleaseDate, whereLabcomes from the model ID prefix;capabilities.thinkingmaps to models.devreasoning; prices use the median across all matching model sources, without matching the local vendor name to a models.dev provider; on fetch failure or no match, the upstream/modelsresults and the project's preset values are kept. coding-plans.vendors[].models[].enableddefaults totrue; whenfalse, the model stays in the config but is not exposed in the final Language Model list, so it does not appear in VS CodeManage Language Models.- When
maxInputTokens/contextSizeare not configured, the extension builds models with a400000token input window and a30000token output window by default; the total context window is the sum of the two. - When
contextSizeis configured, the extension splits the declared input/output windows 80%/20%; when not configured,maxOutputTokensdefaults to30000tokens. coding-plans.advanced.defaultReservedOutputdefaults to60000and overrides the request-side output budget; when sending a request it is automatically capped by the model output limit and does not change the declaredmaxOutputTokens.openai-chatsends this asmax_tokens,openai-responsesasmax_output_tokens, andanthropicasmax_tokens. Native Custom Endpoint typically uses the model's configuredmaxOutputTokensdirectly.- Sampling parameters:
coding-plans.vendors[].defaultTemperature/defaultTopP: vendor sampling config keys;defaultTemperatureis marked deprecated. Values are kept in configuration but are not sent.coding-plans.vendors[].models[].temperature/topP: model-level overrides;temperatureis marked deprecated. Values are kept in configuration but are not sent.request.modelOptions.temperature/personalitymay still be forwarded by the adapter if a caller supplies them; the provider does not write them into the upstream payload. The model rowMore Actionsmenu is thinking-only (no Temperature / Personality).openai-responseskeeps system messages ininputand does not sendinstructions.
- Thinking effort:
- The specific effort value still comes from the request-level override passed by API callers. The adapter also accepts Copilot-style
modelConfiguration.reasoningEffortand copies it tothinkingEffortwhen the latter is absent; an existingthinkingEffort(including a More Actions / schema-default value) is not overwritten byreasoningEffort. Copilot's private_enableThinking: falsedisables thinking whenthinkingTypeis missing or still the schema default (default/think); an explicitenabled/disabled/non-thinkchoice is kept._enableThinking: truedoes not changethinkingTypeand does not force thinking on. Adapter info logs include the forwarded thinking fields._enableThinkingis adapter/provider input only and is not sent upstream. Model-levelcapabilities.thinking: falsehides and forbids sending thinking/reasoning parameters, andsupportsReasoningEffortrestricts model-row options and blocks undeclared values from the payload. editToolsdefaults to["apply-patch","multi-find-replace","find-replace","code-rewrite"], passed through as Copilot-style model metadata tocapabilities.editToolsHintfor VS Code/Copilot to choose edit-tool preferences; this extension itself does not filter request tools by this field.reasoningEffortFormatandzeroDataRetentionEnabledare kept as Copilot-style metadata; the latter does not represent the upstream's real data retention policy.- The inheritance order is fixed as request modelOptions > omit
- Protocol mapping:
openai-chat: usesrequest.modelOptions.thinkingEffort(aliasreasoningEffort), optionsnone/low/medium/high/xhigh/max; the model rowMore Actionsdefault ishigh;nonesendsthinking: { type: "disabled" }. The rest send top-levelreasoning_effortonly by default (native Custom Endpoint Chat Completions shape). Usesrequest.modelOptions.thinkingTypeas the thinking switch; the More Actions default isdefault(omitthinking, A11/A12). Explicitenabledalso sendsthinking: { type: "enabled" }(A13) for vendors that require that field. Response parts emit thinking before output text (native Custom Endpoint order).openai-responses: usesrequest.modelOptions.thinkingEffort(aliasreasoningEffort), optionslow/medium/high/xhigh/max; the model rowMore Actionsdefault ismax; sendsreasoning: { effort }. Copilot_enableThinking: falseor an explicit disabledthinkingTypeomitsreasoning. Response parts emit thinking before output text.anthropic: usesrequest.modelOptions.thinkingTypeas the switch;true/enabled/adaptive/ schema defaultthinksendthinking: { type: "adaptive" },false/disabled/non-thinksendthinking: { type: "disabled" };_enableThinking: truealone does not force thinking on. Usesrequest.modelOptions.effort(aliasesthinkingEffort/reasoningEffort) to sendoutput_config.effort, optionslow/medium/high/xhigh/max. Response parts emit thinking before output text.
- Moonshot/Kimi Anthropic-compatible entrypoints may require the previous assistant tool-call history message to carry the non-standard
reasoning_contentin thinking + tool continuation scenarios, otherwise they returnthinking is enabled but reasoning_content is missing in assistant tool call message; the current implementation does not echo that field on the Anthropic path, so disable thinking or switch to theopenai-chatcompatible API.
- The specific effort value still comes from the request-level override passed by API callers. The adapter also accepts Copilot-style
- When
defaultApiStyle/ modelapiStyleare not configured,openai-chatis assumed. /modelsauto-discovery writes a derivedmodels[].apiStylefor new models:openai-responseswhen the model itself is identified as OpenAI or Grok/xAI source,anthropiconly when the model itself is identified as Anthropic source, andopenai-chatfor everything else; existing manual model entries are not overwritten by refresh, but Grok models that still keep the legacyopenai-chatare automatically upgraded toopenai-responses; extension-generated fallback descriptions (e.g.vendor model: model) can be upgraded to the models.dev structure.anthropicandopenai-responsescurrently focus on chat and tool calling; model discovery is still recommended withuseModelsEndpoint: falseand manually maintainedmodels.- The request chain prefers real upstream streaming by default; when a model has
streaming: false, a non-streaming request is sent directly. If a compatible vendor explicitly does not support streaming, fall back to a non-streaming request and log a warning. capabilitiesis optional; normalization fills intools=trueandvision=defaultVision.- When
useModelsEndpoint: true, refreshing the model list syncs add/remove byname; existing manual model entries in settings stay unchanged and are not overwritten by/modelsor models.dev results. Only models not present in settings are added, filled with auto metadata such asdescription,capabilities,contextSize,price; existing legacy fallback structures generated by the extension can be replaced by new models.dev metadata. - Saving settings only refreshes runtime-configured models by default; config-change listeners must not automatically request
/modelsor write backcoding-plans.vendors[].models. Only the manual commandCoding Plans: Update Coding Plans Models Listis allowed to dynamically discover and write back the model list.coding-plans.autoRefreshModels: falsefurther forbids settings/API-key changes and empty model-picker queries from triggering automatic runtime refresh, but manual refresh commands still work. - If you modify protocol-related behavior, check in sync:
src/providers/genericProvider.tssrc/config/configStore.tspackage.jsonREADME.mdREADME.zh-CN.md