Skip to content

feat(ui): collaborative document editing workspace#1729

Open
ebarroca wants to merge 51 commits into
mainfrom
feat-editing
Open

feat(ui): collaborative document editing workspace#1729
ebarroca wants to merge 51 commits into
mainfrom
feat-editing

Conversation

@ebarroca

@ebarroca ebarroca commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a reusable artifact-backed Markdown editing surface with block selection, comments, rich component edits,
    contextual insertion, exact-change refresh, changed-block highlighting, manual reload, and generation-based
    conflict recovery.
  • Add the full-screen document editing workspace: working copy and agent conversation, active-run reattachment,
    project-default environment/model selection, review mode, explicit publish, save/version selection, new-version
    navigation, and agent-assisted conflict reconciliation.
  • Add @vertesia/rich-text, a Markdown-first TipTap package with component and full-document editors, contextual
    table/list actions, opaque preservation for unsupported Vertesia Markdown, injected renderers, stable external
    value synchronization, and parse/serialize conformance tests.
  • Add a word/line diff review, full-editor change ruler, debounced artifact persistence, and Send changes to
    agent
    using a bounded unified diff.
  • Persist run-local artifact links when publishing and keep all canonical document mutation behind the user-owned
    Save to document action.
  • Lock direct editing while the agent is working. The editor, send, and save controls disable with a persistent
    visual banner; an explicit manual unlock/relock remains available as a recovery control.
  • Extend common/client types for initial conversation setup, agent artifact content, generation preconditions, and
    editing-session bookkeeping. Add all new UI strings to every locale.

Verification

  • pnpm install
  • pnpm --prefix packages/rich-text lint
  • pnpm --prefix packages/rich-text typecheck:test
  • pnpm --prefix packages/rich-text test — 12 tests
  • pnpm --prefix packages/ui lint — 527 files plus strict RTL validation
  • pnpm --prefix packages/ui typecheck:test
  • pnpm --prefix packages/ui test — 54 files, 544 tests
  • pnpm build — 23/23 tasks
  • Fresh PR CI: lint, unit/build tests, plugin template smoke test, CodeQL, and Zizmor

Notes

  • Unsupported custom blocks remain opaque Markdown rather than being silently rewritten.
  • Before full-document rich-text editing, a compatibility check warns when parse/serialize would normalize the
    source and offers exact Markdown-source editing instead. YAML frontmatter is preserved as an opaque header.
  • The editing workspace targets the current document head even when opened from a historical revision page.
  • External artifact changes are applied without unmounting the current document, preserving the editing surface while
    streamed updates arrive.

ebarroca added 9 commits July 14, 2026 01:43
Add CollaborativeMarkdownRenderer with block-level comment/edit controls
and source-position-stable anchors (heading path, occurrence index).
Wire it into ContentOverview via an Edit with AI panel that starts or
resumes a document-scoped agent run, and into ArtifactsTab so Markdown
artifacts open inline against the live conversation. Preserve structured
UPDATE events in the timeline and expose sendMessage/onMessage hooks on
ModernAgentConversation.
…revision

- Extract DocumentEditingWorkspace from DocumentEditingPanel so host
  applications can embed the workspace in their own layout; the panel is
  now a full-screen modal wrapper. sendMessageRef, onClose, and
  onDocumentUpdated are optional in the embeddable component.
- Resolve the head revision when the workspace opens from a historical
  revision page: hydration, the review baseline, and Save to document
  now always target the current head instead of failing with a 400 and
  showing a false unsaved-changes state. Resolution is atomic — a failed
  head lookup never falls back to editing a historical revision.
- Confirm before starting a new session while the working copy has
  unsaved changes.
- Clear the optimistic first message when startWorkflow declines to
  start, so the conversation no longer spins in the preparing state
  forever after a start failure.
@ebarroca
ebarroca requested a review from a team as a code owner July 15, 2026 03:35
ebarroca and others added 20 commits July 15, 2026 13:14
…on for editing sessions

- Detect both save-conflict shapes (If-Match 412 and head-moved 400),
  re-point the save target at the new head, and show a conflict banner
  offering an agent-assisted merge: the agent fetches the new canonical
  revision into a reference artifact, merges it into the working copy,
  and reports what was merged for review before saving again.
- Add a "Summarize changes" action to the review view: the agent
  compares the working copy against the session baseline and replies
  with a changelog suitable for a revision note.
- Pass a hard excluded_tools denylist on editing runs: document/store
  mutation tools and sandbox execution stay unavailable even if a skill
  would unlock them; the working copy is edited only through
  edit_artifact and published only via Save to document. fetch_document
  is enabled read-only for reconcile and summary comparisons.
- @vertesia/common: excluded_tools on conversation payloads and agent
  run creation.
…e header

