mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-25 07:41:17 +00:00
4 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f400d5beb9
|
fix(transcript): load large tool images on demand instead of inline (#1118)
A session whose history holds image tool results (for example `read` on PNG files) never opened over a slow link (#1113): the 200-message page was 16.8 MB, 15.7 MB of it base64 in five tool results. It took 20 s at 6.5 Mbit/s, and a reverse proxy cut the transfer, so the UI showed "Failed to fetch". Every open, reload and history window paid for every image, shown or not. Transcript pages now carry large tool images by reference. The UI's native message list reads (createInstanceFetch) and history windows send the `x-codenomad-media: deferred` opt-in. For those reads only, the server replaces each tool image whose data URI exceeds 32 KiB with a `/api/workspaces/<id>/session-media/<session>/<message>/<part>/<index>/ <sha256>` path, in the instance proxy (forwardRuntimeRequest gains an optional whole-JSON transform for successful JSON responses) and in the history window route. toolImageSource resolves that path on the API base, so the existing lazy `<img>` loads only the images that are shown, as binary rather than base64. The new session-media route checks that the workspace owns the session, reads the native message, and refuses a session that moved during the read and messages at or after an undo boundary. It serves the bytes only when the image still matches the digest, as an immutable, nosniff, sandboxed image; anything else falls back to "Unable to display this image". What stays whole: - Single-message reads (`session.message.get`), so pruning revisions keep hashing native content. - Live events, user attachments, small images, non-image files and error responses. - Requests without the opt-in. The opt-in header is never forwarded to OpenCode. On the reported session, the page drops from 16.8 MB to about 1.1 MB. Validation: - session-media.test.ts: only large renderable tool images change, and only their URI. - routes/session-media.test.ts: exact bytes and headers; invalid references, digest and position mismatches, the undo boundary, ownership and a move during the read. - proxy.test.ts: the transform applies to successful JSON only and releases once. - instance-proxy.test.ts: an opted-in list read is deferred, the opt-in is not forwarded, and plain list or single-message reads stay whole. - session-navigation.test.ts: history windows. - sdk-manager.test.ts: only list reads opt in, keeping other headers. - tool-content.test.ts: path resolution, forged paths rejected; it is now listed in the PR build. - tool-images.test.ts: a deferred image decodes from the route in the real ToolCall renderer, and a missing one shows the fallback. The UI own-tsconfig, server and root typechecks pass, as do: - the server suite (2,467 passed; one index.test.ts process test timed out under load and passes alone, as on dev); - the UI unit step of the PR build (564 tests); - seven browser suites (278 tests). |
||
|
|
47e02795b2
|
fix(session): clear a queued follow-up's badge when it is delivered (#1117)
A follow-up sent while the agent works (follow-up behaviour "queue") shows the "Queued" badge until the engine delivers it. After some turns the badge never cleared: the message was answered, the engine went idle, and only closing and reopening the session removed it (#1112). The stale pending entry also kept the message pinned below the running turn. The session view lists queued prompts from the session reducer's inbox through a memo. CodeNomad replaces that reducer while the session stays open: an authoritative resync after an event-queue overflow, a rotation failure or a reconnect, and a pruning invalidation. The replacement was a plain property write, so the memo kept reading the disposed reducer, which never sees `session.inbox.delivered`. On 0.20.1 nothing rebound it until the view remounted; on dev the reducer retirement at settlement happened to rebind it at the end of the turn, but the badge stayed for the rest of the turn, and indefinitely when retirement waits (another prompt still parked, an unsettled tool or shell). Every replacement now goes through replaceTranscriptEntry, which assigns the new reducer, disposes the previous one and bumps a per-transcript entryRevision signal that getOpenCodeSessionInbox tracks. Only that session's inbox observers re-run; a transcript destroyed and recreated is still rebound by the instance revision. Several queued follow-ups keep their badges until each is delivered; steer-mode actions on a delivered prompt disappear the same way. Validation: opencode-inbox-rebinding.test.ts queues two follow-ups, replaces the reducer by pruning invalidation and by an event-queue overflow, then delivers them one by one with no terminal event: each leaves the memo at once. Both cases fail without the fix. A browser test in session-rendering.test.ts runs the real SessionView and SSE dispatcher: queued badge, a pruning event, delivery, badge gone while the turn still runs; it fails without the fix with the badge still visible. The session fixture's native inbox now lists parked prompts as an array and stubs the permission and form lists, as a real daemon does, so an authoritative resync completes. The new unit file is listed in the PR build's UI unit step, which passes locally (64 files, 562 tests), as do the UI own-tsconfig and root typechecks and the six browser suites using the session fixture (206 tests). |
||
|
|
c716f796d8
|
ui: keep the message token disclosure on one row in both states (#1084)
## Summary The token/cost line that closes every agent message previously turned into two rows when expanded: a bare `Tokens` label line (chevron + label) with the six metric chips on a second line below it. This PR keeps the disclosure on one row in both states — expanding swaps the collapsed summary chips for all six chips on the very same line as the chevron. ## Problem - Collapsed, the row is a compact single line: `› INPUT 3K · OUTPUT 54 · COST $0.76`. - Expanding it replaced that line with a label-only row (`› Tokens`) plus a separate chip row, so a one-line affordance grew to two rows and pushed the transcript content down twice as much. ## Change - **Expanded = same row.** The six chips (input, output, reasoning, cache read, cache write, cost) now render in place of the summary chips, beside the chevron. The `Tokens` label line and the separate content row are gone; at wide widths the expanded card is exactly as tall as the collapsed card. - **Wrapping is preserved.** Expansion exists to read the values, so the expanded row is never ellipsized: when width runs out, the chips wrap onto further lines in place (this wrapping behaviour is unchanged from before). - **Collapsed is untouched.** The collapsed summary keeps its single ellipsized line; its rendering is pixel-identical to before. **Expanded — wide layout** (before shows the label line + chip row; after is one row): <img width="884" height="344" alt="wide-expanded" src="https://github.com/user-attachments/assets/06abd5cd-b15d-4b29-ab39-1202d4c35ca5" /> **Expanded — narrow layout, 220 px** (both wrap instead of truncating; after drops the label line and starts the chips beside the chevron): <img width="390" height="339" alt="narrow-expanded" src="https://github.com/user-attachments/assets/e4e5fbe7-a37c-42f6-8f73-3628d21ac2c6" /> **Collapsed — unchanged** (wide and narrow; pixel-identical before/after, narrow still ellipsizes): <img width="884" height="310" alt="wide-collapsed" src="https://github.com/user-attachments/assets/71b40a15-6a19-4232-8eef-e0ce1327ff90" /> <img width="390" height="175" alt="narrow-collapsed" src="https://github.com/user-attachments/assets/f77ebdd9-0540-4c74-9f2b-3a3fb64a7d9a" /> ## Implementation notes - `packages/ui/src/components/message-usage.tsx`: the toggle now always renders `chevron + chips` — the collapsed state renders the three summary chips, the expanded state renders all six in the same slot. The separate expanded content `<div>` and its `aria-controls` wiring are removed. - `packages/ui/src/styles/messaging/message-usage.css`: `.message-step-usage` is the expanded wrapping row (`flex-wrap`, no truncation); the collapsed `.message-step-usage-summary` keeps its single-line ellipsis. The unused `.message-step-usage-label` / `.message-step-usage-content` rules are deleted. The chevron pins to the first chip row when the row wraps. - **Accessibility:** the button's `aria-label` carries all six full values when expanded (`aria-label` overrides the visible chips, so they are repeated there deliberately); the collapsed label is unchanged. The shared disclosure chevron rotation keeps working via the generic `aria-expanded` rule. - **dev-docs/TRANSCRIPT.md:** the message-token disclosure convention note is updated to describe the one-row layout. ## Help pages No help change needed: `docs/help/*/conversations.md` documents the line as *"expand it for reasoning and cache counts"*, which remains true — the documented behaviour is unchanged and the two-row layout was never documented. ## Validation - TDD red→green: the new assertions were watched failing first (`0 !== 6` chips on the row, stale `aria-controls`), then passing. - `tests/browser/usage-metrics.test.ts` — 5/5, now also covering: expanded chips on the toggle's row; single row at wide width; wrapping onto multiple rows at 220 px in LTR **and** RTL with no horizontal overflow and no ellipsis; chevron level with the first chip row; Space/Enter collapse restores the three-chip summary. - Related suites that render the usage row: `status-tokens` (4/4), `transcript-presets` (1/1), `search-highlight` (0 failures). - Visual: before/after screenshots captured from the real fixture at 900 px and 220 px (the composites above); collapsed rendering verified pixel-identical. |
||
|
|
7a1fc90310
|
docs(agents): keep AGENTS.md to universal rules and agent docs to the current state (#1082)
AGENTS.md loaded about 33,000 tokens into every agent session, subagent and reviewer, mostly per-feature contracts, and the agent documentation around it had accumulated duplicates, dated logs and history of removed designs. This PR makes AGENTS.md a short set of rules that apply everywhere plus an index of area documents, and leaves AGENTS.md, dev-docs and the repository skills describing only the current state. Three commits, reviewable separately: 1. **Move (lossless).** Every per-area rule moved verbatim from AGENTS.md into its area document (existing ones, or six new ones: UI_CONVENTIONS, UI_SHELL, COMPOSER, TRANSCRIPT, SETTINGS, PROJECTS). A script split the old file into 208 units, required one destination for each and checked all 199 content units verbatim at their destination. AGENTS.md went from 134,000 to 16,000 characters. 2. **Trim.** A per-area ponytail review removed rules stated two or three times (keeping the more precise copy), dated validation logs, per-version qualification sections below the current minimum, abandoned designs and self-references; seven documents whose surviving rules live elsewhere were deleted. It also fixed statements the code contradicts (locale registration, the Mission play/recovery condition, plugin package updates, cleanup progress UI, timeline index persistence, automation restart/targets, stale pins and minimums). 3. **Current state only.** The new AGENTS.md rule: no history (removed features and their names, former behavior, provenance, dated logs) and no denials; correct a contradicted statement at its source. DEVELOPER_MODE.md is merged into BROWSER_AUTOMATION.md and every Developer Mode mention is gone (including the README and the browser help page in ten locales). Names that only made sense against older designs are renamed with every reference updated, MISSIONS_ENVIRONMENT_ADMISSION is folded into SESSION_ENVIRONMENT, and INDEX lists every document. The server npm README now states the real OpenCode minimum (2.1.2). AGENTS.md is now about 14,000 characters (roughly 3,500 tokens); AGENTS.md, dev-docs and the vendor README went from about 11,200 lines to under 4,700. Validation: every relative Markdown link and every cited dev-docs path resolves; no reference to a renamed or deleted document remains; `npm run test:help` passes for all ten locales. Review: three independent GPT-6.1 Sol (high) reviews by area found binding rules lost in the trim and current-state passes; 25 were restored as present-tense facts or prohibitions and four contradicting statements corrected, each checked against code. A Fable 5.1 gatekeeper review of the whole PR passed; its follow-up routes session recovery from the index, points to dev-docs/INDEX.md and documents the family identity read. |