-
+
-
- {t("settings.experimental.websearch.title")}
+
+ {t("settings.webTools.webSearch.title")}
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
index f86fe517b0..02fc76303d 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
@@ -1203,7 +1203,13 @@ export const dict = {
"settings.section.configuration": "الإعدادات",
"settings.agentBehaviour.title": "سلوك الوكيل",
"settings.autoApprove.title": "الموافقة التلقائية",
- "settings.browser.title": "المتصفح",
+ "settings.webTools.title": "أدوات الويب",
+ "settings.webTools.description": "اضبط البحث على الويب وأتمتة المتصفح. تتصل طلبات البحث مباشرةً بـ Exa أو Parallel.",
+ "settings.webTools.webSearch.enable": "تمكين لجميع المزوّدين",
+ "settings.webTools.browserAutomation": "أتمتة المتصفح",
+ "settings.webTools.webSearch.title": "البحث على الويب",
+ "settings.webTools.webSearch.description":
+ "اجعل البحث على الويب متاحًا لنماذج جميع المزوّدين. تتصل عمليات البحث مباشرةً بـ Exa أو Parallel.",
"settings.checkpoints.title": "نقاط التحقق",
"settings.display.title": "العرض",
"settings.autocomplete.title": "الإكمال التلقائي",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts
index 35a1450ea1..902114dd85 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts
@@ -1224,7 +1224,14 @@ export const dict = {
"settings.section.configuration": "Configuração",
"settings.agentBehaviour.title": "Comportamento do Agente",
"settings.autoApprove.title": "Aprovação Automática",
- "settings.browser.title": "Navegador",
+ "settings.webTools.title": "Ferramentas da Web",
+ "settings.webTools.description":
+ "Configure a pesquisa na web e a automação do navegador. As solicitações de pesquisa se conectam diretamente ao Exa ou Parallel.",
+ "settings.webTools.webSearch.enable": "Ativar para todos os provedores",
+ "settings.webTools.browserAutomation": "Automação do navegador",
+ "settings.webTools.webSearch.title": "Pesquisa na Web",
+ "settings.webTools.webSearch.description":
+ "Disponibilize a pesquisa na web para modelos de todos os provedores. As pesquisas se conectam diretamente ao Exa ou Parallel.",
"settings.checkpoints.title": "Pontos de Verificação",
"settings.display.title": "Exibição",
"settings.autocomplete.title": "Autocompletar",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
index c19e73262c..dbb2e7b923 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
@@ -1269,7 +1269,14 @@ export const dict = {
"settings.section.configuration": "Konfiguracija",
"settings.agentBehaviour.title": "Ponašanje agenta",
"settings.autoApprove.title": "Automatsko odobravanje",
- "settings.browser.title": "Preglednik",
+ "settings.webTools.title": "Web alati",
+ "settings.webTools.description":
+ "Konfigurišite web pretragu i automatizaciju preglednika. Zahtjevi za pretragu povezuju se direktno s Exa ili Parallel.",
+ "settings.webTools.webSearch.enable": "Omogući za sve pružaoce",
+ "settings.webTools.browserAutomation": "Automatizacija preglednika",
+ "settings.webTools.webSearch.title": "Web pretraga",
+ "settings.webTools.webSearch.description":
+ "Omogućite web pretragu modelima svih pružalaca. Pretrage se povezuju direktno s Exa ili Parallel.",
"settings.checkpoints.title": "Kontrolne tačke",
"settings.display.title": "Prikaz",
"settings.autocomplete.title": "Automatsko dovršavanje",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts
index 8e9a593dd3..028595f859 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts
@@ -1262,7 +1262,14 @@ export const dict = {
"settings.section.configuration": "Konfiguration",
"settings.agentBehaviour.title": "Agentadfærd",
"settings.autoApprove.title": "Automatisk godkendelse",
- "settings.browser.title": "Browser",
+ "settings.webTools.title": "Webværktøjer",
+ "settings.webTools.description":
+ "Konfigurer websøgning og browserautomatisering. Søgeanmodninger sendes direkte til Exa eller Parallel.",
+ "settings.webTools.webSearch.enable": "Aktivér for alle udbydere",
+ "settings.webTools.browserAutomation": "Browserautomatisering",
+ "settings.webTools.webSearch.title": "Websøgning",
+ "settings.webTools.webSearch.description":
+ "Gør websøgning tilgængelig for modeller fra alle udbydere. Søgninger sendes direkte til Exa eller Parallel.",
"settings.checkpoints.title": "Kontrolpunkter",
"settings.display.title": "Visning",
"settings.autocomplete.title": "Autofuldførelse",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts
index 380e7d3db4..4adcf7b72f 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts
@@ -1283,7 +1283,14 @@ export const dict = {
"settings.section.configuration": "Konfiguration",
"settings.agentBehaviour.title": "Agentenverhalten",
"settings.autoApprove.title": "Automatisch genehmigen",
- "settings.browser.title": "Browser",
+ "settings.webTools.title": "Web-Tools",
+ "settings.webTools.description":
+ "Konfigurieren Sie Websuche und Browserautomatisierung. Suchanfragen werden direkt an Exa oder Parallel gesendet.",
+ "settings.webTools.webSearch.enable": "Für alle Anbieter aktivieren",
+ "settings.webTools.browserAutomation": "Browserautomatisierung",
+ "settings.webTools.webSearch.title": "Websuche",
+ "settings.webTools.webSearch.description":
+ "Machen Sie die Websuche für Modelle aller Anbieter verfügbar. Suchanfragen werden direkt an Exa oder Parallel gesendet.",
"settings.checkpoints.title": "Prüfpunkte",
"settings.display.title": "Anzeige",
"settings.autocomplete.title": "Autovervollständigung",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts
index abe0350075..e926699acc 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts
@@ -1176,8 +1176,14 @@ export const dict = {
"settings.section.configuration": "Configuration",
"settings.agentBehaviour.title": "Agent Behaviour",
"settings.autoApprove.title": "Auto-Approve",
- "settings.browser.title": "Browser",
"settings.webTools.title": "Web Tools",
+ "settings.webTools.description":
+ "Configure web search and browser automation. Search requests connect directly to Exa or Parallel.",
+ "settings.webTools.webSearch.enable": "Enable for All Providers",
+ "settings.webTools.browserAutomation": "Browser Automation",
+ "settings.webTools.webSearch.title": "Web Search",
+ "settings.webTools.webSearch.description":
+ "Make web search available to models from all providers. Searches connect directly to Exa or Parallel.",
"settings.checkpoints.title": "Checkpoints",
"settings.display.title": "Display",
"settings.autocomplete.title": "Autocomplete",
@@ -1350,10 +1356,6 @@ export const dict = {
"settings.browser.description":
"When enabled, the AI agent can interact with web pages — navigating, clicking, typing, and taking screenshots. A Chrome window will open so you can watch the agent work.",
- "settings.webTools.description":
- "Configure web search and browser automation. Search requests connect directly to Exa or Parallel.",
- "settings.webTools.websearchEnable": "Enable for All Providers",
- "settings.webTools.browserAutomation": "Browser Automation",
"settings.browser.enable.title": "Enable Browser Automation",
"settings.browser.enable.description": "Register the Playwright MCP server with the CLI backend.",
"settings.browser.systemChrome.title": "Use System Chrome",
@@ -1414,9 +1416,6 @@ export const dict = {
"settings.experimental.lsp.description": "Enable language server protocol integration",
"settings.experimental.batch.title": "Batch Tool",
"settings.experimental.batch.description": "Enable batching of multiple tool calls",
- "settings.experimental.websearch.title": "Web Search",
- "settings.experimental.websearch.description":
- "Make web search available to models from all providers. Searches connect directly to Exa or Parallel.",
"settings.experimental.codebaseSearch.title": "Codebase Search",
"settings.experimental.codebaseSearch.description": "Enable AI-powered natural language search across your codebase",
"settings.experimental.imageGeneration.title": "Image Generation",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts
index e1cd429614..d66f4bd86f 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts
@@ -1276,7 +1276,14 @@ export const dict = {
"settings.section.configuration": "Configuración",
"settings.agentBehaviour.title": "Comportamiento del agente",
"settings.autoApprove.title": "Aprobación automática",
- "settings.browser.title": "Navegador",
+ "settings.webTools.title": "Herramientas web",
+ "settings.webTools.description":
+ "Configura la búsqueda web y la automatización del navegador. Las solicitudes de búsqueda se conectan directamente a Exa o Parallel.",
+ "settings.webTools.webSearch.enable": "Habilitar para todos los proveedores",
+ "settings.webTools.browserAutomation": "Automatización del navegador",
+ "settings.webTools.webSearch.title": "Búsqueda web",
+ "settings.webTools.webSearch.description":
+ "Permite que los modelos de todos los proveedores usen la búsqueda web. Las búsquedas se conectan directamente a Exa o Parallel.",
"settings.checkpoints.title": "Puntos de control",
"settings.display.title": "Pantalla",
"settings.autocomplete.title": "Autocompletado",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
index 71055c0d65..1ed7c73e8b 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
@@ -1287,7 +1287,14 @@ export const dict = {
"settings.section.configuration": "Configuration",
"settings.agentBehaviour.title": "Comportement de l'agent",
"settings.autoApprove.title": "Approbation automatique",
- "settings.browser.title": "Navigateur",
+ "settings.webTools.title": "Outils web",
+ "settings.webTools.description":
+ "Configurez la recherche web et l’automatisation du navigateur. Les requêtes de recherche se connectent directement à Exa ou Parallel.",
+ "settings.webTools.webSearch.enable": "Activer pour tous les fournisseurs",
+ "settings.webTools.browserAutomation": "Automatisation du navigateur",
+ "settings.webTools.webSearch.title": "Recherche web",
+ "settings.webTools.webSearch.description":
+ "Rendez la recherche web disponible pour les modèles de tous les fournisseurs. Les recherches se connectent directement à Exa ou Parallel.",
"settings.checkpoints.title": "Points de contrôle",
"settings.display.title": "Affichage",
"settings.autocomplete.title": "Autocomplétion",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/it.ts b/packages/kilo-vscode/webview-ui/src/i18n/it.ts
index 034276bb9c..b0c9a5f703 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/it.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/it.ts
@@ -1023,7 +1023,14 @@ export const dict = {
"settings.section.configuration": "Configurazione",
"settings.agentBehaviour.title": "Comportamento agente",
"settings.autoApprove.title": "Approvazione automatica",
- "settings.browser.title": "Browser",
+ "settings.webTools.title": "Strumenti web",
+ "settings.webTools.description":
+ "Configura la ricerca web e l'automazione del browser. Le richieste di ricerca si connettono direttamente a Exa o Parallel.",
+ "settings.webTools.webSearch.enable": "Abilita per tutti i provider",
+ "settings.webTools.browserAutomation": "Automazione del browser",
+ "settings.webTools.webSearch.title": "Ricerca web",
+ "settings.webTools.webSearch.description":
+ "Rendi disponibile la ricerca web ai modelli di tutti i provider. Le ricerche si connettono direttamente a Exa o Parallel.",
"settings.checkpoints.title": "Checkpoint",
"settings.display.title": "Visualizzazione",
"settings.autocomplete.title": "Autocompletamento",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
index 2c6bd6c9e3..fd60365ca9 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
@@ -1257,7 +1257,14 @@ export const dict = {
"settings.section.configuration": "設定",
"settings.agentBehaviour.title": "エージェントの動作",
"settings.autoApprove.title": "自動承認",
- "settings.browser.title": "ブラウザ",
+ "settings.webTools.title": "ウェブツール",
+ "settings.webTools.description":
+ "ウェブ検索とブラウザ自動化を設定します。検索リクエストは Exa または Parallel に直接接続されます。",
+ "settings.webTools.webSearch.enable": "すべてのプロバイダーで有効化",
+ "settings.webTools.browserAutomation": "ブラウザ自動化",
+ "settings.webTools.webSearch.title": "ウェブ検索",
+ "settings.webTools.webSearch.description":
+ "すべてのプロバイダーのモデルでウェブ検索を利用できるようにします。検索は Exa または Parallel に直接接続されます。",
"settings.checkpoints.title": "チェックポイント",
"settings.display.title": "表示",
"settings.autocomplete.title": "オートコンプリート",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts
index 990edeb5eb..9dd03144c2 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts
@@ -1210,7 +1210,14 @@ export const dict = {
"settings.section.configuration": "구성",
"settings.agentBehaviour.title": "에이전트 동작",
"settings.autoApprove.title": "자동 승인",
- "settings.browser.title": "브라우저",
+ "settings.webTools.title": "웹 도구",
+ "settings.webTools.description":
+ "웹 검색 및 브라우저 자동화를 구성합니다. 검색 요청은 Exa 또는 Parallel에 직접 연결됩니다.",
+ "settings.webTools.webSearch.enable": "모든 제공업체에 사용",
+ "settings.webTools.browserAutomation": "브라우저 자동화",
+ "settings.webTools.webSearch.title": "웹 검색",
+ "settings.webTools.webSearch.description":
+ "모든 제공업체의 모델에서 웹 검색을 사용할 수 있도록 합니다. 검색은 Exa 또는 Parallel에 직접 연결됩니다.",
"settings.checkpoints.title": "체크포인트",
"settings.display.title": "디스플레이",
"settings.autocomplete.title": "자동 완성",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts
index 75d20e4f17..8158160380 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts
@@ -1218,7 +1218,14 @@ export const dict = {
"settings.section.configuration": "Configuratie",
"settings.agentBehaviour.title": "Agent Gedrag",
"settings.autoApprove.title": "Automatisch Goedkeuren",
- "settings.browser.title": "Browser",
+ "settings.webTools.title": "Webtools",
+ "settings.webTools.description":
+ "Configureer zoeken op internet en browserautomatisering. Zoekopdrachten maken rechtstreeks verbinding met Exa of Parallel.",
+ "settings.webTools.webSearch.enable": "Inschakelen voor alle providers",
+ "settings.webTools.browserAutomation": "Browserautomatisering",
+ "settings.webTools.webSearch.title": "Zoeken op internet",
+ "settings.webTools.webSearch.description":
+ "Maak zoeken op internet beschikbaar voor modellen van alle providers. Zoekopdrachten maken rechtstreeks verbinding met Exa of Parallel.",
"settings.checkpoints.title": "Controlepunten",
"settings.display.title": "Weergave",
"settings.autocomplete.title": "Automatisch Aanvullen",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts
index 68c4af800b..5e8b9faf1f 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts
@@ -1222,7 +1222,14 @@ export const dict = {
"settings.section.configuration": "Konfigurasjon",
"settings.agentBehaviour.title": "Agentoppførsel",
"settings.autoApprove.title": "Automatisk godkjenning",
- "settings.browser.title": "Nettleser",
+ "settings.webTools.title": "Nettverktøy",
+ "settings.webTools.description":
+ "Konfigurer nettsøk og nettleserautomatisering. Søk sendes direkte til Exa eller Parallel.",
+ "settings.webTools.webSearch.enable": "Aktiver for alle leverandører",
+ "settings.webTools.browserAutomation": "Nettleserautomatisering",
+ "settings.webTools.webSearch.title": "Nettsøk",
+ "settings.webTools.webSearch.description":
+ "Gjør nettsøk tilgjengelig for modeller fra alle leverandører. Søk sendes direkte til Exa eller Parallel.",
"settings.checkpoints.title": "Kontrollpunkter",
"settings.display.title": "Visning",
"settings.autocomplete.title": "Autofullfør",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts
index f7238a444c..aa920ac5db 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts
@@ -1221,7 +1221,14 @@ export const dict = {
"settings.section.configuration": "Konfiguracja",
"settings.agentBehaviour.title": "Zachowanie agenta",
"settings.autoApprove.title": "Automatyczne zatwierdzanie",
- "settings.browser.title": "Przeglądarka",
+ "settings.webTools.title": "Narzędzia internetowe",
+ "settings.webTools.description":
+ "Skonfiguruj wyszukiwanie w sieci i automatyzację przeglądarki. Żądania wyszukiwania łączą się bezpośrednio z Exa lub Parallel.",
+ "settings.webTools.webSearch.enable": "Włącz dla wszystkich dostawców",
+ "settings.webTools.browserAutomation": "Automatyzacja przeglądarki",
+ "settings.webTools.webSearch.title": "Wyszukiwanie w sieci",
+ "settings.webTools.webSearch.description":
+ "Udostępnij wyszukiwanie w sieci modelom wszystkich dostawców. Wyszukiwania łączą się bezpośrednio z Exa lub Parallel.",
"settings.checkpoints.title": "Punkty kontrolne",
"settings.display.title": "Wyświetlanie",
"settings.autocomplete.title": "Autouzupełnianie",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
index 47a24933c3..68027826b8 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
@@ -1268,7 +1268,14 @@ export const dict = {
"settings.section.configuration": "Конфигурация",
"settings.agentBehaviour.title": "Поведение агента",
"settings.autoApprove.title": "Автоодобрение",
- "settings.browser.title": "Браузер",
+ "settings.webTools.title": "Веб-инструменты",
+ "settings.webTools.description":
+ "Настройте веб-поиск и автоматизацию браузера. Поисковые запросы отправляются напрямую в Exa или Parallel.",
+ "settings.webTools.webSearch.enable": "Включить для всех провайдеров",
+ "settings.webTools.browserAutomation": "Автоматизация браузера",
+ "settings.webTools.webSearch.title": "Веб-поиск",
+ "settings.webTools.webSearch.description":
+ "Сделайте веб-поиск доступным для моделей всех провайдеров. Поисковые запросы отправляются напрямую в Exa или Parallel.",
"settings.checkpoints.title": "Контрольные точки",
"settings.display.title": "Отображение",
"settings.autocomplete.title": "Автодополнение",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts
index cac0eea7a9..c029e495b6 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts
@@ -1250,7 +1250,14 @@ export const dict = {
"settings.section.configuration": "การกำหนดค่า",
"settings.agentBehaviour.title": "พฤติกรรมของเอเจนต์",
"settings.autoApprove.title": "อนุมัติอัตโนมัติ",
- "settings.browser.title": "เบราว์เซอร์",
+ "settings.webTools.title": "เครื่องมือเว็บ",
+ "settings.webTools.description":
+ "กำหนดค่าการค้นหาเว็บและระบบอัตโนมัติของเบราว์เซอร์ คำขอค้นหาจะเชื่อมต่อโดยตรงกับ Exa หรือ Parallel",
+ "settings.webTools.webSearch.enable": "เปิดใช้สำหรับผู้ให้บริการทั้งหมด",
+ "settings.webTools.browserAutomation": "ระบบอัตโนมัติของเบราว์เซอร์",
+ "settings.webTools.webSearch.title": "ค้นหาเว็บ",
+ "settings.webTools.webSearch.description":
+ "ทำให้โมเดลจากผู้ให้บริการทั้งหมดใช้การค้นหาเว็บได้ การค้นหาจะเชื่อมต่อโดยตรงกับ Exa หรือ Parallel",
"settings.checkpoints.title": "จุดตรวจสอบ",
"settings.display.title": "การแสดงผล",
"settings.autocomplete.title": "เติมข้อความอัตโนมัติ",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts
index e799d07141..a43c79880d 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts
@@ -1215,7 +1215,14 @@ export const dict = {
"settings.section.configuration": "Yapılandırma",
"settings.agentBehaviour.title": "Ajan Davranışı",
"settings.autoApprove.title": "Otomatik Onay",
- "settings.browser.title": "Tarayıcı",
+ "settings.webTools.title": "Web Araçları",
+ "settings.webTools.description":
+ "Web aramasını ve tarayıcı otomasyonunu yapılandırın. Arama istekleri doğrudan Exa veya Parallel'e bağlanır.",
+ "settings.webTools.webSearch.enable": "Tüm Sağlayıcılar İçin Etkinleştir",
+ "settings.webTools.browserAutomation": "Tarayıcı Otomasyonu",
+ "settings.webTools.webSearch.title": "Web Araması",
+ "settings.webTools.webSearch.description":
+ "Web aramasını tüm sağlayıcıların modelleri için kullanılabilir hale getirin. Aramalar doğrudan Exa veya Parallel'e bağlanır.",
"settings.checkpoints.title": "Kontrol Noktaları",
"settings.display.title": "Görünüm",
"settings.autocomplete.title": "Otomatik Tamamlama",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts
index dfc15c248d..75783bc9e4 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts
@@ -1213,7 +1213,14 @@ export const dict = {
"settings.section.configuration": "Конфігурація",
"settings.agentBehaviour.title": "Поведінка агента",
"settings.autoApprove.title": "Автоматичне схвалення",
- "settings.browser.title": "Браузер",
+ "settings.webTools.title": "Вебінструменти",
+ "settings.webTools.description":
+ "Налаштуйте вебпошук і автоматизацію браузера. Пошукові запити надсилаються безпосередньо до Exa або Parallel.",
+ "settings.webTools.webSearch.enable": "Увімкнути для всіх постачальників",
+ "settings.webTools.browserAutomation": "Автоматизація браузера",
+ "settings.webTools.webSearch.title": "Вебпошук",
+ "settings.webTools.webSearch.description":
+ "Зробіть вебпошук доступним для моделей усіх постачальників. Пошукові запити надсилаються безпосередньо до Exa або Parallel.",
"settings.checkpoints.title": "Контрольні точки",
"settings.display.title": "Відображення",
"settings.autocomplete.title": "Автодоповнення",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts
index 8432bbee90..9e1dd05729 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts
@@ -1229,7 +1229,12 @@ export const dict = {
"settings.section.configuration": "配置",
"settings.agentBehaviour.title": "智能体行为",
"settings.autoApprove.title": "自动审批",
- "settings.browser.title": "浏览器",
+ "settings.webTools.title": "网络工具",
+ "settings.webTools.description": "配置网页搜索和浏览器自动化。搜索请求会直接连接到 Exa 或 Parallel。",
+ "settings.webTools.webSearch.enable": "为所有提供商启用",
+ "settings.webTools.browserAutomation": "浏览器自动化",
+ "settings.webTools.webSearch.title": "网页搜索",
+ "settings.webTools.webSearch.description": "让所有提供商的模型都可使用网页搜索。搜索会直接连接到 Exa 或 Parallel。",
"settings.checkpoints.title": "检查点",
"settings.display.title": "显示",
"settings.autocomplete.title": "自动补全",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts
index b69bb7054c..aed2a97179 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts
@@ -1190,7 +1190,12 @@ export const dict = {
"settings.section.configuration": "設定",
"settings.agentBehaviour.title": "Agent 行為",
"settings.autoApprove.title": "自動核准",
- "settings.browser.title": "瀏覽器",
+ "settings.webTools.title": "網路工具",
+ "settings.webTools.description": "設定網頁搜尋和瀏覽器自動化。搜尋請求會直接連線至 Exa 或 Parallel。",
+ "settings.webTools.webSearch.enable": "為所有供應商啟用",
+ "settings.webTools.browserAutomation": "瀏覽器自動化",
+ "settings.webTools.webSearch.title": "網頁搜尋",
+ "settings.webTools.webSearch.description": "讓所有供應商的模型都可使用網頁搜尋。搜尋會直接連線至 Exa 或 Parallel。",
"settings.checkpoints.title": "檢查點",
"settings.display.title": "顯示",
"settings.autocomplete.title": "自動完成",
diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts
index 0dc2d05dc7..89dcc0af83 100644
--- a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts
+++ b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts
@@ -39,7 +39,6 @@ export interface WatcherConfig {
export interface ExperimentalConfig {
batch_tool?: boolean
- websearch?: boolean
codebase_search?: boolean
image_generation?: boolean
image_generation_model?: string
@@ -155,6 +154,7 @@ export interface Config {
compaction?: CompactionConfig
commit_message?: CommitMessageConfig
tools?: Record
+ web_search?: boolean
auto_collapse_reasoning?: boolean
experimental?: ExperimentalConfig
sandbox?: SandboxConfig
diff --git a/packages/opencode/src/kilocode/config/overlay.ts b/packages/opencode/src/kilocode/config/overlay.ts
index b0cd42f88c..ec806bf053 100644
--- a/packages/opencode/src/kilocode/config/overlay.ts
+++ b/packages/opencode/src/kilocode/config/overlay.ts
@@ -88,7 +88,7 @@ export namespace KilocodeConfigOverlay {
["disabled_providers"],
["watcher", "ignore"],
["instructions"],
- ["experimental", "websearch"],
+ ["web_search"],
["indexing", "enabled"],
["indexing", "provider"],
["indexing", "model"],
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index f8eb66469a..4df567dd6b 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -377,7 +377,7 @@ export const layer: Layer.Layer<
const filtered = (yield* all()).filter((tool) => {
if (!KiloToolRegistry.available(tool, input.agent)) return false // kilocode_change
if (tool.id === WebSearchTool.id) {
- if (cfg.experimental?.websearch === true) return true // kilocode_change
+ if (cfg.web_search === true) return true // kilocode_change
return webSearchEnabled(input.providerID, { exa: flags.enableExa, parallel: flags.enableParallel })
}
diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts
index 50529c043f..51902e1514 100644
--- a/packages/opencode/test/kilocode/config/config.test.ts
+++ b/packages/opencode/test/kilocode/config/config.test.ts
@@ -151,13 +151,15 @@ describe("global config updates", () => {
})
})
-describe("kilocode indexing config", () => {
+describe("kilocode web search config", () => {
test("accepts the websearch availability setting", () => {
- const config = Schema.decodeUnknownSync(Config.Info)({ experimental: { websearch: true } })
+ const config = Schema.decodeUnknownSync(Config.Info)({ web_search: true })
- expect(config.experimental?.websearch).toBe(true)
+ expect(config.web_search).toBe(true)
})
+})
+describe("kilocode indexing config", () => {
test("ignores retired semantic indexing flags in existing configs", async () => {
await using tmp = await tmpdir({ git: true })
await writeConfig(tmp.path, {
diff --git a/packages/opencode/test/kilocode/server/config-overlay.test.ts b/packages/opencode/test/kilocode/server/config-overlay.test.ts
index e8a55f9ac7..a21deb1e5d 100644
--- a/packages/opencode/test/kilocode/server/config-overlay.test.ts
+++ b/packages/opencode/test/kilocode/server/config-overlay.test.ts
@@ -204,17 +204,17 @@ describe("config overlay routes", () => {
test.serial("resolves and reverts project websearch overrides", async () => {
await using global = await tmpdir()
await using project = await tmpdir()
- await setGlobal(global.path, { experimental: { websearch: true } })
+ await setGlobal(global.path, { web_search: true })
await json(
await req(project.path, "/config/overlay", {
method: "PATCH",
headers: { "content-type": "application/json" },
- body: JSON.stringify({ scope: "project", set: { experimental: { websearch: false } } }),
+ body: JSON.stringify({ scope: "project", set: { web_search: false } }),
}),
)
const overridden = await json(await req(project.path, "/config/overlay?scope=project"))
- expect(overridden.fields["experimental.websearch"]).toMatchObject({
+ expect(overridden.fields.web_search).toMatchObject({
source: "project",
inherited: false,
overridden: true,
@@ -225,11 +225,11 @@ describe("config overlay routes", () => {
await req(project.path, "/config/overlay", {
method: "PATCH",
headers: { "content-type": "application/json" },
- body: JSON.stringify({ scope: "project", unset: [["experimental", "websearch"]] }),
+ body: JSON.stringify({ scope: "project", unset: [["web_search"]] }),
}),
)
const inherited = await json(await req(project.path, "/config/overlay?scope=project"))
- expect(inherited.fields["experimental.websearch"]).toMatchObject({
+ expect(inherited.fields.web_search).toMatchObject({
source: "global",
inherited: true,
overridden: false,
diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts
index 393bea6f25..97e4e6c51c 100644
--- a/packages/opencode/test/tool/registry.test.ts
+++ b/packages/opencode/test/tool/registry.test.ts
@@ -52,12 +52,13 @@ const configLayer = TestConfig.layer({
type RegistryLayerOptions = {
flags?: Partial
plugin?: Layer.Layer
+ config?: Parameters[0] // kilocode_change
}
const registryLayer = (opts: RegistryLayerOptions = {}) =>
ToolRegistry.layer
.pipe(
- Layer.provide(configLayer),
+ Layer.provide(opts.config ? TestConfig.layer(opts.config) : configLayer), // kilocode_change
Layer.provide(opts.plugin ?? Plugin.defaultLayer),
Layer.provide(Question.defaultLayer),
Layer.provide(Todo.defaultLayer),
@@ -118,6 +119,21 @@ const withBrokenPlugin = testEffect(
Layer.mergeAll(registryLayer({ plugin: brokenPluginLayer }), node, Agent.defaultLayer),
)
// kilocode_change start
+const websearch = testEffect(
+ Layer.mergeAll(
+ registryLayer({
+ config: {
+ get: () =>
+ Effect.succeed({
+ web_search: true,
+ provider: { openai: { options: { apiKey: "test-openai-key" } } },
+ }),
+ },
+ }),
+ node,
+ Agent.defaultLayer,
+ ),
+)
const sandboxed = testEffect(
Layer.mergeAll(registryLayer({ flags: { experimentalLspTool: true } }), node, Agent.defaultLayer),
)
@@ -139,6 +155,38 @@ function sandboxProfile(): Profile {
describe("tool.registry", () => {
// kilocode_change start
+ it.instance("hides websearch for a third-party provider by default", () =>
+ Effect.gen(function* () {
+ const registry = yield* ToolRegistry.Service
+ const agent = yield* Agent.Service
+ const build = yield* agent.get("build")
+ if (!build) return yield* Effect.die(new Error("build agent not found"))
+ const tools = yield* registry.tools({
+ providerID: ProviderV2.ID.openai,
+ modelID: ModelV2.ID.make("test"),
+ agent: build,
+ })
+
+ expect(tools.map((tool) => tool.id)).not.toContain("websearch")
+ }),
+ )
+
+ websearch.instance("shows websearch for a configured third-party provider when enabled", () =>
+ Effect.gen(function* () {
+ const registry = yield* ToolRegistry.Service
+ const agent = yield* Agent.Service
+ const build = yield* agent.get("build")
+ if (!build) return yield* Effect.die(new Error("build agent not found"))
+ const tools = yield* registry.tools({
+ providerID: ProviderV2.ID.openai,
+ modelID: ModelV2.ID.make("test"),
+ agent: build,
+ })
+
+ expect(tools.map((tool) => tool.id)).toContain("websearch")
+ }),
+ )
+
sandboxed.instance("preserves built-in network classification through production tool definition processing", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index 0bd15820a7..5f9963def0 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -1673,6 +1673,7 @@ export type Config = {
tools?: {
[key: string]: boolean
}
+ web_search?: boolean
attachment?: AttachmentConfig
enterprise?: {
url?: string
@@ -1699,7 +1700,6 @@ export type Config = {
disable_paste_summary?: boolean
batch_tool?: boolean
codebase_search?: boolean
- websearch?: boolean
image_generation?: boolean
image_generation_model?: string
agent_requirements?: boolean
diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json
index 7ea6d2387d..1451c3a6b3 100644
--- a/packages/sdk/openapi.json
+++ b/packages/sdk/openapi.json
@@ -26905,6 +26905,9 @@
"type": "boolean"
}
},
+ "web_search": {
+ "type": "boolean"
+ },
"attachment": {
"$ref": "#/components/schemas/AttachmentConfig"
},
@@ -27000,9 +27003,6 @@
"codebase_search": {
"type": "boolean"
},
- "websearch": {
- "type": "boolean"
- },
"image_generation": {
"type": "boolean"
},
From 25dcfb6cff23abe840f3a728ebe48deef6af9355 Mon Sep 17 00:00:00 2001
From: Kelly Sun
Date: Thu, 23 Jul 2026 14:28:32 -0400
Subject: [PATCH 003/100] docs: add Mixlayer provider page
Adds an AI-providers docs page for Mixlayer (OpenAI-compatible inference
for open models like GLM and Qwen) and a nav entry, documenting the
OpenAI-Compatible setup for both VS Code and the CLI.
---
packages/kilo-docs/lib/nav/ai-providers.ts | 1 +
.../kilo-docs/pages/ai-providers/mixlayer.md | 97 +++++++++++++++++++
2 files changed, 98 insertions(+)
create mode 100644 packages/kilo-docs/pages/ai-providers/mixlayer.md
diff --git a/packages/kilo-docs/lib/nav/ai-providers.ts b/packages/kilo-docs/lib/nav/ai-providers.ts
index f604826c7c..1a2dfe9ae3 100644
--- a/packages/kilo-docs/lib/nav/ai-providers.ts
+++ b/packages/kilo-docs/lib/nav/ai-providers.ts
@@ -46,6 +46,7 @@ export const AiProvidersNav: NavSection[] = [
{ href: "/ai-providers/groq", children: "Groq" },
{ href: "/ai-providers/cerebras", children: "Cerebras" },
{ href: "/ai-providers/fireworks", children: "Fireworks AI" },
+ { href: "/ai-providers/mixlayer", children: "Mixlayer" },
],
},
{
diff --git a/packages/kilo-docs/pages/ai-providers/mixlayer.md b/packages/kilo-docs/pages/ai-providers/mixlayer.md
new file mode 100644
index 0000000000..ac0221315a
--- /dev/null
+++ b/packages/kilo-docs/pages/ai-providers/mixlayer.md
@@ -0,0 +1,97 @@
+---
+title: "Using Mixlayer with Kilo Code | Fast Open-Model Inference"
+description: "Run open models like GLM and Qwen on Mixlayer's OpenAI-compatible API in Kilo Code. Setup guide for VS Code and the CLI."
+---
+
+# Using Mixlayer With Kilo Code
+
+Mixlayer is an inference platform for open models such as GLM and Qwen, with a serving stack built from scratch by core contributors to Candle. It exposes an OpenAI-compatible API, so you can use it in Kilo Code through the **OpenAI Compatible** provider.
+
+**Website:** [https://mixlayer.com/](https://mixlayer.com/)
+
+## Getting an API Key
+
+1. **Sign Up/Sign In:** Go to [Mixlayer](https://mixlayer.com/) and create an account or sign in.
+2. **Navigate to API Keys:** Open the [Mixlayer console](https://console.mixlayer.com/) and go to the API Keys page.
+3. **Create a Key:** Click **New Key**, give it a descriptive name (e.g., "Kilo Code"), and copy it. You will not be able to view it again.
+
+## Configuration in Kilo Code
+
+Mixlayer's API is OpenAI-compatible, with the base URL `https://models.mixlayer.ai/v1`. Configure it through Kilo Code's **OpenAI Compatible** provider.
+
+{% tabs %}
+{% tab label="VSCode" %}
+
+1. Open **Settings** (gear icon) and go to the **Providers** tab.
+2. Scroll to the bottom and click **Custom provider**.
+3. Fill in the dialog:
+ - **Provider ID** — `mixlayer`
+ - **Display name** — `Mixlayer`
+ - **Provider API** — **OpenAI Compatible**
+ - **Base URL** — `https://models.mixlayer.ai/v1`
+ - **API key** — your Mixlayer API key
+4. Kilo Code auto-fetches the available models from Mixlayer's `/v1/models` endpoint, so you can pick a model directly from the list. Click **Submit** to save.
+
+{% /tab %}
+{% tab label="CLI" %}
+
+Set the API key as an environment variable and define an OpenAI-compatible provider in your `kilo.json` config file (`~/.config/kilo/kilo.json` or `./kilo.json`):
+
+**Environment variable:**
+
+```bash
+export MIXLAYER_API_KEY="your-api-key"
+```
+
+**Config file:**
+
+```jsonc
+{
+ "provider": {
+ "mixlayer": {
+ "npm": "@ai-sdk/openai-compatible",
+ "env": ["MIXLAYER_API_KEY"],
+ "options": {
+ "baseURL": "https://models.mixlayer.ai/v1",
+ },
+ "models": {
+ "z-ai/glm-5.2": {
+ "name": "GLM-5.2",
+ "limit": { "context": 262144, "output": 262144 },
+ },
+ "qwen/qwen3.5-397b-a17b": {
+ "name": "Qwen3.5 397B A17B",
+ "limit": { "context": 131072, "output": 131072 },
+ },
+ },
+ },
+ },
+}
+```
+
+Then set your default model using the `provider-id/model-id` format:
+
+```jsonc
+{
+ "model": "mixlayer/z-ai/glm-5.2",
+}
+```
+
+{% /tab %}
+{% /tabs %}
+
+## Models
+
+Mixlayer serves open models including:
+
+- `z-ai/glm-5.2` — 256K context
+- `qwen/qwen3.5-397b-a17b` and the Qwen 3.5 / 3.6 line (vision-capable)
+- `moonshotai/kimi-k2.7-code`
+
+Tool calling and reasoning are supported across the model line. See the [Mixlayer docs](https://docs.mixlayer.com) for the full, current model list and supported parameters.
+
+## Tips and Notes
+
+- **Model list:** Kilo Code auto-detects available models from Mixlayer's `/v1/models` endpoint, so the picker stays current with your account.
+- **Pricing:** See the [Mixlayer console](https://console.mixlayer.com/) for current per-model pricing.
+- **Reasoning:** Qwen models support a thinking mode; reasoning tokens count against the output budget, so allow enough `limit.output` when reasoning is enabled.
From 34e787e5ac039b0d070ed186ee5979aba38c8576 Mon Sep 17 00:00:00 2001
From: Josh Lambert
Date: Mon, 27 Jul 2026 11:48:09 -0400
Subject: [PATCH 004/100] fix: enable web search by default
---
packages/core/src/v1/config/config.ts | 3 +-
.../src/routes/config/ToolsRoute.tsx | 2 +-
.../src/components/settings/BrowserTab.tsx | 2 +-
packages/opencode/src/tool/registry.ts | 2 +-
.../test/kilocode/config/config.test.ts | 6 +--
packages/opencode/test/tool/registry.test.ts | 50 ++++++++++++-------
6 files changed, 40 insertions(+), 25 deletions(-)
diff --git a/packages/core/src/v1/config/config.ts b/packages/core/src/v1/config/config.ts
index bd9baab123..0ef9d1ffc7 100644
--- a/packages/core/src/v1/config/config.ts
+++ b/packages/core/src/v1/config/config.ts
@@ -227,7 +227,8 @@ export const Info = Schema.Struct({
permission: Schema.optional(ConfigPermissionV1.Info),
tools: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),
web_search: Schema.optional(Schema.Boolean).annotate({
- description: "Make web search available to models from all providers",
+ description:
+ "Make web search available to models from all providers (default: true). Set to false to limit it to managed providers.",
}), // kilocode_change
attachment: Schema.optional(ConfigAttachmentV1.Info).annotate({
description: "Attachment processing configuration, including image size limits and resizing behavior",
diff --git a/packages/kilo-console/src/routes/config/ToolsRoute.tsx b/packages/kilo-console/src/routes/config/ToolsRoute.tsx
index 9dcb20b6e0..fae54f6b8c 100644
--- a/packages/kilo-console/src/routes/config/ToolsRoute.tsx
+++ b/packages/kilo-console/src/routes/config/ToolsRoute.tsx
@@ -12,7 +12,7 @@ export function ToolsRoute() {
const [search, setSearch] = createSignal("")
const snap = () => ctx.data()
const websearch = createMemo(() => snap()?.overlay.fields.web_search)
- const searchEnabled = createMemo(() => websearch()?.value === true)
+ const searchEnabled = createMemo(() => websearch()?.value !== false)
const rows = createMemo(() => {
const data = snap()
if (!data) return []
diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
index fabc7858b8..ca870fef21 100644
--- a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
+++ b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
@@ -86,7 +86,7 @@ const BrowserTab: Component = () => {
description={t("settings.webTools.webSearch.description")}
last
>
-
+
{t("settings.webTools.webSearch.title")}
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index 4df567dd6b..4f7c275cfa 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -377,7 +377,7 @@ export const layer: Layer.Layer<
const filtered = (yield* all()).filter((tool) => {
if (!KiloToolRegistry.available(tool, input.agent)) return false // kilocode_change
if (tool.id === WebSearchTool.id) {
- if (cfg.web_search === true) return true // kilocode_change
+ if (cfg.web_search !== false) return true // kilocode_change
return webSearchEnabled(input.providerID, { exa: flags.enableExa, parallel: flags.enableParallel })
}
diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts
index 51902e1514..3938950306 100644
--- a/packages/opencode/test/kilocode/config/config.test.ts
+++ b/packages/opencode/test/kilocode/config/config.test.ts
@@ -152,10 +152,10 @@ describe("global config updates", () => {
})
describe("kilocode web search config", () => {
- test("accepts the websearch availability setting", () => {
- const config = Schema.decodeUnknownSync(Config.Info)({ web_search: true })
+ test("accepts explicitly limiting web search to managed providers", () => {
+ const config = Schema.decodeUnknownSync(Config.Info)({ web_search: false })
- expect(config.web_search).toBe(true)
+ expect(config.web_search).toBe(false)
})
})
diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts
index 97e4e6c51c..2420506b9d 100644
--- a/packages/opencode/test/tool/registry.test.ts
+++ b/packages/opencode/test/tool/registry.test.ts
@@ -125,7 +125,21 @@ const websearch = testEffect(
config: {
get: () =>
Effect.succeed({
- web_search: true,
+ provider: { openai: { options: { apiKey: "test-openai-key" } } },
+ }),
+ },
+ }),
+ node,
+ Agent.defaultLayer,
+ ),
+)
+const websearchOff = testEffect(
+ Layer.mergeAll(
+ registryLayer({
+ config: {
+ get: () =>
+ Effect.succeed({
+ web_search: false,
provider: { openai: { options: { apiKey: "test-openai-key" } } },
}),
},
@@ -155,23 +169,7 @@ function sandboxProfile(): Profile {
describe("tool.registry", () => {
// kilocode_change start
- it.instance("hides websearch for a third-party provider by default", () =>
- Effect.gen(function* () {
- const registry = yield* ToolRegistry.Service
- const agent = yield* Agent.Service
- const build = yield* agent.get("build")
- if (!build) return yield* Effect.die(new Error("build agent not found"))
- const tools = yield* registry.tools({
- providerID: ProviderV2.ID.openai,
- modelID: ModelV2.ID.make("test"),
- agent: build,
- })
-
- expect(tools.map((tool) => tool.id)).not.toContain("websearch")
- }),
- )
-
- websearch.instance("shows websearch for a configured third-party provider when enabled", () =>
+ websearch.instance("shows websearch by default for a configured third-party provider", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
const agent = yield* Agent.Service
@@ -187,6 +185,22 @@ describe("tool.registry", () => {
}),
)
+ websearchOff.instance("hides websearch for a configured third-party provider when disabled", () =>
+ Effect.gen(function* () {
+ const registry = yield* ToolRegistry.Service
+ const agent = yield* Agent.Service
+ const build = yield* agent.get("build")
+ if (!build) return yield* Effect.die(new Error("build agent not found"))
+ const tools = yield* registry.tools({
+ providerID: ProviderV2.ID.openai,
+ modelID: ModelV2.ID.make("test"),
+ agent: build,
+ })
+
+ expect(tools.map((tool) => tool.id)).not.toContain("websearch")
+ }),
+ )
+
sandboxed.instance("preserves built-in network classification through production tool definition processing", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
From c5d3032118aa87cdecb3ae40f1117344762efd2b Mon Sep 17 00:00:00 2001
From: Josh Lambert
Date: Mon, 27 Jul 2026 14:47:11 -0400
Subject: [PATCH 005/100] fix: keep third-party web search opt-in
---
.changeset/enable-websearch-config.md | 2 +-
packages/core/src/v1/config/config.ts | 3 +-
.../src/routes/config/ToolsRoute.tsx | 2 +-
.../src/components/settings/BrowserTab.tsx | 2 +-
packages/opencode/src/tool/registry.ts | 2 +-
.../test/kilocode/config/config.test.ts | 6 +--
packages/opencode/test/tool/registry.test.ts | 50 +++++++------------
7 files changed, 26 insertions(+), 41 deletions(-)
diff --git a/.changeset/enable-websearch-config.md b/.changeset/enable-websearch-config.md
index ebbc4135f3..cd47a9e9fb 100644
--- a/.changeset/enable-websearch-config.md
+++ b/.changeset/enable-websearch-config.md
@@ -3,4 +3,4 @@
"kilo-code": patch
---
-Configure web search for models from all providers through Kilo configuration, VS Code settings, and Kilo Console settings.
+Allow users to enable web search for models from all providers through Kilo configuration, VS Code settings, and Kilo Console settings.
diff --git a/packages/core/src/v1/config/config.ts b/packages/core/src/v1/config/config.ts
index 0ef9d1ffc7..fea9a7f598 100644
--- a/packages/core/src/v1/config/config.ts
+++ b/packages/core/src/v1/config/config.ts
@@ -227,8 +227,7 @@ export const Info = Schema.Struct({
permission: Schema.optional(ConfigPermissionV1.Info),
tools: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),
web_search: Schema.optional(Schema.Boolean).annotate({
- description:
- "Make web search available to models from all providers (default: true). Set to false to limit it to managed providers.",
+ description: "Make web search available to models from all providers (default: false)",
}), // kilocode_change
attachment: Schema.optional(ConfigAttachmentV1.Info).annotate({
description: "Attachment processing configuration, including image size limits and resizing behavior",
diff --git a/packages/kilo-console/src/routes/config/ToolsRoute.tsx b/packages/kilo-console/src/routes/config/ToolsRoute.tsx
index fae54f6b8c..9dcb20b6e0 100644
--- a/packages/kilo-console/src/routes/config/ToolsRoute.tsx
+++ b/packages/kilo-console/src/routes/config/ToolsRoute.tsx
@@ -12,7 +12,7 @@ export function ToolsRoute() {
const [search, setSearch] = createSignal("")
const snap = () => ctx.data()
const websearch = createMemo(() => snap()?.overlay.fields.web_search)
- const searchEnabled = createMemo(() => websearch()?.value !== false)
+ const searchEnabled = createMemo(() => websearch()?.value === true)
const rows = createMemo(() => {
const data = snap()
if (!data) return []
diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
index ca870fef21..fabc7858b8 100644
--- a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
+++ b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx
@@ -86,7 +86,7 @@ const BrowserTab: Component = () => {
description={t("settings.webTools.webSearch.description")}
last
>
-
+
{t("settings.webTools.webSearch.title")}
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index 4f7c275cfa..4df567dd6b 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -377,7 +377,7 @@ export const layer: Layer.Layer<
const filtered = (yield* all()).filter((tool) => {
if (!KiloToolRegistry.available(tool, input.agent)) return false // kilocode_change
if (tool.id === WebSearchTool.id) {
- if (cfg.web_search !== false) return true // kilocode_change
+ if (cfg.web_search === true) return true // kilocode_change
return webSearchEnabled(input.providerID, { exa: flags.enableExa, parallel: flags.enableParallel })
}
diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts
index 3938950306..c384d76dff 100644
--- a/packages/opencode/test/kilocode/config/config.test.ts
+++ b/packages/opencode/test/kilocode/config/config.test.ts
@@ -152,10 +152,10 @@ describe("global config updates", () => {
})
describe("kilocode web search config", () => {
- test("accepts explicitly limiting web search to managed providers", () => {
- const config = Schema.decodeUnknownSync(Config.Info)({ web_search: false })
+ test("accepts enabling web search for all providers", () => {
+ const config = Schema.decodeUnknownSync(Config.Info)({ web_search: true })
- expect(config.web_search).toBe(false)
+ expect(config.web_search).toBe(true)
})
})
diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts
index 2420506b9d..97e4e6c51c 100644
--- a/packages/opencode/test/tool/registry.test.ts
+++ b/packages/opencode/test/tool/registry.test.ts
@@ -125,21 +125,7 @@ const websearch = testEffect(
config: {
get: () =>
Effect.succeed({
- provider: { openai: { options: { apiKey: "test-openai-key" } } },
- }),
- },
- }),
- node,
- Agent.defaultLayer,
- ),
-)
-const websearchOff = testEffect(
- Layer.mergeAll(
- registryLayer({
- config: {
- get: () =>
- Effect.succeed({
- web_search: false,
+ web_search: true,
provider: { openai: { options: { apiKey: "test-openai-key" } } },
}),
},
@@ -169,23 +155,7 @@ function sandboxProfile(): Profile {
describe("tool.registry", () => {
// kilocode_change start
- websearch.instance("shows websearch by default for a configured third-party provider", () =>
- Effect.gen(function* () {
- const registry = yield* ToolRegistry.Service
- const agent = yield* Agent.Service
- const build = yield* agent.get("build")
- if (!build) return yield* Effect.die(new Error("build agent not found"))
- const tools = yield* registry.tools({
- providerID: ProviderV2.ID.openai,
- modelID: ModelV2.ID.make("test"),
- agent: build,
- })
-
- expect(tools.map((tool) => tool.id)).toContain("websearch")
- }),
- )
-
- websearchOff.instance("hides websearch for a configured third-party provider when disabled", () =>
+ it.instance("hides websearch for a third-party provider by default", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
const agent = yield* Agent.Service
@@ -201,6 +171,22 @@ describe("tool.registry", () => {
}),
)
+ websearch.instance("shows websearch for a configured third-party provider when enabled", () =>
+ Effect.gen(function* () {
+ const registry = yield* ToolRegistry.Service
+ const agent = yield* Agent.Service
+ const build = yield* agent.get("build")
+ if (!build) return yield* Effect.die(new Error("build agent not found"))
+ const tools = yield* registry.tools({
+ providerID: ProviderV2.ID.openai,
+ modelID: ModelV2.ID.make("test"),
+ agent: build,
+ })
+
+ expect(tools.map((tool) => tool.id)).toContain("websearch")
+ }),
+ )
+
sandboxed.instance("preserves built-in network classification through production tool definition processing", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
From 605dc483e84fbbc3ff5e213e057f3791a14e9299 Mon Sep 17 00:00:00 2001
From: Josh Lambert
Date: Mon, 27 Jul 2026 17:30:02 -0400
Subject: [PATCH 006/100] chore(sdk): minimize web search schema diff
---
packages/sdk/openapi.json | 5637 +++++++++++++++++++++++++++----------
1 file changed, 4111 insertions(+), 1526 deletions(-)
diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json
index 1451c3a6b3..7bd369f6bb 100644
--- a/packages/sdk/openapi.json
+++ b/packages/sdk/openapi.json
@@ -4211,10 +4211,10 @@
]
}
},
- "/experimental/project/{projectID}/copy": {
+ "/experimental/project/{projectID}/copy/generate-name": {
"post": {
"tags": ["projectCopy"],
- "operationId": "experimental.projectCopy.create",
+ "operationId": "experimental.projectCopy.generateName",
"parameters": [
{
"name": "projectID",
@@ -4224,6 +4224,14 @@
},
"required": true
},
+ {
+ "name": "directory",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ },
+ "required": false
+ },
{
"name": "workspace",
"in": "query",
@@ -4235,56 +4243,45 @@
],
"responses": {
"200": {
- "description": "Project copy created",
+ "description": "Success",
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/ProjectCopyCopy"
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": ["name"],
+ "additionalProperties": false
}
}
}
},
"400": {
- "description": "ProjectCopyError | InvalidRequestError",
+ "description": "Bad request",
"content": {
"application/json": {
"schema": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/ProjectCopyError"
- },
- {
- "$ref": "#/components/schemas/InvalidRequestError"
- }
- ]
+ "$ref": "#/components/schemas/BadRequestError"
}
}
}
}
},
- "description": "Create a local physical copy of a project using the selected strategy.",
- "summary": "Create project copy",
+ "description": "Generate a short name for a project copy from task context.",
+ "summary": "Generate project copy name",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "strategy": {
- "type": "string",
- "enum": ["git_worktree"]
- },
- "directory": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
"context": {
"type": "string"
}
},
- "required": ["strategy", "directory"],
"additionalProperties": false
}
}
@@ -4293,145 +4290,7 @@
"x-codeSamples": [
{
"lang": "js",
- "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.experimental.projectCopy.create({\n ...\n})"
- }
- ]
- },
- "delete": {
- "tags": ["projectCopy"],
- "operationId": "experimental.projectCopy.remove",
- "parameters": [
- {
- "name": "projectID",
- "in": "path",
- "schema": {
- "type": "string"
- },
- "required": true
- },
- {
- "name": "directory",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
- },
- {
- "name": "workspace",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
- }
- ],
- "responses": {
- "204": {
- "description": "Project copy removed"
- },
- "400": {
- "description": "ProjectCopyError | InvalidRequestError",
- "content": {
- "application/json": {
- "schema": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/ProjectCopyError"
- },
- {
- "$ref": "#/components/schemas/InvalidRequestError"
- }
- ]
- }
- }
- }
- }
- },
- "description": "Remove a local physical copy of a project using the selected strategy.",
- "summary": "Remove project copy",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "directory": {
- "type": "string"
- }
- },
- "required": ["directory"],
- "additionalProperties": false
- }
- }
- }
- },
- "x-codeSamples": [
- {
- "lang": "js",
- "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.experimental.projectCopy.remove({\n ...\n})"
- }
- ]
- }
- },
- "/experimental/project/{projectID}/copy/refresh": {
- "post": {
- "tags": ["projectCopy"],
- "operationId": "experimental.projectCopy.refresh",
- "parameters": [
- {
- "name": "projectID",
- "in": "path",
- "schema": {
- "type": "string"
- },
- "required": true
- },
- {
- "name": "directory",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
- },
- {
- "name": "workspace",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
- }
- ],
- "responses": {
- "204": {
- "description": "Project copies refreshed"
- },
- "400": {
- "description": "ProjectCopyError | InvalidRequestError",
- "content": {
- "application/json": {
- "schema": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/ProjectCopyError"
- },
- {
- "$ref": "#/components/schemas/InvalidRequestError"
- }
- ]
- }
- }
- }
- }
- },
- "description": "Discover local project copies using one or all configured strategies.",
- "summary": "Refresh project copies",
- "x-codeSamples": [
- {
- "lang": "js",
- "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.experimental.projectCopy.refresh({\n ...\n})"
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.experimental.projectCopy.generateName({\n ...\n})"
}
]
}
@@ -14735,6 +14594,16 @@
}
}
}
+ },
+ "500": {
+ "description": "CloudSessionImportError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CloudSessionImportError"
+ }
+ }
+ }
}
},
"description": "Download a cloud-synced session and write it to local storage with fresh IDs.",
@@ -16890,6 +16759,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -19898,7 +19771,7 @@
},
"/api/health": {
"get": {
- "tags": ["kilo experimental HttpApi"],
+ "tags": ["Kilo HttpApi"],
"operationId": "v2.health.get",
"parameters": [],
"security": [],
@@ -19942,8 +19815,8 @@
}
}
},
- "description": "Check whether the v2 API server is ready to accept requests.",
- "summary": "Check v2 server health",
+ "description": "Check whether the API server is ready to accept requests.",
+ "summary": "Check server health",
"x-codeSamples": [
{
"lang": "js",
@@ -19952,9 +19825,77 @@
]
}
},
+ "/api/location": {
+ "get": {
+ "tags": ["Kilo HttpApi"],
+ "operationId": "v2.location.get",
+ "parameters": [
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Location.Info",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LocationInfo"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Resolve the requested location or the server default location.",
+ "summary": "Get location",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.location.get({\n ...\n})"
+ }
+ ]
+ }
+ },
"/api/agent": {
"get": {
- "tags": ["kilo experimental HttpApi"],
+ "tags": ["Kilo HttpApi"],
"operationId": "v2.agent.list",
"parameters": [
{
@@ -20023,8 +19964,8 @@
}
}
},
- "description": "Retrieve currently registered v2 agents.",
- "summary": "List v2 agents",
+ "description": "Retrieve currently registered agents.",
+ "summary": "List agents",
"x-codeSamples": [
{
"lang": "js",
@@ -20035,7 +19976,7 @@
},
"/api/session": {
"get": {
- "tags": ["v2"],
+ "tags": ["sessions"],
"operationId": "v2.session.list",
"parameters": [
{
@@ -20109,11 +20050,11 @@
"security": [],
"responses": {
"200": {
- "description": "V2SessionsResponse",
+ "description": "SessionsResponse",
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/V2SessionsResponse"
+ "$ref": "#/components/schemas/SessionsResponse"
}
}
}
@@ -20150,18 +20091,192 @@
}
},
"description": "Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.",
- "summary": "List v2 sessions",
+ "summary": "List sessions",
"x-codeSamples": [
{
"lang": "js",
"source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.list({\n ...\n})"
}
]
+ },
+ "post": {
+ "tags": ["sessions"],
+ "operationId": "v2.session.create",
+ "parameters": [],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/SessionV2Info"
+ }
+ },
+ "required": ["data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Create a session at the requested location.",
+ "summary": "Create session",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ "agent": {
+ "type": "string"
+ },
+ "model": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "providerID": {
+ "type": "string"
+ },
+ "variant": {
+ "type": "string"
+ }
+ },
+ "required": ["id", "providerID"],
+ "additionalProperties": false
+ },
+ "location": {
+ "$ref": "#/components/schemas/LocationRef"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.create({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/session/{sessionID}": {
+ "get": {
+ "tags": ["sessions"],
+ "operationId": "v2.session.get",
+ "parameters": [
+ {
+ "name": "sessionID",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^ses.*"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/SessionV2Info"
+ }
+ },
+ "required": ["data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "SessionNotFoundError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve a session by ID.",
+ "summary": "Get session",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.get({\n ...\n})"
+ }
+ ]
}
},
"/api/session/{sessionID}/prompt": {
"post": {
- "tags": ["v2"],
+ "tags": ["sessions"],
"operationId": "v2.session.prompt",
"parameters": [
{
@@ -20218,7 +20333,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
}
}
}
@@ -20234,8 +20356,8 @@
}
}
},
- "description": "Durably admit one v2 session input and schedule agent-loop execution unless resume is false.",
- "summary": "Send v2 message",
+ "description": "Durably admit one session input and schedule agent-loop execution unless resume is false.",
+ "summary": "Send message",
"requestBody": {
"content": {
"application/json": {
@@ -20274,7 +20396,7 @@
},
"/api/session/{sessionID}/compact": {
"post": {
- "tags": ["v2"],
+ "tags": ["sessions"],
"operationId": "v2.session.compact",
"parameters": [
{
@@ -20317,7 +20439,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
}
}
}
@@ -20333,8 +20462,8 @@
}
}
},
- "description": "Compact a v2 session conversation.",
- "summary": "Compact v2 session",
+ "description": "Compact a session conversation.",
+ "summary": "Compact session",
"x-codeSamples": [
{
"lang": "js",
@@ -20345,7 +20474,7 @@
},
"/api/session/{sessionID}/wait": {
"post": {
- "tags": ["v2"],
+ "tags": ["sessions"],
"operationId": "v2.session.wait",
"parameters": [
{
@@ -20388,7 +20517,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
}
}
}
@@ -20404,8 +20540,8 @@
}
}
},
- "description": "Wait for a v2 session agent loop to become idle.",
- "summary": "Wait for v2 session",
+ "description": "Wait for a session agent loop to become idle.",
+ "summary": "Wait for session",
"x-codeSamples": [
{
"lang": "js",
@@ -20416,7 +20552,7 @@
},
"/api/session/{sessionID}/context": {
"get": {
- "tags": ["v2"],
+ "tags": ["sessions"],
"operationId": "v2.session.context",
"parameters": [
{
@@ -20476,7 +20612,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
}
}
}
@@ -20492,8 +20635,8 @@
}
}
},
- "description": "Retrieve the active context messages for a v2 session (all messages after the last compaction).",
- "summary": "Get v2 session context",
+ "description": "Retrieve the active context messages for a session (all messages after the last compaction).",
+ "summary": "Get session context",
"x-codeSamples": [
{
"lang": "js",
@@ -20504,7 +20647,7 @@
},
"/api/session/{sessionID}/message": {
"get": {
- "tags": ["v2 messages"],
+ "tags": ["messages"],
"operationId": "v2.session.messages",
"parameters": [
{
@@ -20546,11 +20689,11 @@
"security": [],
"responses": {
"200": {
- "description": "V2SessionMessagesResponse",
+ "description": "SessionMessagesResponse",
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/V2SessionMessagesResponse"
+ "$ref": "#/components/schemas/SessionMessagesResponse"
}
}
}
@@ -20587,7 +20730,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
}
}
}
@@ -20603,8 +20753,8 @@
}
}
},
- "description": "Retrieve projected v2 messages for a session. Items keep the requested order across pages; use cursor.next or cursor.previous to move through the ordered timeline.",
- "summary": "Get v2 session messages",
+ "description": "Retrieve projected messages for a session. Items keep the requested order across pages; use cursor.next or cursor.previous to move through the ordered timeline.",
+ "summary": "Get session messages",
"x-codeSamples": [
{
"lang": "js",
@@ -20615,7 +20765,7 @@
},
"/api/model": {
"get": {
- "tags": ["v2 models"],
+ "tags": ["models"],
"operationId": "v2.model.list",
"parameters": [
{
@@ -20694,8 +20844,8 @@
}
}
},
- "description": "Retrieve available v2 models ordered by release date.",
- "summary": "List v2 models",
+ "description": "Retrieve available models ordered by release date.",
+ "summary": "List models",
"x-codeSamples": [
{
"lang": "js",
@@ -20706,7 +20856,7 @@
},
"/api/provider": {
"get": {
- "tags": ["v2 providers"],
+ "tags": ["providers"],
"operationId": "v2.provider.list",
"parameters": [
{
@@ -20785,8 +20935,8 @@
}
}
},
- "description": "Retrieve active v2 AI providers so clients can show provider availability and configuration.",
- "summary": "List v2 providers",
+ "description": "Retrieve active AI providers so clients can show provider availability and configuration.",
+ "summary": "List providers",
"x-codeSamples": [
{
"lang": "js",
@@ -20797,7 +20947,7 @@
},
"/api/provider/{providerID}": {
"get": {
- "tags": ["v2 providers"],
+ "tags": ["providers"],
"operationId": "v2.provider.get",
"parameters": [
{
@@ -20891,8 +21041,8 @@
}
}
},
- "description": "Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings.",
- "summary": "Get v2 provider",
+ "description": "Retrieve a single AI provider so clients can inspect its availability and endpoint settings.",
+ "summary": "Get provider",
"x-codeSamples": [
{
"lang": "js",
@@ -20901,9 +21051,1011 @@
]
}
},
+ "/api/integration": {
+ "get": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.list",
+ "parameters": [
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/IntegrationInfo"
+ }
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve available integrations and their authentication methods.",
+ "summary": "List integrations",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.list({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/integration/{integrationID}": {
+ "get": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.get",
+ "parameters": [
+ {
+ "name": "integrationID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "$ref": "#/components/schemas/IntegrationInfo"
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve one integration and its authentication methods.",
+ "summary": "Get integration",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.get({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/integration/{integrationID}/connect/key": {
+ "post": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.connect.key",
+ "parameters": [
+ {
+ "name": "integrationID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Run a key authentication method and store the resulting credential.",
+ "summary": "Connect with key",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "label": {
+ "type": "string"
+ }
+ },
+ "required": ["key"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.connect.key({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/integration/{integrationID}/connect/oauth": {
+ "post": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.connect.oauth",
+ "parameters": [
+ {
+ "name": "integrationID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "$ref": "#/components/schemas/IntegrationAttempt"
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Start an OAuth attempt and return the authorization details.",
+ "summary": "Begin OAuth connection",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "methodID": {
+ "type": "string"
+ },
+ "inputs": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "label": {
+ "type": "string"
+ }
+ },
+ "required": ["methodID", "inputs"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.connect.oauth({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/integration/attempt/{attemptID}": {
+ "get": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.attempt.status",
+ "parameters": [
+ {
+ "name": "attemptID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["pending"]
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "expires": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ }
+ },
+ "required": ["created", "expires"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["status", "time"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["complete"]
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "expires": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ }
+ },
+ "required": ["created", "expires"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["status", "time"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["failed"]
+ },
+ "message": {
+ "type": "string"
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "expires": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ }
+ },
+ "required": ["created", "expires"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["status", "message", "time"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["expired"]
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "expires": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ }
+ },
+ "required": ["created", "expires"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["status", "time"],
+ "additionalProperties": false
+ }
+ ]
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Poll the current status of an OAuth attempt.",
+ "summary": "Get OAuth attempt status",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.attempt.status({\n ...\n})"
+ }
+ ]
+ },
+ "delete": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.attempt.cancel",
+ "parameters": [
+ {
+ "name": "attemptID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Cancel an OAuth attempt and release its resources.",
+ "summary": "Cancel OAuth connection",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.attempt.cancel({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/integration/attempt/{attemptID}/complete": {
+ "post": {
+ "tags": ["integrations"],
+ "operationId": "v2.integration.attempt.complete",
+ "parameters": [
+ {
+ "name": "attemptID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Complete a code-based OAuth attempt and store the resulting credential.",
+ "summary": "Complete OAuth connection",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.integration.attempt.complete({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/credential/{credentialID}": {
+ "patch": {
+ "tags": ["Kilo HttpApi"],
+ "operationId": "v2.credential.update",
+ "parameters": [
+ {
+ "name": "credentialID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Update a stored credential label.",
+ "summary": "Update credential",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "type": "string"
+ }
+ },
+ "required": ["label"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.credential.update({\n ...\n})"
+ }
+ ]
+ },
+ "delete": {
+ "tags": ["Kilo HttpApi"],
+ "operationId": "v2.credential.remove",
+ "parameters": [
+ {
+ "name": "credentialID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Remove a stored integration credential.",
+ "summary": "Remove credential",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.credential.remove({\n ...\n})"
+ }
+ ]
+ }
+ },
"/api/permission/request": {
"get": {
- "tags": ["v2 permissions"],
+ "tags": ["permissions"],
"operationId": "v2.permission.request.list",
"parameters": [
{
@@ -20982,184 +22134,9 @@
]
}
},
- "/api/session/{sessionID}/permission/request": {
- "get": {
- "tags": ["v2 session permissions"],
- "operationId": "v2.session.permission.list",
- "parameters": [
- {
- "name": "sessionID",
- "in": "path",
- "schema": {
- "type": "string",
- "pattern": "^ses.*"
- },
- "required": true
- }
- ],
- "security": [],
- "responses": {
- "200": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/PermissionV2Request"
- }
- }
- },
- "required": ["data"],
- "additionalProperties": false
- }
- }
- }
- },
- "400": {
- "description": "InvalidRequestError",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/InvalidRequestError"
- }
- }
- }
- },
- "401": {
- "description": "UnauthorizedError",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UnauthorizedError"
- }
- }
- }
- },
- "404": {
- "description": "SessionNotFoundError",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SessionNotFoundError"
- }
- }
- }
- }
- },
- "description": "Retrieve pending permission requests owned by a session.",
- "summary": "List session permission requests",
- "x-codeSamples": [
- {
- "lang": "js",
- "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.permission.list({\n ...\n})"
- }
- ]
- }
- },
- "/api/session/{sessionID}/permission/request/{requestID}/reply": {
- "post": {
- "tags": ["v2 session permissions"],
- "operationId": "v2.session.permission.reply",
- "parameters": [
- {
- "name": "sessionID",
- "in": "path",
- "schema": {
- "type": "string",
- "pattern": "^ses.*"
- },
- "required": true
- },
- {
- "name": "requestID",
- "in": "path",
- "schema": {
- "type": "string",
- "pattern": "^per"
- },
- "required": true
- }
- ],
- "security": [],
- "responses": {
- "204": {
- "description": ""
- },
- "400": {
- "description": "InvalidRequestError",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/InvalidRequestError"
- }
- }
- }
- },
- "401": {
- "description": "UnauthorizedError",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UnauthorizedError"
- }
- }
- }
- },
- "404": {
- "description": "SessionNotFoundError | PermissionNotFoundError",
- "content": {
- "application/json": {
- "schema": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/SessionNotFoundError"
- },
- {
- "$ref": "#/components/schemas/PermissionNotFoundError"
- }
- ]
- }
- }
- }
- }
- },
- "description": "Respond to a pending permission request owned by a session.",
- "summary": "Reply to pending permission request",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "reply": {
- "$ref": "#/components/schemas/PermissionV2Reply"
- },
- "message": {
- "type": "string"
- }
- },
- "required": ["reply"],
- "additionalProperties": false
- }
- }
- },
- "required": true
- },
- "x-codeSamples": [
- {
- "lang": "js",
- "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.permission.reply({\n ...\n})"
- }
- ]
- }
- },
"/api/permission/saved": {
"get": {
- "tags": ["v2 saved permissions"],
+ "tags": ["permissions"],
"operationId": "v2.permission.saved.list",
"parameters": [
{
@@ -21226,7 +22203,7 @@
},
"/api/permission/saved/{id}": {
"delete": {
- "tags": ["v2 saved permissions"],
+ "tags": ["permissions"],
"operationId": "v2.permission.saved.remove",
"parameters": [
{
@@ -21274,9 +22251,194 @@
]
}
},
- "/api/fs/read": {
+ "/api/session/{sessionID}/permission": {
"get": {
- "tags": ["v2 filesystem"],
+ "tags": ["permissions"],
+ "operationId": "v2.session.permission.list",
+ "parameters": [
+ {
+ "name": "sessionID",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^ses.*"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PermissionV2Request"
+ }
+ }
+ },
+ "required": ["data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "SessionNotFoundError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve pending permission requests owned by a session.",
+ "summary": "List session permission requests",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.permission.list({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/session/{sessionID}/permission/{requestID}/reply": {
+ "post": {
+ "tags": ["permissions"],
+ "operationId": "v2.session.permission.reply",
+ "parameters": [
+ {
+ "name": "sessionID",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^ses.*"
+ },
+ "required": true
+ },
+ {
+ "name": "requestID",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^per"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "SessionNotFoundError | PermissionNotFoundError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/PermissionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "description": "Respond to a pending permission request owned by a session.",
+ "summary": "Reply to pending permission request",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "reply": {
+ "$ref": "#/components/schemas/PermissionV2Reply"
+ },
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": ["reply"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": true
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.permission.reply({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/fs/read/*": {
+ "get": {
+ "tags": ["filesystem"],
"operationId": "v2.fs.read",
"parameters": [
{
@@ -21304,14 +22466,6 @@
"schema": {
"type": "string"
},
- "required": true
- },
- {
- "name": "reference",
- "in": "query",
- "schema": {
- "type": "string"
- },
"required": false
}
],
@@ -21320,26 +22474,10 @@
"200": {
"description": "Success",
"content": {
- "application/json": {
+ "application/octet-stream": {
"schema": {
- "type": "object",
- "properties": {
- "location": {
- "$ref": "#/components/schemas/LocationInfo"
- },
- "data": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/FileSystemTextContent"
- },
- {
- "$ref": "#/components/schemas/FileSystemBinaryContent"
- }
- ]
- }
- },
- "required": ["location", "data"],
- "additionalProperties": false
+ "type": "string",
+ "format": "binary"
}
}
}
@@ -21365,7 +22503,7 @@
}
}
},
- "description": "Read one file relative to the requested location.",
+ "description": "Serve one file relative to the requested location.",
"summary": "Read file",
"x-codeSamples": [
{
@@ -21377,7 +22515,7 @@
},
"/api/fs/list": {
"get": {
- "tags": ["v2 filesystem"],
+ "tags": ["filesystem"],
"operationId": "v2.fs.list",
"parameters": [
{
@@ -21406,14 +22544,6 @@
"type": "string"
},
"required": false
- },
- {
- "name": "reference",
- "in": "query",
- "schema": {
- "type": "string"
- },
- "required": false
}
],
"security": [],
@@ -21472,9 +22602,115 @@
]
}
},
+ "/api/fs/find": {
+ "get": {
+ "tags": ["filesystem"],
+ "operationId": "v2.fs.find",
+ "parameters": [
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ },
+ {
+ "name": "query",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "type",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "enum": ["file", "directory"]
+ },
+ "required": false
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ },
+ "required": false
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FileSystemEntry"
+ }
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Find recursively ranked filesystem entries relative to the requested location.",
+ "summary": "Find files",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.fs.find({\n ...\n})"
+ }
+ ]
+ }
+ },
"/api/command": {
"get": {
- "tags": ["v2 commands"],
+ "tags": ["commands"],
"operationId": "v2.command.list",
"parameters": [
{
@@ -21543,8 +22779,8 @@
}
}
},
- "description": "Retrieve currently registered v2 commands.",
- "summary": "List v2 commands",
+ "description": "Retrieve currently registered commands.",
+ "summary": "List commands",
"x-codeSamples": [
{
"lang": "js",
@@ -21555,7 +22791,7 @@
},
"/api/skill": {
"get": {
- "tags": ["v2 skills"],
+ "tags": ["skills"],
"operationId": "v2.skill.list",
"parameters": [
{
@@ -21624,8 +22860,8 @@
}
}
},
- "description": "Retrieve currently registered v2 skills.",
- "summary": "List v2 skills",
+ "description": "Retrieve currently registered skills.",
+ "summary": "List skills",
"x-codeSamples": [
{
"lang": "js",
@@ -21636,7 +22872,7 @@
},
"/api/event": {
"get": {
- "tags": ["v2 events"],
+ "tags": ["events"],
"operationId": "v2.event.subscribe",
"parameters": [
{
@@ -21692,8 +22928,8 @@
}
}
},
- "description": "Subscribe to native EventV2 payloads for a location.",
- "summary": "Subscribe to v2 events",
+ "description": "Subscribe to native event payloads for a location.",
+ "summary": "Subscribe to events",
"x-codeSamples": [
{
"lang": "js",
@@ -21704,7 +22940,7 @@
},
"/api/question/request": {
"get": {
- "tags": ["v2 questions"],
+ "tags": ["session questions"],
"operationId": "v2.question.request.list",
"parameters": [
{
@@ -21783,9 +23019,94 @@
]
}
},
- "/api/session/{sessionID}/question/request/{requestID}/reply": {
+ "/api/session/{sessionID}/question": {
+ "get": {
+ "tags": ["session questions"],
+ "operationId": "v2.session.question.list",
+ "parameters": [
+ {
+ "name": "sessionID",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^ses.*"
+ },
+ "required": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/QuestionV2Request"
+ }
+ }
+ },
+ "required": ["data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "SessionNotFoundError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ },
+ {
+ "$ref": "#/components/schemas/SessionNotFoundError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve pending question requests owned by a session.",
+ "summary": "List session question requests",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.session.question.list({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/api/session/{sessionID}/question/{requestID}/reply": {
"post": {
- "tags": ["v2 session questions"],
+ "tags": ["session questions"],
"operationId": "v2.session.question.reply",
"parameters": [
{
@@ -21838,11 +23159,14 @@
"application/json": {
"schema": {
"anyOf": [
+ {
+ "$ref": "#/components/schemas/QuestionNotFoundError"
+ },
{
"$ref": "#/components/schemas/SessionNotFoundError"
},
{
- "$ref": "#/components/schemas/QuestionNotFoundError"
+ "$ref": "#/components/schemas/SessionNotFoundError"
}
]
}
@@ -21870,9 +23194,9 @@
]
}
},
- "/api/session/{sessionID}/question/request/{requestID}/reject": {
+ "/api/session/{sessionID}/question/{requestID}/reject": {
"post": {
- "tags": ["v2 session questions"],
+ "tags": ["session questions"],
"operationId": "v2.session.question.reject",
"parameters": [
{
@@ -21925,11 +23249,14 @@
"application/json": {
"schema": {
"anyOf": [
+ {
+ "$ref": "#/components/schemas/QuestionNotFoundError"
+ },
{
"$ref": "#/components/schemas/SessionNotFoundError"
},
{
- "$ref": "#/components/schemas/QuestionNotFoundError"
+ "$ref": "#/components/schemas/SessionNotFoundError"
}
]
}
@@ -21947,6 +23274,322 @@
]
}
},
+ "/api/reference": {
+ "get": {
+ "tags": ["reference"],
+ "operationId": "v2.reference.list",
+ "parameters": [
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "security": [],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "$ref": "#/components/schemas/LocationInfo"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ReferenceInfo"
+ }
+ }
+ },
+ "required": ["location", "data"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "UnauthorizedError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnauthorizedError"
+ }
+ }
+ }
+ }
+ },
+ "description": "List references available in the requested location.",
+ "summary": "List references",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.reference.list({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/experimental/project/{projectID}/copy": {
+ "post": {
+ "tags": ["projectCopy"],
+ "operationId": "v2.projectCopy.create",
+ "parameters": [
+ {
+ "name": "projectID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "ProjectCopy.Copy",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ProjectCopyCopy"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "ProjectCopyError | InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/ProjectCopyError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string"
+ },
+ "directory": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": ["strategy", "directory"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.projectCopy.create({\n ...\n})"
+ }
+ ]
+ },
+ "delete": {
+ "tags": ["projectCopy"],
+ "operationId": "v2.projectCopy.remove",
+ "parameters": [
+ {
+ "name": "projectID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "ProjectCopyError | InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/ProjectCopyError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "force": {
+ "type": "boolean"
+ }
+ },
+ "required": ["directory", "force"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.projectCopy.remove({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/experimental/project/{projectID}/copy/refresh": {
+ "post": {
+ "tags": ["projectCopy"],
+ "operationId": "v2.projectCopy.refresh",
+ "parameters": [
+ {
+ "name": "projectID",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "location",
+ "in": "query",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "workspace": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "required": false,
+ "style": "deepObject",
+ "explode": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": ""
+ },
+ "400": {
+ "description": "ProjectCopyError | InvalidRequestError",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/ProjectCopyError"
+ },
+ {
+ "$ref": "#/components/schemas/InvalidRequestError"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.v2.projectCopy.refresh({\n ...\n})"
+ }
+ ]
+ }
+ },
"/pty/{ptyID}/connect": {
"get": {
"tags": ["pty"],
@@ -22176,6 +23819,9 @@
{
"$ref": "#/components/schemas/EventSessionNextPromptPromoted"
},
+ {
+ "$ref": "#/components/schemas/EventSessionNextInterruptRequested"
+ },
{
"$ref": "#/components/schemas/EventSessionNextContextUpdated"
},
@@ -22300,61 +23946,10 @@
"$ref": "#/components/schemas/EventPermissionReplied"
},
{
- "$ref": "#/components/schemas/EventTodoUpdated"
+ "$ref": "#/components/schemas/EventReferenceUpdated"
},
{
- "$ref": "#/components/schemas/EventSessionStatus"
- },
- {
- "$ref": "#/components/schemas/EventSessionIdle"
- },
- {
- "$ref": "#/components/schemas/EventSessionCompacted"
- },
- {
- "$ref": "#/components/schemas/EventCommandExecuted"
- },
- {
- "$ref": "#/components/schemas/EventProjectDirectoriesUpdated"
- },
- {
- "$ref": "#/components/schemas/EventProjectUpdated"
- },
- {
- "$ref": "#/components/schemas/EventLspUpdated"
- },
- {
- "$ref": "#/components/schemas/EventFileEdited"
- },
- {
- "$ref": "#/components/schemas/EventFileWatcherUpdated"
- },
- {
- "$ref": "#/components/schemas/EventVcsBranchUpdated"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceReady"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceFailed"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceStatus"
- },
- {
- "$ref": "#/components/schemas/EventWorktreeReady"
- },
- {
- "$ref": "#/components/schemas/EventWorktreeFailed"
- },
- {
- "$ref": "#/components/schemas/EventAccountAdded"
- },
- {
- "$ref": "#/components/schemas/EventAccountRemoved"
- },
- {
- "$ref": "#/components/schemas/EventAccountSwitched"
+ "$ref": "#/components/schemas/EventIntegrationUpdated"
},
{
"$ref": "#/components/schemas/EventPermissionV2Asked"
@@ -22362,6 +23957,15 @@
{
"$ref": "#/components/schemas/EventPermissionV2Replied"
},
+ {
+ "$ref": "#/components/schemas/EventProjectDirectoriesUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventFileEdited"
+ },
+ {
+ "$ref": "#/components/schemas/EventFileWatcherUpdated"
+ },
{
"$ref": "#/components/schemas/EventPtyCreated"
},
@@ -22383,6 +23987,45 @@
{
"$ref": "#/components/schemas/EventQuestionV2Rejected"
},
+ {
+ "$ref": "#/components/schemas/EventTodoUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionStatus"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionIdle"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionCompacted"
+ },
+ {
+ "$ref": "#/components/schemas/EventCommandExecuted"
+ },
+ {
+ "$ref": "#/components/schemas/EventProjectUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventLspUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventVcsBranchUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceReady"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceFailed"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceStatus"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorktreeReady"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorktreeFailed"
+ },
{
"$ref": "#/components/schemas/EventServerInstanceDisposed"
}
@@ -23353,6 +24996,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -23641,6 +25288,27 @@
"required": ["name", "data"],
"additionalProperties": false
},
+ "ContentFilterError": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "enum": ["ContentFilterError"]
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": ["message"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["name", "data"],
+ "additionalProperties": false
+ },
"APIError": {
"type": "object",
"properties": {
@@ -23734,6 +25402,9 @@
{
"$ref": "#/components/schemas/ContextOverflowError"
},
+ {
+ "$ref": "#/components/schemas/ContentFilterError"
+ },
{
"$ref": "#/components/schemas/APIError"
}
@@ -24350,6 +26021,17 @@
},
"snapshot": {
"type": "string"
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "start": {
+ "type": "number",
+ "minimum": 0
+ }
+ },
+ "required": ["start"],
+ "additionalProperties": false
}
},
"required": ["id", "sessionID", "messageID", "type"],
@@ -24393,6 +26075,47 @@
"required": ["providerID", "modelID"],
"additionalProperties": false
},
+ "generationID": {
+ "type": "string"
+ },
+ "vercelID": {
+ "type": "string"
+ },
+ "metrics": {
+ "type": "object",
+ "properties": {
+ "prompt": {
+ "type": "number"
+ },
+ "generation": {
+ "type": "number"
+ },
+ "source": {
+ "type": "string",
+ "enum": ["provider", "computed"]
+ }
+ },
+ "required": ["source"],
+ "additionalProperties": false
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "start": {
+ "type": "number",
+ "minimum": 0
+ },
+ "end": {
+ "type": "number",
+ "minimum": 0
+ },
+ "elapsed": {
+ "type": "number"
+ }
+ },
+ "required": ["start", "end", "elapsed"],
+ "additionalProperties": false
+ },
"cost": {
"type": "number"
},
@@ -24665,12 +26388,6 @@
"items": {
"$ref": "#/components/schemas/PromptAgentAttachment"
}
- },
- "references": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/PromptReferenceAttachment"
- }
}
},
"required": ["text"],
@@ -24981,6 +26698,70 @@
"required": ["name", "data"],
"additionalProperties": false
},
+ "Pty": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^pty"
+ },
+ "title": {
+ "type": "string"
+ },
+ "command": {
+ "type": "string"
+ },
+ "args": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "cwd": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["running", "exited"]
+ },
+ "pid": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "sessionID": {
+ "anyOf": [
+ {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "required": ["id", "title", "command", "args", "cwd", "status", "pid"],
+ "additionalProperties": false
+ },
+ "Todo": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "string",
+ "description": "Brief description of the task"
+ },
+ "status": {
+ "type": "string",
+ "description": "Current status of the task: pending, in_progress, completed, cancelled"
+ },
+ "priority": {
+ "type": "string",
+ "description": "Priority level of the task: high, medium, low"
+ }
+ },
+ "required": ["content", "status", "priority"],
+ "additionalProperties": false
+ },
"SessionStatus": {
"anyOf": [
{
@@ -25072,51 +26853,6 @@
}
]
},
- "Pty": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string",
- "pattern": "^pty"
- },
- "title": {
- "type": "string"
- },
- "command": {
- "type": "string"
- },
- "args": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "cwd": {
- "type": "string"
- },
- "status": {
- "type": "string",
- "enum": ["running", "exited"]
- },
- "pid": {
- "type": "integer",
- "minimum": 0
- },
- "sessionID": {
- "anyOf": [
- {
- "type": "string",
- "pattern": "^ses"
- },
- {
- "type": "null"
- }
- ]
- }
- },
- "required": ["id", "title", "command", "args", "cwd", "status", "pid"],
- "additionalProperties": false
- },
"GlobalEvent": {
"type": "object",
"properties": {
@@ -25269,6 +27005,9 @@
{
"$ref": "#/components/schemas/EventSessionNextPromptPromoted"
},
+ {
+ "$ref": "#/components/schemas/EventSessionNextInterruptRequested"
+ },
{
"$ref": "#/components/schemas/EventSessionNextContextUpdated"
},
@@ -25393,61 +27132,10 @@
"$ref": "#/components/schemas/EventPermissionReplied"
},
{
- "$ref": "#/components/schemas/EventTodoUpdated"
+ "$ref": "#/components/schemas/EventReferenceUpdated"
},
{
- "$ref": "#/components/schemas/EventSessionStatus"
- },
- {
- "$ref": "#/components/schemas/EventSessionIdle"
- },
- {
- "$ref": "#/components/schemas/EventSessionCompacted"
- },
- {
- "$ref": "#/components/schemas/EventCommandExecuted"
- },
- {
- "$ref": "#/components/schemas/EventProjectDirectoriesUpdated"
- },
- {
- "$ref": "#/components/schemas/EventProjectUpdated"
- },
- {
- "$ref": "#/components/schemas/EventLspUpdated"
- },
- {
- "$ref": "#/components/schemas/EventFileEdited"
- },
- {
- "$ref": "#/components/schemas/EventFileWatcherUpdated"
- },
- {
- "$ref": "#/components/schemas/EventVcsBranchUpdated"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceReady"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceFailed"
- },
- {
- "$ref": "#/components/schemas/EventWorkspaceStatus"
- },
- {
- "$ref": "#/components/schemas/EventWorktreeReady"
- },
- {
- "$ref": "#/components/schemas/EventWorktreeFailed"
- },
- {
- "$ref": "#/components/schemas/EventAccountAdded"
- },
- {
- "$ref": "#/components/schemas/EventAccountRemoved"
- },
- {
- "$ref": "#/components/schemas/EventAccountSwitched"
+ "$ref": "#/components/schemas/EventIntegrationUpdated"
},
{
"$ref": "#/components/schemas/EventPermissionV2Asked"
@@ -25455,6 +27143,15 @@
{
"$ref": "#/components/schemas/EventPermissionV2Replied"
},
+ {
+ "$ref": "#/components/schemas/EventProjectDirectoriesUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventFileEdited"
+ },
+ {
+ "$ref": "#/components/schemas/EventFileWatcherUpdated"
+ },
{
"$ref": "#/components/schemas/EventPtyCreated"
},
@@ -25476,6 +27173,45 @@
{
"$ref": "#/components/schemas/EventQuestionV2Rejected"
},
+ {
+ "$ref": "#/components/schemas/EventTodoUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionStatus"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionIdle"
+ },
+ {
+ "$ref": "#/components/schemas/EventSessionCompacted"
+ },
+ {
+ "$ref": "#/components/schemas/EventCommandExecuted"
+ },
+ {
+ "$ref": "#/components/schemas/EventProjectUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventLspUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventVcsBranchUpdated"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceReady"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceFailed"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorkspaceStatus"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorktreeReady"
+ },
+ {
+ "$ref": "#/components/schemas/EventWorktreeFailed"
+ },
{
"$ref": "#/components/schemas/EventServerInstanceDisposed"
},
@@ -25575,9 +27311,6 @@
{
"$ref": "#/components/schemas/SyncEventSessionNextCompactionStarted"
},
- {
- "$ref": "#/components/schemas/SyncEventSessionNextCompactionDelta"
- },
{
"$ref": "#/components/schemas/SyncEventSessionNextCompactionEnded"
}
@@ -25618,44 +27351,6 @@
"additionalProperties": false,
"description": "Server configuration for the kilo serve command"
},
- "ReferenceConfigEntry": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "object",
- "properties": {
- "repository": {
- "type": "string",
- "description": "Git repository URL, host/path reference, or GitHub owner/repo shorthand"
- },
- "branch": {
- "type": "string"
- }
- },
- "required": ["repository"],
- "additionalProperties": false
- },
- {
- "type": "object",
- "properties": {
- "path": {
- "type": "string",
- "description": "Absolute path, ~/ path, or workspace-relative path to a local reference directory"
- }
- },
- "required": ["path"],
- "additionalProperties": false
- }
- ]
- },
- "ReferenceConfig": {
- "type": "object",
- "additionalProperties": {
- "$ref": "#/components/schemas/ReferenceConfigEntry"
- }
- },
"IndexingConfig": {
"type": "object",
"properties": {
@@ -25850,7 +27545,8 @@
"items": {
"type": "string",
"pattern": "^\\s*\\.?[A-Za-z0-9][A-Za-z0-9_+-]*\\s*$"
- }
+ },
+ "minItems": 1
}
},
"additionalProperties": false
@@ -26213,7 +27909,7 @@
"properties": {
"field": {
"type": "string",
- "enum": ["reasoning_content", "reasoning_details"]
+ "enum": ["reasoning", "reasoning_content", "reasoning_details"]
}
},
"required": ["field"],
@@ -26539,8 +28235,37 @@
},
"additionalProperties": false
},
+ "references": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "$ref": "#/components/schemas/ConfigV2ReferenceGit"
+ },
+ {
+ "$ref": "#/components/schemas/ConfigV2ReferenceLocal"
+ }
+ ]
+ }
+ },
"reference": {
- "$ref": "#/components/schemas/ReferenceConfig"
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "$ref": "#/components/schemas/ConfigV2ReferenceGit"
+ },
+ {
+ "$ref": "#/components/schemas/ConfigV2ReferenceLocal"
+ }
+ ]
+ }
},
"watcher": {
"type": "object",
@@ -26647,6 +28372,10 @@
"hide_prompt_training_models": {
"type": "boolean"
},
+ "web_search": {
+ "type": "boolean",
+ "description": "Make web search available to models from all providers (default: false)"
+ },
"sandbox": {
"type": "object",
"properties": {
@@ -26905,9 +28634,6 @@
"type": "boolean"
}
},
- "web_search": {
- "type": "boolean"
- },
"attachment": {
"$ref": "#/components/schemas/AttachmentConfig"
},
@@ -27164,7 +28890,7 @@
"properties": {
"field": {
"type": "string",
- "enum": ["reasoning_content", "reasoning_details"]
+ "enum": ["reasoning", "reasoning_content", "reasoning_details"]
}
},
"required": ["field"],
@@ -27809,6 +29535,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -28494,27 +30224,6 @@
"required": ["_tag", "projectID", "message"],
"additionalProperties": false
},
- "ProjectCopyError": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "enum": ["ProjectCopyError"]
- },
- "data": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- },
- "required": ["message"],
- "additionalProperties": false
- }
- },
- "required": ["name", "data"],
- "additionalProperties": false
- },
"PtyNotFoundError": {
"type": "object",
"properties": {
@@ -28977,6 +30686,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -29146,6 +30859,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -29174,25 +30891,6 @@
}
}
},
- "Todo": {
- "type": "object",
- "properties": {
- "content": {
- "type": "string",
- "description": "Brief description of the task"
- },
- "status": {
- "type": "string",
- "description": "Current status of the task: pending, in_progress, completed, cancelled"
- },
- "priority": {
- "type": "string",
- "description": "Priority level of the task: high, medium, low"
- }
- },
- "required": ["content", "status", "priority"],
- "additionalProperties": false
- },
"Session3": {
"type": "object",
"properties": {
@@ -29353,6 +31051,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -29522,6 +31224,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -29691,6 +31397,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -29860,6 +31570,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -30029,6 +31743,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -30360,6 +32078,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -30529,6 +32251,10 @@
},
"diff": {
"type": "string"
+ },
+ "workspace": {
+ "type": "string",
+ "enum": ["restored", "snapshots-disabled", "unavailable"]
}
},
"required": ["messageID"],
@@ -31425,6 +33151,16 @@
"required": ["_tag"],
"additionalProperties": false
},
+ "CloudSessionImportError": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "type": "string"
+ }
+ },
+ "required": ["error"],
+ "additionalProperties": false
+ },
"AgentRequirementResult": {
"type": "object",
"properties": {
@@ -32361,7 +34097,7 @@
"required": ["_tag", "message"],
"additionalProperties": false
},
- "V2SessionsResponse": {
+ "SessionsResponse": {
"type": "object",
"properties": {
"data": {
@@ -32451,7 +34187,7 @@
"required": ["_tag", "message"],
"additionalProperties": false
},
- "V2SessionMessagesResponse": {
+ "SessionMessagesResponse": {
"type": "object",
"properties": {
"data": {
@@ -32493,6 +34229,30 @@
"required": ["_tag", "providerID", "message"],
"additionalProperties": false
},
+ "ProjectCopyError": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "enum": ["ProjectCopyError"]
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ },
+ "forceRequired": {
+ "type": "boolean"
+ }
+ },
+ "required": ["message"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["name", "data"],
+ "additionalProperties": false
+ },
"effect_HttpApiError_Forbidden": {
"type": "object",
"properties": {
@@ -34539,6 +36299,182 @@
"body": {
"type": "object"
},
+ "generation": {
+ "type": "object",
+ "properties": {
+ "maxTokens": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "temperature": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "topP": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "topK": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "frequencyPenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "presencePenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "seed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "stop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "options": {
+ "type": "object"
+ },
"variant": {
"type": "string"
}
@@ -34562,6 +36498,182 @@
},
"body": {
"type": "object"
+ },
+ "generation": {
+ "type": "object",
+ "properties": {
+ "maxTokens": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "temperature": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "topP": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "topK": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "frequencyPenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "presencePenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "seed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "stop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "options": {
+ "type": "object"
}
},
"required": ["id", "headers", "body"],
@@ -35092,41 +37204,6 @@
"required": ["name"],
"additionalProperties": false
},
- "PromptReferenceAttachment": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
- },
- "kind": {
- "type": "string",
- "enum": ["local", "git", "invalid"]
- },
- "uri": {
- "type": "string"
- },
- "repository": {
- "type": "string"
- },
- "branch": {
- "type": "string"
- },
- "target": {
- "type": "string"
- },
- "targetUri": {
- "type": "string"
- },
- "problem": {
- "type": "string"
- },
- "source": {
- "$ref": "#/components/schemas/PromptSource"
- }
- },
- "required": ["name", "kind"],
- "additionalProperties": false
- },
"EventSessionNextPrompted": {
"type": "object",
"properties": {
@@ -35243,6 +37320,34 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
+ "EventSessionNextInterruptRequested": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["session.next.interrupt.requested"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "timestamp": {
+ "type": "number"
+ },
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ }
+ },
+ "required": ["timestamp", "sessionID"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
"EventSessionNextContextUpdated": {
"type": "object",
"properties": {
@@ -35984,51 +38089,8 @@
"type": "string",
"enum": ["file"]
},
- "source": {
- "anyOf": [
- {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["data"]
- },
- "data": {
- "type": "string"
- }
- },
- "required": ["type", "data"],
- "additionalProperties": false
- },
- {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["url"]
- },
- "url": {
- "type": "string"
- }
- },
- "required": ["type", "url"],
- "additionalProperties": false
- },
- {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["file"]
- },
- "uri": {
- "type": "string"
- }
- },
- "required": ["type", "uri"],
- "additionalProperties": false
- }
- ]
+ "uri": {
+ "type": "string"
},
"mime": {
"type": "string"
@@ -36037,7 +38099,7 @@
"type": "string"
}
},
- "required": ["type", "source", "mime"],
+ "required": ["type", "uri", "mime"],
"additionalProperties": false
},
"EventSessionNextToolProgress": {
@@ -36134,6 +38196,12 @@
]
}
},
+ "outputPaths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
"result": {},
"provider": {
"type": "object",
@@ -36335,11 +38403,15 @@
"type": "string",
"pattern": "^ses"
},
+ "messageID": {
+ "type": "string",
+ "pattern": "^msg_"
+ },
"text": {
"type": "string"
}
},
- "required": ["timestamp", "sessionID", "text"],
+ "required": ["timestamp", "sessionID", "messageID", "text"],
"additionalProperties": false
}
},
@@ -36366,9 +38438,20 @@
"type": "string",
"pattern": "^ses"
},
+ "messageID": {
+ "type": "string",
+ "pattern": "^msg_"
+ },
+ "reason": {
+ "type": "string",
+ "enum": ["auto", "manual"]
+ },
"text": {
"type": "string"
},
+ "recent": {
+ "type": "string"
+ },
"include": {
"type": "string"
}
@@ -36644,6 +38727,9 @@
{
"$ref": "#/components/schemas/ContextOverflowError"
},
+ {
+ "$ref": "#/components/schemas/ContentFilterError"
+ },
{
"$ref": "#/components/schemas/APIError"
},
@@ -36818,26 +38904,7 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
- "SessionTodoInfo": {
- "type": "object",
- "properties": {
- "content": {
- "type": "string",
- "description": "Brief description of the task"
- },
- "status": {
- "type": "string",
- "description": "Current status of the task: pending, in_progress, completed, cancelled"
- },
- "priority": {
- "type": "string",
- "description": "Priority level of the task: high, medium, low"
- }
- },
- "required": ["content", "status", "priority"],
- "additionalProperties": false
- },
- "EventTodoUpdated": {
+ "EventReferenceUpdated": {
"type": "object",
"properties": {
"id": {
@@ -36845,259 +38912,7 @@
},
"type": {
"type": "string",
- "enum": ["todo.updated"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- },
- "todos": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/SessionTodoInfo"
- }
- }
- },
- "required": ["sessionID", "todos"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventSessionStatus": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["session.status"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- },
- "status": {
- "$ref": "#/components/schemas/SessionStatus"
- }
- },
- "required": ["sessionID", "status"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventSessionIdle": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["session.idle"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- }
- },
- "required": ["sessionID"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventSessionCompacted": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["session.compacted"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- }
- },
- "required": ["sessionID"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventCommandExecuted": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["command.executed"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
- },
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- },
- "arguments": {
- "type": "string"
- },
- "messageID": {
- "type": "string",
- "pattern": "^msg"
- }
- },
- "required": ["name", "sessionID", "arguments", "messageID"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventProjectDirectoriesUpdated": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["project.directories.updated"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "projectID": {
- "type": "string"
- }
- },
- "required": ["projectID"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventProjectUpdated": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["project.updated"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "worktree": {
- "type": "string"
- },
- "vcs": {
- "type": "string",
- "enum": ["git"]
- },
- "name": {
- "type": "string"
- },
- "icon": {
- "type": "object",
- "properties": {
- "url": {
- "type": "string"
- },
- "override": {
- "type": "string"
- },
- "color": {
- "type": "string"
- }
- },
- "additionalProperties": false
- },
- "commands": {
- "type": "object",
- "properties": {
- "start": {
- "type": "string",
- "description": "Startup script to run when creating a new workspace (worktree)"
- }
- },
- "additionalProperties": false
- },
- "time": {
- "type": "object",
- "properties": {
- "created": {
- "type": "integer",
- "minimum": 0
- },
- "updated": {
- "type": "integer",
- "minimum": 0
- },
- "initialized": {
- "type": "integer",
- "minimum": 0
- }
- },
- "required": ["created", "updated"],
- "additionalProperties": false
- },
- "sandboxes": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- },
- "required": ["id", "worktree", "time", "sandboxes"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventLspUpdated": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["lsp.updated"]
+ "enum": ["reference.updated"]
},
"properties": {
"type": "object",
@@ -37107,7 +38922,7 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
- "EventFileEdited": {
+ "EventIntegrationUpdated": {
"type": "object",
"properties": {
"id": {
@@ -37115,347 +38930,11 @@
},
"type": {
"type": "string",
- "enum": ["file.edited"]
+ "enum": ["integration.updated"]
},
"properties": {
"type": "object",
- "properties": {
- "file": {
- "type": "string"
- }
- },
- "required": ["file"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventFileWatcherUpdated": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["file.watcher.updated"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "file": {
- "type": "string"
- },
- "event": {
- "type": "string",
- "enum": ["add", "change", "unlink"]
- }
- },
- "required": ["file", "event"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventVcsBranchUpdated": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["vcs.branch.updated"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "branch": {
- "type": "string"
- }
- },
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventWorkspaceReady": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["workspace.ready"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
- }
- },
- "required": ["name"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventWorkspaceFailed": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["workspace.failed"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- },
- "required": ["message"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventWorkspaceStatus": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["workspace.status"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "workspaceID": {
- "type": "string",
- "pattern": "^wrk"
- },
- "status": {
- "type": "string",
- "enum": ["connected", "connecting", "disconnected", "error"]
- }
- },
- "required": ["workspaceID", "status"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventWorktreeReady": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["worktree.ready"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
- },
- "branch": {
- "type": "string"
- }
- },
- "required": ["name"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventWorktreeFailed": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["worktree.failed"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- },
- "required": ["message"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "AuthOAuthCredential": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["oauth"]
- },
- "refresh": {
- "type": "string"
- },
- "access": {
- "type": "string"
- },
- "expires": {
- "type": "integer",
- "minimum": 0
- },
- "accountId": {
- "type": "string"
- }
- },
- "required": ["type", "refresh", "access", "expires"],
- "additionalProperties": false
- },
- "AuthApiKeyCredential": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["api"]
- },
- "key": {
- "type": "string"
- },
- "metadata": {
- "type": "object",
- "additionalProperties": {
- "type": "string"
- }
- }
- },
- "required": ["type", "key"],
- "additionalProperties": false
- },
- "AuthCredential": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/AuthOAuthCredential"
- },
- {
- "$ref": "#/components/schemas/AuthApiKeyCredential"
- }
- ]
- },
- "AuthInfo": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "serviceID": {
- "type": "string"
- },
- "description": {
- "type": "string"
- },
- "credential": {
- "$ref": "#/components/schemas/AuthCredential"
- }
- },
- "required": ["id", "serviceID", "description", "credential"],
- "additionalProperties": false
- },
- "EventAccountAdded": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["account.added"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "account": {
- "$ref": "#/components/schemas/AuthInfo"
- }
- },
- "required": ["account"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventAccountRemoved": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["account.removed"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "account": {
- "$ref": "#/components/schemas/AuthInfo"
- }
- },
- "required": ["account"],
- "additionalProperties": false
- }
- },
- "required": ["id", "type", "properties"],
- "additionalProperties": false
- },
- "EventAccountSwitched": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "type": {
- "type": "string",
- "enum": ["account.switched"]
- },
- "properties": {
- "type": "object",
- "properties": {
- "serviceID": {
- "type": "string"
- },
- "from": {
- "type": "string"
- },
- "to": {
- "type": "string"
- }
- },
- "required": ["serviceID"],
- "additionalProperties": false
+ "properties": {}
}
},
"required": ["id", "type", "properties"],
@@ -37564,6 +39043,82 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
+ "EventProjectDirectoriesUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["project.directories.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "projectID": {
+ "type": "string"
+ }
+ },
+ "required": ["projectID"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventFileEdited": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["file.edited"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "file": {
+ "type": "string"
+ }
+ },
+ "required": ["file"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventFileWatcherUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["file.watcher.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "file": {
+ "type": "string"
+ },
+ "event": {
+ "type": "string",
+ "enum": ["add", "change", "unlink"]
+ }
+ },
+ "required": ["file", "event"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
"EventPtyCreated": {
"type": "object",
"properties": {
@@ -37831,6 +39386,403 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
+ "EventTodoUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["todo.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ "todos": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Todo"
+ }
+ }
+ },
+ "required": ["sessionID", "todos"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventSessionStatus": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["session.status"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ "status": {
+ "$ref": "#/components/schemas/SessionStatus"
+ }
+ },
+ "required": ["sessionID", "status"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventSessionIdle": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["session.idle"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ }
+ },
+ "required": ["sessionID"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventSessionCompacted": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["session.compacted"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ }
+ },
+ "required": ["sessionID"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventCommandExecuted": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["command.executed"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "sessionID": {
+ "type": "string",
+ "pattern": "^ses"
+ },
+ "arguments": {
+ "type": "string"
+ },
+ "messageID": {
+ "type": "string",
+ "pattern": "^msg"
+ }
+ },
+ "required": ["name", "sessionID", "arguments", "messageID"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventProjectUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["project.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "worktree": {
+ "type": "string"
+ },
+ "vcs": {
+ "type": "string",
+ "enum": ["git"]
+ },
+ "name": {
+ "type": "string"
+ },
+ "icon": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string"
+ },
+ "override": {
+ "type": "string"
+ },
+ "color": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "commands": {
+ "type": "object",
+ "properties": {
+ "start": {
+ "type": "string",
+ "description": "Startup script to run when creating a new workspace (worktree)"
+ }
+ },
+ "additionalProperties": false
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "updated": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "initialized": {
+ "type": "integer",
+ "minimum": 0
+ }
+ },
+ "required": ["created", "updated"],
+ "additionalProperties": false
+ },
+ "sandboxes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": ["id", "worktree", "time", "sandboxes"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventLspUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["lsp.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventVcsBranchUpdated": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["vcs.branch.updated"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "branch": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventWorkspaceReady": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["workspace.ready"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": ["name"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventWorkspaceFailed": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["workspace.failed"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": ["message"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventWorkspaceStatus": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["workspace.status"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "workspaceID": {
+ "type": "string",
+ "pattern": "^wrk"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["connected", "connecting", "disconnected", "error"]
+ }
+ },
+ "required": ["workspaceID", "status"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventWorktreeReady": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["worktree.ready"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "branch": {
+ "type": "string"
+ }
+ },
+ "required": ["name"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
+ "EventWorktreeFailed": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["worktree.failed"]
+ },
+ "properties": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": ["message"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "type", "properties"],
+ "additionalProperties": false
+ },
"SyncEventSessionCreated": {
"type": "object",
"properties": {
@@ -39589,6 +41541,12 @@
]
}
},
+ "outputPaths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
"result": {},
"provider": {
"type": "object",
@@ -39817,59 +41775,6 @@
"required": ["type", "id", "syncEvent"],
"additionalProperties": false
},
- "SyncEventSessionNextCompactionDelta": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["sync"]
- },
- "id": {
- "type": "string",
- "pattern": "^evt_"
- },
- "syncEvent": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["session.next.compaction.delta.1"]
- },
- "id": {
- "type": "string",
- "pattern": "^evt_"
- },
- "seq": {
- "type": "number"
- },
- "aggregateID": {
- "type": "string"
- },
- "data": {
- "type": "object",
- "properties": {
- "timestamp": {
- "type": "number"
- },
- "sessionID": {
- "type": "string",
- "pattern": "^ses"
- },
- "text": {
- "type": "string"
- }
- },
- "required": ["timestamp", "sessionID", "text"],
- "additionalProperties": false
- }
- },
- "required": ["type", "id", "seq", "aggregateID", "data"],
- "additionalProperties": false
- }
- },
- "required": ["type", "id", "syncEvent"],
- "additionalProperties": false
- },
"SyncEventSessionNextCompactionEnded": {
"type": "object",
"properties": {
@@ -39908,9 +41813,20 @@
"type": "string",
"pattern": "^ses"
},
+ "messageID": {
+ "type": "string",
+ "pattern": "^msg_"
+ },
+ "reason": {
+ "type": "string",
+ "enum": ["auto", "manual"]
+ },
"text": {
"type": "string"
},
+ "recent": {
+ "type": "string"
+ },
"include": {
"type": "string"
}
@@ -39926,6 +41842,41 @@
"required": ["type", "id", "syncEvent"],
"additionalProperties": false
},
+ "ConfigV2ReferenceGit": {
+ "type": "object",
+ "properties": {
+ "repository": {
+ "type": "string"
+ },
+ "branch": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "hidden": {
+ "type": "boolean"
+ }
+ },
+ "required": ["repository"],
+ "additionalProperties": false
+ },
+ "ConfigV2ReferenceLocal": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "hidden": {
+ "type": "boolean"
+ }
+ },
+ "required": ["path"],
+ "additionalProperties": false
+ },
"PolicyEffect": {
"type": "string",
"enum": ["allow", "deny"]
@@ -39950,19 +41901,19 @@
"ProjectDirectories": {
"type": "array",
"items": {
- "type": "string"
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ },
+ "strategy": {
+ "type": "string"
+ }
+ },
+ "required": ["directory"],
+ "additionalProperties": false
}
},
- "ProjectCopyCopy": {
- "type": "object",
- "properties": {
- "directory": {
- "type": "string"
- }
- },
- "required": ["directory"],
- "additionalProperties": false
- },
"LocationInfo": {
"type": "object",
"properties": {
@@ -40327,12 +42278,6 @@
"$ref": "#/components/schemas/PromptAgentAttachment"
}
},
- "references": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/PromptReferenceAttachment"
- }
- },
"type": {
"type": "string",
"enum": ["user"]
@@ -40560,6 +42505,12 @@
]
}
},
+ "outputPaths": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
"structured": {
"type": "object"
},
@@ -40806,7 +42757,7 @@
"summary": {
"type": "string"
},
- "include": {
+ "recent": {
"type": "string"
},
"id": {
@@ -40827,7 +42778,7 @@
"additionalProperties": false
}
},
- "required": ["type", "reason", "summary", "id", "time"],
+ "required": ["type", "reason", "summary", "recent", "id", "time"],
"additionalProperties": false
},
"SessionMessage": {
@@ -40892,13 +42843,13 @@
"properties": {
"via": {
"type": "string",
- "enum": ["account"]
+ "enum": ["credential"]
},
- "service": {
+ "credentialID": {
"type": "string"
}
},
- "required": ["via", "service"],
+ "required": ["via", "credentialID"],
"additionalProperties": false
},
{
@@ -40984,6 +42935,295 @@
"required": ["id", "name", "enabled", "env", "api", "request"],
"additionalProperties": false
},
+ "IntegrationWhen": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "op": {
+ "type": "string",
+ "enum": ["eq", "neq"]
+ },
+ "value": {
+ "type": "string"
+ }
+ },
+ "required": ["key", "op", "value"],
+ "additionalProperties": false
+ },
+ "IntegrationTextPrompt": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["text"]
+ },
+ "key": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "placeholder": {
+ "type": "string"
+ },
+ "when": {
+ "$ref": "#/components/schemas/IntegrationWhen"
+ }
+ },
+ "required": ["type", "key", "message"],
+ "additionalProperties": false
+ },
+ "IntegrationSelectPrompt": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["select"]
+ },
+ "key": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ },
+ "hint": {
+ "type": "string"
+ }
+ },
+ "required": ["label", "value"],
+ "additionalProperties": false
+ }
+ },
+ "when": {
+ "$ref": "#/components/schemas/IntegrationWhen"
+ }
+ },
+ "required": ["type", "key", "message", "options"],
+ "additionalProperties": false
+ },
+ "IntegrationOAuthMethod": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["oauth"]
+ },
+ "label": {
+ "type": "string"
+ },
+ "prompts": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/IntegrationTextPrompt"
+ },
+ {
+ "$ref": "#/components/schemas/IntegrationSelectPrompt"
+ }
+ ]
+ }
+ }
+ },
+ "required": ["id", "type", "label"],
+ "additionalProperties": false
+ },
+ "IntegrationKeyMethod": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["key"]
+ },
+ "label": {
+ "type": "string"
+ }
+ },
+ "required": ["type"],
+ "additionalProperties": false
+ },
+ "IntegrationEnvMethod": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["env"]
+ },
+ "names": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": ["type", "names"],
+ "additionalProperties": false
+ },
+ "ConnectionCredentialInfo": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["credential"]
+ },
+ "id": {
+ "type": "string"
+ },
+ "label": {
+ "type": "string"
+ }
+ },
+ "required": ["type", "id", "label"],
+ "additionalProperties": false
+ },
+ "ConnectionEnvInfo": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["env"]
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": ["type", "name"],
+ "additionalProperties": false
+ },
+ "ConnectionInfo": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/ConnectionCredentialInfo"
+ },
+ {
+ "$ref": "#/components/schemas/ConnectionEnvInfo"
+ }
+ ]
+ },
+ "IntegrationInfo": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "methods": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/IntegrationOAuthMethod"
+ },
+ {
+ "$ref": "#/components/schemas/IntegrationKeyMethod"
+ },
+ {
+ "$ref": "#/components/schemas/IntegrationEnvMethod"
+ }
+ ]
+ }
+ },
+ "connections": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ConnectionInfo"
+ }
+ }
+ },
+ "required": ["id", "name", "methods", "connections"],
+ "additionalProperties": false
+ },
+ "IntegrationAttempt": {
+ "type": "object",
+ "properties": {
+ "attemptID": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "instructions": {
+ "type": "string"
+ },
+ "mode": {
+ "type": "string",
+ "enum": ["auto", "code"]
+ },
+ "time": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "expires": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ }
+ },
+ "required": ["created", "expires"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["attemptID", "url", "instructions", "mode", "time"],
+ "additionalProperties": false
+ },
"PermissionV2Request": {
"type": "object",
"properties": {
@@ -41039,53 +43279,12 @@
"required": ["id", "projectID", "action", "resource"],
"additionalProperties": false
},
- "FileSystemTextContent": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["text"]
- },
- "content": {
- "type": "string"
- },
- "mime": {
- "type": "string"
- }
- },
- "required": ["type", "content", "mime"],
- "additionalProperties": false
- },
- "FileSystemBinaryContent": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": ["binary"]
- },
- "content": {
- "type": "string"
- },
- "encoding": {
- "type": "string",
- "enum": ["base64"]
- },
- "mime": {
- "type": "string"
- }
- },
- "required": ["type", "content", "encoding", "mime"],
- "additionalProperties": false
- },
"FileSystemEntry": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
- "uri": {
- "type": "string"
- },
"type": {
"type": "string",
"enum": ["file", "directory"]
@@ -41094,7 +43293,7 @@
"type": "string"
}
},
- "required": ["path", "uri", "type", "mime"],
+ "required": ["path", "type", "mime"],
"additionalProperties": false
},
"CommandV2Info": {
@@ -41196,6 +43395,88 @@
"required": ["answers"],
"additionalProperties": false
},
+ "ReferenceLocalSource": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["local"]
+ },
+ "path": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "hidden": {
+ "type": "boolean"
+ }
+ },
+ "required": ["type", "path"],
+ "additionalProperties": false
+ },
+ "ReferenceGitSource": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["git"]
+ },
+ "repository": {
+ "type": "string"
+ },
+ "branch": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "hidden": {
+ "type": "boolean"
+ }
+ },
+ "required": ["type", "repository"],
+ "additionalProperties": false
+ },
+ "ReferenceInfo": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "hidden": {
+ "type": "boolean"
+ },
+ "source": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/ReferenceLocalSource"
+ },
+ {
+ "$ref": "#/components/schemas/ReferenceGitSource"
+ }
+ ]
+ }
+ },
+ "required": ["name", "path", "source"],
+ "additionalProperties": false
+ },
+ "ProjectCopyCopy": {
+ "type": "object",
+ "properties": {
+ "directory": {
+ "type": "string"
+ }
+ },
+ "required": ["directory"],
+ "additionalProperties": false
+ },
"EventMemoryStatus1": {
"type": "object",
"properties": {
@@ -42189,6 +44470,154 @@
"body": {
"type": "object"
},
+ "generation": {
+ "type": "object",
+ "properties": {
+ "maxTokens": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "temperature": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "topP": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "topK": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "frequencyPenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "presencePenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "seed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "stop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "options": {
+ "type": "object"
+ },
"variant": {
"type": "string"
}
@@ -42212,6 +44641,154 @@
},
"body": {
"type": "object"
+ },
+ "generation": {
+ "type": "object",
+ "properties": {
+ "maxTokens": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "temperature": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "topP": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "topK": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "frequencyPenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "presencePenalty": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "seed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ }
+ ]
+ },
+ "stop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "options": {
+ "type": "object"
}
},
"required": ["id", "headers", "body"],
@@ -42431,7 +45008,7 @@
},
{
"name": "projectCopy",
- "description": "Project copy management routes."
+ "description": "Project copy naming routes."
},
{
"name": "pty",
@@ -42542,64 +45119,72 @@
"description": "Kilo memory routes."
},
{
- "name": "kilo experimental HttpApi",
+ "name": "Kilo HttpApi",
"description": "Experimental HttpApi surface for selected instance routes."
},
{
- "name": "kilo experimental HttpApi",
+ "name": "Kilo HttpApi",
"description": "Experimental HttpApi surface for selected instance routes."
},
{
- "name": "v2",
- "description": "Experimental v2 routes."
+ "name": "Kilo HttpApi",
+ "description": "Experimental HttpApi surface for selected instance routes."
},
{
- "name": "v2 messages",
- "description": "Experimental v2 message routes."
+ "name": "sessions",
+ "description": "Experimental session routes."
},
{
- "name": "v2 models",
- "description": "Experimental v2 model routes."
+ "name": "messages",
+ "description": "Experimental message routes."
},
{
- "name": "v2 providers",
- "description": "Experimental v2 provider routes."
+ "name": "models",
+ "description": "Experimental model routes."
},
{
- "name": "v2 permissions",
- "description": "Experimental v2 permission routes."
+ "name": "providers",
+ "description": "Experimental provider routes."
},
{
- "name": "v2 session permissions",
- "description": "Experimental v2 session permission routes."
+ "name": "integrations",
+ "description": "Integration discovery and authentication routes."
},
{
- "name": "v2 saved permissions",
- "description": "Experimental v2 saved permission routes."
+ "name": "Kilo HttpApi",
+ "description": "Experimental HttpApi surface for selected instance routes."
},
{
- "name": "v2 filesystem",
- "description": "Experimental v2 location-scoped filesystem routes."
+ "name": "permissions",
+ "description": "Experimental permission routes."
},
{
- "name": "v2 commands",
- "description": "Experimental v2 command routes."
+ "name": "filesystem",
+ "description": "Experimental location-scoped filesystem routes."
},
{
- "name": "v2 skills",
- "description": "Experimental v2 skill routes."
+ "name": "commands",
+ "description": "Experimental command routes."
},
{
- "name": "v2 events",
- "description": "Experimental v2 event stream route."
+ "name": "skills",
+ "description": "Experimental skill routes."
},
{
- "name": "v2 questions",
- "description": "Experimental v2 question routes."
+ "name": "events",
+ "description": "Experimental event stream route."
},
{
- "name": "v2 session questions",
- "description": "Experimental v2 session question routes."
+ "name": "session questions",
+ "description": "Experimental session question routes."
+ },
+ {
+ "name": "reference",
+ "description": "Location-scoped project references."
+ },
+ {
+ "name": "projectCopy",
+ "description": "Project copy management routes."
},
{
"name": "pty",
From b71a9c0c234cb2fbb55712e4e995e261dde9fab5 Mon Sep 17 00:00:00 2001
From: Josh Lambert
Date: Mon, 27 Jul 2026 22:10:56 -0400
Subject: [PATCH 007/100] fix(vscode): include web search in config exports
---
.../webview-ui/src/components/settings/settings-io.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/settings-io.ts b/packages/kilo-vscode/webview-ui/src/components/settings/settings-io.ts
index d4b1949d2a..be43b46284 100644
--- a/packages/kilo-vscode/webview-ui/src/components/settings/settings-io.ts
+++ b/packages/kilo-vscode/webview-ui/src/components/settings/settings-io.ts
@@ -34,6 +34,7 @@ export const KNOWN_KEYS: ReadonlyArray = [
"compaction",
"commit_message",
"tools",
+ "web_search",
"auto_collapse_reasoning",
"terminal_command_display",
"code_edit_display",
From b0a546049e7fcb212c8d1db344a48531ce65bed9 Mon Sep 17 00:00:00 2001
From: marius-kilocode
Date: Tue, 28 Jul 2026 13:42:15 +0200
Subject: [PATCH 008/100] refactor(cli): remove provably unused kilocode code
Delete code with zero references anywhere in the monorepo (including
tests, docs, scripts, and dynamic import or string-based usage):
- background-process/windows-job.ts: entire Windows Job Object FFI
module left unreferenced after the background process runner refactor
- session/prompt.ts: createShellDecoders helper, CODE_SWITCH_TEXT alias,
and the now-unused StringDecoder import
- text-stream.ts: openUtf8 wrapper
- cli/cmd/tui/component/prompt/vim.ts: enterInsert helper
- config/config.ts: KILO_CONFIG_FILES, AGENT_PATTERNS, COMMAND_PATTERNS
- remote-attachments.ts: TEXT_PLAIN constant
- plan-followup.ts: PLAN_PREFIX constant
- server/httpapi/groups/background-process.ts: SessionParams schema
- server/httpapi/groups/session-import.ts: SessionImportPayloads map
- cloud/contracts.ts: RepositoryInput type alias
---
.../background-process/windows-job.ts | 88 -------------------
.../cli/cmd/tui/component/prompt/vim.ts | 5 --
.../opencode/src/kilocode/cloud/contracts.ts | 1 -
.../opencode/src/kilocode/config/config.ts | 14 ---
.../opencode/src/kilocode/plan-followup.ts | 1 -
.../src/kilocode/remote-attachments.ts | 1 -
.../httpapi/groups/background-process.ts | 1 -
.../server/httpapi/groups/session-import.ts | 7 --
.../opencode/src/kilocode/session/prompt.ts | 26 ------
packages/opencode/src/kilocode/text-stream.ts | 5 --
10 files changed, 149 deletions(-)
delete mode 100644 packages/opencode/src/kilocode/background-process/windows-job.ts
diff --git a/packages/opencode/src/kilocode/background-process/windows-job.ts b/packages/opencode/src/kilocode/background-process/windows-job.ts
deleted file mode 100644
index 85d05b38e6..0000000000
--- a/packages/opencode/src/kilocode/background-process/windows-job.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { dlopen, ptr } from "bun:ffi"
-
-export namespace WindowsJob {
- const LIMITS = 9
- const MEMBERS = 3
- const KILL_ON_CLOSE = 0x00002000
- const PROCESS_TERMINATE = 0x0001
- const PROCESS_SET_QUOTA = 0x0100
- const MORE_DATA = 234
-
- function kernel() {
- return dlopen("kernel32.dll", {
- CreateJobObjectW: { args: ["ptr", "ptr"], returns: "u64" },
- SetInformationJobObject: { args: ["u64", "u32", "ptr", "u32"], returns: "i32" },
- OpenProcess: { args: ["u32", "i32", "u32"], returns: "u64" },
- AssignProcessToJobObject: { args: ["u64", "u64"], returns: "i32" },
- QueryInformationJobObject: { args: ["u64", "u32", "ptr", "u32", "ptr"], returns: "i32" },
- TerminateJobObject: { args: ["u64", "u32"], returns: "i32" },
- CloseHandle: { args: ["u64"], returns: "i32" },
- GetLastError: { args: [], returns: "u32" },
- })
- }
-
- export function create() {
- const lib = (() => {
- try {
- return kernel()
- } catch {
- return undefined
- }
- })()
- if (!lib) return
- const handle = lib.symbols.CreateJobObjectW(null, null)
- if (handle === 0n) {
- const code = lib.symbols.GetLastError()
- lib.close()
- throw new Error(`CreateJobObjectW failed with Windows error ${code}`)
- }
- const limits = new Uint8Array(144)
- new DataView(limits.buffer).setUint32(16, KILL_ON_CLOSE, true)
- if (lib.symbols.SetInformationJobObject(handle, LIMITS, ptr(limits), limits.byteLength) === 0) {
- const code = lib.symbols.GetLastError()
- lib.symbols.CloseHandle(handle)
- lib.close()
- throw new Error(`SetInformationJobObject failed with Windows error ${code}`)
- }
- let closed = false
- return {
- assign(pid: number) {
- const proc = lib.symbols.OpenProcess(PROCESS_TERMINATE | PROCESS_SET_QUOTA, 0, pid)
- if (proc === 0n) throw new Error(`OpenProcess failed with Windows error ${lib.symbols.GetLastError()}`)
- const assigned = lib.symbols.AssignProcessToJobObject(handle, proc)
- const code = assigned === 0 ? lib.symbols.GetLastError() : 0
- lib.symbols.CloseHandle(proc)
- if (assigned === 0) throw new Error(`AssignProcessToJobObject failed with Windows error ${code}`)
- },
- members() {
- let size = 4 * 1024
- while (true) {
- const info = new Uint8Array(size)
- const ok = lib.symbols.QueryInformationJobObject(handle, MEMBERS, ptr(info), info.byteLength, null)
- const code = ok === 0 ? lib.symbols.GetLastError() : 0
- const view = new DataView(info.buffer)
- const assigned = view.getUint32(0, true)
- const count = view.getUint32(4, true)
- if (ok !== 0 && count === assigned) {
- return Array.from({ length: count }, (_, index) => Number(view.getBigUint64(8 + index * 8, true)))
- }
- if (ok === 0 && code !== MORE_DATA) {
- throw new Error(`QueryInformationJobObject failed with Windows error ${code}`)
- }
- size = Math.max(size * 2, 8 + assigned * 8)
- }
- },
- terminate() {
- if (lib.symbols.TerminateJobObject(handle, 1) === 0) {
- throw new Error(`TerminateJobObject failed with Windows error ${lib.symbols.GetLastError()}`)
- }
- },
- close() {
- if (closed) return
- closed = true
- lib.symbols.CloseHandle(handle)
- lib.close()
- },
- }
- }
-}
diff --git a/packages/opencode/src/kilocode/cli/cmd/tui/component/prompt/vim.ts b/packages/opencode/src/kilocode/cli/cmd/tui/component/prompt/vim.ts
index 2b91606c86..020d0be379 100644
--- a/packages/opencode/src/kilocode/cli/cmd/tui/component/prompt/vim.ts
+++ b/packages/opencode/src/kilocode/cli/cmd/tui/component/prompt/vim.ts
@@ -877,8 +877,3 @@ export function handleVisualKey(doc: VimDoc, state: VimState, input: VimKey): Vi
state.countDigits = ""
return { handled: true }
}
-
-export function enterInsert(state: VimState) {
- state.mode = "insert"
- resetPending(state)
-}
diff --git a/packages/opencode/src/kilocode/cloud/contracts.ts b/packages/opencode/src/kilocode/cloud/contracts.ts
index a4716e547e..a78b846b8c 100644
--- a/packages/opencode/src/kilocode/cloud/contracts.ts
+++ b/packages/opencode/src/kilocode/cloud/contracts.ts
@@ -163,7 +163,6 @@ export const GetMessageResultOutputSchema = z
}
})
-export type RepositoryInput = z.infer
export type AgentStartRequest = z.infer
export type AgentSendRequest = z.infer
export type GetMessageResultInput = z.infer
diff --git a/packages/opencode/src/kilocode/config/config.ts b/packages/opencode/src/kilocode/config/config.ts
index a33445494b..608386d4fa 100644
--- a/packages/opencode/src/kilocode/config/config.ts
+++ b/packages/opencode/src/kilocode/config/config.ts
@@ -37,26 +37,12 @@ export namespace KilocodeConfig {
// ── Config file constants ────────────────────────────────────────────
- /** Kilo-specific config file names (highest-to-lowest precedence within kilo). */
- export const KILO_CONFIG_FILES = ["kilo.jsonc", "kilo.json"] as const
-
/** All config file names in precedence order (kilo + opencode). */
export const ALL_CONFIG_FILES = ["kilo.jsonc", "kilo.json", "opencode.jsonc", "opencode.json"] as const
/** Config directory suffixes in update-target preference order. */
export const KILO_DIR_SUFFIXES = [".kilo", ".kilocode"] as const
- /** Path patterns for resolving kilo agent names from file paths. */
- export const AGENT_PATTERNS = ["/.kilo/agent/", "/.kilo/agents/", "/.kilocode/agent/", "/.kilocode/agents/"] as const
-
- /** Path patterns for resolving kilo command names from file paths. */
- export const COMMAND_PATTERNS = [
- "/.kilo/command/",
- "/.kilo/commands/",
- "/.kilocode/command/",
- "/.kilocode/commands/",
- ] as const
-
/**
* Choose the project config file that Config.update should patch.
*
diff --git a/packages/opencode/src/kilocode/plan-followup.ts b/packages/opencode/src/kilocode/plan-followup.ts
index 01de704a54..a0c726f94c 100644
--- a/packages/opencode/src/kilocode/plan-followup.ts
+++ b/packages/opencode/src/kilocode/plan-followup.ts
@@ -157,7 +157,6 @@ export async function generateHandover(input: {
export namespace PlanFollowup {
const log = Log.create({ service: "plan.followup" })
- export const PLAN_PREFIX = "Implement the following plan:"
export const ANSWER_NEW_SESSION = "Start new session"
export const ANSWER_CONTINUE = "Continue here"
export const ANSWER_KEEP_REFINING = "Keep refining"
diff --git a/packages/opencode/src/kilocode/remote-attachments.ts b/packages/opencode/src/kilocode/remote-attachments.ts
index 9008065cc9..b329dbb47d 100644
--- a/packages/opencode/src/kilocode/remote-attachments.ts
+++ b/packages/opencode/src/kilocode/remote-attachments.ts
@@ -66,7 +66,6 @@ export namespace RemoteAttachments {
sql: "text/plain",
}
export const BINARY_MIME = "application/octet-stream"
- export const TEXT_PLAIN = "text/plain"
// Hard cap on attachment bytes (5 MB + 1 byte so the helper aborts
// strictly when the body exceeds the agreed ceiling).
export const MAX_BYTES = 5 * 1024 * 1024 + 1
diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/background-process.ts b/packages/opencode/src/kilocode/server/httpapi/groups/background-process.ts
index e5b0dbc2dc..208cd1f021 100644
--- a/packages/opencode/src/kilocode/server/httpapi/groups/background-process.ts
+++ b/packages/opencode/src/kilocode/server/httpapi/groups/background-process.ts
@@ -22,7 +22,6 @@ export const BackgroundProcessPaths = {
} as const
export const Params = Schema.Struct({ processID: BackgroundProcess.ID })
-export const SessionParams = Schema.Struct({ sessionID: SessionID })
export const BackgroundProcessApi = HttpApi.make("background-process")
.add(
diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/session-import.ts b/packages/opencode/src/kilocode/server/httpapi/groups/session-import.ts
index 596ca4f57d..9aca9d4581 100644
--- a/packages/opencode/src/kilocode/server/httpapi/groups/session-import.ts
+++ b/packages/opencode/src/kilocode/server/httpapi/groups/session-import.ts
@@ -219,13 +219,6 @@ export const SessionImportPaths = {
part: `${root}/part`,
} as const
-export const SessionImportPayloads = {
- Project: ProjectSchema,
- Session: SessionSchema,
- Message: MessageSchema,
- Part: PartSchema,
-} as const
-
export const SessionImportApi = HttpApi.make("session-import")
.add(
HttpApiGroup.make("session-import")
diff --git a/packages/opencode/src/kilocode/session/prompt.ts b/packages/opencode/src/kilocode/session/prompt.ts
index a1fa29b806..ee05f45358 100644
--- a/packages/opencode/src/kilocode/session/prompt.ts
+++ b/packages/opencode/src/kilocode/session/prompt.ts
@@ -1,7 +1,6 @@
// kilocode_change - new file
import path from "path"
import fs from "fs/promises"
-import { StringDecoder } from "string_decoder"
import { Cause, Effect, Exit, Fiber, Scope } from "effect"
import { SessionID, PartID } from "@/session/schema"
import { MessageV2 } from "@/session/message-v2"
@@ -377,25 +376,6 @@ export namespace KiloSessionPrompt {
}
}
- /**
- * Creates StringDecoder-based helpers for shell stdout/stderr that correctly
- * handle multi-byte UTF-8 characters split across chunks.
- */
- export function createShellDecoders() {
- const stdout = new StringDecoder("utf8")
- const stderr = new StringDecoder("utf8")
- return {
- /** Decode a chunk from the given stream. */
- write(stream: "stdout" | "stderr", chunk: Buffer) {
- return stream === "stdout" ? stdout.write(chunk) : stderr.write(chunk)
- },
- /** Flush any trailing buffered bytes from both decoders. */
- flush() {
- return stdout.end() + stderr.end()
- },
- }
- }
-
/**
* Ensures the plan file directory exists. Pre-checks with `Filesystem.isDir`
* because `fs.mkdir(recursive: true)` still throws `EEXIST` on Windows
@@ -455,12 +435,6 @@ export namespace KiloSessionPrompt {
add(`\n${body}\n`)
}
- /**
- * Returns the CODE_SWITCH prompt text (plan-to-code transition).
- * Used when switching from plan agent to code agent.
- */
- export const CODE_SWITCH_TEXT = CODE_SWITCH
-
/**
* Determines the close reason for a session turn.
* Checks for an explicit reason first (e.g. set on error during runLoop),
diff --git a/packages/opencode/src/kilocode/text-stream.ts b/packages/opencode/src/kilocode/text-stream.ts
index 82f2f6cd7c..bfaabd164e 100644
--- a/packages/opencode/src/kilocode/text-stream.ts
+++ b/packages/opencode/src/kilocode/text-stream.ts
@@ -62,11 +62,6 @@ export function abortable(stream: Readable, signal?: AbortSignal) {
return signal ? addAbortSignal(signal, stream) : stream
}
-/** UTF-8 text stream backed by an already-open file. */
-export function openUtf8(open: () => Readable, signal?: AbortSignal): Readable {
- return utf8(open, signal).stream
-}
-
export function safeSlice(text: string, end: number) {
const sliced = text.slice(0, end)
const last = sliced.charCodeAt(sliced.length - 1)
From dab2e79d6ecc24acfd8737a10dfdf8ef02765b30 Mon Sep 17 00:00:00 2001
From: Christiaan Arnoldus
Date: Tue, 28 Jul 2026 14:44:40 +0200
Subject: [PATCH 009/100] fix(cli): exclude gpt-5.6 from ChatGPT subscriptions
---
.changeset/exact-gpt-subscription.md | 5 +++++
packages/opencode/src/plugin/openai/codex.ts | 2 +-
packages/opencode/test/plugin/codex.test.ts | 10 ++++++++++
3 files changed, 16 insertions(+), 1 deletion(-)
create mode 100644 .changeset/exact-gpt-subscription.md
diff --git a/.changeset/exact-gpt-subscription.md b/.changeset/exact-gpt-subscription.md
new file mode 100644
index 0000000000..05332f513e
--- /dev/null
+++ b/.changeset/exact-gpt-subscription.md
@@ -0,0 +1,5 @@
+---
+"@kilocode/cli": patch
+---
+
+Exclude GPT-5.6 from models available through ChatGPT subscriptions while retaining access to variants such as GPT-5.6 Sol.
diff --git a/packages/opencode/src/plugin/openai/codex.ts b/packages/opencode/src/plugin/openai/codex.ts
index 262882669f..5a3a6fc9f9 100644
--- a/packages/opencode/src/plugin/openai/codex.ts
+++ b/packages/opencode/src/plugin/openai/codex.ts
@@ -29,7 +29,7 @@ const ALLOWED_MODELS = new Set([
// kilocode_change end
])
// kilocode_change start
-const DISALLOWED_MODELS = new Set(["gpt-5.5-pro"])
+const DISALLOWED_MODELS = new Set(["gpt-5.5-pro", "gpt-5.6"])
// kilocode_change end
interface PkceCodes {
diff --git a/packages/opencode/test/plugin/codex.test.ts b/packages/opencode/test/plugin/codex.test.ts
index a40b995358..a264bd376a 100644
--- a/packages/opencode/test/plugin/codex.test.ts
+++ b/packages/opencode/test/plugin/codex.test.ts
@@ -148,6 +148,14 @@ describe("plugin.codex", () => {
id: "gpt-5.5",
api: { id: "gpt-5.5" },
} as never,
+ "gpt-5.6": {
+ id: "gpt-5.6",
+ api: { id: "gpt-5.6" },
+ } as never,
+ "gpt-5.6-sol": {
+ id: "gpt-5.6-sol",
+ api: { id: "gpt-5.6-sol" },
+ } as never,
"gpt-5.4-mini": {
id: "gpt-5.4-mini",
api: { id: "gpt-5.4-mini" },
@@ -164,6 +172,8 @@ describe("plugin.codex", () => {
} as never, { auth: { type: "oauth" } } as never)
expect(provider).not.toHaveProperty(["gpt-5.5-pro"])
expect(provider).toHaveProperty(["gpt-5.5"])
+ expect(provider).not.toHaveProperty(["gpt-5.6"])
+ expect(provider).toHaveProperty(["gpt-5.6-sol"])
expect(provider).toHaveProperty(["gpt-5.4-mini"])
expect(provider).toHaveProperty(["gpt-5.1-codex"])
expect(provider).not.toHaveProperty(["other-model"])
From c08f37e88b7d063429fba5b164e31c94d1935610 Mon Sep 17 00:00:00 2001
From: Bruno Agatao
Date: Tue, 28 Jul 2026 15:26:14 +0200
Subject: [PATCH 010/100] feat(cli): execute shell commands in skill files with
batch approval
---
packages/opencode/src/cli/cmd/run.ts | 6 +
packages/opencode/src/effect/runtime-flags.ts | 1 +
.../opencode/src/kilocode/permission/drain.ts | 2 +
.../opencode/src/kilocode/skills/inject.ts | 78 +++++++
packages/opencode/src/permission/index.ts | 13 ++
packages/opencode/src/skill/index.ts | 3 +
packages/opencode/src/tool/skill.ts | 21 +-
.../kilocode/permission/skill-shell.test.ts | 127 +++++++++++
.../test/kilocode/skills/inject.test.ts | 197 ++++++++++++++++++
.../tui/src/routes/session/permission.tsx | 24 ++-
10 files changed, 466 insertions(+), 6 deletions(-)
create mode 100644 packages/opencode/src/kilocode/skills/inject.ts
create mode 100644 packages/opencode/test/kilocode/permission/skill-shell.test.ts
create mode 100644 packages/opencode/test/kilocode/skills/inject.test.ts
diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts
index 56241ace1a..d77916109e 100644
--- a/packages/opencode/src/cli/cmd/run.ts
+++ b/packages/opencode/src/cli/cmd/run.ts
@@ -840,6 +840,12 @@ export const RunCommand = effectCmd({
if (event.type === "permission.asked") {
const permission = event.properties
+ // kilocode_change start - skill shell batches need an interactive human decision; never headless auto-approve
+ if (permission.metadata?.["skillShell"] === true) {
+ await client.permission.reply({ requestID: permission.id, reply: "reject" })
+ continue
+ }
+ // kilocode_change end
// kilocode_change start - approve root and tracked Task child permissions in auto mode
if (args.auto) {
if (!KiloRunAuto.allowed(auto, permission.sessionID)) continue
diff --git a/packages/opencode/src/effect/runtime-flags.ts b/packages/opencode/src/effect/runtime-flags.ts
index 188dc4869a..f1bf3edb26 100644
--- a/packages/opencode/src/effect/runtime-flags.ts
+++ b/packages/opencode/src/effect/runtime-flags.ts
@@ -20,6 +20,7 @@ export class Service extends ConfigService.Service()("@opencode/Runtime
disableChannelDb: bool("KILO_DISABLE_CHANNEL_DB"), // kilocode_change
disableEmbeddedWebUi: bool("KILO_DISABLE_EMBEDDED_WEB_UI"),
disableExternalSkills: bool("KILO_DISABLE_EXTERNAL_SKILLS"),
+ disableSkillShell: bool("KILO_DISABLE_SKILL_SHELL"), // kilocode_change - disable shell injection in skill bodies
disableLspDownload: bool("KILO_DISABLE_LSP_DOWNLOAD"),
skipMigrations: bool("KILO_SKIP_MIGRATIONS"), // kilocode_change
disableClaudeCodePrompt: Config.all({
diff --git a/packages/opencode/src/kilocode/permission/drain.ts b/packages/opencode/src/kilocode/permission/drain.ts
index 78f960c867..499f4f83e1 100644
--- a/packages/opencode/src/kilocode/permission/drain.ts
+++ b/packages/opencode/src/kilocode/permission/drain.ts
@@ -33,6 +33,8 @@ export function drainCovered(
// Never auto-resolve config file edit permissions
const skill = ConfigProtection.globalSkillPattern(entry.info)
if (ConfigProtection.isRequest(entry.info) && !skill) continue
+ // Never auto-resolve a skill shell batch; it must get an explicit reply.
+ if (entry.info.metadata?.["skillShell"] === true) continue
const actions = entry.info.patterns.map((pattern: string) => {
const rule = skill
? Permission.evaluate(entry.info.permission, skill, approved)
diff --git a/packages/opencode/src/kilocode/skills/inject.ts b/packages/opencode/src/kilocode/skills/inject.ts
new file mode 100644
index 0000000000..ceee78c742
--- /dev/null
+++ b/packages/opencode/src/kilocode/skills/inject.ts
@@ -0,0 +1,78 @@
+import { Effect } from "effect"
+import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
+import type { ChildProcessSpawner as Spawner } from "effect/unstable/process/ChildProcessSpawner"
+import { ConfigMarkdown } from "@/config/markdown"
+import { CommandTimeout } from "@/kilocode/command-timeout"
+import { Shell } from "@opencode-ai/core/shell"
+import type * as Tool from "@/tool/tool"
+
+// Shell injection for skill bodies mirrors Claude's "dynamic context injection":
+// a `!`cmd`` placeholder in SKILL.md is replaced by the command's stdout before
+// the content reaches the model. Unlike the slash-command path, this runs for
+// model-initiated skill loads, so it is gated on three independent controls:
+//
+// 1. Trust: only skills from trusted sources (global ~/.claude, ~/.agents,
+// KILO_CONFIG_DIR, and builtins) may execute. Untrusted project/downloaded
+// skills never spawn a process.
+// 2. Kill-switch: `disabled` (KILO_DISABLE_SKILL_SHELL) turns injection off
+// entirely, matching Claude's disableSkillShellExecution.
+// 3. Batch approval: every command in the file is presented once, up front, in
+// a single permission prompt (the `skillShell` metadata marker forces this
+// prompt regardless of any allow/deny/auto-approve rule). Approve runs the
+// whole batch; reject aborts the skill load with nothing run.
+//
+// Substitution runs exactly once. Command output is inlined as plain text and is
+// never re-scanned, so a command cannot emit a `!`cmd`` placeholder that a later
+// pass would execute (second-order injection).
+
+const DISABLED_NOTE = "[skill shell execution disabled by policy]"
+const UNTRUSTED_NOTE = "[skill shell execution disabled for untrusted skill]"
+
+export namespace SkillInject {
+ export type Options = {
+ content: string
+ trusted: boolean
+ disabled: boolean
+ ctx: Tool.Context
+ spawner: Spawner["Service"]
+ }
+
+ export const render = Effect.fn("SkillInject.render")(function* (opts: Options) {
+ const matches = ConfigMarkdown.shell(opts.content)
+ if (matches.length === 0) return opts.content
+
+ // Defense-in-depth ordering: policy checks first, approval gate last.
+ if (opts.disabled) return replace(opts.content, () => DISABLED_NOTE)
+ if (!opts.trusted) return replace(opts.content, () => UNTRUSTED_NOTE)
+
+ // Deduplicate identical commands so the batch lists and runs each once.
+ const commands = Array.from(new Set(matches.map(([, cmd]) => cmd)))
+
+ // Single up-front approval for the whole batch. `skillShell` forces one
+ // prompt even when rules would allow or deny; a reject/deny propagates as a
+ // defect and aborts the skill load without running anything.
+ yield* opts.ctx.ask({
+ permission: "bash",
+ patterns: commands,
+ always: [],
+ metadata: { skillShell: true },
+ })
+
+ const shell = Shell.preferred()
+ const outputs = new Map()
+ for (const command of commands) {
+ outputs.set(
+ command,
+ yield* CommandTimeout.text(command, shell).pipe(Effect.provideService(ChildProcessSpawner, opts.spawner)),
+ )
+ }
+
+ return replace(opts.content, (command) => outputs.get(command) ?? "")
+ })
+
+ // Replace only the exact matches found in the ORIGINAL content. Never re-scan
+ // the result, so inlined output containing `!`cmd`` stays inert.
+ function replace(content: string, value: (command: string) => string) {
+ return content.replace(ConfigMarkdown.SHELL_REGEX, (_, command: string) => value(command))
+ }
+}
diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts
index f15feff563..d5217693d2 100644
--- a/packages/opencode/src/permission/index.ts
+++ b/packages/opencode/src/permission/index.ts
@@ -155,6 +155,7 @@ function subset(permission: string, ruleset: Ruleset) {
function covered(entry: PendingEntry, approved: Ruleset, local: Ruleset) {
if (ConfigProtection.isRequest(entry.info)) return false
+ if (entry.info.metadata?.["skillShell"] === true) return false // kilocode_change - skill batch needs an explicit reply
return entry.info.patterns.every((pattern) => {
if (veto(entry.info.permission, pattern, entry.hardRuleset)) return false
return resolve(entry.info.permission, pattern, entry.ruleset, approved, local).action === "allow"
@@ -221,7 +222,19 @@ export const layer = Layer.effect(
: false
// kilocode_change end
+ // kilocode_change start - skill shell injection always prompts once, overriding every allow/deny/auto-approve rule
+ const forceAsk = request.metadata?.["skillShell"] === true
+ // kilocode_change end
for (const pattern of request.patterns) {
+ // kilocode_change start - force a prompt over soft allow/deny rules, but never over a hard (plan-mode) veto
+ if (forceAsk) {
+ if (veto(request.permission, pattern, hardRuleset)) {
+ return yield* new DeniedError({ ruleset: subset(request.permission, hardRuleset ?? []) })
+ }
+ needsAsk = true
+ continue
+ }
+ // kilocode_change end
const rule = resolve(request.permission, pattern, ruleset, approved, local) // kilocode_change — include session-scoped rules
yield* Effect.logInfo("evaluated", { permission: request.permission, pattern, action: rule })
// kilocode_change start — saved/session approvals cannot override hard Ask/Plan denials
diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts
index 2477093d9f..1b5f4241cc 100644
--- a/packages/opencode/src/skill/index.ts
+++ b/packages/opencode/src/skill/index.ts
@@ -35,6 +35,7 @@ export const Info = Schema.Struct({
description: Schema.optional(Schema.String),
location: Schema.String,
content: Schema.String,
+ trusted: Schema.optional(Schema.Boolean), // kilocode_change - gate skill shell injection to trusted sources
})
export type Info = Schema.Schema.Type
@@ -151,6 +152,7 @@ const add = Effect.fnUntraced(function* (state: State, match: Match, events: Eve
description: md.data.description,
location: match.path, // kilocode_change
content: md.content,
+ trusted: match.trusted, // kilocode_change
}
})
@@ -295,6 +297,7 @@ const loadSkills = Effect.fnUntraced(function* (
description: skill.description,
location: BUILTIN_LOCATION,
content: skill.content,
+ trusted: true, // kilocode_change - builtin skills ship in the binary
}
}
// kilocode_change end
diff --git a/packages/opencode/src/tool/skill.ts b/packages/opencode/src/tool/skill.ts
index 4b84989504..ad2049afc2 100644
--- a/packages/opencode/src/tool/skill.ts
+++ b/packages/opencode/src/tool/skill.ts
@@ -5,6 +5,11 @@ import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { Skill } from "../skill"
import * as Tool from "./tool"
import DESCRIPTION from "./skill.txt"
+// kilocode_change start - gate + run shell injection in skill bodies
+import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
+import { RuntimeFlags } from "@/effect/runtime-flags"
+import { SkillInject } from "@/kilocode/skills/inject"
+// kilocode_change end
export const Parameters = Schema.Struct({
name: Schema.String.annotate({ description: "The name of the skill from available_skills" }),
@@ -15,6 +20,8 @@ export const SkillTool = Tool.define(
Effect.gen(function* () {
const skill = yield* Skill.Service
const ripgrep = yield* Ripgrep.Service
+ const flags = yield* RuntimeFlags.Service // kilocode_change
+ const spawner = yield* ChildProcessSpawner // kilocode_change
return {
description: DESCRIPTION,
@@ -32,6 +39,16 @@ export const SkillTool = Tool.define(
metadata: {},
})
+ // kilocode_change start - render `!`cmd`` shell injection, gated by trust + kill-switch + batch approval
+ const content = yield* SkillInject.render({
+ content: info.content,
+ trusted: info.trusted === true,
+ disabled: flags.disableSkillShell,
+ ctx,
+ spawner,
+ })
+ // kilocode_change end
+
// kilocode_change start - built-in skills have no filesystem directory
if (info.location === Skill.BUILTIN_LOCATION) {
return {
@@ -40,7 +57,7 @@ export const SkillTool = Tool.define(
``,
`# Skill: ${info.name}`,
"",
- info.content.trim(),
+ content.trim(), // kilocode_change
"",
].join("\n"),
metadata: {
@@ -68,7 +85,7 @@ export const SkillTool = Tool.define(
``,
`# Skill: ${info.name}`,
"",
- info.content.trim(),
+ content.trim(), // kilocode_change
"",
`Base directory for this skill: ${base}`,
"Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.",
diff --git a/packages/opencode/test/kilocode/permission/skill-shell.test.ts b/packages/opencode/test/kilocode/permission/skill-shell.test.ts
new file mode 100644
index 0000000000..d6b1fa7981
--- /dev/null
+++ b/packages/opencode/test/kilocode/permission/skill-shell.test.ts
@@ -0,0 +1,127 @@
+import { PermissionV1 } from "@opencode-ai/core/v1/permission"
+import { expect } from "bun:test"
+import { Cause, Effect, Exit, Fiber, Layer } from "effect"
+import { EventV2Bridge } from "@/event-v2-bridge"
+import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
+import { Database } from "@opencode-ai/core/database/database"
+import { Permission } from "@/permission"
+import { InstanceBootstrap } from "@/project/bootstrap-service"
+import { InstanceStore } from "@/project/instance-store"
+import { testEffect } from "../../lib/effect"
+import { SessionID } from "@/session/schema"
+import { RuntimeFlags } from "@/effect/runtime-flags"
+import { Config } from "@/config/config"
+
+// skillShell forces a single up-front prompt over soft allow/deny/auto-approve
+// rules, but must never override a hard (plan-mode) veto, and must never be
+// auto-resolved while pending.
+
+const events = EventV2Bridge.defaultLayer
+const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))
+const env = Layer.mergeAll(
+ Permission.layer.pipe(Layer.provide(Database.defaultLayer), Layer.provide(events)),
+ events,
+ CrossSpawnSpawner.defaultLayer,
+ InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)),
+).pipe(Layer.provide(RuntimeFlags.layer()), Layer.provide(Config.defaultLayer))
+const it = testEffect(Layer.mergeAll(env, RuntimeFlags.layer()))
+
+const ask = (input: Parameters[0]) =>
+ Effect.gen(function* () {
+ return yield* (yield* Permission.Service).ask(input)
+ })
+
+const list = () =>
+ Effect.gen(function* () {
+ return yield* (yield* Permission.Service).list()
+ })
+
+const rejectAll = () =>
+ Effect.gen(function* () {
+ const permission = yield* Permission.Service
+ for (const req of yield* permission.list()) yield* permission.reply({ requestID: req.id, reply: "reject" })
+ })
+
+const waitForPending = (count: number) =>
+ Effect.gen(function* () {
+ const permission = yield* Permission.Service
+ return yield* Effect.gen(function* () {
+ while (true) {
+ const pending = yield* permission.list()
+ if (pending.length === count) return pending
+ yield* Effect.sleep("10 millis")
+ }
+ }).pipe(Effect.timeoutOrElse({ duration: "1 second", orElse: () => Effect.fail(new Error("timed out")) }))
+ })
+
+const fail = (self: Effect.Effect) =>
+ Effect.gen(function* () {
+ const exit = yield* self.pipe(Effect.exit)
+ if (Exit.isFailure(exit)) return Cause.squash(exit.cause)
+ throw new Error("expected permission effect to fail")
+ })
+
+it.instance(
+ "skillShell - forces a prompt even when a matching allow rule exists",
+ () =>
+ Effect.gen(function* () {
+ const fiber = yield* ask({
+ sessionID: SessionID.make("session_test"),
+ permission: "bash",
+ patterns: ["printf hi"],
+ metadata: { skillShell: true },
+ always: [],
+ ruleset: [{ permission: "bash", pattern: "*", action: "allow" }],
+ }).pipe(Effect.forkScoped)
+
+ expect(yield* waitForPending(1)).toHaveLength(1)
+ yield* rejectAll()
+ yield* Fiber.await(fiber)
+ }),
+ { git: true },
+)
+
+it.instance(
+ "skillShell - is denied by a hard-ruleset veto instead of prompting",
+ () =>
+ Effect.gen(function* () {
+ const err = yield* fail(
+ ask({
+ sessionID: SessionID.make("session_test"),
+ permission: "bash",
+ patterns: ["rm -rf /"],
+ metadata: { skillShell: true },
+ always: [],
+ ruleset: [{ permission: "bash", pattern: "*", action: "allow" }],
+ hardRuleset: [{ permission: "bash", pattern: "*", action: "deny" }],
+ }),
+ )
+
+ expect(err).toBeInstanceOf(PermissionV1.DeniedError)
+ expect(yield* list()).toHaveLength(0)
+ }),
+ { git: true },
+)
+
+it.instance(
+ "skillShell - a pending batch is not auto-resolved by allowEverything",
+ () =>
+ Effect.gen(function* () {
+ const fiber = yield* ask({
+ sessionID: SessionID.make("session_test"),
+ permission: "bash",
+ patterns: ["printf hi"],
+ metadata: { skillShell: true },
+ always: [],
+ ruleset: [],
+ }).pipe(Effect.forkScoped)
+
+ expect(yield* waitForPending(1)).toHaveLength(1)
+ yield* (yield* Permission.Service).allowEverything({ enable: true })
+ // still pending: YOLO cannot silently approve a skill batch
+ expect(yield* list()).toHaveLength(1)
+ yield* rejectAll()
+ yield* Fiber.await(fiber)
+ }),
+ { git: true },
+)
diff --git a/packages/opencode/test/kilocode/skills/inject.test.ts b/packages/opencode/test/kilocode/skills/inject.test.ts
new file mode 100644
index 0000000000..1058968d1e
--- /dev/null
+++ b/packages/opencode/test/kilocode/skills/inject.test.ts
@@ -0,0 +1,197 @@
+import { PermissionV1 } from "@opencode-ai/core/v1/permission"
+import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
+import { Ripgrep } from "@opencode-ai/core/ripgrep"
+import { Effect, Exit, Layer } from "effect"
+import { afterEach, describe, expect } from "bun:test"
+import fs from "fs"
+import os from "os"
+import path from "path"
+import type { Tool } from "@/tool/tool"
+import { SkillTool } from "@/tool/skill"
+import { SkillInject } from "@/kilocode/skills/inject"
+import { ToolRegistry } from "@/tool/registry"
+import { disposeAllInstances, TestInstance } from "../../fixture/fixture"
+import { SessionID, MessageID } from "@/session/schema"
+import { testEffect } from "../../lib/effect"
+
+// Global (~/.claude) skills are trusted, but Global.Service snapshots the home
+// path when its layer is built, so KILO_TEST_HOME must be set before the runtime
+// layer below is constructed — not inside a test body.
+const HOME = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "skill-inject-home-")))
+process.env.KILO_TEST_HOME = HOME
+
+const baseCtx: Omit = {
+ sessionID: SessionID.make("ses_test"),
+ messageID: MessageID.make("msg_test"),
+ callID: "",
+ agent: "build",
+ abort: AbortSignal.any([]),
+ messages: [],
+ metadata: () => Effect.void,
+}
+
+afterEach(async () => {
+ await disposeAllInstances()
+})
+
+const it = testEffect(
+ Layer.mergeAll(ToolRegistry.defaultLayer, CrossSpawnSpawner.defaultLayer).pipe(Layer.provide(Ripgrep.defaultLayer)),
+)
+
+// Shell injection spawns real processes; skip on windows CI like the sibling suite.
+const unix = process.platform !== "win32" ? it.instance : it.instance.skip
+
+afterEach(async () => {
+ // reset discovered skills between tests by clearing the global skill dir
+ await fs.promises.rm(path.join(HOME, ".agents"), { recursive: true, force: true })
+})
+
+// Global ~/.agents skills are trusted (and, unlike ~/.claude, not gated by the
+// KILO_DISABLE_CLAUDE_CODE flag the test env sets); project .kilo skills are untrusted.
+function writeGlobalSkill(name: string, body: string) {
+ return Effect.promise(() =>
+ Bun.write(
+ path.join(HOME, ".agents", "skills", name, "SKILL.md"),
+ `---\nname: ${name}\ndescription: ${name} test skill.\n---\n\n${body}\n`,
+ ),
+ )
+}
+
+function writeProjectSkill(dir: string, name: string, body: string) {
+ return Effect.promise(() =>
+ Bun.write(
+ path.join(dir, ".kilo", "skill", name, "SKILL.md"),
+ `---\nname: ${name}\ndescription: ${name} test skill.\n---\n\n${body}\n`,
+ ),
+ )
+}
+
+function loadSkill(name: string, ask: Tool.Context["ask"]) {
+ return Effect.gen(function* () {
+ const registry = yield* ToolRegistry.Service
+ const agent = { name: "build", mode: "primary" as const, permission: [], options: {} }
+ const tool = (yield* registry.tools({
+ providerID: "opencode" as any,
+ modelID: "gpt-5" as any,
+ agent,
+ })).find((t) => t.id === SkillTool.id)
+ if (!tool) throw new Error("Skill tool not found")
+ return yield* tool.execute({ name }, { ...baseCtx, ask })
+ })
+}
+
+describe("skill shell injection", () => {
+ unix("runs the batch after a single forced approval listing every command", () =>
+ Effect.gen(function* () {
+ yield* writeGlobalSkill("trusted-shell", "A: !`printf one` B: !`printf two`")
+
+ const requests: Array> = []
+ const result = yield* loadSkill("trusted-shell", (req) =>
+ Effect.sync(() => {
+ requests.push(req)
+ }),
+ )
+
+ expect(result.output).toContain("A: one B: two")
+ // one skill-load ask plus exactly one batch bash ask carrying all commands
+ const bash = requests.filter((r) => r.permission === "bash")
+ expect(bash.length).toBe(1)
+ expect(bash[0].metadata?.["skillShell"]).toBe(true)
+ // patterns carry the command list the prompt renders
+ expect(bash[0].patterns).toEqual(["printf one", "printf two"])
+ }),
+ )
+
+ unix("aborts the entire skill load when the batch is rejected", () =>
+ Effect.gen(function* () {
+ yield* writeGlobalSkill("denied-shell", "Secret: !`printf leaked`")
+
+ const exit = yield* loadSkill("denied-shell", (req) =>
+ // Reject the batch. Tools wrap ctx.ask with Effect.orDie, so this reaches
+ // the injector as a defect and must abort the whole skill load.
+ req.permission === "bash"
+ ? Effect.fail(new PermissionV1.RejectedError()).pipe(Effect.orDie)
+ : Effect.void,
+ ).pipe(Effect.exit)
+
+ expect(Exit.isFailure(exit)).toBe(true)
+ }),
+ )
+
+ unix("does not run shell injection for untrusted project skills", () =>
+ Effect.gen(function* () {
+ const dir = (yield* TestInstance).directory
+ yield* writeProjectSkill(dir, "untrusted-shell", "Value: !`printf shouldnotrun`")
+
+ const requests: Array> = []
+ const result = yield* loadSkill("untrusted-shell", (req) =>
+ Effect.sync(() => {
+ requests.push(req)
+ }),
+ )
+
+ expect(result.output).toContain("[skill shell execution disabled for untrusted skill]")
+ expect(result.output).not.toContain("shouldnotrun")
+ // no bash permission ask because nothing was scanned or spawned
+ expect(requests.some((r) => r.permission === "bash")).toBe(false)
+ }),
+ )
+
+ unix("does not re-execute shell placeholders emitted by command output", () =>
+ Effect.gen(function* () {
+ // The command emits a literal placeholder `!echo pwned`
+ // built from octal escapes so the SKILL.md itself contains no nested
+ // backticks. If render re-scanned command output, `echo pwned` would run.
+ yield* writeGlobalSkill("nested-shell", "Out: !`printf '!\\140echo pwned\\140'`")
+
+ const result = yield* loadSkill("nested-shell", () => Effect.void)
+
+ expect(result.output).toContain("!`echo pwned`")
+ // "pwned" must appear only inside the inert placeholder, never executed alone.
+ expect(result.output).not.toMatch(/Out:\s*pwned\s*$/m)
+ }),
+ )
+})
+
+// The disabled (kill-switch) and untrusted branches must short-circuit before
+// asking permission or spawning. Passing an ask/spawner that throws proves
+// neither is reached.
+describe("SkillInject.render gating", () => {
+ const boom = () => {
+ throw new Error("must not be reached")
+ }
+ const spawner = new Proxy({}, { get: boom }) as any
+ const ctx = { ...baseCtx, ask: () => Effect.sync(boom) } as Tool.Context
+
+ const run = (opts: { trusted: boolean; disabled: boolean; content?: string }) =>
+ Effect.runPromise(
+ SkillInject.render({
+ content: opts.content ?? "Value: !`printf ran`",
+ trusted: opts.trusted,
+ disabled: opts.disabled,
+ ctx,
+ spawner,
+ }),
+ )
+
+ it.effect("kill-switch replaces every command without asking or running it", () =>
+ Effect.gen(function* () {
+ const out = yield* Effect.promise(() => run({ trusted: true, disabled: true }))
+ expect(out).toBe("Value: [skill shell execution disabled by policy]")
+ }),
+ )
+
+ it.effect("untrusted skills never ask or run their commands", () =>
+ Effect.gen(function* () {
+ const out = yield* Effect.promise(() => run({ trusted: false, disabled: false }))
+ expect(out).toBe("Value: [skill shell execution disabled for untrusted skill]")
+ }),
+ )
+
+ it.effect("content without placeholders is returned unchanged", () =>
+ Effect.gen(function* () {
+ const out = yield* Effect.promise(() => run({ trusted: true, disabled: false, content: "no commands here" }))
+ expect(out).toBe("no commands here")
+ }),
+ )
+})
diff --git a/packages/tui/src/routes/session/permission.tsx b/packages/tui/src/routes/session/permission.tsx
index 6e712ccd34..a6f21d0c2f 100644
--- a/packages/tui/src/routes/session/permission.tsx
+++ b/packages/tui/src/routes/session/permission.tsx
@@ -291,6 +291,20 @@ export function PermissionPrompt(props: { request: PermissionRequest; directory?
}
if (permission === "bash") {
+ // kilocode_change start - skill shell batches list every command
+ if (props.request.metadata?.["skillShell"] === true) {
+ const commands = (props.request.patterns ?? []).filter((p): p is string => typeof p === "string")
+ return {
+ icon: "#",
+ title: "Run these skill commands?",
+ body: (
+
+ {(cmd) => {"$ " + cmd}}
+
+ ),
+ }
+ }
+ // kilocode_change end
// kilocode_change start
const meta = props.request.metadata ?? {}
const desc =
@@ -446,10 +460,12 @@ export function PermissionPrompt(props: { request: PermissionRequest; directory?
)
- // kilocode_change start - hide "Always allow" for protected Kilo configuration access
- const options: Record = props.request.metadata?.[ConfigProtection.DISABLE_ALWAYS_KEY]
- ? { once: "Allow once", reject: "Reject" }
- : { once: "Allow once", always: "Allow always", reject: "Reject" }
+ // kilocode_change start - skill shell batches are never persisted: only Allow / Reject
+ const options: Record = props.request.metadata?.["skillShell"]
+ ? { once: "Allow", reject: "Reject" }
+ : props.request.metadata?.[ConfigProtection.DISABLE_ALWAYS_KEY]
+ ? { once: "Allow once", reject: "Reject" }
+ : { once: "Allow once", always: "Allow always", reject: "Reject" }
// kilocode_change end
const body = (
From 2d784a0e3162818afdb89b2c2352e45fdaaa8c6d Mon Sep 17 00:00:00 2001
From: Bruno Agatao
Date: Tue, 28 Jul 2026 15:27:30 +0200
Subject: [PATCH 011/100] chore(cli): add changeset for skill shell execution
---
.changeset/skill-shell-execution.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/skill-shell-execution.md
diff --git a/.changeset/skill-shell-execution.md b/.changeset/skill-shell-execution.md
new file mode 100644
index 0000000000..bbe09cf70d
--- /dev/null
+++ b/.changeset/skill-shell-execution.md
@@ -0,0 +1,5 @@
+---
+"@kilocode/cli": minor
+---
+
+Support executing shell commands embedded in skill files. Commands written as `` !`command` `` in a SKILL.md run when the skill loads and their output is inlined into the skill, gated by a single up-front approval that lists every command. Only trusted skills can run commands, and `KILO_DISABLE_SKILL_SHELL` disables the behavior.
From 7041ab640d5b5aacbe0755530587142e16bce3a2 Mon Sep 17 00:00:00 2001
From: HDCode
Date: Tue, 28 Jul 2026 18:45:43 +0200
Subject: [PATCH 012/100] chore(jetbrains): centralize test dependency versions
---
packages/kilo-jetbrains/frontend/build.gradle.kts | 4 ++--
packages/kilo-jetbrains/gradle/libs.versions.toml | 7 ++++++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/kilo-jetbrains/frontend/build.gradle.kts b/packages/kilo-jetbrains/frontend/build.gradle.kts
index 0c141225c6..a42f67e199 100644
--- a/packages/kilo-jetbrains/frontend/build.gradle.kts
+++ b/packages/kilo-jetbrains/frontend/build.gradle.kts
@@ -28,8 +28,8 @@ dependencies {
implementation(libs.zxing.core)
testImplementation(kotlin("test"))
- testImplementation("junit:junit:4.13.2")
- testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.11.4")
+ testImplementation(libs.junit)
+ testRuntimeOnly(libs.junit.vintage.engine)
}
val providerIcons = tasks.register("generateProviderIcons") {
diff --git a/packages/kilo-jetbrains/gradle/libs.versions.toml b/packages/kilo-jetbrains/gradle/libs.versions.toml
index 15b48416fe..182e9b77c4 100644
--- a/packages/kilo-jetbrains/gradle/libs.versions.toml
+++ b/packages/kilo-jetbrains/gradle/libs.versions.toml
@@ -5,6 +5,9 @@ intellij-rpc-plugin = "2.3.20-RC2-0.1"
kotlin-jvm-plugin = "2.3.20"
kotlin-serialization-plugin = "2.3.20"
kotlin-serialization = "1.11.0"
+kotlinx-coroutines = "1.10.2"
+junit = "4.13.2"
+junit-vintage = "5.11.4"
okhttp = "4.12.0"
openapi-generator = "7.21.0"
detekt = "1.23.8"
@@ -22,7 +25,9 @@ okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-sse = { module = "com.squareup.okhttp3:okhttp-sse", version.ref = "okhttp" }
okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlin-serialization" }
-kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version = "1.10.2" }
+kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
+junit = { module = "junit:junit", version.ref = "junit" }
+junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit-vintage" }
zxing-core = { module = "com.google.zxing:core", version.ref = "zxing" }
commons-compress = { module = "org.apache.commons:commons-compress", version.ref = "commons-compress" }
From c0ebf987789ab6fa070106219ebc8c46cd0105af Mon Sep 17 00:00:00 2001
From: Aarav
Date: Wed, 29 Jul 2026 02:07:24 -0600
Subject: [PATCH 013/100] feat(opencode): route websearch Exa through Kilo
proxy (#12470)
Add a new Kilo-REST Exa transport alongside the existing MCP-Exa
and MCP-Parallel transports. When the websearch tool picks the Exa
provider and the user is signed into Kilo, requests go to
https://app.kilo.ai/api/exa/search with the user's Kilo bearer.
The cloud proxy injects its own Exa API key; the client sends the
user's Kilo API key as a Bearer token. The MCP-BYOK path (EXA_API_KEY)
and MCP-unauthed fallback are preserved unchanged.
Changes:
* New `packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts`
implements `callKiloExa` against the Exa REST API
(`POST /search`) with `{ highlights: true }` contents and clamps
numResults at 10 (Exa's first-10-results flat $0.007 tier).
* `packages/opencode/src/tool/websearch.ts` adds a `"kilo-exa"`
provider variant (selected only via `KILO_WEBSEARCH_PROVIDER`
override), an Auth.Service yield to source the Kilo bearer, a
transport-dispatch block that prefers Kilo-REST over MCP when
auth is available and EXA_API_KEY is unset, and `transport`
metadata on the tool part. MCP-Exa numResults is now clamped
at 10 (default stays 8).
* 13 unit tests in
`packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts`
cover request shape, response formatting, error handling, and
the costDollars ignore case.
* Parameters snapshot updated for the new numResults description
string.
* Patch-level changeset added.
---
.changeset/kilo-exa-websearch.md | 5 +
.../src/kilocode/tool/websearch-kilo-exa.ts | 74 +++++++
packages/opencode/src/tool/websearch.ts | 66 ++++++-
.../kilocode/tool/websearch-kilo-exa.test.ts | 180 ++++++++++++++++++
.../__snapshots__/parameters.test.ts.snap | 2 +-
5 files changed, 317 insertions(+), 10 deletions(-)
create mode 100644 .changeset/kilo-exa-websearch.md
create mode 100644 packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts
create mode 100644 packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts
diff --git a/.changeset/kilo-exa-websearch.md b/.changeset/kilo-exa-websearch.md
new file mode 100644
index 0000000000..58bd6ec146
--- /dev/null
+++ b/.changeset/kilo-exa-websearch.md
@@ -0,0 +1,5 @@
+---
+"@kilocode/cli": patch
+---
+
+Route the websearch tool's Exa requests through the Kilo proxy when signed into Kilo. The MCP-Exa transport is preserved as a fallback for users who set `EXA_API_KEY` or are not authenticated. A new `KILO_WEBSEARCH_PROVIDER=kilo-exa` env override forces the Kilo proxy path. Results are capped at 10.
diff --git a/packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts b/packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts
new file mode 100644
index 0000000000..1e590b6c18
--- /dev/null
+++ b/packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts
@@ -0,0 +1,74 @@
+// kilocode_change - new file
+import { Duration, Effect, Schema } from "effect"
+import { HttpClient, HttpClientRequest } from "effect/unstable/http"
+import { KILO_API_BASE } from "@kilocode/kilo-gateway"
+
+export const KILO_EXA_URL = `${KILO_API_BASE}/api/exa/search`
+export const MAX_KILO_EXA_RESULTS = 10
+
+const ExaResult = Schema.Struct({
+ title: Schema.optional(Schema.String),
+ url: Schema.String,
+ publishedDate: Schema.optional(Schema.String),
+ author: Schema.optional(Schema.String),
+ highlights: Schema.optional(Schema.Array(Schema.String)),
+})
+
+const ExaResponse = Schema.Struct({
+ results: Schema.Array(ExaResult),
+})
+
+const NO_RESULTS = "No search results found. Please try a different query."
+
+const formatResults = (data: Schema.Schema.Type): string => {
+ if (data.results.length === 0) return NO_RESULTS
+ return data.results
+ .map((r, i) => {
+ const head = `[${i + 1}] ${r.title ?? r.url}\n${r.url}${r.publishedDate ? ` (${r.publishedDate})` : ""}`
+ const hl = r.highlights?.length ? `\n${r.highlights.map((h) => `> ${h}`).join("\n")}` : ""
+ return `${head}${hl}`
+ })
+ .join("\n\n")
+}
+
+export type KiloExaParams = {
+ query: string
+ type?: string
+ numResults?: number
+}
+
+export const callKiloExa = Effect.fn("WebSearchKiloExa.call")(function* (
+ http: HttpClient.HttpClient,
+ params: KiloExaParams,
+ kiloToken: string,
+) {
+ const numResults = Math.min(params.numResults ?? MAX_KILO_EXA_RESULTS, MAX_KILO_EXA_RESULTS)
+ const request = yield* HttpClientRequest.post(KILO_EXA_URL).pipe(
+ HttpClientRequest.bearerToken(kiloToken),
+ HttpClientRequest.acceptJson,
+ HttpClientRequest.bodyJson({
+ query: params.query,
+ type: params.type ?? "auto",
+ numResults,
+ contents: { highlights: true },
+ }),
+ )
+ const response = yield* http.execute(request).pipe(
+ Effect.timeoutOrElse({
+ duration: Duration.seconds(25),
+ orElse: () => Effect.die(new Error("kilo exa request timed out")),
+ }),
+ )
+ const status = response.status
+ if (status === 401 || status === 403) {
+ return yield* Effect.die(new Error(`Kilo exa request unauthorized (${status}); sign in with \`kilo auth login\``))
+ }
+ if (status < 200 || status >= 300) {
+ const body = yield* response.text
+ return yield* Effect.die(new Error(`Kilo exa request failed (${status}): ${body.slice(0, 200)}`))
+ }
+ const data = yield* response.json
+ const decode = Schema.decodeUnknownEffect(ExaResponse)
+ const parsed = yield* decode(data).pipe(Effect.orDie)
+ return formatResults(parsed)
+})
diff --git a/packages/opencode/src/tool/websearch.ts b/packages/opencode/src/tool/websearch.ts
index 12da7fbb3a..9a812cfc62 100644
--- a/packages/opencode/src/tool/websearch.ts
+++ b/packages/opencode/src/tool/websearch.ts
@@ -1,16 +1,20 @@
-import { Effect, Schema } from "effect"
+import { Effect, Option, Schema } from "effect" // kilocode_change - Option added for kilo-exa transport dispatch
import { HttpClient } from "effect/unstable/http"
import * as Tool from "./tool"
import * as McpWebSearch from "./mcp-websearch"
+import * as KiloExa from "@/kilocode/tool/websearch-kilo-exa" // kilocode_change - Kilo-REST Exa transport
import DESCRIPTION from "./websearch.txt"
import { checksum } from "@opencode-ai/core/util/encode"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { RuntimeFlags } from "@/effect/runtime-flags"
+import { Auth } from "@/auth" // kilocode_change - source Kilo bearer for Kilo-REST transport
+
+const MAX_RESULTS = 10 // kilocode_change - cap numResults across all transports
export const Parameters = Schema.Struct({
query: Schema.String.annotate({ description: "Websearch query" }),
numResults: Schema.optional(Schema.Number).annotate({
- description: "Number of search results to return (default: 8)",
+ description: "Number of search results to return (default: 8, maximum: 10)", // kilocode_change - note MAX_RESULTS cap
}),
livecrawl: Schema.optional(Schema.Literals(["fallback", "preferred"])).annotate({
description:
@@ -24,12 +28,12 @@ export const Parameters = Schema.Struct({
}),
})
-const WebSearchProviderSchema = Schema.Literals(["exa", "parallel"])
+const WebSearchProviderSchema = Schema.Literals(["exa", "parallel", "kilo-exa"]) // kilocode_change - kilo-exa env override
export type WebSearchProvider = Schema.Schema.Type
export function selectWebSearchProvider(sessionID: string, flags = { exa: false, parallel: false }): WebSearchProvider {
const override = process.env.KILO_WEBSEARCH_PROVIDER
- if (override === "exa" || override === "parallel") return override
+ if (override === "exa" || override === "parallel" || override === "kilo-exa") return override // kilocode_change - kilo-exa env override
if (flags.parallel) return "parallel"
if (flags.exa) return "exa"
@@ -38,7 +42,7 @@ export function selectWebSearchProvider(sessionID: string, flags = { exa: false,
export function webSearchProviderLabel(provider: unknown) {
if (provider === "parallel") return "Parallel Web Search"
- if (provider === "exa") return "Exa Web Search"
+ if (provider === "exa" || provider === "kilo-exa") return "Exa Web Search" // kilocode_change - kilo-exa shares label
return "Web Search"
}
@@ -88,7 +92,7 @@ function callProvider(
{
query: params.query,
type: params.type || "auto",
- numResults: params.numResults || 8,
+ numResults: Math.min(params.numResults || 8, MAX_RESULTS), // kilocode_change - cap at MAX_RESULTS
livecrawl: params.livecrawl || "fallback",
contextMaxCharacters: params.contextMaxCharacters,
},
@@ -101,6 +105,7 @@ export const WebSearchTool = Tool.define(
Effect.gen(function* () {
const http = yield* HttpClient.HttpClient
const flags = yield* RuntimeFlags.Service
+ const authSvc = yield* Auth.Service // kilocode_change - source Kilo bearer for Kilo-REST transport
return {
get description() {
@@ -114,7 +119,36 @@ export const WebSearchTool = Tool.define(
parallel: flags.enableParallel,
})
const title = webSearchProviderLabel(provider)
- yield* ctx.metadata({ title: `${title} "${params.query}"`, metadata: { provider } })
+ // kilocode_change start - Kilo-REST Exa transport
+ // Precedence:
+ // provider="kilo-exa" -> kilo-rest (auth required)
+ // provider="exa" + EXA_API_KEY -> mcp-exa-byok (BYOK wins)
+ // provider="exa" + Kilo auth -> kilo-rest (new default for authed users)
+ // provider="exa" + no auth -> mcp-exa-unauth (preserves current fallback)
+ // provider="parallel" -> mcp-parallel (unchanged)
+ const kiloToken = yield* Effect.gen(function* () {
+ if (provider !== "exa" && provider !== "kilo-exa") return undefined as string | undefined
+ const info = yield* authSvc.get("kilo")
+ if (!info) return undefined
+ return info.type === "api" ? info.key : info.type === "oauth" ? info.access : undefined
+ })
+ const transport =
+ provider === "kilo-exa"
+ ? "kilo-rest"
+ : provider === "parallel"
+ ? "mcp-parallel"
+ : provider === "exa" && process.env.EXA_API_KEY
+ ? "mcp-exa-byok"
+ : provider === "exa" && kiloToken
+ ? "kilo-rest"
+ : "mcp-exa-unauth"
+ // kilocode_change end
+ // kilocode_change start - add transport to metadata
+ yield* ctx.metadata({
+ title: `${title} "${params.query}"`,
+ metadata: { provider, transport },
+ })
+ // kilocode_change end
yield* ctx.ask({
permission: "websearch",
@@ -130,12 +164,26 @@ export const WebSearchTool = Tool.define(
},
})
- const result = yield* callProvider(http, provider, params, ctx)
+ // kilocode_change start - dispatch Kilo-REST transport
+ const result = yield* transport === "kilo-rest"
+ ? kiloToken
+ ? KiloExa.callKiloExa(
+ http,
+ {
+ query: params.query,
+ type: params.type,
+ numResults: params.numResults,
+ },
+ kiloToken,
+ )
+ : Effect.die(new Error("KILO_WEBSEARCH_PROVIDER=kilo-exa requires Kilo auth; run `kilo auth login`"))
+ : callProvider(http, provider, params, ctx)
+ // kilocode_change end
return {
output: result ?? "No search results found. Please try a different query.",
title: `${title}: ${params.query}`,
- metadata: { provider },
+ metadata: { provider, transport }, // kilocode_change - add transport
}
}).pipe(Effect.orDie),
}
diff --git a/packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts b/packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts
new file mode 100644
index 0000000000..5756e7c671
--- /dev/null
+++ b/packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts
@@ -0,0 +1,180 @@
+// kilocode_change - new file
+import { describe, expect, test } from "bun:test"
+import { Effect, Exit, Layer } from "effect"
+import { HttpBody, HttpClient, HttpClientResponse } from "effect/unstable/http"
+import {
+ KILO_EXA_URL,
+ MAX_KILO_EXA_RESULTS,
+ type KiloExaParams,
+ callKiloExa,
+} from "../../../src/kilocode/tool/websearch-kilo-exa"
+
+type Recorded = {
+ url?: string
+ method?: string
+ authorization?: string
+ body?: string
+}
+
+const readBody = async (body: HttpBody.HttpBody): Promise => {
+ if (body._tag === "Uint8Array") return new TextDecoder().decode(body.body)
+ if (body._tag === "Raw") return JSON.stringify(body.body)
+ return ""
+}
+
+const jsonResponse = (status: number, body: unknown): Response =>
+ new Response(JSON.stringify(body), {
+ status,
+ headers: { "content-type": "application/json" },
+ })
+
+const okJson = (body: unknown) => jsonResponse(200, body)
+
+const fakeHttp = (respond: (status: number) => Response, recorded?: Recorded): HttpClient.HttpClient =>
+ HttpClient.make((request) =>
+ Effect.gen(function* () {
+ const url = request.url
+ const method = request.method
+ const authorization = request.headers["authorization"]
+ const body = yield* Effect.promise(() => readBody(request.body))
+ if (recorded) {
+ recorded.url = url
+ recorded.method = method
+ recorded.authorization = authorization
+ recorded.body = body
+ }
+ return HttpClientResponse.fromWeb(
+ request as unknown as Parameters[0],
+ respond(200),
+ )
+ }),
+ )
+
+const runCall = async (
+ params: KiloExaParams,
+ respond: (status: number) => Response,
+ recorded?: Recorded,
+ kiloToken = "kilo-test-token",
+) =>
+ Effect.runPromiseExit(
+ Effect.gen(function* () {
+ const http = fakeHttp(respond, recorded)
+ return yield* callKiloExa(http, params, kiloToken)
+ }),
+ )
+
+describe("callKiloExa request shape", () => {
+ test("posts to KILO_EXA_URL with bearer token and highlights-only contents", async () => {
+ const recorded: Recorded = {}
+ const exit = await runCall({ query: "drone" }, () => okJson({ results: [] }), recorded)
+ expect(Exit.isSuccess(exit)).toBe(true)
+ expect(recorded.url).toContain("/api/exa/search")
+ expect(recorded.method).toBe("POST")
+ expect(recorded.authorization).toBe("Bearer kilo-test-token")
+ const parsed = JSON.parse(recorded.body!)
+ expect(parsed.query).toBe("drone")
+ expect(parsed.type).toBe("auto")
+ expect(parsed.numResults).toBe(MAX_KILO_EXA_RESULTS)
+ expect(parsed.contents).toEqual({ highlights: true })
+ })
+
+ test("uses caller numResults when below cap", async () => {
+ const recorded: Recorded = {}
+ await runCall({ query: "x", numResults: 3 }, () => okJson({ results: [] }), recorded)
+ expect(JSON.parse(recorded.body!).numResults).toBe(3)
+ })
+
+ test("clamps numResults at MAX_KILO_EXA_RESULTS", async () => {
+ const recorded: Recorded = {}
+ await runCall({ query: "x", numResults: 25 }, () => okJson({ results: [] }), recorded)
+ expect(JSON.parse(recorded.body!).numResults).toBe(MAX_KILO_EXA_RESULTS)
+ })
+
+ test("passes through caller type", async () => {
+ const recorded: Recorded = {}
+ await runCall({ query: "x", type: "deep" }, () => okJson({ results: [] }), recorded)
+ expect(JSON.parse(recorded.body!).type).toBe("deep")
+ })
+
+ test("KILO_EXA_URL is built from KILO_API_BASE", () => {
+ expect(KILO_EXA_URL).toMatch(/\/api\/exa\/search$/)
+ })
+})
+
+describe("callKiloExa response formatting", () => {
+ const okValue = (exit: Exit.Exit): string => {
+ if (Exit.isFailure(exit)) throw new Error("expected success")
+ return (exit as Extract).value as string
+ }
+
+ test("formats results with title, url, date and highlights", async () => {
+ const exit = await runCall({ query: "x" }, () =>
+ okJson({
+ results: [
+ {
+ title: "A drone",
+ url: "https://example.com/a",
+ publishedDate: "2025-01-02T00:00:00.000Z",
+ highlights: ["first", "second"],
+ },
+ ],
+ }),
+ )
+ const text = okValue(exit)
+ expect(text).toContain("[1] A drone")
+ expect(text).toContain("https://example.com/a")
+ expect(text).toContain("(2025-01-02T00:00:00.000Z)")
+ expect(text).toContain("> first")
+ expect(text).toContain("> second")
+ })
+
+ test("falls back to url when title is missing", async () => {
+ const exit = await runCall({ query: "x" }, () => okJson({ results: [{ url: "https://example.com/no-title" }] }))
+ expect(okValue(exit)).toContain("[1] https://example.com/no-title")
+ })
+
+ test("returns NO_RESULTS message on empty results", async () => {
+ const exit = await runCall({ query: "x" }, () => okJson({ results: [] }))
+ expect(okValue(exit)).toBe("No search results found. Please try a different query.")
+ })
+
+ test("ignores costDollars on the response (cost accounting out of scope)", async () => {
+ const exit = await runCall({ query: "x" }, () =>
+ okJson({
+ results: [{ url: "https://example.com" }],
+ costDollars: { total: 0.007, search: { neural: 0.007 } },
+ requestId: "req-123",
+ }),
+ )
+ expect(Exit.isSuccess(exit)).toBe(true)
+ })
+})
+
+describe("callKiloExa error handling", () => {
+ test("dies with auth-required message on 401", async () => {
+ const exit = await runCall({ query: "x" }, () => jsonResponse(401, {}))
+ expect(Exit.isFailure(exit)).toBe(true)
+ if (Exit.isSuccess(exit)) return
+ expect(String((exit as Extract).cause)).toContain("unauthorized")
+ expect(String((exit as Extract).cause)).toContain("kilo auth login")
+ })
+
+ test("dies with auth-required message on 403", async () => {
+ const exit = await runCall({ query: "x" }, () => jsonResponse(403, {}))
+ expect(Exit.isFailure(exit)).toBe(true)
+ if (Exit.isSuccess(exit)) return
+ expect(String((exit as Extract).cause)).toContain("unauthorized")
+ })
+
+ test("dies with status code on other non-2xx", async () => {
+ const exit = await runCall({ query: "x" }, () => jsonResponse(500, { error: "boom" }))
+ expect(Exit.isFailure(exit)).toBe(true)
+ if (Exit.isSuccess(exit)) return
+ expect(String((exit as Extract).cause)).toContain("500")
+ })
+
+ test("dies when response body is not valid ExaResponse shape", async () => {
+ const exit = await runCall({ query: "x" }, () => okJson({ nope: true }))
+ expect(Exit.isFailure(exit)).toBe(true)
+ })
+})
diff --git a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap
index f4951dfa51..368225175b 100644
--- a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap
+++ b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap
@@ -462,7 +462,7 @@ exports[`tool parameters JSON Schema (wire shape) websearch 1`] = `
"type": "string",
},
"numResults": {
- "description": "Number of search results to return (default: 8)",
+ "description": "Number of search results to return (default: 8, maximum: 10)",
"type": "number",
},
"query": {
From 0a1c14073a4bf14f8ad4e3c8295dc6ae6bfbfdaf Mon Sep 17 00:00:00 2001
From: Marius
Date: Wed, 29 Jul 2026 10:30:15 +0200
Subject: [PATCH 014/100] fix(agent-manager): keep terminal destination
consistent across windows (#12629)
---
...anager-terminal-destination-consistency.md | 5 +
packages/kilo-vscode/package.json | 2 +-
.../src/agent-manager/AgentManagerProvider.ts | 11 +++
.../agent-manager/SessionTerminalManager.ts | 21 ++++
.../__tests__/AgentManagerProvider.spec.ts | 15 +++
.../kilo-vscode/src/agent-manager/types.ts | 6 ++
.../tests/unit/agent-manager-arch.test.ts | 1 +
.../unit/agent-manager-terminal-side.test.ts | 99 ++++++++++++++++++-
.../unit/session-terminal-manager.test.ts | 61 ++++++++++++
.../agent-manager/AgentManagerApp.tsx | 20 ++--
.../agent-manager/terminal/index.ts | 2 +-
.../webview-ui/agent-manager/terminal/side.ts | 72 +++++++++++++-
.../src/types/messages/webview-messages.ts | 7 ++
13 files changed, 306 insertions(+), 16 deletions(-)
create mode 100644 .changeset/agent-manager-terminal-destination-consistency.md
diff --git a/.changeset/agent-manager-terminal-destination-consistency.md b/.changeset/agent-manager-terminal-destination-consistency.md
new file mode 100644
index 0000000000..1bd4453d5b
--- /dev/null
+++ b/.changeset/agent-manager-terminal-destination-consistency.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": patch
+---
+
+Keep each Agent Manager panel's terminal destination consistent. A dropdown pick is now remembered per panel and no longer flips when another window rewrites the shared terminal destination setting, so the terminal shortcut keeps opening the terminal type that panel is actually using. The shortcut also no longer dead-ends on worktrees without an active session, and terminals left over from a reloaded webview are cleaned up instead of leaking.
diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json
index 45d6fbeb52..e6fa5101c1 100644
--- a/packages/kilo-vscode/package.json
+++ b/packages/kilo-vscode/package.json
@@ -1028,7 +1028,7 @@
"Open or focus the VS Code integrated terminal.",
"Open or focus an embedded terminal in the Agent Manager side panel."
],
- "description": "Choose where the Agent Manager terminal button and Focus Terminal keyboard shortcut open a terminal."
+ "description": "Default destination for the Agent Manager terminal button and Focus Terminal keyboard shortcut. The terminal button's dropdown remembers its own choice per Agent Manager panel; this setting only applies to panels that never picked one."
},
"kilo-code.new.indexing.showButtonWhenDisabled": {
"type": "boolean",
diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
index bf72af74ab..e92438bd52 100644
--- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
+++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
@@ -593,6 +593,10 @@ export class AgentManagerProvider implements Disposable {
this.terminalManager.showLocalTerminal()
return null
}
+ if (m.type === "agentManager.showWorktreeTerminal") {
+ this.terminalManager.showWorktreeTerminal(m.worktreeId, this.state)
+ return null
+ }
if (m.type === "agentManager.openWorktree") {
this.openWorktreeDirectory(m.worktreeId)
return null
@@ -720,6 +724,13 @@ export class AgentManagerProvider implements Disposable {
}
private onRequestState(): void {
+ // requestState fires from the webview's onMount, and a freshly mounted
+ // webview has no terminal records — any PTYs the router still tracks
+ // belong to a previous webview instance (reload or crash) and are
+ // unreachable orphans. Kill them here rather than leaking shells until
+ // the panel itself is disposed. In-flight creates from the dying
+ // instance are reaped by the router's generation guard.
+ void this.terminalRouter.dispose()
void this.stateReady
?.then(() => {
// When the folder is not a git repo (or has no folder open),
diff --git a/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts b/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts
index 6120ba6a1c..020880244d 100644
--- a/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts
+++ b/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts
@@ -122,6 +122,27 @@ export class SessionTerminalManager {
this.showOrCreate(SessionTerminalManager.LOCAL_KEY, cwd, "Agent: local")
}
+ /**
+ * Show (or create) a terminal rooted at a worktree directory. Used when
+ * the worktree has no session to key the terminal off (e.g. all of its
+ * sessions were closed) so the shortcut never dead-ends on a sessionless
+ * worktree.
+ */
+ showWorktreeTerminal(worktreeId: string, state: WorktreeStateManager | undefined): void {
+ const key = `worktree:${worktreeId}`
+ if (this.showExisting(key, false)) return
+
+ const worktree = state?.getWorktree(worktreeId)
+ const cwd = worktree?.path ?? this.host.repoPath()
+ if (!cwd) {
+ this.log(`showWorktreeTerminal: no cwd resolved for worktree ${worktreeId}`)
+ this.host.showWarning("Open a folder that contains a git repository to use worktrees")
+ return
+ }
+
+ this.showOrCreate(key, cwd, worktree ? `Agent: ${worktree.branch}` : "Agent: worktree")
+ }
+
/**
* Show the existing local terminal if one was previously created (used on context switch).
*/
diff --git a/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts b/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts
index 045a108faf..7766476185 100644
--- a/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts
+++ b/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts
@@ -39,6 +39,7 @@ vi.mock("../SessionTerminalManager", () => ({
SessionTerminalManager: class {
showTerminal() {}
showLocalTerminal() {}
+ showWorktreeTerminal() {}
syncLocalOnSessionSwitch() {}
syncOnSessionSwitch() {
return false
@@ -216,6 +217,20 @@ describe("AgentManagerProvider worktree creation", () => {
expect(manager.createWorktreeOnDisk).toHaveBeenCalledTimes(1)
})
+ it("disposes orphaned terminals when a freshly mounted webview requests state", async () => {
+ const manager = createHarness()
+ const dispose = vi.fn().mockResolvedValue(undefined)
+ manager.terminalRouter = { handle: vi.fn().mockReturnValue(false), dispose } as unknown as {
+ handle: ReturnType
+ }
+ // Avoid the vscode-backed pushEmptyState; the disposal under test is synchronous.
+ ;(manager as unknown as Record).pushEmptyState = vi.fn()
+
+ await manager.onMessage({ type: "agentManager.requestState" })
+
+ expect(dispose).toHaveBeenCalledTimes(1)
+ })
+
it("routes file search through the active worktree session", async () => {
const manager = createHarness()
manager.activeSessionId = "session-wt"
diff --git a/packages/kilo-vscode/src/agent-manager/types.ts b/packages/kilo-vscode/src/agent-manager/types.ts
index 8950c68d22..d386e36acc 100644
--- a/packages/kilo-vscode/src/agent-manager/types.ts
+++ b/packages/kilo-vscode/src/agent-manager/types.ts
@@ -414,6 +414,11 @@ interface ShowLocalTerminalIn {
type: "agentManager.showLocalTerminal"
}
+interface ShowWorktreeTerminalIn {
+ type: "agentManager.showWorktreeTerminal"
+ worktreeId: string
+}
+
interface OpenWorktreeIn {
type: "agentManager.openWorktree"
worktreeId: string
@@ -780,6 +785,7 @@ export type AgentManagerInMessage =
| StopRunScriptIn
| ShowTerminalIn
| ShowLocalTerminalIn
+ | ShowWorktreeTerminalIn
| OpenWorktreeIn
| CopyToClipboardIn
| ShowExistingLocalTerminalIn
diff --git a/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts
index 804471f9bb..afcbae2f3d 100644
--- a/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts
+++ b/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts
@@ -411,6 +411,7 @@ describe("Agent Manager Provider — onMessage routing", () => {
"agentManager.stopRunScript",
"agentManager.showTerminal",
"agentManager.showLocalTerminal",
+ "agentManager.showWorktreeTerminal",
"agentManager.showExistingLocalTerminal",
"agentManager.requestRepoInfo",
"agentManager.requestState",
diff --git a/packages/kilo-vscode/tests/unit/agent-manager-terminal-side.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-terminal-side.test.ts
index 199d3adca2..831e2c187b 100644
--- a/packages/kilo-vscode/tests/unit/agent-manager-terminal-side.test.ts
+++ b/packages/kilo-vscode/tests/unit/agent-manager-terminal-side.test.ts
@@ -1,13 +1,25 @@
import { describe, expect, it } from "bun:test"
-import { createSideTerminal } from "../../webview-ui/agent-manager/terminal/side"
+import {
+ createSideTerminal,
+ readSavedDestination,
+ resolveVscodeTerminalRequest,
+} from "../../webview-ui/agent-manager/terminal/side"
-function scene(opts: { destination?: "vscode" | "agentManager"; visible?: boolean; focused?: boolean } = {}) {
+function scene(
+ opts: {
+ destination?: "vscode" | "agentManager"
+ saved?: "vscode" | "agentManager"
+ visible?: boolean
+ focused?: boolean
+ } = {},
+) {
const calls = {
requestSide: 0,
closeSide: 0,
hide: 0,
refocus: 0,
openVscode: 0,
+ persisted: [] as string[],
posted: [] as Array>,
tracked: [] as string[],
}
@@ -35,8 +47,10 @@ function scene(opts: { destination?: "vscode" | "agentManager"; visible?: boolea
postMessage: (msg) => calls.posted.push(msg as Record),
track: (button) => calls.tracked.push(button),
openVscode: () => calls.openVscode++,
+ saved: opts.saved,
+ save: (destination) => calls.persisted.push(destination),
})
- if (opts.destination) ctl.setDestination(opts.destination)
+ if (opts.destination) ctl.syncDefault(opts.destination)
return { ctl, calls }
}
@@ -88,5 +102,84 @@ describe("Agent Manager side terminal controller", () => {
expect(item.calls.posted).toEqual([
{ type: "updateSetting", key: "agentManager.terminalButtonDestination", value: "agentManager" },
])
+ expect(item.calls.persisted).toEqual(["agentManager"])
+ })
+
+ it("follows the remote default while the panel has no explicit choice", () => {
+ const item = scene()
+ item.ctl.syncDefault("agentManager")
+ expect(item.ctl.destination()).toBe("agentManager")
+ item.ctl.syncDefault("vscode")
+ expect(item.ctl.destination()).toBe("vscode")
+ })
+
+ it("keeps the panel's explicit choice when another window rewrites the shared setting", () => {
+ const item = scene()
+ item.ctl.choose("agentManager")
+ // Echo of the application-scoped setting being rewritten elsewhere:
+ // worktree window B picked the VS Code terminal, which must not flip
+ // this panel's routing.
+ item.ctl.syncDefault("vscode")
+ expect(item.ctl.destination()).toBe("agentManager")
+ item.ctl.openPreferred("keyboard_shortcut")
+ expect(item.calls.requestSide).toBe(1)
+ expect(item.calls.openVscode).toBe(0)
+ })
+
+ it("restores a saved panel choice and ignores remote defaults", () => {
+ const item = scene({ saved: "agentManager" })
+ expect(item.ctl.destination()).toBe("agentManager")
+ item.ctl.syncDefault("vscode")
+ expect(item.ctl.destination()).toBe("agentManager")
+ })
+})
+
+describe("readSavedDestination", () => {
+ it("reads a valid choice and rejects anything else", () => {
+ expect(readSavedDestination({ terminalDestination: "agentManager" })).toBe("agentManager")
+ expect(readSavedDestination({ terminalDestination: "vscode" })).toBe("vscode")
+ expect(readSavedDestination({ terminalDestination: "bogus" })).toBeUndefined()
+ expect(readSavedDestination({})).toBeUndefined()
+ expect(readSavedDestination(undefined)).toBeUndefined()
+ })
+})
+
+describe("resolveVscodeTerminalRequest", () => {
+ const sessions = new Map([
+ ["wt-1", "session-a"],
+ ["wt-2", "session-b"],
+ ])
+ const forWorktree = (id: string) => sessions.get(id)
+
+ it("prefers the current session", () => {
+ expect(resolveVscodeTerminalRequest("wt-1", "session-current", forWorktree)).toEqual({
+ type: "agentManager.showTerminal",
+ sessionId: "session-current",
+ })
+ })
+
+ it("falls back to a session of the selected worktree when the current session is cleared", () => {
+ // Terminal tab activation clears the current session; the shortcut
+ // must still open a terminal for the worktree, not dead-end.
+ expect(resolveVscodeTerminalRequest("wt-2", undefined, forWorktree)).toEqual({
+ type: "agentManager.showTerminal",
+ sessionId: "session-b",
+ })
+ })
+
+ it("opens a worktree-rooted terminal for sessionless worktrees", () => {
+ expect(resolveVscodeTerminalRequest("wt-3", undefined, forWorktree)).toEqual({
+ type: "agentManager.showWorktreeTerminal",
+ worktreeId: "wt-3",
+ })
+ })
+
+ it("opens the local terminal for the local context and unassigned selections", () => {
+ expect(resolveVscodeTerminalRequest("local", undefined, forWorktree)).toEqual({
+ type: "agentManager.showLocalTerminal",
+ })
+ expect(resolveVscodeTerminalRequest(null, undefined, forWorktree)).toEqual({
+ type: "agentManager.showLocalTerminal",
+ })
})
})
diff --git a/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts b/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts
index 4e763196bf..8dc6e7d79c 100644
--- a/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts
+++ b/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts
@@ -9,6 +9,7 @@ import { describe, it, expect } from "bun:test"
import path from "node:path"
import { Project, SyntaxKind } from "ts-morph"
import { SessionTerminalManager, type TerminalHost } from "../../src/agent-manager/SessionTerminalManager"
+import type { WorktreeStateManager } from "../../src/agent-manager/WorktreeStateManager"
const ROOT = path.resolve(import.meta.dir, "../..")
const FILE = path.join(ROOT, "src/agent-manager/SessionTerminalManager.ts")
@@ -162,3 +163,63 @@ describe("SessionTerminalManager command restoration", () => {
state.manager.dispose()
})
})
+
+describe("SessionTerminalManager worktree terminals", () => {
+ function scene(opts: { worktreePath?: string; repoPath?: string } = {}) {
+ const created: Array<{ cwd: string; name: string }> = []
+ const warnings: string[] = []
+ let shown = 0
+ const host: TerminalHost = {
+ createTerminal(o) {
+ created.push(o)
+ return {
+ show: () => shown++,
+ dispose() {},
+ exitStatus: undefined,
+ }
+ },
+ activeTerminal: () => undefined,
+ repoPath: () => opts.repoPath,
+ showWarning: (msg) => warnings.push(msg),
+ setContext() {},
+ onTerminalClosed: () => ({ dispose() {} }),
+ onActiveTerminalChanged: () => ({ dispose() {} }),
+ registerCommand: () => ({ dispose() {} }),
+ executeCommand: () => Promise.resolve(),
+ }
+ const state = {
+ getWorktree: (id: string) =>
+ opts.worktreePath ? { id, path: opts.worktreePath, branch: "feature/x" } : undefined,
+ } as unknown as WorktreeStateManager
+ const manager = new SessionTerminalManager(() => {}, host)
+ return { manager, state, created, warnings, shown: () => shown }
+ }
+
+ it("creates a terminal rooted at the worktree path", () => {
+ const s = scene({ worktreePath: "/repo/.kilo/worktrees/wt-1", repoPath: "/repo" })
+ s.manager.showWorktreeTerminal("wt-1", s.state)
+ expect(s.created).toEqual([{ cwd: "/repo/.kilo/worktrees/wt-1", name: "Agent: feature/x" }])
+ expect(s.shown()).toBe(1)
+ })
+
+ it("reuses the live terminal on repeat calls", () => {
+ const s = scene({ worktreePath: "/repo/.kilo/worktrees/wt-1" })
+ s.manager.showWorktreeTerminal("wt-1", s.state)
+ s.manager.showWorktreeTerminal("wt-1", s.state)
+ expect(s.created).toHaveLength(1)
+ expect(s.shown()).toBe(2)
+ })
+
+ it("falls back to the repo root when the worktree is unknown", () => {
+ const s = scene({ repoPath: "/repo" })
+ s.manager.showWorktreeTerminal("gone", s.state)
+ expect(s.created).toEqual([{ cwd: "/repo", name: "Agent: worktree" }])
+ })
+
+ it("warns and creates nothing when no cwd resolves", () => {
+ const s = scene({})
+ s.manager.showWorktreeTerminal("gone", s.state)
+ expect(s.created).toHaveLength(0)
+ expect(s.warnings).toHaveLength(1)
+ })
+})
diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
index ce6f795941..ff783f0495 100644
--- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
+++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
@@ -126,6 +126,8 @@ import {
createTerminalHandlers,
createTerminalMessageHandler,
createSideTerminal,
+ readSavedDestination,
+ resolveVscodeTerminalRequest,
} from "./terminal"
import { focusCurrentTab, renderTab, renderTerminalLayer, renderNewTabButton } from "./tab-rendering"
import { useTabScroll } from "./tab-scroll"
@@ -1283,7 +1285,7 @@ const AgentManagerContent: Component = () => {
// a slow create landing after a mode switch must not steal it.
if (sidePanel() === "terminal" && terms.sideKey() === contextKey) terms.requestFocus(terminalId)
},
- onDestinationChanged: (destination) => sideCtl.setDestination(destination),
+ onDestinationChanged: (destination) => sideCtl.syncDefault(destination),
})
const unsubTerminals = vscode.onMessage((msg) => {
terminalDispatch(msg)
@@ -2108,11 +2110,17 @@ const AgentManagerContent: Component = () => {
refocus: () => window.dispatchEvent(new Event("focusPrompt")),
postMessage: (msg) => vscode.postMessage(msg as never),
track: (button, surface, properties) => metrics.track(button, surface, properties),
- openVscode: () => {
- const id = session.currentSessionID()
- if (id) vscode.postMessage({ type: "agentManager.showTerminal", sessionId: id })
- else if (selection() === LOCAL) vscode.postMessage({ type: "agentManager.showLocalTerminal" })
- },
+ // Panel-local pick, immune to cross-window setting echoes (see side.ts).
+ saved: readSavedDestination(vscode.getState>()),
+ save: (d) => vscode.setState({ ...vscode.getState>(), terminalDestination: d }),
+ openVscode: () =>
+ vscode.postMessage(
+ resolveVscodeTerminalRequest(
+ selection(),
+ session.currentSessionID(),
+ (wt) => managedSessions().find((ms) => ms.worktreeId === wt)?.id,
+ ) as never,
+ ),
})
const handleReviewTabMouseDown = (e: MouseEvent) => {
diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/index.ts b/packages/kilo-vscode/webview-ui/agent-manager/terminal/index.ts
index 6bac7cab9b..2d76c0f1a5 100644
--- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/index.ts
+++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/index.ts
@@ -23,6 +23,6 @@ export type { TerminalTabState, TerminalStateControls, TerminalHandlerDeps } fro
export { renderTerminalTab, renderTerminalLayer, renderSideTerminalLayer } from "./render"
export { SideTerminalPanel } from "./SideTerminalPanel"
export { TerminalDestinationButton } from "./TerminalDestinationButton"
-export { createSideTerminal } from "./side"
+export { createSideTerminal, readSavedDestination, resolveVscodeTerminalRequest } from "./side"
export { TerminalTab } from "./TerminalTab"
export { SortableTerminalTab } from "./SortableTerminalTab"
diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/side.ts b/packages/kilo-vscode/webview-ui/agent-manager/terminal/side.ts
index 3c7fe39145..cf1c3587cf 100644
--- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/side.ts
+++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/side.ts
@@ -7,11 +7,52 @@
* embedded terminal behaves like the diff panel: press once to reveal,
* press again to hide. Hiding never kills the terminal — only the
* explicit close action (or `Cmd+W` while it holds focus) does.
+ *
+ * ## Destination state ownership
+ *
+ * The VS Code setting is application-scoped, so one value is shared by
+ * every window and echoed back via `terminal.destinationChanged`
+ * whenever ANY window rewrites it. Two windows can therefore fight:
+ * picking "VS Code terminal" in worktree window B would silently flip
+ * the routing of the panel in window A. To keep each panel consistent,
+ * an explicit dropdown pick is stored per panel (webview state) and
+ * wins over remote echoes; the setting only drives panels that never
+ * picked a destination themselves (it stays the default for new ones).
*/
import { createSignal } from "solid-js"
import type { Accessor } from "solid-js"
import type { TerminalDestination } from "../../src/types/messages/agent-manager"
+import { LOCAL } from "../navigate"
+
+/** Read the panel-local destination choice from raw webview state. */
+export function readSavedDestination(state: Record | undefined): TerminalDestination | undefined {
+ const value = state?.terminalDestination
+ return value === "agentManager" || value === "vscode" ? value : undefined
+}
+
+export type VscodeTerminalRequest =
+ | { type: "agentManager.showTerminal"; sessionId: string }
+ | { type: "agentManager.showWorktreeTerminal"; worktreeId: string }
+ | { type: "agentManager.showLocalTerminal" }
+
+/**
+ * Pick the message the terminal button / Focus Terminal shortcut sends
+ * when the destination is the VS Code integrated terminal. The fallback
+ * chain exists so the shortcut never dead-ends: activating a terminal
+ * tab clears the current session, and a worktree may have no sessions
+ * at all. Extracted from AgentManagerApp.tsx (max-lines cap).
+ */
+export function resolveVscodeTerminalRequest(
+ selection: string | null,
+ currentSessionID: string | undefined,
+ sessionForWorktree: (worktreeId: string) => string | undefined,
+): VscodeTerminalRequest {
+ const id = currentSessionID ?? (selection && selection !== LOCAL ? sessionForWorktree(selection) : undefined)
+ if (id) return { type: "agentManager.showTerminal", sessionId: id }
+ if (selection && selection !== LOCAL) return { type: "agentManager.showWorktreeTerminal", worktreeId: selection }
+ return { type: "agentManager.showLocalTerminal" }
+}
interface Handlers {
requestSide(): void
@@ -32,10 +73,16 @@ export interface SideTerminalDeps {
track: (button: string, surface: string, properties: Record) => void
/** Open or focus the VS Code integrated terminal for the active context. */
openVscode: () => void
+ /** Panel-local choice restored from webview state, if the user ever
+ * picked one in this panel. */
+ saved: TerminalDestination | undefined
+ /** Persist the panel-local choice so it survives webview reloads. */
+ save: (destination: TerminalDestination) => void
}
export function createSideTerminal(deps: SideTerminalDeps) {
- const [destination, setDestination] = createSignal("vscode")
+ const [local, setLocal] = createSignal(deps.saved)
+ const [destination, setDestination] = createSignal(deps.saved ?? "vscode")
/**
* Hiding while the terminal holds focus would strand the cursor on
@@ -78,17 +125,32 @@ export function createSideTerminal(deps: SideTerminalDeps) {
}
/**
- * Dropdown pick. Applied locally right away so the button reacts
- * without a round trip, then persisted as a VS Code setting; the
- * extension echoes it back via `terminal.destinationChanged`.
+ * Dropdown pick. The choice is panel-local and sticky: it is kept in
+ * webview state and beats later `terminal.destinationChanged` echoes
+ * caused by other windows rewriting the shared application-scoped
+ * setting. The setting is still written so it stays the default for
+ * panels that never picked a destination (and new panels).
* The key is relative to the `kilo-code.new` section, matching every
* other `updateSetting` sender.
*/
const choose = (target: TerminalDestination) => {
deps.track("terminal_destination", "tab_toolbar", { destination: target })
+ setLocal(target)
setDestination(target)
+ deps.save(target)
deps.postMessage({ type: "updateSetting", key: "agentManager.terminalButtonDestination", value: target })
}
- return { destination, setDestination, toggle, close, openPreferred, choose }
+ /**
+ * Apply a remote default (initial `agentManager.state` payload or a
+ * live `terminal.destinationChanged` echo). Ignored once the user
+ * picked a destination in this panel — their choice wins over every
+ * echo, including ones triggered by this panel's own `choose` write.
+ */
+ const syncDefault = (target: TerminalDestination) => {
+ if (local()) return
+ setDestination(target)
+ }
+
+ return { destination, syncDefault, toggle, close, openPreferred, choose }
}
diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
index 16fcfe59e5..f5dc4a2035 100644
--- a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
+++ b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
@@ -695,6 +695,12 @@ export interface ShowLocalTerminalRequest {
type: "agentManager.showLocalTerminal"
}
+// Show a terminal rooted at a worktree directory (worktree has no session)
+export interface ShowWorktreeTerminalRequest {
+ type: "agentManager.showWorktreeTerminal"
+ worktreeId: string
+}
+
// Open a worktree directory in VS Code
export interface OpenWorktreeRequest {
type: "agentManager.openWorktree"
@@ -1336,6 +1342,7 @@ export type WebviewMessage =
| StopRunScriptRequest
| ShowTerminalRequest
| ShowLocalTerminalRequest
+ | ShowWorktreeTerminalRequest
| OpenWorktreeRequest
| CopyToClipboardRequest
| ShowExistingLocalTerminalRequest
From a7f972f63bc948d70b73a36a5beab6d694316037 Mon Sep 17 00:00:00 2001
From: Marius
Date: Wed, 29 Jul 2026 10:31:22 +0200
Subject: [PATCH 015/100] fix(vscode): speed up embedded terminal startup and
fix cold-connection race (#12630)
Replay retained PTY startup bytes from cursor 0 on initial xterm
attachment so shells receive capability queries emitted before the
WebSocket connected. Fish previously waited ~2s for a terminal
capability response that xterm never saw, then displayed the prompt.
Local terminal creation no longer waits for unrelated Agent Manager
worktree recovery, and now joins the shared backend connection via
getClientAsync instead of racing the synchronous getClient accessor,
which could fail with 'Not connected' during cold kilo serve startup.
Worktree terminals still gate on state recovery since they need the
recovered worktree path.
---
.changeset/fast-agent-manager-terminals.md | 5 +++
.../src/agent-manager/AgentManagerProvider.ts | 4 +-
.../src/agent-manager/terminal-routing.ts | 10 ++++-
.../unit/agent-manager-terminal-font.test.ts | 2 +
.../agent-manager-terminal-routing.test.ts | 44 +++++++++++++++++++
5 files changed, 63 insertions(+), 2 deletions(-)
create mode 100644 .changeset/fast-agent-manager-terminals.md
diff --git a/.changeset/fast-agent-manager-terminals.md b/.changeset/fast-agent-manager-terminals.md
new file mode 100644
index 0000000000..6beace30f4
--- /dev/null
+++ b/.changeset/fast-agent-manager-terminals.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": patch
+---
+
+Open Agent Manager terminals faster and avoid delayed shell prompts.
diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
index e92438bd52..e8e668b4b5 100644
--- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
+++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
@@ -103,6 +103,7 @@ export class AgentManagerProvider implements Disposable {
)
this.terminalRouter = new TerminalRouter({
getClient: () => this.connectionService.getClient(),
+ getClientAsync: () => this.connectionService.getClientAsync(this.getRoot()),
getServerConfig: () => this.connectionService.getServerConfig() ?? undefined,
getRoot: () => this.getRoot(),
getWorktreePath: (id) => this.getStateManager()?.getWorktree(id)?.path,
@@ -917,8 +918,9 @@ export class AgentManagerProvider implements Disposable {
case "agentManager.toggleSectionCollapsed":
case "agentManager.moveToSection":
case "agentManager.moveSection":
- case "agentManager.terminal.create":
return true
+ case "agentManager.terminal.create":
+ return m.worktreeId !== null
default:
return false
}
diff --git a/packages/kilo-vscode/src/agent-manager/terminal-routing.ts b/packages/kilo-vscode/src/agent-manager/terminal-routing.ts
index 566952f9b2..3fef7352ed 100644
--- a/packages/kilo-vscode/src/agent-manager/terminal-routing.ts
+++ b/packages/kilo-vscode/src/agent-manager/terminal-routing.ts
@@ -26,6 +26,8 @@ interface ServerConfig {
export interface TerminalRoutingDeps {
/** Shared SDK client. Throws when the CLI backend is not connected. */
getClient(): KiloClient
+ /** Shared SDK client, connecting the CLI backend when needed. */
+ getClientAsync(): Promise
/** Loopback URL + basic-auth password for the running `kilo serve`. */
getServerConfig(): ServerConfig | undefined
/** Workspace root — used as cwd fallback when no worktree is selected (LOCAL). */
@@ -119,6 +121,9 @@ export class TerminalRouter {
}
const title = `Terminal ${this.nextOrdinal(worktreeId)}`
try {
+ // Join the shared backend connection instead of racing its synchronous
+ // client accessor when this is the first Kilo action in the window.
+ await this.deps.getClientAsync()
const created = await manager.create({ worktreeId, cwd, title })
if (generation !== this.generation) {
await manager.close(created.terminalId)
@@ -182,6 +187,9 @@ export class TerminalRouter {
const token = Buffer.from(`kilo:${config.password}`).toString("base64")
const dir = encodeURIComponent(cwd)
const auth = encodeURIComponent(token)
- return `${base}/pty/${encodeURIComponent(ptyID)}/connect?directory=${dir}&cursor=-1&auth_token=${auth}`
+ // A new terminal has one initial attachment. Replay its retained startup
+ // bytes so xterm can answer shell capability queries emitted before the
+ // WebSocket connected; tailing from -1 can make shells wait for a timeout.
+ return `${base}/pty/${encodeURIComponent(ptyID)}/connect?directory=${dir}&cursor=0&auth_token=${auth}`
}
}
diff --git a/packages/kilo-vscode/tests/unit/agent-manager-terminal-font.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-terminal-font.test.ts
index 64504d2600..02b7fffe27 100644
--- a/packages/kilo-vscode/tests/unit/agent-manager-terminal-font.test.ts
+++ b/packages/kilo-vscode/tests/unit/agent-manager-terminal-font.test.ts
@@ -53,6 +53,7 @@ describe("Agent Manager terminal font", () => {
const message = new Promise((resolve) => {
const router = new TerminalRouter({
getClient: () => client,
+ getClientAsync: async () => client,
getServerConfig: () => ({ baseUrl: "http://127.0.0.1:4096", password: "secret" }),
getRoot: () => "/workspace",
getWorktreePath: () => undefined,
@@ -77,6 +78,7 @@ describe("Agent Manager terminal font", () => {
expect(created.font).toEqual(font)
expect(created.worktreeId).toBeNull()
expect(created.wsUrl).toContain("/pty/pty-1/connect")
+ expect(created.wsUrl).toContain("cursor=0")
})
it("keeps the created font in terminal state", () => {
diff --git a/packages/kilo-vscode/tests/unit/agent-manager-terminal-routing.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-terminal-routing.test.ts
index bfa243d1fc..ffa58bd6db 100644
--- a/packages/kilo-vscode/tests/unit/agent-manager-terminal-routing.test.ts
+++ b/packages/kilo-vscode/tests/unit/agent-manager-terminal-routing.test.ts
@@ -21,6 +21,7 @@ describe("Agent Manager terminal routing", () => {
} as unknown as KiloClient
const router = new TerminalRouter({
getClient: () => client,
+ getClientAsync: async () => client,
getServerConfig: () => ({ baseUrl: "http://127.0.0.1:4096", password: "secret" }),
getRoot: () => "/workspace",
getWorktreePath: (id) => (id === "wt-1" ? "/workspace/wt-1" : undefined),
@@ -78,6 +79,7 @@ describe("Agent Manager terminal routing", () => {
} as unknown as KiloClient
const router = new TerminalRouter({
getClient: () => client,
+ getClientAsync: async () => client,
getServerConfig: () => ({ baseUrl: "http://127.0.0.1:4096", password: "secret" }),
getRoot: () => "/workspace",
getWorktreePath: () => undefined,
@@ -108,4 +110,46 @@ describe("Agent Manager terminal routing", () => {
await router.dispose()
expect(removed).toContain("pty-new")
})
+
+ it("awaits the shared backend connection before creating a terminal", async () => {
+ let connected = false
+ const client = {
+ pty: {
+ create: async () => ({ data: { id: "pty-1", title: "Terminal 1" } }),
+ remove: async () => ({ data: true }),
+ update: async () => ({ data: true }),
+ },
+ } as unknown as KiloClient
+ const router = new TerminalRouter({
+ getClient: () => {
+ if (!connected) throw new Error("Not connected")
+ return client
+ },
+ getClientAsync: async () => {
+ await wait()
+ connected = true
+ return client
+ },
+ getServerConfig: () => ({ baseUrl: "http://127.0.0.1:4096", password: "secret" }),
+ getRoot: () => "/workspace",
+ getWorktreePath: () => undefined,
+ log: () => undefined,
+ post: (message) => messages.push(message),
+ getTerminalFont: () => font,
+ })
+
+ const messages: AgentManagerOutMessage[] = []
+ router.handle({
+ type: "agentManager.terminal.create",
+ createId: "real",
+ placement: "tab",
+ worktreeId: null,
+ })
+ expect(messages).toHaveLength(0)
+ await wait()
+ await wait()
+
+ expect(messages[0]).toMatchObject({ type: "agentManager.terminal.created", createId: "real" })
+ await router.dispose()
+ })
})
From 3321216c0157e1a8a1829b0c8e0a1cae8d2f2ad2 Mon Sep 17 00:00:00 2001
From: Marius
Date: Wed, 29 Jul 2026 10:31:40 +0200
Subject: [PATCH 016/100] feat(agent-manager): reveal jump shortcut badges
while modifier is held (#12631)
---
.../agent-manager-modifier-shortcut-peek.md | 5 +++++
.../agent-manager/AgentManagerApp.tsx | 19 ++++++++++++++++++-
.../agent-manager/agent-manager.css | 19 +++++++++++++++++++
3 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 .changeset/agent-manager-modifier-shortcut-peek.md
diff --git a/.changeset/agent-manager-modifier-shortcut-peek.md b/.changeset/agent-manager-modifier-shortcut-peek.md
new file mode 100644
index 0000000000..96ee306f0c
--- /dev/null
+++ b/.changeset/agent-manager-modifier-shortcut-peek.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": minor
+---
+
+Show the ⌘1-9 (Ctrl+1-9 on Windows/Linux) shortcut badges on every Agent Manager sidebar card while the modifier key is held, making it easy to see which number jumps to which worktree before pressing it.
diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
index ff783f0495..44b7e57832 100644
--- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
+++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
@@ -243,6 +243,8 @@ const AgentManagerContent: Component = () => {
const [repoBranch, setRepoBranch] = createSignal()
const [busyWorktrees, setBusyWorktrees] = createSignal
+