-
Notifications
You must be signed in to change notification settings - Fork 607
[feat] Route phones to /m behind an off-by-default flag (5/12) #5684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/mobile-image-and-ci
Are you sure you want to change the base?
Changes from all commits
e906d68
34d5d57
5dfbd1f
bf159e1
1e88167
c61a6c9
c4c170f
e4893b7
20368ef
5b95ab5
01023c0
a8f89ae
29f6858
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,7 +36,7 @@ headless chat core shared between desktop and mobile skins). | |
| | [plans/2026-07-12-wp0-sessions-query-and-stamping.md](./plans/2026-07-12-wp0-sessions-query-and-stamping.md) | WP0 residual plan — **EXECUTED** (see banner: re-audit corrections + execution deltas) | | ||
| | [plans/2026-07-12-wp3a-chat-headless-core.md](./plans/2026-07-12-wp3a-chat-headless-core.md) | WP3a plan — **EXECUTED under copy-extraction** (see banners: strategy change + task mapping) | | ||
| | [plans/2026-07-25-wp1-infra-tail.md](./plans/2026-07-25-wp1-infra-tail.md) | WP1 infra tail (prod image CI, compose, run.sh) — **EXECUTED** (Tasks 1-5, 7); fixed the latent entrypoint crash in the unbuilt mobile image. Only the first `workflow_dispatch` publish (Task 7 runbook) is still pending, and it's post-merge by design | | ||
| | [plans/2026-07-26-wp5-device-gate.md](./plans/2026-07-26-wp5-device-gate.md) | WP5 device gate (flag-gated middleware, both directions) — **READY TO EXECUTE**; default-off, T8 banner-retirement deferred to flag-flip | | ||
| | [plans/2026-07-26-wp5-device-gate.md](./plans/2026-07-26-wp5-device-gate.md) | WP5 device gate (flag-gated middleware, both directions) — **EXECUTED** (Tasks T1-T7); default-off, T8 banner-retirement deferred to flag-flip | | ||
|
|
||
| Wave-2 plans (WP2 auth + project drawer, WP3b mobile chat skin, WP4 product pages, WP5 device | ||
| gate) are **deliberately unwritten** — they must be planned against the real wave-1 code and the | ||
|
|
@@ -65,6 +65,10 @@ What works right now: `cd web && pnpm dev-mobile` → http://localhost:3000/m re | |
| shell (light+dark from the bridged palette); `pnpm build-mobile` produces a standalone server; | ||
| `pnpm --filter @agenta/mobile lint` enforces the bans + token sync; the dev compose stacks have | ||
| a routable `web-mobile` service (needs a dev-image rebuild to pick up the Dockerfile changes). | ||
| Opt-in in dev too: `run.sh --dev --with-mobile` (originally it rode `with-web` and auto-started, | ||
| but a live dev run showed the second Next dev server pushes an 8GB Docker VM into OOM-killing | ||
| the main web app's first big Turbopack compile — dmesg-confirmed `next-server` kills at ~4.5GB | ||
| RSS. Running both dev servers comfortably wants a 12GB+ VM). | ||
|
|
||
| ### WP0 residual — COMPLETE (2026-07-25, 9 commits, all dual-reviewed) | ||
|
|
||
|
|
@@ -147,6 +151,71 @@ green. Task 5 re-verified (didn't re-add) that mobile lint and `@agenta/chat` un | |
| already reached by the existing generic CI mechanisms (workflows 11 and 12); only the mobile | ||
| image build and `@agenta/mobile` typecheck needed a new job. | ||
|
|
||
| ### WP5 device gate — EXECUTED (2026-07-26, 5 commits) | ||
|
|
||
| Ships the mobile device gate (design.md "Gate and routing") behind a runtime flag, | ||
| `AGENTA_MOBILE_GATE`, **default off**: with the flag off, request behavior is byte-identical to | ||
| today. `NoMobilePageWrapper` retirement (T8) is specified but deliberately **not executed** — | ||
| it ships only in the deployment window where the flag is actually flipped on. See | ||
| [plans/2026-07-26-wp5-device-gate.md](./plans/2026-07-26-wp5-device-gate.md) for the full task | ||
| breakdown and grounding facts. | ||
|
|
||
| | Commit | Content | | ||
| |--------|---------| | ||
| | `cf272e1227` | T1: `@agenta/shared/utils/mobileGate` — pure, framework-free decision core (detection, deep-link maps, cookie semantics, documented exceptions); 27 unit tests in the package's vitest harness | | ||
| | `6b3aaf5654` | T2: `web/oss/src/middleware.ts` + `web/ee/src/middleware.ts` — twin desktop forward-gate adapters (byte-identical, both NEW files) wrapping the shared core | | ||
| | `2df5e4d2a1` | T3: `web/mobile/src/middleware.ts` — reverse-gate middleware carrying a declared verbatim copy of the reverse-gate subset (mobile has zero workspace deps until WP2), new minimal mobile vitest harness, and the "View desktop site" `?view=desktop` escape link on the placeholder page | | ||
| | `7be0b8d528` | T4: plumb `AGENTA_MOBILE_GATE` through dev + gh compose files (default `false`), documented in both dev env examples | | ||
| | `9ac651525f` | T6: self-skipping Playwright UA-emulation smoke (`web/oss/tests/playwright/acceptance/mobile-gate/gate.spec.ts`), 6 tests, skips unless the runner asserts `AGENTA_MOBILE_GATE=true` | | ||
|
Comment on lines
+154
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Reconcile the WP5 commit record. The heading says five commits and the table lists five commits. The section also claims T1-T7 executed and later refers to a six-commit review. Add the T7 documentation commit and update the count, or correct the execution claim. Also applies to: 182-182 |
||
|
|
||
| **Verification highlights:** | ||
|
|
||
| - Build proof: all three apps (`oss`, `ee`, `mobile`) print a `ƒ Middleware` row after adding | ||
| their respective `src/middleware.ts`, confirming Next 15.5.18 picks up the placement. | ||
| - Zero new tsc signatures in `@agenta/oss` or `@agenta/ee` after wiring the middleware (T2). | ||
| Scope note from the combined post-execution review: the T6 Playwright spec itself adds 9 | ||
| signatures to the `@agenta/oss` tsc run (TS2307 `@playwright/test` + implicit-any bindings) — | ||
| the same error class every existing acceptance spec under `tests/playwright/` already | ||
| produces, because playwright specs are type-checked by the `web/tests` harness, not oss tsc. | ||
| Accepted as precedented noise; the clean fix (excluding `tests/playwright` in | ||
| `web/oss/tsconfig.json`) is a separate cleanup, not part of this WP. | ||
| - Combined six-commit review verdict: **approve**. Every code block landed byte-identical to | ||
| the plan, the desktop matcher regex was independently confirmed correct against the compiled | ||
| middleware manifest (`/m` and `/m/*` excluded; `/models`-style paths still gated), and the | ||
| middleware bundle carries only the gate core (no transitive leaks). Two deferred hardening | ||
| notes for the agenta_cloud PR: make the gate cookies `secure` conditional on the forwarded | ||
| proto and add `httpOnly` (safe — nothing client-side reads them), and note that EE's first | ||
| deploy with these commits is the first live `ƒ Middleware` proof for EE (its local build | ||
| predates the middleware; the file is a byte-twin of the verified OSS one). | ||
| - **T5 live proof** (the load-bearing verification): same standalone binary, two runs, no | ||
| rebuild between them. Flag on (`AGENTA_MOBILE_GATE=true`): mobile UA on `/w` → `307` to `/m/`, | ||
| desktop UA on `/w` → `200`. Same binary, flag unset: mobile UA on `/w` → `200`, no redirect — | ||
| proving `process.env` in middleware is read at request time on the pinned standalone server, | ||
| not build-inlined. Also surfaced a **basePath-stripping observation**: at runtime Next strips | ||
| the `/m` basePath from `nextUrl.pathname` before the mobile middleware handler runs, but the | ||
| handler normalizes defensively either way (needed for unit tests, which construct | ||
| `NextRequest` directly and still see the `/m` prefix). | ||
| - **Live QA found two gate defects the review missed (both fixed):** (1) Turbopack's DEV | ||
| middleware sandbox exposes only `.env`-file vars, not the container's process env, so | ||
| `AGENTA_MOBILE_GATE` read `undefined` in `next dev` even with the container env set — dev | ||
| compose commands now mirror the flag into `.env.development.local` at container start | ||
| (prod standalone is unaffected; T5's runtime-read proof stands). (2) With `basePath`, the | ||
| bare root `/m` never matched the `"/((?!...).*)"` matcher (the root strips to an empty | ||
| string), leaving the landing page ungated in BOTH dev and prod — the matcher now carries an | ||
| explicit `"/"` entry. Unit tests construct `NextRequest` directly and bypass Next's matcher | ||
| layer entirely, which is why 27+8 green tests missed it; only a live end-to-end probe | ||
| caught both. Desktop twins are unaffected (no basePath; `/` 308s into gated `/w`). | ||
| - **T6 spec self-skip.** `--list` (which does not invoke `global-setup`) confirms the spec | ||
| discovers exactly the expected 6 tests. A real (non-`--list`) run against this worktree with | ||
| no stack running was attempted to observe the runtime skip directly, but `global-setup` | ||
| unconditionally authenticates against `AGENTA_WEB_URL` before any per-test `test.skip` logic | ||
| runs, so it fails with `ERR_CONNECTION_REFUSED` rather than reporting `6 skipped` — exactly the | ||
| fallback the plan anticipated. With the flag confirmed unset in the runner env (the CI | ||
| default), the `test.skip(!gateEnabled, ...)` predicate is proven to evaluate `true`, so the | ||
| 6-skipped outcome is correct by construction; observing it as a live Playwright report is an | ||
| operator step against a running stack (flag-on run is likewise an operator step — see Open | ||
| items below). | ||
|
|
||
| ## Resume runbook (from here) | ||
|
|
||
| 1. **Plan wave-2** against the real code (WP2 auth/drawer → WP3b skin → WP4 pages → WP5 gate). | ||
|
|
@@ -201,6 +270,14 @@ pnpm dev-mobile # → http://localhost:3000/m, check light+dark | |
| - **Design-doc staleness:** `docs/designs/sessions/**` predates the streams-merge/turns model; | ||
| don't trust it over the code. The memory file `project_agenta_mobile_discovery` (assistant | ||
| memory) mirrors this handoff. | ||
| - **WP5 device gate flag-flip runbook (not yet run):** once WP2 (mobile auth) and WP4 (product | ||
| pages) are live, per deployment: set `AGENTA_MOBILE_GATE=true` in that deployment's env file, | ||
| recreate the `web`/`web-mobile` services, run the T6 Playwright smoke | ||
| (`web/oss/tests/playwright/acceptance/mobile-gate/gate.spec.ts`) against it to confirm 6 | ||
| passed, then land T8 (the prepared, not-yet-executed `NoMobilePageWrapper` retirement commit) | ||
| from [plans/2026-07-26-wp5-device-gate.md](./plans/2026-07-26-wp5-device-gate.md). T8 remains | ||
| **specified but unexecuted** in that plan by design — it is coupled to this flip, not to WP5 | ||
| landing. | ||
|
|
||
| ## Follow-up tracks (post-wave-1, explicitly out of scope for now) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| # `@agenta/chat` headless core — dissection & contract | ||
|
|
||
| Companion to [design.md](./design.md) (decision g). Grounded in a line-level dissection of the | ||
| current `AgentChatSlice` (2026-07-12). This is the working reference for WP3a. | ||
|
|
||
| Legend: **E** = Engine (packaged/pure, reuse as-is) · **B** = Behavior (belongs in the headless | ||
| layer; today inline in components) · **P** = Presentation (skin owns). | ||
|
|
||
| ## 1. Classification of current responsibilities | ||
|
|
||
| | Responsibility | Class | Where it lives today | | ||
| |---|---|---| | ||
| | Stream transport (stream↔batch negotiation, batch replay) | E | `assets/AgentChatTransport.ts` + `createNegotiatingFetch`, `agentChannelModeAtom` (`@agenta/playground`) | | ||
| | Request building (config/auth/references → body) | E | `buildAgentRequest` (`@agenta/playground`) | | ||
| | Turn capture, resume-after-approval, queue release gates | E | `@agenta/playground` `execution/*` (pure) | | ||
| | Render-hint map (`data-render` → `render.kind`) | E | `buildRenderMap`, `renderKindFor` (`execution/renderMap.ts`) | | ||
| | Transcript replay (records → `UIMessage[]`) | E | `assets/transcriptToMessages.ts` + `loadSession.ts` | | ||
| | Tool display resolution / value formatting | E | `assets/toolDisplay.ts`, `assets/toolFormat.ts` (pure registries) | | ||
| | Tool output summarization | B | inline in `ToolActivity.tsx:49-89` — pure logic trapped in a presentational file | | ||
| | Attachment validation / encoding | E | `assets/attachments.ts`, `assets/files.ts` (File-based, pure) | | ||
| | Attachment **state** shape | B/leak | antd `UploadFile` in `AgentConversation.tsx:358-370` and `state/sessionEphemera.ts:1,29` | | ||
| | Trace/usage extraction from metadata | E | `assets/trace.ts` | | ||
| | Session model + ephemera + expand state | E (leaks) | `state/sessions.ts`, `state/sessionEphemera.ts` (holds `UploadFile` + virtuoso `StateSnapshot`), `state/expandState.ts` | | ||
| | Turn grouping (active turn, lastUserIndex) | B | `AgentConversation.tsx:1677-1685` | | ||
| | Empty-turn collapsing predicates | B | `AgentConversation.tsx:167-179,1728` | | ||
| | Turn render model (tool folding, superseded-gate dedup, client-tool split) | B | `AgentMessage.tsx:329-416` | | ||
| | hasAnswer/noResponse/error derivation | B | `AgentMessage.tsx:270-312` | | ||
| | Client-tool dispatch registry | E→registry | `components/clientTools/{registry,meta}.tsx` (widgets are P) | | ||
| | Approval extraction (`getPendingApprovals`) | B | `ApprovalDock.tsx:33-45` | | ||
| | Approval body registry (by tool name) | E→registry | `components/approvals/registry.tsx` (bodies are P) | | ||
| | Queue orchestration | E (hook) | `hooks/useAgentChatQueue.ts` — the template for headless hooks | | ||
| | Model-key gate | E (hook) | `hooks/useAgentModelKeyStatus.ts` | | ||
| | Hydration sequencing (seed → skeleton vs hero → server hydrate → SWR revalidate) | B | `AgentConversation.tsx:571-603,891-913` | | ||
| | Session-status derivation + publish (error>awaiting>running>idle) | B | `AgentConversation.tsx:561,991-1004` | | ||
| | Error stamping onto turn | B | `AgentConversation.tsx:1025-1052` + `parseAgentRunError:191` | | ||
| | Persist-on-settle + expand-prune | B | `AgentConversation.tsx:1055-1082` | | ||
| | Self-commit / committed-revision handling | B | `AgentConversation.tsx:1090-1118` | | ||
| | Rewind orchestration | B (+E core, P confirm) | `AgentConversation.tsx:1637-1672`; pure scan in `assets/rewind.ts`; `modal.confirm` is P | | ||
| | Client-tool output settle → `addToolOutput` | B | `AgentConversation.tsx:616-635` | | ||
| | Elicitation parsing/validation/envelopes | E | `@agenta/shared/utils` (already extracted; only field rendering is antd) | | ||
| | Scroll engineering (SC-1..4, anchor, jump pill, virtuoso) | B, desktop-only | `AgentConversation.tsx:465-488,1140-1497` (~350 lines) — mobile uses native scroll | | ||
| | Bubble/avatar/toolbar, tool rows, approval chrome, queued chips, tray, empty/skeletons, markdown | P | `components/*`, `assets/markdown.tsx` (antd/x + Prism) | | ||
| | Right panel, turn inspector, onboarding hero, template strip | P, desktop/onboarding-only | already null-gated | | ||
|
|
||
| `AgentConversation.tsx` is roughly **65% behavior / 35% presentation**; the behavior is almost | ||
| entirely app-agnostic. Onboarding, build mode, inspectors, and virtualization are all cleanly | ||
| gated (nullable context / atoms / env flags) — the mobile skin simply omits them. | ||
|
|
||
| ## 2. antd/desktop type leaks to neutralize | ||
|
|
||
| 1. **`UploadFile` as canonical attachment state** — `AgentConversation.tsx:358-370,499-516`, | ||
| `state/sessionEphemera.ts:1,29`, `ComposerAttachments.tsx:13,26`. Core moves to `File[]` (or | ||
| neutral `PendingAttachment{file, uid, name}`); `filesToParts`/`validateIncoming` are already | ||
| File-based. | ||
| 2. **`Bubble<ReactNode>` prop shaping** in `AgentMessage.tsx:630-648` + the loading-bubble | ||
| placeholders (`AgentConversation.tsx:1925-1930`) — stays in the desktop skin. | ||
| 3. **antd-x `Actions` items as toolbar data** — `AgentMessage.tsx:561-618`. Contract uses neutral | ||
| `{key, label, icon, onClick}[]` action descriptors. | ||
| 4. **react-virtuoso types in shared state** — `StateSnapshot` in `sessionEphemera.ts:2,21`, | ||
| `state/virtualization.ts`. Desktop-local; moves out of the shared store. | ||
|
|
||
| Minor: `Modal.useModal` for the rewind confirm (core returns a `RewindPlan`, skin renders the | ||
| confirm), `App.useApp` toasts, antd `Form` inside `ElicitationWidget` (contract logic already in | ||
| `@agenta/shared/utils` — the cleanest existing example of the desired split). | ||
|
|
||
| ## 3. Headless hooks (Layer 2 API sketch) | ||
|
|
||
| ```ts | ||
| useAgentConversation({entityId, sessionId}): { | ||
| messages: UIMessage[] | ||
| status: "ready" | "submitted" | "streaming" | "error" | ||
| runStatus: "idle" | "running" | "awaiting" | "error" | ||
| error?: ParsedRunError | ||
| turns: TurnViewModel[] // pre-grouped: active turn, empty-collapse | ||
| send(input: {text: string; files?: File[]}): void // routes through the queue | ||
| stop(): void | ||
| regenerate(id: string): void | ||
| rewind(message: UIMessage): RewindPlan // {sideEffects[], confirm()} — skin renders confirm | ||
| isHydrating: boolean | ||
| isEmpty: boolean | ||
| } | ||
|
|
||
| useTurnRenderModel(message, ctx): RenderItem[] // lifted from AgentMessage.tsx:329-416 | ||
| useComposerAttachments({sessionId, limits}): {files, rejections, add, remove, clear, atMax, toParts} | ||
| useSessionHydration({sessionId}) | ||
| useApprovalDock({messages, onRespond}): {current, count, respond, approveAll, renderer} | ||
| useClientToolDispatch() | ||
| useAgentChatQueue(...) // exists — moves in | ||
| useAgentModelKeyStatus(...) // exists — moves in | ||
| useConversationScroll(ref, {messages, status}) // DESKTOP-ONLY opt-in | ||
|
Comment on lines
+83
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)(chat-headless-contract\.md|.*WP3.*|.*approval.*|.*Approvall.*|.*Approval.*)' || true
echo
echo "== target lines =="
if [ -f docs/design/agenta-mobile/chat-headless-contract.md ]; then
sed -n '1,130p' docs/design/agenta-mobile/chat-headless-contract.md | cat -n
fi
echo
echo "== search useApprovalDock =="
rg -n "useApprovalDock|approval|Approval|approveAll|renderer" -S . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -n 200
echo
echo "== search WP3 contract snippets =="
rg -n "function useApprovalDock|useApprovalDock\\(|approveAll|registry|renderer|render" docs/design/agenta-mobile -S . || trueRepository: Agenta-AI/agenta Length of output: 50373 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== changed files if available =="
git diff --name-only -- docs/design/agenta-mobile/chat-headless-contract.md || true
echo
echo "== staged/unstaged diff around target =="
git diff -- docs/design/agenta-mobile/chat-headless-contract.md | sed -n '1,220p' || true
echo
echo "== locate markdown by exact filename variants =="
fd -a 'chat-headless-contract\.md$' . || trueRepository: Agenta-AI/agenta Length of output: 350 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== target document relevant sections =="
sed -n '80,112p' docs/design/agenta-mobile/chat-headless-contract.md | cat -n
echo
echo "== WP3 plan approval hook sections =="
sed -n '680,705p' docs/design/agenta-mobile/plans/2026-07-12-wp3a-chat-headless-core.md | cat -n
echo
echo "== WP3 plan approval registry section =="
sed -n '705,740p' docs/design/agenta-mobile/plans/2026-07-12-wp3a-chat-headless-core.md | cat -n
echo
echo "== README summary references =="
sed -n '120,135p' docs/design/agenta-mobile/README.md | cat -nRepository: Agenta-AI/agenta Length of output: 11550 Remove
|
||
| ``` | ||
|
|
||
| ## 4. Skin slot contract (Layer 3) | ||
|
|
||
| Every slot receives data + callbacks only — no antd/x types. Registry keys are the existing | ||
| ones: `renderKindFor(...)` → client-tool widget; tool name → approval body; | ||
| `resolveToolDisplay(rawName)` → label/source/kind; expand keys from `expandState.ts`. | ||
|
|
||
| | Slot | Props (from behavior layer) | | ||
| |---|---| | ||
| | `MessageBubble` | `{role, variant, avatar, children, isError}` | | ||
| | `TextPart` | `{markdown}` | | ||
| | `ReasoningPart` | `{text, streaming, expanded, onToggle}` | | ||
| | `FilePart` | `{name, kind: FileKind, url, mediaType}` | | ||
| | `SourcesList` | `{sources: {url, title?}[]}` | | ||
| | `ToolActivityGroup` | `{parts, mode: "summary"\|"live"\|"detailed", summaryLabel, failedCount, expanded, onToggle, onViewTrace?}` | | ||
| | `ToolRow` | `{name, displayLabel, source?, status, midText, io?, expanded, onToggle}` | | ||
| | `ApprovalCard` | `{current, count, headline?, approveLabel?, Body?, onApprove, onDeny, onApproveAll, onViewTrace?}` | | ||
| | approvals registry entry | tool name → `{Body(input, entityId, fallback), headline?, approveLabel?}` | | ||
| | clientTool registry entry | `render.kind` → toolName → widget `{meta, settle, degradedEarlierInTurn}` | | ||
| | Elicitation fields | per schema kind (string/number/enum/date/boolean/array); engine parses, skin draws | | ||
| | `ErrorPart` | `{text, expanded, onToggle}` | | ||
| | `NoResponseNotice` | `{}` | | ||
| | `QueuedChip` / `QueuedList` | `{queued, onRemove, onClear}` | | ||
| | `Composer` | `{onSubmit(text), disabled, streaming, onStop, placeholder, initialMarkdown, onChange, onPasteFile, prefix, header, trailing}` | | ||
| | `AttachmentTray` | `{files, rejections, limits, onAdd, onRemove, onDismissRejections}` | | ||
| | `EmptyState` | `{entityId, onStart, firstRunPrompt?, canStart, onPrefill?}` | | ||
| | Skeletons | transcript / composer / conversation | | ||
| | `MessageToolbar` | `{actions: {key, label, icon, onClick}[]}` | | ||
| | `JumpToLatestPill` (desktop) | `{visible, onClick}` | | ||
| | `WorkingIndicator`, `MessageTimestamp`, `TraceMetrics` | `{}` / `{createdAt}` / `{traceId?, usage?}` | | ||
| | `DropOverlay`, `DockContainer` | layout slots | | ||
|
|
||
| ## 5. WP3a extraction order | ||
|
|
||
| 1. Neutralize the four type leaks (§2) — behavior-neutral, OSS keeps working. | ||
| 2. Lift the pure blocks (turn render model, status/error derivation, tool summarization, | ||
| approval extraction, hydration) into `@agenta/chat`; OSS re-imports them immediately | ||
| (before/after fixture tests prove identical output). | ||
| 3. Assemble `useAgentConversation` from the lifted blocks + engine (mobile-first consumer). | ||
| 4. Generalize the three registries so skins register values against shared keys. | ||
| 5. Desktop re-plumb of the remaining inline host (scroll opt-in, JSX assembly) = follow-up | ||
| track, and the contract's acceptance test. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use the documented Compose entrypoint path.
The command does not state a working directory. Use
hosting/docker-compose/run.shand specify the required OSS or EE edition with the dev and mobile options.As per coding guidelines, run the local dev stack through
hosting/docker-compose/run.shand use the same edition and image mode as the loaded environment.Source: Coding guidelines