Skip to content

feat(mobile): live chat, the shared composer and a responsive app shell - #5872

Draft
ardaerzin wants to merge 4 commits into
oss/chat-on-shared-enginefrom
mobile/chat-and-shell
Draft

feat(mobile): live chat, the shared composer and a responsive app shell#5872
ardaerzin wants to merge 4 commits into
oss/chat-on-shared-enginefrom
mobile/chat-and-shell

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

/m gets live chat on the same @agenta/chat engine the desktop now uses, the shared composer,
and a responsive app shell — rather than a mobile-only reimplementation that would drift.
Not run in a browser — static gates only (pnpm lint-fix 24/24, tsc --noEmit clean
for @agenta/shared, ui, entities, entity-ui, settings-ui, oss, ee, mobile).

Stacked on oss/chat-on-shared-engine; review only this lane's diff.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Error Error Aug 10, 2026 2:58pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: b5c9f2c6-19ad-443c-a69e-3c11bb4fcd04

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added mobile project home screens with agents, sessions, upcoming triggers, and automation runs.
    • Added agent overview pages with session history, runs, triggers, and configuration details.
    • Added live agent conversations with streaming, approvals, attachments, stopping, and status indicators.
    • Added improved chat rendering for reasoning, tool activity, errors, and user/assistant messages.
  • Improvements
    • Updated session browsing with shared filtering and navigation.
    • Improved mobile layouts, safe-area handling, responsive styling, and theme consistency.
    • Added flexible chat header subtitles and clearer loading and empty states.

Walkthrough

The mobile app adopts shared workspace packages and design tokens, adds project home and agent overview routes, replaces local session-list management, and introduces live agent conversations with shared composer, approval, turn, and status components.

Changes

Mobile application experience

Layer / File(s) Summary
Shared package and styling foundation
web/mobile/next.config.ts, web/mobile/package.json, web/mobile/scripts/generate-shadcn-tokens.ts, web/mobile/src/styles/globals.css, web/mobile/src/components/ScreenScaffold.tsx
The mobile app now transpiles and depends on shared workspace packages. Shared semantic and control tokens, Tailwind aliases, stylesheet sources, switch utilities, and safe-area handling are added.
Home and agent overview routes
web/mobile/src/pages/w/[workspace_id]/p/[project_id]/apps/index.tsx, web/mobile/src/pages/w/[workspace_id]/p/[project_id]/agents/[agent_id].tsx, web/mobile/src/features/home/*, web/mobile/src/features/agents/*
The app adds project home and agent overview screens. These screens display sessions, agents, automation runs, upcoming triggers, and agent configuration data.
Shared session listing
web/mobile/src/features/sessions/SessionListScreen.tsx, web/mobile/src/features/sessions/*
The session list now uses shared filters and list components within the mobile shell. Local search, pagination, polling, pending filtering, failure handling, row rendering, and scroll restoration are removed.
Live and replay conversation flow
web/mobile/src/features/chat/*
Chat routing now resolves agent entities and selects live or replay rendering. Live conversations support history hydration, streaming, polling, approvals, attachments, sending, stopping, turn rendering, and status indicators. Shared components replace local approval and control markup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MobileRoute
  participant ChatScreen
  participant useAgentEntity
  participant LiveConversation
  participant Composer
  participant ApprovalDock
  MobileRoute->>ChatScreen: Provide session and project identifiers
  ChatScreen->>useAgentEntity: Resolve agent and workflow revision
  useAgentEntity-->>ChatScreen: Return agentId and entityId
  ChatScreen->>LiveConversation: Render live agent conversation
  LiveConversation->>Composer: Submit message or stop streaming
  LiveConversation->>ApprovalDock: Render and submit approval actions
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 60.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: mobile live chat, shared composer, and responsive app shell.
Description check ✅ Passed The description directly explains the mobile live chat, shared engine, composer, app shell, and validation status.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mobile/chat-and-shell

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

❤️ Share

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

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (5)
web/mobile/src/features/sessions/SessionListScreen.tsx (2)

19-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shorten the block comment.

The coding guidelines limit in-code comments to one short line. Longer comments are reserved for surprising constraints such as bugs, races, or ordering requirements. This comment describes design intent, so reduce it to one line.

♻️ Proposed shortening
-/**
- * The sessions page — the SAME shared body and filters panel the desktop page renders
- * (`@agenta/sessions-ui`): one organisation (groups, pins, filters, paging), mobile's shell.
- * Touch keeps row actions always visible (no hover); rows open the mobile chat route.
- */
+// Shared sessions body and filters panel from `@agenta/sessions-ui`, inside the mobile shell.

