Skip to content

[feat] Show sessions and replay a transcript on mobile (6/12) - #5685

Draft
ardaerzin wants to merge 9 commits into
feat/mobile-device-gatefrom
feat/mobile-sessions-and-transcript
Draft

[feat] Show sessions and replay a transcript on mobile (6/12)#5685
ardaerzin wants to merge 9 commits into
feat/mobile-device-gatefrom
feat/mobile-sessions-and-transcript

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

Lane 1 gave /m a shell. This lane makes it show something real: your sessions, and a read-only transcript of one.

Changes

The @agenta/* packages are wired into the mobile app (and mounted/baked into its containers), with providers, SDK host pinning, and route-scoped project state. The root resolves your workspace and project: it forwards straight to the last one you used, and otherwise shows a picker.

The sessions list is server-searched and cursor-paged on the ordering lane 2 added, with archived rows filtered server-side (an all-archived first page would otherwise render "No sessions." while live rows sat behind the cursor). Opening a session replays its transcript through the durable record log, read-only.

Tests / notes

  • Data comes only from @agenta/entities; the app-layer import ban is lint-enforced, so nothing reaches into web/oss.
  • The transcript is replay-only here. Sending, approving, and stopping arrive in later lanes.

What to QA

  • Open /m signed in. You land on your last project's session list, or a picker if there is no last one.
  • Search for part of a session title. The list narrows server-side; clearing it restores the full list.
  • Open a session. The transcript renders in order. Scroll to the bottom and "Load more" pages without duplicating rows.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 3, 2026 10:30pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a lightweight mobile experience for selecting workspaces and projects.
    • Browse, search, and paginate project sessions, with archived sessions excluded.
    • View read-only chat transcripts, including messages, reasoning, tool summaries, and errors.
    • Added loading, empty, error, retry, and signed-out states.
    • Preserves recently used workspace and project context for easier navigation.
    • Sessions display activity times and live or ended status labels.
  • Documentation

    • Added a mobile implementation plan outlining supported flows and current limitations.

Walkthrough

The PR implements the mobile LITE flow. It adds project resolution, session search and pagination, read-only transcript replay, shared providers, workspace package integration, and container support.

Changes

Mobile LITE application

Layer / File(s) Summary
Workspace and container integration
.github/workflows/17-check-mobile.yml, docs/design/agenta-mobile/plans/..., hosting/docker-compose/*, web/*/docker/*, web/mobile/next.config.ts, web/mobile/package.json, web/turbo.json
The mobile build includes its workspace dependency closure. Containers mount or copy shared packages. Next.js transpiles required packages. Turbo tracks build and type-check dependencies.
App providers and project context
web/mobile/src/features/app/*, web/mobile/src/features/context/*, web/mobile/src/lib/*, web/mobile/src/pages/_app.tsx, web/mobile/src/pages/index.tsx, web/packages/agenta-sdk/src/resources.ts
The app configures SDK, React Query, Jotai, and route synchronization. It validates project responses, persists context, selects projects, and renders routing, signed-out, retry, and picker states.
Session search and pagination
web/mobile/src/features/sessions/*, web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx, web/mobile/tests/unit/pageFailure.test.ts
The sessions page supports debounced search, cursor pagination, archived-session filtering, session metadata, loading/error/empty states, failure classification, and guarded routing.
Read-only transcript replay
web/mobile/src/features/chat/*, web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
The chat page loads transcript messages, handles refresh and cancellation, renders turn content and tool summaries, shows errors and empty states, and provides session navigation with a read-only notice.

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

Sequence Diagram(s)

sequenceDiagram
  participant MobileApp
  participant ContextResolver
  participant ProjectsAPI
  participant SessionsAPI
  participant ChatScreen
  participant loadSessionMessages

  MobileApp->>ContextResolver: Resolve saved workspace and project context
  ContextResolver->>ProjectsAPI: Fetch projects
  ProjectsAPI-->>ContextResolver: Return project result
  ContextResolver->>MobileApp: Redirect to project sessions route
  MobileApp->>SessionsAPI: Query sessions with search and cursor
  SessionsAPI-->>MobileApp: Return session pages
  MobileApp->>ChatScreen: Open selected session
  ChatScreen->>loadSessionMessages: Load transcript messages
  loadSessionMessages-->>ChatScreen: Return transcript messages
  ChatScreen-->>MobileApp: Render read-only transcript turns
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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: displaying mobile sessions and replaying transcripts.
Description check ✅ Passed The description directly explains the mobile session list, transcript replay, package wiring, and QA scope.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mobile-sessions-and-transcript

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Trivy (0.72.0)

Trivy execution failed: 2026-08-03T22:31:24Z FATAL Fatal error run error: fs scan error: scan error: scan failed: failed analysis: post analysis error: post analysis error: kubernetes scan error: fs filter error: fs filter error: walk error range error: stat web/mobile/doctor.config.json: no such file or directory: range error: stat web/mobile/doctor.config.json: no such file or directory


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.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 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: 7


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 32e812e0-335c-45b6-bf48-d5eb695b3f19

📥 Commits

Reviewing files that changed from the base of the PR and between 45fa66f and b43b6c7.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • .github/workflows/17-check-mobile.yml
  • docs/design/agenta-mobile/plans/2026-07-26-mobile-flows-lite.md
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • web/ee/docker/Dockerfile.dev
  • web/mobile/docker/Dockerfile.gh
  • web/mobile/next.config.ts
  • web/mobile/package.json
  • web/mobile/src/features/app/AppProviders.tsx
  • web/mobile/src/features/app/ContextSync.tsx
  • web/mobile/src/features/chat/ChatHeader.tsx
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/chat/useSessionTranscript.ts
  • web/mobile/src/features/context/ContextResolver.tsx
  • web/mobile/src/features/context/WorkspaceProjectList.tsx
  • web/mobile/src/features/context/states/SignedOutNotice.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/states/SessionListStates.tsx
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/lib/context.ts
  • web/mobile/src/lib/env.ts
  • web/mobile/src/lib/queryClient.ts
  • web/mobile/src/pages/_app.tsx
  • web/mobile/src/pages/index.tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx
  • web/oss/docker/Dockerfile.dev
  • web/packages/agenta-sdk/src/resources.ts
  • web/turbo.json

Comment on lines +11 to +36
export const useSessionTranscript = (sessionId: string) => {
const [messages, setMessages] = useState<UIMessage[]>([])
const [state, setState] = useState<"loading" | "ready" | "empty">("loading")
useEffect(() => {
let cancelled = false
let refreshed = false
setState("loading")
setMessages([])
void loadSessionMessages(sessionId, (fresh) => {
// Disk-restore revalidation re-delivery — fresh is non-empty by contract.
if (cancelled) return
refreshed = true
setMessages(fresh)
setState("ready")
}).then((msgs) => {
// A fast revalidation can beat this one-shot resolve; never clobber it.
if (cancelled || refreshed) return
setMessages(msgs ?? [])
setState(msgs && msgs.length > 0 ? "ready" : "empty")
})
return () => {
cancelled = true
}
}, [sessionId])
return {messages, state}
}

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 | 🟠 Major | 🏗️ Heavy lift

Use TanStack Query instead of manual useEffect fetching.

This hook fetches data with useEffect and manual useState tracking. Wrap loadSessionMessages in a useQuery/atomWithQuery call instead, and use the refresh callback to update the query cache (for example through queryClient.setQueryData). This restores native loading/error/retry semantics and keeps the hook consistent with the rest of the codebase.

As per coding guidelines: "Use atomWithQuery with TanStack Query for API data fetching ... Do not use useEffect with manual fetching or introduce SWR+axios for new features."

Source: Coding guidelines


🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add error handling to the transcript load.

loadSessionMessages(...).then(...) has no .catch(). If the promise rejects, state stays "loading" indefinitely, and the rejection goes unhandled. The user sees an infinite spinner with no retry option on a transient failure.

Add an "error" state and a .catch() handler, and surface a retry action from ChatScreen.

🐛 Proposed fix
-    const [state, setState] = useState<"loading" | "ready" | "empty">("loading")
+    const [state, setState] = useState<"loading" | "ready" | "empty" | "error">("loading")
     useEffect(() => {
         let cancelled = false
         let refreshed = false
         setState("loading")
         setMessages([])
         void loadSessionMessages(sessionId, (fresh) => {
             if (cancelled) return
             refreshed = true
             setMessages(fresh)
             setState("ready")
         }).then((msgs) => {
             if (cancelled || refreshed) return
             setMessages(msgs ?? [])
             setState(msgs && msgs.length > 0 ? "ready" : "empty")
-        })
+        }).catch(() => {
+            if (cancelled || refreshed) return
+            setState("error")
+        })
         return () => {
             cancelled = true
         }
     }, [sessionId])

Comment on lines +22 to +25
const query = useQuery({
queryKey: ["mobile", "projects"],
queryFn: () => fetchProjects(),
enabled: !stored,

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 | 🟠 Major | ⚡ Quick win

Validate persisted context before redirecting.

A stored pair disables fetchProjects() and becomes target without checking that the user can still access the workspace and project. If the project was deleted or access was removed, /m/ keeps redirecting to the stale route and cannot show the picker or signed-out state.

Fetch projects for stored contexts. Redirect only when the stored pair exists in the validated result. Otherwise, clear the stored context and continue with normal project selection.

Also applies to: 46-62

Comment on lines +22 to +27
const query = useQuery({
queryKey: ["mobile", "projects"],
queryFn: () => fetchProjects(),
enabled: !stored,
staleTime: 30_000,
})

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 | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 '\batomWithQuery\b|\buseQuery\b' web/mobile

Repository: Agenta-AI/agenta

Length of output: 2315


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Tracked mobile files containing atomWithQuery:\n'
git ls-files 'web/mobile/**' | xargs rg -l 'atomWithQuery' || true

printf '\nContextResolver excerpt:\n'
sed -n '1,80p' web/mobile/src/features/context/ContextResolver.tsx | cat -n

printf '\nMobile package deps query/jotai availability:\n'
if [ -f web/mobile/package.json ]; then
  jq '{dependencies, devDependencies}' web/mobile/package.json
fi

printf '\nProject query/atom definitions referencing projects or mobile projects anywhere:\n'
rg -n 'fetchProjects|mobile.*projects|atomWithQuery|atomWithStorage' web/packages web/mobile || true

Repository: Agenta-AI/agenta

Length of output: 27472


Move project fetching into an atomWithQuery.

ContextResolver.tsx uses @tanstack/react-query's useQuery instead of the mobile data-layer pattern. Keep fetchProjects wrapped in a Jotai query atom, consume it with Jotai, and remove the direct useQuery import.

Source: Coding guidelines

Comment on lines +21 to +35
<button
key={project.project_id}
type="button"
className="border-border rounded-md border px-3 py-2.5 text-left text-xs"
onClick={() =>
void router.replace(
`/w/${group.workspaceId}/p/${project.project_id}/sessions`,
)
}
>
{project.project_name}
{project.is_demo ? (
<span className="text-muted-foreground ml-2">demo</span>
) : null}
</button>

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 | 🟠 Major | ⚡ Quick win

Add explicit interaction states to the new buttons.

The new controls define static semantic colors but no hover, active, or visible keyboard-focus state. Add token-based interaction classes for both controls.

  • web/mobile/src/features/context/WorkspaceProjectList.tsx#L21-L35: Add hover, active, and focus-visible styles to each project button.
  • web/mobile/src/features/context/ContextResolver.tsx#L82-L88: Add the same interaction states to the Retry button.

As per coding guidelines, implement light and dark appearance and interaction states for every added or changed UI element.

📍 Affects 2 files
  • web/mobile/src/features/context/WorkspaceProjectList.tsx#L21-L35 (this comment)
  • web/mobile/src/features/context/ContextResolver.tsx#L82-L88

Source: Coding guidelines

Comment thread web/mobile/src/features/sessions/SessionListScreen.tsx
Comment thread web/mobile/src/lib/context.ts Outdated
@ardaerzin

Copy link
Copy Markdown
Contributor Author

Verified these against the code. None are shipped defects, and two rest on a premise that does not hold for this app — so I would rather argue them than change the architecture quietly.

useEffect fetching / move project fetching into atomWithQuery — not taking. The repo convention (web/AGENTS.md) is TanStack Query, and this app follows it: the sessions list, liveness, interactions and project fetch all run through useQuery/useInfiniteQuery. The two flagged spots are deliberately not queries:

  • useSessionTranscript is not a fetch. It reads through @agenta/chat's loadSessionMessages, which is IndexedDB-restore plus a revalidation re-delivered through a callback, over a jotai-backed shared cache. Wrapping that in atomWithQuery would put a second cache in front of the one it already uses.
  • ContextResolver's project fetch is a useQuery already; what sits in useState is the last-used context read from localStorage, which is a synchronous one-shot read, not server state.

Validate persisted context before redirecting — real, but not a silent trap, and not free. A stored pair pointing at a deleted project does forward into a dead route. Validating first would defeat the point of the fast path, which exists to skip a round trip on every launch. There is now a way out that did not exist when this was written: the sessions header carries a project switcher, and /m/?switch=1 reaches the picker regardless of stored context. The better fix is to clear the stored pair when the sessions query returns not-found, rather than pre-validating every launch. Tracked, not done here.

Distinguish first-page from later-page failure — fair, deferred. Today any null page marks the list failed. In practice the first page is what fails (auth, project scope); a later page failing mid-scroll is rarer and the retry affordance still works. Worth splitting, not urgent.

Explicit interaction states on the picker buttons — superseded. That component was replaced further up the stack: the workspace selector moved into the pinned header and the list became ProjectList. Styling the deleted version would be churn.

Use the shared API-boundary validator in lib/context.ts — fair. It already validates with zod at the boundary; the finding is that it should use safeParseWithLogging from @agenta/entities/shared for consistent structured logging. Agreed in principle; it is a logging change rather than a correctness one, and mobile deliberately keeps its dependency surface small. Tracked.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
.github/workflows/17-check-mobile.yml (4)

22-25: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Serialize publication by the image tag.

Workflow concurrency separates runs by pull request or ref, but manual runs on different refs can still choose the same image_tag and push to ${TAG}-amd64 / ${TAG}-arm64. The merge-manifests job then creates ${TAG} from whichever per-arch images GHCR returns. Add a publish-specific concurrency group keyed to the final tag, use cancel-in-progress: false for the manifest step, or reject reusing an existing tag before publishing.


109-112: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Limit packages: write to the publish job.

build-image runs on pull_request, and GHCR push/cache writes are conditional on needs.prepare.outputs.push == 'true'. Keep this job read-only instead of granting write permissions up front. Use a separate job with packages: write for the registry publish path only.


82-108: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Treat workflow outputs as untrusted data.

image_tag is written unescaped to $GITHUB_OUTPUT under prepare.outputs, and later workflow_dispatch steps interpolate needs.prepare.outputs.image_tag and needs.prepare.outputs.push directly into run: Bash. Validate the tag before setting job outputs, then pass IMAGE and PUSH through env:, quoting any step output values before shell expansion.

Source: Linters/SAST tools


45-45: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable checkout credential persistence.

actions/checkout@v6 persists credentials by default in this checkout job. The subsequent pnpm install --frozen-lockfile step can read those credentials through repository-controlled lifecycle scripts. Add persist-credentials: false to the checkout steps at lines 45, 74, and 130.

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e7574674-71f2-48b1-a4ef-8c55dd063286

📥 Commits

Reviewing files that changed from the base of the PR and between b43b6c7 and 7a90b8c.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • .github/workflows/17-check-mobile.yml
  • docs/design/agenta-mobile/plans/2026-07-26-mobile-flows-lite.md
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • web/ee/docker/Dockerfile.dev
  • web/mobile/docker/Dockerfile.gh
  • web/mobile/next.config.ts
  • web/mobile/package.json
  • web/mobile/src/features/app/AppProviders.tsx
  • web/mobile/src/features/app/ContextSync.tsx
  • web/mobile/src/features/chat/ChatHeader.tsx
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/chat/useSessionTranscript.ts
  • web/mobile/src/features/context/ContextResolver.tsx
  • web/mobile/src/features/context/WorkspaceProjectList.tsx
  • web/mobile/src/features/context/states/SignedOutNotice.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/states/SessionListStates.tsx
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/lib/context.ts
  • web/mobile/src/lib/env.ts
  • web/mobile/src/lib/queryClient.ts
  • web/mobile/src/pages/_app.tsx
  • web/mobile/src/pages/index.tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx
  • web/oss/docker/Dockerfile.dev
  • web/packages/agenta-sdk/src/resources.ts
  • web/turbo.json
🚧 Files skipped from review as they are similar to previous changes (32)
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx
  • web/mobile/src/features/context/states/SignedOutNotice.tsx
  • web/oss/docker/Dockerfile.dev
  • web/mobile/src/features/chat/useSessionTranscript.ts
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • web/mobile/src/features/chat/ChatHeader.tsx
  • web/mobile/src/lib/env.ts
  • web/ee/docker/Dockerfile.dev
  • web/mobile/src/features/sessions/SessionSearchBar.tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
  • web/mobile/src/lib/queryClient.ts
  • web/turbo.json
  • web/mobile/src/features/context/WorkspaceProjectList.tsx
  • web/mobile/src/features/app/ContextSync.tsx
  • web/mobile/src/pages/index.tsx
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/sessions/SessionListScreen.tsx
  • web/mobile/src/pages/_app.tsx
  • web/mobile/src/features/sessions/states/SessionListStates.tsx
  • web/mobile/src/features/app/AppProviders.tsx
  • web/mobile/next.config.ts
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/features/context/ContextResolver.tsx
  • web/mobile/src/features/sessions/SessionRow.tsx
  • web/mobile/docker/Dockerfile.gh
  • web/mobile/package.json
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/lib/context.ts
  • web/packages/agenta-sdk/src/resources.ts
  • docs/design/agenta-mobile/plans/2026-07-26-mobile-flows-lite.md

…ontainers

Both dev composes mount web/packages into web-mobile (same line the web
service already has); both dev Dockerfiles now COPY the agenta-chat
manifest and source (they predate the package); Dockerfile.gh copies the
@agenta/* workspace closure (shared, ui, entities, playground, chat, sdk,
api-client full-dir for its prepare build) so pnpm install resolves the
new workspace deps.

Operator runbook (do not run in-session): the live web-mobile container
has neither the new deps nor @agenta/chat. Applying this change requires
a dev web image rebuild + web-mobile recreate:

    run.sh --ee --dev --with-mobile --build

Interim bootstrap of the RUNNING container, if needed before the rebuild:

    docker exec agenta-ee-dev-web-mobile-1 ls /app/packages   # confirm what's baked
    docker cp web/packages/agenta-chat agenta-ee-dev-web-mobile-1:/app/packages/
    docker cp web/mobile/package.json  agenta-ee-dev-web-mobile-1:/app/mobile/package.json
    docker cp web/pnpm-lock.yaml       agenta-ee-dev-web-mobile-1:/app/pnpm-lock.yaml
    docker exec agenta-ee-dev-web-mobile-1 pnpm install
    docker restart agenta-ee-dev-web-mobile-1
Any null page marked the whole session list failed, so a page that failed halfway down a long
scroll replaced every row already on screen with the full-screen error. Only the first page
failing leaves nothing to show; a later one should keep the rows and offer the retry where the
scroll stopped, which is what the load-more affordance now says when it happens.

The classification moved into `classifyPageFailure` beside the list's other pure helpers, so the
package unit suite covers it rather than only a rendered screen.

Also drops the stored workspace/project pair when its project will not load. That pair is the
fast path `/m/` uses to skip the picker, and a deleted project turned it into a loop: every
launch forwarded straight back to a list that could not render, with no way out but the switcher.
Clearing it is safe to over-do, since ContextSync rewrites it from the next project that loads.

Project fetching now validates through `safeParseWithLogging` from `@agenta/entities/shared`, the
repo's API-boundary validator, instead of an inline safeParse with its own console.error.
@ardaerzin
ardaerzin force-pushed the feat/mobile-device-gate branch from bfad8e0 to 29f6858 Compare August 3, 2026 22:29
@ardaerzin
ardaerzin force-pushed the feat/mobile-sessions-and-transcript branch from e55669f to e9ce407 Compare August 3, 2026 22:29
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
.github/workflows/17-check-mobile.yml (5)

208-213: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Check effective UID instead of exact Config.User strings.

Docker USER supports user:group and uid:gid forms, so root:root and 0:0 will pass ["$USER" = "root"] / ["$USER" = "0"] and report PASS. Reject root UID forms such as ""|root|0|root:*|0:*, or run docker exec and check id -u.


45-45: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable checkout credential persistence in each checkout step.

These checkout steps use actions/checkout’s persisted credentials, which make the runner’s Git credentials available to later PR-controlled commands such as pnpm install and build steps. Set persist-credentials: false for the checkout steps at lines 45, 74, and 144.

Suggested change
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@v6
+        with:
+          persist-credentials: false

Source: Linters/SAST tools


124-126: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Keep build-image read-only for pull requests.

build-image uses PR-controlled code with permissions: packages: write. Same-repository pull requests can provide write-capable GITHUB_TOKEN values depending on repository settings, while cross-repository pull requests are still subject to admin-controlled token access. Use a trusted, post-merge workflow, or workflow_dispatch, for GHCR publishing and keep the PR build job read-only.


105-117: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cap the base tag length before appending the architecture suffix.

Line 114 accepts image_tag up to 128 characters, but the build ref appends -${{ matrix.arch }} (-amd64 or -arm64), and the manual Docker load/tag step does the same. Tags of 123–128 characters become 129–134 characters, which exceeds the OCI reference tag length limit. Limit the base tag to 122 characters, or validate each derived image_tag-${{ matrix.arch }} tag.

Suggested change
-          if [ "${`#TAG`}" -gt 128 ]; then
-            echo "::error::image_tag is longer than 128 characters"
+          MAX_BASE_TAG_LENGTH=122
+          if [ "${`#TAG`}" -gt "$MAX_BASE_TAG_LENGTH" ]; then
+            echo "::error::image_tag is too long for the architecture tags"
             exit 1
           fi

35-37: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Key manual image publishing by the requested image tag.

workflow_dispatch accepts image_tag, but the workflow’s concurrency group uses github.ref_name. Manual runs from different refs can build and merge the same TAG-amd64 and TAG-arm64 images concurrently, producing a manifest that mixes arch builds from different runs. Key the tag group with inputs.image_tag and disable canceling manual publishes, or queue them for the same tag.

Suggested change
-  group: check-mobile-${{ github.event.pull_request.number || github.ref_name }}
-  cancel-in-progress: true
+  group: check-mobile-${{ github.event.pull_request.number || inputs.image_tag || github.sha }}
+  cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b45adcef-1ced-427b-9990-2296091db215

📥 Commits

Reviewing files that changed from the base of the PR and between 7a90b8c and e9ce407.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • .github/workflows/17-check-mobile.yml
  • docs/design/agenta-mobile/plans/2026-07-26-mobile-flows-lite.md
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • web/ee/docker/Dockerfile.dev
  • web/mobile/docker/Dockerfile.gh
  • web/mobile/next.config.ts
  • web/mobile/package.json
  • web/mobile/src/features/app/AppProviders.tsx
  • web/mobile/src/features/app/ContextSync.tsx
  • web/mobile/src/features/chat/ChatHeader.tsx
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/chat/useSessionTranscript.ts
  • web/mobile/src/features/context/ContextResolver.tsx
  • web/mobile/src/features/context/WorkspaceProjectList.tsx
  • web/mobile/src/features/context/states/SignedOutNotice.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/pageFailure.ts
  • web/mobile/src/features/sessions/states/SessionListStates.tsx
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/mobile/src/lib/context.ts
  • web/mobile/src/lib/env.ts
  • web/mobile/src/lib/queryClient.ts
  • web/mobile/src/pages/_app.tsx
  • web/mobile/src/pages/index.tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx
  • web/mobile/tests/unit/pageFailure.test.ts
  • web/oss/docker/Dockerfile.dev
  • web/packages/agenta-sdk/src/resources.ts
  • web/turbo.json
🚧 Files skipped from review as they are similar to previous changes (31)
  • web/turbo.json
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • web/ee/docker/Dockerfile.dev
  • web/mobile/src/lib/queryClient.ts
  • web/oss/docker/Dockerfile.dev
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/index.tsx
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • web/mobile/src/features/chat/useSessionTranscript.ts
  • web/mobile/src/features/sessions/SessionRow.tsx
  • web/mobile/package.json
  • web/mobile/src/features/app/ContextSync.tsx
  • web/mobile/src/pages/index.tsx
  • web/mobile/src/features/sessions/SessionSearchBar.tsx
  • web/mobile/src/features/chat/ChatScreen.tsx
  • web/mobile/src/features/chat/states/ChatStates.tsx
  • web/mobile/src/features/context/states/SignedOutNotice.tsx
  • web/mobile/src/features/chat/TurnRow.tsx
  • web/mobile/src/pages/w/[workspace_id]/p/[project_id]/sessions/[session_id].tsx
  • web/mobile/src/features/app/AppProviders.tsx
  • web/mobile/next.config.ts
  • web/mobile/src/features/sessions/useSessionsInfinite.ts
  • web/packages/agenta-sdk/src/resources.ts
  • web/mobile/src/features/context/WorkspaceProjectList.tsx
  • docs/design/agenta-mobile/plans/2026-07-26-mobile-flows-lite.md
  • web/mobile/src/pages/_app.tsx
  • web/mobile/src/lib/context.ts
  • web/mobile/src/features/sessions/states/SessionListStates.tsx
  • web/mobile/src/lib/env.ts
  • web/mobile/src/features/context/ContextResolver.tsx
  • web/mobile/docker/Dockerfile.gh
  • web/mobile/src/features/chat/ChatHeader.tsx

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