- Save to document now runs the same persistence pass as create_document:
  run-local artifact: links (session-generated charts, files) are copied
  into durable documents/{batch}/ storage server-side and the links
  rewritten before publishing, so canonical documents never depend on
  run-scoped artifact storage. Failed copies pin the link to the explicit
  agents/ path instead of leaving it run-relative. The rewritten links are
  synced back into the working copy after a successful save (CAS-guarded).
- Editing prompt: forbid inline base64 image data and rewriting durable
  artifact:documents/… references; run-local references are allowed and
  made durable on publish.
- Consolidate the workspace chrome into a single header bar: status line
  with working-copy and baseline chips (full values in tooltips), view
  toggle + summarize + refresh, session group (model, run id, new
  session), and actions — the second toolbar row is gone, giving the
  document the vertical space back.
- Model chip shows the model display name (or the final id segment)
  instead of the full provider resource path.
The previous commit unintentionally included the @vertesia/ui references
to the in-progress @vertesia/rich-text workspace package (dependency,
externals, tsconfig reference) while the package itself is not committed
yet, leaving the branch uninstallable from a clean clone. Remove the
references until the package is ready; re-apply them from 42ac546
together with the package.
Builds on the feat-editing collaborative-editing work but replaces its
block-only selection with feat-agent-collab's arbitrary-span model, and makes
the properly-styled TipTap editor the primary surface for agent artifacts.

- The agent Artifacts tab now opens Markdown artifacts in the rich-text
  document editor (viewMode="document") — inline editing on a clean prose
  surface — instead of the read-only block-wrapped renderer.
- Add SpanSelectionComment: a toolbar that lets the user highlight ANY text
  span (not a whole block), attach a note, and send it to the agent. It builds
  a content-anchored MarkdownBlockAnchor (exact_text + prefix/suffix, the same
  TextQuoteSelector model, minus the source range) from the ProseMirror
  selection and feeds the existing editing-action pipeline (handleAction ->
  onSendMessage), so run reattachment, conflict handling, and the model-facing
  instruction are all reused unchanged.
- Re-export the Tiptap Editor type from @vertesia/rich-text so consumers can
  type the editor without a direct @tiptap/core dependency.
- captureSpanAnchor unit tests (real headless editor): span capture with
  surrounding context, block-type labelling, empty-selection guard.
michaelva added 11 commits July 21, 2026 09:39
The display_artifact agent tool emits a `display_artifact` stream event. The
conversation now watches for the latest such event and reveals the artifact in
the document editor (selects the path, switches to the Artifacts tab, opens the
panel), once per distinct event so the user can still close it.
…oolbar

Deletes @vertesia/rich-text's text-symbol MarkdownEditorToolbar (Paragraph | B |
I | S | <> | ...) and its wiring, and adds a new icon-based EditorToolbar in the
UI layer (lucide icons + @vertesia/ui Button/DropdownMenu): a heading dropdown,
bold/italic/strike/inline-code, bullet/ordered list, blockquote/code-block,
horizontal-rule/insert-table, and undo/redo. Active/enabled state stays live via
a lightweight editor-transaction subscription (no @tiptap/react dependency in ui).

- The framework-agnostic rich-text package no longer ships a toolbar; the
  document editor renders EditorToolbar, the compact component editor is
  chrome-free.
- Reuses the existing richText.* i18n strings for accessible names.
- Table row/column editing and list indent/outdent are intentionally dropped
  from the toolbar (list nesting works via Tab/Shift-Tab; table structure editing
  is a planned context menu). Tests updated accordingly; the component-editor
  interaction tests type synchronously to avoid ProseMirror char-drop flake.
- Crisp foreground icons (was muted), shadcn-style hover (bg-muted), neutral
  active highlight.
- Undo/redo moved to the left of the bar, matching the reference layout.
- The Table control is now a context dropdown: "Insert table" when outside a
  table; add/delete row & column and delete-table when the caret is in one —
  restoring the table structure actions that the first toolbar pass dropped.
…sage

Reworks the document comment bar so the user can queue several comments before
sending: "Comment on selection" adds each note (with its quoted span) to a
pending list instead of firing a message per comment. A "Send to agent" button
composes the whole batch into a single conversation message and sends it.

Because the batch is sent as a normal message (no editing_action metadata), it
renders as an ordinary message bubble in the timeline rather than the heavy
"Comment on document" card that clashed with the app.

- ArtifactEditingSurface gains an onSendMessage prop; the agent Artifacts tab
  wires it to the conversation's plain-message sender.
- Component-editor interaction tests paste (one op) instead of typing char by
  char, which raced ProseMirror in jsdom and dropped characters.
…n card

- Merge the comment controls into the formatting toolbar so it is one row: the
  "Comment on selection" button + queued-comment count + "Send to agent" live at
  the end of the toolbar, and the composer/pending list drop below it. Removes
  the separate comment bar and the toolbar's gray background.
