Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

[ADR-0057] Console AI chat unification — implementation work order (P1–P4, agent-executable) #2412

Closed

Description

@os-zhuang

Single, self-contained work order for the ADR-0057 implementation — written for an agent with no prior conversation context. Rolls up to epic #2409.

Read first: docs/adr/0057-console-ai-chat-one-conversation-docked.md (merged in #2411), plus upstream invariants cloud ADR-0063 (two agents, surface-bound) and cloud ADR-0025 (OSS = MCP only).

Objective

Collapse the console's fragmented AI-chat surfaces into one chat system, on the principle:

surface = view · conversation = model · product (ask / build) = binding axis.

This is NOT a merge of ask and build — cloud ADR-0063 already fixed the agent model (two products, bound by surface, no roster, no per-turn classifier; it reversed ADR-0040's unified classifier — do not reintroduce it). This is objectui console-layer consolidation only. No cloud backend change except the optional deps below.

⛔ Repo workflow (mandatory)

  • Worktree-first. This repo is edited by multiple agents and a PreToolUse hook blocks edits outside a dedicated worktree. Create one: git worktree add ../objectui-<task> -b <branch> main && cd ../objectui-<task> && pnpm install (see AGENTS.md / CLAUDE.md).
  • One PR per phase, reversible, each with an ADR-0054 browser proof. No big-bang: P3 touches the most-used AI entry (the FAB) and the Studio layout.

Current state (starting points — line numbers drift, grep the symbols)

Three shells over one backend (POST /api/v1/ai/agents/:name/chat), forking the conversation:

  • packages/app-shell/src/layout/ConsoleFloatingChatbot.tsx — bottom-right FAB (ask); agent pick ~L915; wired to assistant/assistantBus.ts + useReconcileOnError.
  • packages/app-shell/src/console/ai/AiChatPage.tsx — full-page /ai/build + /ai/ask + Live Canvas (ADR-0037); resolve ~L610; exports ChatPane.
  • packages/app-shell/src/views/studio-design/StudioAiCopilot.tsx — left-docked build copilot (ADR-0080 aiSlot); forks the thread via scope studio:${packageId}:${agent} (~L56); reuses ChatPane.
  • packages/plugin-chatbot/src/renderer.tsx — SDUI type:'chatbot' embedded in runtime end-user apps.

Two state layers: app-shell (useChatConversation, useConversationList, useAiSurface, conversationLanguage, reconcileTurn, assistantBus) vs plugin-chatbot (useObjectChat, useAgents, usePendingActions, useHitlInChat, agentAliases).

~5 divergent surface→agent picks (each re-implements the ADR-0063 chain): StudioAiCopilot.tsx:44, ConsoleFloatingChatbot.tsx:915, ConsoleLayout.tsx:84 (unique !aiStudioEnabled && isBuildAgent → downgrade special case), AiChatPage.tsx:610, layout/agentPicker.ts:46.

Two gates: hooks/useAiSurface.ts (correct — access-filtered agent catalog, ADR-0068) vs discovery.services.ai / isAiEnabled (per-user 403 gap; useAiSurface's docstring explicitly warns against it).

Already shared (don't rebuild): ChatbotEnhanced render body, the /api/v1/ai/agents/:name/chat transport, and the assistantBus context bridge (editor context / open / review / canvas-invalidation signals).

Phases

P1 — one conversation context + one gate (no visible change) — LAND FIRST

  • Introduce ChatSessionProvider (or consolidate into @object-ui/plugin-chatbot) owning agent resolution, conversation binding, list, streaming, pending actions, reconcile. All three shells become thin views over it.
  • Key conversations on (user, app, product) — change StudioAiCopilot's studio:${packageId}:${agent} → app:${packageId}:${product} so the full-page focus view and the docked copilot share ONE thread.
  • Delete isAiEnabled / discovery.services.ai; use useAiSurface everywhere.
  • Acceptance: same thread visible in full-page /ai/build ↔ Studio copilot for one app; seat-less user sees no AI surface; no other visible change.

P2 — declarative surface→agent resolver

const SURFACE_DEFAULT = { 'studio-build': 'build', 'default': 'ask' } as const;
function resolveSurfaceAgent(surface, { catalog, appDefaultAgent, aiStudioEnabled }) {
  const want = appDefaultAgent ?? SURFACE_DEFAULT[surface] ?? 'ask';
  const eff  = !aiStudioEnabled && isBuildAgent(want) ? 'ask' : want; // ConsoleLayout special case, folded in ONCE
  return resolveAgentParam(eff, catalog) ?? resolveDefaultAgentName(catalog);
}
  • Migrate every call site (StudioAiCopilot, ConsoleFloatingChatbot, ConsoleLayout, AiChatPage, agentPicker) to it; delete the scattered picks + the ConsoleLayout downgrade.
  • Acceptance: unit table for ADR-0063 — Studio→build, console/app→ask, aiStudio-off downgrade, app.defaultAgent bounded to ask/build (reject anything else). No roster/classifier representable.

P3 — docked rail + Studio right reflow; retire the FAB — ⚠ needs founder sign-off (dock side)

  • ChatDock: render the shared panel as a right, collapsible, resizable rail, default collapsed (keep the FAB's zero-idle-cost). FAB → launcher / ⌘I toggle.
  • /ai = the same panel maximized (build + Live Canvas), same thread; deep links open the dock maximized.
  • Move the Studio copilot into the shared right dock → Studio reflows to [left: nav/tree] [center: canvas+properties] [right: chat].
  • Runtime end-user apps (SDUI chatbot) keep the bubble — same state code, different chrome.
  • Optional dep objectstack-ai/cloud#816 (render debug/canvas/resume by declared capabilities, not isBuildAgent checks). Non-blocking.
  • Acceptance: chat location identical across console pages; expand/collapse preserves the thread; Studio 3-pane reflow; runtime bubble unchanged.

P4 — ask→build explicit handoff — ⚠ needs founder sign-off (explicit vs seamless); dep cloud#817

  • In ask, a build-shaped request surfaces an explicit "Open in Builder →" carrying the conversation context via the generalized assistantBus (ADR-0063 decline-and-redirect — never a silent re-route into authoring).
  • Dep objectstack-ai/cloud#817 upgrades a context-less handoff to context-carrying.
  • Acceptance: ask thread opens the Builder with context; no authoring ever happens on the ask surface.

Invariants (do not violate)

Verification (end-to-end)

  • Boot the cloud local stack (serves /api/v1/ai/*): cd <cloud> && OBJECTUI_ROOT=<objectui> OS_MULTI_ORG_ENABLED=true CLOUD_PORT=4000 OBJECTOS_PORT=5050 bash scripts/dev-local/run-stack.sh --with-ui --seed --keep --workdir /tmp/os-stack. Needs cloud/scripts/dev-local/.env.local with AI_GATEWAY_API_KEY or the agent catalog is empty.
  • Backend/API checks work headless with the seeded session: curl GET /api/v1/ai/agents → build,ask.
  • UI checks: the better-auth.session_token cookie is httpOnly — can't be JS-injected, and the automation browser tab is a separate Chrome profile from the user's, so UI verification needs a login into the controlled tab (or a maintainer). Backend verification needs no browser.
  • Each phase ships an ADR-0054 UI-testability proof.

Open founder decisions (block P3/P4 only)

  • Dock side + Studio reflow (chat vs properties on the right).
  • Handoff explicit "Open in Builder" vs a more seamless in-place switch.
  • P1/P2 do not depend on these — start there.

Related

Epic #2409 · ADR docs/adr/0057-console-ai-chat-one-conversation-docked.md (#2411) · Cloud deps objectstack-ai/cloud#816 (P3, optional), objectstack-ai/cloud#817 (P4).

Activity

  1. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    Contributor

    维护者裁决(2026-08-03)

    排期:v17 后;开工前先核对 P1/P2 实际完成状态(本裁决不假设其已落地——按各阶段验收标准逐条验证后再派 P3)。摘 needs-user-decision。


    Generated by Claude Code


    Generated by Claude Code

  2. claude commented on Aug 6, 2026

    @claude
    Contributor

    分诊:过时前提检查判定「已全部交付」⇒ 关闭(completed),附否决窗口。

    维护者 2026-08-03 的裁决明确写了一句前置条件:「开工前先核对 P1/P2 实际完成状态(本裁决不假设其已落地——按各阶段验收标准逐条验证后再派 P3)」。本轮执行了这次核对,结论是四个阶段连同收尾清理全部已落地,本工单已无可派发内容。

    逐阶段核验(全部读 origin/main,不读共享工作树)

    阶段 验收标记 main 上的读数
    P1 一个会话上下文 + 一个门 删 isAiEnabled/discovery.services.ai;Studio 不再 fork 线程 ✅ StudioAiCopilot.tsx:64 注释写死「no studio: fork」,scope 已是 (user, package, build);app-shell 内 isAiEnabled 仅存于 useAiSurface.ts 的反面警告文档与 packages/react 的通用 discovery hook
    P2 声明式 surface→agent 解析器 单一 resolveSurfaceAgent ✅ packages/app-shell/src/hooks/surfaceAgent.ts 存在,含配套 __tests__/surfaceAgent.test.ts;模块头写明 ConsoleLayout 的降级特例已 folded in ONCE,与工单 P2 代码草图逐条对应
    P3 右侧 dock + FAB 变启动器 ChatDock;FAB 不再挂浮层 ✅ layout/ChatDock.tsx + layout/ConsoleChatbotFab.tsx 均在;⚠️ layout/ConsoleFloatingChatbot.tsx 已从 main 删除(工单「Current state」把它列为起点文件之一 —— 起点已不复存在)
    P4 显式 handoff #2439 + #2444 ✅ 均已 MERGED(#2444 于 2026-07-13 11:04Z)

    最硬的一条读数:docs/adr/0057-console-ai-chat-one-conversation-docked.md 的 Status 行自陈 ——

    Status: Accepted (2026-07-13) — IMPLEMENTED IN FULL. P1+P2 shipped (#2414), P4 shipped (#2439 / #2444 + cloud#818/#819;reliability follow-ups #2449 + cloud#820), P3 shipped (P3a #2464, P3b #2465, P3c #2467, go-live #2469, follow-ups #2470 — epic #2409);the final cleanup removed the chatDock rollout flag, the console floating-overlay path (ConsoleFloatingChatbot), and the legacy left Studio copilot panel

    即 epic #2409 收尾评论里列的三项遗留(① 翻开 flag 放量、② 清理 PR 删 flag 与死浮层路径、③ ADR Status 翻牌)也已全部完成 —— #2409 本身已于 2026-07-14 关为 completed。

    为什么关闭而不是留 pm:on-hold 等 v17:维护者裁决排期到 v17 后,针对的是尚未开工的 P3。既然 P3 已由 #2464/#2465/#2467/#2469/#2470 交付并完成 go-live 与清理,继续挂着这份工单只会让下一次 sweep 把已交付的工作重新派发一次 —— 工单正文的「Current state」还指向一个已被删除的文件,任何 dev 拿到它都会从一个不存在的起点开工。这正是过时前提检查要拦的形状。

    ⚠️ 否决窗口:若维护者认为工单里仍有未被上述 PR 覆盖的具体条目(例如某条 P1 验收细则实际未达成),重开即可,分诊座位会按剩余项重新定级。本次关闭不涉及任何代码改动,纯状态收敛。

    查重与关联:epic #2409(closed/completed)、#2443(P4 follow-ups,同批分诊,见该单结论)、ADR 单 #2411。⛔ 未发现其它仍在流通的 ADR-0057 派发入口。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions