mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-01 20:44:53 +00:00
173 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9e1248416f
|
fix(web): remember the thinking level per model (#1838)
* fix(web): remember the thinking level per model Persist kimi-web.thinking as a JSON map of model id to level instead of a single global value, and resolve the active level against the model's catalog (stored pick when still declared, else the model default) at loadModels, setModel, and on active-model changes via a watcher. Fixes the empty, unresponsive thinking picker shown for a model that does not declare a previously stored level (e.g. a max-only model with a stale global 'low'). * fix(web): resolve a submitted prompt's thinking from its own model submitPromptInternal and the steer path read the single active-session rawState.thinking, so a queue drain for a background session submitted the level of whichever session the user had switched to since enqueueing — the same cross-model leak on the submit path. Thinking now joins model and the per-session modes in being resolved from the prompt's own session model (its stored pick when declared, else the catalog default), falling back to the active value only when the model has left the catalog. * fix(web): keep model switches from persisting derived thinking defaults setModel routed the resolved level through applyThinkingLevel, which writes per-model storage unconditionally — a switch to a model with no saved pick stored the catalog default as if it were an explicit choice, pinning the user to it across later default changes, and the rollback path did the same write for a switch that never happened. Model switches now update the in-memory level only; storage writes stay with setThinking, the explicit picker path. * fix(web): resolve thinking per target session on the BTW and skill paths sendSideChatPromptOn combined the captured parent's model with the active-session level, so a session switch during the startBtw await sent the BTW first turn at the wrong model's effort — resolve it from the parent's own model, falling back to the active value off-catalog, same as the other submit paths. activateSkill carries no thinking either, so the daemon ran skills at the session profile effort, which can predate the per-model restore the picker now shows. Persist the resolved level to the session profile first, mirroring the new-session skill path; that path itself now resolves against the new session's model instead of the raw active value. * fix(web): keep per-model thinking picks in memory as the runtime truth The resolver re-read localStorage on every submission, letting storage — not the displayed state — decide what the daemon receives: with storage unavailable (policy/quota) an explicit pick reached the UI while every submit path fell back to the catalog default, and a pick made in another tab silently changed what this tab submits mid-session. Per-model picks now live in an in-memory map hydrated from localStorage at startup; explicit picks update it first and persist best-effort (read-modify-write merge, so concurrent tabs' entries still survive). localStorage is only hydration plus persistence — another tab's pick can no longer alter this tab's runtime level. * fix(web): carry the legacy global thinking pick forward as a fallback Pre-map installs stored a single global level as a raw string; the map parser dropped it, silently resetting the user's explicit preference to the catalog default on upgrade. The legacy value is now carried as a fallback for models without their own entry — validated against each model's catalog at resolution, so effort models keep the user's pick while a max-only model still falls through to its default and can never be trapped by it. * fix(web): keep the legacy thinking fallback across the first map rewrite The first explicit pick after an upgrade rewrote the raw legacy value into a map containing only that one model, so the next reload saw a nonempty map and dropped the legacy fallback for every other model. The migrated value now lives inside the map under a '*' key that no real model id can collide with: per-model entries override it, and rewrites persist it alongside them instead of deleting it. * fix(web): persist only the changed thinking pick on write Overlaying the whole in-memory map on write could revert a newer pick made in another tab for a model this tab still held a stale copy of. Write the changed entry alone (delta-style, like saveUnread), carrying only the migrated legacy '*' fallback along so it survives the first rewrite into map format. * fix(web): abort skill activation when the thinking profile persist fails persistSessionProfile surfaces failures itself and resolves, so awaiting it never blocked a following activation: a failed /profile write still launched the skill at the session's stale effort. It now resolves a success flag; both activation paths (existing session and new-session draft) gate on it and skip activating when the persist fails, without reporting a second, synthetic error. * refactor(web): persist the new-session skill profile's thinking once startSessionAndActivateSkill persisted the resolved thinking and then activateSkill persisted it again unconditionally — a redundant profile update and status refresh whose transient failure would false-veto an activation whose prerequisite profile was already applied. Thinking is now written by activateSkill alone (the single, gated writer); the draft patch carries only model, plan/swarm and permission. * fix(web): throw an Error instance for the profile-persist sentinel oxlint --type-aware (only-throw-error) rejects throwing a Symbol; the identity-based sentinel works the same as a shared Error instance. * fix(web): resolve an empty session model through the default before skills session.model can be '' transiently (daemon profile echo), so activateSkill fell back to the raw active-view level; in the new-session flow a concurrent switch could persist another model's effort onto the target session. Normalize '' through the configured default_model first, same as the prompt/BTW/steer paths. |
||
|
|
03021b6db7
|
fix(kimi-web): stop the prompt queue from ghost-sending stale attachments (#1833)
* fix(kimi-web): stop the prompt queue from ghost-sending stale attachments Sending while a turn was running queues prompts locally. A failed flush left entries stuck, and every later session open silently re-submitted them with their old file attachments. Gate the drain on locally witnessed turns, re-drive stuck entries FIFO from real events with a failure budget, restore merged entries on steer failure, persist the queue per session so a refresh loses nothing, and converge queues across tabs via storage events. * fix(kimi-web): merge cross-tab queue updates by entry id (review P1/P2) Whole-record adoption could silently discard a prompt another tab enqueued concurrently. Queue entries now carry a stable id and enqueue timestamp; adoption union-merges snapshots by id, a shared TTL'd removal set stops flushed/discarded entries from resurrecting (and being flushed twice), an in-flight marker covers the submit window, and manual reorders re-stamp timestamps so they survive merges. The flush failure budget is also tracked per entry instead of per session, so removing or reordering the head no longer hands its strikes to the next entry. * fix(kimi-web): single-flusher queue entries, merge order convergence, forget guard (review round 2) Turn-end events reach every open tab and the server accepts concurrent submissions as distinct prompts, so two tabs holding the same adopted entry could both submit it. Entries now record their owner tab and only the owner flushes (ownerless legacy entries flush anywhere); an idle send adopts entries left behind by closed tabs so a stranded queue can still drain. Cross-tab merges now keep the newer enqueuedAt copy per id so a manual reorder converges instead of ping-ponging writes, and the flush failure callback no longer resurrects a queue whose session was forgotten while the submit was pending. * refactor(kimi-web): drop the cross-tab queue persistence, keep the minimal fix Cross-tab queue sync over localStorage is a distributed-systems problem (claim/lease, conflict merge, ownership) that keeps generating review findings far beyond this PR's scope. Remove the persistence/hydration/ adoption machinery wholesale; keep the bug fix proper: gated queue drain, event-driven FIFO retry with a per-entry failure budget, steer queue restore, and the forgotten-session flush guard. Durable queued prompts will be designed together with the server-side prompt queue. * chore: align the changeset wording with the reduced scope * fix(kimi-web): never duplicate on ambiguous submit failures; advance after drop Two review findings: (1) restoring merged queue entries after ANY steer failure could re-submit prompts the daemon had already accepted when the failure was a lost response — submits now report ok/rejected/uncertain and restores + flush re-queues happen only on definitive daemon rejections, while ambiguous failures drop the entry (the failure toast still tells the user); (2) dropping an exhausted queue head no longer strands the entries behind it — the new head is submitted immediately, carrying its own failure budget. |
||
|
|
56a321d4d1
|
fix(workspace): dedupe workspaces across Windows path spelling variants (#1809)
* fix(workspace): dedupe workspaces across Windows path spelling variants The same directory reached the workspace registry as distinct strings on Windows (drive-letter casing, typed vs on-disk casing, slash style), and every identity check compared exact strings, so one folder could appear as multiple workspaces with sessions split across hash-keyed buckets. - add workspaceRootKey (slash-normalize + case-fold Windows-shaped paths) in agent-core, agent-core-v2, and the web app, and compare roots by identity key everywhere instead of exact strings - registry createOrTouch folds alias spellings onto the existing entry instead of minting a new workspace id; session buckets reuse the registered id via a resolver in the v1 session store - list endpoints expand alias buckets (resolveAliasIds / resolveAliasWorkDirs, including session-index-only spellings) so previously split workspaces list all sessions and counts under one merged group; session_index entries use the registry-resolved id * fix(workspace): fold the runtime touch path and drive-root identity keys Two gaps in the Windows path-spelling folding, both reachable in the v1 session-create flow: - touchWorkspaceRegistry minted the alias spelling's id outright; the freshly persisted alias entry then became the resolver's preferred id on the next create, splitting sessions into a duplicate bucket again. It now folds onto the identity-matching existing entry, mirroring the registry service. - workspaceRootKey stripped trailing separators before testing the Windows shape, so a drive root (C:\) collapsed to C: and escaped the case-fold. The shape test now runs before the strip in all three copies (agent-core, agent-core-v2, web). * fix(workspace): unfold symmetric operations that escaped the identity key Two asymmetric spots left the folded comparison one-sided: - the web app matched hidden roots by folded key but cleared them on re-add by exact string, so hiding C:\Foo and re-adding c:\foo kept the workspace hidden forever; clearing now folds too - registry delete (both engines) removed and tombstoned only the exact id, so a legacy split sibling resurfaced as the directory's representative on the next list; delete now removes every registered spelling sharing the root's identity key and tombstones the full alias set (registered ids plus session-index spelling mints), so the session-index merge cannot resurrect the directory either |
||
|
|
319001ae5c
|
refactor: remove git detection from workspace wire and folder browse (#1787) | ||
|
|
b5139757e2
|
fix: align context usage display with 1024-based units and ceiled percents (#1771)
* fix(web): align context usage display with 1024-based units and ring-only meter
- simplify the composer context meter to the ring only; the full
used/max/pct numbers live in the tooltip
- format token counts with 1024-based k/M units via a shared formatTokens
helper (256k context reads "256k", not "262k"), applied to the composer
tooltip, status panel, mobile settings sheet, model picker, goal strip,
and turn rendering
- ceil the usage percent so sub-0.5% usage still shows a sliver instead
of an empty meter
* fix(tui): render context usage with 1024-based units and ceil percent
- formatTokenCount is now 1024-based ("256k", not "262.1k"); the footer,
/status and /usage panels, subagent cards, and goal stats all share it,
replacing five local 1000-based copies
- the footer and panel percents use an integer ceil (new usagePercent
helper) so any non-zero usage shows at least 1% instead of "0.0%"
* fix(web): clamp the status panel context percent to [0,100]
ctxUsed can momentarily exceed ctxMax (estimates), which could flash a
"101%" readout — the composer and mobile sheet already clamp the same
ConversationStatus data, so apply the same clamp around the ceiled
percentage here.
* chore: merge the context usage changesets into one
* chore: reword the context usage changeset in English
|
||
|
|
78967e283d
|
refactor(model-catalog): drop WS catalog-changed event; refresh on picker open (#1772)
- kap-server: remove event.model_catalog.changed from the v1 WS union, broadcaster forwarding, and the zod event registry - web: refresh all providers (POST /providers:refresh) before loading models when the model picker opens, replacing the event-driven refresh - keep domain publishers, the protocol schema, and the web receiver for compatibility with older daemons |
||
|
|
7042af3571
|
fix(web): keep the sidebar resize handle above the chat composer background (#1766) | ||
|
|
df75a0f5c2
|
refactor(agent-core-v2): derive session busy from agent activity (#1751) | ||
|
|
e885aec7ff
|
feat(web): show detailed diagnostics for model request failures (#1756)
Surface the coded provider error the daemon already sends: a semantic title per error code, the provider's raw message, and expandable diagnostics (error code, HTTP status, request ID, SDK error name) with copy support, instead of a bare text-only toast. |
||
|
|
1186686554
|
fix(web): dedupe background subagent rows in the agents dock (#1754)
* fix(web): dedupe background subagent rows in the agents dock * fix(web): seed agent identity on late task registration and prefer REST output in task fold * fix(web): backfill terminal output to folded background subagent rows * fix(web): sync subagent phase when the REST fold makes a row terminal |
||
|
|
0b790cdc05
|
feat(web): allow attaching any file type and fix CSP on non-loopback binds (#1731)
* feat(web): allow attaching any file type in chat - Composer, paste, and drop no longer filter out non-media files; arbitrary files upload as generic icon chips and are submitted as file content parts - kap-server materializes file parts into the session's attachments dir and replaces them with a path reference, so the model opens the file with the Read tool on demand instead of receiving inline bytes - Images rejected by the provider format gate (SVG, AVIF, ...) are now persisted and referenced by path instead of being dropped with a notice; uploaded file names are sanitized before hitting disk * fix(server): stop CSP from blocking web bootstrap script and fonts - Move the anti-FOUC bootstrap from an inline <script> in index.html to /boot.js: CSP 'self' never covers inline scripts, while a classic same-origin script keeps the same render-blocking timing - Allow data: in font-src — KaTeX and the Inter / JetBrains Mono Variable fonts ship @font-face data URIs in their distributed CSS - Set explicit form-action, base-uri, and frame-ancestors, which do not fall back to default-src - Add a regression test asserting the served index.html carries no inline scripts or inline event handlers * fix(web): normalize empty attachment MIME so extensionless files submit Files with an empty File.type (Makefile, LICENSE, other extensionless or unknown types) stored mediaType: '' on the chip, and the submit fallback used ?? which does not catch empty strings — the wire schema requires a non-empty media_type, so the prompt was rejected. Normalize to application/octet-stream at attachment creation, adopt the server-recorded MIME after upload completes, and make both submit mappings use || so reloaded chips with '' are covered too. * feat(web): render all user-turn attachments as chips * feat(web): attach files by dropping them anywhere in the window * refactor(web): share one attachment chip between composer and chat bubble * fix(web): neutral attachment chips, paperclip attach icon, and clickable file chips * fix(web): drop the extension badge from attachment chips * fix(web): use the tabler paperclip for the attach button * fix(web): whitelist attachment previews, reject active document types Clicking a file chip navigated a new tab to a blob: URL of the uploaded bytes whenever the type looked browser-renderable. blob: inherits the web origin, so a text/html or image/svg+xml attachment would execute same-origin script with the daemon credential (localStorage) and a live window.opener. Preview is now restricted to inert types (pdf, non-SVG images, video, audio, non-HTML text), the blob is re-wrapped with the whitelisted MIME instead of trusting the recorded content-type, and window.opener is severed. Non-whitelisted types no longer silently download: the chip reports 'unsupported' and the pane shows a transient hint. * fix(web): recover file attachment chips from the server notice The kap-server prompt route replaces file parts with an "Attached file …" text notice before enqueueing, so after any snapshot resync the attachment chip degraded into raw notice text leaking the absolute server path — unlike image/video uploads, which already recover their chip from the <video|image path> tag. Parse the notice the same way: the materialized basename carries the file id, so the chip becomes clickable again (and editable back into the composer); inline-base64 notices (content-hash named, no file id) still collapse into a non-clickable chip instead of raw text. The notice wording is now a client/server contract — flagged on buildAttachedFileNotice. * fix(web): preserve UUID file ids when rebuilding attachment chips * fix(web): skip unresendable file chips when loading attachments for edit --------- Co-authored-by: qer <wbxl2000@outlook.com> |
||
|
|
b89d385fa5
|
fix(web): confirm dialogs respond to Enter and await async actions (#1744)
Some checks are pending
CI / test (3) (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Release (push) Waiting to run
* fix(web): confirm dialogs respond to Enter and await async actions The confirm dialog's initial focus was resolved from the Button component's $el, which is a text node in dev builds (the component has a template-root comment, so it renders as a fragment). Focus fell back to the header close button, so Enter cancelled instead of confirming. Resolve the initial focus with a CSS selector on the confirm button instead. ConfirmOptions now accepts an async action: the dialog stays open with a loading state (cancel/Esc/overlay suppressed) until the work settles. The archive-session, remove-workspace, and delete-provider confirms move from the menu components into App.vue so the dialog can await the actual client call. * fix(web): block superseding a confirm dialog while its action runs A second confirm() during an in-flight action would replace the busy dialog and inherit the global busy state, opening inert until the first action settled. Resolve the new request unconfirmed instead. |
||
|
|
6eb8e13417
|
fix(kimi-web): improve mobile safe-area handling (#1459)
* fix(kimi-web): improve mobile safe-area handling * fix(kimi-web): restore dock-height fallback where ChatDock is absent * fix(kimi-web): pin the app shell to the visual viewport height * fix(kimi-web): pin the app shell to the visual viewport * chore: add changeset for mobile safe-area fixes |
||
|
|
b6ae0a1054
|
fix(web): surface session list load failures (#1641)
* fix(web): surface session list load failures * fix(web): preserve partial session pages |
||
|
|
d8d4e8ceb5
|
fix(web): keep long streams responsive (#1643)
* fix(web): keep long streams responsive * fix(web): drop queued events for archived sessions |
||
|
|
b24a347e20
|
fix(kap-server): carry the live subagent roster in the session snapshot (#1719)
* fix(kap-server): carry the live subagent roster in the session snapshot * fix(kap-server): clear the subagent roster on the next main turn start * fix(kap-server): exclude background subagents from the snapshot roster * fix(kap-server): finalize live roster entries when the main turn aborts * fix(kap-server): drop roster entries when foreground subagents detach * fix(web): expand the swarm card by default while subagents are running * docs(kap-server): qualify the roster-clearing durability claim |
||
|
|
de493aeec9
|
fix(web): use upward chevron for dock card expand buttons (#1715)
* fix(web): use upward chevron for plan card expand button * fix(web): use upward chevron for question card expand button |
||
|
|
20b69724aa
|
fix(web): make code block copy work over plain HTTP (#1714) | ||
|
|
9eff230f97
|
fix(web): show errors for failed actions and add daemon request/operation logging (#1711)
Some checks are pending
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
CI / typecheck (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
* fix(web): show errors for failed actions and add daemon request/operation logging * fix(web): dedupe identical operation-failure toasts to avoid flooding * Revert "fix(web): dedupe identical operation-failure toasts to avoid flooding" This reverts commit 54fcfdcc97a034d7236d61cbb3664292a8966c64. |
||
|
|
ab22a2adf0
|
fix(web): show just the thinking level name in the model pill (#1689)
Drop the "thinking:" / "思考:" prefix from the effort suffix and capitalize the level via effortLabel, matching the segment labels. |
||
|
|
0f64b4dcc4
|
fix(web): submit thinking level verbatim and drop the hardcoded default (#1673)
* fix(web): submit thinking level verbatim and drop the hardcoded default Align kimi-web's thinking-level handling with the TUI: - Submit the stored level as-is on every prompt path (prompt, steer, skill activation, BTW side chat) instead of coercing it onto the target model's declared efforts. - No stored preference (undefined) instead of a hardcoded 'high' default: prompts omit the thinking override and the daemon resolves the config/model default, same as an unset [thinking] in the TUI. - Model switcher pre-selects the target model's own default level when switching models; re-selecting the current model keeps the level. - Display the effective level (stored value, else the model default) in the composer, mobile sheet, and /status panel. * chore(web): remove the dead dev:stub script The stub daemon (dev/stub-daemon.mjs) no longer exists, so the dev:stub npm script and its docs references were dead weight. * fix(web): pin the model default thinking level and persist picks globally - With no stored preference, loadModels() pins the active model's catalog default_effort as a concrete in-memory value, so what the UI shows, what prompts submit, and what the session runs always agree. localStorage stays reserved for levels the user picked. - setThinking and model switches now also write the daemon-wide [thinking] config (same mapping as the TUI's thinkingEffortToConfig), so sessions created by other clients inherit the pick. |
||
|
|
490303db16
|
fix(web): refine goal mode controls (#1669)
* fix(web): refine goal mode controls * fix(web): hide goal progress without budget * fix(web): use design system for goal cancellation * docs: document web goal controls * fix(web): remove collapsed goal actions from tab order |
||
|
|
5eb62178b3
|
feat(web): add session diagnostic export (#1646)
* feat(web): add session diagnostic export * fix(web): bound session export resources * fix(web): make session export atomic * feat(web): add session export entry to session menus with item icons |
||
|
|
0303b82c3e
|
fix: align v1 protocol handshake and tool_result media passthrough (#1630)
* fix(protocol): make server_hello heartbeat_ms optional kap-server dropped the server-initiated WS heartbeat and no longer emits heartbeat_ms in server_hello, but the published v1 schema still required it, so spec-compliant clients rejected the handshake before subscribing. - mark heartbeat_ms optional in serverHelloPayloadSchema (advisory only) - add a ws-control test for a server_hello without heartbeat_ms - align kimi-web WireServerHello and the server-e2e handshake assertion * fix(agent-core-v2): pass media parts through tool_result projection - keep raw kosong content-part array for tool results carrying image/video/audio parts instead of flattening to text - restore ReadMediaFile media rendering after session reload/resume * chore: add changeset for optional server_hello heartbeat_ms * docs(agent-core-v2): move tool_result media rationale to module header Per the agent-core-v2 comment conventions, comments live solely in the top-of-file block — move the media-passthrough rationale out of the buildProtocolContent JSDoc into the module header. |
||
|
|
e91a616f21
|
fix(web): dedupe optimistic user message against snapshot resync (#1620)
* fix(web): dedupe optimistic user message against snapshot resync * fix(web): match snapshot messages by identity |
||
|
|
4ec2e7fab1
|
feat(server): default to kap-server and remove the v1 server package (#1617)
* feat(server): default to kap-server and remove the v1 server package - kimi server run / kimi web now boot kap-server (agent-core-v2 engine) unconditionally; the KIMI_CODE_EXPERIMENTAL_FLAG gate on the server path is gone (the kimi -p print-mode gate stays) - move the OS service manager (svc: launchd/systemd/schtasks) from packages/server into packages/kap-server and export it there - repoint the CLI server subcommands, tests, and dev scripts at kap-server; relabel the web dev backend presets default/multi - delete packages/server and update workspace bookkeeping (flake.nix, pnpm-lock.yaml, changeset ignore docs, AGENTS.md, agent-core-dev skill) * test(server-e2e): remove scenarios that depend on v1 debug endpoints Scenarios 04-stateless-controls, 10-prompt-queue-steer and 12-send-and-cancel assert through the /api/v1/debug/prompts/* introspection routes, which only the deleted v1 server mounted — kap-server's --debug-endpoints is a documented no-op, so these scenarios can only 404 now. The vitest e2e files using the same surface already skip when it is absent. |
||
|
|
32cbd0cf61
|
fix(web): let workspace picker fit its content (#1611)
* fix(web): size workspace picker from full content * chore: add web workspace picker changeset * refactor(web): use intrinsic workspace picker sizing * fix(web): cap workspace picker to conversation pane |
||
|
|
098623ed9f
|
chore(web): drop the /help, /model, /provider, and /permission slash commands (#1615)
* chore(web): drop the /help, /model, /provider, and /permission slash commands * chore: drop the changeset |
||
|
|
e223549a79
|
fix(web): make mid-turn delta offsets step-relative (#1609)
* fix(web): make mid-turn delta offsets step-relative Reset in-flight text and client stream alignment at step boundaries so resync seeds only the current step instead of duplicating prior steps. * fix(web): dedupe resync-seeded messages by normalized content The exact-JSON content signature missed duplicates when the two copies differed by thinking signature, tool progress, part boundaries, or the tool set (finished parallel tools leave running_tools). Reduce content to concatenated stream text plus sorted tool-call ids and treat a covered subset as the duplicate, merging the seed's tool progress into the existing cards before dropping it. |
||
|
|
f338fcdac4
|
fix(web): restore swarm member list after page refresh (#1589)
* fix(web): restore swarm member list after page refresh * chore: add changeset for swarm roster refresh fix |
||
|
|
2da45fc419
|
fix(web): restore the goal card after a page refresh (#1606)
* fix(web): restore the goal card after a page refresh * fix(web): assert goal endpoint URL without stringification * fix(web): skip goal recovery write when a live goal event wins the race * fix(web): track goal events with a per-session version so clears win the recovery race |
||
|
|
dc309a7dfb
|
fix(web): keep context usage live on the v2 engine (#1601) | ||
|
|
4feca6b073
|
fix(agent-core-v2): align rate-limit retries with v1 (#1598) | ||
|
|
924d5c9141
|
feat(web): dev backend switcher and engine badge for dual-engine debugging (#1592)
Add the plumbing to debug kimi-web against the v1 (server) and v2 (kap-server) engines side by side: - root dev:v1 / dev:v2 scripts; v2 boots kap-server with the multi_server flag on a fixed port so both engines can run at once - dev-proxy backend switcher: GET/POST /__kimi-dev/backend repoints the /api/v1 proxy at runtime (HTTP + WS) without a Vite restart - dev-only sidebar backend pill reading /meta's backend field, with a one-click switcher menu; Settings shows the backend engine too - re-fetch /meta on every WS (re)connect so the badge stays truthful across backend restarts and switches - strip the browser Origin header on proxied requests: v1's WS upgrade path rejected the Vite-origin vs server-Host mismatch with 403 |
||
|
|
49a8c84a49
|
feat(web): cap markdown table column width at 700px (#1587)
* feat(web): cap markdown table column width at 700px * fix(web): clamp table column width through the cell content box |
||
|
|
ceb158dc54
|
feat(v2): land agent-core-v2 engine and kap-server behind experimental flag (#1441)
Some checks are pending
CI / typecheck (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix: adapt grep tool to agent-core-v2 * fix(agent-core-v2): enrich PATH from the user's login shell at startup - port probeLoginShellPath/mergeLoginShellPath/applyLoginShellPath into _base/execEnv/loginShellPath.ts as a pure helper (no DI) - export execFileText from environmentProbe for reuse by the probe - run applyLoginShellPathFromNode concurrently with the host probe in HostEnvironmentService, mirroring kaos LocalKaos.create() Aligns agent-core-v2 with kaos |
||
|
|
6fc1deb453
|
fix(web): wide markdown tables scroll internally and break out on desktop (#1577)
* fix(web): scroll wide markdown tables inside their own wrapper * feat(web): break wide markdown tables out of the reading column * fix(web): sample the full TOC rail for wide-table occlusion * refactor(web): use rect overlap for the TOC occlusion check |
||
|
|
b1942bd571
|
fix(web): keep the connecting splash and retry the first-load auth check (#1574)
* fix(web): retry the first-load auth check behind the connecting splash * fix(web): fall back instead of retrying deterministic 4xx auth-check failures * fix(web): show the connection error on the splash while retrying * fix(web): keep the first quick auth-check failure silent on the splash * chore: remove accidentally committed dist-web symlink * fix(web): hold onboarding until first load settles; drop unsupported 4xx auth fallback |
||
|
|
3a7aad653f
|
fix(web): finish local prompt state from session snapshot after a reconnect (#1572) | ||
|
|
9d96b538bf
|
fix(web): scroll wide markdown tables inside their own wrapper (#1575) | ||
|
|
5a208cb041
|
fix(web): auto-enable default thinking effort when switching to an effort-capable model (#1475)
Some checks are pending
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(web): auto-enable default thinking effort when switching to an effort-capable model * chore: add changeset * fix(web): preserve thinking off when reselecting current model |
||
|
|
f901b9e1da
|
fix(web): persist server access token across tabs and browser restarts (#1567)
* fix(web): persist server access token across tabs and browser restarts The web UI kept the server bearer credential in sessionStorage, which is tab-scoped and cleared on tab close, so users had to re-enter the token for every new tab and after every mobile tab eviction. Mirror it to localStorage instead: the token already lives on disk at <KIMI_CODE_HOME>/server.token and rides in the launch URL fragment, so browser-profile persistence does not materially widen exposure for this local tool. Existing sessionStorage copies are migrated on first boot, and a 401 (e.g. after `kimi server rotate-token`) still clears the stored credential. * fix(web): avoid clearing a fresh shared token from a stale tab localStorage is shared across tabs, so the unconditional removal let a tab holding a stale in-memory credential erase a newer token another tab had just persisted (e.g. after `kimi server rotate-token` one tab stores the fresh fragment token, then an older tab's delayed 401 wiped it). Only clear the persisted copy when it still matches the rejected credential this tab was using. * test(web): fix type-aware lint findings in server-auth tests Drop return-await on the dynamic import, brace the void arrow in the toThrow assertion, and remove a redundant String() conversion — CI runs oxlint --type-aware, which flags these where the plain local run does not. * fix(web): expire persisted server credentials after 7 days * fix(web): clear legacy session token even when localStorage is blocked setCredential ran persistCredential and the legacy sessionStorage cleanup in one try, so a localStorage.setItem failure (private mode, quota) skipped the cleanup: a stale session-scoped credential left behind was re-migrated on the next reload and 401'd into another token prompt. Split the session cleanup into its own best-effort block. |
||
|
|
1d3dba5683
|
fix(web): match current model by id in model picker dropdown (#1565)
Model names and display names can collide across providers, so the composer dropdown's checkmark matched by name and lit up every same-named entry. Resolve the current model through its unique id everywhere (dropdown check, thinking controls, status resolution). |
||
|
|
d2c2c33f3e
|
feat(web): type absolute paths directly in the workspace picker (#1556)
* feat(web): type absolute paths directly in the workspace picker The add-workspace dialog's fuzzy-search box now doubles as an absolute path entry: input starting with "/" or "~" is validated live (missing path / missing parent get specific errors plus prefix-matched candidates), and a valid path live-follows the folder browser so the existing "Open this folder" button submits it. Enter accepts the first candidate or opens a valid path; Esc clears the box. The collapsed paste-path section at the bottom is removed, and the degraded (no-browse) mode reuses the same box with format-only validation. * fix(web): recognize Windows absolute paths and gate Open button in path mode Two review fixes on the workspace picker's path entry: - PATH_LIKE now also matches Windows drive (C:\x, C:/x) and UNC (\\srv\x) forms, matching node:path.isAbsolute on the daemon side. Without this, Windows users in degraded (no-browse) mode had no way to submit a path at all. Parent-dir splitting and trailing-separator trimming are now separator-aware (drive roots are preserved). - "Open this folder" is disabled while path mode has no validated target. Previously, after typing a valid prefix and then an invalid path, the button still submitted the stale followed prefix. * fix(web): submit the typed lexical root when adding a workspace in path mode fs:browse canonicalizes via realpath, but workspace/session ids are based on the lexical root. For a symlinked cwd (/tmp/project -> /private/tmp/ project on macOS), live-follow stored the resolved target in currentPath and "Open this folder" emitted it, so sessions under the typed cwd would not group under the workspace. Keep the typed normalized path for the add action and use the browse result only to populate the visible browser. * fix(web): handle workspace path input edge cases |
||
|
|
c98238699c
|
fix(web): avoid repeated session list scans in sidebar computeds (#1563) | ||
|
|
264525eb51
|
fix(web): prevent chat scroll yank while browsing history (#1553)
* fix(web): preserve scroll position while loading older messages * fix(web): prevent chat scroll yank while browsing history * fix(web): stop stale auto-follow writes * fix(web): anchor long tool histories * fix(web): stabilize scroll anchor cancellation |
||
|
|
37bb4b870e
|
fix(web): keep ReadMediaFile media rendering after session resume (#1552)
Tool-role messages reached the snapshot/messages REST projection with their content flattened to text, dropping image/video/audio parts, so a ReadMediaFile result rendered as an image while streaming but fell back to a generic tool card after a reload. Pass the raw content parts through when a tool result carries media, matching the live tool.result event shape the web client already parses. |
||
|
|
f80b2eaf04
|
fix(kimi-web): single-source session status to stop duplicate turn-end notifications (#1542)
The web client received two sessionStatusChanged events per turn transition: one projected client-side from the raw turn.started/turn.ended stream, one mapped from the daemon's event.session.status_changed. After the tag scheme in #1479 keyed the completion notification by prompt id, the second (redundant) idle event lost the cached prompt id and fell back to a Date.now() tag, so every turn end popped a second "Turn finished" notification and replayed the completion sound. Stop projecting sessionStatusChanged from the raw turn stream (turn.started, turn.ended, and the in-flight snapshot seed). The daemon's event.session.status_changed is the single source of status transitions: it is computed from live daemon state (covering awaiting-approval / awaiting-question / aborted), carries the authoritative previousStatus and currentPromptId, and is deduped per real transition server-side. The turn stream keeps its content responsibilities (message finalization, usage, duration); seedInFlight keeps seeding the partially-streamed message while status comes from the snapshot's authoritative session record. |
||
|
|
04041eb998
|
fix(web): hide injected system asides in user message bubbles (#1535)
Some checks are pending
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(web): hide injected system asides in user message bubbles * fix(web): preserve literal <system> tags in user prompts * chore: fold duplicate web changeset into caption-hiding entry |
||
|
|
ec8dc3456c
|
fix(web): stop sending prompts into a busy turn on the web UI (#1522)
* fix(web): prevent duplicate first prompts and keep goal drives from looking idle
- Guard startSessionAndSendPrompt with a per-workspace reentry lock so a
double-click / repeated Enter during draft-session creation cannot fire
two concurrent first prompts into the same new session.
- Track goal.active in the agent event projector so turn.ended between
goal-driven continuation turns keeps the session 'running' instead of
projecting a false 'idle' that drains the local queue into a still-busy
core (turn.agent_busy).
- Show a 'starting conversation…' loading state on the empty-session
landing while the first prompt is being created and submitted.
- Persist the resolved model in startSessionAndActivateSkill so the first
skill turn on a fresh session does not fail with 'Model not set'.
* chore: add changeset for web first-prompt fixes
* fix(web): close remaining first-prompt and goal-settle gaps
- Pass the starting guard through the dock composer: draft-session
creation selects the new session before submit, which swaps the empty
composer for the dock; disabling both composers closes the last path
to a concurrent first POST. Also take the workspace lock in
startSessionAndActivateSkill / startSessionAndOpenSideChat.
- Emit the owed idle when a goal settles (blocked/paused/completed) in
the inter-turn gap after a turn.ended was projected as 'running', so
sending state, in-flight flags and queued prompts flush instead of
the session staying 'running' forever.
* style(web): fix eqeqeq lint error in first-prompt guard
* fix(web): clear owed idle when a new goal turn starts
The idle debt from a 'running' projection survived turn.started, so an
UpdateGoal('complete'|'blocked') landing mid-turn in the NEXT goal turn
synthesized an early idle. onSessionIdle could then drain queued prompts
into a core that was mid-turn again, re-opening the turn.agent_busy race
for multi-turn goals. Clear the debt on turn.started: from that point the
turn's own turn.ended carries the idle with goalActive already false.
* fix(web): make first-prompt starting state workspace-id-agnostic
isStartingFirstPrompt now reads from the lock set directly (size > 0)
instead of the current activeWorkspaceId. createDraftSession can swap
activeWorkspaceId to a registered id mid-flight; a workspace-keyed read
would then return false while the first prompt is still in the create/
select/submit window, re-enabling the composer and reopening the
duplicate first-submit race.
* revert(web): drop goal-aware idle projection from agentEventProjector
The goalActive / idleOwed shadow state machine grew through multiple
review rounds and still leaves edge cases (snapshot-seeded turns, mid-
turn goal updates). Roll it back to the simple 'turn.ended projects idle'
behavior. Goal-driven sessions can once again race a queued prompt into a
busy core; this is accepted as a known limitation to be resolved properly
in a follow-up that has the core emit an authoritative idle signal.
* chore: align changeset with actual fix scope
* test(web): update profile-patch expectation for model field
|