Skip to content

feat(agent): In-App Agent side panel behind the agent-in-app-experience flag#13472

Open
CodeJuggernaut wants to merge 78 commits into
mainfrom
nathaniel/fe-1187-agent-side-panel-fe-implementation
Open

feat(agent): In-App Agent side panel behind the agent-in-app-experience flag#13472
CodeJuggernaut wants to merge 78 commits into
mainfrom
nathaniel/fe-1187-agent-side-panel-fe-implementation

Conversation

@CodeJuggernaut

@CodeJuggernaut CodeJuggernaut commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

In-App Agent side panel (FE-1187): the agent chat panel lands as an in-source workbench extension wired to the comfy-agent v1 backend (Comfy-Org/cloud PR 4432), fail-closed behind the PostHog flag agent-in-app-experience. Nothing renders unless the flag is enabled; the flag exists in PostHog (staging + prod) and is off.

What ships

  • src/workbench/extensions/agent/ feature subtree: chat panel UI, a zod wire contract with live-captured fixtures, a REST client for ingest /api/agent/*, a reconnecting WS event transport on the host /ws, a server-draft store, and a schema-validated full-graph canvas apply.
  • Flag-gated extension entry src/extensions/core/agentPanel.ts: registers the sidebar tab and a top-bar "Ask Comfy Agent" button only when the flag is on, unregisters on flip-off.
  • The draft loop: draft_patch WS events adopt monotonically into agentDraftStore; useDraftCanvasApply reloads the canvas via validateComfyWorkflow then app.loadGraphData. The server owns the workflow: it creates one when a message opens a thread and returns its id in the 202 ack, and the panel binds drafts to that id (no client-side minting).
  • Attach image/video, streamed thinking / tool-call / markdown rendering, chat-history drawer with copy-as-markdown, message rating to telemetry (PM-98), onboarding coach.
  • Dependencies: shiki (lazy-imported by CodeBlock for highlighting), catalog-pinned. Button.vue uses the existing cva.

Rollout and open decisions

  • Flag is OFF in staging and prod; the extension is tree-shaken from non-cloud builds. Safe to merge dark.
  • Two items pending design sign-off, each sourced from the Figma spec and a one-line change: the composer caption copy (agent.caption) and the entry-button/tab icon (a lucide sparkles placeholder stands in for the Comfy mark).
  • Known V0 limitations (documented, non-blocking): closing the panel within a send's POST round-trip leaves that one turn uncancelled and it self-heals on reopen; past chat sessions are not persisted across reload (the current conversation is the one copyable history row).

Acceptance (V0)

Every P0 bucket from the Design & Requirements doc is shipped and tested: flag-gated entry + top-bar button, the five exact suggested prompts, streamed turns, attach-to-upload, the draft-to-canvas loop, history + copy-markdown, message rating, reconnect resilience. Deferred with reason: @-tag canvas nodes (ticket canceled), tool-call duration (the v1 wire emits no per-call duration), the minimized-ball form factor (superseded by the sidebar tab).

Review focus

  • The draft pipeline: the server-owned workflow id from the message ack binds the draft store, and monotonic draft_patch adoption drives the canvas.
  • The telemetry addition is additive (a new optional provider method + event); no existing provider signature changed.
  • Linear: FE-1187 (panel), PM-98 (rating capture via telemetry).

Screenshots

image image image image

Reviewer notes

  • Conflict dialog: copy, action structure, and choice semantics follow DES-502 as posted; it renders as a centered modal for now, with the canvas-anchored placement pending Jo/Uy sign-off on the DES-502 thread.
  • Attachments: the reported loss (images vanishing from the chat on send) is fixed and visible in-session. Persisting attachment refs across a thread reopen needs the history endpoint to return them, a backend gap already flagged to Kishore.

Fixes FE-1187

…kage

Bulk copy of the panel from Comfy-Org/comfy-inapp-agent (branch
feat/agent-panel-services at b3675fc) into packages/agent-panel
(@comfyorg/agent-panel), per the decision to home the panel in this
repo. The package is self-contained with its own dependency set and
configs; tooling versions align with the workspace catalog (vite 8,
vitest 4, zod ^3.23.8, typescript 5.9, vue-tsc 3.2), so the code
relocates verbatim. Excluded from the copy: the standalone project's
lockfile and nested workspace marker; the root allowBuilds already
carries vue-demi: false. The unused @ai-sdk/vue dependency was dropped.

Contents: the comfy-agent v1 client stack (zod wire contract with
live-captured fixtures, REST client for ingest /api/agent/*, WebSocket
event transport and event-source adapter, server-draft store plus the
useDraftCanvasApply seam, useAgentSession composition root), the
fail-closed PostHog gate for the agent-in-app-experience flag, the full
chat panel UI (message stream, composer, chrome, shelved safety
surfaces), i18n, and a dev harness with an offline scripted mode and a
live proxy mode verified against pr-4432.testenvs.comfy.org.

Package gates green in the workspace: typecheck clean, 197 tests
passing, build succeeds.
Next (B8): mount the panel in the app, wire the host socket, JWT,
PostHog client, and canvas draft-apply, then cut over from the legacy
extension.
…nsion

The panel now runs the way everything user-facing runs here: as an
extension. src/extensions/core/agentPanel.ts (cloud-only, loaded from
the core extension index) registers a sidebar tab gated by the PostHog
flag agent-in-app-experience, fail-closed: the tab is not registered
until the flag evaluates true and unregisters if it turns off. The tab
is type custom: it mounts the panel as its own Vue app via the new
mountAgentPanel entry, which keeps the package's vue-i18n major (11)
and pinia instance isolated from the host (vue-i18n 9). Host wiring in
the entry: workspace Cloud JWT as the REST bearer (store instance
captured in host context, since pinia's active-instance global is
shared with the panel app), the host /ws socket wrapped by
createWebSocketEventSource, and draft apply as a schema-validated
full-graph load (validateComfyWorkflow then app.loadGraphData) per the
V0 tech design.

To make the package importable from src, it is properly library-ized:
all internal @/ alias imports rewritten to relative paths (the alias
would have resolved against the HOST src when host tooling compiles the
package sources), the alias config dropped, and a public entry exposed
via package.json exports (mount + the host-facing seam builders and
types). Root package.json declares the workspace dependency like every
other @comfyorg package.

Known follow-ups tracked in FE-1187: socket-reconnect rebinding for the
event source, confirming agent_* frames reach raw socket listeners,
the workflowId provider for draft binding, panel styling inside the tab
(tailwind theme integration), and the design-alignment pass.

Package gates green (typecheck, 197 tests, build); host root typecheck
green with the entry included.
…subtree

The panel now lives at src/workbench/extensions/agent (manager-extension
pattern) on host package versions, host pinia, and host vue-i18n; the
workspace package is gone. The sidebar tab becomes a plain type vue
registration (AgentPanelRoot rendered by the host app) and the
fail-closed PostHog flag gate in the extension entry is unchanged.

AgentPanelRoot is the host-context session root: workspace Cloud JWT as
the REST bearer, the host /ws socket wrapped as the event source (null
socket degrades to a warned no-op source), draft apply as a
schema-validated full-graph load, and the chrome the dev harness
carried (history drawer, starting-point modal, onboarding coach with
the same storage key and anchor) minus the dev fakes.

Theme tokens route through host semantics instead of hardcoded values:
the feature-owned agentTheme.css aliases every agent-* token to a host
token via @theme inline (pairing table documented inline), so the panel
tracks host theme flips including light mode, an intentional divergence
from the dark-only Figma frames deferred to the FE-1187 design pass.
Literals remain only for accent-fg, pill, and radius, each flagged as a
design-review item. The design-system master is untouched; the host
style entry gains one import line.

Locale keys merge under a top-level agent block in the host main.json.
cn comes from @comfyorg/tailwind-utils. shiki and
class-variance-authority join the catalog and root deps (CodeBlock
highlighting, Button variants). Dead-in-src modules are deleted rather
than knip-ignored: the shelved agentCore kernel and its tests, the
MinimizedBall dock (superseded by the sidebar form factor), and six
never-wired components knip flagged with zero consumers; unused schema
type exports trimmed likewise.

Gates: typecheck clean, moved tree 147/147 (197 minus the deleted
kernel's 50 cases; no surviving test lost), full unit suite 12550
passed, oxlint, eslint, oxfmt, and knip all green. Handoff invariants
re-verified in the moved tree: fixture schema gate, event transport
acceptance, draft monotonic adoption and canvas-apply seam, fail-closed
gate, entries interleave, send/stop/new-chat paths.

Known follow-ups (FE-1187): browser visual pass on the aliased tokens
and light mode, socket-reconnect rebinding, workflowId provider for
draft binding, design alignment.
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🌐 Website E2E

Tip

All tests passed.

Status ✅ Passed
Report View Report

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/11/2026, 12:21:06 AM UTC

Links

🎭 Playwright: ✅ 1696 passed, 0 failed · 1 flaky

📊 Browser Reports
  • chromium: View Report (✅ 1677 / ❌ 0 / ⚠️ 0 / ⏭️ 5)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 16 / ❌ 0 / ⚠️ 1 / ⏭️ 0)

📦 Bundle: 7.88 MB gzip 🔴 +92.8 kB

Details

Summary

  • Raw size: 33.1 MB baseline 32.8 MB — 🔴 +353 kB
  • Gzip: 7.88 MB baseline 7.78 MB — 🔴 +92.8 kB
  • Brotli: 5.44 MB baseline 5.36 MB — 🔴 +76.8 kB
  • Bundles: 307 current • 303 baseline • 267 added / 263 removed

Category Glance
Vendor & Third-Party 🔴 +241 kB (15.5 MB) · Other 🔴 +105 kB (11.8 MB) · Graph Workspace 🔴 +3.69 kB (1.27 MB) · Panels & Settings 🔴 +1.85 kB (552 kB) · Data & Services 🔴 +1.5 kB (271 kB) · App Entry Points 🔴 +36 B (53.2 kB) · + 5 more

App Entry Points — 53.2 kB (baseline 53.2 kB) • 🔴 +36 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-C2tLXiQ0.js (new) 53.2 kB 🔴 +53.2 kB 🔴 +15.7 kB 🔴 +13.5 kB
assets/index-v1Y-tns7.js (removed) 53.2 kB 🟢 -53.2 kB 🟢 -15.7 kB 🟢 -13.5 kB

Status: 1 added / 1 removed

Graph Workspace — 1.27 MB (baseline 1.27 MB) • 🔴 +3.69 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CsXJQdKG.js (new) 1.27 MB 🔴 +1.27 MB 🔴 +272 kB 🔴 +204 kB
assets/GraphView-D7HDMaQE.js (removed) 1.27 MB 🟢 -1.27 MB 🟢 -271 kB 🟢 -203 kB

Status: 1 added / 1 removed

Views & Navigation — 110 kB (baseline 110 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-5ic1Ngdf.js (removed) 25 kB 🟢 -25 kB 🟢 -6.26 kB 🟢 -5.55 kB
assets/CloudSurveyView-CfXra0UK.js (new) 25 kB 🔴 +25 kB 🔴 +6.26 kB 🔴 +5.54 kB
assets/OAuthConsentView-CUfO7YYE.js (new) 15 kB 🔴 +15 kB 🔴 +4.1 kB 🔴 +3.57 kB
assets/OAuthConsentView-DcwvlIX4.js (removed) 15 kB 🟢 -15 kB 🟢 -4.1 kB 🟢 -3.56 kB
assets/CloudLoginView-B3tsI7Y_.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.07 kB 🔴 +2.69 kB
assets/CloudLoginView-Dz8BQLIc.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.07 kB 🟢 -2.68 kB
assets/CloudSignupView-CmEcMBcn.js (new) 9.79 kB 🔴 +9.79 kB 🔴 +2.74 kB 🔴 +2.41 kB
assets/CloudSignupView-cXJoBvkR.js (removed) 9.79 kB 🟢 -9.79 kB 🟢 -2.74 kB 🟢 -2.4 kB
assets/CloudLayoutView-BSfZXopw.js (new) 9.59 kB 🔴 +9.59 kB 🔴 +2.37 kB 🔴 +2.04 kB
assets/CloudLayoutView-PCj5q42g.js (removed) 9.59 kB 🟢 -9.59 kB 🟢 -2.37 kB 🟢 -2.06 kB
assets/UserCheckView-CSWuLBlJ.js (removed) 8.8 kB 🟢 -8.8 kB 🟢 -2.22 kB 🟢 -1.93 kB
assets/UserCheckView-DZFNpkUI.js (new) 8.8 kB 🔴 +8.8 kB 🔴 +2.22 kB 🔴 +1.93 kB
assets/CloudSubscriptionRedirectView-BeaRudEI.js (new) 6.98 kB 🔴 +6.98 kB 🔴 +2.58 kB 🔴 +2.26 kB
assets/CloudSubscriptionRedirectView-BuT99c5i.js (removed) 6.98 kB 🟢 -6.98 kB 🟢 -2.58 kB 🟢 -2.26 kB
assets/WidgetTextPreview-BoTLxnoA.js (new) 6.13 kB 🔴 +6.13 kB 🔴 +2.15 kB 🔴 +1.91 kB
assets/WidgetTextPreview-DNf8PILv.js (removed) 6.13 kB 🟢 -6.13 kB 🟢 -2.16 kB 🟢 -1.92 kB
assets/UserSelectView-qq4WJRG2.js (new) 6 kB 🔴 +6 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/UserSelectView-rPjh4MBk.js (removed) 6 kB 🟢 -6 kB 🟢 -2.15 kB 🟢 -1.89 kB
assets/CloudForgotPasswordView-C1q0Ltjo.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.76 kB 🔴 +1.54 kB
assets/CloudForgotPasswordView-DuJ3SuzE.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -1.76 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-D4fwPw-L.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.58 kB 🔴 +1.38 kB
assets/CloudAuthTimeoutView-DSo3nH9g.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.58 kB 🟢 -1.37 kB
assets/CloudSorryContactSupportView-CM4hSkTB.js (removed) 1.21 kB 🟢 -1.21 kB 🟢 -607 B 🟢 -529 B
assets/CloudSorryContactSupportView-Djc5nzI4.js (new) 1.21 kB 🔴 +1.21 kB 🔴 +607 B 🔴 +524 B
assets/layout-C88aNlyB.js (new) 447 B 🔴 +447 B 🔴 +284 B 🔴 +231 B
assets/layout-TjZhjbdY.js (removed) 447 B 🟢 -447 B 🟢 -283 B 🟢 -230 B
assets/WidgetTextPreview-B77Ay7MV.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +88 B
assets/WidgetTextPreview-BzgEUNez.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -89 B

Status: 14 added / 14 removed

Panels & Settings — 552 kB (baseline 550 kB) • 🔴 +1.85 kB

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-CyK-ec5H.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.97 kB 🟢 -8.83 kB
assets/KeybindingPanel-X3pukncb.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.97 kB 🔴 +8.83 kB
assets/settings-BM5CyS1j.js (new) 39.8 kB 🔴 +39.8 kB 🔴 +9.73 kB 🔴 +7.99 kB
assets/settings-Cqh0gKi5.js (removed) 39.8 kB 🟢 -39.8 kB 🟢 -9.73 kB 🟢 -7.99 kB
assets/settings-B29A6_Q9.js (new) 35.4 kB 🔴 +35.4 kB 🔴 +8.66 kB 🔴 +7.31 kB
assets/settings-BeJc46cE.js (removed) 35.4 kB 🟢 -35.4 kB 🟢 -8.66 kB 🟢 -7.32 kB
assets/settings-BXVYhVYo.js (new) 33.5 kB 🔴 +33.5 kB 🔴 +8.48 kB 🔴 +6.97 kB
assets/settings-C2dJcQWA.js (removed) 33.5 kB 🟢 -33.5 kB 🟢 -8.48 kB 🟢 -6.91 kB
assets/settings-B2c4ifiI.js (new) 33.1 kB 🔴 +33.1 kB 🔴 +8.51 kB 🔴 +7.09 kB
assets/settings-C3dopYiP.js (removed) 33.1 kB 🟢 -33.1 kB 🟢 -8.51 kB 🟢 -7.09 kB
assets/settings-CuKuvFYz.js (new) 31.5 kB 🔴 +31.5 kB 🔴 +8.78 kB 🔴 +7.31 kB
assets/settings-DVKUbm2d.js (removed) 31.5 kB 🟢 -31.5 kB 🟢 -8.78 kB 🟢 -7.32 kB
assets/settings-BO2pzKtl.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -8.41 kB 🟢 -7.37 kB
assets/settings-BzQ8bjtj.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +8.41 kB 🔴 +7.37 kB
assets/settings-BrS__ne3.js (new) 29.7 kB 🔴 +29.7 kB 🔴 +8.07 kB 🔴 +6.88 kB
assets/settings-D8b1JrNH.js (removed) 29.7 kB 🟢 -29.7 kB 🟢 -8.07 kB 🟢 -6.88 kB
assets/settings-BYr2fpjd.js (removed) 29.6 kB 🟢 -29.6 kB 🟢 -8.31 kB 🟢 -7.25 kB
assets/settings-dAU9ch_M.js (new) 29.6 kB 🔴 +29.6 kB 🔴 +8.31 kB 🔴 +7.26 kB
assets/settings-BgSipy9Z.js (removed) 28.8 kB 🟢 -28.8 kB 🟢 -7.99 kB 🟢 -6.95 kB
assets/settings-Dz9zribz.js (new) 28.8 kB 🔴 +28.8 kB 🔴 +7.99 kB 🔴 +6.96 kB
assets/settings-DH4zP_r4.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -8.44 kB 🟢 -7.03 kB
assets/settings-E8K8vuf2.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +8.45 kB 🔴 +7.02 kB
assets/SecretsPanel-0nbPQCgh.js (new) 27.3 kB 🔴 +27.3 kB 🔴 +6.63 kB 🔴 +5.82 kB
assets/SecretsPanel-DDq2UKoE.js (removed) 27.3 kB 🟢 -27.3 kB 🟢 -6.63 kB 🟢 -5.81 kB
assets/settings-Bv9lBdMq.js (removed) 25.2 kB 🟢 -25.2 kB 🟢 -8.2 kB 🟢 -6.6 kB
assets/settings-j9oSpTPg.js (new) 25.2 kB 🔴 +25.2 kB 🔴 +8.2 kB 🔴 +6.61 kB
assets/settings-BH65j1Ym.js (removed) 24.6 kB 🟢 -24.6 kB 🟢 -8.02 kB 🟢 -6.28 kB
assets/settings-Da-qfddl.js (new) 24.6 kB 🔴 +24.6 kB 🔴 +8.01 kB 🔴 +6.27 kB
assets/CreditsPanel-B4nmovJA.js (new) 15.9 kB 🔴 +15.9 kB 🔴 +4.66 kB 🔴 +4.09 kB
assets/CreditsPanel-BgiGtmx8.js (removed) 15.9 kB 🟢 -15.9 kB 🟢 -4.66 kB 🟢 -4.09 kB
assets/AboutPanel-B08O4kiJ.js (new) 12 kB 🔴 +12 kB 🔴 +3.29 kB 🔴 +2.94 kB
assets/AboutPanel-Cd18xW32.js (removed) 12 kB 🟢 -12 kB 🟢 -3.29 kB 🟢 -2.94 kB
assets/SubscriptionPanel-0Azj6BvR.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.66 kB 🟢 -3.21 kB
assets/SubscriptionPanel-DTAJJhbh.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.66 kB 🔴 +3.21 kB
assets/ExtensionPanel-CE4L38Kd.js (new) 9.03 kB 🔴 +9.03 kB 🔴 +2.5 kB 🔴 +2.2 kB
assets/ExtensionPanel-DH0O9Ddw.js (removed) 9.03 kB 🟢 -9.03 kB 🟢 -2.5 kB 🟢 -2.2 kB
assets/ServerConfigPanel-CEghRsh0.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -1.98 kB 🟢 -1.76 kB
assets/ServerConfigPanel-DrrbxUKK.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +1.98 kB 🔴 +1.76 kB
assets/UserPanel-CaxIvems.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/UserPanel-DMXBrNwd.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/refreshRemoteConfig-DC-rXBmU.js (removed) 2.88 kB 🟢 -2.88 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/refreshRemoteConfig-xl-zSlj0.js (new) 2.88 kB 🔴 +2.88 kB 🔴 +1.26 kB 🔴 +1.11 kB
assets/config-DKLPHzmn.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +1.04 kB 🔴 +841 B
assets/config-dOowlgvn.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -1.04 kB 🟢 -839 B
assets/agentPanel-bsT2HHTU.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +881 B 🔴 +794 B
assets/cloudRemoteConfig-BuRwqLOj.js (new) 990 B 🔴 +990 B 🔴 +544 B 🔴 +469 B
assets/cloudRemoteConfig-DF7LQuRS.js (removed) 990 B 🟢 -990 B 🟢 -542 B 🟢 -461 B
assets/refreshRemoteConfig-4g3iWUDG.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +87 B
assets/refreshRemoteConfig-DsJP6ulK.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -82 B

Status: 25 added / 24 removed / 3 unchanged

User & Accounts — 29.1 kB (baseline 29.1 kB) • 🔴 +1 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SignUpForm-B_zY3wr0.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +4.19 kB 🔴 +3.66 kB
assets/SignUpForm-ViAvnW_P.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -4.19 kB 🟢 -3.66 kB
assets/PasswordFields-CtH3edle.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.42 kB 🔴 +1.26 kB
assets/PasswordFields-QXBspEcz.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.42 kB 🟢 -1.26 kB
assets/auth-YA90nFDS.js (new) 3.69 kB 🔴 +3.69 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/auth-Y0eyzq29.js (removed) 3.69 kB 🟢 -3.69 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/usePostAuthRedirect-D3hYdF21.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.27 kB 🟢 -1.11 kB
assets/usePostAuthRedirect-Vk9bxl5W.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.27 kB 🔴 +1.11 kB
assets/UpdatePasswordContent-C0AeQZ5g.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -880 B 🟢 -768 B
assets/UpdatePasswordContent-CyPeKgYE.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +878 B 🔴 +766 B
assets/WorkspaceProfilePic-CpDzoCi8.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +860 B 🔴 +778 B
assets/WorkspaceProfilePic-D2A9kmRt.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -860 B 🟢 -775 B
assets/authStore-CaEV_lWw.js (new) 130 B 🔴 +130 B 🔴 +109 B 🔴 +107 B
assets/authStore-DxoWAu0A.js (removed) 130 B 🟢 -130 B 🟢 -109 B 🟢 -106 B
assets/workspaceAuthStore-DOdH_LTL.js (removed) 110 B 🟢 -110 B 🟢 -104 B 🟢 -113 B
assets/workspaceAuthStore-mwuc1WMo.js (new) 110 B 🔴 +110 B 🔴 +104 B 🔴 +114 B
assets/auth-BTFUKWYB.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -79 B
assets/auth-DnFuw44M.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +88 B

Status: 9 added / 9 removed / 1 unchanged

Editors & Dialogs — 117 kB (baseline 117 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-DQpzOmAE.js (removed) 90.5 kB 🟢 -90.5 kB 🟢 -19.3 kB 🟢 -16.5 kB
assets/ComfyHubPublishDialog-DwN1W31E.js (new) 90.5 kB 🔴 +90.5 kB 🔴 +19.3 kB 🔴 +16.5 kB
assets/useShareDialog-CoYMvTNb.js (removed) 23.7 kB 🟢 -23.7 kB 🟢 -5.59 kB 🟢 -4.96 kB
assets/useShareDialog-D9BXmRfB.js (new) 23.7 kB 🔴 +23.7 kB 🔴 +5.59 kB 🔴 +4.97 kB
assets/SubscriptionInactiveMemberDialog-0nugrdwq.js (removed) 2.55 kB 🟢 -2.55 kB 🟢 -1.03 kB 🟢 -882 B
assets/SubscriptionInactiveMemberDialog-CM5O7QC2.js (new) 2.55 kB 🔴 +2.55 kB 🔴 +1.03 kB 🔴 +898 B
assets/ComfyHubPublishDialog-BN4hotNT.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +88 B
assets/ComfyHubPublishDialog-CPLjsjp4.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -91 B
assets/useSubscriptionDialog-C9CDfZmI.js (removed) 110 B 🟢 -110 B 🟢 -102 B 🟢 -89 B
assets/useSubscriptionDialog-CL3fi7aR.js (new) 110 B 🔴 +110 B 🔴 +102 B 🔴 +89 B

Status: 5 added / 5 removed

UI Components — 57.5 kB (baseline 57.5 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-C3EZ_8Mz.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.82 kB 🟢 -3.41 kB
assets/ComfyQueueButton-kySFguYE.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.82 kB 🔴 +3.41 kB
assets/useTerminalTabs-B8h1Qetf.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +3.84 kB 🔴 +3.38 kB
assets/useTerminalTabs-BKOcx1qS.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -3.83 kB 🟢 -3.38 kB
assets/TopbarBadge-BvFQgqkE.js (new) 7.7 kB 🔴 +7.7 kB 🔴 +1.87 kB 🔴 +1.65 kB
assets/TopbarBadge-DOJmk-uy.js (removed) 7.7 kB 🟢 -7.7 kB 🟢 -1.87 kB 🟢 -1.64 kB
assets/ScrubableNumberInput-CN1nrHnX.js (removed) 6.55 kB 🟢 -6.55 kB 🟢 -2.19 kB 🟢 -1.93 kB
assets/ScrubableNumberInput-l-KR11P0.js (new) 6.55 kB 🔴 +6.55 kB 🔴 +2.19 kB 🔴 +1.93 kB
assets/toggle-group-BhX4fvNT.js (removed) 4.16 kB 🟢 -4.16 kB 🟢 -1.45 kB 🟢 -1.28 kB
assets/toggle-group-BIHlkQCh.js (new) 4.16 kB 🔴 +4.16 kB 🔴 +1.45 kB 🔴 +1.27 kB
assets/Button-GnEb057H.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.41 kB 🟢 -1.25 kB
assets/Button-WAyZ5Hkq.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.41 kB 🔴 +1.23 kB
assets/SubscribeButton-lrH6pEds.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -1.05 kB 🟢 -916 B
assets/SubscribeButton-Pjq6G09A.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +1.06 kB 🔴 +946 B
assets/WidgetButton-C5VlCTQY.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +924 B 🔴 +817 B
assets/WidgetButton-Drnc42Wz.js (removed) 1.98 kB 🟢 -1.98 kB 🟢 -921 B 🟢 -816 B
assets/Input-B5GxogcN.js (new) 1.81 kB 🔴 +1.81 kB 🔴 +902 B 🔴 +811 B
assets/Input-BRI-NJWP.js (removed) 1.81 kB 🟢 -1.81 kB 🟢 -902 B 🟢 -791 B
assets/UserAvatar-BIj85jn1.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -673 B 🟢 -576 B
assets/UserAvatar-GdBq97AE.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +672 B 🔴 +584 B
assets/CloudBadge-Ubc4VSyT.js (removed) 1.18 kB 🟢 -1.18 kB 🟢 -594 B 🟢 -515 B
assets/CloudBadge-ZTTHdVXJ.js (new) 1.18 kB 🔴 +1.18 kB 🔴 +595 B 🔴 +515 B
assets/cloudFeedbackTopbarButton-CQ7Lq7Ob.js (new) 829 B 🔴 +829 B 🔴 +501 B 🔴 +423 B
assets/cloudFeedbackTopbarButton-qWsn5-yu.js (removed) 829 B 🟢 -829 B 🟢 -497 B 🟢 -418 B
assets/ComfyQueueButton-D9835bnG.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -92 B
assets/ComfyQueueButton-g9pZ1fGH.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +92 B

Status: 13 added / 13 removed

Data & Services — 271 kB (baseline 270 kB) • 🔴 +1.5 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/load3dService-dHiACR47.js (new) 127 kB 🔴 +127 kB 🔴 +27.8 kB 🔴 +23.5 kB
assets/load3dService-e-PV4_hJ.js (removed) 127 kB 🟢 -127 kB 🟢 -27.8 kB 🟢 -23.5 kB
assets/api-Ds27ymO1.js (new) 91.9 kB 🔴 +91.9 kB 🔴 +25.4 kB 🔴 +21.7 kB
assets/api-CuSSCymh.js (removed) 91.9 kB 🟢 -91.9 kB 🟢 -25.4 kB 🟢 -21.7 kB
assets/workflowShareService-CU5saeyL.js (new) 17 kB 🔴 +17 kB 🔴 +5.01 kB 🔴 +4.44 kB
assets/workflowShareService-Ln3DdHp4.js (removed) 17 kB 🟢 -17 kB 🟢 -5.01 kB 🟢 -4.44 kB
assets/releaseStore-B1Txwwuc.js (new) 8.29 kB 🔴 +8.29 kB 🔴 +2.34 kB 🔴 +2.05 kB
assets/releaseStore-DeH2ku73.js (removed) 8.29 kB 🟢 -8.29 kB 🟢 -2.34 kB 🟢 -2.05 kB
assets/keybindingService-CdEMzit9.js (removed) 7.46 kB 🟢 -7.46 kB 🟢 -1.92 kB 🟢 -1.64 kB
assets/keybindingService-D1Ld4sK9.js (new) 7.46 kB 🔴 +7.46 kB 🔴 +1.92 kB 🔴 +1.65 kB
assets/dialogStore-BxSjTi21.js (new) 5.36 kB 🔴 +5.36 kB 🔴 +1.66 kB 🔴 +1.43 kB
assets/dialogStore-Tsl1x9JG.js (removed) 5.36 kB 🟢 -5.36 kB 🟢 -1.67 kB 🟢 -1.43 kB
assets/extensionStore-nX8Ko6SG.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/extensionStore-VQyBp4Hv.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/userStore-CSgp_ona.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -930 B 🟢 -818 B
assets/userStore-DyJWsYSn.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +932 B 🔴 +818 B
assets/serverConfigStore-CcUnx1EN.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +811 B 🔴 +708 B
assets/serverConfigStore-qu3oQ3lz.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -811 B 🟢 -707 B
assets/audioService-BGnm2X0P.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +860 B 🔴 +755 B
assets/audioService-YjBFhNJk.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -862 B 🟢 -749 B
assets/agentPanelStore-BWAbdV5d.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +665 B 🔴 +594 B
assets/dialogService-B_shkPYv.js (new) 100 B 🔴 +100 B 🔴 +99 B 🔴 +102 B
assets/dialogService-BJcfLLXz.js (removed) 100 B 🟢 -100 B 🟢 -99 B 🟢 -95 B
assets/settingStore-BATtcN4h.js (removed) 98 B 🟢 -98 B 🟢 -98 B 🟢 -89 B
assets/settingStore-BZ_HU6hs.js (new) 98 B 🔴 +98 B 🔴 +98 B 🔴 +89 B
assets/assetsStore-C5efdOjk.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +100 B
assets/assetsStore-CRtBreV_.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -86 B
assets/releaseStore-2tMzgKOp.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +83 B
assets/releaseStore-DIFpSdBC.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -83 B
assets/api-CfZYNu6b.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B
assets/api-CiU_NWYq.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B

Status: 16 added / 15 removed / 1 unchanged

Utilities & Hooks — 3.39 MB (baseline 3.39 MB) • 🔴 +9 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/promotionUtils-DJE6K3Bz.js (new) 3.03 MB 🔴 +3.03 MB 🔴 +699 kB 🔴 +527 kB
assets/promotionUtils-CXL3DXlF.js (removed) 3.03 MB 🟢 -3.03 MB 🟢 -699 kB 🟢 -527 kB
assets/useConflictDetection-pCs3JoB2.js (new) 234 kB 🔴 +234 kB 🔴 +52.3 kB 🔴 +42.6 kB
assets/useConflictDetection-Cx-htaTD.js (removed) 234 kB 🟢 -234 kB 🟢 -52.3 kB 🟢 -42.6 kB
assets/useLoad3d-BoqlmYd5.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -5.82 kB 🟢 -5.16 kB
assets/useLoad3d-BsKQeosX.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +5.82 kB 🔴 +5.17 kB
assets/useLoad3dViewer-CogkThju.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -4.98 kB 🟢 -4.36 kB
assets/useLoad3dViewer-DDqO9B_f.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +4.98 kB 🔴 +4.36 kB
assets/useFeatureFlags-BT8EspF4.js (removed) 6.51 kB 🟢 -6.51 kB 🟢 -2.02 kB 🟢 -1.7 kB
assets/useFeatureFlags-DVpspWFT.js (new) 6.51 kB 🔴 +6.51 kB 🔴 +2.02 kB 🔴 +1.7 kB
assets/useTypeformEmbed-BTG9LPXB.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.96 kB 🟢 -1.64 kB
assets/useTypeformEmbed-CDV6n1l8.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.95 kB 🔴 +1.64 kB
assets/downloadUtil-CFh6pcLP.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.85 kB 🔴 +1.54 kB
assets/downloadUtil-DvewDGtL.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.85 kB 🟢 -1.54 kB
assets/subscriptionCheckoutUtil-B7FnA69u.js (new) 3.85 kB 🔴 +3.85 kB 🔴 +1.54 kB 🔴 +1.35 kB
assets/subscriptionCheckoutUtil-BpI9SM-X.js (removed) 3.85 kB 🟢 -3.85 kB 🟢 -1.54 kB 🟢 -1.35 kB
assets/curveUtils-CeJ5Qppt.js (removed) 3.83 kB 🟢 -3.83 kB 🟢 -1.29 kB 🟢 -1.13 kB
assets/curveUtils-Kw2FgkNT.js (new) 3.83 kB 🔴 +3.83 kB 🔴 +1.29 kB 🔴 +1.14 kB
assets/useSessionCookie-BVCr9Sh8.js (new) 3.61 kB 🔴 +3.61 kB 🔴 +1.21 kB 🔴 +1.04 kB
assets/useSessionCookie-DrAaFXWj.js (removed) 3.61 kB 🟢 -3.61 kB 🟢 -1.2 kB 🟢 -1.04 kB
assets/useTransformState-Dbk6AwPT.js (new) 3.58 kB 🔴 +3.58 kB 🔴 +1.58 kB 🔴 +1.3 kB
assets/useTransformState-DdsD-mnX.js (removed) 3.58 kB 🟢 -3.58 kB 🟢 -1.58 kB 🟢 -1.31 kB
assets/useExternalLink-BBvmwM9X.js (new) 3.03 kB 🔴 +3.03 kB 🔴 +1.16 kB 🔴 +1.02 kB
assets/useExternalLink-CaGsK5HI.js (removed) 3.03 kB 🟢 -3.03 kB 🟢 -1.16 kB 🟢 -1.03 kB
assets/useDowngradeToPersonal-BxIq-WwF.js (removed) 3 kB 🟢 -3 kB 🟢 -1.19 kB 🟢 -1.03 kB
assets/useDowngradeToPersonal-ByuATjLu.js (new) 3 kB 🔴 +3 kB 🔴 +1.19 kB 🔴 +1.05 kB
assets/assetPreviewUtil-Cl9VF1Ni.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.01 kB 🔴 +878 B
assets/assetPreviewUtil-gFdxlBRV.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1 kB 🟢 -881 B
assets/useUpstreamValue-BO0Ec6MR.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -794 B 🟢 -705 B
assets/useUpstreamValue-BuxR5mvT.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +795 B 🔴 +704 B
assets/useWorkspaceTierLabel-C0C6iu-f.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -854 B 🟢 -734 B
assets/useWorkspaceTierLabel-Dyj-VnWQ.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +855 B 🔴 +736 B
assets/useErrorHandling-D9xwlTKc.js (new) 1.54 kB 🔴 +1.54 kB 🔴 +646 B 🔴 +551 B
assets/useErrorHandling-zBNaKbWw.js (removed) 1.54 kB 🟢 -1.54 kB 🟢 -647 B 🟢 -549 B
assets/hdrFormatUtil-Chs6GzfH.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -517 B 🟢 -436 B
assets/hdrFormatUtil-CZLxszMu.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +516 B 🔴 +441 B
assets/histogramUtil-BpR6BGBm.js (removed) 972 B 🟢 -972 B 🟢 -572 B 🟢 -489 B
assets/histogramUtil-UGuiwAC3.js (new) 972 B 🔴 +972 B 🔴 +572 B 🔴 +490 B
assets/useClickDragGuard-5Dg9wfa6.js (new) 828 B 🔴 +828 B 🔴 +409 B 🔴 +359 B
assets/useClickDragGuard-HXtF0ahu.js (removed) 828 B 🟢 -828 B 🟢 -408 B 🟢 -360 B
assets/useLoad3d-Cmx136J5.js (removed) 311 B 🟢 -311 B 🟢 -163 B 🟢 -147 B
assets/useLoad3d-TdK02y5C.js (new) 311 B 🔴 +311 B 🔴 +162 B 🔴 +147 B
assets/SkeletonUtils-CCVsh2oZ.js (new) 133 B 🔴 +133 B 🔴 +111 B 🔴 +111 B
assets/SkeletonUtils-DTLaglou.js (removed) 133 B 🟢 -133 B 🟢 -111 B 🟢 -106 B
assets/useSessionCookie-ChdLOmwP.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +77 B
assets/useSessionCookie-D_rnx1Vv.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -81 B
assets/useFeatureFlags-6Ye-qyxh.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +86 B
assets/useFeatureFlags-CqqTW44X.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -84 B
assets/useLoad3dViewer-BOJ3yI44.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +83 B
assets/useLoad3dViewer-DBecnAuR.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -84 B
assets/useCurrentUser-BkyVoUOu.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +96 B
assets/useCurrentUser-BS8J5iFg.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -83 B

Status: 26 added / 26 removed / 9 unchanged

Vendor & Third-Party — 15.5 MB (baseline 15.3 MB) • 🔴 +241 kB

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-three-BAYtRT8A.js (new) 7.09 MB 🔴 +7.09 MB 🔴 +2.18 MB 🔴 +1.02 MB
assets/vendor-three-GauOUfg-.js (removed) 7.09 MB 🟢 -7.09 MB 🟢 -2.18 MB 🟢 -1.02 MB
assets/vendor-other-_oQ2j-ur.js (new) 2.11 MB 🔴 +2.11 MB 🔴 +471 kB 🔴 +381 kB
assets/vendor-other-AZ71J3fe.js (removed) 1.87 MB 🟢 -1.87 MB 🟢 -405 kB 🟢 -326 kB
assets/vendor-xterm-Day2jAYN.js (new) 374 kB 🔴 +374 kB 🔴 +75.6 kB 🔴 +61.1 kB
assets/vendor-xterm-m0jE-nSN.js (removed) 374 kB 🟢 -374 kB 🟢 -75.6 kB 🟢 -61.1 kB

Status: 3 added / 3 removed / 13 unchanged

Other — 11.8 MB (baseline 11.7 MB) • 🔴 +105 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/nodeDefs-Bs-ibNX3.js (new) 682 kB 🔴 +682 kB 🔴 +112 kB 🔴 +76.2 kB
assets/nodeDefs-xJPONwzr.js (removed) 682 kB 🟢 -682 kB 🟢 -112 kB 🟢 -76.3 kB
assets/nodeDefs-8r3RBeRN.js (removed) 626 kB 🟢 -626 kB 🟢 -101 kB 🟢 -70.6 kB
assets/nodeDefs-DJ7Ir9tI.js (new) 626 kB 🔴 +626 kB 🔴 +101 kB 🔴 +70.6 kB
assets/nodeDefs-CjaB8vcO.js (removed) 623 kB 🟢 -623 kB 🟢 -104 kB 🟢 -72.7 kB
assets/nodeDefs-nIoR9_qC.js (new) 623 kB 🔴 +623 kB 🔴 +104 kB 🔴 +72.7 kB
assets/nodeDefs-4kst3wes.js (new) 572 kB 🔴 +572 kB 🔴 +101 kB 🔴 +70.3 kB
assets/nodeDefs-bmezO03p.js (removed) 572 kB 🟢 -572 kB 🟢 -101 kB 🟢 -70.3 kB
assets/nodeDefs-BIK6qk2f.js (removed) 569 kB 🟢 -569 kB 🟢 -95.4 kB 🟢 -68.2 kB
assets/nodeDefs-K3lbmCbE.js (new) 569 kB 🔴 +569 kB 🔴 +95.4 kB 🔴 +68.2 kB
assets/nodeDefs-CDT4odM0.js (new) 552 kB 🔴 +552 kB 🔴 +98.7 kB 🔴 +69.6 kB
assets/nodeDefs-D6-HkKVz.js (removed) 552 kB 🟢 -552 kB 🟢 -98.7 kB 🟢 -69.6 kB
assets/nodeDefs-0IDP729m.js (removed) 549 kB 🟢 -549 kB 🟢 -97.1 kB 🟢 -70.5 kB
assets/nodeDefs-DuUgmAK1.js (new) 549 kB 🔴 +549 kB 🔴 +97.1 kB 🔴 +70.5 kB
assets/nodeDefs-BnX7Jsuo.js (removed) 544 kB 🟢 -544 kB 🟢 -97.8 kB 🟢 -71.3 kB
assets/nodeDefs-C5DXsv2C.js (new) 544 kB 🔴 +544 kB 🔴 +97.8 kB 🔴 +71.2 kB
assets/nodeDefs-D0OGP4f0.js (new) 541 kB 🔴 +541 kB 🔴 +94.6 kB 🔴 +68.9 kB
assets/nodeDefs-D2WLc9pl.js (removed) 541 kB 🟢 -541 kB 🟢 -94.6 kB 🟢 -68.9 kB
assets/nodeDefs-DPxVRl02.js (new) 535 kB 🔴 +535 kB 🔴 +93.4 kB 🔴 +67.9 kB
assets/nodeDefs-fdYOg9sS.js (removed) 535 kB 🟢 -535 kB 🟢 -93.4 kB 🟢 -67.9 kB
assets/nodeDefs-C6YLZU3S.js (removed) 497 kB 🟢 -497 kB 🟢 -96.8 kB 🟢 -67.8 kB
assets/nodeDefs-D3urOw6D.js (new) 497 kB 🔴 +497 kB 🔴 +96.8 kB 🔴 +67.8 kB
assets/nodeDefs-C1EfRvuM.js (new) 493 kB 🔴 +493 kB 🔴 +95.4 kB 🔴 +66.4 kB
assets/nodeDefs-DuIlxeOb.js (removed) 493 kB 🟢 -493 kB 🟢 -95.4 kB 🟢 -66.4 kB
assets/main-CI5d_j2_.js (removed) 288 kB 🟢 -288 kB 🟢 -71.7 kB 🟢 -56 kB
assets/main-RZT5XbPM.js (new) 288 kB 🔴 +288 kB 🔴 +71.7 kB 🔴 +56 kB
assets/main-DSjyYl_A.js (removed) 258 kB 🟢 -258 kB 🟢 -65 kB 🟢 -52 kB
assets/main-DVHzSZy3.js (new) 258 kB 🔴 +258 kB 🔴 +65 kB 🔴 +52 kB
assets/main-C3A5vjjV.js (new) 245 kB 🔴 +245 kB 🔴 +64.4 kB 🔴 +51.2 kB
assets/main-DPDvrQgO.js (removed) 245 kB 🟢 -245 kB 🟢 -64.4 kB 🟢 -51.2 kB
assets/main-B5wALbHD.js (new) 237 kB 🔴 +237 kB 🔴 +64 kB 🔴 +50.5 kB
assets/main-D6zgj7cl.js (removed) 237 kB 🟢 -237 kB 🟢 -64 kB 🟢 -50.5 kB
assets/main-CqNsvZL3.js (removed) 229 kB 🟢 -229 kB 🟢 -61.9 kB 🟢 -49.6 kB
assets/main-Dl7LP7xE.js (new) 229 kB 🔴 +229 kB 🔴 +61.9 kB 🔴 +49.6 kB
assets/main-Bs0oBo9N.js (removed) 216 kB 🟢 -216 kB 🟢 -62.8 kB 🟢 -52 kB
assets/main-ZICQCE6B.js (new) 216 kB 🔴 +216 kB 🔴 +62.8 kB 🔴 +52 kB
assets/main-CP1-_ZeO.js (removed) 214 kB 🟢 -214 kB 🟢 -61.9 kB 🟢 -49.7 kB
assets/main-X-7399_s.js (new) 214 kB 🔴 +214 kB 🔴 +61.9 kB 🔴 +49.6 kB
assets/main-C7LYd-QC.js (new) 209 kB 🔴 +209 kB 🔴 +61.1 kB 🔴 +50.5 kB
assets/main-D6kstxVq.js (removed) 209 kB 🟢 -209 kB 🟢 -61.1 kB 🟢 -50.5 kB
assets/main-CN8z1V8O.js (removed) 206 kB 🟢 -206 kB 🟢 -61.3 kB 🟢 -51.1 kB
assets/main-DJWuRyP8.js (new) 206 kB 🔴 +206 kB 🔴 +61.3 kB 🔴 +51.1 kB
assets/main-_mWkfgpI.js (new) 205 kB 🔴 +205 kB 🔴 +60.4 kB 🔴 +50.5 kB
assets/main-CJUn43cO.js (removed) 205 kB 🟢 -205 kB 🟢 -60.4 kB 🟢 -50.5 kB
assets/main-BqIQI16O.js (new) 189 kB 🔴 +189 kB 🔴 +55.4 kB 🔴 +46.5 kB
assets/main-IAojJkel.js (removed) 186 kB 🟢 -186 kB 🟢 -54.4 kB 🟢 -45.8 kB
assets/main-CM8drmsk.js (removed) 182 kB 🟢 -182 kB 🟢 -60.1 kB 🟢 -47.8 kB
assets/main-DlQ4STjb.js (new) 182 kB 🔴 +182 kB 🔴 +60.1 kB 🔴 +47.8 kB
assets/main-BO6gdMR6.js (removed) 180 kB 🟢 -180 kB 🟢 -60 kB 🟢 -47.6 kB
assets/main-OzD5xBSt.js (new) 180 kB 🔴 +180 kB 🔴 +60 kB 🔴 +47.6 kB
assets/core-C6vaSUlc.js (new) 121 kB 🔴 +121 kB 🔴 +31.2 kB 🔴 +26.3 kB
assets/core-DUU6U31m.js (removed) 121 kB 🟢 -121 kB 🟢 -31.1 kB 🟢 -26.3 kB
assets/AgentPanelRoot-C1b5tYCv.js (new) 101 kB 🔴 +101 kB 🔴 +22.1 kB 🔴 +18.9 kB
assets/WidgetSelect-CLxlwJ8y.js (new) 89.3 kB 🔴 +89.3 kB 🔴 +20.1 kB 🔴 +17.2 kB
assets/WidgetSelect-DNit_Wow.js (removed) 89.3 kB 🟢 -89.3 kB 🟢 -20.1 kB 🟢 -17.3 kB
assets/Load3DControls-DrXSOOAx.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +7.57 kB 🔴 +6.62 kB
assets/Load3DControls-ZHZmkJ2K.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -7.57 kB 🟢 -6.61 kB
assets/SubscriptionTransitionPreviewWorkspace-aUU2JDO9.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -9.65 kB 🟢 -8.53 kB
assets/SubscriptionTransitionPreviewWorkspace-BCIZuEUc.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +9.65 kB 🔴 +8.53 kB
assets/SubscriptionRequiredDialogContentUnified-CJav4RS8.js (new) 41.2 kB 🔴 +41.2 kB 🔴 +9.16 kB 🔴 +7.96 kB
assets/SubscriptionRequiredDialogContentUnified-OmgSlL5_.js (removed) 41.2 kB 🟢 -41.2 kB 🟢 -9.16 kB 🟢 -7.97 kB
assets/WorkspacePanelContent-BzZhFlOV.js (removed) 34.5 kB 🟢 -34.5 kB 🟢 -7.5 kB 🟢 -6.6 kB
assets/WorkspacePanelContent-D5P3Q83a.js (new) 34.5 kB 🔴 +34.5 kB 🔴 +7.5 kB 🔴 +6.6 kB
assets/WidgetBoundingBoxes-C85TNxjK.js (new) 33.8 kB 🔴 +33.8 kB 🔴 +9.2 kB 🔴 +8.17 kB
assets/WidgetBoundingBoxes-D5KcvGpE.js (removed) 33.8 kB 🟢 -33.8 kB 🟢 -9.2 kB 🟢 -8.16 kB
assets/WidgetPainter-_fZce0SV.js (removed) 32.7 kB 🟢 -32.7 kB 🟢 -7.9 kB 🟢 -6.98 kB
assets/WidgetPainter-BlPeGXPf.js (new) 32.7 kB 🔴 +32.7 kB 🔴 +7.91 kB 🔴 +7.01 kB
assets/Load3dViewerContent-CUB_2h_V.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +6.3 kB 🔴 +5.47 kB
assets/Load3dViewerContent-CydekvQl.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -6.3 kB 🟢 -5.47 kB
assets/HdrViewerContent-C6YwUGhX.js (new) 29.2 kB 🔴 +29.2 kB 🔴 +8.09 kB 🔴 +7.14 kB
assets/HdrViewerContent-CTyuU-Ya.js (removed) 29.2 kB 🟢 -29.2 kB 🟢 -8.09 kB 🟢 -7.13 kB
assets/initHostTelemetry-B296ZE6L.js (new) 27.8 kB 🔴 +27.8 kB 🔴 +6.65 kB 🔴 +5.53 kB
assets/SubscriptionRequiredDialogContent-BuAHbTvc.js (new) 27.4 kB 🔴 +27.4 kB 🔴 +6.75 kB 🔴 +5.95 kB
assets/SubscriptionRequiredDialogContent-DCrvFD8Z.js (removed) 27.4 kB 🟢 -27.4 kB 🟢 -6.75 kB 🟢 -5.96 kB
assets/initHostTelemetry-Bvyw9WBU.js (removed) 26.3 kB 🟢 -26.3 kB 🟢 -6.4 kB 🟢 -5.33 kB
assets/SubscriptionPanelContentWorkspace-C0pHJuBV.js (new) 25 kB 🔴 +25 kB 🔴 +5.84 kB 🔴 +5.13 kB
assets/SubscriptionPanelContentWorkspace-DnHaOmAC.js (removed) 25 kB 🟢 -25 kB 🟢 -5.84 kB 🟢 -5.12 kB
assets/ColorPicker-BKIlJVfJ.js (removed) 25 kB 🟢 -25 kB 🟢 -6.54 kB 🟢 -5.77 kB
assets/ColorPicker-CZI6hb3K.js (new) 25 kB 🔴 +25 kB 🔴 +6.54 kB 🔴 +5.78 kB
assets/SubscriptionRequiredDialogContentWorkspace-BQiUG-vc.js (new) 24.6 kB 🔴 +24.6 kB 🔴 +5.66 kB 🔴 +4.97 kB
assets/SubscriptionRequiredDialogContentWorkspace-CIXwF4I3.js (removed) 24.6 kB 🟢 -24.6 kB 🟢 -5.66 kB 🟢 -4.98 kB
assets/WidgetImageCrop-CSCbX-5A.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.75 kB 🟢 -5.05 kB
assets/WidgetImageCrop-DgC3-O4n.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.75 kB 🔴 +5.04 kB
assets/load3d-CGeEJ94J.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.44 kB 🟢 -4.71 kB
assets/load3d-DHzvkqiK.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.45 kB 🔴 +4.71 kB
assets/CurrentUserPopoverWorkspace-BX8CWkIh.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +4.75 kB 🔴 +4.23 kB
assets/CurrentUserPopoverWorkspace-H3hhLl3e.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -4.75 kB 🟢 -4.22 kB
assets/SignInContent-Be6jhUPd.js (removed) 20.1 kB 🟢 -20.1 kB 🟢 -5.07 kB 🟢 -4.43 kB
assets/SignInContent-LlOyBdWS.js (new) 20.1 kB 🔴 +20.1 kB 🔴 +5.07 kB 🔴 +4.44 kB
assets/WidgetInputNumber-1NK4YTER.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.82 kB 🟢 -4.29 kB
assets/WidgetInputNumber-CYYSWVpf.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.82 kB 🔴 +4.28 kB
assets/Load3D-DvmBD-Ou.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.52 kB 🟢 -3.94 kB
assets/Load3D-QOQg7BUi.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.52 kB 🔴 +3.93 kB
assets/commands-Cw_FARKe.js (new) 18.4 kB 🔴 +18.4 kB 🔴 +4 kB 🔴 +3.12 kB
assets/commands-mCcLSjbe.js (removed) 18.4 kB 🟢 -18.4 kB 🟢 -4 kB 🟢 -3.12 kB
assets/commands-B9Z_9DRZ.js (removed) 17.5 kB 🟢 -17.5 kB 🟢 -3.65 kB 🟢 -2.89 kB
assets/commands-SFV4BxsM.js (new) 17.5 kB 🔴 +17.5 kB 🔴 +3.65 kB 🔴 +2.88 kB
assets/commands-aCIZS-sI.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +3.69 kB 🔴 +2.83 kB
assets/commands-CfQIeGHN.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -3.69 kB 🟢 -2.83 kB
assets/commands-Cq3bfBXD.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.77 kB 🟢 -2.96 kB
assets/commands-Dtqx10UC.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.76 kB 🔴 +2.96 kB
assets/CreditsTile-0fud1LPA.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.54 kB 🟢 -4.01 kB
assets/CreditsTile-CCiAyRei.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.54 kB 🔴 +4.01 kB
assets/WidgetRecordAudio-C8KkNa9e.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.63 kB 🔴 +4.14 kB
assets/WidgetRecordAudio-DUznN0EC.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.63 kB 🟢 -4.14 kB
assets/commands-CDf5Nwi4.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +3.8 kB 🔴 +2.99 kB
assets/commands-CdHEIfEK.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -3.79 kB 🟢 -2.99 kB
assets/commands-CJ6QJ5QO.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.54 kB 🔴 +2.94 kB
assets/commands-fQ9UB4ym.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.53 kB 🟢 -2.95 kB
assets/WidgetRange-DFG3iVZ0.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.16 kB 🔴 +3.73 kB
assets/WidgetRange-DQR7ACYn.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.17 kB 🟢 -3.73 kB
assets/commands-BWboOlYz.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.5 kB 🔴 +2.91 kB
assets/commands-gcbWaWPr.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.5 kB 🟢 -2.91 kB
assets/commands-CST0_Zk5.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.42 kB 🟢 -2.8 kB
assets/commands-Dwi5la__.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.42 kB 🔴 +2.8 kB
assets/commands-CWo9RtqI.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.39 kB 🟢 -2.81 kB
assets/commands-f8GbIkjx.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.39 kB 🔴 +2.81 kB
assets/commands-BPDCVQ5E.js (removed) 15.6 kB 🟢 -15.6 kB 🟢 -3.65 kB 🟢 -2.85 kB
assets/commands-Cok0Eb6J.js (new) 15.6 kB 🔴 +15.6 kB 🔴 +3.65 kB 🔴 +2.85 kB
assets/commands-C-I_M23C.js (new) 14.9 kB 🔴 +14.9 kB 🔴 +3.59 kB 🔴 +2.74 kB
assets/commands-CcDbvw2g.js (removed) 14.9 kB 🟢 -14.9 kB 🟢 -3.59 kB 🟢 -2.74 kB
assets/commands-99eKo7Tz.js (removed) 14.7 kB 🟢 -14.7 kB 🟢 -3.54 kB 🟢 -2.63 kB
assets/commands-DsVha5EJ.js (new) 14.7 kB 🔴 +14.7 kB 🔴 +3.54 kB 🔴 +2.63 kB
assets/DialogHeader-jVRIHgjc.js (removed) 14.7 kB 🟢 -14.7 kB 🟢 -4 kB 🟢 -3.55 kB
assets/DialogHeader-qnNIHwfR.js (new) 14.7 kB 🔴 +14.7 kB 🔴 +3.99 kB 🔴 +3.55 kB
assets/WaveAudioPlayer-B-GrQvbM.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.49 kB 🔴 +3.06 kB
assets/WaveAudioPlayer-DlyMVuf8.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.48 kB 🟢 -3.06 kB
assets/i18n-C_d-IzZ7.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +3.25 kB 🔴 +2.74 kB
assets/i18n-D6tg2GFA.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -3.24 kB 🟢 -2.72 kB
assets/WidgetCurve-D61Xd2J-.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.5 kB 🔴 +3.16 kB
assets/WidgetCurve-R3Nhk6JP.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.5 kB 🟢 -3.16 kB
assets/AudioPreviewPlayer-Crc4n0vm.js (removed) 10.6 kB 🟢 -10.6 kB 🟢 -3.06 kB 🟢 -2.73 kB
assets/AudioPreviewPlayer-DkI61gIb.js (new) 10.6 kB 🔴 +10.6 kB 🔴 +3.06 kB 🔴 +2.74 kB
assets/TeamWorkspacesDialogContent-C78Lbl9Y.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +3 kB 🔴 +2.66 kB
assets/TeamWorkspacesDialogContent-W-fmSVgc.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -3 kB 🟢 -2.67 kB
assets/SelectValue-B-bocZcT.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.48 kB 🔴 +2.19 kB
assets/SelectValue-BIsIrLc9.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.48 kB 🟢 -2.19 kB
assets/Load3DConfiguration-B7P1saN_.js (removed) 9.02 kB 🟢 -9.02 kB 🟢 -2.66 kB 🟢 -2.35 kB
assets/Load3DConfiguration-Drg7UjeC.js (new) 9.02 kB 🔴 +9.02 kB 🔴 +2.67 kB 🔴 +2.35 kB
assets/onboardingCloudRoutes-DjsBznJ9.js (removed) 8.5 kB 🟢 -8.5 kB 🟢 -2.67 kB 🟢 -2.29 kB
assets/onboardingCloudRoutes-UkhoJ_Lr.js (new) 8.5 kB 🔴 +8.5 kB 🔴 +2.66 kB 🔴 +2.3 kB
assets/nodeTemplates-CLRvPg54.js (new) 8.33 kB 🔴 +8.33 kB 🔴 +2.88 kB 🔴 +2.54 kB
assets/nodeTemplates-D9G0mjsp.js (removed) 8.33 kB 🟢 -8.33 kB 🟢 -2.88 kB 🟢 -2.54 kB
assets/WidgetImageCompare-C46gDJSI.js (removed) 8.19 kB 🟢 -8.19 kB 🟢 -2.33 kB 🟢 -2.04 kB
assets/WidgetImageCompare-CkIzm4-3.js (new) 8.19 kB 🔴 +8.19 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/NightlySurveyController-BXZV0qa2.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.7 kB 🔴 +2.39 kB
assets/NightlySurveyController-Cb-SdODj.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.71 kB 🟢 -2.37 kB
assets/Popover-BbTFDHmn.js (new) 7.52 kB 🔴 +7.52 kB 🔴 +2.72 kB 🔴 +2.39 kB
assets/Popover-VMkykqla.js (removed) 7.52 kB 🟢 -7.52 kB 🟢 -2.72 kB 🟢 -2.39 kB
assets/InviteMemberDialogContent-BW8hgly8.js (new) 6.76 kB 🔴 +6.76 kB 🔴 +2.22 kB 🔴 +1.96 kB
assets/InviteMemberDialogContent-C_r4ssZN.js (removed) 6.76 kB 🟢 -6.76 kB 🟢 -2.22 kB 🟢 -1.96 kB
assets/WidgetWithControl-Dyu0CbEj.js (new) 6.38 kB 🔴 +6.38 kB 🔴 +2.59 kB 🔴 +2.29 kB
assets/WidgetWithControl-mNHFmWte.js (removed) 6.38 kB 🟢 -6.38 kB 🟢 -2.59 kB 🟢 -2.29 kB
assets/AnimationControls-BaJItnIg.js (removed) 6.16 kB 🟢 -6.16 kB 🟢 -1.88 kB 🟢 -1.67 kB
assets/AnimationControls-BFmEcnfU.js (new) 6.16 kB 🔴 +6.16 kB 🔴 +1.88 kB 🔴 +1.67 kB
assets/tierBenefits-CMlKQ8Mt.js (new) 6.02 kB 🔴 +6.02 kB 🔴 +1.93 kB 🔴 +1.67 kB
assets/tierBenefits-fWvftZIg.js (removed) 6.02 kB 🟢 -6.02 kB 🟢 -1.93 kB 🟢 -1.67 kB
assets/load3dPreviewExtensions-QIGuA-vw.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -1.85 kB 🟢 -1.63 kB
assets/load3dPreviewExtensions-t6jXgE3V.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +1.85 kB 🔴 +1.63 kB
assets/main-2eYWKIsX.js (new) 5.8 kB 🔴 +5.8 kB 🔴 +1.86 kB 🔴 +1.56 kB
assets/main-F2jpGxVI.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.84 kB 🟢 -1.56 kB
assets/CancelSubscriptionDialogContent-Bw9lPJG6.js (new) 5.76 kB 🔴 +5.76 kB 🔴 +1.98 kB 🔴 +1.73 kB
assets/CancelSubscriptionDialogContent-cYsM-Wld.js (removed) 5.76 kB 🟢 -5.76 kB 🟢 -1.97 kB 🟢 -1.73 kB
assets/FreeTierDialogContent-DJhli9k7.js (removed) 5.25 kB 🟢 -5.25 kB 🟢 -1.76 kB 🟢 -1.55 kB
assets/FreeTierDialogContent-GZllUKmj.js (new) 5.25 kB 🔴 +5.25 kB 🔴 +1.76 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-_gArdPSK.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/CreateWorkspaceDialogContent-D1ypqsCU.js (removed) 5.19 kB 🟢 -5.19 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/CloudNotificationContent-BQQT2JVk.js (new) 5.11 kB 🔴 +5.11 kB 🔴 +1.79 kB 🔴 +1.54 kB
assets/CloudNotificationContent-DHerAfhQ.js (removed) 5.11 kB 🟢 -5.11 kB 🟢 -1.79 kB 🟢 -1.54 kB
assets/missingModelDownload-BCMEZirc.js (removed) 5.07 kB 🟢 -5.07 kB 🟢 -1.98 kB 🟢 -1.73 kB
assets/missingModelDownload-VxCgE7_b.js (new) 5.07 kB 🔴 +5.07 kB 🔴 +1.98 kB 🔴 +1.72 kB
assets/ChangeMemberRoleDialogContent-CmrHob-B.js (new) 5.04 kB 🔴 +5.04 kB 🔴 +1.67 kB 🔴 +1.46 kB
assets/ChangeMemberRoleDialogContent-DRPvUXL4.js (removed) 5.04 kB 🟢 -5.04 kB 🟢 -1.67 kB 🟢 -1.46 kB
assets/EditWorkspaceDialogContent-BEjtk8qe.js (new) 5 kB 🔴 +5 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/EditWorkspaceDialogContent-CpxqgJYp.js (removed) 5 kB 🟢 -5 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/PaletteSwatchRow-B8qN4PEN.js (removed) 4.91 kB 🟢 -4.91 kB 🟢 -1.9 kB 🟢 -1.69 kB
assets/PaletteSwatchRow-iqlmWsCZ.js (new) 4.91 kB 🔴 +4.91 kB 🔴 +1.9 kB 🔴 +1.69 kB
assets/WidgetTextarea-Be31NEQB.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.9 kB 🟢 -1.66 kB
assets/WidgetTextarea-BnqG5oBV.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.9 kB 🔴 +1.66 kB
assets/DowngradeRemoveMembersDialogContent-C06Z8MAE.js (new) 4.83 kB 🔴 +4.83 kB 🔴 +1.7 kB 🔴 +1.47 kB
assets/DowngradeRemoveMembersDialogContent-DzN_tMvA.js (removed) 4.83 kB 🟢 -4.83 kB 🟢 -1.71 kB 🟢 -1.47 kB
assets/saveMesh-DgvBW7Q-.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.55 kB 🔴 +1.37 kB
assets/saveMesh-IuPMRW2m.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.55 kB 🟢 -1.37 kB
assets/Preview3d-BXBGY1RB.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.43 kB 🔴 +1.23 kB
assets/Preview3d-VD-QHOCj.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.43 kB 🟢 -1.23 kB
assets/ValueControlPopover-DvFNWTiy.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.59 kB 🔴 +1.42 kB
assets/ValueControlPopover-DVWGh2ma.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.59 kB 🟢 -1.42 kB
assets/ApiNodesSignInContent-CY_jJn-q.js (removed) 4.14 kB 🟢 -4.14 kB 🟢 -1.34 kB 🟢 -1.17 kB
assets/ApiNodesSignInContent-kxepA636.js (new) 4.14 kB 🔴 +4.14 kB 🔴 +1.35 kB 🔴 +1.18 kB
assets/Slider-BOVx5iF3.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.45 kB 🔴 +1.26 kB
assets/Slider-CxhfDuXq.js (removed) 3.92 kB 🟢 -3.92 kB 🟢 -1.45 kB 🟢 -1.26 kB
assets/DeleteWorkspaceDialogContent-BfpTlfN7.js (new) 3.91 kB 🔴 +3.91 kB 🔴 +1.47 kB 🔴 +1.27 kB
assets/DeleteWorkspaceDialogContent-D6mC4s6p.js (removed) 3.91 kB 🟢 -3.91 kB 🟢 -1.47 kB 🟢 -1.27 kB
assets/WidgetBoundingBox-6Jmn1YnP.js (new) 3.82 kB 🔴 +3.82 kB 🔴 +1.06 kB 🔴 +933 B
assets/WidgetBoundingBox-OdempNsT.js (removed) 3.82 kB 🟢 -3.82 kB 🟢 -1.06 kB 🟢 -922 B
assets/WidgetGalleria-BqEJ_HqZ.js (new) 3.8 kB 🔴 +3.8 kB 🔴 +1.48 kB 🔴 +1.32 kB
assets/WidgetGalleria-rj03JvFs.js (removed) 3.8 kB 🟢 -3.8 kB 🟢 -1.47 kB 🟢 -1.32 kB
assets/LeaveWorkspaceDialogContent-BR0IMCkT.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.42 kB 🟢 -1.23 kB
assets/LeaveWorkspaceDialogContent-DS4dXA5_.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.42 kB 🔴 +1.22 kB
assets/RemoveMemberDialogContent-CdJr9my9.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.37 kB 🟢 -1.19 kB
assets/RemoveMemberDialogContent-CWPYTFOM.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.19 kB
assets/WidgetToggleSwitch-B_KkIJE-.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.4 kB 🔴 +1.24 kB
assets/WidgetToggleSwitch-DnRYORGX.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.4 kB 🟢 -1.24 kB
assets/RevokeInviteDialogContent-Ck5Iqnvq.js (removed) 3.63 kB 🟢 -3.63 kB 🟢 -1.38 kB 🟢 -1.21 kB
assets/RevokeInviteDialogContent-DjDWaalr.js (new) 3.63 kB 🔴 +3.63 kB 🔴 +1.38 kB 🔴 +1.21 kB
assets/InviteMemberUpsellDialogContent-C55AJyUe.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.27 kB 🟢 -1.11 kB
assets/InviteMemberUpsellDialogContent-DKptG34Q.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.27 kB 🔴 +1.11 kB
assets/workspaceCheckoutTelemetry-CaH_n40U.js (removed) 3.47 kB 🟢 -3.47 kB 🟢 -1.56 kB 🟢 -1.36 kB
assets/workspaceCheckoutTelemetry-DsTFDSZL.js (new) 3.47 kB 🔴 +3.47 kB 🔴 +1.56 kB 🔴 +1.36 kB
assets/Media3DTop-DquUFrDF.js (removed) 3.26 kB 🟢 -3.26 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/Media3DTop-DXmlVNh6.js (new) 3.26 kB 🔴 +3.26 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/WidgetMarkdown-4i21RAuz.js (new) 3.13 kB 🔴 +3.13 kB 🔴 +1.28 kB 🔴 +1.11 kB
assets/WidgetMarkdown-DMRCVzWl.js (removed) 3.13 kB 🟢 -3.13 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetInputText-BD27BmmP.js (new) 3.07 kB 🔴 +3.07 kB 🔴 +1.29 kB 🔴 +1.16 kB
assets/WidgetInputText-BkPLjp6o.js (removed) 3.07 kB 🟢 -3.07 kB 🟢 -1.29 kB 🟢 -1.16 kB
assets/GlobalToast-CgzYAIwc.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/GlobalToast-D_u1dc7S.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/MediaVideoTop-jISDJECV.js (new) 2.91 kB 🔴 +2.91 kB 🔴 +1.18 kB 🔴 +1.05 kB
assets/MediaVideoTop-pvzVQ4Un.js (removed) 2.91 kB 🟢 -2.91 kB 🟢 -1.18 kB 🟢 -1.03 kB
assets/load3dAdvanced-BZPj5Qpa.js (removed) 2.87 kB 🟢 -2.87 kB 🟢 -1.13 kB 🟢 -981 B
assets/load3dAdvanced-Cw6O6PaY.js (new) 2.87 kB 🔴 +2.87 kB 🔴 +1.13 kB 🔴 +981 B
assets/loadExternalScript-B_CMtZ-X.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -947 B 🟢 -771 B
assets/loadExternalScript-C_rebJiy.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +946 B 🔴 +771 B
assets/ErrorPanelSurveyCta-DpfJBuK3.js (removed) 2.64 kB 🟢 -2.64 kB 🟢 -1.17 kB 🟢 -1.03 kB
assets/ErrorPanelSurveyCta-DQk80Ip3.js (new) 2.64 kB 🔴 +2.64 kB 🔴 +1.17 kB 🔴 +1.03 kB
assets/SubscribeToRun-B2Suu81T.js (new) 2.56 kB 🔴 +2.56 kB 🔴 +1.11 kB 🔴 +974 B
assets/SubscribeToRun-DYO4ejHS.js (removed) 2.56 kB 🟢 -2.56 kB 🟢 -1.11 kB 🟢 -975 B
assets/WidgetLayoutField-9JM3MA8x.js (new) 2.43 kB 🔴 +2.43 kB 🔴 +1.06 kB 🔴 +980 B
assets/WidgetLayoutField-DQuuyCxU.js (removed) 2.43 kB 🟢 -2.43 kB 🟢 -1.06 kB 🟢 -981 B
assets/WidgetChart-CsnLCEJG.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.03 kB 🔴 +889 B
assets/WidgetChart-DFIWWUUc.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1.03 kB 🟢 -890 B
assets/SubscriptionBenefits-aD2va9TB.js (new) 2.07 kB 🔴 +2.07 kB 🔴 +710 B 🔴 +606 B
assets/SubscriptionBenefits-r46JKqq6.js (removed) 2.07 kB 🟢 -2.07 kB 🟢 -710 B 🟢 -610 B
assets/MediaImageTop-BiumeZam.js (removed) 2.06 kB 🟢 -2.06 kB 🟢 -992 B 🟢 -856 B
assets/MediaImageTop-VrAN2s0S.js (new) 2.06 kB 🔴 +2.06 kB 🔴 +993 B 🔴 +884 B
assets/constants-B2Er7DMT.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -724 B 🟢 -613 B
assets/constants-CobDif5d.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +724 B 🔴 +609 B
assets/graphHasMissingNodes-CEu_pgN5.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -906 B 🟢 -796 B
assets/graphHasMissingNodes-DJblq49B.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +909 B 🔴 +791 B
assets/MediaTextTop-CkAW2Lsq.js (new) 1.82 kB 🔴 +1.82 kB 🔴 +886 B 🔴 +757 B
assets/MediaTextTop-CkIytMYS.js (removed) 1.82 kB 🟢 -1.82 kB 🟢 -886 B 🟢 -772 B
assets/webviewDetection-CJzPgyiQ.js (new) 1.81 kB 🔴 +1.81 kB 🔴 +864 B 🔴 +714 B
assets/webviewDetection-Cys3rZXE.js (removed) 1.81 kB 🟢 -1.81 kB 🟢 -865 B 🟢 -715 B
assets/WidgetColorPicker-BVfYvJjx.js (new) 1.74 kB 🔴 +1.74 kB 🔴 +785 B 🔴 +697 B
assets/WidgetColorPicker-MmGr9gLx.js (removed) 1.74 kB 🟢 -1.74 kB 🟢 -787 B 🟢 -696 B
assets/Loader-BzvHBgB8.js (new) 1.69 kB 🔴 +1.69 kB 🔴 +813 B 🔴 +746 B
assets/Loader-iwVpHujT.js (removed) 1.69 kB 🟢 -1.69 kB 🟢 -814 B 🟢 -747 B
assets/WidgetColors-BxwJxpgD.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -834 B 🟢 -738 B
assets/WidgetColors-DxuRbzR4.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +833 B 🔴 +739 B
assets/MediaAudioTop-BfyZlxvp.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -834 B 🟢 -698 B
assets/MediaAudioTop-DHEETOw3.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +837 B 🔴 +700 B
assets/Textarea-fL2OpQ9f.js (removed) 1.61 kB 🟢 -1.61 kB 🟢 -843 B 🟢 -739 B
assets/Textarea-sVaVqCDn.js (new) 1.61 kB 🔴 +1.61 kB 🔴 +842 B 🔴 +745 B
assets/signInSchema-6IRN57Rp.js (new) 1.6 kB 🔴 +1.6 kB 🔴 +586 B 🔴 +512 B
assets/signInSchema-D7bvrYAk.js (removed) 1.6 kB 🟢 -1.6 kB 🟢 -586 B 🟢 -510 B
assets/widgetPropFilter-BJY3NS_s.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +704 B 🔴 +607 B
assets/widgetPropFilter-CW26IoSd.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -705 B 🟢 -573 B
assets/VideoPlayOverlay-b0lY4esR.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +761 B 🔴 +676 B
assets/VideoPlayOverlay-D-8Ok2ob.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -757 B 🟢 -676 B
assets/CloudRunButtonWrapper-DSuPgprz.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +551 B 🔴 +519 B
assets/CloudRunButtonWrapper-uZLTZJv7.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -553 B 🟢 -488 B
assets/MediaOtherTop-CdbyekeI.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +606 B 🔴 +503 B
assets/MediaOtherTop-DAT83Emv.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -606 B 🟢 -504 B
assets/nodeTypes-gVz_GAPY.js (removed) 1.03 kB 🟢 -1.03 kB 🟢 -467 B 🟢 -397 B
assets/nodeTypes-WuA4ox_f.js (new) 1.03 kB 🔴 +1.03 kB 🔴 +466 B 🔴 +393 B
assets/cloudSessionCookie-BEBZkCER.js (removed) 991 B 🟢 -991 B 🟢 -467 B 🟢 -425 B
assets/cloudSessionCookie-CJwkiTdL.js (new) 991 B 🔴 +991 B 🔴 +467 B 🔴 +422 B
assets/cloudBadges-B1LByM70.js (new) 973 B 🔴 +973 B 🔴 +553 B 🔴 +495 B
assets/cloudBadges-CcdbwN4P.js (removed) 973 B 🟢 -973 B 🟢 -552 B 🟢 -501 B
assets/ComfyOrgHeader-BkvFD7HJ.js (new) 960 B 🔴 +960 B 🔴 +528 B 🔴 +460 B
assets/ComfyOrgHeader-DPS2o_ns.js (removed) 960 B 🟢 -960 B 🟢 -527 B 🟢 -459 B
assets/load3dSerialize-DayL4Ps5.js (removed) 885 B 🟢 -885 B 🟢 -424 B 🟢 -363 B
assets/load3dSerialize-DpM-5VnJ.js (new) 885 B 🔴 +885 B 🔴 +425 B 🔴 +359 B
assets/WebGLViewport-CcXwBN0H.js (new) 842 B 🔴 +842 B 🔴 +415 B 🔴 +337 B
assets/WebGLViewport-Dfw4EZck.js (removed) 842 B 🟢 -842 B 🟢 -416 B 🟢 -339 B
assets/Load3DAdvanced-DXbu4AcT.js (new) 813 B 🔴 +813 B 🔴 +455 B 🔴 +414 B
assets/Load3DAdvanced-tFzEACot.js (removed) 813 B 🟢 -813 B 🟢 -454 B 🟢 -409 B
assets/nightlyBadges-B9MLPv_Y.js (new) 464 B 🔴 +464 B 🔴 +309 B 🔴 +255 B
assets/nightlyBadges-BMUTUF9S.js (removed) 464 B 🟢 -464 B 🟢 -307 B 🟢 -254 B
assets/src-ByXWsKdX.js (removed) 446 B 🟢 -446 B 🟢 -320 B 🟢 -269 B
assets/src-D92NdP8i.js (new) 446 B 🔴 +446 B 🔴 +318 B 🔴 +268 B
assets/cloud-subscription-7D5pDaJD.js (new) 279 B 🔴 +279 B 🔴 +184 B 🔴 +149 B
assets/cloud-subscription-DVUGKl65.js (removed) 279 B 🟢 -279 B 🟢 -186 B 🟢 -152 B
assets/comfy-logo-single-BlZiOEc2.js (new) 272 B 🔴 +272 B 🔴 +186 B 🔴 +149 B
assets/comfy-logo-single-DynPvHhk.js (removed) 272 B 🟢 -272 B 🟢 -185 B 🟢 -152 B
assets/missingModelDownload-BaNyVPju.js (new) 228 B 🔴 +228 B 🔴 +150 B 🔴 +129 B
assets/missingModelDownload-fbFr19ES.js (removed) 228 B 🟢 -228 B 🟢 -148 B 🟢 -129 B
assets/SubscriptionPanelContentWorkspace-AqCkutwi.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -93 B
assets/SubscriptionPanelContentWorkspace-CtSXIWxF.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +92 B
assets/Load3dViewerContent-Cb2uEit2.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +90 B
assets/Load3dViewerContent-snXlxd3k.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -106 B
assets/WidgetBoundingBox-CCbNShfm.js (new) 131 B 🔴 +131 B 🔴 +100 B 🔴 +92 B
assets/WidgetBoundingBox-TMFQ_hbX.js (removed) 131 B 🟢 -131 B 🟢 -100 B 🟢 -91 B
assets/Load3DAdvanced-D-3M8cpa.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -90 B
assets/Load3DAdvanced-DE0sMqLT.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +92 B
assets/WidgetLegacy-B0D_ZByQ.js (removed) 119 B 🟢 -119 B 🟢 -108 B 🟢 -94 B
assets/WidgetLegacy-bwVbOBNc.js (new) 119 B 🔴 +119 B 🔴 +108 B 🔴 +109 B
assets/workflowDraftStoreV2-BauLYLYG.js (new) 113 B 🔴 +113 B 🔴 +105 B 🔴 +117 B
assets/workflowDraftStoreV2-CEyn7dsv.js (removed) 113 B 🟢 -113 B 🟢 -105 B 🟢 -117 B
assets/Load3D-DslDrS5C.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -84 B
assets/Load3D-DYkVJ5VU.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +93 B
assets/i18n-BQm7KIyU.js (new) 97 B 🔴 +97 B 🔴 +92 B 🔴 +86 B
assets/i18n-wGHO7fW5.js (removed) 97 B 🟢 -97 B 🟢 -92 B 🟢 -87 B
assets/module-DtK8IRNl.js (new) 95 B 🔴 +95 B 🔴 +102 B 🔴 +90 B
assets/changeTracker-C7LM7-Cm.js (new) 93 B 🔴 +93 B 🔴 +95 B 🔴 +82 B
assets/changeTracker-Nu0VaN4q.js (removed) 93 B 🟢 -93 B 🟢 -95 B 🟢 -81 B

Status: 154 added / 152 removed / 13 unchanged

⚡ Performance

⏳ Performance tests in progress…

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Cloud-only in-app AI Agent panel with feature gating, REST/WebSocket contracts, session and store orchestration, message rendering, theming, telemetry, and browser coverage.

Changes

In-App Agent Panel

Layer / File(s) Summary
Dependencies and theme
package.json, pnpm-workspace.yaml, src/assets/css/style.css, src/workbench/extensions/agent/agentTheme.css, src/locales/en/main.json, src/workbench/extensions/agent/README.md
Adds shiki, agent theme tokens/animations, stylesheet import ordering, locale strings, and panel README content.
Extension registration and feature gate
src/extensions/core/index.ts, src/extensions/core/agentPanel.ts, src/extensions/core/agentPanel.test.ts, src/workbench/extensions/agent/composables/agent/useAgentFeatureGate.ts, src/workbench/extensions/agent/composables/agent/useAgentFeatureGate.test.ts
Registers the Cloud-only sidebar tab and gates it through a PostHog-backed feature flag source.
API schemas, fixtures, and markdown sanitization
src/workbench/extensions/agent/schemas/agentApiSchema.ts, src/workbench/extensions/agent/schemas/agentApiSchema.test.ts, src/workbench/extensions/agent/schemas/__fixtures__/agent/*.jsonl, src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.ts, src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.test.ts
Defines REST/WS schemas, validates fixture payloads, and adds sanitized markdown rendering.
REST client, event source, and event transport
src/workbench/extensions/agent/services/agent/*.ts, src/workbench/extensions/agent/services/agent/*.test.ts
Implements the REST client, reconnecting WebSocket adapter, event-to-message transport, assistant message parts, and transcript builder.
Draft, conversation, and chat history stores
src/workbench/extensions/agent/stores/agent/*.ts, src/workbench/extensions/agent/stores/agent/*.test.ts
Adds Pinia stores for draft reconciliation, turn-based conversation state, and chat history grouping.
Session composition root and draft canvas apply
src/workbench/extensions/agent/composables/agent/useAgentSession.ts, src/workbench/extensions/agent/composables/agent/useAgentSession.test.ts, src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.ts, src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.test.ts
Orchestrates sending, cancellation, resync, WS ingestion, and canvas draft application.
Composer, attachment, canvas, and onboarding composables
src/workbench/extensions/agent/composables/agent/useComposer.ts, src/workbench/extensions/agent/composables/agent/useComposer.test.ts, src/workbench/extensions/agent/composables/agent/useAttachment.ts, src/workbench/extensions/agent/composables/agent/useAttachment.test.ts, src/workbench/extensions/agent/composables/agent/useCanvasContext.ts, src/workbench/extensions/agent/composables/agent/useCanvasSelection.ts, src/workbench/extensions/agent/composables/agent/useCloudAssets.ts, src/workbench/extensions/agent/composables/agent/useOnboarding.ts, src/workbench/extensions/agent/composables/agent/useOnboarding.test.ts, src/workbench/extensions/agent/composables/agent/useCanvasSelection.test.ts, src/workbench/extensions/agent/components/agent/composer/*.vue, src/workbench/extensions/agent/components/agent/m4HostPieces.test.ts
Adds supporting composables and small host-facing composer/canvas helpers.
Reusable UI primitives
src/workbench/extensions/agent/components/ui/*.vue, src/workbench/extensions/agent/components/ui/uiPrimitives.test.ts
Adds the shared button, avatar, dialog, dropdown, scroll area, textarea, and collapsible primitives.
Message rendering components
src/workbench/extensions/agent/components/agent/message/*.vue, src/workbench/extensions/agent/components/agent/message/*.test.ts
Renders assistant/user messages, code blocks, markdown, reasoning, tool calls, feedback, thinking status, and assets.
Safety UI
src/workbench/extensions/agent/components/agent/safety/*.vue, src/workbench/extensions/agent/components/agent/safety/*.test.ts
Adds shelved approval, lock, conflict, and revert UI surfaces.
Panel shell and root component
src/workbench/extensions/agent/components/agent/*.vue, src/workbench/extensions/agent/AgentPanelRoot.vue, src/workbench/extensions/agent/AgentPanelRoot.test.ts, browser_tests/tests/agent/*, src/platform/telemetry/*
Composes the panel UI, wires session/stores/composables, adds telemetry, and covers the full flow in browser tests.

Estimated code review effort: 5 (Critical) | ~150 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
End-To-End Regression Coverage For Fixes ✅ Passed PR includes browser_tests/ Playwright coverage, and the description/docs do not say E2E regression tests were omitted.
Adr Compliance For Entity/Litegraph Changes ✅ Passed No changed files touch src/lib/litegraph/, src/ecs/, or graph-entity paths, so ADR 0003/0008 checks are not applicable.
Title check ✅ Passed The title clearly summarizes the main change: an in-app agent side panel gated by the agent-in-app-experience flag.
Description check ✅ Passed The description covers summary, changes, review focus, screenshots, and rollout details, though it does not use the template's exact Changes bullets.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nathaniel/fe-1187-agent-side-panel-fe-implementation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.31387% with 119 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/components/LiteGraphCanvasSplitterOverlay.vue 0.00% 43 Missing and 3 partials ⚠️
src/platform/telemetry/TelemetryRegistry.ts 0.00% 19 Missing ⚠️
...emetry/providers/cloud/PostHogTelemetryProvider.ts 10.00% 18 Missing ⚠️
src/workbench/extensions/agent/AgentPanelRoot.vue 97.22% 7 Missing ⚠️
...ensions/agent/composables/agent/useAgentSession.ts 96.36% 6 Missing ⚠️
src/components/graph/GraphCanvas.vue 0.00% 5 Missing ⚠️
...sions/agent/components/agent/ChatHistoryScreen.vue 82.14% 4 Missing and 1 partial ⚠️
...h/extensions/agent/stores/agent/agentPanelStore.ts 85.18% 4 Missing ⚠️
...h/extensions/agent/components/agent/AgentPanel.vue 94.33% 3 Missing ⚠️
...nch/extensions/agent/components/agent/Composer.vue 96.00% 1 Missing and 1 partial ⚠️
... and 4 more
@@            Coverage Diff             @@
##             main   #13472      +/-   ##
==========================================
+ Coverage   77.92%   78.08%   +0.16%     
==========================================
  Files        1648     1692      +44     
  Lines       97376   100386    +3010     
  Branches    34059    35069    +1010     
==========================================
+ Hits        75876    78386    +2510     
- Misses      20788    21266     +478     
- Partials      712      734      +22     
Flag Coverage Δ
unit 66.51% <91.31%> (+0.88%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...components/rightSidePanel/errors/useErrorGroups.ts 97.28% <100.00%> (+1.63%) ⬆️
src/components/topbar/WorkflowTabs.vue 85.71% <100.00%> (+2.80%) ⬆️
src/extensions/core/agentPanel.ts 100.00% <100.00%> (ø)
src/platform/errorCatalog/promptErrorResolver.ts 100.00% <ø> (ø)
src/platform/telemetry/types.ts 100.00% <ø> (ø)
...tensions/agent/components/agent/ActiveTabStrip.vue 100.00% <100.00%> (ø)
...nsions/agent/components/agent/ConversationView.vue 100.00% <100.00%> (ø)
...ensions/agent/components/agent/OnboardingCoach.vue 100.00% <100.00%> (ø)
.../extensions/agent/components/agent/PanelHeader.vue 100.00% <100.00%> (ø)
...ns/agent/components/agent/message/AgentMessage.vue 100.00% <100.00%> (ø)
... and 34 more

... and 79 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Review fixes from the four-hat panel, each independently specified:

- the event source now follows the host socket across reconnects:
  createReconnectingEventSource rebinds message and open/close listeners
  to the fresh api.socket on the host reconnected event, reports live on
  an already-open rebind, warns once on a null socket and attaches on
  the first reconnect; AgentPanelRoot uses it in place of the
  instance-bound adapter (the panel no longer goes deaf after a routine
  /ws reconnect)
- the fail-closed flag gate in the extension entry gains a four-case
  test suite modeled on the previewAny sibling (no register while the
  flag is unknown, register once on true, unregister on flip-off, no
  double-register across toggles)
- session notices forward to the host toast store (new-entries-only
  watch), making cancel failures and malformed-event warnings visible;
  covered by a mount test driving a malformed frame through a fake
  socket
- the five staged M4 surfaces (tab context, attachments, canvas
  selection) carry explicit STAGED markers and the subtree gains a
  README recording them plus the intentional local ui-primitives
  decision
- onboarding coach copy moves to i18n keys; the storage key and root id
  drop their dev-harness names (Comfy.AgentPanel.onboarded,
  agent-panel-root)
- the composer paperclip hides behind a default-false canAttach prop
  until an attach flow is wired

The workflowId provider (panel-to-draft binding) is intentionally NOT
wired: no host surface exposes the server-side workflow uuid (the
workflow class is path-keyed; the uuid appears only in the agent's own
202 ack and per-job queue fields). Recorded as an open product/plumbing
decision.

Typecheck clean, full suite 12561 passed, oxlint and eslint clean, no
new knip findings from these files.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 25

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 38-46: The AgentPanelRoot.vue event source is binding to the
initial api.socket instance, so a reconnect that swaps api.socket can leave the
panel deaf to agent_* events. Update the setup in AgentPanelRoot.vue so events
is recreated or otherwise kept in sync when the socket changes, using
createWebSocketEventSource and the api.socket binding path. If this behavior is
not being fixed now, ensure FE-1187 is explicitly confirmed/accepted before
broad rollout and leave the TODO tied to the relevant
AgentEventSource/api.socket logic.
- Around line 53-58: The draft-to-canvas apply flow in useDraftCanvasApply
currently has no failure handling, so errors from validateComfyWorkflow or
app.loadGraphData can become unhandled rejections. Update the async callback in
AgentPanelRoot to wrap the validateComfyWorkflow/app.loadGraphData sequence in
explicit try/catch, and add logging and/or user-facing failure handling in the
catch path so apply failures are surfaced instead of silently dropping the
draft.
- Around line 42-45: The event source initialization in AgentPanelRoot.vue mixes
a side effect into a ternary via the comma operator, which should be refactored
for clarity. Update the logic around the events/AgentEventSource setup to use an
explicit if/else so the websocket path and the fallback subscription stub are
assigned separately, and keep the console.warn call only in the fallback branch.
- Around line 69-75: The onboarding copy in AgentPanelRoot.vue is hardcoded
English and should be localized via vue-i18n. Update the coach step definition
in coachSteps to read the title and body from translation keys instead of
literals, and add those keys to src/locales/en/main.json. Keep the target
behavior the same while ensuring the user-facing strings for the “Meet the
agent” step are sourced through i18n.

In `@src/workbench/extensions/agent/components/agent/Composer.test.ts`:
- Around line 9-11: The test helper mount currently accepts overly broad props,
which weakens type safety at call sites. Update mount in Composer.test.ts to use
a precise props type based on Partial<ComponentProps<typeof Composer>> instead
of Record<string, unknown>, and keep the render(Composer, { props, global: {
plugins: [i18n] } }) usage unchanged. Use the Composer component and the mount
helper signature as the main symbols to locate and adjust the typing.

In `@src/workbench/extensions/agent/components/agent/m4HostPieces.test.ts`:
- Around line 33-41: The ActiveTabStrip test currently rerenders with tab set to
null but never verifies the empty state, so the “nothing when there is no tab”
behavior is untested. Update the ActiveTabStrip spec to add an assertion after
rerendering with tab: null, using the existing render/rerender and screen usage
in m4HostPieces.test.ts to confirm no tab text is shown or that the component
renders nothing for the null case.

In `@src/workbench/extensions/agent/components/agent/message/AgentMessage.vue`:
- Line 3: The `AgentMessage` component imports and uses `useI18n` only to
provide `t` for the template, so simplify the script by removing the `useI18n`
import and any `t` setup in the component’s script section. Update the template
to call the built-in `$t` directly wherever `t` is currently used, keeping the
localization behavior unchanged while eliminating the unnecessary script-side
i18n wiring.

In `@src/workbench/extensions/agent/components/agent/message/CodeBlock.vue`:
- Around line 18-19: The highlighted HTML is being passed to v-html without an
actual sanitization step, so update CodeBlock.vue to run shiki output through
DOMPurify before injection. Locate the fallback/highlighting flow that produces
the HTML string used by v-html, and sanitize both the shiki-rendered markup and
any other HTML path in this component (including the areas referenced by the
comment) before assigning or rendering it.
- Around line 20-40: The async highlight logic in CodeBlock.vue can let an older
codeToHtml result overwrite a newer one when code or lang changes rapidly.
Update the watch callback to invalidate stale async work by adding a
generation/token or watcher cleanup guard around the highlighted assignment in
the watch on [code, lang], so only the latest invocation can set
highlighted.value. Keep the lazy shiki import and current error handling, but
ensure any out-of-order resolution is ignored before writing the HTML.

In `@src/workbench/extensions/agent/components/agent/message/Lightbox.vue`:
- Around line 22-29: Update the video element in Lightbox.vue so autoplay works
reliably by adding muted and playsinline alongside the existing autoplay, loop,
and controls attributes on the <video> used for isVideo/url. This change should
be made in the Lightbox component’s video tag so browsers allow autoplay and iOS
Safari can play inline instead of forcing manual playback.

In `@src/workbench/extensions/agent/components/agent/message/UserMessage.vue`:
- Around line 15-22: The initials logic in UserMessage.vue uses name ??
t('agent.you'), which only falls back for null or undefined and lets empty
strings produce blank initials. Update the computed initials in the initials
declaration to treat empty-string names as missing, so it falls back to the
localized agent.you label before splitting and deriving initials.

In `@src/workbench/extensions/agent/components/agent/OnboardingCoach.vue`:
- Around line 56-75: The onboarding coach overlay in OnboardingCoach.vue needs
proper dialog accessibility handling. Add dialog semantics to the root
overlay/card (for example, role and aria-modal) and make the coach content
focusable when it opens. Implement focus trapping within the coach, restore
focus on close, and wire an Escape key handler to call skip so keyboard and
screen-reader users cannot tab into hidden content behind the backdrop.
- Around line 25-53: The onboarding coach positioning in OnboardingCoach.vue
uses a hard-coded CARD_H, so long step copy can still push the card off-screen.
Update the watchEffect positioning logic to use the card’s actual rendered
height instead of the fixed constant, and add a template ref on the positioned
card element so the code can measure it before setting cardStyle. Keep the
existing clamping behavior in sync with the measured size when computing the
top/left for currentStep.

In `@src/workbench/extensions/agent/components/agent/safety/ApprovalCard.vue`:
- Around line 30-41: The ApprovalCard component can emit answer twice on a rapid
double-click because both Buttons remain enabled while card.status is still
open. In ApprovalCard.vue, add a local “pending”/locked state around the
existing emit('answer', card.approvalId, ...) handlers so the first click
immediately disables both approve and deny actions until the parent updates
card.status away from open. Keep the fix scoped to the ApprovalCard
template/logic and use the existing card.status and emit flow to clear the lock
when the prop changes.

In `@src/workbench/extensions/agent/composables/agent/useAttachment.ts`:
- Around line 32-59: The addFiles flow in useAttachment is toggling
pending.value inside the per-file loop, causing the upload state to drop between
uploads in a multi-file batch. Move the pending state management so it stays
true for the entire addFiles() batch and is cleared only once after all files
have been processed, while preserving the existing upload/error handling and
staged results behavior in options.upload and options.onError.

In `@src/workbench/extensions/agent/composables/agent/useCloudAssets.ts`:
- Around line 20-34: The deduplication logic in load() currently uses a manual
Set-based loop, but this should follow the project guideline to use es-toolkit
utilities. Update the asset deduping in useCloudAssets.ts to replace the
explicit seen/deduped iteration with uniqBy on asset.id, then keep the existing
max slicing and loading state handling intact.

In `@src/workbench/extensions/agent/schemas/agentApiSchema.ts`:
- Around line 41-49: The zAgentMessage schema is stricter than the other agent
schemas and will reject additive server fields during getMessages parsing.
Update zAgentMessage to tolerate unknown properties the same way
zAgentTurnAccepted and the WS event schemas do by adding passthrough behavior
while keeping the existing validated fields intact. Use the zAgentMessage and
zAgentMessages schema definitions in agentApiSchema.ts as the place to make the
change.

In `@src/workbench/extensions/agent/services/agent/agentEventTransport.test.ts`:
- Around line 93-148: The replay coverage in agentEventTransport.test only
exercises ws-turn-edit and ws-turn-cancelled, leaving the remaining ws-*.jsonl
fixtures unverified. Add new test cases in agentEventTransport.test using
chatEventsFor and drive for ws-turn-denied-run.jsonl (and ws-turn-ask-run.jsonl
if applicable), and assert the distinct outcomes on the resulting message via
textParts, toolParts, parts, and token/streaming flags so the new fixture paths
in createAgentEventTransport are covered.
- Around line 196-231: Add a regression test in the agentEventTransport
settle-lifecycle suite for ingesting events after the transport has already been
settled. In the agentEventTransport tests, create a transport, call
finalize(null) or abort(), then call ingest(...) and assert it is a no-op by
verifying no additional emissions and no message state changes. Reference the
agentEventTransport() instance methods ingest(), finalize(), and abort() so the
missing settled guard is covered.

In `@src/workbench/extensions/agent/services/agent/agentRestClient.ts`:
- Around line 105-113: The agent REST request helper currently forwards init
directly through request() to fetchImpl, so stalled calls can hang indefinitely.
Update request() in agentRestClient.ts to enforce a timeout or accept and honor
a caller-provided AbortSignal, and make sure the agent session send/resync path
threads that signal through from the session boundary. Use the request() helper
and any session-layer caller that invokes it as the main places to wire in the
cancellation behavior.

In `@src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.test.ts`:
- Around line 1-42: Add tests covering the `useAgentChatHistoryStore` actions
(`upsert`, `remove`, `setActive`) so the store behavior is exercised directly,
including `remove` clearing `activeId` when the active session is deleted. Also
add a DST-boundary test for `groupSessionsByRecency`/`startYesterday` using a
date near a daylight-saving transition to verify the guard works as intended.

In `@src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.ts`:
- Around line 58-60: The computed `grouped` in `agentChatHistoryStore.ts` uses
`Date.now()` directly, so it only recomputes when `sessions` or `activeId`
change and won’t update at midnight. Replace the non-reactive time read in
`computed(() => groupSessionsByRecency(...))` with a reactive clock from VueUse,
such as `useNow()` or `useTimestamp()`, and use that reactive value when calling
`groupSessionsByRecency` so the recency buckets refresh automatically over time.
- Around line 29-52: Refactor groupSessionsByRecency in agentChatHistoryStore to
use es-toolkit’s groupBy from es-toolkit/array instead of the manual
if/else/push bucketing loop. Keep the existing recency precedence based on
activeId, startToday, and startYesterday by sorting into the same
current/today/yesterday/earlier keys, then default any missing buckets with ??
[] when building the returned HistoryGroups object.

In `@src/workbench/extensions/agent/stores/agent/agentDraftStore.ts`:
- Around line 19-21: The public draft state in agentDraftStore is currently
exposed as mutable refs, so consumers can bypass the store’s update methods.
Update the store export to wrap workflowId, content, and version with readonly()
in the agentDraftStore implementation, while keeping all mutations confined to
bind, applyPatch, adoptSnapshot, and reset. Use the existing ref declarations in
the store to locate the fields that need to be made read-only.

In `@src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.ts`:
- Around line 1-22: The link-rewrite hook in renderMarkdownToHtml mutates the
shared DOMPurify singleton, so every sanitize call across the app inherits this
behavior. Fix it by avoiding DOMPurify.addHook at module load; instead, use a
local DOMPurify instance inside renderMarkdownToHtml or apply the target and rel
attributes after sanitizing the marked.parse output, keeping the change scoped
to this renderer.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3afacd9a-ddc9-4d69-9170-de3b80ce7919

📥 Commits

Reviewing files that changed from the base of the PR and between 854770d and 083cb95.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (89)
  • package.json
  • pnpm-workspace.yaml
  • src/assets/css/style.css
  • src/extensions/core/agentPanel.ts
  • src/extensions/core/index.ts
  • src/locales/en/main.json
  • src/workbench/extensions/agent/AgentPanelRoot.vue
  • src/workbench/extensions/agent/agentTheme.css
  • src/workbench/extensions/agent/components/agent/ActiveTabStrip.vue
  • src/workbench/extensions/agent/components/agent/AgentPanel.vue
  • src/workbench/extensions/agent/components/agent/ChatHistoryDrawer.vue
  • src/workbench/extensions/agent/components/agent/Composer.test.ts
  • src/workbench/extensions/agent/components/agent/Composer.vue
  • src/workbench/extensions/agent/components/agent/ConversationView.test.ts
  • src/workbench/extensions/agent/components/agent/ConversationView.vue
  • src/workbench/extensions/agent/components/agent/EmptyState.vue
  • src/workbench/extensions/agent/components/agent/OnboardingCoach.vue
  • src/workbench/extensions/agent/components/agent/PanelHeader.vue
  • src/workbench/extensions/agent/components/agent/StartingPointModal.vue
  • src/workbench/extensions/agent/components/agent/composer/AssetTray.vue
  • src/workbench/extensions/agent/components/agent/composer/AttachmentChip.vue
  • src/workbench/extensions/agent/components/agent/composer/SelectionActionChips.vue
  • src/workbench/extensions/agent/components/agent/composer/SuggestedPromptChip.vue
  • src/workbench/extensions/agent/components/agent/m4HostPieces.test.ts
  • src/workbench/extensions/agent/components/agent/message/AgentMessage.vue
  • src/workbench/extensions/agent/components/agent/message/AssetCard.vue
  • src/workbench/extensions/agent/components/agent/message/AssetGrid.vue
  • src/workbench/extensions/agent/components/agent/message/CodeBlock.vue
  • src/workbench/extensions/agent/components/agent/message/Lightbox.vue
  • src/workbench/extensions/agent/components/agent/message/MarkdownStream.vue
  • src/workbench/extensions/agent/components/agent/message/MessageFeedback.vue
  • src/workbench/extensions/agent/components/agent/message/ReasoningDisclosure.vue
  • src/workbench/extensions/agent/components/agent/message/ThinkingStatus.vue
  • src/workbench/extensions/agent/components/agent/message/ToolCallCard.vue
  • src/workbench/extensions/agent/components/agent/message/ToolCallGroup.vue
  • src/workbench/extensions/agent/components/agent/message/UserMessage.vue
  • src/workbench/extensions/agent/components/agent/safety/ApprovalCard.test.ts
  • src/workbench/extensions/agent/components/agent/safety/ApprovalCard.vue
  • src/workbench/extensions/agent/components/agent/safety/ConflictDialog.vue
  • src/workbench/extensions/agent/components/agent/safety/LockBanner.vue
  • src/workbench/extensions/agent/components/agent/safety/RevertButton.vue
  • src/workbench/extensions/agent/components/agent/safety/safetyTypes.ts
  • src/workbench/extensions/agent/components/ui/Avatar.vue
  • src/workbench/extensions/agent/components/ui/Button.vue
  • src/workbench/extensions/agent/components/ui/CollapsibleContent.vue
  • src/workbench/extensions/agent/components/ui/DialogContent.vue
  • src/workbench/extensions/agent/components/ui/DropdownMenuContent.vue
  • src/workbench/extensions/agent/components/ui/DropdownMenuItem.vue
  • src/workbench/extensions/agent/components/ui/ScrollArea.vue
  • src/workbench/extensions/agent/components/ui/Textarea.vue
  • src/workbench/extensions/agent/components/ui/uiPrimitives.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentFeatureGate.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentFeatureGate.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.ts
  • src/workbench/extensions/agent/composables/agent/useAttachment.test.ts
  • src/workbench/extensions/agent/composables/agent/useAttachment.ts
  • src/workbench/extensions/agent/composables/agent/useCanvasContext.ts
  • src/workbench/extensions/agent/composables/agent/useCanvasSelection.test.ts
  • src/workbench/extensions/agent/composables/agent/useCanvasSelection.ts
  • src/workbench/extensions/agent/composables/agent/useCloudAssets.ts
  • src/workbench/extensions/agent/composables/agent/useComposer.ts
  • src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.test.ts
  • src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.ts
  • src/workbench/extensions/agent/composables/agent/useOnboarding.test.ts
  • src/workbench/extensions/agent/composables/agent/useOnboarding.ts
  • src/workbench/extensions/agent/schemas/__fixtures__/agent/rest-responses.jsonl
  • src/workbench/extensions/agent/schemas/__fixtures__/agent/ws-turn-ask-run.jsonl
  • src/workbench/extensions/agent/schemas/__fixtures__/agent/ws-turn-cancelled.jsonl
  • src/workbench/extensions/agent/schemas/__fixtures__/agent/ws-turn-denied-run.jsonl
  • src/workbench/extensions/agent/schemas/__fixtures__/agent/ws-turn-edit.jsonl
  • src/workbench/extensions/agent/schemas/agentApiSchema.test.ts
  • src/workbench/extensions/agent/schemas/agentApiSchema.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.test.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.ts
  • src/workbench/extensions/agent/services/agent/agentEventTransport.test.ts
  • src/workbench/extensions/agent/services/agent/agentEventTransport.ts
  • src/workbench/extensions/agent/services/agent/agentMessageParts.ts
  • src/workbench/extensions/agent/services/agent/agentRestClient.test.ts
  • src/workbench/extensions/agent/services/agent/agentRestClient.ts
  • src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.test.ts
  • src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.ts
  • src/workbench/extensions/agent/stores/agent/agentConversationEntries.test.ts
  • src/workbench/extensions/agent/stores/agent/agentConversationStore.test.ts
  • src/workbench/extensions/agent/stores/agent/agentConversationStore.ts
  • src/workbench/extensions/agent/stores/agent/agentDraftStore.test.ts
  • src/workbench/extensions/agent/stores/agent/agentDraftStore.ts
  • src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.test.ts
  • src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.ts

Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue Outdated
Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue Outdated
Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue Outdated
Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue Outdated
Comment thread src/workbench/extensions/agent/components/agent/Composer.test.ts Outdated
Comment thread src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.test.ts Outdated
Comment thread src/workbench/extensions/agent/stores/agent/agentDraftStore.ts
Comment thread src/workbench/extensions/agent/utils/agent/renderMarkdownToHtml.ts Outdated
Acceptance items from the approved In-App Agent design doc, plus PM-98
and the coverage-audit gaps:

- suggested prompts carry the five exact approved labels
- an Ask Comfy Agent top-bar button registers next to the feedback
  button, present only while the flag gate has the tab registered (same
  fail-closed source, reactive mirror ref); click toggles the sidebar
  tab
- attach is wired end-to-end: paperclip opens a picker (image/video),
  files upload through rest.uploadImage via useAttachment (20MB guard,
  failure does not stage), staged chips carry the server ref into the
  message attachments; the STAGED marker drops from useAttachment
- drafts bind to a session workflow: agentWorkflowBinding mints a
  server workflow (single-flight POST /api/workflows with the current
  canvas graph, tolerant id parse, degrade-to-unbound on any failure)
  and the root awaits ensure() before the first send so messages carry
  workflow_id and draft_patch events resolve against a bound draft; the
  FE has no host uuid surface today (path-keyed workflow classes,
  /api/workflows unused in src), so the binding mirrors the backend's
  own flow with a TODO to adopt the host id when one exists
- a muted composer caption states the agent-writes/user-runs contract
  (copy pending design sign-off, one-line locale swap)
- a scroll-to-latest pill floats over the conversation when scrolled up
- history copy-as-markdown works for the active conversation via a pure
  transcript builder; other sessions toast the V0 limitation
- message ratings capture app:agent_message_feedback through a typed
  telemetry method (types, registry dispatch, PostHog implementation),
  null vote forwarded as a retraction for the eval pipeline
- coverage gaps closed: DST-boundary recency bucketing, history store
  upsert/remove/setActive behaviors, stopTurn network-error notice,
  direct useComposer suite; the session error counter moves off module
  scope into the instance; the dead null-tab rerender line becomes a
  real assertion

Typecheck clean, full suite 12588 passed, oxlint, eslint, and knip
green on these files. 27 tests added.
Three @cloud Playwright scenarios in browser_tests/tests/agent, using
the comfyPageFixture + webSocketFixture merge and typed mocks copied
from the live-captured wire fixtures:

- fail-closed flag gate: no sidebar tab or top-bar button without the
  PostHog flag; both appear with it (flag seeded via
  posthog_config.bootstrap.featureFlags with flags disabled-fetch, so
  the gate resolves synchronously and deterministically)
- a full streamed turn: composer submit posts the message, the 202 ack
  adopts the server message id, injected agent_thinking, tool-call,
  delta, and done frames render thinking, tool cards, and markdown
  (bold asserted as rendered strong)
- the draft loop: the first send mints the session workflow (mocked
  POST /api/workflows), the bound draft_patch applies through
  validateComfyWorkflow into the canvas, asserted by node count via
  window.app.graph

The spec sends before pushing draft frames because the draft store
drops patches for an unbound workflow id, matching the binding order in
AgentPanelRoot. Draft content is a minimal schema-valid v0.4 graph
(the raw captured draft omits the top-level version field the validator
requires first).

Runs in the cloud project only (the extension is tree-shaken from
non-cloud builds); listed 3/3 there and 0 in chromium. Browser
typecheck, eslint, and format clean.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/workbench/extensions/agent/composables/agent/useAgentSession.ts (1)

117-167: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Guard sendMessage() against newChat() resets.
If newChat() runs while the POST is in flight, stopTurn() can no-op because activeTurnId is still null. When the ack returns, sendMessage() still writes threadIdRef and records the turn into the reset store, bringing the old message back into the new chat. Add an epoch/generation check before applying the ack.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/composables/agent/useAgentSession.ts` around
lines 117 - 167, sendMessage() is still applying a late POST ack after
newChat()/reset can clear the store, which lets an old turn reappear in a fresh
chat. Add a request epoch/generation guard in useAgentSession’s sendMessage
flow: capture the current session/generation before rest.postMessage, and after
the await only update threadIdRef, recordUser, and startTurn if the generation
still matches. If it changed, ignore the ack and avoid mutating the reset
conversationStore.
♻️ Duplicate comments (1)
src/workbench/extensions/agent/AgentPanelRoot.vue (1)

96-104: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Draft-to-canvas apply pipeline still has no error handling.

This block was flagged in an earlier review round for the exact same gap and remains unchanged: if validateComfyWorkflow throws or app.loadGraphData rejects, the failure becomes an unhandled promise rejection with no logging or user feedback — the draft silently fails to apply. This is explicitly called out as the PR's review focus for the draft pipeline.

🛡️ Proposed fix
 useDraftCanvasApply((content) => {
   void (async () => {
-    const workflow = await validateComfyWorkflow(content)
-    if (workflow) await app.loadGraphData(workflow)
+    try {
+      const workflow = await validateComfyWorkflow(content)
+      if (workflow) await app.loadGraphData(workflow)
+    } catch (error) {
+      console.error('[agent-panel] failed to apply draft to canvas', error)
+      toast.add({ severity: 'error', summary: t('agent.draftApplyFailed') })
+    }
+  })()
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/AgentPanelRoot.vue` around lines 96 - 104, The
draft-to-canvas apply flow in useDraftCanvasApply currently has no failure
handling, so errors from validateComfyWorkflow or app.loadGraphData can become
unhandled rejections. Wrap the async body in AgentPanelRoot.vue with explicit
error handling, and use the existing workflow-apply path to log/report the
failure so the user gets feedback when the draft cannot be applied.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@browser_tests/tests/agent/agentPanelMocks.ts`:
- Around line 178-247: The generic boot mock payloads in mockAgentBoot are
untyped ad-hoc objects, so response-shape drift for routes like /api/users,
/api/settings, /api/workspaces, and similar won’t be caught at compile time.
Tighten these fulfill calls by introducing or reusing explicit response types
for the boot mocks, keeping jsonRoute for already typed agent payloads and
wiring the surrounding route handlers to those typed shapes so the mock contract
stays aligned with the real API.

In `@src/workbench/extensions/agent/components/agent/ConversationView.test.ts`:
- Around line 152-153: The test setup in ConversationView.test.ts is mutating
Element.prototype.scrollIntoView directly, which bypasses Vitest cleanup.
Replace the direct prototype assignment with vi.spyOn on
Element.prototype.scrollIntoView so the mock is tracked and restored by the
existing vi.restoreAllMocks calls in this suite. Keep the change localized to
the scrollIntoView setup used by the ConversationView tests.

In `@src/workbench/extensions/agent/components/agent/ConversationView.vue`:
- Around line 36-44: The watch in ConversationView.vue is deep-watching the
entire entries array, which makes each streaming token update re-traverse the
full conversation tree. Update the watcher around entries/scrollToLatest to use
a narrower dependency instead of { deep: true }, such as a cheap signal derived
from entries.length and the last entry’s text, so only the changed message
drives auto-scroll updates.

In `@src/workbench/extensions/agent/composables/agent/useAttachment.test.ts`:
- Around line 45-54: Add a mixed-batch test in useAttachment.test.ts for
useAttachment/addFiles that passes both a successful file and a failing file in
one call, so the existing single-file failure case is complemented by the
“already-staged files are not lost” behavior. Verify that the good file is still
included in the staged result, that the rejected upload still triggers onError,
and that addFiles continues processing the batch rather than dropping previously
staged entries.

In `@src/workbench/extensions/agent/README.md`:
- Line 3: The opening line in README.md is a sentence fragment and needs a main
verb. Update the first sentence in the In-App Agent side panel description so it
reads as a complete sentence, keeping the same meaning while fixing the grammar.

In `@src/workbench/extensions/agent/services/agent/agentEventSource.ts`:
- Around line 69-131: Extract the duplicated reconnect-tracking flow in
createReconnectingEventSource into a shared helper used by both subscribe and
onStatus. Factor out the common attach/detach,
host.addEventListener('reconnected', ...) registration, and cleanup logic so the
only difference remains the socket event bindings (message vs open/close). Keep
the helper centered around the existing symbols createReconnectingEventSource,
subscribe, and onStatus so future reconnect behavior stays consistent in both
paths.

---

Outside diff comments:
In `@src/workbench/extensions/agent/composables/agent/useAgentSession.ts`:
- Around line 117-167: sendMessage() is still applying a late POST ack after
newChat()/reset can clear the store, which lets an old turn reappear in a fresh
chat. Add a request epoch/generation guard in useAgentSession’s sendMessage
flow: capture the current session/generation before rest.postMessage, and after
the await only update threadIdRef, recordUser, and startTurn if the generation
still matches. If it changed, ignore the ack and avoid mutating the reset
conversationStore.

---

Duplicate comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 96-104: The draft-to-canvas apply flow in useDraftCanvasApply
currently has no failure handling, so errors from validateComfyWorkflow or
app.loadGraphData can become unhandled rejections. Wrap the async body in
AgentPanelRoot.vue with explicit error handling, and use the existing
workflow-apply path to log/report the failure so the user gets feedback when the
draft cannot be applied.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7269e7c6-9ceb-4ebe-ac4e-be2908263730

📥 Commits

Reviewing files that changed from the base of the PR and between 083cb95 and 4a6a877.

📒 Files selected for processing (33)
  • browser_tests/tests/agent/agentPanel.spec.ts
  • browser_tests/tests/agent/agentPanelMocks.ts
  • src/extensions/core/agentPanel.test.ts
  • src/extensions/core/agentPanel.ts
  • src/locales/en/main.json
  • src/platform/telemetry/TelemetryRegistry.ts
  • src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts
  • src/platform/telemetry/types.ts
  • src/workbench/extensions/agent/AgentPanelRoot.test.ts
  • src/workbench/extensions/agent/AgentPanelRoot.vue
  • src/workbench/extensions/agent/README.md
  • src/workbench/extensions/agent/components/agent/ActiveTabStrip.vue
  • src/workbench/extensions/agent/components/agent/AgentPanel.vue
  • src/workbench/extensions/agent/components/agent/Composer.test.ts
  • src/workbench/extensions/agent/components/agent/Composer.vue
  • src/workbench/extensions/agent/components/agent/ConversationView.test.ts
  • src/workbench/extensions/agent/components/agent/ConversationView.vue
  • src/workbench/extensions/agent/components/agent/EmptyState.vue
  • src/workbench/extensions/agent/components/agent/composer/AssetTray.vue
  • src/workbench/extensions/agent/components/agent/composer/SelectionActionChips.vue
  • src/workbench/extensions/agent/components/agent/m4HostPieces.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.ts
  • src/workbench/extensions/agent/composables/agent/useAttachment.test.ts
  • src/workbench/extensions/agent/composables/agent/useCanvasSelection.ts
  • src/workbench/extensions/agent/composables/agent/useComposer.test.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.test.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.ts
  • src/workbench/extensions/agent/services/agent/agentTranscript.test.ts
  • src/workbench/extensions/agent/services/agent/agentTranscript.ts
  • src/workbench/extensions/agent/services/agent/agentWorkflowBinding.test.ts
  • src/workbench/extensions/agent/services/agent/agentWorkflowBinding.ts
  • src/workbench/extensions/agent/stores/agent/agentChatHistoryStore.test.ts
💤 Files with no reviewable changes (1)
  • src/workbench/extensions/agent/components/agent/EmptyState.vue

Comment thread browser_tests/tests/agent/agentPanelMocks.ts Outdated
Comment thread src/workbench/extensions/agent/composables/agent/useAttachment.test.ts Outdated
Comment thread src/workbench/extensions/agent/README.md Outdated
Comment thread src/workbench/extensions/agent/services/agent/agentEventSource.ts Outdated
Findings from a four-hat panel, a QA-coverage gate, and three fail-fast
gates, each fixed with its test:

- Button.vue uses the existing cva (object API) instead of the branch's
  class-variance-authority add, matching the rest of src; the root drops
  that dependency (apps/website keeps its own pre-existing use). shiki
  stays as the genuinely new dep for CodeBlock highlighting.
- copy-as-markdown now works: the active conversation registers as the
  one current history row, so the drawer is not empty mid-chat and the
  copy action has a target. Past sessions remain a documented V0 limit.
- onSend warns once via a toast when the session workflow cannot be
  minted, so the draft loop no longer fails silently while the send
  still proceeds unbound.
- the cloud e2e spec sources its suggested-prompt assertion from the
  bundled locale, so it cannot drift from the rendered prompts again.
- the thread id moves into the conversation store so it survives a
  panel remount (a sidebar toggle unmounts the panel), and the in-flight
  turn is cancelled on unmount; together these stop a reopened panel
  from splitting the transcript across two threads or leaving a turn
  billing unheard.
- remove dead surface: createWebSocketEventSource, the workflow
  binding's unused reset() and workflowName knob, an unused apply
  version parameter, four unreferenced i18n keys, and a stale comment.

Typecheck, browser typecheck, oxlint, eslint, and knip are clean; the
unit suite is 1163 passing.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/workbench/extensions/agent/AgentPanelRoot.vue (1)

96-101: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Draft-to-canvas apply still has no error handling.

If validateComfyWorkflow throws or app.loadGraphData rejects, this becomes an unhandled promise rejection with the draft silently failing to apply. This exact gap was flagged in a prior review round on these lines and does not appear to have been addressed (unlike the sibling comments on this PR, which are marked resolved).

🛡️ Proposed fix
 useDraftCanvasApply((content) => {
   void (async () => {
-    const workflow = await validateComfyWorkflow(content)
-    if (workflow) await app.loadGraphData(workflow)
+    try {
+      const workflow = await validateComfyWorkflow(content)
+      if (workflow) await app.loadGraphData(workflow)
+    } catch (error) {
+      console.error('[agent-panel] failed to apply draft to canvas', error)
+    }
   })()
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/AgentPanelRoot.vue` around lines 96 - 101, The
draft-to-canvas apply flow in AgentPanelRoot’s useDraftCanvasApply callback
still launches an unhandled async path, so wrap the
validateComfyWorkflow/app.loadGraphData sequence in proper try/catch handling
and surface failures instead of letting the promise reject silently. Update the
async callback so both validateComfyWorkflow and app.loadGraphData failures are
caught, then log or report the error through the existing panel/error handling
path used in AgentPanelRoot.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 104-111: The unmount cleanup in AgentPanelRoot.vue calls stop()
immediately after firing stopTurn(), which can unsubscribe the websocket before
the cancel flow receives agent_message_done and clears activeTurnId/streaming
state. Update the onBeforeUnmount cleanup to await the stopTurn() promise before
invoking stop(), so the turn can settle cleanly before the websocket is torn
down.

---

Duplicate comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 96-101: The draft-to-canvas apply flow in AgentPanelRoot’s
useDraftCanvasApply callback still launches an unhandled async path, so wrap the
validateComfyWorkflow/app.loadGraphData sequence in proper try/catch handling
and surface failures instead of letting the promise reject silently. Update the
async callback so both validateComfyWorkflow and app.loadGraphData failures are
caught, then log or report the error through the existing panel/error handling
path used in AgentPanelRoot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1bff3088-97a6-4428-ba69-83d0aaa6eee5

📥 Commits

Reviewing files that changed from the base of the PR and between 4a6a877 and fd83e79.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • browser_tests/tests/agent/agentPanel.spec.ts
  • package.json
  • src/locales/en/main.json
  • src/workbench/extensions/agent/AgentPanelRoot.test.ts
  • src/workbench/extensions/agent/AgentPanelRoot.vue
  • src/workbench/extensions/agent/components/agent/AgentPanel.vue
  • src/workbench/extensions/agent/components/ui/Button.vue
  • src/workbench/extensions/agent/composables/agent/useAgentSession.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.ts
  • src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.test.ts
  • src/workbench/extensions/agent/composables/agent/useDraftCanvasApply.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.test.ts
  • src/workbench/extensions/agent/services/agent/agentEventSource.ts
  • src/workbench/extensions/agent/services/agent/agentWorkflowBinding.test.ts
  • src/workbench/extensions/agent/services/agent/agentWorkflowBinding.ts
  • src/workbench/extensions/agent/stores/agent/agentConversationStore.test.ts
  • src/workbench/extensions/agent/stores/agent/agentConversationStore.ts
💤 Files with no reviewable changes (2)
  • package.json
  • src/workbench/extensions/agent/components/agent/AgentPanel.vue

Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue Outdated
The server owns the workflow: it creates one when a message opens a
thread and returns its id in the 202 ack (confirmed by the live-captured
wire fixtures, where every postMessage ack carries the same
workflow_id). The panel previously minted its own session workflow via
POST /api/workflows before the first send, which was redundant and
carried a latent bug: resuming a persisted thread would mint a fresh
workflow whose id never matches the thread's real one, so every
draft_patch would be foreign-dropped and the canvas would never update.

Now sendMessage posts without a workflow id and binds the draft store to
ack.workflow_id (bind is idempotent for an unchanged id, so re-binding
per ack never wipes an in-progress draft). The whole minting subsystem
goes away: agentWorkflowBinding and its tests, the ensure-before-send
in the root, the mint-failure toast and its i18n key, and the
/api/workflows route mock in the e2e mocks. start() no longer baselines
the draft; resync still fires on reconnect and behind-heartbeats, both
of which no-op until a send has bound a workflow, matching the previous
effective behavior.

zAgentTurnAccepted declares the optional workflow_id it always carried
through passthrough. Session and root tests rebind via the ack; the
root draft-binding test proves ack id -> draft_patch -> loadGraphData
and that a foreign-workflow patch is ignored.

Net -248 lines. Typecheck, browser typecheck, oxlint, eslint, and knip
clean; 1158 unit tests pass.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/workbench/extensions/agent/composables/agent/useAgentSession.ts (1)

181-188: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reset the draft store in newChat() conversationStore.reset() leaves the previous workflow bound, so a late draft_patch or heartbeat from the abandoned chat can still be applied to the canvas. Add draftStore.reset() here too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/composables/agent/useAgentSession.ts` around
lines 181 - 188, `newChat()` currently resets only `conversationStore`, which
leaves the previous workflow state active and can let late `draft_patch` or
heartbeat updates affect the canvas. Update `newChat()` in `useAgentSession` to
also call `draftStore.reset()` alongside `conversationStore.reset()` after
`stopTurn()`, so a new chat starts with both conversation and draft state
cleared.
♻️ Duplicate comments (2)
src/workbench/extensions/agent/AgentPanelRoot.vue (2)

82-90: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Still missing error handling around the draft-to-canvas apply pipeline.

If validateComfyWorkflow throws or app.loadGraphData rejects, this becomes an unhandled promise rejection with no logging or user feedback — this was already flagged in a prior review round and remains unaddressed in this diff.

🛡️ Proposed fix
 useDraftCanvasApply((content) => {
   void (async () => {
-    const workflow = await validateComfyWorkflow(content)
-    if (workflow) await app.loadGraphData(workflow)
+    try {
+      const workflow = await validateComfyWorkflow(content)
+      if (workflow) await app.loadGraphData(workflow)
+    } catch (error) {
+      console.error('[agent-panel] failed to apply draft to canvas', error)
+    }
   })()
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/AgentPanelRoot.vue` around lines 82 - 90, The
draft-to-canvas apply flow in AgentPanelRoot.vue still lacks error handling
around the async pipeline. Wrap the logic inside useDraftCanvasApply with
try/catch so failures from validateComfyWorkflow or app.loadGraphData are
caught, then log the error and surface an appropriate user-facing failure state
or notification instead of allowing an unhandled promise rejection.

92-100: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Websocket unsubscribe still races the cancel flow on unmount.

stop() runs synchronously right after firing void stopTurn(), so the socket can be torn down before the terminal agent_message_done for the cancelled turn arrives. Since the conversation store survives unmounts, reopening the panel can find activeTurnId/streaming stuck. Already flagged previously and still present unchanged.

🛡️ Proposed fix
-onBeforeUnmount(() => {
+onBeforeUnmount(async () => {
   // ...
-  void stopTurn()
-  stop()
+  await stopTurn()
+  stop()
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workbench/extensions/agent/AgentPanelRoot.vue` around lines 92 - 100, The
unmount cleanup in AgentPanelRoot.vue is still tearing down the websocket too
early because onBeforeUnmount calls stopTurn() without waiting and then
immediately calls stop(), so the final agent_message_done can be missed and
activeTurnId may stay stuck. Update the unmount flow to ensure the
cancel/terminal event path completes before unsubscribing the socket, either by
awaiting the stopTurn() completion or by moving stop() into a post-cancel
completion path. Keep the fix anchored around onBeforeUnmount, stopTurn, and
stop so the conversation store can settle cleanly before the component fully
unmounts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 162-167: The send flow in onSend currently ignores the boolean
result from sendMessage(), which prevents failed sends from restoring the
composer state. Update onSend to forward or return the sendMessage() result so
useComposer.submit() can detect false and keep the draft and attachments intact,
and ensure the handling around sendMessage and submit preserves the composer
contents on failure.

---

Outside diff comments:
In `@src/workbench/extensions/agent/composables/agent/useAgentSession.ts`:
- Around line 181-188: `newChat()` currently resets only `conversationStore`,
which leaves the previous workflow state active and can let late `draft_patch`
or heartbeat updates affect the canvas. Update `newChat()` in `useAgentSession`
to also call `draftStore.reset()` alongside `conversationStore.reset()` after
`stopTurn()`, so a new chat starts with both conversation and draft state
cleared.

---

Duplicate comments:
In `@src/workbench/extensions/agent/AgentPanelRoot.vue`:
- Around line 82-90: The draft-to-canvas apply flow in AgentPanelRoot.vue still
lacks error handling around the async pipeline. Wrap the logic inside
useDraftCanvasApply with try/catch so failures from validateComfyWorkflow or
app.loadGraphData are caught, then log the error and surface an appropriate
user-facing failure state or notification instead of allowing an unhandled
promise rejection.
- Around line 92-100: The unmount cleanup in AgentPanelRoot.vue is still tearing
down the websocket too early because onBeforeUnmount calls stopTurn() without
waiting and then immediately calls stop(), so the final agent_message_done can
be missed and activeTurnId may stay stuck. Update the unmount flow to ensure the
cancel/terminal event path completes before unsubscribing the socket, either by
awaiting the stopTurn() completion or by moving stop() into a post-cancel
completion path. Keep the fix anchored around onBeforeUnmount, stopTurn, and
stop so the conversation store can settle cleanly before the component fully
unmounts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 56b2b4f5-3c68-4f3e-9acb-2f70236bdaf0

📥 Commits

Reviewing files that changed from the base of the PR and between fd83e79 and 42a7681.

📒 Files selected for processing (8)
  • browser_tests/tests/agent/agentPanel.spec.ts
  • browser_tests/tests/agent/agentPanelMocks.ts
  • src/locales/en/main.json
  • src/workbench/extensions/agent/AgentPanelRoot.test.ts
  • src/workbench/extensions/agent/AgentPanelRoot.vue
  • src/workbench/extensions/agent/composables/agent/useAgentSession.test.ts
  • src/workbench/extensions/agent/composables/agent/useAgentSession.ts
  • src/workbench/extensions/agent/schemas/agentApiSchema.ts

Comment thread src/workbench/extensions/agent/AgentPanelRoot.vue
From a refresh of the V0 design spec (Notion "In-App Agent V0 - Design &
Requirements", Section A + B5) against the shipped panel:

- Branding: the design pins "the original Comfy mark" everywhere; the
  panel used a lucide sparkles placeholder. Swap to the square Comfy
  mark (icon-[comfy--comfy-c]) on all four surfaces - the sidebar tab,
  the top-bar "Ask Comfy Agent" button, the panel header title row, and
  the empty-state mark.
- Empty state: B5 requires a centered Comfy mark with a glow above the
  greeting; it was missing. Add it (accent-tinted, currentColor glow).
- Greeting: B5/Section A want the account first name ("Hello Jo,"); the
  panel rendered "Hello there," because the name was never wired. Pull
  the first name from useCurrentUser and pass it through to the greeting,
  falling back to the existing neutral default when there is no name.

Tests: assert the Comfy mark on both the tab registration and the top-bar
button; add a greeting-personalization test; loosen the e2e greeting
assertion to the stable "Hello" prefix so it survives personalization.

Typecheck, browser typecheck, oxlint, eslint, and knip clean; 1159 unit
tests pass.
… canvas

Design B2 wants the panel to push the canvas and be drag-resizable (the
~30% / ~50% docks). The host sidebar already provides both - it is a
splitter panel (LiteGraphCanvasSplitterOverlay) that pushes the canvas
and drag-resizes, the same as the Assets panel. The agent panel was
fighting that by capping its own content width (max-w-md / max-w-2xl,
mx-auto): dragging the sidebar wider only added gutters instead of
widening the panel, and the Medium/Large toggle changed the cap rather
than the dock.

Remove the self-imposed width cap so the panel fills the resizable
sidebar, and drop the Medium/Large size toggle (the design struck the
width-toggle from B3; the host's native drag-resize replaces it). The
sizeMode prop drove nothing else - the empty-state layout never used it -
so this is a net removal: the toggle button, its emit chain across
AgentPanel and PanelHeader, the panelWidth computed, the now-unused cn
import, and the orphaned expand/collapse locale keys all go.

Typecheck, oxlint, eslint, and knip clean; 900 agent/core tests pass.
- Local dev visibility: the panel is gated on the PostHog flag
  agent-in-app-experience, but that flag lives in a cloud PostHog project
  the local dev build does not read, so the panel never appeared on
  localhost. Force the gate open when the mode is development, so the
  panel is visible on the dev server without wiring the flag; test and
  production builds still gate on it (fail-closed unchanged).

- Empty-state overflow: the centered Comfy mark made the empty state
  taller than the panel at the narrow default width, and justify-end
  pushed the overflow up into the header (the greeting overlapped the
  title). Use a scroll container with mt-auto so the mark + greeting
  center when they fit and the whole thing scrolls when they do not,
  instead of overlapping the header.

Flag-gate tests still pass with the mode guard; typecheck, oxlint, and
eslint clean.
Bring the panel closer to the Figma design (it had been built to the
written requirements, not the frames):

- The Comfy mark renders in brand yellow (text-brand-yellow), not the
  generic blue accent, in both the header and the centered empty-state
  mark.
- The panel title is "Comfy Agent" (Figma) rather than "AI Agent" (the
  written doc, which disagreed with the design).
- Suggested prompts are light rows with a leading icon instead of heavy
  bordered cards, per Figma B5 ("leading icon + label"). The per-prompt
  icons are best-fit lucide icons pending the exact Figma icon set.

Typecheck, oxlint, and eslint clean; agent and core tests pass.
Tailwind Preflight is disabled host-wide (PrimeVue + litegraph coexistence),
so a raw <button> in the panel fell back to the browser default: a grey
buttonface fill and a 2px outset border. That is what made the suggested-
prompt rows, the header history/new-chat buttons, and the composer attach
button look like heavy grey cards instead of the clean rows in the Figma
frames.

Re-establish Preflight's button normalization (background transparent,
border 0 solid) in one @layer base rule scoped to #agent-panel-root and the
teleported reka surfaces (dialogs, dropdowns, drawer now carry .agent-scope).
The selector is wrapped in :where() so it stays at zero specificity and every
button's own bg-* / border utilities still win, so filled/bordered buttons
(the blue send button, bordered chips) render exactly as authored.

Verified live: no grey buttonface or outset border remains on any panel
button, and the send button keeps its accent background.
Against the finalized "In-App Agent V0 - Design & Requirements" doc and its
Figma frames (fileKey G7ZjPEAFJB8cqb7halGEfa):

- Empty state: the Comfy mark sits on a dark rounded tile; both greeting
  lines are bold; all five suggested prompts are pinned just above the
  composer (mark + greeting center above them) instead of overflowing, each
  a light row with its Figma leading icon (lightbulb, list, search,
  message-circle-question, workflow).
- Composer bottom row (B6): add the @ (mention) button beside the paperclip,
  add the "Auto" model label, and make the send button white with a dark
  up-arrow when active / grey when empty (was always the blue accent).
- Header (B3): ALPHA is a neutral outline badge (was blue-tinted), new chat
  uses the speech-bubble icon, and the history clock is removed.
- Add the session bar (B4): a "New Chat" row under the header that opens
  Chat History (the history entry point the header clock used to be).
- Rename the sidebar tab label from "AI Agent" to "Comfy Agent" to match the
  panel title and branding.

Verified live against the Figma frames.
The Figma docks the agent on the right of the canvas (pushing the canvas
left) and opens it from the top-bar "Ask Comfy Agent" button — the left rail
keeps Assets/Nodes/etc. and has no agent icon. It was previously a left
sidebar tab.

- New agentPanelStore holds the panel's { enabled, isOpen }. agentPanel.ts no
  longer registers a sidebar tab; the top-bar button toggles isOpen, and the
  PostHog flag gate drives enabled (fail-closed: flag off hides the button and
  closes the panel).
- GraphCanvas renders AgentPanelRoot in the host right-side-panel slot when the
  panel is enabled + open (taking precedence over the node-properties panel),
  and the splitter shows that offside panel while the agent is open, so the
  canvas shrinks to the left. The panel's close button closes the store.
- Update the unit + e2e specs to open via the top-bar button.

Verified live: opens/closes on the right, canvas pushes left, left rail
intact, no agent icon in the rail. Typecheck + unit tests pass.
@CodeJuggernaut CodeJuggernaut force-pushed the nathaniel/fe-1187-agent-side-panel-fe-implementation branch from 6e0e15d to 88cdef7 Compare July 7, 2026 23:14
The thread id lived only in the in-memory store, so a reload always opened a
blank panel and the next send even split the transcript onto a new server
thread. Per the backend contract, GET /api/agent/threads/{id}/messages is the
page-load history endpoint (seq ascending; 404 = thread not found).

- Persist the thread id (localStorage) when a send's ack adopts it; clear it
  on new chat.
- On session start with an empty store, restore the persisted thread and
  hydrate its transcript through the new conversationStore.hydrate(): rows
  pair by turn_id in seq order and arrive settled; a turn whose assistant row
  is missing still renders its user prompt. A 404 forgets the stale id
  silently; reopening the panel within the same page session leaves the live
  conversation untouched.
- Tests: hydrate-on-start, stale-404 forget, persist-on-send/clear-on-new-
  chat, no-clobber-on-reopen; the harness clears localStorage between tests.
Iterative style pass against the design prototype (visual reference only; all
changes are tweaks to our own components):

- Dock: the panel is now a full-viewport-height right column beside the tab
  bar (was a splitter percentage panel below it), 420px default <-> 960px
  maximized with a drag handle on its left edge; 8px inset wrapper with a
  rounded interface-stroke border.
- Entry: the 'Ask Comfy Agent' button moves from the actionbar row into the
  workflow tab bar (plum-bordered ink pill, yellow Comfy-C, open state
  highlights); still flag-gated fail-closed. The extension is now gate-only.
- Header: h-12/px-4, regular-weight title, neutral ALPHA pill (no
  semibold/tracking), icons message-circle-plus + maximize-2/minimize-2 +
  x with tooltips.
- Session bar: compact h-6 rounded-sm pill (align-justify icon, truncated
  title, no chevron) instead of a full-width bordered row.
- Empty state: ink-700 tile with plum-600 border and size-6 mark; greeting
  scales text-base -> text-2xl via container query; suggested prompts are
  rounded-full pill chips (size-3 icons) that wrap centered at >=460px;
  4th prompt icon corrected to message-circle-warning.
- Composer: rounded-2xl container owning all padding, focus-within border
  brighten, min-h-20 textarea (px-4 py-3), toolbar px-3 py-2, Auto gets its
  chevron, send is rounded-xl light-on-dark with opacity-50 disabled state;
  placeholder is now 'Ask Comfy Agent…'.
- Footer: p-4 with a mx-auto max-w-[640px] column and my-0 caption.
- Tokens: agent-* aliases retuned to the reference's host tokens
  (base-background surface, secondary-background raised/hover,
  muted-foreground for all secondary text, component-node-border dividers).

Running mismatch list: temp/plans/fe-1187-figma-acceptance.md
Computed-style diff of our conversation vs the design reference (prototype);
re-probed live after the fix for an exact match on the user bubble.

- User message: right-aligned pill, no avatar (dropped the Avatar and the
  name/userName props that fed it) — w-fit rounded-lg bg-agent-surface-raised
  px-4 py-3 text-xs (was rounded-agent bg-agent-pill max-w-sm px-3 py-2
  text-sm with an avatar; bubble was 14px/#303036/radius12, now
  12px/rgb(38,39,41)/radius8/py-3 px-4 to match).
- Markdown prose: h1 text-2xl/600, h2 text-base/600, p 14/1.625, decimal/disc
  lists, accent underlined links, 3px muted blockquote, bordered
  secondary-surface tables (were entirely missing), bordered inline code.
- Tool-call summary row: wrench + 'Ran N…' summary + right chevron on a
  borderless h-8 rounded-md muted row (was a bordered card with a left
  chevron); expanded steps render as a plain gap list.
- Conversation column: mx-auto max-w-[640px] p-4.

Verified live on localhost against the prototype. Typecheck clean; agent
tests 177/177.
Three reported bugs:

- History did nothing: it was a reka Dialog teleported to <body> that opened
  behind the docked panel's z-999 stacking context, so it never appeared.
  Replace it with an in-panel Chat History screen (new ChatHistoryScreen)
  that the session bar swaps in over the conversation, with a back arrow;
  picking a chat or starting a new one returns. No teleport, no stacking
  fight. Deleted ChatHistoryDrawer + its DropdownMenu* deps.
- No way to make a new chat: the header new-chat button opened the
  out-of-V0-scope 'starting point' onboarding modal instead of resetting.
  It now just clears to the empty state; deleted StartingPointModal.
- Textarea border wrong: the panel-scoped Preflight reset in agentTheme.css
  covered <button> but not <textarea>/<input>/<select>, so the textarea kept
  its UA border/font inside the composer's own border (double border). Extend
  the reset to those elements (border 0, transparent bg, inherit font).

Verified live: session bar -> in-panel history -> back; new-chat -> empty
state; textarea border now 0 (single border on the composer container).
Typecheck/knip clean; agent tests 177/177.
Kishore shipped the list-threads endpoint, so Chat History is no longer a
single local 'current' row.

- New listThreads() on the REST client + a tolerant zAgentThreads schema
  (every field optional + passthrough): the endpoint shipped after the openapi
  extract, so the client normalizes id / title / timestamp across the likely
  spellings and a shape drift degrades to a best-effort row rather than a hard
  zod failure that would blank the list.
- useAgentSession gains listThreads() and loadThread(id): loadThread cancels
  any in-flight turn, adopts + persists the thread id, and hydrates its
  transcript (reusing the B17 resume path; a stale id 404s and is forgotten).
- AgentPanelRoot fetches the list on mount and each time history opens
  (best-effort: a failed fetch keeps the last-known list), maps threads to
  ChatSession rows, tracks the active row off the live threadId, and loads a
  picked chat via loadThread. Removed the old local 'current row' mirror.
- History store gains replaceAll() for the authoritative server list.

Verified live: the panel calls GET /api/agent/threads and, because the
endpoint 404s on the pr-4432 preview env (Kishore's build not deployed there
yet), the history screen shows 'No conversations yet' with no crash — the
graceful-degradation path. Real rows will populate on an env with the
endpoint; the field mapping should be reconfirmed against the live shape.
Typecheck/knip clean; agent tests 180/180 (added loadThread + listThreads +
server-history-population coverage).
- ThinkingStatus: brain icon and a shimmer on the "Thinking…" label
  (new agent-shimmer keyframes; static muted fallback under
  prefers-reduced-motion and .disable-animations)
- CodeBlock: bordered chrome; header gains a file-code icon, the
  language, and a bordered copy button; mono body
- MessageFeedback: gap-0.5 row, size-6 buttons, size-3.5 icons
- Composer: send button shows a loader-circle spinner while the turn
  is thinking, via a new submitting prop threaded
  AgentPanelRoot -> AgentPanel -> Composer
The server-side draft never mirrors the live canvas (it starts empty
even for saved workflows), so @-tagged node_ids resolved to nothing and
the agent replied that the canvas was empty. Each tagged node now rides
the POST with its serialized definition from the graph the canvas is
showing (root or an open subgraph), plus a context note that claims
inline definitions only for tags that resolved, names the gap when some
did not, and nudges a save when the tab has no server-side workflow.
postMessage now carries the serialized active graph when it changed
since the last upload (2MB cap, re-upload after failed sends or thread
switches), per the agreed cloud contract; current servers ignore the
field. The ack binds the uploaded tab to the thread's workflow id, so
agent patches apply in place on the user's own tab. Empty drafts park
everywhere, and the conflict dialog still guards modified tabs.
REST failures (e.g. Bad Gateway on hydrate), malformed events, and
upload failures rendered as bespoke toasts floating over the docked
panel. They now share the one host error modal already used for
draft-apply failures; warnings/info stay transient toasts.
Tags send bare node_ids again; they resolve against the full graph the
same POST already uploads (workflow.content) once the server seeds the
draft from it. No client-side stopgap.
Rename the WorkflowUpload fields so the wire contract reads plainly:
content -> graph (the prompt is already the top-level content field), and
base_version -> last_seen_version (the draft version the client last
received; draft_version would have collided with the existing WS event
type of that name).
… action bar

Draft applies now re-baseline the bound tab's change tracker to the canvas
as loaded and clear isModified, on both the in-place and minted-new-tab
paths. A minted tab's stored baseline carries an ensureWorkflowId id the
canvas never adopts, so the first capture flipped isModified and every
following draft_patch raised the conflict dialog with zero user edits.
Manual edits still re-arm the dialog.

The thumbs up/down + copy row under a completed agent message no longer
hides until hover (V0: always display).
Adds the V0 FE metric set through the existing telemetry layer (typed
events, optional provider methods, cloud PostHog provider):

- app:agent_panel_opened / app:agent_panel_closed with source
  (topbar_button | close_button | flag_disabled) and open_duration_ms,
  so open-vs-closed share per session is computable
- app:agent_entry_button_clicked (resulting_state) and
  app:agent_close_button_clicked for the raw clicks
- app:agent_message_sent (attachment_count, node_tag_count),
  app:agent_node_tagged (mention_picker), app:agent_attach_button_clicked
- app:agent_workflow_applied (workflow_id, new_tab | existing_tab) for
  agent-created vs agent-edited workflow attribution
- app:agent_message_feedback now carries workflow_id (PM-98)

The panel store owns open/close state, so it emits the state events with
an idempotency guard (the flag gate re-syncs close on every evaluation).
…t regressions

- MarkdownStream renders through the shared markdownRendererUtil; the
  agent copy (and its module-load DOMPurify hook that gave every host
  anchor target=_blank) is deleted.
- The agent event source is now a thin adapter over the api singleton's
  typed custom-event dispatch: no second socket follower, no re-parse of
  every /ws frame, no "Unknown message type" throw noise. Zod payload
  validation and the malformed-event notice stay.
- AgentPanelRoot loads via defineAsyncComponent, keeping the flag-gated
  subtree out of the GraphCanvas chunk.
- Prompt-error cards show details only for the agent's own error types;
  host cards restored to pre-PR behavior, both pinned by tests.
- The agent REST client rides api.fetchApi (Firebase init-wait, auth
  headers, 401 remint, Comfy-User) instead of a hand-rolled fetch with
  workspace-token-only auth; zod parsing and AgentApiError stay.
- Agent-local Button/Textarea forks replaced by the shared UI kit with
  variant mappings verified pixel-equivalent through tailwind-merge;
  dialogs inline reka primitives (the shared kit's entrance animations
  and sizing cannot be neutralized). ScrollArea/CollapsibleContent
  wrappers inlined per the sibling idiom.
- WorkflowTabs CTA uses the shared Button.
- agentTheme.css no longer redefines tw-animate-css collapsible
  keyframes (they globally retargeted three sharing-dialog consumers).
- CodeBlock keeps the framed header + copy but renders plain monospace;
  the shiki dependency and catalog entry are removed. MarkdownStream
  tokenizes fences via marked.lexer, fixing the 4-backtick gap.
- Safety UI that nothing drives (ApprovalCard, LockBanner, RevertButton
  and their AgentPanel plumbing); ConflictDialog stays.
- Dead message-part clusters: file/asset rendering and reasoning
  disclosure that no transport path constructs; the parts union and
  AgentMessage grouping shrink to text/tool/notice.
- Unwired composer pieces (AssetTray, SelectionActionChips,
  useCloudAssets) with zero non-test importers.
- Dead exports (createThread, history.upsert, useAgentFeatureGate fn,
  hasDraft, onboarding multi-step machinery) - each re-verified for
  zero production consumers on the current head; parseAgentWsEvent /
  isAgentEvent kept, they are live imports since the event rework.
- Write-only token pipeline, info/warning notice machinery, and the
  transport's no-op finalize loop removed; finalize/abort merged into
  one settle().
- 17 locale keys with zero usages removed from en (other locales are
  lobe-i18n generated and never carried them); error-catalog and
  design-locked keys kept.
- useAttachment strings go through i18n; the 20MB label derives from
  the named constant (max_upload_size flag exists but has no production
  consumer, so the constant stays).
- A failed thread-list fetch now raises the shared error modal instead
  of silently showing empty history, with a regression test.
Adds the V0 FE metric set through the existing telemetry layer (typed
events, optional provider methods, cloud PostHog provider):

- app:agent_panel_opened / app:agent_panel_closed with source
  (topbar_button | close_button | flag_disabled) and open_duration_ms,
  so open-vs-closed share per session is computable
- app:agent_entry_button_clicked (resulting_state) and
  app:agent_close_button_clicked for the raw clicks
- app:agent_message_sent (attachment_count, node_tag_count),
  app:agent_node_tagged (mention_picker), app:agent_attach_button_clicked
- app:agent_workflow_applied (workflow_id, new_tab | existing_tab) for
  agent-created vs agent-edited workflow attribution
- app:agent_message_feedback now carries workflow_id (PM-98)

The panel store owns open/close state, so it emits the state events with
an idempotency guard (the flag gate re-syncs close on every evaluation).
The entry/close click events are kept alongside the state events
deliberately: the V0 metrics checklist names them as PM-queryable
trackers, though the state events' sources make them derivable.

Also hardens autosaveAppliedDraft: the tracker re-baselines with the RAW
canvas serialization. A schema-validated baseline would diff against raw
captures under strict graphEqual and re-raise the conflict dialog on an
unedited canvas; a test pins validateComfyWorkflow to its single
loadDraft call so the baseline can never route through the schema.
The trim deleted the collapsible keyframes as duplicates of
tw-animate-css, but that package defines no collapsible-* keys, so the
tool-disclosure animation silently no-opd. Restored under agent-*
names: the globally-imported sheet can no longer retarget the host's
animate-collapsible-* utilities (undefined on main) in sharing dialogs.
Adds the three review-flagged test gaps: indented code stays prose,
bare fences label as text, and the oversize-attachment message pins
its i18n interpolation.
- ToolCallGroup: streaming auto-open, same-name merge, failure reopen,
  and the AgentMessage adjacent-merge branch with pluralized header.
- WorkflowTabs: the Ask Comfy Agent CTA renders when enabled and
  toggles the panel (mock rewired ref-backed for storeToRefs).
- useAgentSession: non-object and foreign host frames drop silently
  mid-turn.
- MarkdownStream: fence label picks the first info-string word.
autosaveAppliedDraft re-baselines with the RAW canvas serialization: a
schema-validated baseline diffs against raw captures under strict
graphEqual and re-raises the conflict dialog on an unedited canvas. A
test pins validateComfyWorkflow to its single loadDraft call so the
baseline can never route through the schema.

Coverage hardening from review: entry-click resulting_state both ways,
close-button click attribution through the real store, message_sent
payloads (attachments and node tags), mention-pick positive plus
stages-nothing negative, null open_duration_ms, flag_disabled pin.
Merges the reviewed trim (-1,189 net lines, 19 fewer files, shiki
dropped, four host regressions fixed, zero functionality loss;
validated by a full review pipeline) into the PR branch as a single
revertible merge. Conflict resolutions favor the amended stable side
where it superseded the trim: raw-serialization autosave baseline
(schema-normalized baselines re-flip isModified via graphEqual),
dedupe-gated mention telemetry, the richer WorkflowTabs CTA tests, and
the validate-once assertion; the trim's ws event fake wins in the Root
tests.
…el-fe-implementation' into nathaniel/fe-1187-agent-side-panel-fe-implementation
The client hardcoded person_profiles: 'identified_only' AFTER the
posthog_config spread, silently overriding the server's explicit
'always' (live on /api/features). Under identified_only every event
captured before identify() resolves is a person-less anonymous event
that never attaches to the user, so early-session events (entry click,
panel opened, first message) vanish from person-scoped PostHog views.
The hardcode is now a default the server can override; before_send
stays locked (PII stripping). Reverses the person_profiles half of the
pin added in #12479, test updated accordingly.

Also retries the posthog-js dynamic import once: a stale deploy can
404 the chunk, which previously disabled telemetry for the entire
session after a single console.error.
The module map caches a failed module resolution, so re-importing the
same specifier rejects from cache without refetching; the retry could
never succeed. Stale-chunk failures are already handled app-wide by the
vite:preloadError listener in App.vue.
The 2MB cap guarded a server limit that does not exist yet and silently
skipped uploads for large graphs, which are normal on a video/image
platform. The server owns its own limits.
The backend now seeds the thread's draft from the graph the client
sends each turn. Align to its shape and rules:
- The turn POST carries draft: { content: <serialize() save format>,
  version: <last seen draft version | null> } (was the inert
  workflow/graph/last_seen_version shape).
- Snapshots gate on canvas-non-empty, not workflow_id, so templates,
  unsaved tabs, and new tabs seed correctly; skipping an unchanged
  canvas stays as the server-blessed optimization.
- A 409 {error, version} means the agent's draft advanced: adopt the
  returned version and retry the send once.
- autosaveAppliedDraft only reset the change tracker and isModified,
  but the tab dot renders whenever a workflow is not persisted, so
  agent-applied drafts always showed unsaved and lived only in memory
- save through workflowService instead: temporary tabs use a silent
  saveWorkflowAs with a collision-safe filename (no prompt or
  overwrite dialog), persisted tabs re-save silently
- rebind workflow_id to the tab current path in finally so service
  renames (collision bump, app extension mismatch) and failed saves
  never strand the binding on a dead path
- known limit: host saveWorkflow drift handling can rarely toast or
  confirm on persisted tabs; reusing the canonical save path there
  is intentional
- tests: failure isolation keeps the applied draft and surfaces no
  error, an app-mode collision bumps the filename and rebinds, a
  save that fails after rename still rebinds; binding tests now
  stub a valid empty threads page
Per the per-file consolidation audit (temp/plans/pr13472-file-consolidation-audit.md):
safetyTypes -> ConflictDialog (SFC type export, ActiveTabStrip pattern),
agentTranscript + useDraftCanvasApply -> AgentPanelRoot, ThinkingStatus ->
AgentMessage, SuggestedPromptChip -> EmptyState, SelectionTagChip -> Composer,
SessionBar -> AgentPanel. All moves byte-identical; net -9 files.

agentTranscript's test is replaced by a stronger end-to-end copy test
asserting the exact clipboard markdown. useDraftCanvasApply's tests were
retired as redundant rather than merged: patch-to-canvas firing is covered
end-to-end by the draft binding suite, rejection semantics are owned by
agentDraftStore.test.ts, and the stop handle was unused API removed by the
fold.
…JECT_TOKEN

Deployed builds keep reading the token from the backend-injected __CONFIG__
(precedence unchanged); the env fallback only enables event verification from
local dev servers, which otherwise have no key and silently queue forever.
- loadThread and newChat fired a server-side cancel for the in-flight
  turn; the backend recorded it and the reply was lost ("Stopped
  streaming..."). Panel unmount did the same. All implicit cancels are
  removed; the explicit Stop button is the only cancel left
- switching away parks the live turn (message + event transport) in a
  per-thread registry; events keep accumulating silently and cannot
  bleed into the displayed chat; switching back re-attaches the turn
  live with no lost text, or renders the finished reply from history
- a done landing during the return fetch keeps the parked entry so the
  full reply still renders; overlapping or double-clicked history loads
  are generation-gated; socket death and panel close settle parked
  turns; remount refreshes a surviving thread from history
- draft patches from a backgrounded thread no longer drive the
  displayed canvas (thread guard; version heartbeat unchanged)
- transport ignores events after settle; chat history date buckets
  follow a reactive clock across midnight; onboarding coach gains
  dialog semantics and Escape to dismiss; dead approval-flow fixtures
  removed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant