mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 01:51:21 +08:00
fix(vscode): allow agent-only switch links
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Support VS Code switch links that select a Kilo model and optional agent.
|
||||
Support VS Code switch links that select a Kilo model, agent, or both.
|
||||
|
||||
@@ -142,19 +142,21 @@ The model selection is remembered per mode across sessions.
|
||||
|
||||
For details on configuring subagent models, see [Custom Subagents](/docs/customize/custom-subagents).
|
||||
|
||||
## Selecting a Model via a Link (VS Code)
|
||||
## Selecting a Model or Agent via a Link (VS Code)
|
||||
|
||||
The VS Code extension supports a `vscode://` protocol handler that lets you open VS Code and automatically select a specific model — no manual picker interaction required. This is useful for sharing model recommendations, launching a specific model tier from a web page, or switching quickly to a newly announced model.
|
||||
The VS Code extension supports a `vscode://` protocol handler that lets you open VS Code and automatically select a model, an agent, or both — no manual picker interaction required. This is useful for sharing model recommendations, launching a specific model tier from a web page, or switching quickly to a preferred agent.
|
||||
|
||||
### URL Format
|
||||
|
||||
Include at least one of the `model` or `agent` parameters:
|
||||
|
||||
```
|
||||
vscode://kilocode.kilo-code/kilocode/switch?model=<modelID>[&agent=<agentName>]
|
||||
vscode://kilocode.kilo-code/kilocode/switch?model=<modelID>
|
||||
vscode://kilocode.kilo-code/kilocode/switch?agent=<agentName>
|
||||
vscode://kilocode.kilo-code/kilocode/switch?model=<modelID>&agent=<agentName>
|
||||
```
|
||||
|
||||
Replace `<modelID>` with the Kilo Gateway model ID you want to select (e.g. `kilo-auto/free`). Only models available in the Kilo Gateway catalog are accepted; the link is silently ignored if the model ID is not found.
|
||||
|
||||
The optional `agent` parameter switches to a visible primary agent before selecting the model. Use the agent's ID, such as `code` or `plan`, rather than its display name. `mode` is also accepted as an alias for `agent`.
|
||||
Replace `<modelID>` with a Kilo Gateway model ID such as `kilo-auto/free`. Replace `<agentName>` with a visible primary agent ID such as `code` or `plan`, rather than its display name. `mode` is also accepted as an alias for `agent`.
|
||||
|
||||
### Example: Auto Free
|
||||
|
||||
@@ -164,7 +166,13 @@ To open Kilo Code and switch to the [Auto Free](/docs/code-with-ai/agents/auto-m
|
||||
vscode://kilocode.kilo-code/kilocode/switch?model=kilo-auto%2Ffree
|
||||
```
|
||||
|
||||
To switch to Plan at the same time, add the optional agent:
|
||||
To switch only to Plan and use its normal model selection, specify the agent without a model:
|
||||
|
||||
```
|
||||
vscode://kilocode.kilo-code/kilocode/switch?agent=plan
|
||||
```
|
||||
|
||||
To select both at the same time, include both parameters:
|
||||
|
||||
```
|
||||
vscode://kilocode.kilo-code/kilocode/switch?model=kilo-auto%2Ffree&agent=plan
|
||||
@@ -176,11 +184,12 @@ URL-encode the `/` in model IDs as `%2F` when embedding this URL in HTML links o
|
||||
|
||||
### How It Works
|
||||
|
||||
- **VS Code open**: the Kilo sidebar is focused and the model is selected in the active session immediately.
|
||||
- **VS Code closed**: VS Code launches, then applies the model selection once the extension is ready.
|
||||
- The model is validated against the current Kilo Gateway model catalog before being applied. If the model ID is not found in the catalog, the deep link is silently ignored.
|
||||
- **VS Code open**: the Kilo sidebar is focused and the linked selection is applied to the active session immediately.
|
||||
- **VS Code closed**: VS Code launches, then applies the selection once the extension is ready.
|
||||
- When `model` is provided, it must identify a model in the current Kilo Gateway catalog. Invalid or unavailable models cause the deep link to be ignored.
|
||||
- When `agent` or `mode` is provided, it must identify a visible primary agent. Invalid or unavailable agents cause the deep link to be ignored.
|
||||
- The agent is selected before the model so the linked model applies to that agent. The selection follows the same precedence as using the pickers: it updates the active session, or the next session when no session is active. It does **not** change your configured defaults in settings.
|
||||
- An agent-only link uses the model that would normally be selected for that agent. When both parameters are present, the agent is selected first so the linked model applies to it.
|
||||
- The selection follows the same precedence as using the pickers: it updates the active session, or the next session when no session is active. It does **not** change your configured defaults in settings.
|
||||
|
||||
### Sharing and Embedding
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
private configWarningsShown = false
|
||||
/** Cached notificationsLoaded payload */
|
||||
private cachedNotificationsMessage: unknown = null
|
||||
private pendingKiloModel: { modelID: string; agent?: string } | null = null
|
||||
private pendingKiloModel: { modelID?: string; agent?: string } | null = null
|
||||
private pendingReviewComments: { comments: unknown[]; autoSend: boolean }[] = []
|
||||
private readyResolvers: (() => void)[] = []
|
||||
private promptRecoveryQueued = false
|
||||
@@ -716,8 +716,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
this.postMessage({ type: "openCloudSession", sessionId })
|
||||
}
|
||||
|
||||
public selectKiloModel(modelID: string, agent?: string): void {
|
||||
this.pendingKiloModel = { modelID, ...(agent && { agent }) }
|
||||
public selectKiloModel(modelID?: string, agent?: string): void {
|
||||
if (!modelID && !agent) return
|
||||
this.pendingKiloModel = { ...(modelID && { modelID }), ...(agent && { agent }) }
|
||||
this.flushPendingKiloModel()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ export function parseSwitchLink(path: string, query: string) {
|
||||
if (!paths.has(path)) return
|
||||
|
||||
const params = new URLSearchParams(query)
|
||||
const modelID = params.get("model")
|
||||
if (!modelID) return
|
||||
|
||||
const modelID = params.get("model") || undefined
|
||||
const agent = params.get("agent") || params.get("mode") || undefined
|
||||
return { modelID, ...(agent && { agent }) }
|
||||
if (!modelID && !agent) return
|
||||
|
||||
return { ...(modelID && { modelID }), ...(agent && { agent }) }
|
||||
}
|
||||
|
||||
@@ -8,16 +8,21 @@ describe("parseSwitchLink", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("includes an optional agent", () => {
|
||||
it("parses an agent without a model", () => {
|
||||
expect(parseSwitchLink("/kilocode/switch", "agent=plan")).toEqual({
|
||||
agent: "plan",
|
||||
})
|
||||
})
|
||||
|
||||
it("parses a model and agent together", () => {
|
||||
expect(parseSwitchLink("/kilocode/switch", "model=kilo-auto%2Ffree&agent=plan")).toEqual({
|
||||
modelID: "kilo-auto/free",
|
||||
agent: "plan",
|
||||
})
|
||||
})
|
||||
|
||||
it("accepts mode as an agent alias", () => {
|
||||
expect(parseSwitchLink("/kilocode/switch", "model=kilo-auto%2Ffree&mode=code")).toEqual({
|
||||
modelID: "kilo-auto/free",
|
||||
it("accepts mode as an agent alias without a model", () => {
|
||||
expect(parseSwitchLink("/kilocode/switch", "mode=code")).toEqual({
|
||||
agent: "code",
|
||||
})
|
||||
})
|
||||
@@ -35,8 +40,8 @@ describe("parseSwitchLink", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("rejects unsupported routes and missing models", () => {
|
||||
it("rejects unsupported routes and empty selections", () => {
|
||||
expect(parseSwitchLink("/kilocode/other", "model=kilo-auto%2Ffree")).toBeUndefined()
|
||||
expect(parseSwitchLink("/kilocode/switch", "agent=plan")).toBeUndefined()
|
||||
expect(parseSwitchLink("/kilocode/switch", "")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -369,7 +369,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
const [allAgents, setAllAgents] = createSignal<AgentInfo[]>([])
|
||||
const [defaultAgent, setDefaultAgent] = createSignal("code")
|
||||
const [pendingKiloModel, setPendingKiloModel] = createSignal<{
|
||||
modelID: string
|
||||
modelID?: string
|
||||
agent?: string
|
||||
after: number
|
||||
} | null>(null)
|
||||
@@ -602,9 +602,10 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
function selectKiloModel(modelID: string, agent?: string) {
|
||||
setPendingKiloModel({ modelID, ...(agent && { agent }), after: catalog() })
|
||||
vscode.postMessage({ type: "requestProviders" })
|
||||
function selectKiloModel(modelID?: string, agent?: string) {
|
||||
if (!modelID && !agent) return
|
||||
setPendingKiloModel({ ...(modelID && { modelID }), ...(agent && { agent }), after: catalog() })
|
||||
if (modelID) vscode.postMessage({ type: "requestProviders" })
|
||||
}
|
||||
|
||||
const unsubKiloModel = vscode.onMessage((message: ExtensionMessage) => {
|
||||
@@ -618,9 +619,9 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
|
||||
createEffect(() => {
|
||||
const pending = pendingKiloModel()
|
||||
if (!pending || agents().length === 0 || catalog() <= pending.after) return
|
||||
if (!pending || agents().length === 0 || (pending.modelID && catalog() <= pending.after)) return
|
||||
setPendingKiloModel(null)
|
||||
if (!provider.providers()[KILO_PROVIDER_ID]?.models[pending.modelID]) {
|
||||
if (pending.modelID && !provider.providers()[KILO_PROVIDER_ID]?.models[pending.modelID]) {
|
||||
console.warn("[Kilo New] Ignoring unavailable Kilo catalog model:", pending.modelID)
|
||||
return
|
||||
}
|
||||
@@ -629,7 +630,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
return
|
||||
}
|
||||
if (pending.agent) selectAgent(pending.agent)
|
||||
selectModel(KILO_PROVIDER_ID, pending.modelID)
|
||||
if (pending.modelID) selectModel(KILO_PROVIDER_ID, pending.modelID)
|
||||
})
|
||||
|
||||
function promptAgent(sessionID?: string) {
|
||||
|
||||
@@ -241,7 +241,7 @@ export interface OpenCloudSessionMessage {
|
||||
|
||||
export interface SelectKiloModelMessage {
|
||||
type: "selectKiloModel"
|
||||
modelID: string
|
||||
modelID?: string
|
||||
agent?: string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user