As per coding guidelines: "Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements."

Source: Coding guidelines


45-46: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Memoize openRow.

openRow is recreated on every render and passed to SessionsListView. If that component or its rows are memoized, the new identity defeats the memoization. Wrap it in useCallback.

♻️ Proposed change
-    const openRow = (vm: SessionRowVm) =>
-        void router.push(`/w/${workspaceId}/p/${projectId}/sessions/${vm.id}`)
+    const openRow = useCallback(
+        (vm: SessionRowVm) =>
+            void router.push(`/w/${workspaceId}/p/${projectId}/sessions/${vm.id}`),
+        [router, workspaceId, projectId],
+    )

Update the import on line 1:

-import {useMemo} from "react"
+import {useCallback, useMemo} from "react"

As per coding guidelines: "Minimize React re-renders with useMemo, useCallback, and React.memo where appropriate; avoid unstable inline functions and objects, especially in lists."

Source: Coding guidelines

web/mobile/src/features/home/HomeScreen.tsx (2)

53-55: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Stabilize the session-row callback.

Each openRow function is recreated on every parent render and is passed to SessionCardList. Use useCallback with base and router dependencies. Verify whether SessionCardList memoizes callback inputs before merge.

  • web/mobile/src/features/home/HomeScreen.tsx#L53-L55: Memoize openRow before passing it to both session lists.
  • web/mobile/src/features/agents/AgentOverviewScreen.tsx#L37-L50: Memoize openRow before passing it to both agent-scoped session lists.

As per coding guidelines, “Minimize React re-renders with useMemo, useCallback, and React.memo where appropriate; avoid unstable inline functions and objects, especially in lists.”

Source: Coding guidelines


45-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shorten nonessential code comments.

These comments restate layout or implementation details. They do not document bugs, races, or ordering constraints. Remove them or reduce each to one short line.

  • web/mobile/src/features/home/HomeScreen.tsx#L45-L49: Reduce the component description to one short line.
  • web/mobile/src/features/home/HomeScreen.tsx#L79-L84: Remove or shorten the layout and shared-list comments.
  • web/mobile/src/features/home/HomeScreen.tsx#L112-L113: Remove or shorten the trigger-section comment.
  • web/mobile/src/features/home/AgentListRow.tsx#L6-L9: Reduce the component description to one short line.
  • web/mobile/src/features/home/HomeSessionRow.tsx#L4-L7: Reduce the component description to one short line.
  • web/mobile/src/features/home/states/HomeStates.tsx#L11-L12: Reduce the empty-state comment to one short line.
  • web/mobile/src/features/agents/AgentOverviewScreen.tsx#L21-L26: Reduce the component description to one short line.

As per coding guidelines, “Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements.”

Source: Coding guidelines

web/mobile/src/features/chat/LiveConversation.tsx (1)

104-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the shared empty-state component instead of duplicating the copy.

This paragraph repeats the markup and most of the text of ChatEmpty in web/mobile/src/features/chat/states/ChatStates.tsx. The two strings will drift. Extend ChatEmpty with an optional suffix, or add a sibling export, and render it here.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 7aca63c7-aff9-47a1-82e8-549cc060fbab

📥 Commits

Reviewing files that changed from the base of the PR and between 92cc9cf and 3ec8109.

