Skip to content

Commit 3defacd

Browse files
CodeKingKilo
andcommitted
Merge integration: tool-call pipeline fixes, browser tools, UI cleanup
Brings in 9 commits from integration branch: - fix(ui): strip malformed tool-call markup fragments from chat display - fix(browser): click_browser_by_text context-destroyed in getSummary (Round 2) - fix(browser): click_browser_by_text 'context destroyed' false error - fix(tools): generate_image 'None' sentinel + playwright-core bundling - fix(tools): MiMo serialization, shell selection, duplicate messages + prior WIP - fix(tools): narrow RecoverableAssistantBlock name access in recovery tests - fix(tools): execute MiniMax/Hermes XML tool recovery end-to-end - fix(tools): recover textual tool_calls and harden tool selection - feat(spec-workspace): selection context intelligence, sanitization boundary, tool reliability All tools verified working on both Xiaomi built-in and OpenAI Compatible providers. Co-authored-by: Kilo <kilo@kilocode.com>
2 parents 71a167f + 67e1cf9 commit 3defacd

160 files changed

Lines changed: 24030 additions & 496 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,8 @@ qdrant_storage/
5555
plans/
5656

5757
roo-cli-*.tar.gz*
58+
59+
# Temporary one-off fix scripts
60+
fix_spec.js
61+
fix_spec.mjs
62+
tmp-*.mjs

packages/types/src/model.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,18 @@ export type ServiceTier = z.infer<typeof serviceTierSchema>
6565
* ModelParameter
6666
*/
6767

68-
export const modelParameters = ["max_tokens", "temperature", "reasoning", "include_reasoning"] as const
68+
export const modelParameters = [
69+
"max_tokens",
70+
"temperature",
71+
"reasoning",
72+
"include_reasoning",
73+
// Tool-calling parameters (OpenRouter-style supported_parameters contract). Presence in
74+
// a model's supportedParameters allow-list signals the endpoint accepts these fields;
75+
// absence tells generic OpenAI-compatible handlers to omit them for compatibility.
76+
"tools",
77+
"tool_choice",
78+
"parallel_tool_calls",
79+
] as const
6980

7081
export const modelParametersSchema = z.enum(modelParameters)
7182

packages/types/src/roomodes-schema.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import { toolGroups, deprecatedToolGroups } from "./tool.js"
1212
import { groupOptionsSchema, modeConfigSchema } from "./mode.js"
1313

1414
// Build a ToolGroup enum that includes deprecated groups so existing configs
15-
// still validate.
16-
const allToolGroups = [...toolGroups, ...deprecatedToolGroups] as [string, ...string[]]
15+
// still validate. Deduplicated: a group may be listed as deprecated while still
16+
// being active (e.g. "browser"), and JSON Schema rejects an enum with duplicate
17+
// items, which would make the generated schema fail to compile.
18+
const allToolGroups = [...new Set<string>([...toolGroups, ...deprecatedToolGroups])] as [string, ...string[]]
1719
const allToolGroupsSchema = z.enum(allToolGroups)
1820

1921
// Build a GroupEntry schema that uses the extended tool group list.

