mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 10:02:04 +08:00
Merge branch 'dev' into catrielmuller/kilo-opencode-v1.1.43
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
@@ -75,7 +75,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -109,7 +109,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -136,7 +136,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
@@ -160,7 +160,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -185,7 +185,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@opencode-ai/app": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
@@ -216,7 +216,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
@@ -245,7 +245,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "catalog:",
|
||||
@@ -261,7 +261,7 @@
|
||||
},
|
||||
"packages/kilo-gateway": {
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "1.0.0-alpha.1",
|
||||
"@kilocode/plugin": "workspace:*",
|
||||
@@ -303,7 +303,7 @@
|
||||
},
|
||||
"packages/kilo-telemetry": {
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
@@ -323,7 +323,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "@kilocode/cli",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -429,7 +429,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@kilocode/plugin",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -450,7 +450,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@kilocode/sdk",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.90.10",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -461,7 +461,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -474,7 +474,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -516,7 +516,7 @@
|
||||
},
|
||||
"packages/util": {
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
},
|
||||
@@ -527,7 +527,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
|
||||
@@ -33,10 +33,14 @@
|
||||
pkg-config
|
||||
openssl
|
||||
git
|
||||
gh
|
||||
playwright-driver.browsers
|
||||
kilo
|
||||
];
|
||||
shellHook = ''
|
||||
export KILO_ROOT="$PWD"
|
||||
export PLAYWRIGHT_BROWSERS_PATH="${pkgs.playwright-driver.browsers}"
|
||||
export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true
|
||||
'';
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "kilo"
|
||||
name = "Kilo"
|
||||
description = "The open source coding agent."
|
||||
version = "1.1.43"
|
||||
version = "1.0.14"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/Kilo-Org/kilo"
|
||||
@@ -11,26 +11,26 @@ name = "Kilo"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.1.43/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.14/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.1.43/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.14/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.1.43/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.14/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.1.43/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.14/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.1.43/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.14/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Telemetry for Kilo CLI - PostHog analytics integration",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"name": "@kilocode/cli",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -34,6 +34,7 @@ export namespace ProviderTransform {
|
||||
case "@ai-sdk/gateway":
|
||||
return "gateway"
|
||||
case "@openrouter/ai-sdk-provider":
|
||||
case "@kilocode/kilo-gateway": // kilocode_change
|
||||
return "openrouter"
|
||||
}
|
||||
return undefined
|
||||
@@ -66,7 +67,14 @@ export namespace ProviderTransform {
|
||||
.filter((msg): msg is ModelMessage => msg !== undefined && msg.content !== "")
|
||||
}
|
||||
|
||||
if (model.api.id.includes("claude")) {
|
||||
// kilocode_change - skip toolCallId normalization for OpenRouter/Kilo Gateway
|
||||
// OpenRouter handles tool call IDs differently and modifying messages can break
|
||||
// thinking/redacted_thinking blocks which must remain unchanged per Anthropic API
|
||||
if (
|
||||
model.api.id.includes("claude") &&
|
||||
model.api.npm !== "@openrouter/ai-sdk-provider" &&
|
||||
model.api.npm !== "@kilocode/kilo-gateway"
|
||||
) {
|
||||
return msgs.map((msg) => {
|
||||
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
|
||||
msg.content = msg.content.map((part) => {
|
||||
@@ -239,13 +247,89 @@ export namespace ProviderTransform {
|
||||
export function message(msgs: ModelMessage[], model: Provider.Model, options: Record<string, unknown>) {
|
||||
msgs = unsupportedParts(msgs, model)
|
||||
msgs = normalizeMessages(msgs, model, options)
|
||||
|
||||
// kilocode_change - skip caching for OpenRouter/Kilo Gateway to avoid modifying thinking blocks
|
||||
// Anthropic API requires thinking/redacted_thinking blocks to remain exactly unchanged
|
||||
const isOpenRouterOrKilo =
|
||||
model.api.npm === "@openrouter/ai-sdk-provider" || model.api.npm === "@kilocode/kilo-gateway"
|
||||
|
||||
// kilocode_change - strip thinking/reasoning blocks for OpenRouter/Kilo Gateway
|
||||
// Anthropic's API requires thinking blocks to be EXACTLY unchanged, but our storage
|
||||
// reconstructs them which counts as modification. Stripping them is safe because
|
||||
// the reasoning was already shown to the user and doesn't need to be sent back.
|
||||
if (isOpenRouterOrKilo) {
|
||||
// Helper to strip reasoning-related data from provider options/metadata
|
||||
const stripReasoningData = (opts: Record<string, any> | undefined) => {
|
||||
if (!opts) return undefined // Return undefined instead of empty object to clean up
|
||||
const result = { ...opts }
|
||||
// Strip from openrouter namespace
|
||||
if (result.openrouter) {
|
||||
result.openrouter = { ...result.openrouter }
|
||||
delete result.openrouter.reasoning_details
|
||||
delete result.openrouter.reasoning
|
||||
delete result.openrouter.thinking
|
||||
}
|
||||
// Strip from kilo namespace
|
||||
if (result.kilo) {
|
||||
result.kilo = { ...result.kilo }
|
||||
delete result.kilo.reasoning_details
|
||||
delete result.kilo.reasoning
|
||||
delete result.kilo.thinking
|
||||
}
|
||||
// Strip from anthropic namespace
|
||||
if (result.anthropic) {
|
||||
result.anthropic = { ...result.anthropic }
|
||||
delete result.anthropic.thinking
|
||||
delete result.anthropic.reasoning
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
msgs = msgs.flatMap((msg): ModelMessage[] => {
|
||||
// Handle string content (just strip metadata)
|
||||
if (!Array.isArray(msg.content)) {
|
||||
const result = { ...msg, providerOptions: stripReasoningData(msg.providerOptions) }
|
||||
if ("experimental_providerMetadata" in msg) {
|
||||
;(result as any).experimental_providerMetadata = stripReasoningData(
|
||||
(msg as any).experimental_providerMetadata,
|
||||
)
|
||||
}
|
||||
return [result]
|
||||
}
|
||||
// Filter out reasoning parts from content and strip metadata from remaining parts
|
||||
const filtered = msg.content
|
||||
.filter(
|
||||
(part: any) => part.type !== "thinking" && part.type !== "redacted_thinking" && part.type !== "reasoning",
|
||||
)
|
||||
.map((part: any) => ({
|
||||
...part,
|
||||
providerOptions: stripReasoningData(part.providerOptions),
|
||||
providerMetadata: stripReasoningData(part.providerMetadata),
|
||||
experimental_providerMetadata: stripReasoningData(part.experimental_providerMetadata),
|
||||
}))
|
||||
|
||||
// Providers may reject empty array content; drop empty messages.
|
||||
if (filtered.length === 0) return []
|
||||
|
||||
// Also strip from message-level options/metadata
|
||||
const result = { ...msg, content: filtered, providerOptions: stripReasoningData(msg.providerOptions) }
|
||||
if ("experimental_providerMetadata" in msg) {
|
||||
;(result as any).experimental_providerMetadata = stripReasoningData(
|
||||
(msg as any).experimental_providerMetadata,
|
||||
)
|
||||
}
|
||||
return [result as ModelMessage]
|
||||
})
|
||||
}
|
||||
|
||||
if (
|
||||
model.providerID === "anthropic" ||
|
||||
model.api.id.includes("anthropic") ||
|
||||
model.api.id.includes("claude") ||
|
||||
model.id.includes("anthropic") ||
|
||||
model.id.includes("claude") ||
|
||||
model.api.npm === "@ai-sdk/anthropic"
|
||||
!isOpenRouterOrKilo &&
|
||||
(model.providerID === "anthropic" ||
|
||||
model.api.id.includes("anthropic") ||
|
||||
model.api.id.includes("claude") ||
|
||||
model.id.includes("anthropic") ||
|
||||
model.id.includes("claude") ||
|
||||
model.api.npm === "@ai-sdk/anthropic")
|
||||
) {
|
||||
msgs = applyCaching(msgs, model.providerID)
|
||||
}
|
||||
@@ -330,7 +414,8 @@ export namespace ProviderTransform {
|
||||
|
||||
// see: https://docs.x.ai/docs/guides/reasoning#control-how-hard-the-model-thinks
|
||||
if (id.includes("grok") && id.includes("grok-3-mini")) {
|
||||
if (model.api.npm === "@openrouter/ai-sdk-provider") {
|
||||
if (model.api.npm === "@openrouter/ai-sdk-provider" || model.api.npm === "@kilocode/kilo-gateway") {
|
||||
// kilocode_change - add Kilo Gateway support
|
||||
return {
|
||||
low: { reasoning: { effort: "low" } },
|
||||
high: { reasoning: { effort: "high" } },
|
||||
@@ -348,8 +433,19 @@ export namespace ProviderTransform {
|
||||
if (!model.id.includes("gpt") && !model.id.includes("gemini-3")) return {}
|
||||
return Object.fromEntries(OPENAI_EFFORTS.map((effort) => [effort, { reasoning: { effort } }]))
|
||||
|
||||
// kilocode_change start - GPT models via Kilo need encrypted reasoning content to avoid org_id mismatch
|
||||
// kilocode_change start - Claude and GPT models via Kilo Gateway
|
||||
case "@kilocode/kilo-gateway":
|
||||
// Claude/Anthropic models support reasoning via effort levels through OpenRouter API
|
||||
// OpenRouter maps effort to budget_tokens percentages (xhigh=95%, high=80%, medium=50%, low=20%, minimal=10%)
|
||||
if (
|
||||
model.id.includes("claude") ||
|
||||
model.id.includes("anthropic") ||
|
||||
model.api.id.includes("claude") ||
|
||||
model.api.id.includes("anthropic")
|
||||
) {
|
||||
return Object.fromEntries(OPENAI_EFFORTS.map((effort) => [effort, { reasoning: { effort } }]))
|
||||
}
|
||||
// GPT models via Kilo need encrypted reasoning content to avoid org_id mismatch
|
||||
if (!model.id.includes("gpt") && !model.id.includes("gemini-3")) return {}
|
||||
return Object.fromEntries(
|
||||
OPENAI_EFFORTS.map((effort) => [
|
||||
@@ -576,6 +672,16 @@ export namespace ProviderTransform {
|
||||
if (input.model.api.id.includes("gemini-3")) {
|
||||
result["reasoning"] = { effort: "high" }
|
||||
}
|
||||
// kilocode_change - enable reasoning for Claude models via Kilo Gateway
|
||||
if (
|
||||
input.model.api.npm === "@kilocode/kilo-gateway" &&
|
||||
(input.model.id.includes("claude") ||
|
||||
input.model.id.includes("anthropic") ||
|
||||
input.model.api.id.includes("claude") ||
|
||||
input.model.api.id.includes("anthropic"))
|
||||
) {
|
||||
result["reasoning"] = { effort: "medium" }
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -647,10 +753,21 @@ export namespace ProviderTransform {
|
||||
}
|
||||
return { thinkingConfig: { thinkingBudget: 0 } }
|
||||
}
|
||||
if (model.providerID === "openrouter") {
|
||||
if (model.providerID === "openrouter" || model.api.npm === "@kilocode/kilo-gateway") {
|
||||
// kilocode_change - add Kilo Gateway support with model-specific handling
|
||||
if (model.api.id.includes("google")) {
|
||||
return { reasoning: { enabled: false } }
|
||||
}
|
||||
// Claude models need reasoning.effort format (OpenRouter API)
|
||||
if (
|
||||
model.id.includes("claude") ||
|
||||
model.id.includes("anthropic") ||
|
||||
model.api.id.includes("claude") ||
|
||||
model.api.id.includes("anthropic")
|
||||
) {
|
||||
return { reasoning: { effort: "minimal" } }
|
||||
}
|
||||
// Other models use reasoningEffort (AI SDK format)
|
||||
return { reasoningEffort: "minimal" }
|
||||
}
|
||||
return {}
|
||||
|
||||
@@ -623,6 +623,75 @@ describe("ProviderTransform.message - anthropic empty content filtering", () =>
|
||||
})
|
||||
})
|
||||
|
||||
describe("ProviderTransform.message - OpenRouter/Kilo Gateway thinking stripping", () => {
|
||||
const claudeViaGateway = {
|
||||
id: "openrouter/anthropic/claude-3-5-sonnet",
|
||||
providerID: "openrouter",
|
||||
api: {
|
||||
id: "anthropic/claude-3-5-sonnet",
|
||||
url: "https://openrouter.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
name: "Claude 3.5 Sonnet (Gateway)",
|
||||
capabilities: {
|
||||
temperature: true,
|
||||
reasoning: true,
|
||||
attachment: true,
|
||||
toolcall: true,
|
||||
input: { text: true, audio: false, image: true, video: false, pdf: true },
|
||||
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
||||
interleaved: false,
|
||||
},
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cache: { read: 0, write: 0 },
|
||||
},
|
||||
limit: {
|
||||
context: 200000,
|
||||
output: 8192,
|
||||
},
|
||||
status: "active",
|
||||
options: {},
|
||||
headers: {},
|
||||
} as any
|
||||
|
||||
test("drops messages that become empty after stripping thinking/reasoning", () => {
|
||||
const msgs = [
|
||||
{ role: "user", content: "Hello" },
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "thinking", text: "..." }, { type: "reasoning", text: "..." }, { type: "redacted_thinking" }],
|
||||
},
|
||||
{ role: "user", content: "World" },
|
||||
] as any[]
|
||||
|
||||
const result = ProviderTransform.message(msgs, claudeViaGateway, {})
|
||||
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[0].content).toBe("Hello")
|
||||
expect(result[1].content).toBe("World")
|
||||
})
|
||||
|
||||
test("keeps messages that still contain supported parts after stripping", () => {
|
||||
const msgs = [
|
||||
{
|
||||
role: "assistant",
|
||||
content: [
|
||||
{ type: "thinking", text: "..." },
|
||||
{ type: "text", text: "Answer" },
|
||||
],
|
||||
},
|
||||
] as any[]
|
||||
|
||||
const result = ProviderTransform.message(msgs, claudeViaGateway, {})
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].content).toHaveLength(1)
|
||||
expect(result[0].content[0]).toEqual({ type: "text", text: "Answer" })
|
||||
})
|
||||
})
|
||||
|
||||
describe("ProviderTransform.message - strip openai metadata when store=false", () => {
|
||||
const openaiModel = {
|
||||
id: "openai/gpt-5",
|
||||
@@ -1031,41 +1100,42 @@ describe("ProviderTransform.message - claude w/bedrock custom inference profile"
|
||||
})
|
||||
})
|
||||
|
||||
describe("ProviderTransform.variants", () => {
|
||||
const createMockModel = (overrides: Partial<any> = {}): any => ({
|
||||
id: "test/test-model",
|
||||
providerID: "test",
|
||||
api: {
|
||||
id: "test-model",
|
||||
url: "https://api.test.com",
|
||||
npm: "@ai-sdk/openai",
|
||||
},
|
||||
name: "Test Model",
|
||||
capabilities: {
|
||||
temperature: true,
|
||||
reasoning: true,
|
||||
attachment: true,
|
||||
toolcall: true,
|
||||
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
||||
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
||||
interleaved: false,
|
||||
},
|
||||
cost: {
|
||||
input: 0.001,
|
||||
output: 0.002,
|
||||
cache: { read: 0.0001, write: 0.0002 },
|
||||
},
|
||||
limit: {
|
||||
context: 200_000,
|
||||
output: 64_000,
|
||||
},
|
||||
status: "active",
|
||||
options: {},
|
||||
headers: {},
|
||||
release_date: "2024-01-01",
|
||||
...overrides,
|
||||
})
|
||||
// Helper function moved to top level for reuse across test suites
|
||||
const createMockModel = (overrides: Partial<any> = {}): any => ({
|
||||
id: "test/test-model",
|
||||
providerID: "test",
|
||||
api: {
|
||||
id: "test-model",
|
||||
url: "https://api.test.com",
|
||||
npm: "@ai-sdk/openai",
|
||||
},
|
||||
name: "Test Model",
|
||||
capabilities: {
|
||||
temperature: true,
|
||||
reasoning: true,
|
||||
attachment: true,
|
||||
toolcall: true,
|
||||
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
||||
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
||||
interleaved: false,
|
||||
},
|
||||
cost: {
|
||||
input: 0.001,
|
||||
output: 0.002,
|
||||
cache: { read: 0.0001, write: 0.0002 },
|
||||
},
|
||||
limit: {
|
||||
context: 200_000,
|
||||
output: 64_000,
|
||||
},
|
||||
status: "active",
|
||||
options: {},
|
||||
headers: {},
|
||||
release_date: "2024-01-01",
|
||||
...overrides,
|
||||
})
|
||||
|
||||
describe("ProviderTransform.variants", () => {
|
||||
test("returns empty object when model has no reasoning capabilities", () => {
|
||||
const model = createMockModel({
|
||||
capabilities: { reasoning: false },
|
||||
@@ -1206,6 +1276,107 @@ describe("ProviderTransform.variants", () => {
|
||||
})
|
||||
})
|
||||
|
||||
// kilocode_change start
|
||||
describe("@kilocode/kilo-gateway", () => {
|
||||
test("claude models return OPENAI_EFFORTS with reasoning", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/anthropic/claude-sonnet-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "anthropic/claude-sonnet-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"])
|
||||
expect(result.none).toEqual({ reasoning: { effort: "none" } })
|
||||
expect(result.low).toEqual({ reasoning: { effort: "low" } })
|
||||
expect(result.medium).toEqual({ reasoning: { effort: "medium" } })
|
||||
expect(result.high).toEqual({ reasoning: { effort: "high" } })
|
||||
expect(result.xhigh).toEqual({ reasoning: { effort: "xhigh" } })
|
||||
})
|
||||
|
||||
test("anthropic models in api.id return OPENAI_EFFORTS with reasoning", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/anthropic/claude-opus-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "anthropic/claude-opus-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"])
|
||||
expect(result.low).toEqual({ reasoning: { effort: "low" } })
|
||||
})
|
||||
|
||||
test("gpt models return OPENAI_EFFORTS with reasoning and encrypted content", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/openai/gpt-5",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "openai/gpt-5",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"])
|
||||
expect(result.low).toEqual({
|
||||
reasoningEffort: "low",
|
||||
reasoningSummary: "auto",
|
||||
include: ["reasoning.encrypted_content"],
|
||||
})
|
||||
})
|
||||
|
||||
test("gemini-3 models return OPENAI_EFFORTS with reasoning and encrypted content", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/google/gemini-3-pro",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "google/gemini-3-pro",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"])
|
||||
})
|
||||
|
||||
test("non-qualifying models return empty object", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/meta/llama-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "meta/llama-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(result).toEqual({})
|
||||
})
|
||||
|
||||
test("grok-3-mini returns low and high with reasoning", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/x-ai/grok-3-mini",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "x-ai/grok-3-mini",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.variants(model)
|
||||
expect(Object.keys(result)).toEqual(["low", "high"])
|
||||
expect(result.low).toEqual({ reasoning: { effort: "low" } })
|
||||
expect(result.high).toEqual({ reasoning: { effort: "high" } })
|
||||
})
|
||||
})
|
||||
// kilocode_change end
|
||||
|
||||
describe("@ai-sdk/gateway", () => {
|
||||
test("returns OPENAI_EFFORTS with reasoningEffort", () => {
|
||||
const model = createMockModel({
|
||||
@@ -1725,3 +1896,65 @@ describe("ProviderTransform.variants", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// kilocode_change start
|
||||
describe("ProviderTransform.smallOptions", () => {
|
||||
describe("@kilocode/kilo-gateway", () => {
|
||||
test("claude models use reasoning.effort format", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/anthropic/claude-sonnet-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "anthropic/claude-sonnet-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.smallOptions(model)
|
||||
expect(result).toEqual({ reasoning: { effort: "minimal" } })
|
||||
})
|
||||
|
||||
test("anthropic models in api.id use reasoning.effort format", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/anthropic/claude-opus-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "anthropic/claude-opus-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.smallOptions(model)
|
||||
expect(result).toEqual({ reasoning: { effort: "minimal" } })
|
||||
})
|
||||
|
||||
test("non-claude models use reasoningEffort format", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/openai/gpt-4",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "openai/gpt-4",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.smallOptions(model)
|
||||
expect(result).toEqual({ reasoningEffort: "minimal" })
|
||||
})
|
||||
|
||||
test("google models disable reasoning", () => {
|
||||
const model = createMockModel({
|
||||
id: "kilo/google/gemini-2.0-flash",
|
||||
providerID: "kilo",
|
||||
api: {
|
||||
id: "google/gemini-2.0-flash",
|
||||
url: "https://gateway.kilo.ai",
|
||||
npm: "@kilocode/kilo-gateway",
|
||||
},
|
||||
})
|
||||
const result = ProviderTransform.smallOptions(model)
|
||||
expect(result).toEqual({ reasoning: { enabled: false } })
|
||||
})
|
||||
})
|
||||
})
|
||||
// kilocode_change end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/plugin",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/sdk",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@opencode-ai/web",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "1.0.13",
|
||||
"version": "1.0.14",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user