⛔ Files ignored due to path filters (1)
  • web/mobile/src/styles/theme.generated.css is excluded by !**/*.generated.*
📒 Files selected for processing (39)
  • web/mobile/next.config.ts
  • web/mobile/package.json
  • web/mobile/scripts/generate-shadcn-tokens.ts
  • web/mobile/src/components/ScreenScaffold.tsx
  • web/mobile/src/features/agents/AgentOverviewScreen.tsx
  • web/mobile/src/features/agents/AgentOverviewSection.tsx
  • web/mobile/src/features/chat/ApprovalDock.tsx
  • web/mobile/src/features/chat/ChatHeader.tsx
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/features/chat/Composer.tsx
  • web/mobile/src/features/chat/LiveConversation.tsx
  • web/mobile/src/features/chat/StopButton.tsx
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/features/chat/TurnStatusLine.tsx
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/chat/useAgentEntity.ts
  • web/mobile/src/features/home/AgentListRow.tsx
  • web/mobile/src/features/home/HomeScreen.tsx
  • web/mobile/src/features/home/HomeSessionRow.tsx
  • web/mobile/src/features/home/states/HomeStates.tsx
  • web/mobile/src/features/sessions/SessionListScreen.tsx
  • web/mobile/src/features/sessions/SessionRow.tsx
  • web/mobile/src/features/sessions/SessionSearchBar.tsx
  • web/mobile/src/features/sessions/mergeSessionRows.ts
  • web/mobile/src/features/sessions/pageFailure.ts
  • web/mobile/src/features/sessions/pendingFilter.ts
  • web/mobile/src/features/sessions/states/SessionListStates.tsx
  • web/mobile/src/features/sessions/useSessionListHead.ts
  • web/mobile/src/features/sessions/useSessionListScrollRestore.ts
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/agents/[agent_id].tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/apps/index.tsx
  • web/mobile/src/styles/globals.css
  • web/mobile/tests/unit/authConfig.test.ts
  • web/mobile/tests/unit/authDiscover.test.ts
  • web/mobile/tests/unit/mergeSessionRows.test.ts
  • web/mobile/tests/unit/otpMachine.test.ts
  • web/mobile/tests/unit/pageFailure.test.ts
  • web/mobile/tests/unit/pendingFilter.test.ts
💤 Files with no reviewable changes (15)
  • web/mobile/src/features/sessions/useSessionListHead.ts
  • web/mobile/tests/unit/pageFailure.test.ts
  • web/mobile/src/features/sessions/pendingFilter.ts
  • web/mobile/src/features/sessions/useSessionListScrollRestore.ts
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/features/sessions/mergeSessionRows.ts
  • web/mobile/tests/unit/authConfig.test.ts
  • web/mobile/src/features/sessions/states/SessionListStates.tsx
  • web/mobile/tests/unit/authDiscover.test.ts
  • web/mobile/src/features/sessions/SessionSearchBar.tsx
  • web/mobile/src/features/sessions/SessionRow.tsx
  • web/mobile/tests/unit/pendingFilter.test.ts
  • web/mobile/tests/unit/otpMachine.test.ts
  • web/mobile/src/features/sessions/pageFailure.ts
  • web/mobile/tests/unit/mergeSessionRows.test.ts

Comment thread web/mobile/next.config.ts
Comment on lines +16 to +26
"@agenta/auth",
"@agenta/auth-ui",
"@agenta/sdk",
"@agentaai/api-client",
"@agenta/shared",
"@agenta/ui",
"@agenta/entities",
"@agenta/entity-ui",
"@agenta/navigation",
"@agenta/navigation-ui",
"@agenta/sessions",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 '"`@agenta/sessions-ui`"|transpilePackages' \
  web/mobile/package.json web/mobile/next.config.ts

rg -nP -C 3 \
  '(?:from\s+["'\'']`@agenta/sessions-ui`(?:/[^"'\'']*)?["'\'']|require\(\s*["'\'']`@agenta/sessions-ui`)' \
  web/mobile/src

Repository: Agenta-AI/agenta

Length of output: 3556


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== next config =="
cat -n web/mobile/next.config.ts

echo
echo "== agenta-sessions-ui package files =="
fd -a . web/packages/agenta-sessions-ui | sed 's#^\./##' | head -80

echo
echo "== agenta-sessions-ui package manifests =="
for f in web/packages/agenta-sessions-ui/package.json web/packages/agenta-sessions-ui/tsconfig*.json web/packages/agenta-sessions-ui/next.config.* web/packages/agenta-sessions-ui/babel.config.* web/packages/agenta-sessions-ui/vite.config.* web/packages/agenta-sessions-ui/rollup.config.* web/packages/agenta-sessions-ui/tsup.config.*; do
  [ -f "$f" ] && { echo "--- $f"; cat -n "$f"; }
done

echo
echo "== imports from sessions-ui =="
rg -n "'`@agenta/sessions-ui`|\"`@agenta/sessions-ui`" web/mobile/src || true

echo
echo "== package scripts/package manager =="
cat -n web/package.json | sed -n '1,80p'

Repository: Agenta-AI/agenta

Length of output: 11557


🌐 Web query:

Next.js transpilePackages packages from node_modules source TypeScript packages

💡 Result:

In Next.js, the transpilePackages configuration option is used to instruct the compiler to transpile and bundle dependencies from node_modules or local monorepo workspaces that are not automatically processed [1][2]. By default, Next.js does not compile code inside node_modules [1]. If a dependency ships raw TypeScript (.ts/.tsx), JSX, or modern JavaScript syntax that requires transformation, it will cause errors (such as a SyntaxError or an unexpected token error) when imported [1][3]. You should add a package to transpilePackages when: * The dependency ships raw TypeScript or JSX source code directly [1][3]. * The dependency uses features that require the Next.js transformation pipeline, such as CSS Modules imports, server-only guards, or React Server Component directives ('use client'/'use server') [3]. * You are using the Pages Router and wish to bundle a server-side dependency into the route instead of loading it via Node.js require at runtime [1][4]. To use it, add the package name (including scope, if applicable) to your next.config.js file: // next.config.js / @type {import('next').NextConfig} */ const nextConfig = { transpilePackages: ['@scope/package-name', 'another-package'], } module.exports = nextConfig Key points to remember: * Values must be package names; file paths and glob patterns are not supported [1][2]. * Turbopack and Webpack handle local monorepo workspace packages differently, but explicitly listing them in transpilePackages is considered the safest and most predictable approach [1][3]. * A package cannot be listed in both transpilePackages and serverExternalPackages [1][4]. * Next.js may automatically include some internal packages in the transpilation process [1]. Checking the default-transpiled-packages.json file in the Next.js repository can show you which packages are handled automatically [1][4].

