feat(frontend): auto-open artifact panel when agent creates new artifact (SECRT-2263) - #12997
Conversation
- Extend useAutoOpenArtifacts with messages + isLoadingSession params
- Snapshot known artifact IDs on first stable render so history doesn't
auto-open on session load
- Watch for new agent artifacts (origin === 'agent') and open the most
recently added one automatically
- Track user-close via isOpen true→false transition; suppress auto-open
for the remainder of that session (refs reset on session change via
key={sessionId} remount)
- Update ChatContainer call site to pass messages and isLoadingSession
- Add 6 new tests: auto-open, no-open-on-load, no-open-user-upload,
most-recent-wins, user-close-suppression, reconnect-no-false-positive
- Update __tests__ duplicate to use new hook signature
Closes SECRT-2263
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/review |
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe PR enhances ChangesArtifact Auto-Open
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 0 conflict(s), 0 medium risk, 1 low risk (out of 1 PRs with file overlap) Auto-generated on push. Ignores: |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatContainer/ChatContainer.tsx:
- Line 94: The call to useAutoOpenArtifacts should be skipped when the artifacts
feature flag is off to avoid populating hidden state; either wrap the call site
so useAutoOpenArtifacts({ sessionId, messages, isLoadingSession }) only runs
when Flag.ARTIFACTS is enabled, or modify useAutoOpenArtifacts itself to
early-return/no-op when the artifacts feature flag (Flag.ARTIFACTS) is disabled
(optionally clearing artifact panel state when the flag flips off). Ensure you
reference the existing hook name useAutoOpenArtifacts and the feature flag
Flag.ARTIFACTS so the change prevents any artifact-panel store updates while the
flag is false.
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.ts:
- Around line 58-85: The auto-open logic currently recomputes artifacts from the
entire messages array and treats any fetched historical artifacts as new; modify
useAutoOpenArtifacts to ignore prepended/historical messages by only inspecting
appended/tail-updated messages instead of the full messages list: keep a ref
like lastSeenMessageCountRef or lastSeenMessageIdsRef and when handling updates,
compute agentArtifacts only for messages.slice(lastSeenMessageCountRef.current)
(or filter messages by IDs greater than lastSeenMessageIdsRef), update that ref
after processing, and continue using existing refs (snapshotTakenRef,
knownArtifactIdsRef, userHasClosedRef) and functions (getMessageArtifacts,
openArtifact) so you only add and auto-open artifacts from newly appended
messages rather than the entire history.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1a3962c9-f0d4-4569-9e5f-cf1311931c48
📒 Files selected for processing (4)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: lint
- GitHub Check: integration_test
- GitHub Check: check API types
- GitHub Check: Cursor Bugbot
- GitHub Check: end-to-end tests
- GitHub Check: Check PR Status
- GitHub Check: Analyze (typescript)
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (16)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend developmentFormat frontend code using
pnpm format
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Fully capitalize acronyms in symbols, e.g.graphID,useBackendAPI
No linter suppressors (//@ts-ignore``,// eslint-disable) — fix the actual issue
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development
autogpt_platform/frontend/**/*.{ts,tsx}: Use function declarations (not arrow functions) for components/handlers
Noanytypes unless the value genuinely can be anything
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/src/**/*.{ts,tsx}: Use generated API hooks from@/app/api/__generated__/endpoints/following the patternuse{Method}{Version}{OperationName}, and regenerate withpnpm generate:api
Separate render logic from business logic using component.tsx + useComponent.ts + helpers.ts pattern, colocate state when possible and avoid creating large components, use sub-components in local/componentsfolder
Use function declarations for components and handlers, use arrow functions only for callbacks
Do not useuseCallbackoruseMemounless asked to optimise a given function
autogpt_platform/frontend/src/**/*.{ts,tsx}: Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}
Always import the-Icon-suffixed alias from@phosphor-icons/react(e.g.TrashIcon,PlusIcon,SquareIcon) — bare exports are deprecated
Do not useuseCallbackoruseMemounless asked to optimize a given function
Never usesrc/components/__legacy__/*— use design system components fromsrc/components/
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
autogpt_platform/frontend/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Component props should use
interface Props { ... }(not exported) unless the interface needs to be used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
autogpt_platform/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never type with
any, if no types available useunknown
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
autogpt_platform/frontend/**/*.{tsx,jsx}: Nodark:Tailwind classes — the design system handles dark mode
Use Next.js<Link>for internal navigation — never raw<a>tags
Use Tailwind CSS only for styling with design tokens and Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
autogpt_platform/frontend/src/**/components/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Put sub-components in local
components/folder; component props should betype Props = { ... }(not exported) unless used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
autogpt_platform/frontend/src/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Structure components as
ComponentName/ComponentName.tsx+useComponentName.ts+helpers.ts
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Avoid index and barrel files
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
No barrel files or
index.tsre-exports in the frontend
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not type hook returns, let Typescript infer as much as possible
autogpt_platform/frontend/src/**/*.ts: Extract component logic into custom hooks grouped by concern, not by component, with each hook in its own.tsfile
Do not type hook returns; let TypeScript infer as much as possible
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}: Use Vitest + RTL + MSW for integration tests as the primary testing approach (~90%, page-level), use Playwright for E2E critical flows, and use Storybook for design system components
Run frontend integration tests withpnpm test:unit(Vitest + RTL + MSW)
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/src/app/**/__tests__/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Write integration tests in
__tests__/next topage.tsxusing Vitest + RTL + MSW for new pages/features
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.ts
autogpt_platform/frontend/src/**/__tests__/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Use Orval-generated MSW handlers from
@/app/api/__generated__/endpoints/{tag}/{tag}.msw.tsfor API mocking
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.ts
🧠 Learnings (10)
📚 Learning: 2026-02-27T10:45:49.499Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx:23-24
Timestamp: 2026-02-27T10:45:49.499Z
Learning: Prefer using generated OpenAPI types from '@/app/api/__generated__/' for payloads defined in openapi.json (e.g., MCPToolsDiscoveredResponse, MCPToolOutputResponse). Use inline TypeScript interfaces only for payloads that are SSE-stream-only and not exposed via OpenAPI. Apply this pattern to frontend tool components (e.g., RunMCPTool) and related areas where similar SSE/openapi-discrepancies occur; avoid re-implementing types when a generated type is available.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
📚 Learning: 2026-03-24T02:05:04.672Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:04.672Z
Learning: When gating React component logic on a React Query result (e.g., hooks like `useQuery` / `useGetV2GetCopilotUsage`), prefer destructuring and checking `isSuccess` (or aliasing it to a meaningful boolean like `isSuccess: hasUsage`) instead of relying on `!isLoading`. Reason: `isLoading` can be `false` in error/idle states where `data` may still be `undefined`, while `isSuccess` indicates the query completed successfully and `data` is populated.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
📚 Learning: 2026-03-24T02:23:31.305Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/RateLimitResetDialog/RateLimitResetDialog.tsx:0-0
Timestamp: 2026-03-24T02:23:31.305Z
Learning: In the Copilot platform UI code, follow the established Orval hook `onError` error-handling convention: first explicitly detect/handle `ApiError`, then read `error.response?.detail` (if present) as the primary message; if not available, fall back to `error.message`; and finally fall back to a generic string message. This convention should be used for generated Orval hooks even if the custom Orval mutator already maps details into `ApiError.message`, to keep consistency across hooks/components (e.g., `useCronSchedulerDialog.ts`, `useRunGraph.ts`, and rate-limit/reset flows).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
📚 Learning: 2026-03-31T14:04:42.444Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatInput/ChatInput.tsx:172-177
Timestamp: 2026-03-31T14:04:42.444Z
Learning: In the Copilot frontend components under autogpt_platform/frontend/src/app/(platform)/copilot/, Tailwind dark mode variants (e.g., `dark:*`) are intentional and should be allowed. Do not flag `dark:` utilities in these Copilot UI components as incorrect; they are used to ensure proper contrast and correct behavior in both light and dark themes.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
📚 Learning: 2026-04-01T18:54:16.035Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 12633
File: autogpt_platform/frontend/src/app/(platform)/library/components/AgentFilterMenu/AgentFilterMenu.tsx:3-10
Timestamp: 2026-04-01T18:54:16.035Z
Learning: In the frontend, the legacy Select component at `@/components/__legacy__/ui/select` is an intentional, codebase-wide visual-consistency pattern. During code reviews, do not flag or block PRs merely for continuing to use this legacy Select. If a migration to the newer design-system Select is desired, bundle it into a single dedicated cleanup/migration PR that updates all Select usages together (e.g., avoid piecemeal replacements).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
📚 Learning: 2026-04-07T09:24:16.582Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12686
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/__tests__/PainPointsStep.test.tsx:1-19
Timestamp: 2026-04-07T09:24:16.582Z
Learning: In Significant-Gravitas/AutoGPT’s `autogpt_platform/frontend` (Vite + `vitejs/plugin-react` with the automatic JSX transform), do not flag usages of React types/components (e.g., `React.ReactNode`) in `.ts`/`.tsx` files as missing `React` imports. Since the React namespace is made available by the project’s TS/Vite setup, an explicit `import React from 'react'` or `import type { ReactNode } ...` is not required; only treat it as missing if typechecking (e.g., `pnpm types`) would actually fail.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
📚 Learning: 2026-04-02T05:43:49.128Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12640
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/WelcomeStep.tsx:13-13
Timestamp: 2026-04-02T05:43:49.128Z
Learning: Do not flag `import { Question } from "phosphor-icons/react"` as an invalid import. `Question` is a valid named export from `phosphor-icons/react` (as reflected in the package’s generated `.d.ts` files and re-exports via `dist/index.d.ts`), so it should be treated as a supported named export during code reviews.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/useAutoOpenArtifacts.test.ts
📚 Learning: 2026-04-13T13:11:07.445Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx:143-145
Timestamp: 2026-04-13T13:11:07.445Z
Learning: In `autogpt_platform/frontend`, do not flag direct interpolation of `executionID` UUID strings into URL query parameters (e.g., `activeItem=${executionID}` in JSX/Next links). If the value is a UUID string matching `[0-9a-f-]`, it contains no reserved URL characters, so additional `encodeURIComponent` or Next.js object-based `href` encoding is unnecessary. Only treat it as an encoding issue if the query-param value is not guaranteed to be UUID-formatted (i.e., may include characters outside `[0-9a-f-]`).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
📚 Learning: 2026-04-15T22:49:06.896Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11235
File: autogpt_platform/frontend/src/app/(platform)/admin/diagnostics/components/ExecutionsTable.tsx:0-0
Timestamp: 2026-04-15T22:49:06.896Z
Learning: In the AutoGPT frontend (React Query + toast/ErrorCard patterns), do not require `Sentry.captureException` in React Query mutation `catch` blocks. React Query handles error propagation for mutation paths, so follow the established pattern: show toast notifications for mutation errors and use `ErrorCard` for render/fetch errors. Only add `Sentry.captureException` for truly manual/unexpected exception paths that are outside React Query’s control (e.g., standalone async utilities or event handlers not wired through React Query).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx
📚 Learning: 2026-04-20T20:07:22.981Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11235
File: autogpt_platform/frontend/src/app/(platform)/admin/diagnostics/__tests__/ExecutionsTable.test.tsx:27-76
Timestamp: 2026-04-20T20:07:22.981Z
Learning: In this codebase, Orval-generated API modules under `src/app/api/__generated__/` are not committed to git and must be generated via `pnpm generate:api` (requires a running backend). In integration tests, it’s acceptable—and expected—to stub generated hooks/modules by mocking them with `vi.mock("@/app/api/__generated__/endpoints/{tag}/{tag}")`. Do not treat `vi.mock` of these generated hook modules as a violation of the MSW handler guideline, since the corresponding MSW handlers cannot be imported at test time when generated files are absent.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/__tests__/useAutoOpenArtifacts.test.ts
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #12997 +/- ##
==========================================
- Coverage 70.20% 69.61% -0.60%
==========================================
Files 2175 2162 -13
Lines 162477 158835 -3642
Branches 16682 16446 -236
==========================================
- Hits 114063 110566 -3497
+ Misses 45087 45002 -85
+ Partials 3327 3267 -60
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
📋 Automated Review — PR #12997
PR #12997 — feat(frontend): auto-open artifact panel when agent creates new artifact (SECRT-2263)
Author: ntindle | Files: 4
🎯 Verdict: REQUEST_CHANGES
PR Description Quality
✅ Has Why + What + How — PR description explains the feature, lists edge cases handled, documents the snapshot-based approach, and includes a test plan checklist.
What This PR Does
When an AI agent creates a file artifact during a copilot chat session, the artifact panel now automatically opens to show it. Previously, users had to manually discover and open new artifacts. The hook snapshots existing artifacts on session load, watches for new agent-originated ones, and respects user preference if they explicitly close the panel.
Specialist Findings
🛡️ Security ✅ — No new attack surface. Artifact ID extraction uses strict hex-UUID regex, origin === "agent" filter prevents user-controlled triggering, and openArtifact only mutates local Zustand UI state. No new endpoints, auth changes, or dependencies.
🏗️ Architecture
🟠 Feature flag bypass: useAutoOpenArtifacts runs unconditionally even when Flag.ARTIFACTS is off (ChatContainer.tsx:94), mutating store state with no visible panel. (Flagged by: architect, product, discussion — 3 specialists)
🟡 Five refs approaching complexity ceiling (useAutoOpenArtifacts.ts:25); a single state-object ref or reducer would be clearer.
⚡ Performance getMessageArtifacts() (regex parsing) on ALL messages every time messages changes. During streaming, this fires dozens of times per second as O(M×P). Acceptable for typical session sizes (<100 messages) but suboptimal.
🟡 Track last-checked index and only scan tail-appended messages (useAutoOpenArtifacts.ts:58).
🟡 Move userHasClosedRef check before the artifact scan to short-circuit earlier (useAutoOpenArtifacts.ts:72).
🧪 Testing
🟡 No test for sessionId: null early-return path.
🟡 No test for session-switch resetting close suppression.
📖 Quality ✅ — Excellent inline comments explaining why each effect exists, with ticket references. Naming is clear and consistent. Minor DRY issue with repeated type casts in tests.
📦 Product
📬 Discussion
🔎 QA
🔴 Blockers
-
TypeScript errors break CI (
useAutoOpenArtifacts.test.ts:28,46) —contentproperty does not exist onUIMessage<unknown, UIDataTypes, UITools>. ThemakeAgentMessageandmakeUserMessagetest helpers use an invalid property, failing thecheck API typesCI check. (Flagged by: discussion — CI failure) -
Prettier formatting failures (
__tests__/useAutoOpenArtifacts.test.ts,useAutoOpenArtifacts.test.ts) — Both test files fail lint CI. Runpnpm formatbefore pushing. (Flagged by: discussion — CI failure)
🟠 Should Fix
-
Feature flag not respected by auto-open hook (
ChatContainer.tsx:94) —useAutoOpenArtifactsruns and callsopenArtifact()even whenFlag.ARTIFACTSis disabled. This leaves phantom store state (isOpen=true,activeArtifactpopulated) with no rendered panel. If the flag toggles mid-session, the panel appears unexpectedly. Fix: passisArtifactsEnabledto the hook and early-return when false. (Flagged by: architect, product, discussion — 3 specialists + 2 bots) -
Duplicate test files (
__tests__/useAutoOpenArtifacts.test.ts+useAutoOpenArtifacts.test.ts) — Two files test the same hook (3 tests vs 11 tests). Both run in CI, creating maintenance burden and divergence risk. Consolidate into the canonical colocated file. (Flagged by: architect, testing, quality — 3 specialists)
🟡 Nice to Have
- Incremental message scanning (
useAutoOpenArtifacts.ts:58) — Track last-checked message index to avoid O(M×P) full-scan on every streaming token. (performance, architect) - Pagination ghost-open risk (
useAutoOpenArtifacts.ts:58) — If chat loads older history via scroll-up pagination, those old messages would introduce unseen IDs and could trigger false auto-open. (discussion) - Reset close suppression on manual re-open (
useAutoOpenArtifacts.ts:36) — Once user closes panel, auto-open is suppressed forever in that session, even after manually re-opening an artifact. (product)
🔵 Nits
- Repeated type cast (
useAutoOpenArtifacts.test.ts:211,239,253,271) — Extracttype Messages = UIMessage<unknown, UIDataTypes, UITools>[]alias to reduce noise.
QA Screenshots
| Screenshot | Description |
|---|---|
![]() |
Copilot page loads correctly after login ✅ |
![]() |
Subscription paywall blocks live artifact testing (environment issue, not PR) |
Human Review Needed
YES — Feature-flag interaction needs human judgment on the correct gating approach, and CI failures need verification after fix. No human approvals yet on a user-facing UX change.
Risk Assessment
Merge risk: LOW | Rollback: EASY
Frontend-only hook change with no backend, DB, or auth modifications. Worst case is the artifact panel opens unexpectedly; no data loss possible. Easy to revert.
CI Status
❌ 2/6 local checks failed (frontend lint, frontend typecheck). TypeScript errors in test helpers and Prettier formatting issues must be resolved.
UIMessage type from the ai SDK does not include a content property; it uses parts[] exclusively. Remove the extra field to fix tsc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add isArtifactsEnabled feature flag guard to useAutoOpenArtifacts - Move userHasClosedRef check before artifact extraction (early exit) - Delete duplicate __tests__/useAutoOpenArtifacts.test.ts file - Add Messages type alias to reduce repeated casts - Add test: session switch resets close-suppression - Add test: sessionId null path - Add test: feature flag disabled path - Use defaultProps pattern for cleaner test setup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
Keep our useAutoOpenArtifacts.test.ts (dev deleted the stub; we have the full test suite). ChatContainer.tsx auto-merged cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace message-scanning approach with card-based auto-open architecture: - ArtifactCard registers on mount via registerArtifactForAutoOpen - Store decides auto-open using module-level state (no extra re-renders) - Hook manages lifecycle only (session change, readiness, user-close) - UUID validation prevents partial-ID artifacts during streaming - Derived isActive selector reduces ArtifactCard re-renders - FULL_UUID regex hoisted to module scope per Vercel best practices Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…etadata upgrade deps - Reset wasOpenRef.current on session change to prevent false user-close detection - Add artifact.mimeType to ArtifactCard effect deps for metadata upgrade path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5cf2a48. Configure here.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/dev-review |
There was a problem hiding this comment.
📋 Automated Review — PR #12997
PR #12997 — feat(frontend): auto-open artifact panel when agent creates new artifact (SECRT-2263)
Author: ntindle | Files: 7
🎯 Verdict: APPROVE
PR Description Quality
✅ Has Why + What + How — PR describes the problem (users didn't know artifacts existed because the panel didn't open), the solution (card-based registration auto-opens the panel for agent-created artifacts), and the architectural approach (Zustand store actions + dedicated hook replacing message-scanning).
What This PR Does
Previously, when an AI agent created an artifact during a copilot session, the artifact panel stayed closed — users had to manually discover and open it. This PR auto-opens the artifact panel when the agent creates a new artifact, while respecting user intent (if the user closes the panel, it stays closed for that session). The implementation replaces an expensive message-scanning approach with an O(1) card-based registration pattern, and adds UUID validation to prevent DOM churn during streaming.
Specialist Findings
🛡️ Security ✅ — Frontend-only changes with no new API endpoints, auth changes, or backend code. The origin field on ArtifactRef is trusted from the AI SDK's message.role, which is an acceptable trust boundary. UUID validation via FULL_UUID regex is a positive security addition preventing malformed IDs from triggering unexpected API calls.
🟡 Removed isPreviewableArtifact gate from openArtifact (store.ts:229) slightly widens the client-side attack surface for malicious MIME types — blast radius is limited to the preview renderer.
🏗️ Architecture ✅ — Card-based registration is a well-designed pattern. Zustand store actions follow existing conventions. Hook separation is clean.
🟠 clearCopilotLocalData (store.ts:375-377) duplicates the three module-level reset lines from resetAutoOpenState (store.ts:329-331) — a DRY violation that will cause bugs if a fourth variable is added. (Flagged by: architect, quality — 2)
🟠 wasEverLoadingRef (useAutoOpenArtifacts.ts:70) is never reset on session change, which could block auto-open readiness in a fresh empty session after navigating from a loaded session. (Flagged by: architect, product — 2)
⚡ Performance ✅ — Net improvement. Replaces O(n·m) message-scanning on every streaming tick with O(1) per-artifact-mount registration. Module-level state avoids Zustand re-render overhead. UUID validation prevents DOM churn during streaming.
🟡 isOpen subscription in useAutoOpenArtifacts.ts:33 causes ChatContainer re-renders on every panel toggle; could use useCopilotUIStore.subscribe imperatively instead.
🧪 Testing helpers.ts changes have zero test coverage:
🟠 extractWorkspaceArtifacts UUID validation filter (helpers.ts:295) — a streaming safety feature with no tests. A regression would cause ArtifactCards to mount with garbage IDs. (Flagged by: testing — 1)
🟠 getMessageArtifacts rewrite (helpers.ts:322-351) — file-parts-first dedup logic with Map-based approach has no tests. No verification that file-part metadata wins over text-extracted metadata for the same ID. (Flagged by: testing — 1)
🟠 clearCopilotLocalData auto-open state clearing (store.ts:376) has no test. (Flagged by: testing — 1)
📖 Quality ✅ — Clean, well-documented code. JSDoc on useAutoOpenArtifacts explains the architecture clearly. Naming is descriptive.
🔵 Test comment at useAutoOpenArtifacts.test.ts:252 reads like debugging notes ("wait, resetAutoOpenState clears known IDs too") rather than documentation.
📦 Product ✅ — Solves a real UX pain point where artifacts felt broken because they required manual opening. Proper gating: only agent artifacts auto-open, user uploads don't, user-close is respected per-session, session switches reset state.
🟡 No focus management on auto-open — screen reader users won't know the panel appeared. Consider aria-live region.
🟡 Rapid artifact generation (3+ at once) causes visible panel content switching with no debounce.
📬 Discussion ✅ — All critical reviewer concerns addressed: feature flag bypass fixed in ce8398e, O(n·m) performance regression eliminated by rewrite. 34/36 CI checks pass (2 expected skips). PR was approved and merged.
🔎 QA ✅ — All 59 unit tests pass. Copilot streaming API verified end-to-end (session creation → streaming → tool execution). Negative auth tests confirm proper access control. Interactive browser testing of the artifact panel auto-open was blocked by a pre-existing subscription paywall in the dev environment — not a regression from this PR.
🟠 Should Fix
- DRY the reset logic (
store.ts:375-377) —clearCopilotLocalDataduplicates three module-level reset lines fromresetAutoOpenState. Replace withget().resetAutoOpenState()to maintain a single source of truth. (Flagged by: architect, quality — 2) - Reset
wasEverLoadingRefon session change (useAutoOpenArtifacts.ts:55) — The ref retains staletruefrom a previous session, blocking readiness in a fresh empty session until messages arrive. AddwasEverLoadingRef.current = falsein the session-change effect. (Flagged by: architect, product — 2) - Add tests for UUID validation in
extractWorkspaceArtifacts(helpers.ts:295) — This streaming safety feature has zero coverage. Add tests: partial UUID rejected, full UUID accepted. (Flagged by: testing — 1) - Add tests for
getMessageArtifactsrewrite (helpers.ts:322-351) — File-parts-first dedup logic, origin assignment ("agent"vs"user-upload"), and Map-based dedup are all untested. (Flagged by: testing — 1) - Add test for
clearCopilotLocalDataauto-open reset (store.ts:376) — Verify that callingclearCopilotLocalDataclears known IDs, readiness, and user-closed flags. (Flagged by: testing — 1)
🟡 Nice to Have
- Use imperative
subscribeforisOpenwatcher (useAutoOpenArtifacts.ts:33) — Eliminates unnecessary ChatContainer re-renders on panel toggle by usinguseCopilotUIStore.subscribein an effect instead of a React selector. (performance) - Verify ArtifactPanel handles non-previewable MIME types (
store.ts:229) — TheisPreviewableArtifactgate was intentionally removed; ensure the panel shows a graceful fallback (file info + download) for binary blobs. (security, product) - Encapsulate module-level state (
store.ts:159-161) — If more auto-open variables are added, wrap_autoOpenKnownIds,_autoOpenReady,_autoOpenUserClosedin a small class with a singlereset()method. (architect) - Add
aria-livefor auto-open (store.ts:327) — Announce panel appearance to screen readers when auto-open triggers. (product)
🔵 Nits
- Clean up debugging comment (
useAutoOpenArtifacts.test.ts:252) — Replace "wait, resetAutoOpenState clears known IDs too" with a concise note like// resetAutoOpenState clears knownIds, so re-registration opens again.
QA Screenshots
| Screenshot | Description |
|---|---|
![]() |
Copilot page loads successfully; subscription paywall blocks interactive testing (env limitation, not PR regression) |
Human Review Needed
YES — While security risk is low (frontend-only), the module-level mutable state pattern, removed previewability gate, and untested helper functions warrant a human glance to confirm the architectural trade-offs align with team preferences. The wasEverLoadingRef stale-state bug could affect real user sessions.
Risk Assessment
Merge risk: LOW | Rollback: EASY
Frontend-only changes to client-side Zustand state and React hooks. No backend, database, or auth changes. Feature is isolated to the copilot artifact panel. Rollback is a simple revert with no data migration concerns.
CI Status
| artifactPanel: { ...state.artifactPanel, activeArtifact: ref }, | ||
| })); | ||
| } | ||
| return; |
There was a problem hiding this comment.
🤖 🟢 low (security/trust boundary)
The origin field on ArtifactRef is trusted without independent validation. If any code path incorrectly sets origin: "agent" for user-uploaded content, it would bypass the auto-open suppression for user uploads.
Suggestion: Consider validating origin against the message role at registration time rather than trusting the caller, or add a comment documenting this trust assumption.
| set((state) => { | ||
| if (!isPreviewableArtifact(ref)) return state; | ||
|
|
||
| const { activeArtifact, history: prevHistory } = state.artifactPanel; |
There was a problem hiding this comment.
🤖 🟢 low (security/removed guard)
Removed isPreviewableArtifact gate from openArtifact — any artifact type (including binary blobs) can now open the preview panel. Ensure the artifact preview renderer handles unexpected MIME types safely.
Suggestion: Verify that the ArtifactPanel gracefully handles non-previewable MIME types without attempting unsafe rendering (e.g., executing scripts from blob content).
| @@ -335,6 +373,9 @@ export const useCopilotUIStore = create<CopilotUIState>((set) => ({ | |||
|
|
|||
There was a problem hiding this comment.
🤖 🟡 medium (architect/DRY violation)
clearCopilotLocalData duplicates the three module-level reset lines from resetAutoOpenState. If a fourth variable is added, both sites must be updated independently.
Suggestion: Replace the three lines with get().resetAutoOpenState() to maintain a single source of truth for auto-open state cleanup.
| const prevSessionIdRef = useRef(sessionId); | ||
| const wasOpenRef = useRef(false); | ||
| const wasEverLoadingRef = useRef(isLoadingSession); | ||
| const hasMessages = messages.length > 0; |
There was a problem hiding this comment.
🤖 🟡 medium (architect/Stale ref on session change)
wasEverLoadingRef is set to true when isLoadingSession is true but never reset on session change. If a user navigates from a loading session to a fresh one that was never loading, the stale true value gates readiness until messages arrive unnecessarily.
Suggestion: Add wasEverLoadingRef.current = false; inside the session-change effect (around line 45) alongside the other resets.
| // ── Card-based auto-open tracking ─────────────────────────────────── | ||
| // Module-level state — not in Zustand to avoid unnecessary re-renders. | ||
| // ArtifactCard calls registerArtifactForAutoOpen on mount; the store | ||
| // decides whether to auto-open based on these flags. |
There was a problem hiding this comment.
🤖 🟢 low (architect/Shadow state design)
Three module-level mutable variables (_autoOpenKnownIds, _autoOpenReady, _autoOpenUserClosed) form a shadow state system invisible to Zustand devtools. Acceptable for perf but increases cognitive overhead.
Suggestion: Consider encapsulating in a small AutoOpenState class with a single reset() method if more variables are added in the future.
| }; | ||
| }), | ||
|
|
||
| // ── Card-based auto-open actions ───────────────────────────────── |
There was a problem hiding this comment.
🤖 🟢 low (product/UX: rapid artifact switching)
If an agent creates multiple artifacts in quick succession, each card mount calls registerArtifactForAutoOpen → openArtifact, causing rapid panel content switching. The user sees the active artifact change multiple times in under a second.
Suggestion: Consider debouncing auto-open or only auto-opening the last artifact in a batch (e.g., via a short setTimeout that gets cleared on subsequent registrations).
| // Mark auto-open as ready once the session is fully loaded. | ||
| // | ||
| // React fires child effects (ArtifactCard) before parent effects (this hook), | ||
| // so all existing cards have already called registerArtifactForAutoOpen by the |
There was a problem hiding this comment.
🤖 🟢 low (product/UX: stale loading ref)
wasEverLoadingRef is never reset on session change. If session A loaded (wasEverLoading=true), then session B starts fresh (isLoadingSession=false, messages=[]), the guard at line 81 blocks readiness until messages arrive — which may never happen in a brand-new empty session, preventing auto-open of the first agent artifact.
Suggestion: Reset wasEverLoadingRef.current = false in the session-change effect (around line 55) alongside the other resets.
| artifactPanel: { ...state.artifactPanel, activeArtifact: ref }, | ||
| })); | ||
| } | ||
| return; |
There was a problem hiding this comment.
🤖 🟢 low (product/Accessibility: focus management)
When openArtifact is called via auto-open, the panel appears but focus remains in the chat area. Screen reader users receive no notification that new content appeared.
Suggestion: Add an aria-live="polite" region to the artifact panel or programmatically announce the auto-open event.
|
|
||
| const prevSessionIdRef = useRef(sessionId); | ||
| const wasOpenRef = useRef(false); | ||
| const wasEverLoadingRef = useRef(isLoadingSession); |
There was a problem hiding this comment.
🤖 🟢 low (product/UX: close-detection coupling)
The user-close detection (isOpen true→false) fires for programmatic closes too (e.g., session-change resetArtifactPanel). It relies on the session-change effect running afterward to call resetAutoOpenState, clearing the false positive. This ordering dependency is implicit and fragile.
Suggestion: Guard the close-detection with a check like if (sessionId === prevSessionIdRef.current) so programmatic session-change resets don't trigger user-close suppression.
| }; | ||
| }), | ||
|
|
||
| // ── Card-based auto-open actions ───────────────────────────────── |
There was a problem hiding this comment.
🤖 🟢 low (discussion/coverage gap)
Codecov reports 17 lines missing coverage in this PR (75.71% patch). The registerArtifactForAutoOpen store action's metadata upgrade path and edge cases lack direct unit test coverage beyond the happy path.
Suggestion: Consider adding edge-case tests for the metadata upgrade logic (e.g. when active artifact is not the same ID as the registering ref).
## AutoPilot Scheduling, New Design & Out of Beta Changelog covering platform versions `v0.6.59` through `v0.6.63` (May 7 – June 10, 2026). ### Featured sections - **AutoPilot major upgrades** — native scheduling (#13190), self-distilled skills registry (#13195), message queuing (#12841) - **New login & signup** — animated panel, aurora, integrations marquee (#13169) - **Subscriptions out of beta** — plans & payments fully live (#12935) - **Settings rebuilt + profile dropdown** — cleaner layout, integrations tab, quick-action menu (#13138, #12976) ### Improvements listed (not featured) - Trigger On Anything (#12740) - Export Chat as Markdown (#13070) - Auto-open artifact panel (#12997) - Slack block (#13008) - Cost breakdown in briefing panel (#13129) - Session sidebar pagination (#13128) - Faster first response in AutoPilot (#12828) ### Files changed - `docs/platform/changelog/may-7-june-10-2026.md` — new changelog page - `docs/platform/.gitbook/assets/` — 5 new hero images - `docs/platform/SUMMARY.md` — new entry at top - `docs/platform/changelog/README.md` — new row at top of table




