Uh oh!
There was an error while loading. Please reload this page.
feat(console-ai): unify AI chat — one conversation key + one surface→agent resolver (ADR-0057 P1+P2) - #2414
Merged
Conversation
…DR-0057 P1)
The console forked the AI conversation across shells: the Studio design copilot
scoped its thread as `studio:${packageId}:${agent}` while the full-page
`/ai/build` focus view scoped on the agent alone, so the same app showed an
empty "Build with AI" copilot beside an active full-page build thread.
Per ADR-0057 (surface = view · conversation = model · product = binding axis),
conversations are now keyed on `(user, app, product)`:
- New pure, unit-tested `chatConversationScope({ appId, product })` +
`chatProductOfAgent(name)` helper (hooks/chatScope.ts) — the single place the
scope key is formed. `product` is the ADR-0063 axis (ask | build), derived
from the resolved agent, never a per-surface choice.
- StudioAiCopilot and AiChatPage both resolve `app:${packageId}:${product}` for a
package-scoped surface, so the Studio copilot editing package X and the
`/ai/build?package=X` "Edit with AI" focus view resume ONE shared thread; the
legacy `studio:` surface prefix is dropped. A generic `/ai/:agent` visit with
no `?package=` degrades to the product alone — unchanged.
- AiChatPage's URL-mirror guard now compares the resolved scope against the new
scope value instead of the raw agent name.
Enablement stays on the single access-filtered agent-catalog gate
(useAiSurfaceEnabled, ADR-0068). No layout change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJKsT9dvjxgVSPYid8EtTQThe latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
The console re-implemented the ADR-0063 surface→agent chain in ~5 places, each
spelled slightly differently, and ConsoleLayout carried an AI-Studio-off
downgrade special case that existed nowhere else. Collapse them into one pure,
unit-tested resolver so ADR-0063 (exactly two products ask/build, bound by
surface — no roster, no per-turn classifier) is a STRUCTURAL guarantee.
- New hooks/surfaceAgent.ts: resolveSurfaceAgent(surface, { agents,
appDefaultAgent, aiStudioEnabled }) + SURFACE_DEFAULT. app.defaultAgent is
bounded to ask/build (alias-aware) — a withdrawn tenant custom agent is
rejected, not passed through, so no roster is representable. The
AI-Studio-off build→ask downgrade is folded in ONCE.
- StudioAiCopilot (studio-build→build) and the console FAB (default→ask) resolve
through it. The FAB keeps #771's "prefer build when the catalog unlocks it and
nothing pinned a product" by passing that as its default PRODUCT input, so the
resolver still owns bounding + the downgrade — which now also applies to the
#771 preference (closing the leak where an authoring-disabled deployment could
still open build).
- ConsoleLayout's bespoke downgrade is deleted; it passes the raw
app.defaultAgent and the resolver downgrades.
Ships a unit table proving the ADR-0063 rows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJKsT9dvjxgVSPYid8EtTQos-zhuang
marked this pull request as ready for review
July 13, 2026 05:30
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lands the two sign-off-free phases of ADR-0057 — Console AI chat unification (work order #2412, epic #2409). Both are reversible; the two founder-decision phases (P3 dock / P4 handoff) are follow-ups.
P1 — key conversations on
(user, app, product), not surfaceThe console forked the AI conversation across shells: the Studio copilot scoped
studio:${packageId}:${agent}while the full-page/ai/buildfocus view scoped on the agent alone — the same app showed an empty "Build with AI" copilot beside an active full-page build thread (looks like data loss).hooks/chatScope.ts(pure, unit-tested):chatConversationScope({ appId, product })+chatProductOfAgent(name)— the single place the scope key is formed.productis the ADR-0063 axis (ask|build), derived from the resolved agent, never per-surface.StudioAiCopilotand full-pageAiChatPageboth resolveapp:${packageId}:${product}, so the Studio copilot editing package X and/ai/build?package=X("Edit with AI", ADR-0070) resume one shared thread. Legacystudio:prefix dropped. Generic/ai/:agent(no?package=) degrades to the product alone — unchanged.useAiSurfaceEnabled(ADR-0068); no change needed.P2 — one declarative surface→agent resolver
~5 divergent re-implementations of the ADR-0063 chain (and a
ConsoleLayoutdowngrade special case that existed nowhere else) collapse into one pure resolver, making ADR-0063 a structural guarantee.hooks/surfaceAgent.ts:resolveSurfaceAgent(surface, { agents, appDefaultAgent, aiStudioEnabled })+SURFACE_DEFAULT.app.defaultAgentis bounded to ask/build (alias-aware) — a withdrawn tenant custom agent is rejected, so no roster is representable (open question Add default props to all components to prevent collapse in designer #4). The AI-Studio-offbuild→askdowngrade is folded in once.StudioAiCopilot(studio-build→build) and the console FAB (default→ask) resolve through it. The FAB preserves chore(deps): bump lucide-react from 0.574.0 to 0.575.0 #771's "prefer build when the catalog unlocks it and nothing pinned a product" by passing that as its default product input — the resolver still owns bounding + the downgrade, which now also applies to the chore(deps): bump lucide-react from 0.574.0 to 0.575.0 #771 preference (closing the leak where an authoring-disabled deployment could still open build).ConsoleLayout's bespoke downgrade is deleted; it passes the rawapp.defaultAgent.Invariants held
resolveSurfaceAgentreturnsundefined;useAiSurfaceEnabledhides everything).Verification
chatScope.test.ts(shared-thread key invariant + product derivation incl. legacy aliases) andsurfaceAgent.test.ts(the ADR-0063 rows: Studio→build, other→ask, AI-Studio-off downgrade,app.defaultAgentbounded + roster rejected, alias-aware resolution, empty catalog→inert).pnpm --filter @object-ui/app-shell: 267 hooks/layout/studio/console tests green (incl. the two new tables).turbo type-checkclean;turbo build --filter=@object-ui/consoleclean (full-graph integration).Follow-ups
Refs: ADR
docs/adr/0057-console-ai-chat-one-conversation-docked.md(#2411) · work order #2412 · epic #2409.