Citations:


Add @agenta/sessions-ui to transpilePackages.

web/mobile imports @agenta/sessions-ui, and that package exposes raw .ts/.tsx through main/exports without a compiled dist. Add @agenta/sessions-ui to web/mobile/next.config.ts so mobile bundles it in production.

Comment thread web/mobile/package.json
Comment on lines +23 to +34
"@agenta/auth": "workspace:../packages/agenta-auth",
"@agenta/auth-ui": "workspace:../packages/agenta-auth-ui",
"@agenta/chat": "workspace:../packages/agenta-chat",
"@agenta/entities": "workspace:../packages/agenta-entities",
"@agenta/entity-ui": "workspace:../packages/agenta-entity-ui",
"@agenta/navigation": "workspace:../packages/agenta-navigation",
"@agenta/navigation-ui": "workspace:../packages/agenta-navigation-ui",
"@agenta/sdk": "workspace:../packages/agenta-sdk",
"@agenta/sessions": "workspace:../packages/agenta-sessions",
"@agenta/sessions-ui": "workspace:../packages/agenta-sessions-ui",
"@agenta/shared": "workspace:../packages/agenta-shared",
"@agenta/ui": "workspace:../packages/agenta-ui",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Regenerate and commit pnpm-lock.yaml.

These dependency changes make pnpm install --frozen-lockfile fail. Regenerate the lockfile and commit it with this manifest update.

Source: Pipeline failures

