* fix: make tool invalid-arguments errors clearly actionable to the model
* fix: address kilo-code-bot review on schema error formatting
Return a jargon-free actionable message when the schema formatter yields no issues (instead of the raw SchemaError), and match Effect's missing-key message case-insensitively so it survives library wording changes.
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
* Address review: cap rendered issues, isolate Kilo logic, harden the fallbacks
- Move formatter/format/path/reason out of the shared upstream tool.ts into
packages/opencode/src/kilocode/tool/tool.ts.
- Cap output at 20 issues / 4 KiB with an '...and N more' suffix, since
validation fails before the normal output truncation.
- Return a readable message when the formatter yields zero issues instead of
falling back to SchemaError jargon.
- Match missing-key messages with a regex instead of an exact string compare.
- Rewrite the changeset around the user-visible outcome.
* chore: annotate the reformatted decode call with kilocode_change markers
The multi-line reformat left lines 122-125 unannotated in a shared upstream
file. Wrap the whole statement in a start/end block instead of per-line inline
markers, and drop the two now-redundant inline ones. Comments only.
---------
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Christiaan Arnoldus <christiaan.arnoldus@outlook.com>
* feat: add signal-to-noise controls to grep tool
Add configurable options to reduce noise in grep results:
- context: show N lines before/after each match
- limit: bound maximum matches (default 100) with early termination
- literal: treat pattern as plain text instead of regex
- ignoreCase: case-insensitive matching
These controls help models avoid overwhelming context windows with too
many matches and provide clear guidance when results are truncated.
Implementation preserves upstream ripgrep structure with minimal Kilo
hooks for additive behavior only. Shared-file changes reduced from 183
to 60 lines compared to initial implementation.
* test(core): tolerate PTY event publication race
* fix(cli): count grep matches independently of context
Add a new Kilo-REST Exa transport alongside the existing MCP-Exa
and MCP-Parallel transports. When the websearch tool picks the Exa
provider and the user is signed into Kilo, requests go to
https://app.kilo.ai/api/exa/search with the user's Kilo bearer.
The cloud proxy injects its own Exa API key; the client sends the
user's Kilo API key as a Bearer token. The MCP-BYOK path (EXA_API_KEY)
and MCP-unauthed fallback are preserved unchanged.
Changes:
* New `packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts`
implements `callKiloExa` against the Exa REST API
(`POST /search`) with `{ highlights: true }` contents and clamps
numResults at 10 (Exa's first-10-results flat $0.007 tier).
* `packages/opencode/src/tool/websearch.ts` adds a `"kilo-exa"`
provider variant (selected only via `KILO_WEBSEARCH_PROVIDER`
override), an Auth.Service yield to source the Kilo bearer, a
transport-dispatch block that prefers Kilo-REST over MCP when
auth is available and EXA_API_KEY is unset, and `transport`
metadata on the tool part. MCP-Exa numResults is now clamped
at 10 (default stays 8).
* 13 unit tests in
`packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts`
cover request shape, response formatting, error handling, and
the costDollars ignore case.
* Parameters snapshot updated for the new numResults description
string.
* Patch-level changeset added.
* feat: add AI image generation tool
Port the legacy generate_image tool to the opencode-based CLI as a
Kilo-owned tool gated by experimental.image_generation config flag.
- New generate_image tool with prompt/path/image/model params
- Routes through Kilo Gateway (zero-config) or BYO OpenRouter key
- Supports text-to-image generation and image editing
- Dynamic model discovery via GET /kilo/models/images endpoint
- VS Code settings toggle + live model dropdown in Experimental tab
- Writes image to disk and returns inline FilePart attachment
- Fallback model catalog for offline resilience
* refactor: change default image model to openrouter/auto
* fix: address bot review feedback
- Remove unused fetchKiloImageModels import in tool
- Normalize jpg→jpeg MIME in parser, input image, and attachment
- Replace mismatched extensions in ensureExtension (not just append)
- Add assertExternalDirectoryEffect for output path traversal guard
- Map unauthorized errors to 401 (not 400) in image models handler
- Keep last known model list on fetch failure (don't overwrite with empty)
- Fix tool description (remove false web search claim, fix grammar)
- Remove duplicated provider resolver tests
* fix: add retry for image models request to handle backend startup race
* fix(image-generation): address kilo bot review comments
- ensureExtension replaces mismatched image extensions instead of
appending (photo.jpg + PNG -> photo.png, not photo.jpg.png)
- Gateway /models/images normalizes errors to 400/401 matching every
other gateway route (was leaking undeclared upstream statuses)
- Add 401 response to openapi.json + SDK types for /kilo/models/images
to match the gateway's errors(400, 401) declaration
* fix(gateway): align /models/images error handling with other gateway routes
* refactor: switch image generation to effect HttpClient
* test: cover kilo models images endpoint in httpapi exercise scenarios
* Exclude POST-only and parameterized API endpoints from link checker
* Add ImageModelsProvider to agent manager context tree
* chore(deps): bump @openrouter/ai-sdk-provider to 2.10.0
Switches imageModel() to OpenRouter's POST /api/v1/images endpoint for
proper image usage/billing and image-specific params.
* fix: address image generation PR review feedback
- revert @openrouter/ai-sdk-provider 2.9.0->2.10.0 bump (image tool uses raw HTTP, not the SDK)
- translate image generation settings strings across all locales
- use central KILO_OPENROUTER_BASE instead of hardcoded URL fallback
- remove completed plan file
* chore: refresh source-links.md after URL refactor
* feat(memory): opt-in project memory — capture, recall, CLI + TUI integration
Add project memory: the standalone @kilocode/kilo-memory effect layer plus the
opencode CLI/server/TUI integration. Memory is disabled by default, so it is a
no-op until enabled (no behavior change when off).
Capture (turn-close consolidation): per-op parse salvage, secret redaction that
skips the offending op instead of aborting the batch, supersede-only auto-updates
(never model-driven deletes), correction-aware echo handling, non-LLM fallback
digests on interrupted/error turns, a shared interval throttle with idle-flush.
Recall + injection: keyword tokenizer with camelCase/compound splitting, light
stemming, and an English-first stopword filter (Unicode-aware; non-English falls
back to plain token-overlap), a live relevance floor, a budget-reserved startup
index, a session-digest catalog, and per-session prompt-cache pinning of the
injected memory block.
Surfaces: kilo_memory_save / kilo_memory_recall tools, the memory HTTP API
(contract schemas live in the package), and a status-focused TUI sidebar showing
auto-save, loaded context, and active recall, plus the /memory dialog.
* fix(memory): address PR review feedback
- C1: bump @kilocode/kilo-memory in the changeset
- C2: redact secrets before they hit the audit log (skip + salvage paths);
redact before truncating in salvageTyped so a secret straddling the
500-char cap can't leak an unmatched fragment; opText -> salvageText
- C3: de-abbreviate savedOperations, "changes" wording, ops.ts -> operations.ts
- C4: log.warn on the remaining silent-catch fallbacks (turn diff, memory
context injection, tool-visibility check)
- C5: relocate memory storage from ~/.kilo to Global.Path.data, delete the
now-dead needsDependencyInstall guard, add /memory status (root path) and
/memory edit ($VISUAL/$EDITOR + auto-rebuild)
- C6: replace the hardcoded English stopword list with corpus-derived
ubiquitous-term filtering (df across the user's own entries) and the
English suffix stemmer with suffix-tolerant term matching, so recall
noise-filtering works in any language
- C8: delete the CORRECTION_INTENT English regex; echo turns now run typed
capture (digest stays echo-gated), bounded by the interval throttle, with
the typed prompt as the language-agnostic content filter
- C9: exclude generated paths (dist/build/coverage/*.gen.*/*.map/snapshots)
from the durable-diff churn fallback so generated churn can't burn a
consolidation call
- C11: fix duplicated assert in httpapi-memory test; assert the error body
- kilo-code-bot batch: clause-boundary regex fix, byte-safe catalog
truncation, max-length guards on remember/correct/forget payloads (text,
query, key, sessionID), trim consistency in reconcile, param-shadowing
rename, missing doc entry for kilo_memory_recall, dead-code removal,
dialog UI fixes, memoryEnabledCache eviction bound, dedicated Configure
schema, recall permission renderer, covered-session pointer cap, redact
chat transcript before the consolidation model call, split configProtected
metadata from disableAlways so memory-save prompts don't show config-file
copy, drop unused MemoryService.layer provide from tool registry
- redact colon-separated low-entropy secrets too (password: hunterx),
accepting the prose false-positive tradeoff (secret: enabled) in favor of
not missing a real secret
- rename lastConsolidatedAt -> lastTypedConsolidationAt to make its narrow
scope (typed-consolidation throttle clock) explicit; regen openapi/SDK
- drop now-dead home/config fields from MemoryPaths.Host after the data-dir
relocation; add Process.splitCommand for quoted $EDITOR/$VISUAL paths with
spaces, used by /memory edit and the pre-existing Editor.open utility
* refactor(memory): shared client helpers, capture hardening, /memory UX rework
- extract client-side derivations into kilo-memory so both frontends share
one implementation: MemoryDecisions.summarize (decision-log summary),
MemoryAutosaveStatus.summarize (autosave-status semantics), and
MemoryMarkerMeta (marker wire contract encode/decode)
- match exact-key upserts via the canonical stored id (slugged key,
normalized section) so a re-emitted spaced/uppercase key updates the
entry instead of falling to fuzzy dedupe
- salvageTyped throws on valid JSON without an operations array so the
caller's fallback path records a parse error instead of a silent
zero-op success
- rename memory tool metadata files -> sources (stripPartMetadata rewrites
tool-part metadata.files assuming apply_patch records, mangling string[])
- read state instead of status for tool enabled checks; dedupe TUI helpers
(errorMessage, shared route(), Locale.number, relativeTime)
- /memory UX: bare /memory opens a help modal driven by a structured
command catalog in kilo-memory; /memory on|off become the canonical
toggle verbs (enable/disable kept as quiet aliases); /memory status opens
a clean overview dialog (root path, autosave, startup context, source
counts, index size) instead of a toast; /memory show is the single full
audit view (inspect removed)
Foreground and background subagent failures now include the child
session's task_id and a hint that it can be resumed via the task tool,
so a stopped subagent can be continued instead of being lost (#11620).
- Rename catalog.loader() to catalog.transform() in tests
- Add SessionStatus.Service dependency to tool registry layer
- Remove `loop` method from session prompt ops stubs
- Remove `onOpenChange` prop from BasicToolProps
- Update codex plugin import path to plugin/openai/codex
- Delete packages/cli scaffold (now skipped from upstream)
- Downgrade virtua to 0.42.3 and remove its patch
- Add @ai-sdk/xai@3.0.82 patch for PDF file support
Adapt Kilo-specific code to breaking changes introduced by the v1.15.9
merge:
- Migrate LLM test helpers to use LLMEvent factory constructors instead
of raw event object literals
- Update provider cost extraction from `usage.raw` to native
`usage.providerMetadata` keyed by provider name
- Preserve AI SDK raw usage in providerMetadata for billing continuity
- Replace `findStartIndex()` with `findItemIndex(scrollOffset)` in
virtualizer calls
- Replace `overscan` prop with pixel-based `bufferSize` in virtual lists
- Change provider `all` data shape from array to Map
- Remove `useCommandPalette` dependency, replaced by mode stack pattern
- Fix ToolResultValue schema to avoid circular inference with tsgo
- Add missing test layer dependencies (HttpClient, RepositoryCache,
Command)
- Remove obsolete models-snapshot files
- Fix Permission reply routing tests to expect NotFoundError instead of
boolean false
- Normalize config references and fix nested type narrowing