packages/types/src/task.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export type TaskProviderEvents = {
8585

8686
export interface CreateTaskOptions {
8787
taskId?: string
88+
/** Internal context sent to the model for the initial request only; never rendered in chat. */
89+
initialHiddenContext?: string
8890
enableCheckpoints?: boolean
8991
consecutiveMistakeLimit?: number
9092
experiments?: Record<string, boolean>

packages/types/src/tool.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ export const toolNames = [
8989
"toggle_mcp_server",
9090
"delete_mcp_server",
9191
"refresh_mcp_servers",
92+
// Virtual Spec Workspace (F-004 / F-022) — globalStorage only, never project files
93+
"list_specs",
94+
"read_spec",
95+
"write_spec",
96+
"delete_spec",
9297
] as const
9398

9499
export const toolNamesSchema = z.enum(toolNames)

packages/types/src/vscode-extension-host.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ export interface ExtensionMessage {
108108
| "fileContent"
109109
| "rooHistoryImportProgress"
110110
text?: string
111+
/** Opaque, one-use context token associated with a visible chat prefill. */
112+
selectionContextToken?: string
113+
/** The AI selection action type (rewrite/improve/remove/custom) for pill rendering. */
114+
selectionContextAction?: string
111115
/** For fileContent: { path, content, error? } */
112116
fileContent?: { path: string; content: string | null; error?: string }
113117
payload?: any // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -668,6 +672,8 @@ export interface WebviewMessage {
668672
| "renameTask"
669673
text?: string
670674
taskId?: string
675+
/** Opaque, one-use context token associated with a visible chat prefill. */
676+
selectionContextToken?: string
671677
editedMessageContent?: string
672678
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"
673679
disabled?: boolean
@@ -878,7 +884,25 @@ export interface ClineSayTool {
878884
| "listMcpConfig"
879885
| "getMcpServer"
880886
| "refreshMcpServers"
887+
// Virtual Spec Workspace tools (F-004 / F-019 / F-022 activity mapping)
888+
| "list_specs"
889+
| "read_spec"
890+
| "write_spec"
891+
| "delete_spec"
881892
path?: string
893+
/** write_spec / read_spec document kind */
894+
doc?: string
895+
/** write_spec: create|write; delete_spec: delete|delete_bulk|delete_progress */
896+
action?: string
897+
/** write_spec pack title (create) / delete_spec title */
898+
title?: string
899+
/** write_spec / delete_spec pack id */
900+
specId?: string
901+
/** F-022b bulk delete progress */
902+
index?: number
903+
total?: number
904+
count?: number
905+
explicitBulk?: boolean
882906
// For readCommandOutput
883907
readStart?: number
884908
readEnd?: number

packages/types/src/vscode.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export const commandIds = [
4848
"toggleAutoApprove",
4949

5050
"showRipgrepDiagnostic",
51+
52+
/** Open virtual Spec Workspace panel (F-002) */
53+
"openSpecWorkspace",
5154
] as const
5255

5356
export type CommandId = (typeof commandIds)[number]

schemas/roomodes.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,16 @@
4444
"anyOf": [
4545
{
4646
"type": "string",
47-
"enum": ["read", "edit", "command", "mcp", "modes", "browser"]
47+
"enum": [
48+
"read",
49+
"edit",
50+
"command",
51+
"mcp",
52+
"modes",
53+
"browser",
54+
"provider_manage",
55+
"mcp_manage"
56+
]
4857
},
4958
{
5059
"type": "array",
@@ -53,7 +62,16 @@
5362
"items": [
5463
{
5564
"type": "string",
56-
"enum": ["read", "edit", "command", "mcp", "modes", "browser"]
65+
"enum": [
66+
"read",
67+
"edit",
68+
"command",
69+
"mcp",
70+
"modes",
71+
"browser",
72+
"provider_manage",
73+
"mcp_manage"
74+
]
5775
},
5876
{
5977
"type": "object",

src/activate/registerCommands.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ const getCommandsMap = ({
157157
const { promptForCustomStoragePath } = await import("../utils/storage")
158158
await promptForCustomStoragePath()
159159
},
160+
openSpecWorkspace: async () => {
161+
const { SpecWorkspacePanel } = await import("../core/specs/ui/SpecWorkspacePanel")
162+
const globalStoragePath = provider.contextProxy.globalStorageUri.fsPath
163+
SpecWorkspacePanel.createOrShow({
164+
context,
165+
globalStoragePath,
166+
getWorkspaceRoot: () => provider.cwd,
167+
outputChannel,
168+
})
169+
},
160170
importSettings: async (filePath?: string) => {
161171
const visibleProvider = getVisibleProviderOrLog(outputChannel)
162172
if (!visibleProvider) {

src/api/providers/__tests__/base-provider.spec.ts

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,24 @@ class TestProvider extends BaseProvider {
2222
}
2323
}
2424

25-
// Expose protected method for testing
25+
// Expose protected method for testing (schema rewrite used when enableStrict: true)
2626
public testConvertToolSchemaForOpenAI(schema: any): any {
27-
return this.convertToolsForOpenAI(schema)
27+
return this.convertToolSchemaForOpenAI(schema)
2828
}
2929

3030
// Expose protected method for testing
31-
public testConvertToolsForOpenAI(tools: any[] | undefined): any[] | undefined {
32-
return this.convertToolsForOpenAI(tools)
31+
public testConvertToolsForOpenAI(
32+
tools: any[] | undefined,
33+
options?: { enableStrict?: boolean },
34+
): any[] | undefined {
35+
return this.convertToolsForOpenAI(tools, options)
36+
}
37+
38+
public convertToolsForOpenAIPublic(
39+
tools: any[] | undefined,
40+
options?: { enableStrict?: boolean },
41+
): any[] | undefined {
42+
return this.convertToolsForOpenAI(tools, options)
3343
}
3444

3545
// Expose private method for testing via any cast (private methods cannot be overridden)
@@ -166,21 +176,56 @@ describe("BaseProvider", () => {
166176
expect(result).toBeUndefined()
167177
})
168178

169-
it("should set strict: true for non-MCP tools", () => {
179+
it("defaults to strict: false for non-MCP tools (third-party gateway safe)", () => {
170180
const tools = [
171181
{
172182
type: "function",
173183
function: {
174184
name: "read_file",
175185
description: "Read a file",
176-
parameters: { type: "object", properties: {} },
186+
parameters: {
187+
type: "object",
188+
properties: {
189+
path: { type: "string" },
190+
limit: { type: "number" },
191+
},
192+
required: ["path"],
193+
},
177194
},
178195
},
179196
]
180197

181198
const result = provider.testConvertToolsForOpenAI(tools)
182199

200+
expect(result?.[0].function.strict).toBe(false)
201+
// Optional params must stay optional (not rewritten to required: all keys)
202+
expect(result?.[0].function.parameters.required).toEqual(["path"])
203+
})
204+
205+
it("should set strict: true when enableStrict is true", () => {
206+
const tools = [
207+
{
208+
type: "function",
209+
function: {
210+
name: "read_file",
211+
description: "Read a file",
212+
parameters: {
213+
type: "object",
214+
properties: {
215+
path: { type: "string" },
216+
limit: { type: "number" },
217+
},
218+
required: ["path"],
219+
},
220+
},
221+
},
222+
]
223+
224+
const result = provider.convertToolsForOpenAIPublic(tools, { enableStrict: true })
225+
183226
expect(result?.[0].function.strict).toBe(true)
227+
expect(result?.[0].function.parameters.required).toEqual(["path", "limit"])
228+
expect(result?.[0].function.parameters.additionalProperties).toBe(false)
184229
})
185230

186231
it("should set strict: false for MCP tools (mcp-- prefix)", () => {

0 commit comments

Comments
 (0)