mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #12982 from Kilo-Org/investigate-kilocode-luna-openai-usage-leak
feat(vscode): sync model selector with slash command overrides
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Update the active model, mode, and thinking selectors when executing a slash command with configured overrides.
|
||||
@@ -13,12 +13,18 @@ export async function loadCommands(client: KiloClient, dir: string): Promise<unk
|
||||
|
||||
const promise = retry(() => client.command.list({ directory: dir }, { throwOnError: true })).then(({ data }) => ({
|
||||
type: "commandsLoaded",
|
||||
commands: data.map((cmd) => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description,
|
||||
source: cmd.source,
|
||||
hints: cmd.hints,
|
||||
})),
|
||||
commands: data.map((cmd) => {
|
||||
const item = cmd as typeof cmd & { variant?: string }
|
||||
return {
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
agent: item.agent,
|
||||
model: item.model,
|
||||
variant: item.variant,
|
||||
source: item.source,
|
||||
hints: item.hints,
|
||||
}
|
||||
}),
|
||||
}))
|
||||
|
||||
promises.set(dir, promise)
|
||||
|
||||
@@ -78,6 +78,15 @@ describe("sendCommand dismisses pending tool requests", () => {
|
||||
it("rejects questions before sending", () => {
|
||||
expect(body).toContain("dismissQuestion")
|
||||
})
|
||||
|
||||
it("applies model, agent, and variant overrides when provided by a command", () => {
|
||||
expect(body).toContain("if (overrides?.agent)")
|
||||
expect(body).toContain("selectAgent(overrides.agent, scope)")
|
||||
expect(body).toContain("if (overrides?.model)")
|
||||
expect(body).toContain("selectModel(parsed.providerID, parsed.modelID, scope)")
|
||||
expect(body).toContain("if (overrides?.variant)")
|
||||
expect(body).toContain("selectVariant(overrides.variant, scope)")
|
||||
})
|
||||
})
|
||||
|
||||
describe("static command completion contract", () => {
|
||||
|
||||
@@ -188,4 +188,31 @@ describe("useSlashCommand sandbox action", () => {
|
||||
expect(ctx.slash.results()[0]?.description).toBe("Toggle sandbox")
|
||||
ctx.dispose()
|
||||
})
|
||||
|
||||
it("preserves model, agent, and variant metadata on loaded server commands", () => {
|
||||
const ctx = setup(() => {})
|
||||
|
||||
ctx.fire({
|
||||
type: "commandsLoaded",
|
||||
commands: [
|
||||
{
|
||||
name: "ship",
|
||||
description: "Ship PR",
|
||||
agent: "code",
|
||||
model: "openai/gpt-5.6-luna-fast",
|
||||
variant: "xhigh",
|
||||
hints: ["deploy"],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
ctx.slash.onInput("/ship", 5)
|
||||
const matches = ctx.slash.results()
|
||||
expect(matches).toHaveLength(1)
|
||||
expect(matches[0]?.name).toBe("ship")
|
||||
expect(matches[0]?.agent).toBe("code")
|
||||
expect(matches[0]?.model).toBe("openai/gpt-5.6-luna-fast")
|
||||
expect(matches[0]?.variant).toBe("xhigh")
|
||||
ctx.dispose()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1239,6 +1239,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
pendingId,
|
||||
context,
|
||||
origin ?? null,
|
||||
{
|
||||
agent: matched.agent,
|
||||
model: matched.model,
|
||||
variant: matched.variant,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
session.sendMessage(message, sel?.providerID, sel?.modelID, attachments, pendingId, context, data, origin ?? null)
|
||||
|
||||
@@ -283,6 +283,7 @@ interface SessionContextValue {
|
||||
draftID?: string,
|
||||
context?: string,
|
||||
origin?: string | null,
|
||||
overrides?: { agent?: string; model?: string; variant?: string },
|
||||
) => void
|
||||
abort: () => void
|
||||
compact: () => void
|
||||
@@ -2352,31 +2353,51 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
draftID?: string,
|
||||
context?: string,
|
||||
origin?: string | null,
|
||||
overrides?: { agent?: string; model?: string; variant?: string },
|
||||
) {
|
||||
if (!server.isConnected()) {
|
||||
console.warn("[Kilo New] Cannot send command: not connected")
|
||||
return
|
||||
}
|
||||
|
||||
// Cloud previews need import-then-command; post importAndSend with command metadata
|
||||
const sid = origin === undefined ? currentSessionID() : (origin ?? undefined)
|
||||
const selection = providerID && modelID ? { providerID, modelID } : selected(sid)
|
||||
recordModelUsage(selection?.providerID, selection?.modelID)
|
||||
const effectiveDraftID = !sid && !draftID ? crypto.randomUUID() : draftID
|
||||
const scope = effectiveDraftID ?? sid
|
||||
if (!sid && !draftID && effectiveDraftID) agentDrafts.seed(effectiveDraftID)
|
||||
|
||||
if (overrides?.agent) {
|
||||
selectAgent(overrides.agent, scope)
|
||||
}
|
||||
if (overrides?.model) {
|
||||
const parsed = parseModelString(overrides.model)
|
||||
if (parsed) {
|
||||
selectModel(parsed.providerID, parsed.modelID, scope)
|
||||
}
|
||||
}
|
||||
if (overrides?.variant) {
|
||||
selectVariant(overrides.variant, scope)
|
||||
}
|
||||
|
||||
const effectiveSelection = selected(scope)
|
||||
const effectiveProvider = effectiveSelection?.providerID ?? providerID
|
||||
const effectiveModel = effectiveSelection?.modelID ?? modelID
|
||||
recordModelUsage(effectiveProvider, effectiveModel)
|
||||
|
||||
// Cloud previews need import-then-command; post importAndSend with command metadata
|
||||
const preview = sid?.startsWith("cloud:")
|
||||
? sid.slice("cloud:".length)
|
||||
: origin === undefined
|
||||
? cloudPreviewId()
|
||||
: null
|
||||
if (preview) {
|
||||
const scope = draftID ?? sid
|
||||
const agent = promptAgent(scope)
|
||||
vscode.postMessage({
|
||||
type: "importAndSend",
|
||||
cloudSessionId: preview,
|
||||
text: `/${command} ${args}`.trim(),
|
||||
messageID: Identifier.ascending("message"),
|
||||
providerID,
|
||||
modelID,
|
||||
providerID: effectiveProvider,
|
||||
modelID: effectiveModel,
|
||||
agent,
|
||||
variant: currentVariant(scope),
|
||||
files,
|
||||
@@ -2393,9 +2414,6 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
dismissQuestion(q.id)
|
||||
}
|
||||
|
||||
const effectiveDraftID = !sid && !draftID ? crypto.randomUUID() : draftID
|
||||
const scope = effectiveDraftID ?? sid
|
||||
if (!sid && !draftID && effectiveDraftID) agentDrafts.seed(effectiveDraftID)
|
||||
if (scope) {
|
||||
clearClose(scope)
|
||||
addOptimistic(scope, messageID, `/${command} ${args}`.trim(), files)
|
||||
@@ -2414,8 +2432,8 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
messageID,
|
||||
sessionID: sid,
|
||||
draftID: effectiveDraftID,
|
||||
providerID,
|
||||
modelID,
|
||||
providerID: effectiveProvider,
|
||||
modelID: effectiveModel,
|
||||
agent,
|
||||
variant: currentVariant(scope),
|
||||
files,
|
||||
|
||||
@@ -11,6 +11,9 @@ export interface SkillInfo {
|
||||
export interface SlashCommandInfo {
|
||||
name: string
|
||||
description?: string
|
||||
agent?: string
|
||||
model?: string
|
||||
variant?: string
|
||||
source?: "command" | "mcp" | "skill"
|
||||
hints: string[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user