- EditorToolbar gains an optional onSendComment prop; VertesiaMarkdownDocumentEditor
  forwards it; ArtifactEditingSurface wires it to the conversation sender. Deletes
  the standalone SpanSelectionComment.
- Lighten DocumentEditingActionCard: drop the heavy colored box, icon circle, and
  collapsible; render a compact muted header + content (+ a subtle quote) so it
  reads like an ordinary message instead of a mismatched card.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a collaborative, artifact-backed Markdown editing workflow in @vertesia/ui, adds a new Markdown-first TipTap-based rich-text package (@vertesia/rich-text), and wires agent conversation UI to support document-edit actions, artifact editing, and artifact viewing.

Changes:

  • Add @vertesia/rich-text package and UI adapters for Vertesia-specific Markdown rendering/editing.
  • Add artifact-backed collaborative editing surfaces, diff/rebase helpers, and structured “document edit/comment” cards in the agent chat UI.
  • Extend client/common types and UI plumbing for artifact content reads/writes, run reattachment, and expanded i18n coverage.

Reviewed changes

Copilot reviewed 86 out of 87 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/ui/vitest.config.ts Add aliases for @vertesia/ui/rich-text subpath and @vertesia/rich-text in UI tests.
packages/ui/tsconfig.json Add project reference to ../rich-text.
packages/ui/src/widgets/markdown/useArtifactContent.ts Add blob-storage wording + expose artifact response ETag.
packages/ui/src/widgets/markdown/textDiff.test.ts Add tests for word/line diff, unified diff, and rebase behavior.
packages/ui/src/widgets/markdown/MarkdownRenderer.tsx Add onArtifactOpen and preserveSourcePositions options.
packages/ui/src/widgets/markdown/MarkdownLink.tsx Allow host to intercept Markdown artifact clicks via onArtifactOpen.
packages/ui/src/widgets/markdown/MarkdownLink.test.tsx Test artifact-open interception behavior.
packages/ui/src/widgets/markdown/index.ts Export collaborative editing, artifact editing surface, and text diff utilities.
packages/ui/src/rich-text/VertesiaRichTextEditor.tsx Add Vertesia UI adapters around @vertesia/rich-text editors/renderers.
packages/ui/src/rich-text/VertesiaRichTextEditor.test.tsx Add integration tests for Vertesia rich-text adapters + source-preserve flow.
packages/ui/src/rich-text/index.ts Export Vertesia rich-text editor adapters from UI package.
packages/ui/src/i18n/locales/zh.json Add document-editing + rich-text strings (zh).
packages/ui/src/i18n/locales/zh-TW.json Add document-editing + rich-text strings (zh-TW).
packages/ui/src/i18n/locales/tr.json Add document-editing + rich-text strings (tr).
packages/ui/src/i18n/locales/ru.json Add document-editing + rich-text strings (ru).
packages/ui/src/i18n/locales/pt.json Add document-editing + rich-text strings (pt).
packages/ui/src/i18n/locales/ko.json Add document-editing + rich-text strings (ko).
packages/ui/src/i18n/locales/ja.json Add document-editing + rich-text strings (ja).
packages/ui/src/i18n/locales/it.json Add document-editing + rich-text strings (it).
packages/ui/src/i18n/locales/fr.json Add document-editing + rich-text strings (fr).
packages/ui/src/i18n/locales/es.json Add document-editing + rich-text strings (es).
packages/ui/src/i18n/locales/de.json Add document-editing + rich-text strings (de).
packages/ui/src/i18n/locales/ar.json Add document-editing + rich-text strings (ar).
packages/ui/src/features/store/objects/components/useContentPanelHooks.ts Add change-highlighting + safer async loading/cropping behavior for object text.
packages/ui/src/features/store/objects/components/TextEditorPanel.tsx Use rich-text document editor for Markdown objects.
packages/ui/src/features/store/objects/components/TextEditorPanel.test.tsx Test Markdown objects render rich-text editor in the panel.
packages/ui/src/features/store/objects/components/index.ts Export DocumentEditingPanel from components barrel.
packages/ui/src/features/store/objects/components/documentEditingTarget.ts Resolve “edit target” to current head revision + load ETag/content.
packages/ui/src/features/store/objects/components/documentEditingTarget.test.ts Tests for head-resolution and failure modes.
packages/ui/src/features/store/objects/components/documentEditingRun.ts Identify/reattach editing runs via tags/properties + scope open tracking.
packages/ui/src/features/store/objects/components/documentEditingRun.test.ts Tests for identity matching and lookup fallback behavior.
packages/ui/src/features/store/objects/components/DocumentEditingLockBanner.tsx Add persistent lock/unlock banner for agent-editing periods.
packages/ui/src/features/store/objects/components/DocumentEditingLockBanner.test.tsx Tests for lock banner messaging and toggle callback.
packages/ui/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx Add environment/model selector for document-editing sessions.
packages/ui/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts Tests for project default selection logic.
packages/ui/src/features/store/objects/components/documentEditingAgentConfig.ts Define tools/skills allowlist + excluded tools for document-editing agent sessions.
packages/ui/src/features/store/objects/components/documentEditingAgentConfig.test.ts Tests ensuring shell stays allowed and canonical writes remain excluded.
packages/ui/src/features/store/objects/components/documentArtifactRefs.ts Persist run-local artifact references to durable documents/ storage on publish.
packages/ui/src/features/store/objects/components/documentArtifactRefs.test.ts Tests for reference collection, rewrite, and failure pinning.
packages/ui/src/features/agent/chat/ModernAgentOutput/utils.ts Ignore passive artifact autosave updates when computing “in progress”.
packages/ui/src/features/agent/chat/ModernAgentOutput/utils.test.ts Test “passive artifact update does not resurrect Working” behavior.
packages/ui/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx Thread artifact-open callback + render document edit/comment cards.
packages/ui/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx Add shared prose rendering with “show more/less” collapsing.
packages/ui/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx Tests for collapse toggle + table rendering.
packages/ui/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx Add onOpenArtifact path for Markdown artifact attachments.
packages/ui/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx Wire artifact-open and structured edit action cards into summary/stacked views.
packages/ui/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx Test summary rendering of structured editing cards.
packages/ui/src/features/agent/chat/ModernAgentConversation.test.tsx Add tests for right-panel artifact opening + collaboration availability.
packages/ui/src/features/agent/chat/index.ts Export SendAgentMessageFn type.
packages/ui/src/features/agent/chat/hooks/useAgentStream.ts Add onMessage callback + retain structured UPDATE events and guard replayed history.
packages/ui/src/features/agent/chat/hooks/useAgentStream.test.tsx Tests for structured updates retention + callback forwarding + replay suppression.
packages/ui/src/features/agent/chat/DocumentEditingActionCard.tsx Render structured edit/comment actions as compact cards (with inline diffs).
packages/ui/src/features/agent/chat/DocumentEditingActionCard.test.tsx Tests for parsing/validation and rendering for comment/edit/applied cases.
packages/ui/src/features/agent/chat/ArtifactsTab.tsx Add in-panel Markdown artifact editor (block/doc modes), autosave status, and host open/download paths.
packages/ui/src/features/agent/chat/AgentRightPanel.tsx Add selected-artifact plumbing + send-message callback for artifacts editor.
packages/ui/src/core/components/shadcn/modal/dialog.tsx Add size="full" modal option.
packages/ui/src/tests/setup.ts Add jsdom shims for canvas + caret geometry used by chart/mermaid/ProseMirror.
packages/ui/src/tests/axe-helper.ts Add shared axe run options + per-test exclude support.
packages/ui/src/tests/a11y.test.tsx Exclude Radix focus guards from axe run to avoid false positives.
packages/ui/package.json Add dependency + export subpath for @vertesia/ui/rich-text.
packages/ui/externals.js Mark @vertesia/rich-text as external.
packages/rich-text/tsconfig.test.json Add test tsconfig for @vertesia/rich-text.
packages/rich-text/tsconfig.json Add library tsconfig for @vertesia/rich-text.
packages/rich-text/src/types.ts Define rich-text renderer prop contracts and opaque markdown kinds.
packages/rich-text/src/MarkdownRichTextEditor.tsx Implement Markdown-first TipTap editor with stable renderer proxies + external sync policies.
packages/rich-text/src/MarkdownEditors.tsx Provide component/document editor shells with default debounce policies.
packages/rich-text/src/markdown.test.ts Add parse/serialize conformance tests and editing command round-trips.
packages/rich-text/src/index.ts Export rich-text editor APIs, helpers, and types.
packages/rich-text/rolldown.config.js Add ESM bundling config for rich-text runtime.
packages/rich-text/package.json Add @vertesia/rich-text package definition, deps, build/test scripts.
packages/common/src/store/conversation-state.ts Add initialization_call_ids to conversation state.
packages/common/src/store/agent-run.ts Add initial skills/tool calls/excluded tools + artifact content update types.
packages/common/src/interaction.ts Add InitialToolCall and conversation execution fields for initial skills/tools/exclusions.
packages/client/src/store/AgentsApi.ts Add artifact content read + conditional update endpoints.
package.json Pin vite version to 8.1.0.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/ui/src/features/agent/chat/ArtifactsTab.tsx
Comment thread packages/ui/src/features/agent/chat/ArtifactsTab.tsx
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.

3 participants