Comment on lines +53 to +57
const {entityId} = useAgentEntity(sessionId, projectId)
const liveness = useLivenessPoll(projectId)
const running = Boolean(
liveness.data?.find((s) => s.session_id === sessionId)?.flags?.is_running,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use resolving to avoid the incorrect read-only message during agent resolution.

useAgentEntity returns resolving, but ChatScreen ignores it. While the agent query is in flight, entityId is null, so ReplayScreen mounts and ChatHeader shows "Read-only — this session has no agent to message yet.". That statement is false for an agent-backed session. When resolution completes, the screen swaps components and the replay transcript state is discarded.

Gate the replay subtitle (or render ChatLoading) on resolving.

🔧 Proposed fix
-    const {entityId} = useAgentEntity(sessionId, projectId)
+    const {entityId, resolving} = useAgentEntity(sessionId, projectId)
     const liveness = useLivenessPoll(projectId)
     const running = Boolean(
         liveness.data?.find((s) => s.session_id === sessionId)?.flags?.is_running,
     )
     return (
         <ReplayScreen
             sessionId={sessionId}
             projectId={projectId}
             workspaceId={workspaceId}
             running={running}
+            resolving={resolving}
         />
     )

Then pass subtitle={resolving ? undefined : "Read-only — …"} inside ReplayScreen.

Comment on lines +34 to +39
const submit = async (text: string) => {
const staged = attachments.files
const parts = staged.length > 0 ? stagedFilesToParts(staged, sessionId) : undefined
await onSend({text, parts})
attachments.clearAttachments(staged.map((file) => file.uid))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Locate ChatComposer and inspect its onSubmit invocation and error handling.
fd -t f 'ChatComposer' | xargs -r ast-grep outline --items all
rg -nP -C 6 'onSubmit\s*[(?.]' --iglob '*ChatComposer*'

Repository: Agenta-AI/agenta

Length of output: 1005


🏁 Script executed:

#!/bin/bash
set -u

echo "## relevant ChatComposer file"
wc -l web/packages/agenta-chat/src/components/ChatComposer.tsx
cat -n web/packages/agenta-chat/src/components/ChatComposer.tsx | sed -n '1,240p'

echo
echo "## references to ChatComposer onSubmit prop/usages"
rg -n -C 4 'ChatComposer|\.onSubmit\(|onSubmit\s*=' web/packages/agenta-chat web/mobile --iglob '*.{ts,tsx}'

echo
echo "## Composer.tsx relevant file"
fd -t f 'Composer.tsx' web/mobile | xargs -r -I{} sh -c 'echo "--- {}"; wc -l "{}"; cat -n "{}" | sed -n "1,140p"'

Repository: Agenta-AI/agenta

Length of output: 17601


🏁 Script executed:

#!/bin/bash
set -u

echo "## RichChatInput files"
fd -t f 'rich.*chat.*input|chat.*input|RichChatInput' web --iglob '*.{ts,tsx}'

echo
echo "## RichChatInput implementations"
for f in $(fd -t f 'RichChatInput|rich-chat-input|chat-input' web/packages web/mobile --iglob '*.{ts,tsx}'); do
  echo "--- $f"
  wc -l "$f"
  cat -n "$f" | sed -n '1,260p'
done

echo
echo "## onSubmit consumers across web/mobile"
rg -n -C 5 'onSubmit\s*=|\.onSubmit\(' web/packages web/mobile --iglob '*.{ts,tsx}'

Repository: Agenta-AI/agenta

Length of output: 18353


🏁 Script executed:

#!/bin/bash
set -u

echo "## RichChatInput SendButton/SubmitPlugin definitions"
rg -n -C 6 'SubmitPlugin|onSubmit|forceEnabled|sendForceEnabled' web/packages/agenta-ui/src/RichChatInput --glob '*.{ts,tsx}'

echo
echo "## RichChatInput component outline"
ast-grep outline web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx --match RichChatInput --view compact || true

echo
echo "## RichChatInput section"
cat -n web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx | sed -n '1,360p'

echo
echo "## lexical submit plugin/package maybe in node_modules or source?"
rg -n -C 5 'SubmitPlugin|return lexicon?|onSubmit.*LexicalNode|LexicalSubmitPlugin' web --glob '*.{ts,tsx}'

Repository: Agenta-AI/agenta

Length of output: 50374


Handle failed sends before clearing staged attachments.

submit awaits onSend({text, parts}) and only clears attachments afterward. A rejected send makes the promise passed through RichChatInput/SubmitPlugin.addSubmitHandler unresolved to the UI, so the user gets no feedback and the attachments remain queued. Catch the rejection and clear only after the send succeeds, or surface the error in the way ChatComposer expects.

Comment on lines +93 to +94
const visibleTurns = conversation.turns.filter((turn) => !turn.hidden)
const autoScroll = useTranscriptAutoScroll(visibleTurns)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect useTranscriptAutoScroll to see whether the turns argument is an effect dependency.
fd -t f 'useTranscriptAutoScroll' | xargs -r cat -n

Repository: Agenta-AI/agenta

Length of output: 1122


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)LiveConversation\.tsx$|(^|/)ChatScreen\.tsx$|useTranscriptAutoScroll' || true

printf '\nLiveConversation relevant section:\n'
sed -n '1,150p' web/mobile/src/features/chat/LiveConversation.tsx 2>/dev/null | cat -n

printf '\nChatScreen useTranscriptAutoScroll usages:\n'
rg -n "useTranscriptAutoScroll|turns|visibleTurns" web/mobile/src/features/chat/ChatScreen.tsx web/mobile/src/features/chat/LiveConversation.tsx -C 2

Repository: Agenta-AI/agenta

Length of output: 11867


Memoize visibleTurns before passing it to useTranscriptAutoScroll.

useTranscriptAutoScroll includes content in its useLayoutEffect dependency list, so a new array on each render re-runs the pin effect even when only unrelated state such as watch.connected or steerActions.phase changes.

Proposed fix
-    const visibleTurns = conversation.turns.filter((turn) => !turn.hidden)
+    const visibleTurns = useMemo(
+        () => conversation.turns.filter((turn) => !turn.hidden),
+        [conversation.turns],
+    )
     const autoScroll = useTranscriptAutoScroll(visibleTurns)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const visibleTurns = conversation.turns.filter((turn) => !turn.hidden)
const autoScroll = useTranscriptAutoScroll(visibleTurns)
const visibleTurns = useMemo(
() => conversation.turns.filter((turn) => !turn.hidden),
[conversation.turns],
)
const autoScroll = useTranscriptAutoScroll(visibleTurns)

Source: Coding guidelines

Comment on lines +36 to +38
<Link href={viewAllHref} className="text-muted-foreground text-xs no-underline">
View all →
</Link>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add semantic interaction states to the new navigation links.

These links define static styling only. Add visible hover, active, and focus-visible states with semantic Tailwind colors. Verify the states in both light and dark themes.

  • web/mobile/src/features/home/HomeScreen.tsx#L36-L38: Add interaction-state utilities to the Sessions “View all” link.
  • web/mobile/src/features/home/AgentListRow.tsx#L14-L14: Add interaction-state utilities to the agent row link.
  • web/mobile/src/features/home/HomeSessionRow.tsx#L9-L9: Add interaction-state utilities to the session row link.
  • web/mobile/src/features/agents/AgentOverviewScreen.tsx#L60-L66: Add interaction-state utilities to the back link.
  • web/mobile/src/features/agents/AgentOverviewSection.tsx#L17-L19: Add interaction-state utilities to the “View all” link.

As per coding guidelines, “Implement light and dark appearance and interaction states for every added or changed UI element, and verify both themes.”

📍 Affects 5 files
  • web/mobile/src/features/home/HomeScreen.tsx#L36-L38 (this comment)
  • web/mobile/src/features/home/AgentListRow.tsx#L14-L14
  • web/mobile/src/features/home/HomeSessionRow.tsx#L9-L9
  • web/mobile/src/features/agents/AgentOverviewScreen.tsx#L60-L66
  • web/mobile/src/features/agents/AgentOverviewSection.tsx#L17-L19

Source: Coding guidelines

Comment on lines +11 to +16
<span
aria-label={vm.status.label}
className={`size-2 shrink-0 rounded-full ${vm.status.dotClassName} ${
vm.status.pulse ? "motion-safe:animate-pulse" : ""
}`}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file exists and around target =="
if [ -f "web/mobile/src/features/home/HomeSessionRow.tsx" ]; then
  nl -ba web/mobile/src/features/home/HomeSessionRow.tsx | sed -n '1,220p'
else
  fd -a HomeSessionRow.tsx .
fi

echo
echo "== search HomeSessionRow and chipLabel/status =="
rg -n "HomeSessionRow|chipLabel|status:|dotClassName|aria-label" web/mobile/src/features/home -S || true

echo
echo "== package / lint / a11y config clues =="
fd -a "package.json|eslint|prettier|biome|tsconfig|app.json|app.config" web/mobile web -t f | sed -n '1,120p'

Repository: Agenta-AI/agenta

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file and show with cat -n =="
if [ -f "web/mobile/src/features/home/HomeSessionRow.tsx" ]; then
  cat -n web/mobile/src/features/home/HomeSessionRow.tsx | sed -n '1,240p'
else
  fd HomeSessionRow.tsx . -t f -x echo 'FILE:{}' -x sh -c 'sed -n "1,240p" "$1"' sh {}
fi

echo
echo "== search related identifiers =="
rg -n "HomeSessionRow|chipLabel|status:|dotClassName|aria-label|role=" web/mobile/src/features/home web/mobile/src -S || true

echo
echo "== lint/dependency config clues =="
fd package.json|head -n 20|xargs -r -n1 sh -c 'echo "--- $0"; sed -n "1,220p" "$0"'
fd -i "eslint|prettier|biome|tsconfig|app.json|app.config|metro|babel|tailwind" -t f web/mobile web | sed -n '1,160p'

Repository: Agenta-AI/agenta

Length of output: 45065


🌐 Web query:

WCAG ARIA name computation generic span no exposed role nameFrom attribute aria-label

💡 Result:

According to the WAI-ARIA and Accessible Name and Description Computation (AccName) specifications, using an aria-label attribute on a generic element (such as a or

with no explicit role) is considered a conformance error [1][2]. Key technical points regarding this behavior include: 1. Prohibited Usage: The generic role is explicitly defined as a role that does not support author-provided accessible names [3][4]. The specification states that for such roles, authors must not use aria-label or aria-labelledby [5][3]. 2. Algorithm Behavior: The AccName computation algorithm categorizes the generic role as having a nameFrom value of "prohibited" [3]. Consequently, when a user agent or assistive technology processes an element with the generic role, it is instructed not to use the aria-label attribute to compute an accessible name [5][1]. 3. Browser/Assistive Technology Support: Because this usage violates the specification, browser and screen reader support is inconsistent and unreliable [4][6]. While some implementations may ignore the attribute entirely, others might attempt to process it or produce unpredictable results [1][7]. Reliable accessibility depends on adhering to the specification, which dictates that naming attributes should only be applied to roles that explicitly support them [1][8]. To achieve the desired accessibility outcome, you should either: - Replace the with an element that has an appropriate semantic role (e.g., , , or ) [1]. - Assign an explicit ARIA role to the (e.g., role="button") that supports naming, provided the use of that role is appropriate for the element's function [1][2]. If the intention is simply to provide text, reliance on the element's natural text content is preferred [1].

Citations:


🌐 Web query:

MDN ARIA img role span aria-label nameFrom attribute

💡 Result:

When using an element like a span with role="img", the accessible name is determined by the Accessible Name and Description Computation (AccName) specification [1][2]. For elements with an explicit ARIA role of img, the nameFrom attribute is "author" [1][2]. This means the element derives its accessible name from author-provided markup, such as the aria-label or aria-labelledby attributes [1][2]. Key points regarding this computation: - Name Calculation: Elements with role="img" are generally treated as a single entity by assistive technologies [3][4]. Because role="img" does not support "name from content" (i.e., it does not automatically extract text from its children), you must explicitly provide an accessible name [3][4][5]. - Attributes: - aria-label: Provides a string value to name the element [6]. It is used when there is no visible text on the page to serve as a label [6][7]. - aria-labelledby: References other elements on the page via their IDs to provide the accessible name [7]. This is preferred over aria-label if a visible label exists [3][6][7]. - Precedence: If both aria-labelledby and aria-label are provided on the same element, aria-labelledby takes precedence [7]. While role="img" is primarily designed to use author-provided names, the broader W3C Accessible Name Computation algorithm accounts for various scenarios where other host-language mechanisms (like the alt or title attributes on native HTML elements) might contribute to the accessible name if the element is not a simple span [1][2]. However, for a span specifically, aria-label or aria-labelledby are the standard and expected methods to ensure the element has a meaningful accessible name [3][4].

Citations:


Expose the status indicator with a permitted semantic role.

The generic span does not support aria-label, so screen readers may skip this status label. Add role="img" or render visible/visually hidden text instead when chipLabel is absent.

Comment thread web/mobile/src/styles/globals.css Outdated
--text-field-md--line-height: 1.6666666666666667;
--text-field-lg: 14px;
--text-field-lg--line-height: 1.5714285714285714;
--shadow-switch-handle: 0 2px 4px 0 rgba(0, 35, 11, 0.2);

Copy link
Copy Markdown

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

Move the switch shadow color into the palette-backed token layer.

rgba(0, 35, 11, 0.2) bypasses semantic theme tokens and applies the same shadow color in both themes. Add a light/dark palette token, emit it through generate-shadcn-tokens.ts, and reference that variable here.

As per coding guidelines, “Consume theme colors through Ant Design semantic tokens, Tailwind color utilities, or supported var(--ag-color*) variables.”

Source: Coding guidelines

The app imports it from Home, the session list and the agent overview, but Next
was never told to transpile it. The workspace packages ship raw TS
(main: ./src/index.ts) with no dist, so a production build cannot parse it —
every other package the app uses is already on this list.
…r claims read-only

Three chat-screen correctness fixes.

The composer awaited onSend and let the rejection escape: nothing consumes the
promise RichChatInput hands back, so a failed send left the user with no
message, no error, and no idea it had failed — and `stagedFilesToParts` throws
outright on an unsettled upload, which Enter reaches (only the send BUTTON is
gated on `attachmentsSettled`). It now catches, keeps the attachments staged,
puts the text back in the editor, and reports through the same inline
rejections strip the desktop composer uses.

The screen router ignored `resolving`, so while the session's agent was still
being looked up it mounted the replay and told the user 'Read-only — this
session has no agent to message yet' about a perfectly live agent, then threw
the replay transcript away when the answer landed. It now waits on the loading
state until the lookup settles.

`visibleTurns` was a fresh array every render, and the auto-scroll effect lists
it as a dependency — so the transcript re-pinned on renders that changed
nothing about it (a watch reconnect, a steer phase change). Memoized.
… a themed switch shadow

The links and rows added for Home and the agent overview rendered as static
text: no hover, no active, no focus-visible treatment. One module now holds the
three variants (row, inline, icon) so all of them read the same instead of
drifting into five near-identical treatments; colours come from the semantic
tokens, which already resolve per theme, so there is no dark-mode override.
(The focus ring spells out `outline-solid`: Tailwind v4's `outline-none` sets
--tw-outline-style: none, which `outline-2` reads back, so the pair alone draws
nothing.)

The session row's status dot carried an aria-label on a bare span, which is not
reliably exposed — it is a named image now.

The switch-handle shadow was a literal rgba() in globals.css, painting the same
near-black green in both themes. It joins the palette as a light/dark pair and
rides the generator like every other token.

NOTE: src/styles/theme.generated.css still needs regenerating for the new
--switch-handle-shadow var. It is deliberately NOT regenerated here: the
committed file on this branch is already ahead of this branch's generator (13
vars per block that a later lane's role map adds, several of them referenced by
globals.css), so a regeneration now would delete them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant