* feat(cli): add /desktop slash command and kimi install-app subcommand
Both entry points print the Kimi Code desktop app page
(https://www.kimi.com/code) and open it in the default browser:
the kimi install-app subcommand from the shell, and /desktop
(alias /install-desktop) from the TUI.
* fix(cli): derive the desktop app page from the active region
Replace the hardcoded .com URL with the existing region-aware
kimiCodeOfficialInstallUrl() resolved at invocation time, so
global-region users land on the .ai site and region changes are
respected.
* docs(cli): describe the desktop app page URL as region-dependent
* feat(agent-core-v2): add skill scopes and mark custom-theme as tui-only
Builtin skills can now declare a scopes whitelist (tui | web); skills
without scopes stay visible everywhere. The value is carried through
SkillSummary, the klient RPC contract, and the kap-server REST wire,
and the TUI slash commands filter by it. HTTP clients (code-app) drop
skills whose scopes exclude their own UI mode, so TUI-only skills like
/custom-theme no longer leak into app/web.
* fix: filter scoped skills from the acp and vscode palettes
ACP slash commands and the VS Code GetSlashCommands handler also
project SkillSummary lists; both now drop skills that carry a scopes
restriction so tui-scoped skills stay out of non-tui clients.
* feat(agent-core-v2): upload images as file references for Kimi models
* fix(agent-core-v2): scope media upload cache by endpoint and recognize SDK auth error status
* fix(agent-core-v2): restore the stripped /v1 for kimi files uploads on the anthropic route
* feat(agent-core-v2): omit oldest media when accumulated inline media exceed the request budget
* fix(agent-core-v2): key the media upload cache by the stable JWT subject
* fix(agent-core-v2): harden media request recovery
* fix(agent-core-v2): correct image memo accounting
* feat(agent-core-v2): include saved paths in dropped media placeholders
* docs: drop the saved-path re-read guarantee from the media budget note
The guarantee does not hold for inline data-URL media (no persisted
path exists), and the runtime warning already conveys path availability
when it applies. Addresses the codex P2 review suggestion by removal.
* fix(tui): stop /usage and /status from prompting login before the first message
* docs(changeset): simplify the /usage fix entry
* fix(tui): mute the session-usage error line and cover the session-less path in tests
* docs(changeset): restore the confirmed wording
* perf(tui): batch and cache agent swarm progress rendering
* perf(agent-core-v2): evict completed subagent scopes behind an LRU cache
* fix(agent-core-v2): stop the agent actor in the session machine when its scope is removed
* fix(agent-core-v2): emit a terminal event for the final rate-limited run and defer eviction while background tasks run
* fix(agent-core-v2): include in-flight retries when abandoning suspended agents
* fix(agent-core-v2): roll back the closing flag when scope removal fails and wait per the configured eviction timeout
* fix(agent-core-v2): terminalize subagents spawned after batch cancellation and report task timeouts as failures
* chore: restore upstream/main state of files mangled by lint-staged autofix in the merge commit
oxlint --fix rewrites (prefer-set-has, catch-error-name, prefer toSorted/.at(-1)/toReversed)
touched seven files the branch never modified; one of them (oauth managed-kimi-code.ts)
no longer typechecks. Restore all seven to their exact upstream/main state. Committed
with --no-verify so the same autofix does not re-mangle them.
* fix(agent-core-v2): retry deferred scope evictions without exhausting the attempt budget, dedupe terminal events for starting retries, and patch-level the changeset
* fix(agent-core-v2): finish scope teardown instead of reactivating a partially torn-down scope
* fix(agent-core-v2): terminalize subagent-start hook cancellations and re-acquire resume targets after metadata reads
* fix(tui): record cancelled background agents in the transcript
* fix(agent-core-v2): route mirror terminal events through the batch exactly-once guard
* fix(tui): guard terminal swarm members from re-cancellation and deliver terminal status to cancelled foreground subagent cards
* fix(agent-core-v2): classify eviction as removed when teardown already closed the scope
* Merge remote-tracking branch 'upstream/main' into perf/subagent-scope-eviction
Skip lint-staged for this merge: its oxlint --fix pass rewrites unrelated files
(prefer-set-has etc. mangled seven files in the previous merge commit), while the
merge content is upstream's lint-clean code plus conflict resolutions already
verified by oxlint.
* chore: restore upstream/main changes dropped by a stash roundtrip during the merge
A git stash/pop cycle used to isolate an unrelated flaky test reverted 82 files of the
merge result to the pre-merge branch state, so commit 375ff2a4a missed them. The
working tree already held the correct merged content; this commit restores it.
* fix(agent-core-v2): propagate the cancellation reason from turn abort to tool signals
Cancelling a turn aborted the turn's llm scope and every tool scope
without a reason, so tools and subagents only ever saw the default
AbortError and could not tell a user cancellation from a system abort.
With the swarm terminal-event classification this surfaced as
`subagent.failed` ("This operation was aborted") on Ctrl+C instead of
`subagent.cancelled`.
Carry the reason end to end: `MachineEngine.abort(reason)` sends it on
`input.abort`, the agent machine remembers it for the turn and forwards
it to `turn.abort` and to every tool scope it aborts, the turn machine
passes it to the llm scope, and the loop service hands its cancellation
(a `UserCancellationError` by default) to the engine.
* fix(agent-core-v2): stop rebuilding an evicted subagent after its caller aborts
`createAgentAwaitingClose` polled for the previous scope to finish
closing without ever looking at the caller's abort signal, so cancelling
an `Agent` or `AgentSwarm` resume during that wait still recreated the
scope afterwards. In the `Agent` path the run then rejected before any
terminal event was mirrored, leaving an idle scope that the scope cache
no longer tracked.
Thread the caller's signal into the helper and check it before every
attempt; the Agent tool passes its call controller and the swarm service
passes the attempt signal. Also trim the eviction changeset to the one
sentence the changeset rules ask for.
* fix(agent-core-v2): report task-manager aborts of a subagent as cancelled
When the task manager times out or stops a background subagent it aborts
the run with a plain reason ('Timed out', the TaskStop reason), and the
run rejects with that raw reason. The task manager therefore classifies
the task as timed_out or killed, but the mirror only recognised
`UserCancellationError` as a cancellation and emitted `subagent.failed`,
so the transcript recorded a failure before the authoritative
`background.task.terminated` event could land.
Classify a terminated run by the shape of its abort reason: a real
Error that is not an AbortError (the swarm's own per-item timeout) stays
a failure, everything else that aborted the run is a cancellation. The
swarm's start-failure path uses the same rule.
* fix(agent-core-v2): flush the wire before evicting a subagent scope and re-pick LRU candidates
Two gaps in the scope-cache eviction pass:
- `AgentLifecycleService.remove()` swallows a failed wire flush and still
tears the scope down, so an eviction that hit a disk-full or transient
I/O error would drop the in-memory scope and let a later resume rebuild
from a stale wire. Flush the agent's wire explicitly before removing;
if that fails, keep the scope resident and retry on a later pass. The
idle and task checks are repeated after the flush so a resume that
started meanwhile is not cancelled by the removal.
- The pass snapshotted its candidates up front and re-validated them by
attempt count only, so a scope that was resumed and completed again
while an earlier eviction was awaited kept matching with attempts 0 and
was evicted despite now being the most recently used. Pick the oldest
eligible entry from the live map on every step instead, skipping only
the entries this pass already tried.
---------
Co-authored-by: Kaiyi <me@kaiyi.cool>
* fix(plugins): rename WebBridge display name to Kimi Browser Extension
The product has renamed WebBridge to Kimi Browser Extension in work and
Chrome. Update the user-facing display name across the built-in
capability entry, TUI plugins selector, managed plugin manifest,
marketplace catalog, skill docs, and user docs to match. Internal ids,
binary names, CDN paths, and daemon references are unchanged.
* fix(plugins): bump webbridge to 1.11.4 and keep legacy docs anchor
Address review: point the changeset at the scoped CLI package, bump the
renamed plugin's manifest/catalog/docs version so installed users are
offered the renamed package as an update, and preserve the published
#kimi-webbridge documentation anchor beside the renamed heading.
* docs(plugins): match only the known extension-update error messages
Broadening the version-mismatch trigger to the generic prefix 'Please
update the' would misclassify unrelated tool errors as an outdated
browser extension; match the two known full messages instead.
---------
Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
The platform /usages payload now serves per-window used ratios
(goods_version, a usages map of limit5h/limit7d/monthTotal/monthCode
entries with used_ratio/reset_time, and boosterWallet) instead of
absolute used/limit rows.
- oauth: parse and fetch the quota model; keep the platform helpers
- toolkit / agent-core-v2 / node-sdk: getManagedUsage returns the quota
- kap-server: /oauth/usage passes the camelCase quota shape through
(the legacy snake_case wire is gone)
- TUI /usage: plan rows are presence-driven from the quota payload;
the monthly row carries a kimi/code breakdown line
- docs: server-api reference updated for the new response shape
* perf(tui): batch and cache agent swarm progress rendering
* perf(tui): honor the render-cache escape hatch for cell memoization
* fix(tui): stop swarm frame ticks after tool call end and cap retained label code units
* fix(tui): house swarm label caps in TUI constants and stop splitting surrogate pairs
* fix(tui): close OSC 8 hyperlinks sliced by the swarm label storage cap
* fix(tui): reset SGR styling sliced by the swarm label storage cap
* fix(tui): back the swarm label storage cap off to grapheme cluster boundaries
* test(tui): verify swarm terminal-state retention through the render seam
* perf(agent-core-v2): shard the session event bus by agent id
* fix(agent-core-v2): preserve full-stream-before-typed ordering in agent channels and render perAgent counts in the inspector
* fix(agent-core-v2): deliver agent full streams before session typed handlers and dispose sharded channels with the bus
* fix(agent-core-v2): prevent rebuilding agent channels after the event bus is disposed
* fix(agent-core-v2): isolate agent channels on generation replace and keep typed handlers on the shared per-type channel
* fix(agent-core-v2): require the active lifecycle context before firing an agent full-stream channel
* fix(agent-core-v2): reject stale lifecycle contexts when subscribing to an agent full-stream channel
* fix(agent-core-v2): honor the agent context in typed subscribeAgent subscriptions
* refactor(agent-core-v2): fold the prompt queue into the agent loop service
Delete AgentPromptService/IAgentPromptService: prompt submit/queue/steer/
abort now ride the agent machine queue through IAgentLoopService's extended
surface (submitPrompt/submitSteerPrompt/enqueuePrompt/steerPrompts/
abortPrompt/drainPrompts/injectPrompt/retryPrompt/promptQueue plus
hooks.onBeforeSubmitPrompt and the promptAdmission reservation slot).
Durable prompt.* event classes move to agent/prompt/promptEvents.ts and keep
their registrations; promptAdmissionKey keeps its fold. Dead assets go away:
promptResolutionKey, PROMPT_ALREADY_COMPLETED (kap-server 40903 path),
promptLaunchingKey and clear(). Compaction gating (queue while compacting,
resume on finish) moves into the loop reservation drain.
The 'agentPromptService' wire name keeps its shape: a thin AgentPromptChannel
facade (same decorator id) forwards submit/submitSteer to the loop, so
klient memory/ipc/debug transports and the kap-server dispatcher are
unchanged.
* test(agent-core-v2): re-pin prompt queue semantics on the loop service
Rewrite promptService.test.ts (25 cases, count unchanged) against the real
AgentLoopService with the scripted-LLM harness, fold the launch-window
reservation out of promptQueue().pending to match the old snapshot contract
exactly, and update the debug-channels pin to the facade's submit/submitSteer
surface.
* refactor(agent-core-v2): lint-align the loop prompt queue surface
* fix(agent-core-v2): settle prompt completions on the turn-result chain
Match the deleted service's microtask position: prompt.completed/aborted and
the completion deferreds fire from a result.then chain attached at bind time
instead of synchronously inside endTurn, so wire/emit ordering with
post-turn producers (tool unregister, next-prompt launch) stays identical to
the baseline snapshots. Steered children move onto the reservation so the
chain can settle them after the active turn is gone.
* refactor(agent-core-v2): move the prompt-submit gate into the agent machine
* refactor(agent-core-v2): keep image compression captions inline in prompt messages
* refactor(agent-core-v2): drop the durable prompt admission facility
* refactor(kap-server): resolve prompt auth at turn runtime instead of submit time
* refactor(agent-core-v2): teach the agent machine queue metadata, multi-id steer, gate rewrite, and pause
* refactor(agent-core-v2): converge prompt submission on machine queue user entries
* refactor(agent-core-v2): replace loop prompt records with a waiter registry fed by machine events
* feat(kap-server): add flat entity message protocol (v3 WS + history API)
* feat(kap-server): add task notification user messages, skill origins, and history has_more
* fix(kap-server): page history by turns so oversized turns stay reachable
* fix(kap-server): synthesize foreground subagent tasks in the cold fold when no task records exist
* fix(kap-server): dedupe queued prompts for turn records without a prompt id
* fix(kap-server): adapt v3 projection to agent-core-v2 API changes and filter empty thinking
* feat(kap-server): align v3 protocol with design revision 1094 and add agent.state
---------
Co-authored-by: liruifengv <liruifeng1024@gmail.com>
* fix(remote-control): carry server token in rc local UI link
- add required localServerToken to RemoteControlOutputOptions
- render the Local UI line with buildOpenableUrl and dim the #token= fragment like the ready banner
- pass the resolved token at both rc call sites (kimi web --rc, TUI /rc)
* chore(changeset): add changeset for rc local UI token fix
* fix(remote-control): align rc output test with token-bearing local UI link
- assert the Local UI line carries the #token= fragment
- scope the token-free ban to the relay and session URLs, which must never leak the local server token
The human/llm provider-catalog state machine becomes the single source of
truth for the runtime model/provider directory. IModelCatalog's data plane
reads through a new llm-adapter catalog-runtime adapter that mirrors config
section diffs into catalog upserts, and CatalogEntry cache invalidation is
driven precisely by the machine's changed events instead of a blunt clear.
The persistence layer is untouched: config.toml stays the full source of
truth and refresh results keep being written to it.
Also remove the model resolution trace/inspect stack end to end:
ResolutionTraceCollector, the llm-adapter model/contract inspection modules,
IModelCatalog.inspect, the capability explainability indirection, and the
kimi-inspect model inspector panel.
- the human agent state machine now assigns turn ids and echoes the drained queue item in turn.started; the facade adopts machine ids instead of reserving its own
- the turn machine produces the step ordinal and surfaces it via a first-class step.started fact; the llm requester layer stays step-agnostic
- turn.prompt wire records carry an explicit turnId; turnKey and transcript foldFacts read it directly with a counting fallback for legacy records
- queued prompts are addressed by promptId: cancel(turnId) is active-turn only, cancelQueued targets queue entries, Turn.id resolves once the turn starts
- drop PromptPayload.disabledTools and its klient/node-sdk pass-through (no client consumer)
* feat(agent-core-v2): accept HEIC, HEIF, and BMP images for Kimi models
Key the accepted image MIME set by the provider the agent is bound to
instead of a single global allowlist: Kimi accepts PNG/JPEG/GIF/WebP plus
BMP/HEIC/HEIF, every other provider keeps the baseline set. The provider
image policy lives in the human layer (`llm/media/image-formats`) so both
the agent-side gates and the Anthropic protocol lowering share it.
- thread the provider type through every ingestion gate: ReadMediaFile,
prompt entry, MCP tool results, session media references, kap-server
prompt/skill routes; expose it via IAgentProfileService.getModelProviderType
- ReadMediaFile sends accepted formats it cannot re-encode locally inline
up to the provider's per-image budget (5MB for Kimi, 3.75MB otherwise)
and points at a conversion command above that; full_resolution uses the
same provider budget
- acp-server no longer gates formats itself and leaves the decision to the
engine prompt pipeline, which knows the bound provider
- the Anthropic lowering allowlist follows the bound provider so Kimi over
the Anthropic-compatible protocol no longer rejects HEIC client-side
* fix(agent-core-v2): resolve the image format policy on the production paths
Follow-ups from review of the provider-aware image formats:
- the Anthropic lowering read the policy from `LlmModel.provider`, which
the adapter registry sets to the route id (`anthropic`) rather than the
model's provider type, so Kimi over the Anthropic-compatible protocol
still rejected HEIC client-side; the accepted set now comes from a
`ProtocolTrait.acceptedImageMimes` hook that the Kimi traits implement,
and the test goes through the real trait with the routed provider id
- kap-server prompt ingestion gated media against the currently bound
model even when the same request selected another model; the profile
service now resolves the provider type for a requested alias
- the session media memo served a cached inline image to a provider that
does not accept its format; memo hits are re-judged against the current
provider before being returned
- the media tools registrar keyed ReadMediaFile only by alias and
capabilities, so a reload that changed the alias's provider type or
protocol kept the stale tool; both now take part in the key
* test(kap-server): keep the optional chain the lint autofix dropped
* refactor(interaction): replace per-agent InteractionService with human-native session facade
- add human/interaction: global interaction machine + tag-query facade (enqueue/respond/findAll/findOne/wait)
- add session-scope SessionInteractionService owning one interaction actor per session
- rewire approval/question/userTool/sessionActivity to the session facade and delete features/interaction
* refactor(interaction): rewire kap-server, klient and node-sdk to the session interaction facade
- kap-server routes, ws broadcaster and transcript binding read ISessionInteractionService (tags replace origin)
- klient memory dispatcher delegates to the session service; zod contract mirrors origin -> tags
- node-sdk session wiring subscribes the session service directly
- register interaction wire events in their new home and regenerate the wire manifest
* refactor(agent-core-v2): replace interaction DI services with a global human singleton
resolve rebase conflicts
- scrub all ambient KIMI_CODE_* env vars in the agent-core-v2 and
kap-server test setups so developer shell env cannot leak in
- drop the load-sensitive stepRetry fake-timer cases and the three
FSEvents-based skill catalog watch cases
- give node-sdk, klient and the vscode extension project an explicit
15s testTimeout matching their integration-test nature
- retry temp-dir removal in taskManager teardown to absorb async
terminal-effect writes
* fix(telemetry): stop silently dropping key event attributes
- turn_ended now carries error_type (the engine error code) when a turn
fails, matching the v2 event catalog definition that no emitter set
- TelemetryClient reports properties dropped by sanitizeProperties via a
new onUnexpectedError hook, wired to the CLI, web, and v2-print logs
- session_started client attribution keys emit empty strings instead of
null so they survive payload flattening
* fix(telemetry): sanitize at sink accept time and guard the drop handler
Addresses review on #3638:
- Properties are sanitized when the sink accepts the event (at track time
on the direct path, at drain time for the pre-init queue), so drops on
events queued before initialization are reported once
onUnexpectedError is installed
- The onUnexpectedError hook is invoked behind a guard, mirroring the
agent-core-v2 unexpectedError path, so a faulty host handler cannot
abort track()
* fix(telemetry): snapshot queued properties at track time
Addresses review on #3638: the pre-init queue now stores the sanitized
snapshot taken at track time (only primitives survive, so the snapshot
is exact), and the dropped keys ride along as pending diagnostics that
are replayed once the handler is installed. Callers mutating a reused
properties object between track() and initialization can no longer
alter the emitted event or its drop reports
* feat(kimi-code): two-line collapsed tool cards with width-aware headers
Collapsed cards now show the call on line one and a single dim outcome
row on line two: a Bash command's last output line (the live tail while
running) with a line-count chip, a Grep/Glob path sample, or a generic
tool's first output line. Read groups stay header-only and honor the
global expand state; failed calls keep their preview. Headers split into
head / flexible / tail segments so a long command fills the terminal
width before the chip.
* feat(kimi-code): NotifyUser tool and mid-turn update panel
Add an experimental NotifyUser tool (flag notify_user, off by default)
that agent-core-v2 offers only when the host declares the update_panel
UI capability at bootstrap; the TUI declares it through the SDK harness
options. The system prompt's guidance to send updates is injected only
when the tool is active for the agent. The TUI renders the turn's
updates in a panel above the editor (stacked, 8-row window, Ctrl+N pages
back) that the next turn clears, and keeps a one-line card in the
transcript.
* feat: add subagent updates and bidirectional paging
* fix: preserve session tools and prompts when toggling updates
* fix: correct notification delivery and CI regressions
* feat(secondary-model): drop the experimental flag from the subagent model pool
* feat(secondary-model): sync the web bundle without the experimental gate
* feat(agent-core-v2): anchor compaction resumption on the latest user message
* fix(agent-core-v2): count the continuation anchor in tokensAfter
* fix(agent-core-v2): simplify the continuation anchor to a single statement
* fix(agent-core-v2): avoid absolute claims in the compaction continuation texts
* fix(agent-core-v2): flag the continuation anchor in compaction records so old records replay unchanged
* fix(agent-core-v2): replay the continuation anchor unconditionally, drop hasContinuation
The anchor is an injection (policy, not history): like the system prompt
and other reminders, it is re-rendered by current code at replay time, so
pre-anchor compaction records gain it on resume. The divergence is
self-limiting (only records written before this change, absorbed on first
resume) and needs no per-record format flag. Fold-length accounting counts
the anchor unconditionally to stay at parity with the rebuilt context.
* fix(vis): align the context projector with the compaction continuation anchor
Locate the compaction summary by origin instead of assuming it is the last
shape message (the anchor now follows it), and pin the anchor in the
projection expectations.
* feat(tui): show each background agent's model in the /tasks list
* fix(agent-core-v2): carry model and thinking effort in tower spawn task metadata
* fix(tower): honor subagent timeout config for tower spawn tasks
TowerSpawnTool registered its detached subagent task with the hardcoded
DEFAULT_SUBAGENT_TIMEOUT_MS, bypassing the [subagent] timeout_ms setting
and KIMI_SUBAGENT_TIMEOUT_MS. Resolve the timeout through
resolveSubagentTimeoutMs(config) like AgentTool does, keeping the 2h
default when nothing is configured.
* test(agent-core-v2): deflake the sessionIndex perf baseline under load
* feat(agent-core-v2): carry user-verbatim mission context through tower briefings
TowerPlan missions accept an optional context field holding the user's
own key sentences verbatim, rendered into the mission file and every
briefing that embeds it. Reviewer briefings now include the full mission
text and the author's review-request, with an intent-first checklist;
worker briefings escalate substantive ambiguity to the tower before
acting and reconcile completion reports task by task.
* chore: merge tower changesets into one
* refactor(tui): narrow tasks-browser host appState with Pick
* docs(agent-core-v2): correct the subagent timeout description in the Agent tool
* docs(agent-core-v2): drop the timeout bullet from the Agent tool description
---------
Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>
* feat(kimi-code): two-line collapsed tool cards with width-aware headers
Collapsed cards now show the call on line one and a single dim outcome
row on line two: a Bash command's last output line (the live tail while
running) with a line-count chip, a Grep/Glob path sample, or a generic
tool's first output line. Read groups stay header-only and honor the
global expand state; failed calls keep their preview. Headers split into
head / flexible / tail segments so a long command fills the terminal
width before the chip.
* feat(kimi-code): show short tool output whole and point at hidden output
Collapsed cards now show up to three output lines before falling back to
a single outcome row, the Grep chip counts files or matches according to
output_mode, and the tools' pagination and empty-result notices no longer
count as results. While the recent turns hold tool output that ctrl+o
would reveal or hide, the footer shows ctrl+o expand or ctrl+o collapse.
* feat(kimi-code): mark hidden tool output with counts and direction
A collapsed Bash card's chip now counts the hidden lines (`N more
lines`), its last-line outcome row carries a leading ellipsis, a generic
tool's first-line row a trailing one, and the Grep glance keeps its
"+N more" count in the fixed tail so width cuts drop samples, never the
count. Background Bash results identify the task by their first
metadata line instead of trailing internal hints, and header truncation
now treats ANSI escapes as atomic zero-width units and stays bounded by
the terminal width for huge arguments.
* fix(kimi-code): keep tool notices and context rows out of result counts
Glob's timeout, truncation, and warning lines no longer inflate the
file count or pose as glance samples, and unnumbered Grep content with
context flags falls back to an exact file count instead of claiming
matches it cannot distinguish. The footer's ctrl+o hint now also
appears when an outcome row is cut by the terminal width — one to three
very long lines hide the remainder that ctrl+o reveals wrapped.
* fix(kimi-code): align the ctrl+o hint with what expansion reveals
The Edit check now uses the same clustered diff render as the preview
(context rows and inter-hunk separators count toward the cap), and an
ExitPlanMode outcome card no longer reports hidden content — the plan
is fully rendered by the call preview and its result body is
expansion-independent. OUTCOME_MAX_LINES moves to the TUI constant
directory with the other shared rendering limits.
* fix(kimi-code): tighten the collapsed-card hidden-content signals
Outcome rows drop terminal control sequences before they are cut, a
failed Bash card leaves the hidden-line count to its preview trailer,
an unnumbered Grep glance lists each file once, a solo subagent card
never reports hidden content, and the glance sample cap joins the other
collapsed-card limits in the rendering constants.
* fix(kimi-code): count paginated Grep totals and wrapped error previews as hidden
The Grep chip and glance use the tool's count-mode summary and pagination
total instead of the current page, Windows drive letters stay inside
unnumbered content paths, Glob's ripgrep stderr continuation lines no
longer count as files, a background question follows the line-count rule,
and an error preview whose long line wraps past its row cap keeps the
footer's ctrl+o hint on.
* fix(kimi-code): treat spilled tool output as an envelope, not as results
An oversized result reaches the TUI as agent-core's truncation envelope;
cards now render its first line as the outcome row and carry no chip
instead of counting its metadata as files or lines. The Grep chip keeps
the count-mode totals on an empty page, and the Bash chip counts rows
the way the outcome rows do, so whitespace-only rows never claim hidden
lines.
* fix(kimi-code): widen the hidden-content signal to failed previews and ! cards
A paginated content search reports the tool's match total, a capped Edit
or Write preview counts as hidden even when the call failed, and a
user-run ! command card tells the footer about its running tail or
capped result.
* fix(kimi-code): keep result chips honest on incomplete, narrow, and cut-off cards
Grep and Glob counts read as lower bounds (`12+ files`) when the tool
reports a timeout or output cap, a header too narrow for its fixed parts
drops the middle and cuts the head before the chip, and a call whose
arguments were cut off by max_tokens no longer claims hidden content.
* fix(kimi-code): stop the expand hint lying on goal cards, ! cards, and paginated context
A pagination total only stands in for the match count when no context
flag is set, a ! command card that finished while expanded still counts
its rows past the preview cap, parsed goal snapshots and bodiless goal
updates report nothing to expand, header fitting measures graphemes
instead of trusting code-unit length, and the escape pattern and tail
window join the rendering constants.
* fix(kimi-code): read zero context flags as none and mirror the Edit cap exactly
A Grep call with -A/-B/-C set to zero produces no context rows, so its
matches stay countable; the Edit hidden-content check now renders the
preview capped and uncapped and compares them, so a body that fills the
cap exactly no longer counts as cut.
* fix(kimi-code): keep the collapse hint for expanded cards outside the window
Toggling ctrl+o off collapses every expanded card, including one that
slid before the three-turn cutoff since it was expanded, so the footer
now keeps offering collapse while any expanded card hides content. Grep
context detection follows the backend's -C precedence, where a defined
-C makes -A and -B moot.
* fix(kimi-code): render Edit and Write results the same way in both states
Their one-line success acknowledgements repeat what the header, chip and
preview already show, so they render in neither state; any other
successful output shows as an outcome row in both. The footer's expand
hint therefore depends only on the capped preview for these cards.
* fix(kimi-code): keep a Read group's failure count on narrow rows
The finished header is three segments — label, line count, `· N failed`
tail — so a narrow row drops the line count before the failure count,
which is the only sign of partial failure while the per-file body is
collapsed.
* fix(kimi-code): show cut-short empty searches and keep the hint with a status command
A Grep or Glob the tool cut short before any row renders its notice
instead of an exact-looking empty result and carries no chip, a
ReadMediaFile result that is not a media envelope follows the line-count
rule, and the footer's ctrl+o hint moves to line 2 when a
status_line.command owns line 1.
* fix(kimi-code): count unreadable directories as an incomplete Glob and stop hinting on notice-only searches
A Glob that skipped unreadable directories reports its file count as a
lower bound, and a search cut short before any row — which renders only
the tool's notice, the same way in both states — no longer makes the
footer offer ctrl+o.
* fix(kimi-code): let the ctrl+o hint displace an inline tip and count parsed WaitFor results as hidden
An inline tips slot gives way when the fixed hint would not fit beside
it, and a parsed WaitFor result — whose raw fields only render when
expanded — reports hidden content instead of falling to the line-count
rule.
* fix(kimi-code): keep spill pointers and sensitive-only notices out of counts and honor streaming previews
The per-line truncation pointer agent-core appends to an oversized
result stays out of line and file counts, byte sizes and outcome rows; a
search whose only matches were filtered as sensitive files shows the
tool's notice instead of an exact-looking empty result; and while
arguments still stream, only a Bash card (whose partial command appears
once expanded) reports hidden content.
The decode-window split measured part arrival at the moment the event
loop resumed the pending await, so any loop-busy work (rendering,
timers, GC) between parts was reported as server time. Measure loop
utilization across the decode window with perf_hooks and split it into
loop-idle wait (server), per-part processing (client), and a new
clientBlockedMs bucket (loop busy with other work), carried through to
the step events, wire record, transcript contract, and the TUI debug
timing line.