Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,24 @@ model for one launch. OpenCode's `provider/model` form is also accepted.
Unknown Databricks models produce an error; this option does not add models
to discovery or change ug's saved default.

`ug copilot` uses the Anthropic Messages API for Claude model IDs, the Responses
API for GPT-5 and newer model IDs, and Chat Completions for other models. The
model selected at launch (including `--model`) determines the API. An inherited `COPILOT_PROVIDER_WIRE_MODEL` takes precedence
because it overrides the model sent to the gateway. Restart Copilot through `ug`
to change the wire model or API; in-session model selection does not rebuild its
provider configuration.
`ug copilot` lists every Claude and GPT model you can use on the workspace in
Copilot's `/model` picker, and you can switch between them mid-session. Claude
models use the Anthropic Messages API, GPT-5 and newer use Responses, and older
GPT models use Chat Completions. Gemini and open-source models aren't offered.
`ug copilot --model claude-opus-5-5` (or `system.ai.claude-opus-5-5`, or Copilot's
own `dbx-anthropic/system.ai.claude-opus-5-5`) picks the model a session starts on;
an unknown or unsupported model fails before Copilot starts and lists the
available ones. ug passes Copilot a per-session model registry, so your own
`~/.copilot/providers.json` and `COPILOT_PROVIDER_*` settings apply only to plain
`copilot`. Use plain `/model`, not `/model --global`, inside `ug copilot`: a
global choice is saved for plain `copilot` too, where the Databricks models don't
exist. Requires Copilot CLI 1.0.91 or newer.

`ug copilot` runs Copilot against a loopback proxy for the session. Copilot holds only
a random session secret; the proxy adds a fresh Databricks token to each gateway
request, so OAuth sessions keep working past token expiry without a restart, and no
token is written to `~/.copilot/ucode.env`. If the Databricks sign-in itself expires,
a random session secret, kept in the session's `~/.copilot/ug-providers-<id>.json`
registry (readable only by you, deleted when the session ends); the proxy adds a fresh Databricks token to
each gateway request, so OAuth sessions keep working past token expiry without a
restart, and no Databricks token is written to disk. If the Databricks sign-in itself expires,
Copilot shows a "Databricks sign-in expired" error; run `databricks auth login` and
restart `ug copilot`. Proxy errors are logged to `~/.ucode/logs/copilot-proxy.log`.

Expand Down
7 changes: 7 additions & 0 deletions scripts/run_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,13 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str:
runtime_paths = [runtime_bin, agent_bin, tool_bin]
if os.name == "nt":
system_root = Path(base_env["SYSTEMROOT"])
# Copilot's shell tool tries pwsh first; Windows PowerShell alone can miss its 40s
# startup probe. pwsh loads pwsh.dll beside it, so it can't go in tool_bin; expose
# only a dedicated install dir, never a shared alias dir like WindowsApps.
pwsh = shutil.which("pwsh", path=base_env.get("PATH"))
pwsh_dir = Path(pwsh).resolve().parent if pwsh else None
if "copilot" in agents and pwsh_dir and (pwsh_dir / "pwsh.dll").is_file():
runtime_paths.append(pwsh_dir)
runtime_paths.extend(
[
system_root / "System32",
Expand Down
4 changes: 2 additions & 2 deletions src/ucode/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ def check_gateway_endpoint(state: dict, tool: str) -> bool:
if tool == "gemini":
return bool(state.get("gemini_models"))
if tool == "copilot":
return bool(state.get("claude_models")) or bool(state.get("codex_models"))
return bool(copilot.copilot_catalog(state))
if tool == "pi":
return (
bool(state.get("claude_models"))
Expand All @@ -545,7 +545,7 @@ def check_gateway_endpoint(state: dict, tool: str) -> bool:
"kilo": ("claude", "gemini", "oss"),
"codex": ("codex",),
"gemini": ("gemini",),
"copilot": ("claude", "codex"),
"copilot": ("copilot",),
"pi": ("claude", "codex", "gemini"),
}

Expand Down
1 change: 1 addition & 0 deletions src/ucode/agents/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class LaunchOptions:

launch_smart_routing: bool = False
user_pinned_model: str | None = None
launch_model: str | None = None


def explicit_model_arg_value(tool_args: list[str]) -> str | None:
Expand Down
Loading
Loading