Why / What / How
Why: The artifact side panel never auto-opened when Autopilot generated a new artifact — users had to manually click the artifact card to see their result. This made the feature feel broken.
What: Implements card-based auto-open for the artifact panel. Each
ArtifactCardregisters itself on mount via the Zustand store, which decides whether to auto-open based on readiness, user-close suppression, and agent origin. Explicit user closes are respected: once the user dismisses the panel in a session, it won't auto-open again for that session (but resets naturally on session switch).How:
ArtifactCardcallsregisterArtifactForAutoOpen(ref)on mount — the store tracks known IDs and auto-opens only genuinely new agent artifacts_autoOpenKnownIds,_autoOpenReady,_autoOpenUserClosedkept outside Zustand to avoid re-rendersuseAutoOpenArtifactshook manages lifecycle — defers readiness until messages hydrate (prevents false opens on session load), gates on feature flag and session IDisOpentrue→false transition sets_autoOpenUserClosed, suppressing auto-open for the rest of the sessionextractWorkspaceArtifactsrejects partial IDs during character-by-character streamingclearCopilotLocalDatareset: Module-level auto-open state is cleared alongside Zustand store stateChanges 🏗️
store.ts— Module-level auto-open tracking vars; 4 new store actions (registerArtifactForAutoOpen,setAutoOpenReady,markUserClosedForAutoOpen,resetAutoOpenState); removedisPreviewableArtifactgate fromopenArtifact;clearCopilotLocalDataclears module-level stateArtifactCard.tsx—useEffectcallsregisterArtifactForAutoOpenon mount; combinedisOpen+activeIDinto derivedisActiveselectoruseAutoOpenArtifacts.ts— Complete rewrite: lifecycle management only (session change reset, user-close detection, readiness gating, unmount cleanup)helpers.ts— HoistedFULL_UUIDregex; UUID validation filter; reorderedgetMessageArtifactsto process file parts first with Map dedupuseAutoOpenArtifacts.test.ts— 15 tests across 2 describe blocks (hook lifecycle + store unit tests)store.test.ts— UpdatedopenArtifacttest for removed previewability gateChatContainer.tsx— Updated hook call to passmessages,isLoadingSession,isArtifactsEnabledChecklist 📋
For code changes:
clearCopilotLocalDataproperly resets auto-open state