Repository navigation
copilot: add a VS Code extension that serves Databricks models to Copilot Chat - #1314
Conversation
Polly AI ReviewBlocking issues
Security vulnerabilities
Non-blocking notes
ApproachThe protocol split and shared message-part helpers fit the goal. Reuse the existing distinction between ordinary token retrieval and forced renewal for 401 recovery. No materially simpler replacement for the two wire-format adapters was identified. SummaryDiff size (computed): 32 files; +3635 / -0 lines (3635 changed text lines); 0 binary files.
Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements. ChangesThe PR adds provider registration, settings and model metadata, authentication, Chat Completions and Responses adapters, streaming conversion, logging, build tooling, CI, tests, licensing documentation, dependencies, and committed distribution assets. The size is broadly justified by introducing a separate extension and shipping its bundled dependencies. The staged manifest/license copies have a concrete packaging purpose and a rebuild-drift check. Beyond the unused cancellation instrumentation noted above, no substantial removable duplication was identified. TestsTest-by-test assessmentThis is a static assessment. Tests, typecheck, build, wheel contents, and byte-identical rebuilding were not executed or independently verified. Existing auth/proxy tests were inspected for context, but they do not establish the extension’s configuration precedence or external-helper refresh behavior. Environment limitation: OpenCode, Cursor, Hermes, Pi, and Antigravity CLIs were unavailable on PATH.
The two demonstrated defects need configuration-isolation and forced-refresh regressions. Existing adapter and SDK-component tests are otherwise appropriately layered; duplicating their assertions in live E2E tests is unnecessary. A focused extension-host check uniquely establishes real VS Code configuration precedence. After fixes, run ScopeAll inspected changes support the stated extension outcome; no clearly unrelated changes were found. Deferring Automated review by Polly · workflow run |
ec13431 to
9e8bdc9
Compare
|
Thanks. Addressed in 9e8bdc9, which also rewrites the extension smaller: no runtime dependencies, four source files, a 10 KB bundle.
|
9e8bdc9 to
33e1816
Compare
A language model chat provider for VS Code (vscode-extension/, TypeScript). It adds the workspace's AI Gateway models to the chat model picker and calls the gateway directly, with no local proxy and no runtime dependencies: Chat Completions (/ai-gateway/mlflow/v1/chat/completions) for Claude and open models, and stateless Responses (/ai-gateway/mlflow/v1/responses) for GPT-5 and later, which reject function tools on Chat Completions. Streaming, tool calls, tool results and images work on both. It reads unityGateway.workspace, unityGateway.models and unityGateway.authCommand from user settings only, so a workspace's settings can't redirect the token or choose the command that prints it. The token comes from running the auth command (ug auth-token), is kept in memory until shortly before it expires, and after a 401 is fetched again with --force-refresh. Nothing is stored. Refresh Models re-reads the settings. The minified bundle and package.json are built into src/ucode/vscode/extension/ and committed, so ug can pack and install the extension without Node; CI fails when they are stale, and the job is part of the required test check. ug configure doesn't install it yet. Co-authored-by: Isaac <no-reply@databricks.com>
Drops vitest, which made up about two-thirds of the lockfile. esbuild, already used for the bundle, compiles the tests with `vscode` aliased to the test stand-in, and `node --test` runs them. Nothing shipped changes. Co-authored-by: Isaac <no-reply@databricks.com>
The default import inlined the whole manifest into the bundle, so any package.json edit changed it. The User-Agent is now a small tested function. Co-authored-by: Isaac <no-reply@databricks.com>
While a Claude model thinks, the AI Gateway's Chat Completions stream sends
`delta.content` as a list of blocks instead of a string:
{"choices":[{"delta":{"content":[{"type":"reasoning","summary":[...]}]}}]}
The extension passed that list straight into a `LanguageModelTextPart`, and
Copilot Chat's agent loop then failed the whole turn with "Cannot read
properties of undefined (reading 'length')" before the model's tool call ran.
Whether a model thinks depends on the prompt, so the same model would answer
some requests and fail others.
Take the text out of the blocks instead, and drop the reasoning.
Co-authored-by: Isaac <no-reply@databricks.com>
The chat model picker and Manage Language Models showed VS Code's generic icon next to the Databricks provider. Give the provider the Databricks logo: one SVG in the brand red, which reads on light and dark themes. The build copies it next to the bundle so ug ships it. Co-authored-by: Isaac <no-reply@databricks.com>
Every model reported 128K input and 32K output tokens, so VS Code showed a 160K context window for all of them, and Copilot Chat compacted a Claude conversation at 128K although these models take far more. A model entry in unityGateway.models can now carry maxInputTokens and maxOutputTokens. Models without them keep 128K / 32K. Co-authored-by: Isaac <no-reply@databricks.com>
927bcc0 to
238af81
Compare
masonc08
left a comment
There was a problem hiding this comment.
approving to put in a working version but followups should be completed
🥞 Stacked PR
Use this link to review incremental changes.
What
First of two PRs that bring Databricks models to Copilot Chat in VS Code. This PR adds the extension; the next one makes
ug configure --agents vscodepack, install and configure it.The extension (
vscode-extension/, TypeScript, no runtime dependencies) registers a language model chat provider. It puts the workspace's AI Gateway models in the chat model picker, in both Ask and Agent mode and in both the Local and Copilot harnesses. It calls the gateway directly withfetch, with no local proxy:{workspace}/ai-gateway/mlflow/v1/chat/completions) for Claude. The next PR'sug configureoffers only Claude and GPT models, the same set as Copilot CLI.{workspace}/ai-gateway/mlflow/v1/responses) for GPT-5 and later. It's stateless:store: false, and the whole conversation is sent each turn. GPT-5.6 and later reject function tools on Chat Completions, as do the codex and pro models, so they need this route for Agent mode.Settings, which
ug configurewill write to the user settings:unityGateway.workspaceunityGateway.models[{"id": "<model service>", "api": "chat_completions" | "responses", "maxInputTokens"?: n, "maxOutputTokens"?: n}]unityGateway.authCommandug auth-token --host ...command ug already writes for other agentsAll three are
"scope": "application", so VS Code reads them from user settings only. A repository's.vscode/settings.jsoncan't redirect the token to another URL, or pick the command that prints it.Auth. The extension runs the auth command when it needs a token, keeps the token in memory until five minutes before its
exp, and shares one fetch between concurrent requests. When the gateway answers 401 it runs the command again with--force-refresh, because the Databricks CLI can return its cached token whileexpis still ahead, and retries once. If that also fails, it reports "Databricks rejected the sign-in. Rundatabricks auth login --host ..., then retry." It stores no credentials, and the token is never logged.Other behavior:
ucode/<extension version> githubcopilotchat/<Copilot Chat version>. The gateway already attributes thegithubcopilotchattoken to Copilot Chat.familyis the model's own name (claude-sonnet-5-5,gpt-6-luna), which Copilot Chat uses to pick its prompts and tools. The gateway doesn't report context limits, so a model's limits come from itsmaxInputTokens/maxOutputTokenssettings, and a model without them gets 128K input and 32K output (Copilot's own default). Image input is on for Claude and Responses models. Token counts are about four characters per token, plus a flat 1,000 per image.media/databricks.svg, in the brand red) in the model picker.Unity Gateway: Refresh Modelsre-reads the settings; settings changes also refresh.extensionKind: ["ui"], engine^1.128.0(the first version that offers extension models in the Copilot harness).Packaging.
npm run build(esbuild, minified) writessrc/ucode/vscode/extension/out/extension.js(9 KB) and copiespackage.jsonandmedia/next to it. Both are committed, so the wheel ships them and ug can pack the vsix with the standard library: no Node on users' machines, no binary in the repo.just vscode-buildrebuilds them, and rebuilds are byte-identical..gitattributesmarks the bundle as generated.CI. A new
VS Code extensionjob runsnpm ci(with the npm cache), typecheck and the tests. It then rebuilds and fails if the committed files undersrc/ucode/vscode/extension/changed. Thetestcheck that branch rules require now needs this job too.package-lock.jsonrecords the public npm registry;.npmrcsetsreplace-registry-host=always, sonpm cifetches the same tarballs from whatever registry is configured locally.Not in this PR
ug configuredoesn't install or configure the extension yet; that's the next PR.Validation
npm run typecheckis clean.npm testruns 25 cases with Node's own test runner (esbuild compiles them, withvscodealiased to a test stand-in, so the only dev dependencies are esbuild, TypeScript and type packages):--force-refreshafter a rejection but not after a stale one or while a fetch is in flight, command failure and empty output;[DONE]and a last event without a trailing newline; one forced retry after 401, then the sign-in message; other errors with the gateway's body;apiwith the User-Agent;just lintpasses. The PR changes no Python.claude-haiku-5-5, Chat Completions): file written, in both the Local and the Copilot harness.gpt-6-luna, Responses): file written, in both the Local and the Copilot harness.deepseek-v4-1-flash(Chat Completions): file written..vscode/settings.jsonsetunityGateway.workspaceto another host andunityGateway.authCommandto a different command. Both were ignored: the task completed through the user-level settings, and the workspace's command never ran.gpt-oss-120b, tested on an earlier version: with Copilot's full 49-tool request, the model reasons about the tool call and then stops without making it. The gateway's response contains no tool call.This pull request and its description were written by Isaac.