Adds an experimental.websearch config flag that exposes the websearch
tool to models from any provider, not only the Kilo gateway. The flag
is editable from the VS Code Web Tools settings tab (renamed from
Browser) and the Kilo Console Tools page, with project/global overlay
inheritance and revert support. Environment flags KILO_ENABLE_EXA and
KILO_ENABLE_PARALLEL keep working as before.
The two compaction interruption tests ("stops quickly when aborted during
retry backoff" and "does not leave a summary assistant when aborted before
processor setup") intermittently fail on the Windows CI shard with an
uncaught TimeoutError.
Root cause: Effect 4.x changed Effect.timeout to throw a TimeoutError on
the error channel instead of returning Option (as in Effect 3.x). The
tests wrapped Deferred.await(ready) and Fiber.await(fiber) in
Effect.timeout as a guard against the fiber never reaching the trigger
state, but on loaded Windows runners the fiber can take longer than the
1 second / 250 millis deadlines to reach that state. When the deadline
expired the TimeoutError propagated uncaught and failed the test, even
though the interrupt assertions would still hold.
Swallow the TimeoutError from the ready wait so the test proceeds to
interrupt the fiber regardless of whether the trigger fired in time, and
drop the inner Fiber.await timeout since Fiber.interrupt already waits for
termination. The assertions verify the interrupt exit either way.
* test(cli): stabilize global skill permission test on slow CI
The global skill permission test runs two full agent loops with real
bash subprocess execution but used much tighter timeouts than every
other test in the file:
- Test timeout 15s vs 30s elsewhere
- pollWithTimeout default 5s vs 15s elsewhere
- awaitWithTimeout default 2s for fiber completion vs Fiber.await
with the 30s test-level backstop
On Windows CI (where the file took 64s), these bounds caused
intermittent timeouts. Align all three with the rest of the file
and add a best-effort finalizer to clean up the skill directory
created under the global config path.
* test(cli): focus global skill timeout fix
PR #12158 enforced read permissions for file mentions by routing
directory attachments through the permission resolver with
denyDirectory: true. That flag is set for every prompt-mention
attachment, so the read tool denied all directory listings, including
directories inside the current workspace.
Only deny directory attachments whose canonical path changed after
permission approval. A symlink swap during the permission wait moves
the resolved target, so the approved permission no longer applies and
the listing is denied. Unchanged in-workspace directories are listed
as before.
Fixes#12241
A new Agent Manager worktree session can fail before its first model
response with "All fibers interrupted without error" when automatic
branch-name generation runs concurrently and the Kilo model cache is
expired. Branch-name generation has a 10-second timeout; when it fires,
it interrupted the shared cached model refresh, and every waiter on that
refresh received an interrupt-only cause. SessionPrompt.getModel squashed
that cause into a generic error, which promptAsync published as
UnknownError.
The model cache previously used Effect.cachedInvalidateWithTTL, which
coupled the shared refresh lifetime to the first caller. A timeout or
interruption from one waiter could interrupt the computation observed by
every waiter.
Move the in-flight refresh to the ModelCache service scope:
- A refresh fiber is forked into the service scope, not the caller.
- Each caller awaits the shared deferred interruptibly.
- Caller interruption detaches only that waiter; the service-owned
refresh continues for remaining callers.
- The service-owned fiber commits successful results even when no waiter
survives, so a timed-out branch-name request no longer leaves the
session without a model.
- Overlapping refreshes share one request instead of duplicating.
- Cached stale-version results are promoted to the public provider view
when a newer option load has superseded and failed.
- Clear and invalidate still prevent obsolete flights from restoring
stale data, and existing version checks still prevent stale refreshes
from overwriting newer values.
- Service disposal still interrupts owned background refresh fibers.
Treat pure interruption as cancellation rather than an error:
- SessionPrompt.getModel propagates interrupt-only causes as interruption
instead of squashing them into a generic defect.
- The promptAsync HTTP handler suppresses interrupt-only causes instead
of publishing UnknownError with "All fibers interrupted without error".
- Mixed interruption plus failure or defect remains reportable.
Classification lives in a Kilo-owned helper
(packages/opencode/src/kilocode/effect/cause.ts) using
Cause.hasInterruptsOnly, so only pure interruption is treated as
cancellation.