Conversation
…ser load The browser UI served by `kimi web` shipped every asset uncompressed with no cache validators, streamed one WebSocket envelope per model token, let `GET /api/v1/sessions` return every session when `page_size` was omitted, and forced `no-cache` on assets tunnelled through Remote Control. Static assets: negotiate precompressed `.br`/`.gz` siblings (generated by the new precompress script during `pnpm build` and the native bundle workflow, gitignored), add weak ETag + 304 revalidation and `Vary`, fix wasm/woff/ttf/riv/map content types, and stat each file once. WebSocket: enable permessage-deflate and a 16 MiB max payload, expose the tuning knobs through `KIMI_CODE_WS_*`, replace the 100 ms forced flush with real backpressure that closes stalled peers with 1013, and always flush control frames. Append-only transcript ops are micro-batched before seq assignment so clients keep receiving contiguous seqs. REST: the sessions list is always paginated (default 50) with `busy` applied while collecting; the transcript ops catch-up accepts `limit` and reports `has_more`. Remote Control: keep upstream cache headers, revalidate rewritten HTML/JS/CSS through a versioned ETag, pass 204/304/HEAD through bodiless, add reconnect jitter, cap early frames, apply pause/resume backpressure on the WebSocket bridge, and add an experimental chunked response mode behind `KIMI_CODE_REMOTE_CONTROL_CHUNKED_RESPONSES`.
…local hop The relay forwards the browser's Sec-WebSocket-Extensions header, but the loopback ws client runs with permessage-deflate disabled, so when the local server accepted the advertised extension the client rejected the upgrade. Strip the browser's handshake fields and let ws negotiate its own.
…ses behind an experimental flag The always-paginated sessions list silently truncated callers that never passed page_size, which is a breaking API change under a patch changeset. Without page_size the listing now returns every eligible session again (archived_only keeps its historical page of 20); explicit page_size keeps the collect-while-filtering behaviour and accurate has_more. Remote Control chunked responses were toggled by a standalone env var that bypassed KIMI_CODE_EXPERIMENTAL_FLAG and the [experimental] config. The feature is now the `remote_control_chunked_responses` flag registered through registerFlagDefinition; `kimi web --rc` and the TUI /rc command resolve it through IFlagService and pass it to the tunnel as an option.
…tal flags to the CLI Pre-compressed asset selection now picks the accepted encoding with the highest q value, falling back to the built-in br-before-gzip order only on ties. RunningServer gains a `flags` handle so the CLI reads the remote-control chunked-responses flag through kap-server instead of importing the engine's IFlagService directly.
…ated tunnels Tunnels started through POST /api/v1/remote-control go through createRemoteControlManager, which never passed chunkedResponses. The manager now takes a chunkedResponses thunk resolved at each tunnel start, and kap-server wires it to the remote_control_chunked_responses flag via IFlagService (the manager is created after the engine core bootstraps).
- ws v1: control frames no longer force-flush the deferred backlog above the high-water mark, and the slow-consumer clock resets while the peer drains - transcript ops catch-up: a capped response reports latest_seq as the last returned batch so cursors written against the old contract stay correct - transcript service: pending appends are flushed, not discarded, when a session is dropped or purged - kimi-inspect: seed from one unsized request, drain with before_id only when has_more, and keep the pages already collected when a later page fails - remote-control: the chunked-responses flag is excluded from the KIMI_CODE_EXPERIMENTAL_FLAG master switch - precompress: write siblings atomically, and --check honours the size threshold and sibling freshness - webAssets: stat precompressed siblings in parallel, reuse pickHeader and buildEtag, drop the redundant .riv case - reuse the shared env parsers for KIMI_CODE_WS_* and the ops batch window, simplify flushPendingOps, drop the unused --only flag and skip list, and share a header lookup in remote-control
…d responses Drop the excludeFromMaster escape hatch added for remote_control_chunked_responses so KIMI_CODE_EXPERIMENTAL_FLAG=1 enables it like every other experimental flag. The flag still defaults to off and the per-flag env var and [experimental] config keep precedence.
Omitting limit on GET .../transcript/ops returns every journaled batch after since_seq again, as it did before limit existed; only an explicit limit caps the response and sets has_more.
# Conflicts: # packages/remote-control/src/remote-control.ts # packages/remote-control/test/remote-control.test.ts
…to keep seqs ordered
…ins to the high-water mark
🦋 Changeset detectedLatest commit: a06d67b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 028c709bb2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… backlog and weigh identity in asset negotiation Stop the outbound flush loop at the high-water mark instead of depositing the whole backlog into ws in one pass; the remaining frames stay queued in order and resume on drain. Let identity compete on q-value when picking a precompressed sibling (unlisted identity defaults to q=1, a tie still prefers the encoded sibling) and reply 406 when identity is excluded and no acceptable sibling exists. Trim the remote-control changeset to one sentence.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d09d01b1c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…im changesets Run precompress-web-assets.mjs (generate, then --check) from scripts/native/build.mjs before the blob collects dist-web so local and non-CI native builds ship the .br/.gz siblings too. Reduce the WebSocket and sessions changesets to one sentence each and split the transcript ops limit into its own entry.
…rmance-5b01eb # Conflicts: # docs/en/configuration/env-vars.md # docs/zh/configuration/env-vars.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 310288403f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…e the high-water mark sendImmediateEnvelope used to write straight to ws when no subscription backlog was queued, even with bufferedAmount above the mark, so a slow client could keep growing its socket buffer through other sessions' events without ever arming the backpressure retry or the slow-consumer close. Queue the envelope and defer instead.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ef7564976
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…r mark gate bridgeSockets used to forward every buffered early frame in one pass even after a send crossed the 1 MiB mark. The pump now keeps the unsent frames pending, stops at the mark, and continues the replay on each drain poll before letting the source read again; dispose drops whatever is still pending.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf0ecd7412
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ining ws.pause() only stops the socket read; messages already decoded from the last chunk still reach the pump after the sink crossed the high-water mark. Those frames now join the pending queue and are replayed by the drain poll in order instead of being written straight into the throttled socket.
…ove the high-water mark Acks and heartbeat pings still flush immediately, but when the socket is already above the mark they now arm the backpressure stall clock, so a peer that stops reading while it keeps sending control frames is closed with 1013 like any other stalled consumer. The clock resets whenever a flush sees the socket back below the mark.
The remote_control_chunked_responses flag, its CLI/TUI plumbing and the kap-server flags handle are out of scope for the slow-link work and the relay contract for multi-frame responses is unverified. Responses go back to one tunnel frame each, as before.
Filling filtered GET /api/v1/sessions pages up to page_size and the kimi-inspect seed drain are a correctness fix unrelated to slow links; they ship in their own PR.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cc6f39283
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5563ce74d9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2efbef8f60
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # packages/agent-core-v2/src/_base/utils/env.ts # packages/kap-server/src/services/transcript/transcriptService.ts
Related Issue
No linked issue. This PR comes from a performance review of the
kimi webhost for users on slow connections and low-end browsers.Problem
Using the browser UI over a slow or high-latency link was painful, and long sessions could overload the browser:
ETag, so each page load re-downloaded ~3.9 MB of entry JS/CSS;.wasm/.woff/.ttffell back toapplication/octet-stream, which brokeWebAssembly.instantiateStreamingundernosniffand made the Rive runtime download twice.Accept-Encodingand forcedCache-Control: no-cacheon every rewritten asset, so hashed assets were re-fetched on every load, and the loopback bridge had no backpressure.What changed
Static assets (
packages/kap-server/src/routes/webAssets.ts).br/.gzsiblings viaAccept-Encoding, ranked by the client'sqweights (identity competes on its own weight;identity;q=0with no acceptable sibling is a 406); siblings older than the source are ignored.ETag+If-None-Match→ 304,Last-Modified,Vary: Accept-Encoding; complete MIME table; onestatper request.apps/kimi-code/scripts/precompress-web-assets.mjsruns inpnpm buildand in the native build (scripts/native/build.mjs, with a--checkgate in the workflow); the siblings are gitignored, never committed.WebSocket (
packages/kap-server/src/transport/ws/v1/)permessage-deflate(no context takeover, 1 KiB threshold) and a 16 MiBmaxPayload;server_hello.capabilities.compressionreflects negotiation.KIMI_CODE_WS_*env vars.bufferedAmountis above the high-water mark and a queued backlog is released only down to the mark; a peer stalled for 15 s or with more than 4096 queued frames is closed with1013 slow consumer. Control replies and heartbeat pings still flush immediately but arm the same stall clock when the socket is above the mark.KIMI_CODE_TRANSCRIPT_OPS_BATCH_MS) before seq assignment, so one flush = one seq = one envelope and existing clients need no change. Journal reads flush first, so REST watermarks stay exact.REST
GET .../transcript/opsacceptslimit(1–500) and reportshas_more;completesemantics are unchanged.Remote Control (
packages/remote-control)public, no-cachewith a versionedETagso a cheap 304 reuses the browser copy while rewrite-rule changes still invalidate it. 204/304/HEAD pass through bodiless.perMessageDeflateoff on the loopback hop. The browser'sSec-WebSocket-*handshake headers are no longer forwarded to the loopbackwsclient, which used to reject upgrades when the local server acceptedpermessage-deflate.Docs: server API reference (heartbeat contract corrected, new fields), env vars, Remote Control guide (en/zh).
AGENTS.mdnote aboutdist-webtracking updated.Reviewer notes
modulepreload) lives in code-app and is out of scope here.GET /api/v1/sessionspage-filling fix; both were dropped from this PR as unrelated to slow links. The sessions fix will follow in its own PR.catch (error)/toSorted()hunks inpackages/minidbandsearchService.tsare produced by the repository's own lint-stagedoxlint --fixstep whenever those files are staged; they carry no behavior change.kap-serversuite has pre-existing path-separator/symlink failures; all targeted suites plustranscript,remote-control,kimi-inspectand the new script tests pass, typecheck andcheck-no-commentsare clean.Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.