mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
Merge branch 'main' into legend-bonnet
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@kilocode/cli": minor
|
||||
"@kilocode/sdk": minor
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Connect to a local Anaconda Desktop text-generation model server from the CLI or VS Code.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Support NVIDIA Parakeet TDT 0.6B v3 for speech-to-text input.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Color Agent Manager PR badges by pull request state (open, draft, merged, closed) and show CI and review status as a separate icon, so a failing check is no longer mistaken for a closed PR.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Add a sandbox toggle to the Agent Manager New Worktree modal so each worktree session can start sandboxed
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Gate experimental agents on their declared skill, MCP, and VS Code extension requirements. VS Code shows requirement groups with Marketplace shortcuts, and the CLI stops before sending when requirements are unmet.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Translate the Anaconda Desktop provider strings into all supported languages instead of falling back to English.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Animate tool-call and reasoning details when expanding and collapsing.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Open the model picker expanded by default, keep the preview pinned while hovering, separate Kilo Auto models into their own marked group with summary tooltips, and show backend-provided Auto Efficient model choices.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Explain Marketplace item types, installation scopes, destination files, and MCP security before installation.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show experimental sandbox controls by default for non-Windows users.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Filter marketplace items to those relevant to the current workspace's files and installed VS Code extensions.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Improve autocomplete error messages to clarify BYOK and credits issues
|
||||
|
||||
When autocomplete is paused due to a payment or auth error, the messages now explain all possible causes: no Kilo credits, API key (BYOK) quota exhausted, not signed in, or invalid/missing API key.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Allow the default TUI to import cloud-only sessions without rejecting their IDs as missing locally.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@kilocode/cli": minor
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Enforce the sandbox network restriction for agent commands on Linux, including TCP, UDP, IPv4, IPv6, and descendant processes.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/kilo-jetbrains": patch
|
||||
---
|
||||
|
||||
Improve JetBrains session error logs so nested CLI error messages are visible.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Preserve new-chat prompts, attachments, and scroll position when toggling sandbox, and keep sandbox status stable while switching sessions.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-gateway": patch
|
||||
"@kilocode/sdk": patch
|
||||
---
|
||||
|
||||
Expose Kilo Pass state on the Kilo profile API contract.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Notify when a marketplace item matches your workspace, with a one-click install button and a "Don't show again" option per suggestion.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Support safely reading, editing, and executing Jupyter notebook cells directly from Kilo in VS Code, including absolute workspace paths and content-based edit conflict detection.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Let the notebook tools create a new empty notebook.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show sandbox state changes as concise VS Code notifications.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Open the model selector instantly, even with large model catalogs.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/sdk": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Remember sandbox choices per session and start new sessions with the last selected sandbox state.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Support resetting read notifications from the VS Code extension settings.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Prevent confined sessions and delegated agents from weakening their sandbox policy through configuration changes or unauthenticated server control.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show full external directory paths in permission auto-approve rules.
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/sdk": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show the concrete model reported for routed Kilo auto-model steps in CLI and VS Code session timelines.
|
||||
Show the concrete model reported for routed Kilo auto-model steps in CLI and VS Code session timelines, and break down TUI sidebar token usage, cache rate, and cost by model across subagent sessions.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Show filesystem and network restriction states in the sandbox tooltip.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
Sort slash-command dropdown results by relevance. Exact matches now appear first, followed by prefix matches, then substring matches.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Toggle the current session sandbox with `/sandbox` in the sidebar and Agent Manager.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Stop shipping the local-only `.cli-version` build marker in packaged VSIX installs, which previously made production installs detect as local builds and inject a dev-only bwrap fallback.
|
||||
+6
-1
@@ -10,15 +10,20 @@ packages/kilo-ui/tests/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
packages/kilo-vscode/tests/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
packages/kilo-docs/public/img/screenshot-tests/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Hide non-English localization files by default in GitHub PR diffs.
|
||||
# Hide most localization files by default in GitHub PR diffs. Show English as the source
|
||||
# language and German so reviewers can catch untranslated copy-pasted English strings.
|
||||
**/i18n/*.ts linguist-generated=true
|
||||
**/i18n/en.ts linguist-generated=false
|
||||
**/i18n/en*.ts linguist-generated=false
|
||||
**/i18n/de.ts linguist-generated=false
|
||||
**/i18n/de*.ts linguist-generated=false
|
||||
**/i18n/package-nls-en.ts linguist-generated=false
|
||||
**/i18n/package-nls-de.ts linguist-generated=false
|
||||
**/i18n/index.ts linguist-generated=false
|
||||
**/i18n/parity.test.ts linguist-generated=false
|
||||
packages/kilo-i18n/src/*.ts linguist-generated=true
|
||||
packages/kilo-i18n/src/en.ts linguist-generated=false
|
||||
packages/kilo-i18n/src/de.ts linguist-generated=false
|
||||
|
||||
# Auto-generated CLI reference docs
|
||||
packages/kilo-docs/markdoc/partials/cli-commands-table.md linguist-generated=true
|
||||
|
||||
@@ -33,6 +33,7 @@ jobs:
|
||||
filters: |
|
||||
jetbrains:
|
||||
- '**'
|
||||
- '!.changeset/**'
|
||||
- '!packages/kilo-vscode/**'
|
||||
- '!packages/kilo-docs/**'
|
||||
|
||||
|
||||
+59
-13
@@ -22,31 +22,73 @@ env:
|
||||
|
||||
jobs:
|
||||
# kilocode_change start
|
||||
changes:
|
||||
name: detect general unit test changes
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
settings: ${{ steps.matrix.outputs.settings }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Detect general unit test changes
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
id: filter
|
||||
uses: Kilo-Org/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # v3
|
||||
with:
|
||||
predicate-quantifier: every
|
||||
filters: |
|
||||
general:
|
||||
- '**'
|
||||
- '!.changeset/**'
|
||||
- '!packages/kilo-jetbrains/**'
|
||||
- '!packages/kilo-vscode/**'
|
||||
- '!packages/kilo-docs/**'
|
||||
- '!packages/extensions/zed/**'
|
||||
- '!specs/**'
|
||||
- '!perf/**'
|
||||
|
||||
- name: Configure unit matrix
|
||||
id: matrix
|
||||
env:
|
||||
GENERAL: ${{ github.event_name != 'pull_request' || steps.filter.outputs.general == 'true' }}
|
||||
run: |
|
||||
if [ "$GENERAL" = "true" ]; then
|
||||
echo 'settings=[{"name":"linux","host":"blacksmith-4vcpu-ubuntu-2404","run":true},{"name":"macos","host":"macos-15","run":true},{"name":"windows","host":"blacksmith-4vcpu-windows-2025","run":true}]' >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo 'settings=[{"name":"linux","host":"blacksmith-4vcpu-ubuntu-2404","run":false}]' >> "$GITHUB_OUTPUT"
|
||||
|
||||
unit:
|
||||
name: unit (${{ matrix.settings.name }})
|
||||
needs: changes
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- name: linux
|
||||
host: blacksmith-4vcpu-ubuntu-2404 # kilocode_change
|
||||
- name: macos
|
||||
host: macos-15 # kilocode_change
|
||||
- name: windows
|
||||
host: blacksmith-4vcpu-windows-2025 # kilocode_change
|
||||
settings: ${{ fromJSON(needs.changes.outputs.settings) }}
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
timeout-minutes: 45 # kilocode_change
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Skip unchanged general unit tests
|
||||
if: ${{ !matrix.settings.run }}
|
||||
run: echo "Only isolated product, documentation, or metadata files changed; general unit tests are unchanged."
|
||||
|
||||
- name: Checkout repository
|
||||
if: matrix.settings.run
|
||||
uses: actions/checkout@v6 # kilocode_change
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# kilocode_change start
|
||||
- name: Setup Node
|
||||
if: matrix.settings.run
|
||||
id: setup-node
|
||||
continue-on-error: ${{ runner.os == 'Windows' }}
|
||||
uses: actions/setup-node@v6 # kilocode_change
|
||||
@@ -54,18 +96,19 @@ jobs:
|
||||
node-version: "24"
|
||||
|
||||
- name: Retry Setup Node on Windows
|
||||
if: runner.os == 'Windows' && steps.setup-node.outcome == 'failure'
|
||||
if: matrix.settings.run && runner.os == 'Windows' && steps.setup-node.outcome == 'failure'
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "24"
|
||||
# kilocode_change end
|
||||
|
||||
- name: Setup Bun
|
||||
if: matrix.settings.run
|
||||
uses: ./.github/actions/setup-bun
|
||||
|
||||
# kilocode_change start
|
||||
- name: Setup Zig for Linux sandbox helper
|
||||
if: runner.os == 'Linux'
|
||||
if: matrix.settings.run && runner.os == 'Linux'
|
||||
run: |
|
||||
curl --fail --location --retry 3 \
|
||||
https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz \
|
||||
@@ -75,17 +118,19 @@ jobs:
|
||||
echo "$RUNNER_TEMP/zig-linux-x86_64-0.14.0" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build Linux sandbox helper
|
||||
if: runner.os == 'Linux'
|
||||
if: matrix.settings.run && runner.os == 'Linux'
|
||||
run: |
|
||||
bun packages/opencode/script/kilocode/bubblewrap.ts --arch x64 --output "$RUNNER_TEMP/bwrap"
|
||||
echo "KILO_BWRAP_PATH=$RUNNER_TEMP/bwrap" >> "$GITHUB_ENV"
|
||||
# kilocode_change end
|
||||
- name: Configure git identity
|
||||
if: matrix.settings.run
|
||||
run: |
|
||||
git config --global user.email "kilo-maintainer[bot]@users.noreply.github.com"
|
||||
git config --global user.name "kilo-maintainer[bot]"
|
||||
|
||||
- name: Cache Turbo
|
||||
if: matrix.settings.run
|
||||
uses: actions/cache@v5 # kilocode_change
|
||||
with:
|
||||
path: node_modules/.cache/turbo
|
||||
@@ -95,6 +140,7 @@ jobs:
|
||||
turbo-${{ runner.os }}-
|
||||
|
||||
- name: Run unit tests
|
||||
if: matrix.settings.run
|
||||
run: bun turbo test:ci --filter='!@kilocode/kilo-jetbrains'
|
||||
env:
|
||||
KILO_EXPERIMENTAL_DISABLE_FILEWATCHER: ${{ runner.os == 'Windows' && 'true' || 'false' }}
|
||||
@@ -102,13 +148,13 @@ jobs:
|
||||
|
||||
# kilocode_change start
|
||||
- name: Run HttpApi exerciser gates
|
||||
if: runner.os == 'Linux'
|
||||
if: matrix.settings.run && runner.os == 'Linux'
|
||||
working-directory: packages/opencode
|
||||
run: bun run test:httpapi
|
||||
# kilocode_change end
|
||||
|
||||
- name: Publish unit reports # kilocode_change
|
||||
if: always()
|
||||
if: always() && matrix.settings.run
|
||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v6.4.0
|
||||
with:
|
||||
report_paths: packages/*/.artifacts/unit/junit.xml
|
||||
@@ -118,7 +164,7 @@ jobs:
|
||||
fail_on_failure: false
|
||||
|
||||
- name: Upload unit artifacts
|
||||
if: always()
|
||||
if: always() && matrix.settings.run
|
||||
uses: actions/upload-artifact@v7 # kilocode_change
|
||||
with:
|
||||
name: unit-${{ matrix.settings.name }}-${{ github.run_attempt }}
|
||||
|
||||
@@ -27,8 +27,33 @@ jobs:
|
||||
# kilocode_change end
|
||||
|
||||
# kilocode_change start
|
||||
jetbrains-changes:
|
||||
name: detect JetBrains changes
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
outputs:
|
||||
jetbrains: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.filter.outputs.jetbrains }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Detect JetBrains changes
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
id: filter
|
||||
uses: Kilo-Org/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # v3
|
||||
with:
|
||||
predicate-quantifier: every
|
||||
filters: |
|
||||
jetbrains:
|
||||
- '**'
|
||||
- '!.changeset/**'
|
||||
- '!packages/kilo-vscode/**'
|
||||
- '!packages/kilo-docs/**'
|
||||
|
||||
typecheck-jetbrains:
|
||||
name: typecheck-jetbrains
|
||||
needs: jetbrains-changes
|
||||
if: github.event_name == 'workflow_dispatch' || needs.jetbrains-changes.outputs.jetbrains == 'true'
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -57,13 +82,21 @@ jobs:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
needs:
|
||||
- typecheck-js
|
||||
- jetbrains-changes
|
||||
- typecheck-jetbrains
|
||||
if: always()
|
||||
steps:
|
||||
- name: Verify typecheck jobs passed
|
||||
run: |
|
||||
echo "typecheck-js=${{ needs.typecheck-js.result }}"
|
||||
echo "jetbrains-changes=${{ needs.jetbrains-changes.result }}"
|
||||
echo "typecheck-jetbrains=${{ needs.typecheck-jetbrains.result }}"
|
||||
test "${{ needs.typecheck-js.result }}" = "success"
|
||||
test "${{ needs.typecheck-jetbrains.result }}" = "success"
|
||||
test "${{ needs.jetbrains-changes.result }}" = "success"
|
||||
if [ "${{ needs.jetbrains-changes.outputs.jetbrains }}" = "true" ]; then
|
||||
test "${{ needs.typecheck-jetbrains.result }}" = "success"
|
||||
else
|
||||
test "${{ needs.jetbrains-changes.outputs.jetbrains }}" = "false"
|
||||
test "${{ needs.typecheck-jetbrains.result }}" = "skipped"
|
||||
fi
|
||||
# kilocode_change end
|
||||
|
||||
@@ -62,6 +62,18 @@ Pay special attention to:
|
||||
|
||||
When in doubt, add a finding. A human will verify it. Compiling code is not proof the chain is intact.
|
||||
|
||||
## CONFIG_REGRESSION.md
|
||||
|
||||
Check whether this PR introduces or re-introduces fallback logic for `opencode` config files, or accidentally breaks code that now correctly expects only `.kilo`-based configuration.
|
||||
|
||||
Kilo removed fallback support for `opencode` config directories. Look for:
|
||||
|
||||
- Any new or restored code that reads from `opencode` config paths.
|
||||
- Upstream additions to config discovery, loading, or path resolution that add `opencode` fallback candidates we stripped.
|
||||
- Changes that break `.kilo`-only config lookup by removing or reordering it in a multi-path search.
|
||||
|
||||
When in doubt, add a finding. A human should verify config path changes manually.
|
||||
|
||||
## TESTS.md
|
||||
|
||||
Check whether this PR removed any Kilo-specific tests.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
English | <a href="README.zh.md">简体中文</a> | <a href="README.zht.md">繁體中文</a> | <a href="README.ko.md">한국어</a> | <a href="README.de.md">Deutsch</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.it.md">Italiano</a> | <a href="README.da.md">Dansk</a> | <a href="README.ja.md">日本語</a> | <a href="README.pl.md">Polski</a> | <a href="README.ru.md">Русский</a> | <a href="README.bs.md">Bosanski</a> | <a href="README.ar.md">العربية</a> | <a href="README.no.md">Norsk</a> | <a href="README.br.md">Português (Brasil)</a> | <a href="README.th.md">ไทย</a> | <a href="README.tr.md">Türkçe</a> | <a href="README.uk.md">Українська</a> | <a href="README.bn.md">বাংলা</a> | <a href="README.gr.md">Ελληνικά</a> | <a href="README.vi.md">Tiếng Việt</a>
|
||||
English | <a href="translations/README.zh.md">简体中文</a> | <a href="translations/README.zht.md">繁體中文</a> | <a href="translations/README.ko.md">한국어</a> | <a href="translations/README.de.md">Deutsch</a> | <a href="translations/README.es.md">Español</a> | <a href="translations/README.fr.md">Français</a> | <a href="translations/README.it.md">Italiano</a> | <a href="translations/README.da.md">Dansk</a> | <a href="translations/README.ja.md">日本語</a> | <a href="translations/README.pl.md">Polski</a> | <a href="translations/README.ru.md">Русский</a> | <a href="translations/README.bs.md">Bosanski</a> | <a href="translations/README.ar.md">العربية</a> | <a href="translations/README.no.md">Norsk</a> | <a href="translations/README.br.md">Português (Brasil)</a> | <a href="translations/README.th.md">ไทย</a> | <a href="translations/README.tr.md">Türkçe</a> | <a href="translations/README.uk.md">Українська</a> | <a href="translations/README.bn.md">বাংলা</a> | <a href="translations/README.gr.md">Ελληνικά</a> | <a href="translations/README.vi.md">Tiếng Việt</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -168,7 +168,7 @@ MIT. You're free to use, modify, and distribute this code, including commerciall
|
||||
<details>
|
||||
<summary>Where did Kilo CLI come from?</summary>
|
||||
|
||||
Kilo CLI is a fork of [OpenCode](https://github.com/Kilo-Org/kilocode), enhanced to work within the Kilo agentic engineering platform.
|
||||
Kilo CLI is a fork of [OpenCode](https://github.com/anomalyco/opencode), enhanced to work within the Kilo agentic engineering platform.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { createSocket } from "node:dgram"
|
||||
import fs from "node:fs/promises"
|
||||
import os from "node:os"
|
||||
import path from "node:path"
|
||||
@@ -9,15 +10,20 @@ import { backendSupport, run, type Profile } from "@kilocode/sandbox"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
|
||||
const linux = process.platform === "linux" ? test : test.skip
|
||||
const linuxIPv6 = process.platform === "linux" && supportsIPv6() ? test : test.skip
|
||||
|
||||
function profile(allow: ReadonlyArray<string>, denyNames: ReadonlyArray<string> = []): Profile {
|
||||
function profile(
|
||||
allow: ReadonlyArray<string>,
|
||||
denyNames: ReadonlyArray<string> = [],
|
||||
mode: Profile["network"]["mode"] = "allow",
|
||||
): Profile {
|
||||
return {
|
||||
filesystem: {
|
||||
allowWrite: allow.map((path) => ({ path, kind: "subtree" })),
|
||||
denyWrite: [],
|
||||
denyNames,
|
||||
},
|
||||
network: { mode: "allow", allowedHosts: [] },
|
||||
network: { mode, allowedHosts: [] },
|
||||
environment: { deny: [], set: {} },
|
||||
}
|
||||
}
|
||||
@@ -48,6 +54,81 @@ async function fixture() {
|
||||
return { root, project, outside }
|
||||
}
|
||||
|
||||
function requireNetwork() {
|
||||
const support = backendSupport({ mode: "deny", allowedHosts: [] })
|
||||
expect(support.available, support.reason).toBe(true)
|
||||
}
|
||||
|
||||
function tcp(hostname = "127.0.0.1") {
|
||||
let accepted = 0
|
||||
const listener = Bun.listen({
|
||||
hostname,
|
||||
port: 0,
|
||||
socket: {
|
||||
open(socket) {
|
||||
accepted++
|
||||
socket.write("sandbox-tcp-ok")
|
||||
socket.end()
|
||||
},
|
||||
data() {},
|
||||
},
|
||||
})
|
||||
return { listener, accepted: () => accepted }
|
||||
}
|
||||
|
||||
function supportsIPv6() {
|
||||
if (process.platform !== "linux") return false
|
||||
try {
|
||||
const probe = tcp("::1")
|
||||
probe.listener.stop(true)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function udp() {
|
||||
let received = 0
|
||||
const socket = createSocket("udp4")
|
||||
socket.on("message", (_message, peer) => {
|
||||
received++
|
||||
socket.send("sandbox-udp-ok", peer.port, peer.address)
|
||||
})
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
socket.once("error", reject)
|
||||
socket.bind(0, "127.0.0.1", () => {
|
||||
socket.off("error", reject)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
const address = socket.address()
|
||||
if (typeof address === "string") throw new Error("UDP server did not expose an IP address")
|
||||
return { socket, port: address.port, received: () => received }
|
||||
}
|
||||
|
||||
function tcpClient(port: number, expected: boolean, hostname = "127.0.0.1") {
|
||||
return [
|
||||
'const net = require("node:net")',
|
||||
`const socket = net.connect({ host: ${JSON.stringify(hostname)}, port: ${port} })`,
|
||||
`const expected = ${expected}`,
|
||||
'socket.on("data", (data) => process.exit(expected && data.toString() === "sandbox-tcp-ok" ? 0 : 2))',
|
||||
'socket.on("error", () => process.exit(expected ? 3 : 0))',
|
||||
"setTimeout(() => process.exit(expected ? 4 : 0), 1000)",
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
function udpClient(port: number, expected: boolean) {
|
||||
return [
|
||||
'const dgram = require("node:dgram")',
|
||||
'const socket = dgram.createSocket("udp4")',
|
||||
`const expected = ${expected}`,
|
||||
'socket.on("message", (data) => process.exit(expected && data.toString() === "sandbox-udp-ok" ? 0 : 2))',
|
||||
'socket.on("error", () => process.exit(expected ? 3 : 0))',
|
||||
`socket.send("probe", ${port}, "127.0.0.1", (error) => { if (error) process.exit(expected ? 4 : 0) })`,
|
||||
"setTimeout(() => process.exit(expected ? 5 : 0), 500)",
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
linux("confines writes from spawned processes to the profile allowlist", async () => {
|
||||
const support = backendSupport()
|
||||
expect(support.available, support.reason).toBe(true)
|
||||
@@ -76,6 +157,154 @@ linux("confines writes from spawned processes to the profile allowlist", async (
|
||||
}
|
||||
})
|
||||
|
||||
linux("allows host loopback TCP in network allow mode and blocks it in deny mode", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const allowed = tcp()
|
||||
const blocked = tcp()
|
||||
|
||||
try {
|
||||
const allow = profile([root.project], [], "allow")
|
||||
const deny = profile([root.project], [], "deny")
|
||||
expect(Number(await Effect.runPromise(spawn(tcpClient(allowed.listener.port, true), root.project, allow)))).toBe(0)
|
||||
expect(Number(await Effect.runPromise(spawn(tcpClient(blocked.listener.port, false), root.project, deny)))).toBe(0)
|
||||
expect(allowed.accepted()).toBe(1)
|
||||
expect(blocked.accepted()).toBe(0)
|
||||
} finally {
|
||||
allowed.listener.stop(true)
|
||||
blocked.listener.stop(true)
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("blocks UDP datagrams in network deny mode", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const allowed = await udp()
|
||||
const blocked = await udp()
|
||||
|
||||
try {
|
||||
const allow = profile([root.project], [], "allow")
|
||||
const deny = profile([root.project], [], "deny")
|
||||
expect(Number(await Effect.runPromise(spawn(udpClient(allowed.port, true), root.project, allow)))).toBe(0)
|
||||
expect(Number(await Effect.runPromise(spawn(udpClient(blocked.port, false), root.project, deny)))).toBe(0)
|
||||
expect(allowed.received()).toBe(1)
|
||||
expect(blocked.received()).toBe(0)
|
||||
} finally {
|
||||
allowed.socket.close()
|
||||
blocked.socket.close()
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("blocks localhost connections in network deny mode", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const listener = tcp()
|
||||
const deny = profile([root.project], [], "deny")
|
||||
|
||||
try {
|
||||
expect(
|
||||
Number(await Effect.runPromise(spawn(tcpClient(listener.listener.port, false, "localhost"), root.project, deny))),
|
||||
).toBe(0)
|
||||
expect(listener.accepted()).toBe(0)
|
||||
} finally {
|
||||
listener.listener.stop(true)
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linuxIPv6("blocks IPv6 loopback connections in network deny mode", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const listener = tcp("::1")
|
||||
const deny = profile([root.project], [], "deny")
|
||||
|
||||
try {
|
||||
expect(
|
||||
Number(await Effect.runPromise(spawn(tcpClient(listener.listener.port, false, "::1"), root.project, deny))),
|
||||
).toBe(0)
|
||||
expect(listener.accepted()).toBe(0)
|
||||
} finally {
|
||||
listener.listener.stop(true)
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("keeps loopback available between processes inside the denied network namespace", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const child = [
|
||||
'const net = require("node:net")',
|
||||
"const port = Number(process.argv[1])",
|
||||
'const socket = net.connect({ host: "127.0.0.1", port })',
|
||||
'socket.on("connect", () => socket.write("sandbox-internal-ok"))',
|
||||
'socket.on("data", (data) => process.exit(data.toString() === "sandbox-internal-ok" ? 0 : 2))',
|
||||
'socket.on("error", () => process.exit(3))',
|
||||
].join("\n")
|
||||
const script = [
|
||||
'const child = require("node:child_process")',
|
||||
'const net = require("node:net")',
|
||||
'const server = net.createServer((socket) => socket.on("data", (data) => socket.end(data)))',
|
||||
'server.listen(0, "127.0.0.1", () => {',
|
||||
` const proc = child.spawn(process.execPath, ["-e", ${JSON.stringify(child)}, String(server.address().port)])`,
|
||||
' proc.on("exit", (code) => process.exit(code ?? 4))',
|
||||
"})",
|
||||
].join("\n")
|
||||
|
||||
try {
|
||||
expect(Number(await Effect.runPromise(spawn(script, root.project, profile([root.project], [], "deny"))))).toBe(0)
|
||||
} finally {
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("keeps descendants in the denied network namespace", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const blocked = tcp()
|
||||
const child = tcpClient(blocked.listener.port, false)
|
||||
const script = [
|
||||
'const child = require("node:child_process")',
|
||||
`const result = child.spawnSync(process.execPath, ["-e", ${JSON.stringify(child)}])`,
|
||||
"process.exit(result.status ?? 3)",
|
||||
].join("\n")
|
||||
|
||||
try {
|
||||
expect(Number(await Effect.runPromise(spawn(script, root.project, profile([root.project], [], "deny"))))).toBe(0)
|
||||
expect(blocked.accepted()).toBe(0)
|
||||
} finally {
|
||||
blocked.listener.stop(true)
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("preserves filesystem confinement in network deny mode", async () => {
|
||||
requireNetwork()
|
||||
const root = await fixture()
|
||||
const allowed = path.join(root.project, "network-deny.txt")
|
||||
const sentinel = path.join(root.outside, "network-deny.txt")
|
||||
await fs.writeFile(sentinel, "original")
|
||||
const script = [
|
||||
'const fs = require("node:fs")',
|
||||
`fs.writeFileSync(${JSON.stringify(allowed)}, "allowed")`,
|
||||
"try {",
|
||||
` fs.writeFileSync(${JSON.stringify(sentinel)}, "escaped")`,
|
||||
" process.exit(2)",
|
||||
"} catch {",
|
||||
" process.exit(0)",
|
||||
"}",
|
||||
].join("\n")
|
||||
|
||||
try {
|
||||
expect(Number(await Effect.runPromise(spawn(script, root.project, profile([root.project], [], "deny"))))).toBe(0)
|
||||
expect(await fs.readFile(allowed, "utf8")).toBe("allowed")
|
||||
expect(await fs.readFile(sentinel, "utf8")).toBe("original")
|
||||
} finally {
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("keeps reads available when no paths are writable", async () => {
|
||||
const root = await fixture()
|
||||
const sentinel = path.join(root.project, "sentinel.txt")
|
||||
@@ -212,6 +441,30 @@ linux("applies explicit file and subtree denies after a writable parent", async
|
||||
}
|
||||
})
|
||||
|
||||
linux("prevents renaming denied policy state while sibling state remains writable", async () => {
|
||||
const root = await fixture()
|
||||
const state = path.join(root.project, "state")
|
||||
const store = path.join(root.project, "policy")
|
||||
const sibling = path.join(state, "sibling.txt")
|
||||
const moved = path.join(state, "moved")
|
||||
await fs.mkdir(state)
|
||||
await fs.mkdir(store)
|
||||
const policy = denied(profile([state]), [{ path: store, kind: "subtree" }])
|
||||
const script = [
|
||||
'const fs = require("node:fs")',
|
||||
`fs.writeFileSync(${JSON.stringify(sibling)}, "allowed")`,
|
||||
`try { fs.renameSync(${JSON.stringify(store)}, ${JSON.stringify(moved)}); process.exit(2) } catch {}`,
|
||||
].join("\n")
|
||||
|
||||
try {
|
||||
expect(Number(await Effect.runPromise(spawn(script, root.project, policy)))).toBe(0)
|
||||
expect(await fs.readFile(sibling, "utf8")).toBe("allowed")
|
||||
expect((await fs.stat(store)).isDirectory()).toBe(true)
|
||||
} finally {
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("supports writable literal files without opening writable siblings", async () => {
|
||||
const root = await fixture()
|
||||
const allowed = path.join(root.project, "allowed.txt")
|
||||
@@ -448,6 +701,48 @@ linux("rejects a Bubblewrap helper inside a writable root", async () => {
|
||||
}
|
||||
})
|
||||
|
||||
linux("reports network namespace support separately and fails deny mode closed", async () => {
|
||||
const root = await fixture()
|
||||
const source = process.env.KILO_BWRAP_PATH ?? "/usr/bin/bwrap"
|
||||
const helper = path.join(root.outside, "bwrap-no-network")
|
||||
await fs.writeFile(
|
||||
helper,
|
||||
[
|
||||
"#!/bin/sh",
|
||||
'for arg in "$@"; do',
|
||||
' if [ "$arg" = "--unshare-net" ]; then echo "network namespaces blocked" >&2; exit 42; fi',
|
||||
"done",
|
||||
`exec ${JSON.stringify(source)} "$@"`,
|
||||
"",
|
||||
].join("\n"),
|
||||
)
|
||||
await fs.chmod(helper, 0o755)
|
||||
const script = [
|
||||
'import { Effect } from "effect"',
|
||||
'import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"',
|
||||
'import { backendSupport, run } from "@kilocode/sandbox"',
|
||||
'import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"',
|
||||
'const allow = backendSupport({ mode: "allow", allowedHosts: [] })',
|
||||
'const deny = backendSupport({ mode: "deny", allowedHosts: [] })',
|
||||
"if (!allow.available) process.exit(2)",
|
||||
'if (deny.available || !deny.reason?.includes("Linux network sandbox")) process.exit(3)',
|
||||
'const profile = { filesystem: { allowWrite: [], denyWrite: [], denyNames: [] }, network: { mode: "deny", allowedHosts: [] }, environment: { deny: [], set: {} } }',
|
||||
'const effect = Effect.scoped(run(profile, ChildProcessSpawner.ChildProcessSpawner.use((spawner) => spawner.spawn(ChildProcess.make(process.execPath, ["-e", "process.exit(0)"])))).pipe(Effect.provide(CrossSpawnSpawner.defaultLayer)))',
|
||||
"try { await Effect.runPromise(effect); process.exit(4) } catch { process.exit(0) }",
|
||||
].join("\n")
|
||||
|
||||
try {
|
||||
const result = spawnSync(process.execPath, ["-e", script], {
|
||||
cwd: import.meta.dir,
|
||||
env: { ...process.env, KILO_BWRAP_PATH: helper },
|
||||
encoding: "utf8",
|
||||
})
|
||||
expect(result.status, result.stderr).toBe(0)
|
||||
} finally {
|
||||
await fs.rm(root.root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
linux("fails closed when Bubblewrap is unavailable", () => {
|
||||
const script = [
|
||||
'import { Effect } from "effect"',
|
||||
|
||||
@@ -119,14 +119,14 @@ describe("ProjectV2.resolve", () => {
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||
)
|
||||
yield* Effect.promise(() => initRepo(ssh.path, { commit: true, remote: "git@github.com:owner/repo.git" }))
|
||||
yield* Effect.promise(() => initRepo(https.path, { commit: true, remote: "https://github.com/owner/repo.git" }))
|
||||
yield* Effect.promise(() => initRepo(ssh.path, { commit: true, remote: "git@example.com:owner/repo.git" }))
|
||||
yield* Effect.promise(() => initRepo(https.path, { commit: true, remote: "https://example.com/owner/repo.git" }))
|
||||
const project = yield* Project.Service
|
||||
|
||||
const a = yield* project.resolve(abs(ssh.path))
|
||||
const b = yield* project.resolve(abs(https.path))
|
||||
|
||||
expect(a.id).toBe(remoteID("github.com/owner/repo"))
|
||||
expect(a.id).toBe(remoteID("example.com/owner/repo"))
|
||||
expect(b.id).toBe(a.id)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -56,6 +56,10 @@ export const AiProvidersNav: NavSection[] = [
|
||||
{ href: "/ai-providers/ollama", children: "Ollama" },
|
||||
{ href: "/ai-providers/lmstudio", children: "LM Studio" },
|
||||
{ href: "/ai-providers/atomic-chat", children: "Atomic Chat" },
|
||||
{
|
||||
href: "/ai-providers/anaconda-desktop",
|
||||
children: "Anaconda Desktop",
|
||||
},
|
||||
{ href: "/ai-providers/vscode-lm", children: "VS Code LM API" },
|
||||
{
|
||||
href: "/ai-providers/openai-compatible",
|
||||
|
||||
@@ -36,10 +36,12 @@ export const GettingStartedNav: NavSection[] = [
|
||||
children: "System Notifications",
|
||||
platform: "legacy",
|
||||
},
|
||||
{ href: "/getting-started/settings/sandboxing", children: "Sandboxing" },
|
||||
],
|
||||
},
|
||||
{ href: "/getting-started/adding-credits", children: "Adding Credits" },
|
||||
{ href: "/getting-started/rate-limits-and-costs", children: "Rate Limits and Costs" },
|
||||
{ href: "/getting-started/rate-limits-and-costs", children: "Cost Efficiency & Model Selection" },
|
||||
{ href: "/getting-started/cost-controls-and-usage-safeguards", children: "Cost Controls and Usage Safeguards" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -50,6 +50,8 @@ exclude = [
|
||||
'^https?://api\.apertis\.ai/v1/?$',
|
||||
# Redirects to authenticated Google Cloud console
|
||||
'^https?://console\.cloud\.google\.com',
|
||||
# Linear intermittently returns 503 to CI link checks.
|
||||
'^https?://linear\.app/?$',
|
||||
# Consistently times out in CI
|
||||
'^https?://opncd\.ai',
|
||||
'^https?://zod\.dev/v4/changelog',
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: "Using Anaconda Desktop with Kilo Code | Local Models"
|
||||
description: "Connect Kilo Code to a local Anaconda Desktop text-generation model server from the TUI or VS Code."
|
||||
sidebar_label: Anaconda Desktop
|
||||
---
|
||||
|
||||
# Using Anaconda Desktop With Kilo Code
|
||||
|
||||
Kilo Code can discover the text-generation model served by [Anaconda Desktop](https://www.anaconda.com/products/desktop) and connect to its local OpenAI-compatible endpoint. Kilo imports the server connection for you, so you do not need to copy an API key or configure a base URL manually.
|
||||
|
||||
**Official documentation:** [Anaconda Desktop](https://www.anaconda.com/docs/tools/anaconda-desktop/key-features)
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Anaconda Desktop and Kilo must run on the same supported computer.
|
||||
|
||||
| Operating system | Supported installation |
|
||||
|---|---|
|
||||
| Windows | Windows 11, x86-64 |
|
||||
| macOS | macOS 13 or later, Apple Silicon |
|
||||
| Linux | Debian or Ubuntu, x86-64 or ARM64 |
|
||||
|
||||
Remote backends, remote-only model endpoints, and non-interactive or headless setup are not supported. Complete setup in the Kilo TUI or VS Code on the computer running Anaconda Desktop.
|
||||
|
||||
## Set Up Anaconda Desktop
|
||||
|
||||
1. Download and install Anaconda Desktop from the [official product page](https://www.anaconda.com/products/desktop). See Anaconda's [installation guide](https://www.anaconda.com/docs/tools/anaconda-desktop/install-desktop) for platform-specific steps.
|
||||
2. Open Anaconda Desktop and sign in with your Anaconda account or your organization's assigned credentials.
|
||||
3. Select **Model Catalog** and filter for a **Text Generation** model. Prefer a model tagged **Tool Calling** for full Kilo agent functionality.
|
||||
4. Select a quantization that fits your computer, then click **Download**. Anaconda's [model catalog guide](https://www.anaconda.com/docs/tools/anaconda-desktop/model-catalog) explains model types, hardware requirements, and quantization choices.
|
||||
5. Select **Model Servers**, choose the downloaded model and file, and start its server. Enable tool calling when the selected model and server configuration support it.
|
||||
|
||||
{% callout type="note" %}
|
||||
Kilo only discovers Desktop state and connects to an existing server. Downloading or deleting models and creating, switching, starting, stopping, or deleting servers must be done in Anaconda Desktop. See Anaconda's [model server guide](https://www.anaconda.com/docs/tools/anaconda-desktop/servers).
|
||||
{% /callout %}
|
||||
|
||||
## Connect Kilo Code
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="TUI" %}
|
||||
|
||||
1. Run `/connect` in the Kilo TUI.
|
||||
2. Select **Anaconda Desktop**.
|
||||
3. Follow the setup dialog. Kilo can open Anaconda Desktop; after making changes there, return and choose **Check again**.
|
||||
4. When the model server is ready, choose **Connect** to import its connection and make the served model available in the model picker.
|
||||
|
||||
To refresh an existing connection, run `/connect`, select **Anaconda Desktop**, and choose **connect / refresh now** after changing the model, server address or port, or server API key in Desktop. Kilo re-discovers the active server and replaces its stored model and connection information.
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="VS Code" %}
|
||||
|
||||
1. Open Kilo Code **Settings** using the gear icon and select **Providers**.
|
||||
2. Add **Anaconda Desktop**. No manual API-key field is shown.
|
||||
3. Follow the setup dialog. Kilo can open Anaconda Desktop; after making changes there, return and select **Check again**.
|
||||
4. When the model server is ready, select **Connect** to import its connection and refresh the model picker.
|
||||
|
||||
For an existing connection, open **Settings**, select **Providers**, and select **Manage / Refresh** for Anaconda Desktop after changing the model, server address or port, or server API key in Desktop.
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
## Tool Calling
|
||||
|
||||
When Desktop reports that the model server supports tool calling, Kilo allows you to connect without an additional warning. Tool calling lets the model use Kilo's tools to inspect files, edit code, and run commands.
|
||||
|
||||
{% callout type="warning" %}
|
||||
If tool support is unavailable or cannot be detected, Kilo shows a warning and requires confirmation before connecting. You can still use the model for text generation, but normal coding-agent actions are limited and may fail. For the best experience, choose a **Text Generation** model tagged **Tool Calling** and enable the server's tool-call support when available.
|
||||
{% /callout %}
|
||||
|
||||
## How Keys Are Handled
|
||||
|
||||
Anaconda Desktop uses two separate credentials:
|
||||
|
||||
- **Desktop management key** - Allows local discovery of Desktop models and servers. Kilo reads it from Desktop's configuration only when needed and never copies it into Kilo storage.
|
||||
- **Inference server key** - Authenticates chat-completion requests to the running model server. Kilo imports this key into its normal provider authentication storage together with the local endpoint and model details.
|
||||
|
||||
Kilo never asks you to paste either key. If the inference server key or endpoint changes, use **Refresh** to import the current values.
|
||||
|
||||
## Disconnect
|
||||
|
||||
In VS Code, open **Settings** > **Providers** and select **Disconnect** for Anaconda Desktop. In a terminal, run `kilo auth logout` and select Anaconda Desktop. Disconnecting removes only Kilo's stored provider authentication and connection metadata. It does not stop Anaconda Desktop, stop the model server, or delete the downloaded model.
|
||||
|
||||
Use Anaconda Desktop itself to stop or change the server.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Desktop is not detected:** Install it from the [official product page](https://www.anaconda.com/products/desktop), or use **Open Anaconda Desktop** if it is installed but not running.
|
||||
- **Sign-in is required:** Open Desktop, complete sign-in, and leave the Kilo setup dialog open so it can detect the change.
|
||||
- **No model is available:** Download a model whose type is **Text Generation**, not an embedding-only model.
|
||||
- **No server is available:** Start the downloaded model from **Model Servers** in Desktop.
|
||||
- **The server changed:** Use **Refresh** in Kilo to replace the stored model, endpoint, and inference key.
|
||||
- **The server is unhealthy:** Check the server status and logs in Desktop, then restart it there before refreshing Kilo.
|
||||
@@ -34,6 +34,7 @@ Major AI companies offering powerful models via API:
|
||||
Run models on your own hardware for privacy and offline use:
|
||||
|
||||
- **[Atomic Chat](/docs/ai-providers/atomic-chat)** - Local models with TurboQuant inference and auto-discovery in Kilo Code
|
||||
- **[Anaconda Desktop](/docs/ai-providers/anaconda-desktop)** - Discover and connect to a local text-generation model server
|
||||
- **[Ollama](/docs/ai-providers/ollama)** - Easy local model management
|
||||
- **[LM Studio](/docs/ai-providers/lmstudio)** - Desktop app for local models
|
||||
- **[OpenAI Compatible](/docs/ai-providers/openai-compatible)** - Any OpenAI-compatible endpoint
|
||||
|
||||
@@ -30,7 +30,7 @@ Every installation has a scope:
|
||||
|
||||
Project files can be committed to version control and shared with teammates. Global files remain on your machine and do not travel with a repository.
|
||||
|
||||
When the same configuration exists at both scopes, project configuration takes precedence over global configuration. Learn more about [Kilo's configuration files and precedence](/docs/getting-started/settings#configuration-files).
|
||||
When the same configuration exists at both scopes, project configuration takes precedence over global configuration. Learn more about [Kilo's configuration files and precedence](/docs/getting-started/settings#config-file-precedence).
|
||||
|
||||
## Files changed by installation
|
||||
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
---
|
||||
title: "Cost Controls and Usage Safeguards"
|
||||
description: "How to prevent runaway agent usage, reduce token consumption, choose the right model, and govern spend at the individual and organization level"
|
||||
---
|
||||
|
||||
# Cost Controls and Usage Safeguards
|
||||
|
||||
## Overview
|
||||
|
||||
How much you spend with Kilo Code is shaped by several factors working together:
|
||||
|
||||
- **Model selection** — frontier models cost significantly more per token than efficient or free tiers
|
||||
- **Prompt and context size** — every token in your system prompt, conversation history, file attachments, and tool definitions is billed as input
|
||||
- **Number of agent steps and tool calls** — each step the agent takes (read a file, run a command, write code) generates its own request
|
||||
- **Repeated retries or loops** — a stuck agent that keeps retrying the same failing step multiplies your cost
|
||||
- **Background and automated tasks** — long-running or unattended tasks accumulate cost without immediate visibility
|
||||
- **Session length** — long sessions carry more conversation history into every new request
|
||||
|
||||
No single control eliminates cost on its own. The most effective approach combines model selection, context management, task scope, and account-level monitoring together.
|
||||
|
||||
This page covers the controls currently available in Kilo Code. For a direct overview of Auto Model tiers and token optimization tips, see [Cost Efficiency & Model Selection](/docs/getting-started/rate-limits-and-costs).
|
||||
|
||||
---
|
||||
|
||||
## Preventing Loops and Runaway Usage
|
||||
|
||||
### Doom loop protection
|
||||
|
||||
When the agent enters a repeated failure cycle — attempting the same action multiple times without making progress — Kilo pauses and asks for permission before continuing. This is controlled by the `doom_loop` permission, which defaults to `ask`.
|
||||
|
||||
**Where to configure:** Settings → Auto Approve (VS Code) or the `permission.doom_loop` key in `kilo.jsonc` (CLI).
|
||||
|
||||
**When to use:** Leave this at `ask` (the default) unless you are running fully unattended automation in a controlled environment. Setting it to `deny` blocks recovery entirely; `allow` lets loops continue without interruption.
|
||||
|
||||
### Per-tool approval controls
|
||||
|
||||
Every action Kilo takes — reading files, editing code, running shell commands, launching sub-agents — is governed by the permission system. Each tool can be set to `allow`, `ask`, or `deny`. When set to `ask`, Kilo pauses before executing and you can approve or reject that specific action.
|
||||
|
||||
**Where to configure:** Settings → Auto Approve (VS Code) or the `permission` section in `kilo.jsonc` (CLI). See [Auto-Approving Actions](/docs/getting-started/settings/auto-approving-actions) for the full list of available permissions.
|
||||
|
||||
**When to use:** Keep `bash` set to `ask` by default for unfamiliar tasks. You can allow specific safe command prefixes (e.g. `git *`, `npm *`) while keeping everything else at `ask`. This prevents the agent from running expensive or destructive commands in a loop without oversight.
|
||||
|
||||
### Runtime auto-approve toggle (VS Code)
|
||||
|
||||
A shield button in the prompt controls lets you toggle auto-approve on and off at runtime without opening Settings. When enabled, pending permission prompts are approved automatically. The state stays synced across the sidebar and open Kilo tabs.
|
||||
|
||||
**When to use:** Turn it on when working on a well-understood, low-risk task that does not need step-by-step review. Turn it off as soon as you want to pause and review the agent's next actions.
|
||||
|
||||
### Spending limits
|
||||
|
||||
Individual accounts stop spending when their balance reaches zero — further requests to paid models return an error and prompt you to add credits. This acts as a hard ceiling on total spend.
|
||||
|
||||
Organization accounts can additionally configure **per-user daily spending limits**. When a member reaches their daily cap, subsequent requests are blocked until midnight UTC, when the limit resets.
|
||||
|
||||
**Where to configure:** Organization spending limits are managed in the organization dashboard at [app.kilo.ai](https://app.kilo.ai). Individual credit top-up is at Settings → Adding Credits.
|
||||
|
||||
### Free model rate limits
|
||||
|
||||
Requests to free models (`kilo-auto/free` and other free-tier models) are rate-limited to **200 requests per hour**. If you exceed this, requests return HTTP 429 and you must wait before continuing.
|
||||
|
||||
### Practical recommendations
|
||||
|
||||
- **Define a narrow scope before starting.** "Fix the null pointer in `processData`" generates far fewer steps than "keep fixing everything that looks wrong." Specificity reduces both steps and cost.
|
||||
- **Ask the agent to stop and report after a stage.** Phrases like "analyze the problem and summarize your findings before making any changes" let you review the plan and cost before committing to implementation.
|
||||
- **Review plans before allowing broad execution.** Use Architect mode (which cannot modify code) to get a plan first, then switch to Code mode to apply it incrementally.
|
||||
- **Monitor long-running or unattended tasks.** Check the per-request cost estimates in the chat history as the session progresses. If cost is climbing unexpectedly, pause and review what the agent is doing.
|
||||
- **Avoid open-ended prompts.** Prompts like "keep trying until it works" or "explore the whole codebase and clean it up" give the agent unlimited scope to continue generating steps.
|
||||
|
||||
---
|
||||
|
||||
## Reducing Context and Token Usage
|
||||
|
||||
### Start a new session when the topic changes
|
||||
|
||||
Conversation history accumulates with every turn. When you finish a task and move on to something unrelated, starting a new session resets the context to just your system prompt and instructions — significantly cheaper than carrying the full prior conversation.
|
||||
|
||||
### Keep prompts focused
|
||||
|
||||
Concise, specific prompts cost fewer tokens. Instead of pasting large blocks of background, describe what you need in plain terms and let the agent ask for files if it needs them. Repeating context you already provided earlier in the session is rarely necessary.
|
||||
|
||||
### Use `@file` and `@folder` mentions selectively
|
||||
|
||||
Attaching an entire folder sends every file in it as input tokens, even if only one or two files are relevant. Use `@file` with specific paths rather than broad directory mentions. When reviewing a bug, include only the file containing the bug and its closest dependencies.
|
||||
|
||||
### Exclude generated, build, and vendor directories
|
||||
|
||||
Kilo automatically skips a set of directories including `node_modules`, `dist`, `build`, `.git`, `__pycache__`, `.cache`, and `vendor`. You can add additional paths using **permission deny rules** in `kilo.jsonc` or using a `.kilocodeignore` file at your workspace root.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"permission": {
|
||||
"read": {
|
||||
"coverage/**": "deny",
|
||||
".next/**": "deny",
|
||||
"*": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Where to configure:** `kilo.jsonc` (VS Code / CLI). See [.kilocodeignore](/docs/customize/context/kilocodeignore) for full details.
|
||||
|
||||
### Compact long conversations
|
||||
|
||||
When a conversation grows long, use `/compact` in the chat (also searchable as `smol` or `condense`) to summarize the history and free up context space. Kilo replaces older conversation turns with an anchored summary that captures your goal, constraints, progress, and next steps.
|
||||
|
||||
Auto-compaction is **enabled by default** — Kilo automatically compacts when approaching the context window limit so you do not need to intervene manually.
|
||||
|
||||
**Where to configure:** Toggle auto-compaction in **Settings → Context** (VS Code) or set `compaction.auto` in `kilo.jsonc`. Configure the trigger threshold with `compaction.threshold_percent` (e.g. `80` to compact at 80% of the model's context window).
|
||||
|
||||
You can also configure a cheaper model specifically for compaction, so summarization does not consume frontier model tokens:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agent": {
|
||||
"compaction": {
|
||||
"model": "anthropic/claude-haiku-4-5"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [Context Condensing](/docs/customize/context/context-condensing) for full configuration options.
|
||||
|
||||
### Keep max output tokens conservative
|
||||
|
||||
Every token you allocate to model output reduces how much conversation history can remain in the context window. For routine coding tasks, keep Code mode at **16k max output tokens or below**. Raise the limit only in Architect or Debug modes where extended reasoning is useful.
|
||||
|
||||
**Where to configure:** Model settings in the Kilo Code UI, or the `limit.output` key in custom model configuration.
|
||||
|
||||
### Use project instructions efficiently
|
||||
|
||||
Encode recurring guidance — coding standards, project conventions, preferred libraries — in your `AGENTS.md` or custom instructions once. This avoids repeating the same context in every prompt, and prompt caching means stable instructions are served from cache at a discounted rate on supported providers.
|
||||
|
||||
### Disable unused MCP servers
|
||||
|
||||
MCP tool definitions are included in the system prompt sent with every request. If you are not using MCP features, disable MCP servers in **Settings → Agent Behaviour → MCP Servers**. This can meaningfully reduce per-request system prompt size.
|
||||
|
||||
See [MCP Overview](/docs/automate/mcp/overview) for details.
|
||||
|
||||
### Prompt caching
|
||||
|
||||
Kilo automatically applies prompt caching on supported providers. Repeated context — your system prompt, stable file contents, and tool definitions — is reused from cache at a discounted rate. No configuration is required to benefit from this.
|
||||
|
||||
---
|
||||
|
||||
## Choosing Models for Specific Tasks
|
||||
|
||||
Different tasks benefit from different model characteristics. Routing work to the right model reduces cost without sacrificing quality.
|
||||
Kilo has auto-models that can help you control costs; more information is available in [Auto Model](/docs/code-with-ai/agents/auto-model).
|
||||
|
||||
### Practical examples by task type
|
||||
|
||||
| Task type | Suggested approach |
|
||||
|---|---|
|
||||
| Quick questions, syntax lookups, simple formatting | `kilo-auto/efficient` or a lightweight model |
|
||||
| Routine edits, test generation, straightforward refactors | `kilo-auto/efficient` or a mid-tier model |
|
||||
| Complex debugging, tracing unexpected behavior | `kilo-auto/frontier` or a strong reasoning model; Debug mode |
|
||||
| Architecture planning, design decisions | `kilo-auto/frontier`; Architect mode |
|
||||
| Repository-wide analysis or search | A model with a large context window (256K+); Architect mode |
|
||||
| Code review and summarization | `kilo-auto/efficient` or a cost-effective model |
|
||||
| Automated background tasks (CI, scripting) | `kilo-auto/efficient` or `kilo-auto/free` |
|
||||
|
||||
### Manually selecting a model
|
||||
|
||||
Use the **model selector dropdown** in the Kilo Code chat interface to switch models for the current session. In the CLI, pass the `--model` flag to `kilo run` or use the model picker in the TUI (`Ctrl+X m` or `/models`).
|
||||
|
||||
### Configuring a model per agent or mode
|
||||
|
||||
You can set a default model for each agent (Code, Architect, Debug, Plan, or a custom subagent) independently:
|
||||
|
||||
- **VS Code:** Settings → Models → Model per Mode, or edit `kilo.jsonc` directly.
|
||||
- **CLI:** Set `agent.<name>.model` in `kilo.jsonc`.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agent": {
|
||||
"code": {
|
||||
"model": "kilo-auto/efficient"
|
||||
},
|
||||
"architect": {
|
||||
"model": "kilo-auto/frontier"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This lets you run cost-effective models for implementation while automatically routing planning tasks to a more capable model.
|
||||
|
||||
### Organization-level model restrictions
|
||||
|
||||
Enterprise organizations can restrict which models team members may use. See [Enterprise Cost Controls](#enterprise-cost-controls) below.
|
||||
|
||||
For full guidance on model selection, see the [Model Selection Guide](/docs/code-with-ai/agents/model-selection).
|
||||
|
||||
---
|
||||
|
||||
## Enterprise Cost Controls
|
||||
|
||||
The following controls are available to organizations and, where noted, are exclusive to Enterprise plans.
|
||||
|
||||
### Model access controls (Enterprise only)
|
||||
|
||||
Enterprise organization owners can block specific models or entire providers for all team members using the **Providers & Models** page in the dashboard. The system uses a blocklist approach — everything is allowed by default, and admins explicitly block what should not be accessible.
|
||||
|
||||
Blocking a provider blocks all current and future models from that provider. Filters are available for:
|
||||
|
||||
- Data policy (trains on prompts, retains prompts)
|
||||
- Provider location / datacenter region
|
||||
- Specific model ID
|
||||
|
||||
Only **Owners** can modify model access controls. Individual members cannot override organization-level restrictions.
|
||||
|
||||
**Where to configure:** Dashboard → Providers and Models (Enterprise only). See [Model Access Controls](/docs/collaborate/enterprise/model-access-controls).
|
||||
|
||||
**How it helps:** Prevents accidental use of high-cost frontier models; enforces data residency or compliance requirements; limits cost surface by allowing only approved models.
|
||||
|
||||
### Shared credit pool and auto top-up
|
||||
|
||||
All organization members draw from a single shared credit balance. Administrators can configure:
|
||||
|
||||
- **Auto top-up:** Automatically replenish credits when the balance drops below a threshold (minimum $50 balance, minimum $100 purchase)
|
||||
- **Minimum balance alerts:** Email notifications when the balance drops below a configured amount
|
||||
|
||||
**Where to configure:** Dashboard → Billing.
|
||||
|
||||
### Usage analytics
|
||||
|
||||
The **Usage** tab of the organization dashboard provides:
|
||||
|
||||
- Total spend, request count, average cost per request, total tokens, and active users for any selected time period (past week, month, year, or all time)
|
||||
- Usage broken down by day, by model and day, or by project
|
||||
- Per-user attribution — individual usage statistics visible to Owners and Admins
|
||||
|
||||
This gives administrators visibility into which team members, models, and projects are driving the majority of spend.
|
||||
|
||||
**Where to access:** [app.kilo.ai](https://app.kilo.ai) → Usage tab.
|
||||
|
||||
### Administrative permissions
|
||||
|
||||
Dashboard administrative actions (model restrictions, spending limits, billing management) are gated by role. Only **Owners** can modify model access controls and organization-level settings. **Owners and Admins** can view per-user usage data.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Configurations
|
||||
|
||||
### Cost-conscious individual developer
|
||||
|
||||
- Use `kilo-auto/efficient` as the default model
|
||||
- Switch to `kilo-auto/free` for low-stakes questions and exploration
|
||||
- Enable auto-compaction (on by default); set `compaction.threshold_percent: 80` to compact earlier
|
||||
- Set Code agent max output tokens to 16k or below
|
||||
- Keep `doom_loop` permission at `ask`
|
||||
- Start a new session whenever you switch to an unrelated task
|
||||
- Use `@file` mentions with specific paths instead of `@folder` for whole directories
|
||||
- Disable any MCP servers you are not actively using
|
||||
|
||||
### Developer working on a large repository
|
||||
|
||||
- Use Architect mode for initial codebase exploration — it cannot modify code, keeping exploration cost lower
|
||||
- Use `@file` mentions with specific paths instead of attaching whole directories
|
||||
- Add generated and build directories to permission deny rules (`coverage/**`, `.next/**`, etc.)
|
||||
- Configure a cheap model for compaction (`anthropic/claude-haiku-4-5` or equivalent)
|
||||
- Consider using a model with a large context window (256K+) for cross-file analysis tasks
|
||||
- Break large tasks into focused sub-tasks rather than asking for a single comprehensive change
|
||||
|
||||
### Team using multiple models
|
||||
|
||||
- Assign `kilo-auto/efficient` to Code and Debug agents for everyday work
|
||||
- Assign `kilo-auto/frontier` to Architect (or Plan) agent for planning tasks
|
||||
- Set `kilo-auto/efficient` as the compaction model for all agents
|
||||
- If on an Enterprise plan, use Providers & Models to block high-cost models that are not needed for your team's typical work
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agent": {
|
||||
"code": { "model": "kilo-auto/efficient" },
|
||||
"debug": { "model": "kilo-auto/efficient" },
|
||||
"architect": { "model": "kilo-auto/frontier" },
|
||||
"compaction": { "model": "anthropic/claude-haiku-4-5" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Maximum-constraint starter configuration
|
||||
|
||||
The snippet below is a ready-to-copy `kilo.jsonc` that turns on every available cost-control knob at its most restrictive setting. Drop it into your project root (or your global `~/.config/kilo/kilo.jsonc`) and adjust individual values upward as you get comfortable with how each one behaves.
|
||||
|
||||
{% callout type="tip" %}
|
||||
This configuration uses only `kilo-auto/efficient`.
|
||||
{% /callout %}
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"$schema": "https://app.kilo.ai/config.json",
|
||||
|
||||
// ── Model selection ──────────────────────────────────────────────────────
|
||||
// Route all requests through the two lowest-cost Kilo Auto tiers.
|
||||
// kilo-auto/efficient: lowest-cost paid tier (classifies each request by
|
||||
// difficulty and routes to the cheapest benchmark-proven model).
|
||||
"model": "kilo-auto/efficient",
|
||||
"subagent_model": "kilo-auto/efficient", // default model for Task-tool subagents
|
||||
|
||||
// ── Per-agent model and step limits ─────────────────────────────────────
|
||||
// Assign the cheapest suitable tier to each agent and cap how many
|
||||
// agentic iterations it may take before it must produce a text-only reply.
|
||||
// Raise `steps` for agents that need more room; lower it to tighten cost.
|
||||
"agent": {
|
||||
"code": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 20 // hard cap on agentic iterations per turn
|
||||
},
|
||||
"plan": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 10
|
||||
},
|
||||
"debug": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 20
|
||||
},
|
||||
"ask": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 5
|
||||
},
|
||||
"orchestrator": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 10
|
||||
},
|
||||
"explore": {
|
||||
"model": "kilo-auto/free",
|
||||
"steps": 15
|
||||
},
|
||||
"general": {
|
||||
"model": "kilo-auto/efficient",
|
||||
"steps": 15
|
||||
},
|
||||
// Dedicated agents for background summarization
|
||||
"compaction": { "model": "kilo-auto/free" },
|
||||
"title": { "model": "kilo-auto/free" },
|
||||
"summary": { "model": "kilo-auto/free" }
|
||||
},
|
||||
|
||||
// ── Compaction (context management) ─────────────────────────────────────
|
||||
// Auto-compact aggressively to keep conversation history short and cheap.
|
||||
"compaction": {
|
||||
"auto": true, // enable automatic compaction (default: true)
|
||||
"threshold_percent": 50, // compact when context reaches 50% full (default: ~80%)
|
||||
"prune": true, // prune old tool outputs to recover context space
|
||||
"tail_turns": 1, // keep only 1 recent user-turn verbatim after compaction
|
||||
"preserve_recent_tokens": 2000, // cap on tokens preserved verbatim from recent turns
|
||||
"reserved": 8000 // token buffer reserved so compaction itself doesn't overflow
|
||||
},
|
||||
|
||||
// ── Tool output truncation ───────────────────────────────────────────────
|
||||
// Clip large tool responses early so they don't bloat the context window.
|
||||
// Increase these if the agent needs more output (e.g. long test logs).
|
||||
"tool_output": {
|
||||
"max_lines": 500, // default: 2000 lines
|
||||
"max_bytes": 10240 // default: 51200 bytes (~50 KB)
|
||||
},
|
||||
|
||||
// ── Permission safeguards ────────────────────────────────────────────────
|
||||
// "ask" means Kilo pauses and requires your approval before executing.
|
||||
// This prevents runaway loops from autonomously consuming tokens or making
|
||||
// irreversible changes. Flip individual entries to "allow" once you trust them.
|
||||
"permission": {
|
||||
"bash": "ask", // shell commands (highest risk of runaway cost)
|
||||
"edit": "ask", // file writes and edits
|
||||
"task": "ask", // launching sub-agents (each sub-agent = extra LLM requests)
|
||||
"webfetch": "ask", // outbound HTTP fetches
|
||||
"websearch": "ask", // web search calls
|
||||
"doom_loop": "ask" // repeated-failure loop detection — always keep at "ask" or "deny"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Every field in this block is documented in the sections above. Use it as a starting point, then relax individual settings (for example, setting `permission.edit` to `"allow"` for a trusted project, or raising `compaction.threshold_percent` to `70` if compaction feels too aggressive) as you build confidence in how the agent behaves.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Unexpected Usage
|
||||
|
||||
If your spend is higher than expected:
|
||||
|
||||
- **Check your usage dashboard** at [app.kilo.ai/usage](https://app.kilo.ai/usage) for a breakdown by day, model, and project
|
||||
- **Review the model in use** — an accidental switch to a frontier model for routine tasks can significantly raise costs
|
||||
- **Look for long sessions** — sessions that were never compacted carry their full history as input tokens on every request; use `/compact` to reset them
|
||||
- **Check MCP server configuration** — unused MCP servers add tool definitions to every system prompt
|
||||
- **Review permission settings** — auto-approving all actions with no `doom_loop` guard removes the friction that normally slows down runaway loops
|
||||
|
||||
For further reading: [4 Levers to Take Control of Your AI Spend](https://blog.kilo.ai/p/4-spend-levers)
|
||||
|
||||
## Related
|
||||
|
||||
- [Cost Efficiency & Model Selection](/docs/getting-started/rate-limits-and-costs) — Auto Model tier comparison, rate limits, and per-request cost calculation
|
||||
- [Auto Model](/docs/code-with-ai/agents/auto-model) — Full details on each Auto Model tier and routing strategy
|
||||
- [Context Condensing](/docs/customize/context/context-condensing) — How compaction works and all configuration options
|
||||
- [Auto-Approving Actions](/docs/getting-started/settings/auto-approving-actions) — Permission system reference for VS Code and CLI
|
||||
- [Model Access Controls](/docs/collaborate/enterprise/model-access-controls) — Enterprise model and provider blocklist configuration
|
||||
- [Usage & Billing](/docs/gateway/usage-and-billing) — Gateway billing mechanics and organization controls
|
||||
@@ -1,51 +1,96 @@
|
||||
# Rate Limits and Costs
|
||||
---
|
||||
title: "Cost Efficiency & Model Selection"
|
||||
description: "How to choose the right Auto Model tier and reduce token spend in Kilo Code"
|
||||
---
|
||||
|
||||
Understanding and managing API usage is crucial for a smooth and cost-effective experience with Kilo Code. This section explains how to track your token usage, costs, and how to configure rate limits.
|
||||
# Cost Efficiency & Model Selection
|
||||
|
||||
## Token Usage
|
||||
Kilo routes your requests through its gateway, and your costs primarily depend on the model you use. The single most effective way to control spend is to pick the right Auto Model tier for each job — and to keep your context lean.
|
||||
|
||||
Kilo Code interacts with AI models using tokens. Tokens are essentially pieces of words. The number of tokens used in a request and response affects both the processing time and the cost.
|
||||
## Understanding Auto Models
|
||||
|
||||
- **Input Tokens:** These are the tokens in your prompt, including the system prompt, your instructions, and any context provided (e.g., file contents).
|
||||
- **Output Tokens:** These are the tokens generated by the AI model in its response.
|
||||
Auto Model is Kilo's smart routing system. Instead of selecting a specific provider model yourself, you choose a tier that matches your performance and budget needs. Each tier uses its own routing strategy under the hood.
|
||||
|
||||
You can see the number of input and output tokens used for each interaction in the chat history.
|
||||
| Tier | Name | Best For | Cost |
|
||||
|---|---|---|---|
|
||||
| `kilo-auto/frontier` | Auto Frontier | Maximum capability — routes to top-tier models for planning/architect/debug and high-quality models for coding | Paid (highest) |
|
||||
| `kilo-auto/balanced` | Auto Balanced | Strong performance at a predictably lower cost — routes every request to one fixed high-quality model | Paid |
|
||||
| `kilo-auto/efficient` | Auto Efficient | Lowest cost per task — classifies each request by difficulty and routes to the cheapest benchmark-proven model for that task | Paid (lowest) |
|
||||
| `kilo-auto/free` | Auto Free | No credits required — rotates through available free models | Free |
|
||||
|
||||
## Cost Calculation
|
||||
{% callout type="info" title="Live model assignments" %}
|
||||
The underlying models behind each tier are updated server-side as better options become available or as providers change pricing. See [kilo.ai/models](https://kilo.ai/models) for current model assignments and live pricing.
|
||||
{% /callout %}
|
||||
|
||||
Most AI providers charge based on the number of tokens used. Pricing varies depending on the provider and the specific model.
|
||||
## Balanced vs Efficient — What's the Difference?
|
||||
|
||||
Kilo Code automatically calculates the estimated cost of each API request based on the configured model's pricing. This cost is displayed in the chat history, next to the token usage.
|
||||
Both tiers are paid, but they optimize for different things.
|
||||
|
||||
**Note:**
|
||||
**Auto Balanced** routes every request to a single, fixed high-quality model. You get consistent, strong results with predictable cost — a reliable default for most developers.
|
||||
|
||||
- The cost calculation is an _estimate_. The actual cost may vary slightly depending on the provider's billing practices.
|
||||
- Some providers may offer free tiers or credits. Check your provider's documentation for details.
|
||||
- Some providers offer prompt caching which greatly lowers cost.
|
||||
**Auto Efficient** goes further. It observes your coding session in context, classifies the difficulty of each request in real time, and routes it to the *cheapest model proven accurate enough* for that specific task, based on Kilo's continuously running benchmarks. Routine tasks (small edits, lookups, quick explanations) are handled by leaner models; harder tasks (architecture, debugging, complex refactors) automatically get a more capable model.
|
||||
|
||||
## Configuring Rate Limits
|
||||
Efficient is also session-aware: it stays with a model across related turns and only switches when a cheaper option is clearly worth it. If it cannot make a routing decision with confidence, it falls back to Balanced — so quality never drops below Balanced.
|
||||
|
||||
To prevent accidental overuse of the API and to help you manage costs, Kilo Code allows you to set a rate limit. The rate limit specifies the minimum time (in seconds) between API requests.
|
||||
Think of Efficient as Balanced with an intelligent cost optimizer layered on top.
|
||||
|
||||
**How to configure:**
|
||||
{% callout type="tip" %}
|
||||
For everyday coding tasks, start with **Auto Efficient** or **Auto Balanced**. Switch to **Auto Frontier** for complex architecture sessions or deep debugging where maximum capability matters.
|
||||
{% /callout %}
|
||||
|
||||
1. Open the Kilo Code settings ({% codicon name="gear" /%} icon in the top right corner).
|
||||
2. Go to the "Advanced Settings" section.
|
||||
3. Find the "Rate Limit (seconds)" setting.
|
||||
4. Enter the desired delay in seconds. A value of 0 disables rate limiting.
|
||||
## How to Switch Auto Models
|
||||
|
||||
**Example:**
|
||||
|
||||
If you set the rate limit to 10 seconds, Kilo Code will wait at least 10 seconds after one API request completes before sending the next one.
|
||||
Open the model selector dropdown in the Kilo Code chat interface and choose the tier you want. No other configuration is needed; routing happens automatically from that point forward.
|
||||
|
||||
## Tips for Optimizing Token Usage
|
||||
|
||||
- **Be Concise:** Use clear and concise language in your prompts. Avoid unnecessary words or details.
|
||||
- **Provide Only Relevant Context:** Use context mentions (`@file.ts`, `@folder/`) selectively. Only include the files that are directly relevant to the task.
|
||||
- **Break Down Tasks:** Divide large tasks into smaller, more focused sub-tasks.
|
||||
- **Use Custom Instructions:** Provide custom instructions to guide Kilo Code's behavior and reduce the need for lengthy explanations in each prompt.
|
||||
- **Choose the Right Model:** Some models are more cost-effective than others. Consider using a smaller, faster model for tasks that don't require the full power of a larger model.
|
||||
- **Use Modes:** Different modes can access different tools, for example `Architect` can't modify code, which makes it a safe choice when analyzing a complex codebase, without worrying about accidentally allowing expensive operations.
|
||||
- **Disable MCP If Not Used:** If you're not using MCP (Model Context Protocol) features, consider [disabling it in Settings > Agent Behaviour > MCP Servers](/docs/automate/mcp/overview) to significantly reduce the size of the system prompt and save tokens.
|
||||
### Choose the right context
|
||||
|
||||
By understanding and managing your API usage, you can use Kilo Code effectively and efficiently.
|
||||
- **Be concise.** Clear, focused prompts cost fewer tokens than lengthy ones.
|
||||
- **Provide only relevant context.** Use `@file` and `@folder` mentions selectively — include only what is directly relevant to the current task.
|
||||
- **Break down large tasks.** Smaller, focused sub-tasks are cheaper per-turn and easier for the model to answer precisely.
|
||||
- **Use custom instructions.** Encode recurring guidance in your custom instructions once, instead of repeating it in every prompt.
|
||||
|
||||
### Use modes appropriately
|
||||
|
||||
- **Architect mode** cannot modify code, making it a safe and cost-effective choice for analysing a codebase without risking unintended changes.
|
||||
- **Debug mode** is optimized for diagnosis — use it when tracking down a specific problem rather than for general exploration.
|
||||
|
||||
### Context condensing
|
||||
|
||||
When a conversation grows long, use `/compact` (also searchable as `smol` or `condense`) to summarize the history and free up context space. You can also enable **auto-compaction** in **Settings → Context** so Kilo compacts automatically when approaching the context limit, without any manual intervention.
|
||||
|
||||
### Max tokens for thinking models
|
||||
|
||||
Every token you allocate to model output reduces how much conversation history can remain in the window. Consider keeping Code mode at 16k max output tokens or below, and raising the limit only in Architect or Debug modes where extended reasoning is genuinely useful.
|
||||
|
||||
### Disable unused MCP servers
|
||||
|
||||
If you are not using MCP (Model Context Protocol) features, consider [disabling MCP Servers in Settings → Agent Behaviour](/docs/automate/mcp/overview). This significantly reduces the size of the system prompt sent with every request.
|
||||
|
||||
### Prompt caching
|
||||
|
||||
Kilo automatically applies prompt caching on supported providers. Repeated context, such as your system prompt and stable file contents, is reused from cache at a discounted rate. No action is required to benefit from this.
|
||||
|
||||
## Rate Limits
|
||||
|
||||
- **Free models** (`kilo-auto/free`): 200 requests per hour per IP.
|
||||
- **Paid models**: Kilo does not impose gateway-level rate limits on paid traffic. However, [org-level per-user daily spending limits](/docs/gateway/usage-and-billing) and upstream provider rate limits can still apply.
|
||||
|
||||
|
||||
## How Costs Are Calculated
|
||||
|
||||
- Costs are a pass-through of provider pricing with no general markup.
|
||||
- Kilo calculates an estimated cost for each request based on configured pricing. This estimate is shown per-request in the chat history.
|
||||
- Cache hits are billed at a discounted rate compared to regular input tokens.
|
||||
- Requests using **Auto Free** models are billed at $0 on Kilo's side.
|
||||
- **BYOK (Bring Your Own Key)** requests are billed at $0 on Kilo's side — you pay the provider directly.
|
||||
|
||||
For current pricing, visit [kilo.ai/models](https://kilo.ai/models).
|
||||
|
||||
## Related
|
||||
|
||||
- [Auto Model](/docs/code-with-ai/agents/auto-model) — Full details on each Auto Model tier
|
||||
- [Context Condensing](/docs/customize/context/context-condensing) — How compaction works and how to configure it
|
||||
- [Using Kilo for Free](/docs/getting-started/using-kilo-for-free) — Getting started without spending credits
|
||||
- [Bring Your Own Key (BYOK)](/docs/getting-started/byok) — Use your own provider API keys
|
||||
|
||||
@@ -224,6 +224,7 @@ Available experimental settings include:
|
||||
- **Paste summary** - summarize large clipboard pastes before including them
|
||||
- **Batch tool** - allow the agent to batch multiple tool calls in one step
|
||||
- **OpenTelemetry** - enable Kilo telemetry and optional OTLP export when configured
|
||||
- **Sandbox** - confine agent shell commands and file writes to the project and Kilo state directories, with optional outbound network blocking. See [Sandboxing](/docs/getting-started/settings/sandboxing).
|
||||
|
||||
Advanced options not exposed in the UI can be configured via the `experimental` key in `kilo.jsonc`:
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: "Sandboxing"
|
||||
description: "Confine agent shell commands and file writes with the experimental OS-level sandbox"
|
||||
---
|
||||
|
||||
# Sandboxing
|
||||
|
||||
The experimental sandbox runs agent shell commands and file-tool writes inside an OS-level sandbox that restricts filesystem writes to your project and Kilo state directories, and can block outbound network access from model-originated commands. It is an extra guardrail on top of the permission system: even if the agent is allowed to run a command, the operating system will deny writes outside the allowed roots.
|
||||
|
||||
{% callout type="warning" %}
|
||||
Sandboxing is experimental. Behavior may change between releases, and it is not available on Windows.
|
||||
{% /callout %}
|
||||
|
||||
## How it works
|
||||
|
||||
When enabled, the agent's shell commands and file-write tools run confined to a small set of writable directories:
|
||||
|
||||
- Your **project directory** (and its worktree, when running in a linked git worktree)
|
||||
- Kilo **state directories**: data, cache, config, state, tmp, bin, log, and repos
|
||||
|
||||
Everything else is denied at the OS level. File **reads are not confined** — the agent can still read anywhere it has permission to. The `.git` directory is always denied for writes, regardless of location.
|
||||
|
||||
When network restriction is on (the default), outbound network access is blocked for:
|
||||
|
||||
- Shell commands originated by the model
|
||||
- First-party HTTP tools (for example web fetch and browser tools)
|
||||
|
||||
The following are **not** affected by the network restriction:
|
||||
|
||||
- **Provider and model inference traffic** — your LLM API calls keep working
|
||||
- **Local MCP servers and plugin hooks** — these run outside the restriction
|
||||
|
||||
## Enable the sandbox
|
||||
|
||||
The sandbox is off by default. Enable it under the `experimental` key in `kilo.jsonc`:
|
||||
|
||||
```json
|
||||
{
|
||||
"experimental": {
|
||||
"sandbox": true,
|
||||
"sandbox_restrict_network": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Default | Effect |
|
||||
|---|---|---|
|
||||
| `experimental.sandbox` | `false` | Turn the sandbox on. When `false`, no confinement applies. |
|
||||
| `experimental.sandbox_restrict_network` | `true` | Block outbound network from model-originated commands and HTTP tools. Set to `false` to allow network (filesystem confinement still applies). |
|
||||
|
||||
You can also enable it from the VS Code Settings webview: gear icon ({% codicon name="gear" /%}) → **Experimental** → **Sandbox**. Once the sandbox is on, a dedicated **Sandboxing** tab appears with the **Restrict Network Access** switch for `sandbox_restrict_network`.
|
||||
|
||||
## Toggle per session
|
||||
|
||||
Enabling `experimental.sandbox` sets the default for new sessions, but the setting is ephemeral per session and can be flipped without editing config:
|
||||
|
||||
- **VS Code**: a sandbox toggle appears in the prompt input when `experimental.sandbox` is on (not available for cloud sessions). The tooltip shows whether filesystem writes and network are restricted.
|
||||
- **CLI / TUI**: run the `/sandbox` slash command or the **Toggle sandbox** palette command. A `◆ Sandbox on` indicator appears next to the prompt when active.
|
||||
|
||||
Toggling is in-memory and scoped to the current session, so it does not persist across restarts. If the OS sandbox backend is unavailable on your platform, the toggle reports the reason and confinement stays off.
|
||||
|
||||
## Platform support
|
||||
|
||||
| Platform | Backend | Notes |
|
||||
|---|---|---|
|
||||
| macOS | `sandbox-exec` (seatbelt) | Uses the system `/usr/bin/sandbox-exec`. |
|
||||
| Linux | Bubblewrap (`bwrap`) | Uses system `/usr/bin/bwrap`, or a bundled, SHA-256-verified binary. Override the path with the `KILO_BWRAP_PATH` environment variable. The executable is probed at startup to confirm it can create the sandbox. |
|
||||
| Windows | none | The sandbox backend is unavailable on Windows. Enabling the config has no effect. |
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Windows is not supported.**
|
||||
- Local MCP servers and plugin hooks are **not** covered by the network restriction.
|
||||
- File **reads** are not confined — only writes and shell command effects are.
|
||||
- Writable file handles are unavailable while the sandbox is active; writes are performed through a sandboxed worker, so some tools that open files for writing may behave differently.
|
||||
- The sandbox is additive to the permission system, not a replacement. Permission rules still apply first.
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:af33f5d026513422db6efc37848eec76d9da511432e5933606ae0be73da684f8
|
||||
size 16675
|
||||
oid sha256:6ee59e48c176043eee3b22441ce1c50e8d17dbafe58e969cfc8e97f404f2608d
|
||||
size 17429
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:da91a2dd21f1b647d3d7e95756755d5e8357bbba7f964f328d1f58363990e2cd
|
||||
size 12377
|
||||
oid sha256:e2b861de27fb8e6d64becd50bb4b3b05d748fba74b98aafaf5cb2a182ff74655
|
||||
size 26259
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:79039cc251eaee4b01ad5eace1bf9fc28a85184fb98695694cc6f3c93e734813
|
||||
size 177
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:79039cc251eaee4b01ad5eace1bf9fc28a85184fb98695694cc6f3c93e734813
|
||||
size 177
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:79039cc251eaee4b01ad5eace1bf9fc28a85184fb98695694cc6f3c93e734813
|
||||
size 177
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:79039cc251eaee4b01ad5eace1bf9fc28a85184fb98695694cc6f3c93e734813
|
||||
size 177
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a093b9658cc15d0789da5afebde7163ec51e743af59975e2a031aed3e9144d56
|
||||
size 22336
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0b20e8e50b583cc6a884e08648a9f1efcdfc2a9561b97145811ebc9c24d244fd
|
||||
size 23100
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3b24b0d2694d2eeec0ea4cd827bd3a61bb47150605b838b43e4f422c9b960f0e
|
||||
size 29744
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd27610a2518018c16e4227728221ed9bf67a7d3c8ab207b2835dc60964ec63d
|
||||
size 33323
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8ad46cc736472c6a2a46bb80e6622333f49960e74dcb6782d35aa72fa32378c
|
||||
size 23725
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:61b1d0bc725e3b33a40d1d777d71b70afcec1b6cdcfae15e2023667bc4574f23
|
||||
size 17201
|
||||
oid sha256:6f05d9512bbe3309c6d073fd8aca8e0800c7e2827bdefe6115e636e8a6e94070
|
||||
size 16239
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6eb9d7670f55c5529dce90d11fceb5c9da7a0d3a5f7270fdfd27e66ca1f3d72f
|
||||
size 9851
|
||||
oid sha256:36101257010ff15372b8e2b7ace1b5128ecc820ce5ca4111ff1ba7905473b0b4
|
||||
size 19407
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:45d2e8b0e2a5dd7a40ec5c0b5ab4acee6035ede90135980038628e98e3478cd9
|
||||
size 682
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4a7bcef3102838812625393f0cead3a10067ae32e67dd3f174d0e74d03116c8c
|
||||
size 54735
|
||||
oid sha256:cca305368e62ec5b45c8b20bc5d4921e0ca8df1c54eb110efffe188837400b95
|
||||
size 57533
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9a681b7c8866aa3aa6f1e8673afcb5efb79d3a251ba46b3c7201e22dcc77b9c2
|
||||
size 55898
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:47770a3c0f31c816f0dc21fc75dc9c591209c7599e3f69df31f5b1e267546c62
|
||||
size 1167
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6c000d3be4d59f1baf63415abecfe1ffb470ef3e9068876fd5c0d1ee0b12f6c0
|
||||
size 1336
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b197d749f21df8d3061b93d13281a346b52514bec1b6855b474a03cfaeeb117b
|
||||
size 2500
|
||||
@@ -123,10 +123,15 @@
|
||||
<!-- packages/opencode/src/cli/cmd/providers.ts -->
|
||||
- <https://kilo.ai/docs/ai-providers#custom-provider>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx -->
|
||||
- <https://kilo.ai/docs/automate/mcp/what-is-mcp>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/marketplace/InstallModal.tsx -->
|
||||
- <https://kilo.ai/docs/code-with-ai/platforms/vscode/whats-new>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx -->
|
||||
- <https://kilo.ai/docs/customize/custom-subagents>
|
||||
<!-- packages/opencode/src/config/config.ts -->
|
||||
- <https://kilo.ai/docs/customize/marketplace>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/marketplace/InstallModal.tsx -->
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/marketplace/MarketplaceListView.tsx -->
|
||||
- <https://kilo.ai/docs/customize/workflows>
|
||||
<!-- packages/opencode/src/config/config.ts -->
|
||||
- <https://kilo.ai/gateway>
|
||||
@@ -188,6 +193,8 @@
|
||||
<!-- packages/opencode/src/provider/transform.ts -->
|
||||
- <https://vercel.link/ai-gateway-token>
|
||||
<!-- packages/opencode/src/cli/cmd/providers.ts -->
|
||||
- <https://www.anaconda.com/products/desktop>
|
||||
<!-- packages/opencode/src/kilocode/anaconda-desktop/domain.ts -->
|
||||
- <https://www.eclipse.org/downloads/download.php?file=/jdtls/snapshots/jdt-language-server-latest.tar.gz>
|
||||
<!-- packages/opencode/src/lsp/server.ts -->
|
||||
- <https://www.googleapis.com/auth/cloud-platform>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { buildKiloHeaders } from "../headers.js"
|
||||
import type { KiloPassState } from "../types.js"
|
||||
import { KILO_API_BASE } from "./constants.js"
|
||||
|
||||
function record(value: unknown) {
|
||||
return value !== null && typeof value === "object" ? (value as Record<string, unknown>) : undefined
|
||||
}
|
||||
|
||||
function num(value: unknown) {
|
||||
return typeof value === "number" && Number.isFinite(value) ? value : 0
|
||||
}
|
||||
|
||||
export function parseKiloPassState(value: unknown): KiloPassState | null {
|
||||
const item = Array.isArray(value) ? value[0] : value
|
||||
const data = record(record(record(item)?.result)?.data)
|
||||
const root = record(data?.json) ?? data ?? record(value)
|
||||
const sub = record(root?.subscription)
|
||||
if (!sub || (sub.currentPeriodBaseCreditsUsd == null && sub.currentPeriodUsageUsd == null)) return null
|
||||
|
||||
const next = sub.nextBillingAt ?? sub.nextRenewalAt
|
||||
return {
|
||||
currentPeriodBaseCreditsUsd: num(sub.currentPeriodBaseCreditsUsd),
|
||||
currentPeriodUsageUsd: num(sub.currentPeriodUsageUsd),
|
||||
currentPeriodBonusCreditsUsd: num(sub.currentPeriodBonusCreditsUsd),
|
||||
nextBillingAt: typeof next === "string" ? next : null,
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchKiloPassState(token: string): Promise<KiloPassState | null> {
|
||||
try {
|
||||
const params = new URLSearchParams({ batch: "1", input: JSON.stringify({ "0": null }) })
|
||||
const response = await fetch(`${KILO_API_BASE}/api/trpc/kiloPass.getState?${params}`, {
|
||||
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", ...buildKiloHeaders() },
|
||||
})
|
||||
if (!response.ok) {
|
||||
console.warn(`Failed to fetch Kilo Pass: ${response.status}`)
|
||||
return null
|
||||
}
|
||||
return parseKiloPassState(await response.json())
|
||||
} catch (err) {
|
||||
console.warn("Error fetching Kilo Pass:", err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,12 @@ const openRouterModelSchema = z.object({
|
||||
isFree: z.boolean().optional(),
|
||||
mayTrainOnYourPrompts: z.boolean().optional(),
|
||||
hasUserByokAvailable: z.boolean().optional(),
|
||||
autoRouting: z
|
||||
.object({
|
||||
models: z.array(z.string()),
|
||||
})
|
||||
.optional()
|
||||
.catch(undefined),
|
||||
terminalBench: z
|
||||
.object({
|
||||
overallScore: z.number(),
|
||||
@@ -194,6 +200,7 @@ function transformToModelDevFormat(model: OpenRouterModel): any {
|
||||
isFree: model.isFree,
|
||||
mayTrainOnYourPrompts: model.mayTrainOnYourPrompts,
|
||||
hasUserByokAvailable: model.hasUserByokAvailable,
|
||||
...(model.autoRouting && { autoRouting: model.autoRouting }),
|
||||
...(model.terminalBench && { terminalBench: model.terminalBench }),
|
||||
...(inputPrice !== undefined &&
|
||||
outputPrice !== undefined && {
|
||||
|
||||
@@ -33,6 +33,7 @@ export {
|
||||
getKiloDefaultModel,
|
||||
promptOrganizationSelection,
|
||||
} from "./api/profile.js"
|
||||
export { fetchKiloPassState } from "./api/kilo-pass.js"
|
||||
export { fetchKiloModels, type KiloModelsResult } from "./api/models.js"
|
||||
export {
|
||||
EMPTY_KILO_EMBEDDING_MODEL_CATALOG,
|
||||
@@ -94,6 +95,7 @@ export type {
|
||||
Organization,
|
||||
KilocodeProfile,
|
||||
KilocodeBalance,
|
||||
KiloPassState,
|
||||
PollOptions,
|
||||
PollResult,
|
||||
// Provider types
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { fetchBalance, fetchProfile } from "../api/profile.js"
|
||||
import { fetchKiloPassState } from "../api/kilo-pass.js"
|
||||
import { fetchKilocodeNotifications } from "../api/notifications.js"
|
||||
import { clearModesCache } from "../api/modes.js"
|
||||
import { HEADER_ORGANIZATIONID, KILO_API_BASE, KILO_CHAT_URL, KILO_EVENT_SERVICE_URL } from "../api/constants.js"
|
||||
import type { KilocodeBalance, KilocodeProfile } from "../types.js"
|
||||
import type { KilocodeBalance, KilocodeProfile, KiloPassState } from "../types.js"
|
||||
import { buildKiloHeaders } from "../headers.js"
|
||||
|
||||
export type KiloAuth =
|
||||
@@ -13,6 +14,7 @@ export type KiloAuth =
|
||||
export interface KiloProfileResult {
|
||||
profile: KilocodeProfile
|
||||
balance: KilocodeBalance | null
|
||||
kiloPass: KiloPassState | null
|
||||
currentOrgId: string | null
|
||||
}
|
||||
|
||||
@@ -67,11 +69,12 @@ export async function getProfile(auth: AuthStore): Promise<KiloProfileResult> {
|
||||
if (!info || info.type !== "oauth") throw new UnauthorizedError("Not authenticated with Kilo Gateway")
|
||||
|
||||
const currentOrgId = info.accountId ?? null
|
||||
const [profile, balance] = await Promise.all([
|
||||
const [profile, balance, kiloPass] = await Promise.all([
|
||||
fetchProfile(info.access),
|
||||
fetchBalance(info.access, currentOrgId ?? undefined),
|
||||
fetchKiloPassState(info.access),
|
||||
])
|
||||
return { profile, balance, currentOrgId }
|
||||
return { profile, balance, kiloPass, currentOrgId }
|
||||
}
|
||||
|
||||
export async function getNotifications(auth: AuthStore) {
|
||||
|
||||
@@ -107,9 +107,17 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
|
||||
balance: z.number(),
|
||||
})
|
||||
|
||||
const KiloPassState = z.object({
|
||||
currentPeriodBaseCreditsUsd: z.number(),
|
||||
currentPeriodUsageUsd: z.number(),
|
||||
currentPeriodBonusCreditsUsd: z.number(),
|
||||
nextBillingAt: z.string().nullable().optional(),
|
||||
})
|
||||
|
||||
const ProfileWithBalance = z.object({
|
||||
profile: Profile,
|
||||
balance: Balance.nullable(),
|
||||
kiloPass: KiloPassState.nullable(),
|
||||
currentOrgId: z.string().nullable(),
|
||||
})
|
||||
|
||||
|
||||
@@ -33,6 +33,13 @@ export interface KilocodeBalance {
|
||||
balance: number
|
||||
}
|
||||
|
||||
export interface KiloPassState {
|
||||
currentPeriodBaseCreditsUsd: number
|
||||
currentPeriodUsageUsd: number
|
||||
currentPeriodBonusCreditsUsd: number
|
||||
nextBillingAt?: string | null
|
||||
}
|
||||
|
||||
export interface PollOptions<T> {
|
||||
interval: number
|
||||
maxAttempts: number
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { parseKiloPassState } from "../../src/api/kilo-pass"
|
||||
|
||||
describe("parseKiloPassState", () => {
|
||||
test("parses batched tRPC subscription data", () => {
|
||||
const state = parseKiloPassState([
|
||||
{
|
||||
result: {
|
||||
data: {
|
||||
json: {
|
||||
subscription: {
|
||||
tier: "tier_199",
|
||||
currentPeriodBaseCreditsUsd: 199,
|
||||
currentPeriodUsageUsd: 73.27,
|
||||
currentPeriodBonusCreditsUsd: 99.5,
|
||||
nextBillingAt: "2026-07-01T00:00:00.000Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
expect(state).toEqual({
|
||||
currentPeriodBaseCreditsUsd: 199,
|
||||
currentPeriodUsageUsd: 73.27,
|
||||
currentPeriodBonusCreditsUsd: 99.5,
|
||||
nextBillingAt: "2026-07-01T00:00:00.000Z",
|
||||
})
|
||||
})
|
||||
|
||||
test("parses plain subscription payload", () => {
|
||||
const state = parseKiloPassState([
|
||||
{
|
||||
result: {
|
||||
data: {
|
||||
subscription: {
|
||||
tier: "tier_199",
|
||||
status: "active",
|
||||
currentPeriodBaseCreditsUsd: 199,
|
||||
currentPeriodUsageUsd: 0.01,
|
||||
currentPeriodBonusCreditsUsd: 29.85,
|
||||
isBonusUnlocked: false,
|
||||
nextBillingAt: "2026-07-20T09:30:20.806Z",
|
||||
},
|
||||
isEligibleForFirstMonthPromo: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
expect(state).toEqual({
|
||||
currentPeriodBaseCreditsUsd: 199,
|
||||
currentPeriodUsageUsd: 0.01,
|
||||
currentPeriodBonusCreditsUsd: 29.85,
|
||||
nextBillingAt: "2026-07-20T09:30:20.806Z",
|
||||
})
|
||||
})
|
||||
|
||||
test("returns null without period amounts", () => {
|
||||
expect(parseKiloPassState({ status: "none" })).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -42,6 +42,25 @@ const VALID_BENCH_RESPONSE = JSON.stringify({
|
||||
],
|
||||
})
|
||||
|
||||
const VALID_AUTO_ROUTING_RESPONSE = JSON.stringify({
|
||||
data: [
|
||||
{
|
||||
id: "kilo-auto/efficient",
|
||||
name: "Kilo Auto Efficient",
|
||||
context_length: 128000,
|
||||
max_completion_tokens: 16384,
|
||||
architecture: {
|
||||
input_modalities: ["text"],
|
||||
output_modalities: ["text"],
|
||||
},
|
||||
supported_parameters: ["tools", "temperature"],
|
||||
autoRouting: {
|
||||
models: ["google/gemini-2.5-flash", "anthropic/claude-sonnet-4.6"],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const INVALID_BENCH_RESPONSE = JSON.stringify({
|
||||
data: [
|
||||
{
|
||||
@@ -174,6 +193,26 @@ test("preserves Terminal Bench metadata as a dedicated model field", async () =>
|
||||
})
|
||||
})
|
||||
|
||||
test("preserves Auto Efficient routing metadata as a dedicated model field", async () => {
|
||||
const orig = globalThis.fetch
|
||||
stubFetch(
|
||||
async () =>
|
||||
new Response(VALID_AUTO_ROUTING_RESPONSE, {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
)
|
||||
|
||||
const result = await fetchKiloModels({})
|
||||
|
||||
;(globalThis as any).fetch = orig
|
||||
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(result.models["kilo-auto/efficient"].autoRouting).toEqual({
|
||||
models: ["google/gemini-2.5-flash", "anthropic/claude-sonnet-4.6"],
|
||||
})
|
||||
})
|
||||
|
||||
test("omits malformed Terminal Bench metadata without rejecting the catalog", async () => {
|
||||
const orig = globalThis.fetch
|
||||
stubFetch(
|
||||
|
||||
Generated
+20
@@ -42,6 +42,24 @@ export const dict = {
|
||||
"marketplace.install.scope": "النطاق",
|
||||
"marketplace.install.scope.project": "المشروع",
|
||||
"marketplace.install.scope.global": "عالمي",
|
||||
"marketplace.install.scope.project.description":
|
||||
"هذا المشروع فقط. يمكن إضافة الملفات المثبتة إلى نظام التحكم في الإصدارات ومشاركتها مع فريقك.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"جميع المشاريع على هذا الجهاز. تُحفظ في إعدادات المستخدم الخاصة بك.",
|
||||
"marketplace.install.destination": "وجهة التثبيت",
|
||||
"marketplace.install.about.mcp":
|
||||
"يمنح خادم MCP منصة Kilo أدوات إضافية للعمل مع الخدمات الخارجية أو البرامج المحلية.",
|
||||
"marketplace.install.about.agent": "يضيف الوكيل دورًا قابلاً لإعادة الاستخدام بتعليماته وأذوناته الخاصة.",
|
||||
"marketplace.install.about.skill": "تضيف المهارة تعليمات وموارد خاصة بمهام معينة يمكن لـ Kilo تحميلها عند الحاجة.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"يمكن لخوادم MCP تشغيل أوامر محلية أو الاتصال بخدمات خارجية. ستطلب Kilo الإذن قبل استخدام أدواتها ما لم تسمح أذوناتك بذلك تلقائيًا.",
|
||||
"marketplace.install.project.warning":
|
||||
"قد تُضاف ملفات المشروع إلى نظام التحكم في الإصدارات. لا تخزّن الأسرار هنا إلا إذا كان الإعداد يشير إلى متغير بيئة.",
|
||||
"marketplace.install.learnMore": "تعرّف على كيفية عمل عمليات التثبيت من Marketplace",
|
||||
"marketplace.install.learnMcp": "معرفة المزيد عن MCP",
|
||||
"marketplace.install.installedAt": "تم التثبيت في {{path}}",
|
||||
"marketplace.intro": "ثبّت وكلاء ومهارات وأدوات MCP قابلة لإعادة الاستخدام لمشروع واحد أو لجميع المشاريع.",
|
||||
"marketplace.intro.learnMore": "حول Marketplace",
|
||||
"marketplace.install.prerequisites": "المتطلبات الأساسية",
|
||||
"marketplace.install.installing": "جاري التثبيت...",
|
||||
"marketplace.install.cancel": "إلغاء",
|
||||
@@ -59,7 +77,9 @@ export const dict = {
|
||||
"marketplace.search": "بحث...",
|
||||
"marketplace.filter.all": "جميع العناصر",
|
||||
"marketplace.filter.notInstalled": "غير مثبت",
|
||||
"marketplace.filter.relevant": "ذات صلة بمساحة العمل الخاصة بي",
|
||||
"marketplace.empty": "لم يتم العثور على عناصر",
|
||||
"marketplace.empty.relevant": "لم يتم العثور على عناصر سوق ذات صلة بمساحة العمل هذه.",
|
||||
"marketplace.badge.mcpServer": "خادم MCP",
|
||||
"marketplace.badge.mode": "وضع",
|
||||
"marketplace.card.by": "بواسطة {{author}}",
|
||||
|
||||
Generated
+21
@@ -42,6 +42,25 @@ export const dict = {
|
||||
"marketplace.install.scope": "Escopo",
|
||||
"marketplace.install.scope.project": "Projeto",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Somente este projeto. Os arquivos instalados podem ser adicionados ao controle de versão e compartilhados com sua equipe.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Todos os projetos nesta máquina. Armazenado na sua configuração de usuário.",
|
||||
"marketplace.install.destination": "Destino da instalação",
|
||||
"marketplace.install.about.mcp":
|
||||
"Um servidor MCP fornece ao Kilo ferramentas adicionais para trabalhar com serviços externos ou programas locais.",
|
||||
"marketplace.install.about.agent": "Um agente adiciona uma função reutilizável com instruções e permissões próprias.",
|
||||
"marketplace.install.about.skill":
|
||||
"Uma habilidade adiciona instruções e recursos específicos para tarefas que o Kilo pode carregar quando necessário.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"Servidores MCP podem executar comandos locais ou se conectar a serviços externos. O Kilo solicitará permissão antes de usar suas ferramentas, a menos que suas permissões permitam isso automaticamente.",
|
||||
"marketplace.install.project.warning":
|
||||
"Os arquivos do projeto podem ser adicionados ao controle de versão. Não armazene segredos aqui, a menos que a configuração faça referência a uma variável de ambiente.",
|
||||
"marketplace.install.learnMore": "Saiba como funcionam as instalações do Marketplace",
|
||||
"marketplace.install.learnMcp": "Saiba mais sobre MCP",
|
||||
"marketplace.install.installedAt": "Instalado em {{path}}",
|
||||
"marketplace.intro": "Instale agentes, habilidades e ferramentas MCP reutilizáveis em um projeto ou em todos os projetos.",
|
||||
"marketplace.intro.learnMore": "Sobre o Marketplace",
|
||||
"marketplace.install.prerequisites": "Pré-requisitos",
|
||||
"marketplace.install.installing": "Instalando...",
|
||||
"marketplace.install.cancel": "Cancelar",
|
||||
@@ -59,7 +78,9 @@ export const dict = {
|
||||
"marketplace.search": "Pesquisar...",
|
||||
"marketplace.filter.all": "Todos os Itens",
|
||||
"marketplace.filter.notInstalled": "Não Instalado",
|
||||
"marketplace.filter.relevant": "Relevantes para meu espaço de trabalho",
|
||||
"marketplace.empty": "Nenhum item encontrado",
|
||||
"marketplace.empty.relevant": "Nenhum item relevante do marketplace foi encontrado para este espaço de trabalho.",
|
||||
"marketplace.badge.mcpServer": "Servidor MCP",
|
||||
"marketplace.badge.mode": "Modo",
|
||||
"marketplace.card.by": "por {{author}}",
|
||||
|
||||
Generated
+21
@@ -47,6 +47,25 @@ export const dict = {
|
||||
"marketplace.install.scope": "Opseg",
|
||||
"marketplace.install.scope.project": "Projekat",
|
||||
"marketplace.install.scope.global": "Globalno",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Samo ovaj projekat. Instalirane datoteke mogu se dodati u kontrolu verzija i dijeliti s vašim timom.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Svi projekti na ovom računaru. Čuva se u vašoj korisničkoj konfiguraciji.",
|
||||
"marketplace.install.destination": "Odredište instalacije",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP server pruža Kilu dodatne alate za rad s vanjskim servisima ili lokalnim programima.",
|
||||
"marketplace.install.about.agent": "Agent dodaje višekratnu ulogu s vlastitim uputama i dozvolama.",
|
||||
"marketplace.install.about.skill":
|
||||
"Vještina dodaje upute i resurse za određene zadatke koje Kilo može učitati kada su potrebni.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP serveri mogu pokretati lokalne naredbe ili se povezivati s vanjskim servisima. Kilo će zatražiti dozvolu prije korištenja njihovih alata, osim ako vaše dozvole to automatski dopuštaju.",
|
||||
"marketplace.install.project.warning":
|
||||
"Datoteke projekta mogu se dodati u kontrolu verzija. Ne čuvajte tajne ovdje osim ako konfiguracija upućuje na varijablu okruženja.",
|
||||
"marketplace.install.learnMore": "Saznajte kako funkcionišu instalacije s Marketplacea",
|
||||
"marketplace.install.learnMcp": "Saznajte više o MCP-u",
|
||||
"marketplace.install.installedAt": "Instalirano u {{path}}",
|
||||
"marketplace.intro": "Instalirajte višekratne agente, vještine i MCP alate za jedan ili sve projekte.",
|
||||
"marketplace.intro.learnMore": "O Marketplaceu",
|
||||
"marketplace.install.prerequisites": "Preduslovi",
|
||||
"marketplace.install.installing": "Instalacija...",
|
||||
"marketplace.install.cancel": "Otkaži",
|
||||
@@ -64,7 +83,9 @@ export const dict = {
|
||||
"marketplace.search": "Pretraži...",
|
||||
"marketplace.filter.all": "Sve stavke",
|
||||
"marketplace.filter.notInstalled": "Nije instalirano",
|
||||
"marketplace.filter.relevant": "Relevantno za moj radni prostor",
|
||||
"marketplace.empty": "Nema pronađenih stavki",
|
||||
"marketplace.empty.relevant": "Nisu pronađene relevantne stavke marketplacea za ovaj radni prostor.",
|
||||
"marketplace.badge.mcpServer": "MCP Server",
|
||||
"marketplace.badge.mode": "Režim",
|
||||
"marketplace.card.by": "od {{author}}",
|
||||
|
||||
Generated
+21
@@ -42,6 +42,25 @@ export const dict = {
|
||||
"marketplace.install.scope": "Omfang",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Kun dette projekt. De installerede filer kan føjes til versionsstyring og deles med dit team.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Alle projekter på denne maskine. Gemmes i din brugerkonfiguration.",
|
||||
"marketplace.install.destination": "Installationsplacering",
|
||||
"marketplace.install.about.mcp":
|
||||
"En MCP-server giver Kilo yderligere værktøjer til at arbejde med eksterne tjenester eller lokale programmer.",
|
||||
"marketplace.install.about.agent": "En agent tilføjer en genanvendelig rolle med egne instruktioner og tilladelser.",
|
||||
"marketplace.install.about.skill":
|
||||
"En færdighed tilføjer opgavespecifikke instruktioner og ressourcer, som Kilo kan indlæse efter behov.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-servere kan køre lokale kommandoer eller oprette forbindelse til eksterne tjenester. Kilo beder om tilladelse, før deres værktøjer bruges, medmindre dine tilladelser automatisk tillader det.",
|
||||
"marketplace.install.project.warning":
|
||||
"Projektfiler kan føjes til versionsstyring. Gem ikke hemmeligheder her, medmindre konfigurationen henviser til en miljøvariabel.",
|
||||
"marketplace.install.learnMore": "Se, hvordan installationer fra Marketplace fungerer",
|
||||
"marketplace.install.learnMcp": "Få mere at vide om MCP",
|
||||
"marketplace.install.installedAt": "Installeret i {{path}}",
|
||||
"marketplace.intro": "Installer genanvendelige agenter, færdigheder og MCP-værktøjer til ét eller alle projekter.",
|
||||
"marketplace.intro.learnMore": "Om Marketplace",
|
||||
"marketplace.install.prerequisites": "Forudsætninger",
|
||||
"marketplace.install.installing": "Installerer...",
|
||||
"marketplace.install.cancel": "Annuller",
|
||||
@@ -59,7 +78,9 @@ export const dict = {
|
||||
"marketplace.search": "Søg...",
|
||||
"marketplace.filter.all": "Alle elementer",
|
||||
"marketplace.filter.notInstalled": "Ikke installeret",
|
||||
"marketplace.filter.relevant": "Relevante for mit arbejdsområde",
|
||||
"marketplace.empty": "Ingen elementer fundet",
|
||||
"marketplace.empty.relevant": "Der blev ikke fundet relevante marketplace-elementer for dette arbejdsområde.",
|
||||
"marketplace.badge.mcpServer": "MCP-server",
|
||||
"marketplace.badge.mode": "Tilstand",
|
||||
"marketplace.card.by": "af {{author}}",
|
||||
|
||||
@@ -42,6 +42,27 @@ export const dict = {
|
||||
"marketplace.install.scope": "Bereich",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Nur dieses Projekt. Die installierten Dateien können versioniert und mit Ihrem Team geteilt werden.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Alle Projekte auf diesem Computer. Wird in Ihrer Benutzerkonfiguration gespeichert.",
|
||||
"marketplace.install.destination": "Installationsziel",
|
||||
"marketplace.install.about.mcp":
|
||||
"Ein MCP-Server stellt Kilo zusätzliche Werkzeuge für die Arbeit mit externen Diensten oder lokalen Programmen bereit.",
|
||||
"marketplace.install.about.agent":
|
||||
"Ein Agent fügt eine wiederverwendbare Rolle mit eigenen Anweisungen und Berechtigungen hinzu.",
|
||||
"marketplace.install.about.skill":
|
||||
"Ein Skill fügt aufgabenspezifische Anweisungen und Ressourcen hinzu, die Kilo bei Bedarf laden kann.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-Server können lokale Befehle ausführen oder eine Verbindung zu externen Diensten herstellen. Kilo fragt vor der Verwendung ihrer Werkzeuge um Erlaubnis, sofern Ihre Berechtigungen dies nicht automatisch erlauben.",
|
||||
"marketplace.install.project.warning":
|
||||
"Projektdateien können in die Versionsverwaltung aufgenommen werden. Speichern Sie hier keine Geheimnisse, es sei denn, die Konfiguration verweist auf eine Umgebungsvariable.",
|
||||
"marketplace.install.learnMore": "Erfahren Sie, wie Installationen aus dem Marketplace funktionieren",
|
||||
"marketplace.install.learnMcp": "Mehr über MCP erfahren",
|
||||
"marketplace.install.installedAt": "Installiert unter {{path}}",
|
||||
"marketplace.intro":
|
||||
"Installieren Sie wiederverwendbare Agenten, Skills und MCP-Werkzeuge für ein Projekt oder für alle Projekte.",
|
||||
"marketplace.intro.learnMore": "Über den Marketplace",
|
||||
"marketplace.install.prerequisites": "Voraussetzungen",
|
||||
"marketplace.install.installing": "Wird installiert...",
|
||||
"marketplace.install.cancel": "Abbrechen",
|
||||
@@ -59,7 +80,9 @@ export const dict = {
|
||||
"marketplace.search": "Suchen...",
|
||||
"marketplace.filter.all": "Alle Elemente",
|
||||
"marketplace.filter.notInstalled": "Nicht installiert",
|
||||
"marketplace.filter.relevant": "Relevant für meinen Arbeitsbereich",
|
||||
"marketplace.empty": "Keine Elemente gefunden",
|
||||
"marketplace.empty.relevant": "Keine relevanten Marketplace-Elemente für diesen Arbeitsbereich gefunden.",
|
||||
"marketplace.badge.mcpServer": "MCP-Server",
|
||||
"marketplace.badge.mode": "Modus",
|
||||
"marketplace.card.by": "von {{author}}",
|
||||
|
||||
@@ -41,9 +41,26 @@ export const dict = {
|
||||
"marketplace.card.showMore": "Show more",
|
||||
"marketplace.card.showLess": "Show less",
|
||||
"marketplace.install.title": "Install {{name}}",
|
||||
"marketplace.install.scope": "Scope",
|
||||
"marketplace.install.scope": "Where should this be available?",
|
||||
"marketplace.install.scope.project": "Project",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Only this project. The installed files can be committed and shared with your team.",
|
||||
"marketplace.install.scope.global.description": "All projects on this machine. Stored in your user configuration.",
|
||||
"marketplace.install.destination": "Installation destination",
|
||||
"marketplace.install.about.mcp":
|
||||
"An MCP server gives Kilo additional tools for working with external services or local programs.",
|
||||
"marketplace.install.about.agent": "An agent adds a reusable role with its own instructions and permissions.",
|
||||
"marketplace.install.about.skill": "A skill adds task-specific instructions and resources that Kilo can load when needed.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP servers can run local commands or connect to external services. Kilo will ask for permission before using their tools unless your permissions allow them automatically.",
|
||||
"marketplace.install.project.warning":
|
||||
"Project files may be committed to version control. Do not store secrets here unless the configuration references an environment variable.",
|
||||
"marketplace.install.learnMore": "Learn how Marketplace installs work",
|
||||
"marketplace.install.learnMcp": "Learn more about MCP",
|
||||
"marketplace.install.installedAt": "Installed to {{path}}",
|
||||
"marketplace.intro": "Install reusable agents, skills, and MCP tools for one project or every project.",
|
||||
"marketplace.intro.learnMore": "About Marketplace",
|
||||
"marketplace.install.prerequisites": "Prerequisites",
|
||||
"marketplace.install.installing": "Installing...",
|
||||
"marketplace.install.cancel": "Cancel",
|
||||
@@ -61,7 +78,9 @@ export const dict = {
|
||||
"marketplace.search": "Search...",
|
||||
"marketplace.filter.all": "All Items",
|
||||
"marketplace.filter.notInstalled": "Not Installed",
|
||||
"marketplace.filter.relevant": "Relevant to my workspace",
|
||||
"marketplace.empty": "No items found",
|
||||
"marketplace.empty.relevant": "No relevant marketplace items found for this workspace.",
|
||||
"marketplace.badge.mcpServer": "MCP Server",
|
||||
"marketplace.badge.mode": "Mode",
|
||||
"marketplace.card.by": "by {{author}}",
|
||||
|
||||
Generated
+22
@@ -42,6 +42,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "Alcance",
|
||||
"marketplace.install.scope.project": "Proyecto",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Solo este proyecto. Los archivos instalados se pueden añadir al control de versiones y compartir con tu equipo.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Todos los proyectos de este equipo. Se almacena en tu configuración de usuario.",
|
||||
"marketplace.install.destination": "Destino de la instalación",
|
||||
"marketplace.install.about.mcp":
|
||||
"Un servidor MCP proporciona a Kilo herramientas adicionales para trabajar con servicios externos o programas locales.",
|
||||
"marketplace.install.about.agent":
|
||||
"Un agente añade un rol reutilizable con sus propias instrucciones y permisos.",
|
||||
"marketplace.install.about.skill":
|
||||
"Una habilidad añade instrucciones y recursos específicos para tareas que Kilo puede cargar cuando sea necesario.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"Los servidores MCP pueden ejecutar comandos locales o conectarse a servicios externos. Kilo pedirá permiso antes de usar sus herramientas, a menos que tus permisos lo permitan automáticamente.",
|
||||
"marketplace.install.project.warning":
|
||||
"Los archivos del proyecto pueden añadirse al control de versiones. No guardes secretos aquí, a menos que la configuración haga referencia a una variable de entorno.",
|
||||
"marketplace.install.learnMore": "Descubre cómo funcionan las instalaciones de Marketplace",
|
||||
"marketplace.install.learnMcp": "Más información sobre MCP",
|
||||
"marketplace.install.installedAt": "Instalado en {{path}}",
|
||||
"marketplace.intro": "Instala agentes, habilidades y herramientas MCP reutilizables en uno o todos los proyectos.",
|
||||
"marketplace.intro.learnMore": "Acerca de Marketplace",
|
||||
"marketplace.install.prerequisites": "Requisitos previos",
|
||||
"marketplace.install.installing": "Instalando...",
|
||||
"marketplace.install.cancel": "Cancelar",
|
||||
@@ -59,7 +79,9 @@ export const dict = {
|
||||
"marketplace.search": "Buscar...",
|
||||
"marketplace.filter.all": "Todos los elementos",
|
||||
"marketplace.filter.notInstalled": "No instalado",
|
||||
"marketplace.filter.relevant": "Relevantes para mi espacio de trabajo",
|
||||
"marketplace.empty": "No se encontraron elementos",
|
||||
"marketplace.empty.relevant": "No se encontraron elementos relevantes del marketplace para este espacio de trabajo.",
|
||||
"marketplace.badge.mcpServer": "Servidor MCP",
|
||||
"marketplace.badge.mode": "Modo",
|
||||
"marketplace.card.by": "por {{author}}",
|
||||
|
||||
Generated
+23
@@ -42,6 +42,27 @@ export const dict = {
|
||||
"marketplace.install.scope": "Portée",
|
||||
"marketplace.install.scope.project": "Projet",
|
||||
"marketplace.install.scope.global": "Global",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Uniquement ce projet. Les fichiers installés peuvent être ajoutés au contrôle de version et partagés avec votre équipe.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Tous les projets sur cette machine. Enregistré dans votre configuration utilisateur.",
|
||||
"marketplace.install.destination": "Destination de l'installation",
|
||||
"marketplace.install.about.mcp":
|
||||
"Un serveur MCP fournit à Kilo des outils supplémentaires pour interagir avec des services externes ou des programmes locaux.",
|
||||
"marketplace.install.about.agent":
|
||||
"Un agent ajoute un rôle réutilisable avec ses propres instructions et autorisations.",
|
||||
"marketplace.install.about.skill":
|
||||
"Une compétence ajoute des instructions et des ressources propres à une tâche que Kilo peut charger en cas de besoin.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"Les serveurs MCP peuvent exécuter des commandes locales ou se connecter à des services externes. Kilo demandera votre autorisation avant d'utiliser leurs outils, sauf si vos autorisations le permettent automatiquement.",
|
||||
"marketplace.install.project.warning":
|
||||
"Les fichiers du projet peuvent être ajoutés au contrôle de version. N'y stockez pas de secrets, sauf si la configuration fait référence à une variable d'environnement.",
|
||||
"marketplace.install.learnMore": "Découvrir le fonctionnement des installations depuis le Marketplace",
|
||||
"marketplace.install.learnMcp": "En savoir plus sur MCP",
|
||||
"marketplace.install.installedAt": "Installé dans {{path}}",
|
||||
"marketplace.intro":
|
||||
"Installez des agents, des compétences et des outils MCP réutilisables pour un projet ou pour tous vos projets.",
|
||||
"marketplace.intro.learnMore": "À propos du Marketplace",
|
||||
"marketplace.install.prerequisites": "Prérequis",
|
||||
"marketplace.install.installing": "Installation en cours...",
|
||||
"marketplace.install.cancel": "Annuler",
|
||||
@@ -59,7 +80,9 @@ export const dict = {
|
||||
"marketplace.search": "Rechercher...",
|
||||
"marketplace.filter.all": "Tous les éléments",
|
||||
"marketplace.filter.notInstalled": "Non installé",
|
||||
"marketplace.filter.relevant": "Pertinents pour mon espace de travail",
|
||||
"marketplace.empty": "Aucun élément trouvé",
|
||||
"marketplace.empty.relevant": "Aucun élément pertinent du marketplace trouvé pour cet espace de travail.",
|
||||
"marketplace.badge.mcpServer": "Serveur MCP",
|
||||
"marketplace.badge.mode": "Mode",
|
||||
"marketplace.card.by": "par {{author}}",
|
||||
|
||||
Generated
+22
@@ -45,6 +45,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "Ambito",
|
||||
"marketplace.install.scope.project": "Progetto",
|
||||
"marketplace.install.scope.global": "Globale",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Solo questo progetto. I file installati possono essere aggiunti al controllo versione e condivisi con il team.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Tutti i progetti su questo computer. Viene salvato nella configurazione utente.",
|
||||
"marketplace.install.destination": "Destinazione dell'installazione",
|
||||
"marketplace.install.about.mcp":
|
||||
"Un server MCP fornisce a Kilo strumenti aggiuntivi per interagire con servizi esterni o programmi locali.",
|
||||
"marketplace.install.about.agent":
|
||||
"Un agente aggiunge un ruolo riutilizzabile con istruzioni e autorizzazioni proprie.",
|
||||
"marketplace.install.about.skill":
|
||||
"Una skill aggiunge istruzioni e risorse specifiche per un'attività che Kilo può caricare quando necessario.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"I server MCP possono eseguire comandi locali o connettersi a servizi esterni. Kilo chiederà l'autorizzazione prima di usare i loro strumenti, a meno che le tue autorizzazioni non lo consentano automaticamente.",
|
||||
"marketplace.install.project.warning":
|
||||
"I file del progetto possono essere aggiunti al controllo versione. Non salvare segreti qui, a meno che la configurazione non faccia riferimento a una variabile di ambiente.",
|
||||
"marketplace.install.learnMore": "Scopri come funzionano le installazioni dal Marketplace",
|
||||
"marketplace.install.learnMcp": "Scopri di più su MCP",
|
||||
"marketplace.install.installedAt": "Installato in {{path}}",
|
||||
"marketplace.intro": "Installa agenti, skill e strumenti MCP riutilizzabili per uno o tutti i progetti.",
|
||||
"marketplace.intro.learnMore": "Informazioni sul Marketplace",
|
||||
"marketplace.install.prerequisites": "Prerequisiti",
|
||||
"marketplace.install.installing": "Installazione...",
|
||||
"marketplace.install.cancel": "Annulla",
|
||||
@@ -60,7 +80,9 @@ export const dict = {
|
||||
"marketplace.search": "Cerca...",
|
||||
"marketplace.filter.all": "Tutti gli elementi",
|
||||
"marketplace.filter.notInstalled": "Non installati",
|
||||
"marketplace.filter.relevant": "Rilevanti per il mio spazio di lavoro",
|
||||
"marketplace.empty": "Nessun elemento trovato",
|
||||
"marketplace.empty.relevant": "Nessun elemento rilevante del marketplace trovato per questo spazio di lavoro.",
|
||||
"marketplace.badge.mcpServer": "Server MCP",
|
||||
"marketplace.badge.mode": "Modalità",
|
||||
"marketplace.card.by": "di {{author}}",
|
||||
|
||||
Generated
+22
@@ -41,6 +41,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "スコープ",
|
||||
"marketplace.install.scope.project": "プロジェクト",
|
||||
"marketplace.install.scope.global": "グローバル",
|
||||
"marketplace.install.scope.project.description":
|
||||
"このプロジェクトのみ。インストールしたファイルはバージョン管理に追加し、チームと共有できます。",
|
||||
"marketplace.install.scope.global.description":
|
||||
"このマシン上のすべてのプロジェクト。ユーザー設定に保存されます。",
|
||||
"marketplace.install.destination": "インストール先",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCPサーバーは、外部サービスやローカルプログラムを操作するための追加ツールをKiloに提供します。",
|
||||
"marketplace.install.about.agent": "エージェントは、独自の指示と権限を持つ再利用可能な役割を追加します。",
|
||||
"marketplace.install.about.skill":
|
||||
"スキルは、必要に応じてKiloが読み込めるタスク固有の指示とリソースを追加します。",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCPサーバーはローカルコマンドを実行したり、外部サービスに接続したりできます。権限で自動的に許可されていない限り、Kiloはツールを使用する前に許可を求めます。",
|
||||
"marketplace.install.project.warning":
|
||||
"プロジェクトファイルはバージョン管理に追加される場合があります。設定で環境変数を参照している場合を除き、ここにシークレットを保存しないでください。",
|
||||
"marketplace.install.learnMore": "Marketplaceからのインストールの仕組みを見る",
|
||||
"marketplace.install.learnMcp": "MCPについて詳しく見る",
|
||||
"marketplace.install.installedAt": "{{path}} にインストール済み",
|
||||
"marketplace.intro":
|
||||
"再利用可能なエージェント、スキル、MCPツールを1つのプロジェクトまたはすべてのプロジェクトにインストールできます。",
|
||||
"marketplace.intro.learnMore": "Marketplaceについて",
|
||||
"marketplace.install.prerequisites": "前提条件",
|
||||
"marketplace.install.installing": "インストール中...",
|
||||
"marketplace.install.cancel": "キャンセル",
|
||||
@@ -57,7 +77,9 @@ export const dict = {
|
||||
"marketplace.search": "検索...",
|
||||
"marketplace.filter.all": "すべてのアイテム",
|
||||
"marketplace.filter.notInstalled": "未インストール",
|
||||
"marketplace.filter.relevant": "自分のワークスペースに関連",
|
||||
"marketplace.empty": "アイテムが見つかりません",
|
||||
"marketplace.empty.relevant": "このワークスペースに関連するマーケットプレイスのアイテムが見つかりませんでした。",
|
||||
"marketplace.badge.mcpServer": "MCPサーバー",
|
||||
"marketplace.badge.mode": "モード",
|
||||
"marketplace.card.by": "作成者: {{author}}",
|
||||
|
||||
Generated
+22
@@ -41,6 +41,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "범위",
|
||||
"marketplace.install.scope.project": "프로젝트",
|
||||
"marketplace.install.scope.global": "글로벌",
|
||||
"marketplace.install.scope.project.description":
|
||||
"이 프로젝트에만 적용됩니다. 설치된 파일을 버전 관리에 추가하고 팀과 공유할 수 있습니다.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"이 컴퓨터의 모든 프로젝트에 적용됩니다. 사용자 구성에 저장됩니다.",
|
||||
"marketplace.install.destination": "설치 위치",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP 서버는 외부 서비스나 로컬 프로그램과 작업할 수 있는 추가 도구를 Kilo에 제공합니다.",
|
||||
"marketplace.install.about.agent": "에이전트는 자체 지침과 권한을 가진 재사용 가능한 역할을 추가합니다.",
|
||||
"marketplace.install.about.skill":
|
||||
"스킬은 필요할 때 Kilo가 불러올 수 있는 작업별 지침과 리소스를 추가합니다.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP 서버는 로컬 명령을 실행하거나 외부 서비스에 연결할 수 있습니다. 권한 설정에서 자동으로 허용하지 않는 한 Kilo는 도구를 사용하기 전에 권한을 요청합니다.",
|
||||
"marketplace.install.project.warning":
|
||||
"프로젝트 파일이 버전 관리에 추가될 수 있습니다. 구성에서 환경 변수를 참조하는 경우가 아니면 여기에 비밀 정보를 저장하지 마세요.",
|
||||
"marketplace.install.learnMore": "Marketplace 설치 방식 알아보기",
|
||||
"marketplace.install.learnMcp": "MCP 자세히 알아보기",
|
||||
"marketplace.install.installedAt": "{{path}}에 설치됨",
|
||||
"marketplace.intro":
|
||||
"재사용 가능한 에이전트, 스킬 및 MCP 도구를 하나의 프로젝트 또는 모든 프로젝트에 설치하세요.",
|
||||
"marketplace.intro.learnMore": "Marketplace 정보",
|
||||
"marketplace.install.prerequisites": "사전 요구 사항",
|
||||
"marketplace.install.installing": "설치 중...",
|
||||
"marketplace.install.cancel": "취소",
|
||||
@@ -57,7 +77,9 @@ export const dict = {
|
||||
"marketplace.search": "검색...",
|
||||
"marketplace.filter.all": "모든 항목",
|
||||
"marketplace.filter.notInstalled": "설치되지 않음",
|
||||
"marketplace.filter.relevant": "내 작업 영역과 관련됨",
|
||||
"marketplace.empty": "항목을 찾을 수 없음",
|
||||
"marketplace.empty.relevant": "이 작업 영역과 관련된 마켓플레이스 항목을 찾을 수 없습니다.",
|
||||
"marketplace.badge.mcpServer": "MCP 서버",
|
||||
"marketplace.badge.mode": "모드",
|
||||
"marketplace.card.by": "제작: {{author}}",
|
||||
|
||||
Generated
+22
@@ -44,6 +44,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "Scope",
|
||||
"marketplace.install.scope.project": "Project",
|
||||
"marketplace.install.scope.global": "Globaal",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Alleen dit project. De geïnstalleerde bestanden kunnen aan versiebeheer worden toegevoegd en met je team worden gedeeld.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Alle projecten op deze computer. Wordt opgeslagen in je gebruikersconfiguratie.",
|
||||
"marketplace.install.destination": "Installatielocatie",
|
||||
"marketplace.install.about.mcp":
|
||||
"Een MCP-server geeft Kilo extra hulpmiddelen om met externe diensten of lokale programma's te werken.",
|
||||
"marketplace.install.about.agent": "Een agent voegt een herbruikbare rol toe met eigen instructies en machtigingen.",
|
||||
"marketplace.install.about.skill":
|
||||
"Een vaardigheid voegt taakspecifieke instructies en bronnen toe die Kilo indien nodig kan laden.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-servers kunnen lokale opdrachten uitvoeren of verbinding maken met externe diensten. Kilo vraagt toestemming voordat hun hulpmiddelen worden gebruikt, tenzij je machtigingen dit automatisch toestaan.",
|
||||
"marketplace.install.project.warning":
|
||||
"Projectbestanden kunnen aan versiebeheer worden toegevoegd. Sla hier geen geheimen op, tenzij de configuratie naar een omgevingsvariabele verwijst.",
|
||||
"marketplace.install.learnMore": "Lees hoe installaties vanuit Marketplace werken",
|
||||
"marketplace.install.learnMcp": "Meer informatie over MCP",
|
||||
"marketplace.install.installedAt": "Geïnstalleerd in {{path}}",
|
||||
"marketplace.intro":
|
||||
"Installeer herbruikbare agenten, vaardigheden en MCP-hulpmiddelen voor één project of voor alle projecten.",
|
||||
"marketplace.intro.learnMore": "Over Marketplace",
|
||||
"marketplace.install.prerequisites": "Vereisten",
|
||||
"marketplace.install.installing": "Installeren...",
|
||||
"marketplace.install.cancel": "Annuleren",
|
||||
@@ -61,7 +81,9 @@ export const dict = {
|
||||
"marketplace.search": "Zoeken...",
|
||||
"marketplace.filter.all": "Alle items",
|
||||
"marketplace.filter.notInstalled": "Niet geïnstalleerd",
|
||||
"marketplace.filter.relevant": "Relevant voor mijn werkruimte",
|
||||
"marketplace.empty": "Geen items gevonden",
|
||||
"marketplace.empty.relevant": "Geen relevante marketplace-items gevonden voor deze werkruimte.",
|
||||
"marketplace.badge.mcpServer": "MCP Server",
|
||||
"marketplace.badge.mode": "Modus",
|
||||
"marketplace.card.by": "door {{author}}",
|
||||
|
||||
Generated
+21
@@ -42,6 +42,25 @@ export const dict = {
|
||||
"marketplace.install.scope": "Omfang",
|
||||
"marketplace.install.scope.project": "Prosjekt",
|
||||
"marketplace.install.scope.global": "Globalt",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Bare dette prosjektet. De installerte filene kan legges til i versjonskontroll og deles med teamet ditt.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Alle prosjekter på denne maskinen. Lagres i brukerkonfigurasjonen din.",
|
||||
"marketplace.install.destination": "Installasjonssted",
|
||||
"marketplace.install.about.mcp":
|
||||
"En MCP-server gir Kilo flere verktøy for å arbeide med eksterne tjenester eller lokale programmer.",
|
||||
"marketplace.install.about.agent": "En agent legger til en gjenbrukbar rolle med egne instruksjoner og tillatelser.",
|
||||
"marketplace.install.about.skill":
|
||||
"En ferdighet legger til oppgavespesifikke instruksjoner og ressurser som Kilo kan laste inn ved behov.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-servere kan kjøre lokale kommandoer eller koble til eksterne tjenester. Kilo ber om tillatelse før verktøyene brukes, med mindre tillatelsene dine automatisk tillater det.",
|
||||
"marketplace.install.project.warning":
|
||||
"Prosjektfiler kan legges til i versjonskontroll. Ikke lagre hemmeligheter her med mindre konfigurasjonen viser til en miljøvariabel.",
|
||||
"marketplace.install.learnMore": "Finn ut hvordan installasjoner fra Marketplace fungerer",
|
||||
"marketplace.install.learnMcp": "Finn ut mer om MCP",
|
||||
"marketplace.install.installedAt": "Installert i {{path}}",
|
||||
"marketplace.intro": "Installer gjenbrukbare agenter, ferdigheter og MCP-verktøy for ett eller alle prosjekter.",
|
||||
"marketplace.intro.learnMore": "Om Marketplace",
|
||||
"marketplace.install.prerequisites": "Forutsetninger",
|
||||
"marketplace.install.installing": "Installerer...",
|
||||
"marketplace.install.cancel": "Avbryt",
|
||||
@@ -59,7 +78,9 @@ export const dict = {
|
||||
"marketplace.search": "Søk...",
|
||||
"marketplace.filter.all": "Alle elementer",
|
||||
"marketplace.filter.notInstalled": "Ikke installert",
|
||||
"marketplace.filter.relevant": "Relevant for arbeidsområdet mitt",
|
||||
"marketplace.empty": "Ingen elementer funnet",
|
||||
"marketplace.empty.relevant": "Ingen relevante marketplace-elementer funnet for dette arbeidsområdet.",
|
||||
"marketplace.badge.mcpServer": "MCP-server",
|
||||
"marketplace.badge.mode": "Modus",
|
||||
"marketplace.card.by": "av {{author}}",
|
||||
|
||||
Generated
+22
@@ -42,6 +42,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "Zakres",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
"marketplace.install.scope.global": "Globalny",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Tylko ten projekt. Zainstalowane pliki można dodać do systemu kontroli wersji i udostępnić zespołowi.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Wszystkie projekty na tym komputerze. Zapisywane w konfiguracji użytkownika.",
|
||||
"marketplace.install.destination": "Miejsce instalacji",
|
||||
"marketplace.install.about.mcp":
|
||||
"Serwer MCP zapewnia Kilo dodatkowe narzędzia do pracy z usługami zewnętrznymi lub programami lokalnymi.",
|
||||
"marketplace.install.about.agent": "Agent dodaje rolę wielokrotnego użytku z własnymi instrukcjami i uprawnieniami.",
|
||||
"marketplace.install.about.skill":
|
||||
"Umiejętność dodaje instrukcje i zasoby dotyczące określonych zadań, które Kilo może wczytać w razie potrzeby.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"Serwery MCP mogą uruchamiać lokalne polecenia lub łączyć się z usługami zewnętrznymi. Kilo poprosi o pozwolenie przed użyciem ich narzędzi, chyba że uprawnienia zezwalają na to automatycznie.",
|
||||
"marketplace.install.project.warning":
|
||||
"Pliki projektu mogą zostać dodane do systemu kontroli wersji. Nie przechowuj tutaj sekretów, chyba że konfiguracja odwołuje się do zmiennej środowiskowej.",
|
||||
"marketplace.install.learnMore": "Dowiedz się, jak działają instalacje z Marketplace",
|
||||
"marketplace.install.learnMcp": "Dowiedz się więcej o MCP",
|
||||
"marketplace.install.installedAt": "Zainstalowano w {{path}}",
|
||||
"marketplace.intro":
|
||||
"Instaluj agentów, umiejętności i narzędzia MCP wielokrotnego użytku w jednym lub we wszystkich projektach.",
|
||||
"marketplace.intro.learnMore": "O Marketplace",
|
||||
"marketplace.install.prerequisites": "Wymagania wstępne",
|
||||
"marketplace.install.installing": "Instalowanie...",
|
||||
"marketplace.install.cancel": "Anuluj",
|
||||
@@ -59,7 +79,9 @@ export const dict = {
|
||||
"marketplace.search": "Szukaj...",
|
||||
"marketplace.filter.all": "Wszystkie elementy",
|
||||
"marketplace.filter.notInstalled": "Nie zainstalowano",
|
||||
"marketplace.filter.relevant": "Istotne dla mojego obszaru roboczego",
|
||||
"marketplace.empty": "Nie znaleziono elementów",
|
||||
"marketplace.empty.relevant": "Nie znaleziono elementów marketplace istotnych dla tego obszaru roboczego.",
|
||||
"marketplace.badge.mcpServer": "Serwer MCP",
|
||||
"marketplace.badge.mode": "Tryb",
|
||||
"marketplace.card.by": "autor: {{author}}",
|
||||
|
||||
Generated
+23
@@ -42,6 +42,27 @@ export const dict = {
|
||||
"marketplace.install.scope": "Область",
|
||||
"marketplace.install.scope.project": "Проект",
|
||||
"marketplace.install.scope.global": "Глобально",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Только этот проект. Установленные файлы можно добавить в систему контроля версий и предоставить команде.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Все проекты на этом компьютере. Сохраняется в вашей пользовательской конфигурации.",
|
||||
"marketplace.install.destination": "Место установки",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP-сервер предоставляет Kilo дополнительные инструменты для работы с внешними сервисами или локальными программами.",
|
||||
"marketplace.install.about.agent":
|
||||
"Агент добавляет многократно используемую роль с собственными инструкциями и разрешениями.",
|
||||
"marketplace.install.about.skill":
|
||||
"Навык добавляет инструкции и ресурсы для определённых задач, которые Kilo может загрузить при необходимости.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-серверы могут выполнять локальные команды или подключаться к внешним сервисам. Kilo запросит разрешение перед использованием их инструментов, если только ваши разрешения не допускают это автоматически.",
|
||||
"marketplace.install.project.warning":
|
||||
"Файлы проекта могут быть добавлены в систему контроля версий. Не храните здесь секреты, если только конфигурация не ссылается на переменную окружения.",
|
||||
"marketplace.install.learnMore": "Узнайте, как работает установка из Marketplace",
|
||||
"marketplace.install.learnMcp": "Подробнее о MCP",
|
||||
"marketplace.install.installedAt": "Установлено в {{path}}",
|
||||
"marketplace.intro":
|
||||
"Устанавливайте многократно используемых агентов, навыки и инструменты MCP для одного или всех проектов.",
|
||||
"marketplace.intro.learnMore": "О Marketplace",
|
||||
"marketplace.install.prerequisites": "Предварительные требования",
|
||||
"marketplace.install.installing": "Установка...",
|
||||
"marketplace.install.cancel": "Отмена",
|
||||
@@ -59,7 +80,9 @@ export const dict = {
|
||||
"marketplace.search": "Поиск...",
|
||||
"marketplace.filter.all": "Все элементы",
|
||||
"marketplace.filter.notInstalled": "Не установлено",
|
||||
"marketplace.filter.relevant": "Подходящие для моего рабочего пространства",
|
||||
"marketplace.empty": "Элементы не найдены",
|
||||
"marketplace.empty.relevant": "Для этого рабочего пространства не найдено подходящих элементов маркетплейса.",
|
||||
"marketplace.badge.mcpServer": "MCP-сервер",
|
||||
"marketplace.badge.mode": "Режим",
|
||||
"marketplace.card.by": "от {{author}}",
|
||||
|
||||
Generated
+21
@@ -42,6 +42,25 @@ export const dict = {
|
||||
"marketplace.install.scope": "ขอบเขต",
|
||||
"marketplace.install.scope.project": "โปรเจกต์",
|
||||
"marketplace.install.scope.global": "โกลบอล",
|
||||
"marketplace.install.scope.project.description":
|
||||
"เฉพาะโปรเจกต์นี้ ไฟล์ที่ติดตั้งสามารถเพิ่มลงในระบบควบคุมเวอร์ชันและแชร์กับทีมของคุณได้",
|
||||
"marketplace.install.scope.global.description":
|
||||
"ทุกโปรเจกต์ในเครื่องนี้ จัดเก็บไว้ในการกำหนดค่าผู้ใช้ของคุณ",
|
||||
"marketplace.install.destination": "ปลายทางการติดตั้ง",
|
||||
"marketplace.install.about.mcp":
|
||||
"เซิร์ฟเวอร์ MCP เพิ่มเครื่องมือให้ Kilo สำหรับทำงานกับบริการภายนอกหรือโปรแกรมในเครื่อง",
|
||||
"marketplace.install.about.agent": "เอเจนต์เพิ่มบทบาทที่นำกลับมาใช้ใหม่ได้พร้อมคำสั่งและสิทธิ์ของตนเอง",
|
||||
"marketplace.install.about.skill":
|
||||
"ทักษะเพิ่มคำสั่งและทรัพยากรเฉพาะงานที่ Kilo สามารถโหลดได้เมื่อจำเป็น",
|
||||
"marketplace.install.mcp.warning":
|
||||
"เซิร์ฟเวอร์ MCP สามารถเรียกใช้คำสั่งในเครื่องหรือเชื่อมต่อกับบริการภายนอกได้ Kilo จะขออนุญาตก่อนใช้เครื่องมือ เว้นแต่สิทธิ์ของคุณจะอนุญาตโดยอัตโนมัติ",
|
||||
"marketplace.install.project.warning":
|
||||
"ไฟล์โปรเจกต์อาจถูกเพิ่มลงในระบบควบคุมเวอร์ชัน อย่าเก็บข้อมูลลับไว้ที่นี่ เว้นแต่การกำหนดค่าจะอ้างอิงตัวแปรสภาพแวดล้อม",
|
||||
"marketplace.install.learnMore": "เรียนรู้วิธีการติดตั้งจาก Marketplace",
|
||||
"marketplace.install.learnMcp": "เรียนรู้เพิ่มเติมเกี่ยวกับ MCP",
|
||||
"marketplace.install.installedAt": "ติดตั้งไปยัง {{path}} แล้ว",
|
||||
"marketplace.intro": "ติดตั้งเอเจนต์ ทักษะ และเครื่องมือ MCP ที่นำกลับมาใช้ใหม่ได้สำหรับหนึ่งโปรเจกต์หรือทุกโปรเจกต์",
|
||||
"marketplace.intro.learnMore": "เกี่ยวกับ Marketplace",
|
||||
"marketplace.install.prerequisites": "ข้อกำหนดเบื้องต้น",
|
||||
"marketplace.install.installing": "กำลังติดตั้ง...",
|
||||
"marketplace.install.cancel": "ยกเลิก",
|
||||
@@ -59,7 +78,9 @@ export const dict = {
|
||||
"marketplace.search": "ค้นหา...",
|
||||
"marketplace.filter.all": "รายการทั้งหมด",
|
||||
"marketplace.filter.notInstalled": "ยังไม่ได้ติดตั้ง",
|
||||
"marketplace.filter.relevant": "เกี่ยวข้องกับพื้นที่ทำงานของฉัน",
|
||||
"marketplace.empty": "ไม่พบรายการ",
|
||||
"marketplace.empty.relevant": "ไม่พบรายการในมาร์เก็ตเพลสที่เกี่ยวข้องกับพื้นที่ทำงานนี้",
|
||||
"marketplace.badge.mcpServer": "เซิร์ฟเวอร์ MCP",
|
||||
"marketplace.badge.mode": "โหมด",
|
||||
"marketplace.card.by": "โดย {{author}}",
|
||||
|
||||
Generated
+22
@@ -42,6 +42,26 @@ export const dict = {
|
||||
"marketplace.install.scope": "Kapsam",
|
||||
"marketplace.install.scope.project": "Proje",
|
||||
"marketplace.install.scope.global": "Genel",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Yalnızca bu proje. Yüklenen dosyalar sürüm kontrolüne eklenebilir ve ekibinizle paylaşılabilir.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Bu makinedeki tüm projeler. Kullanıcı yapılandırmanızda saklanır.",
|
||||
"marketplace.install.destination": "Yükleme hedefi",
|
||||
"marketplace.install.about.mcp":
|
||||
"Bir MCP sunucusu, harici hizmetler veya yerel programlarla çalışmak için Kilo'ya ek araçlar sağlar.",
|
||||
"marketplace.install.about.agent": "Bir ajan, kendi talimatları ve izinleri olan yeniden kullanılabilir bir rol ekler.",
|
||||
"marketplace.install.about.skill":
|
||||
"Bir yetenek, Kilo'nun gerektiğinde yükleyebileceği göreve özel talimatlar ve kaynaklar ekler.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP sunucuları yerel komutları çalıştırabilir veya harici hizmetlere bağlanabilir. İzinleriniz otomatik olarak izin vermediği sürece Kilo, araçlarını kullanmadan önce izin ister.",
|
||||
"marketplace.install.project.warning":
|
||||
"Proje dosyaları sürüm kontrolüne eklenebilir. Yapılandırma bir ortam değişkenine başvurmuyorsa gizli bilgileri burada saklamayın.",
|
||||
"marketplace.install.learnMore": "Marketplace yüklemelerinin nasıl çalıştığını öğrenin",
|
||||
"marketplace.install.learnMcp": "MCP hakkında daha fazla bilgi edinin",
|
||||
"marketplace.install.installedAt": "{{path}} konumuna yüklendi",
|
||||
"marketplace.intro":
|
||||
"Yeniden kullanılabilir ajanları, yetenekleri ve MCP araçlarını bir proje veya tüm projeler için yükleyin.",
|
||||
"marketplace.intro.learnMore": "Marketplace hakkında",
|
||||
"marketplace.install.prerequisites": "Ön koşullar",
|
||||
"marketplace.install.installing": "Yükleniyor...",
|
||||
"marketplace.install.cancel": "İptal",
|
||||
@@ -59,7 +79,9 @@ export const dict = {
|
||||
"marketplace.search": "Ara...",
|
||||
"marketplace.filter.all": "Tüm Öğeler",
|
||||
"marketplace.filter.notInstalled": "Yüklü Değil",
|
||||
"marketplace.filter.relevant": "Çalışma alanımla ilgili",
|
||||
"marketplace.empty": "Öğe bulunamadı",
|
||||
"marketplace.empty.relevant": "Bu çalışma alanıyla ilgili marketplace öğesi bulunamadı.",
|
||||
"marketplace.badge.mcpServer": "MCP Sunucusu",
|
||||
"marketplace.badge.mode": "Mod",
|
||||
"marketplace.card.by": "{{author}} tarafından",
|
||||
|
||||
Generated
+23
@@ -42,6 +42,27 @@ export const dict = {
|
||||
"marketplace.install.scope": "Область",
|
||||
"marketplace.install.scope.project": "Проєкт",
|
||||
"marketplace.install.scope.global": "Глобально",
|
||||
"marketplace.install.scope.project.description":
|
||||
"Лише цей проєкт. Встановлені файли можна додати до системи контролю версій і надати команді.",
|
||||
"marketplace.install.scope.global.description":
|
||||
"Усі проєкти на цьому комп'ютері. Зберігається у вашій користувацькій конфігурації.",
|
||||
"marketplace.install.destination": "Місце встановлення",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP-сервер надає Kilo додаткові інструменти для роботи із зовнішніми сервісами або локальними програмами.",
|
||||
"marketplace.install.about.agent":
|
||||
"Агент додає багаторазову роль із власними інструкціями та дозволами.",
|
||||
"marketplace.install.about.skill":
|
||||
"Навичка додає інструкції та ресурси для певних завдань, які Kilo може завантажити за потреби.",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP-сервери можуть виконувати локальні команди або підключатися до зовнішніх сервісів. Kilo запитає дозвіл перед використанням їхніх інструментів, якщо ваші дозволи не дають змоги робити це автоматично.",
|
||||
"marketplace.install.project.warning":
|
||||
"Файли проєкту можуть бути додані до системи контролю версій. Не зберігайте тут секрети, якщо конфігурація не посилається на змінну середовища.",
|
||||
"marketplace.install.learnMore": "Дізнайтеся, як працює встановлення з Marketplace",
|
||||
"marketplace.install.learnMcp": "Докладніше про MCP",
|
||||
"marketplace.install.installedAt": "Встановлено в {{path}}",
|
||||
"marketplace.intro":
|
||||
"Встановлюйте багаторазових агентів, навички та інструменти MCP для одного або всіх проєктів.",
|
||||
"marketplace.intro.learnMore": "Про Marketplace",
|
||||
"marketplace.install.prerequisites": "Передумови",
|
||||
"marketplace.install.installing": "Встановлення...",
|
||||
"marketplace.install.cancel": "Скасувати",
|
||||
@@ -59,7 +80,9 @@ export const dict = {
|
||||
"marketplace.search": "Пошук...",
|
||||
"marketplace.filter.all": "Усі елементи",
|
||||
"marketplace.filter.notInstalled": "Не встановлено",
|
||||
"marketplace.filter.relevant": "Відповідні моєму робочому простору",
|
||||
"marketplace.empty": "Елементів не знайдено",
|
||||
"marketplace.empty.relevant": "Для цього робочого простору не знайдено відповідних елементів маркетплейсу.",
|
||||
"marketplace.badge.mcpServer": "MCP-сервер",
|
||||
"marketplace.badge.mode": "Режим",
|
||||
"marketplace.card.by": "від {{author}}",
|
||||
|
||||
Generated
+19
@@ -40,6 +40,23 @@ export const dict = {
|
||||
"marketplace.install.scope": "作用域",
|
||||
"marketplace.install.scope.project": "项目",
|
||||
"marketplace.install.scope.global": "全局",
|
||||
"marketplace.install.scope.project.description":
|
||||
"仅限此项目。安装的文件可以提交到版本控制并与你的团队共享。",
|
||||
"marketplace.install.scope.global.description": "此计算机上的所有项目。存储在你的用户配置中。",
|
||||
"marketplace.install.destination": "安装位置",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP 服务器为 Kilo 提供用于处理外部服务或本地程序的额外工具。",
|
||||
"marketplace.install.about.agent": "智能体会添加一个具有专属指令和权限的可复用角色。",
|
||||
"marketplace.install.about.skill": "技能会添加特定任务的指令和资源,Kilo 可在需要时加载它们。",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP 服务器可以运行本地命令或连接外部服务。除非你的权限允许自动使用,否则 Kilo 会在使用其工具前请求许可。",
|
||||
"marketplace.install.project.warning":
|
||||
"项目文件可能会提交到版本控制。除非配置引用了环境变量,否则不要在此处存储密钥。",
|
||||
"marketplace.install.learnMore": "了解 Marketplace 安装的工作方式",
|
||||
"marketplace.install.learnMcp": "详细了解 MCP",
|
||||
"marketplace.install.installedAt": "已安装到 {{path}}",
|
||||
"marketplace.intro": "为一个项目或所有项目安装可复用的智能体、技能和 MCP 工具。",
|
||||
"marketplace.intro.learnMore": "关于 Marketplace",
|
||||
"marketplace.install.prerequisites": "先决条件",
|
||||
"marketplace.install.installing": "安装中...",
|
||||
"marketplace.install.cancel": "取消",
|
||||
@@ -56,7 +73,9 @@ export const dict = {
|
||||
"marketplace.search": "搜索...",
|
||||
"marketplace.filter.all": "所有项目",
|
||||
"marketplace.filter.notInstalled": "未安装",
|
||||
"marketplace.filter.relevant": "与我的工作区相关",
|
||||
"marketplace.empty": "未找到项目",
|
||||
"marketplace.empty.relevant": "未找到与此工作区相关的市场项目。",
|
||||
"marketplace.badge.mcpServer": "MCP 服务器",
|
||||
"marketplace.badge.mode": "模式",
|
||||
"marketplace.card.by": "作者:{{author}}",
|
||||
|
||||
Generated
+19
@@ -40,6 +40,23 @@ export const dict = {
|
||||
"marketplace.install.scope": "作用域",
|
||||
"marketplace.install.scope.project": "專案",
|
||||
"marketplace.install.scope.global": "全域",
|
||||
"marketplace.install.scope.project.description":
|
||||
"僅限此專案。安裝的檔案可以提交至版本控制並與你的團隊分享。",
|
||||
"marketplace.install.scope.global.description": "此電腦上的所有專案。儲存在你的使用者設定中。",
|
||||
"marketplace.install.destination": "安裝位置",
|
||||
"marketplace.install.about.mcp":
|
||||
"MCP 伺服器為 Kilo 提供用於處理外部服務或本機程式的額外工具。",
|
||||
"marketplace.install.about.agent": "智能體會新增一個具有專屬指示和權限的可重複使用角色。",
|
||||
"marketplace.install.about.skill": "技能會新增特定任務的指示和資源,Kilo 可在需要時載入它們。",
|
||||
"marketplace.install.mcp.warning":
|
||||
"MCP 伺服器可以執行本機命令或連線至外部服務。除非你的權限允許自動使用,否則 Kilo 會在使用其工具前請求許可。",
|
||||
"marketplace.install.project.warning":
|
||||
"專案檔案可能會提交至版本控制。除非設定引用了環境變數,否則請勿在此儲存密鑰。",
|
||||
"marketplace.install.learnMore": "瞭解 Marketplace 安裝的運作方式",
|
||||
"marketplace.install.learnMcp": "深入瞭解 MCP",
|
||||
"marketplace.install.installedAt": "已安裝至 {{path}}",
|
||||
"marketplace.intro": "為一個專案或所有專案安裝可重複使用的智能體、技能和 MCP 工具。",
|
||||
"marketplace.intro.learnMore": "關於 Marketplace",
|
||||
"marketplace.install.prerequisites": "先決條件",
|
||||
"marketplace.install.installing": "安裝中...",
|
||||
"marketplace.install.cancel": "取消",
|
||||
@@ -56,7 +73,9 @@ export const dict = {
|
||||
"marketplace.search": "搜尋...",
|
||||
"marketplace.filter.all": "所有項目",
|
||||
"marketplace.filter.notInstalled": "未安裝",
|
||||
"marketplace.filter.relevant": "與我的工作區相關",
|
||||
"marketplace.empty": "找不到項目",
|
||||
"marketplace.empty.relevant": "找不到與此工作區相關的市集項目。",
|
||||
"marketplace.badge.mcpServer": "MCP 伺服器",
|
||||
"marketplace.badge.mode": "模式",
|
||||
"marketplace.card.by": "作者:{{author}}",
|
||||
|
||||
+9
@@ -419,6 +419,10 @@ class KiloBackendAppService private constructor(
|
||||
warnings = warns,
|
||||
)
|
||||
)
|
||||
log.info(
|
||||
"Application snapshot: profile=${if (prof != null) "loaded" else "not_logged_in"} " +
|
||||
"warnings=${warns.size} notifications=${notifs.size} ${configSummary(cfg)}",
|
||||
)
|
||||
log.info("Application started — config, profile, notifications loaded")
|
||||
} catch (e: TimeoutCancellationException) {
|
||||
val err = LoadError(
|
||||
@@ -639,6 +643,11 @@ class KiloBackendAppService private constructor(
|
||||
return "${warn.path}: ${warn.message}$detail"
|
||||
}
|
||||
|
||||
private fun configSummary(cfg: Config): String {
|
||||
val text = cfg.toString()
|
||||
return "configChars=${text.length} configHash=${text.hashCode().toUInt().toString(16)}"
|
||||
}
|
||||
|
||||
private suspend fun restartConnection(reason: String) {
|
||||
clear()
|
||||
connection.restart()
|
||||
|
||||
+20
-2
@@ -15,6 +15,7 @@ import ai.kilocode.rpc.dto.PromptDto
|
||||
import ai.kilocode.rpc.dto.QuestionReplyDto
|
||||
import ai.kilocode.rpc.dto.QuestionRequestDto
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
@@ -89,10 +90,26 @@ class KiloBackendChatManager(
|
||||
watcher = cs.launch {
|
||||
sse.collect { event ->
|
||||
if (event.type in CHAT_EVENTS) {
|
||||
val events = normalizer.parse(event.type, event.data)
|
||||
val events = try {
|
||||
normalizer.parse(event.type, event.data)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
log.warn(
|
||||
"route=chat-events parse=false type=${event.type} bytes=${event.data.length} ${ChatLogSummary.body(event.data)}",
|
||||
e,
|
||||
)
|
||||
return@collect
|
||||
}
|
||||
if (events != null) {
|
||||
for (parsed in events) {
|
||||
log.debug { ChatLogSummary.event(parsed) }
|
||||
ChatLogSummary.error(parsed)?.let { error ->
|
||||
log.warn(
|
||||
"route=chat-events emit=true raw=${event.type} bytes=${event.data.length} " +
|
||||
"subscribers=${_events.subscriptionCount.value} $error",
|
||||
)
|
||||
}
|
||||
if (parsed is ChatEventDto.SessionStatusChanged && parsed.status.type != "busy") {
|
||||
log.info(
|
||||
"${ChatLogSummary.sid(parsed.sessionID)} kind=status route=chat-events emit=true " +
|
||||
@@ -102,7 +119,7 @@ class KiloBackendChatManager(
|
||||
_events.emit(parsed)
|
||||
}
|
||||
} else {
|
||||
log.warn("SSE parse returned null for type=${event.type} bytes=${event.data.length}")
|
||||
log.warn("route=chat-events parse=null type=${event.type} bytes=${event.data.length} ${ChatLogSummary.body(event.data)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,6 +188,7 @@ class KiloBackendChatManager(
|
||||
val detail = raw?.takeIf { it.isNotBlank() }?.let { ": ${ChatLogSummary.body(it)}" }.orEmpty()
|
||||
throw RuntimeException("prompt_async failed: HTTP $code$detail")
|
||||
}
|
||||
log.info("${ChatLogSummary.sid(id)} kind=prompt op=prompt_async accepted=true code=$code ${ChatLogSummary.prompt(prompt)}")
|
||||
log.debug { "${ChatLogSummary.sid(id)} kind=prompt op=prompt_async ok=true code=$code" }
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
|
||||
+5
-7
@@ -267,15 +267,13 @@ class KiloConnectionService(
|
||||
|
||||
override fun onFailure(src: EventSource, t: Throwable?, response: Response?) {
|
||||
if (source.get() !== src) return
|
||||
val detail = when {
|
||||
t != null -> t.stackTraceToString()
|
||||
response != null -> response.body?.string()
|
||||
else -> null
|
||||
}?.trim()?.ifEmpty { null }
|
||||
val raw = response?.body?.string()?.trim()?.ifEmpty { null }
|
||||
val body = raw?.let { ChatLogSummary.body(it) }
|
||||
val detail = t?.stackTraceToString() ?: body
|
||||
if (t != null) {
|
||||
log.warn("SSE: failure (${t.message}) — scheduling reconnect")
|
||||
log.warn("SSE: failure (${t.message}) code=${response?.code} body=${body ?: "none"} — scheduling reconnect", t)
|
||||
} else {
|
||||
log.warn("SSE: failure (HTTP ${response?.code}) — scheduling reconnect")
|
||||
log.warn("SSE: failure (HTTP ${response?.code}) body=${body ?: "none"} — scheduling reconnect")
|
||||
}
|
||||
setState(ConnectionState.Error(t?.message ?: "SSE connection failed (HTTP ${response?.code})", detail))
|
||||
scheduleReconnect()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user