Skip to content

feat(mcp): render_page — interactive pages, answers and annotations - #1061

Open
leehom0123 wants to merge 3 commits into
spacering-net:mainfrom
leehom0123:pr/render-page
Open

leehom0123 wants to merge 3 commits into
spacering-net:mainfrom
leehom0123:pr/render-page

Conversation

@leehom0123

Copy link
Copy Markdown
Contributor

What

Ports OpenChamber's render_page capability to codeg: an agent can show a small self-contained HTML page inline in the chat; the user can answer on it (unblocking the tool call), copy/quote text selections, and mark it up (element / region / freehand) so the marked-up report returns to the agent as a prompt.

Reading guide (3 commits, in merge order)

  1. feat(mcp): render pages from the agent as an answerable card — all Rust (bounds + title extraction in acp/render_page.rs, delegation plumbing, commands/web handlers, RenderPageRequest event on both emitters, persisted render_page.enabled setting) + frontend pipe (types, api, connection/context, the settings matrix entry with i18n for all 10 languages).
  2. feat(mcp): show the page, collect its answer, quote its selections — the card: sandboxed srcdoc iframe, answer/cancel flow, result card for replayed turns, selection copy/quote into the composer, annotation chip wiring in composer/panels/canvas. The card holds waiting across submit/close so the iframe does not reload under the page that just answered.
  3. feat(mcp): annotate a page into the transcript, badge-first and expandable — re-read annotation messages recompose to what was sent: badges hoisted before the prose, report collapsed at the bottom, click-to-expand across content parts; fence-guarded embedded links; prose fallback strips the internal Label: line; annotation payloads truncate to the region/stroke caps instead of dropping.

No behavior is removed from existing features: deletions across the whole branch total ~135 lines, all re-wiring.

Verification

  • pnpm lint ., tsc --noEmit, pnpm build clean.
  • vitest full run: 11236 passed / 1 failed — the failure is task-schedule-dialog.test.tsx (tasks page date picker, from fdb760d0 on main), reproduced identically on a clean origin/main worktree, unrelated to this branch.
  • Rust: cargo test --no-default-features --features server-bin --bin codeg-server --lib acp::render_page (14 passed), cargo clippy … --lib -- -D warnings clean.
  • Manual browser testing on the web build (Chrome DevTools): render → answer → decline, quote selection, annotate with element/region/freehand and numbered chips surviving a refresh.

Add the render_page companion tool: the agent's HTML shows as a card in
the chat, the user can answer on the page and the blocked tool call
resolves with that answer, and a settings switch (协作 → 渲染页面) gates
injection per deployment.

Backend: `acp/render_page.rs` (input bounds, title extraction incl.
attribute-quoted `>` and single-pass entity decoding), delegation
broker/companion/listener plumbing, `commands/render_page.rs` + web
handlers for answer/cancel, the RenderPageRequest event on both
emitters, and the persisted `render_page.enabled` setting. Frontend
pipes: event types, api calls, connection/context state, the settings
matrix entry and its i18n labels (the hint already describes page
annotation, which lands in a later commit).
Render the tool call as an inline card: a sandboxed srcdoc iframe with
the agent's page, an answer flow that unblocks the tool call, and a
result card for replayed turns (awaiting / answered / declined). Select
text on a page to copy or quote it; a quote lands in the composer as
markdown, and page annotations (their composer wiring included) arrive
through the same injection channel as chips labeled "Page annotation N".

Keeping the card `waiting` while a submit or close is in flight stops
the srcdoc rebuild from reloading the iframe out from under the page
that just answered.
…dable

A re-read annotation message recomposes to what the sender composed:
liftEmbeddedContext turns the persisted context block into an inline
<annotation> tag named by the report's own Label line (first line only,
matching the tag builder), and the bubble hoists the annotation badges
ahead of the prose and keeps the report collapsed at the bottom.
Clicking a badge opens its report in place — across parts, since the
provider is given every ref the message carries.

Hardening folded in from review: an embedded link inside a code fence
is quoted wire text and must survive verbatim; the prose fallback for
agents without embedded-context support strips the internal Label line
so it never leaks into the draft; annotation payloads are truncated to
the region/stroke caps instead of dropped whole.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant