Skip to content

fix(mobile): render typed failure copy and one row per submission - #6209

Merged
iscekic merged 1 commit into
mainfrom
kwf/assistant-message-rendered-as-user-eb6a
Sep 16, 2026
Merged

iscekic merged 1 commit into
mainfrom
kwf/assistant-message-rendered-as-user-eb6a

Conversation

@iscekic

@iscekic iscekic commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Changelog for users

  • An assistant message keeps the assistant treatment before the first token, while it streams and after it completes.
  • A submission no longer leaves an empty yellow bubble above its text in the transcript.
  • A failed submission keeps its failure copy, Retry button and copy action after the user retries it.
  • An agent error or retry in the status line shows the app's own translated copy instead of raw provider or transport text.
  • Raw transport text for a failed delivery no longer renders in the transcript; it stays reachable through the copy action.
  • A connection loss, a session termination or a failed stop in the mobile status line shows the SDK's own message instead of the generic "The response failed."
  • The session status keeps the agent's specific failure reason on web and the extension, including the insufficient-credits message.
  • A failed message delivery in the mobile status line shows the delivery copy instead of the generic assistant-failed line.

Changelog for maintainers

  • apps/mobile/src/components/agents/session-status-indicator.tsx:37 — accepted. The error branch maps its message through sessionStatusErrorMessage, and the SDK's own fixed lines (Agent connection lost, Session terminated, Failed to stop execution) matched no classifier rule, so each rendered the generic assistant-failure line. Added an SDK_FIXED_ERROR_MESSAGES allowlist in session-terminal-error.ts that returns those three unchanged; the warning indicator still renders the fixed retrying copy.
  • packages/cloud-agent-sdk/src/service-state.ts:675 — accepted, also line 688. Restored event.error, the Durable Object's safe projection, for both the stale-preparing status and the terminal settlement status, so web and the extension keep the specific reason and the extension's credits detection matches again. Removed the fixed delivery-status constant.
  • apps/mobile/src/components/agents/session-terminal-error.ts:129 — accepted. The delivery special case matched only Message failed to deliver; the status string Message delivery failed fell through to the generic line. It now matches both strings and returns the delivery copy.
  • apps/mobile/src/components/agents/session-transcript.ts:109 — accepted. !message.parts.some(partRendersContent) is redundant with the outer messageRendersContent gate: a synthetic row whose parts render nothing is dropped there anyway. Replaced it with message.parts.length === 0 and corrected the comment; the rendered rows are unchanged.
  • Client-materialised user rows carry synthetic: true; the ingest contract declares the optional flag so a round-trip preserves it. retryMessageAndClear is replaced by retryFailedMessage; a re-send no longer clears the failed row, which keeps its delivery state and footer.
  • Copy in the details sheet adds the raw transport text for a failed delivery; selectMessageFailure gains a copyDetail (empty for assistant failures); the failure footer still renders typed copy only, and the select-text view still shows the prompt alone.
  • Review first the transcript drop rule and the synthetic lifetime; the assistant treatment needed no production change, and tests now pin its streaming, empty and undefined-role cases.
  • The earlier assistant-streaming captures were not retained; the p1 and e3 streaming captures now prove the assistant treatment, and new captures prove the connection-loss status line and the failed-delivery status line (which replace the superseded fixed delivery-status claim).
  • SDK and mobile tests updated: the SDK suites now expect event.error as the status message, and the mobile suites pin the three fixed SDK lines and both delivery strings.

Reviewer facts (production record)

  • Both reported sessions exist in the read replica cli_sessions_v2 with status idle; report 2 was created 22:15:47.336Z and last updated 22:26:17.129Z, sandbox ses-5092b0e42508979ef156795ae2fc3f4b20a293097cd9dc9a.
  • cloud_agent_session_runs shows four completed runs then three FAILED runs for report 2; each carries failure_code unclassified and "Run failed without a classified cause".
  • Axiom cloudflare-logpush shows POST /trpc/sendMessageV2 at 22:25:21.412Z, 22:25:57.431Z and 22:25:59.068Z, each followed by "Sending V2 message to existing session"; the send path returned no 401.
  • The R2 wrapper log recorded session.prompt received and prompt_completed for all three prompts, then "outcome":"rejected", "reason":"event_batch_rejected", "rejectedCount": 732 (report 1 reaches 18150).
  • No product code writes the literal prompt "Continue"; only the common.continue label and test fixtures contain it.

E2E proof

p1-run2.mp4.trim.mp4
e3-dark.mp4.trim.mp4
e3-stream.mp4.trim.mp4

p1

e3-submit

e3-dark

p1

e3-dark

p3-dark

https://github.com/user-attachments/assets/fc221fc7-2a3e-42c4-ad0a-ae556a2997ad

e1

e2

Owner request

Assistant messages must never render with the user treatment

Surface: the mobile app (apps/mobile). Reported on Android; iOS is in scope because the session transcript is shared JS (packages/cloud-agent-sdk + apps/mobile/src/components/agents).

Problem

Two independent reports from the same user, two sessions, both opened from the mobile app. Both show a message that was not written by the user rendered with the USER message treatment (right-aligned, filled with the user accent colour).

Report 1, session ses_f590ac654ff8O2KiV6C2BTh53O ("AI gateway request retention in abuse service", git branch kilo/able-ridge-vwj): the bubble holds an assistant answer — repository prose with inline code chips (POST /api/classify), bold runs and a bullet list — and it sits directly under this turn's tool-call rows. The composer still shows the streaming state ("Antwoord schrijven · 22 sec") and the stop button, so the turn was still generating while the bubble was on screen.

Report 2, session ses_f58dc0cebfffJoPUmXs05c76pv ("Relocating credit expiration logic from AI gateway", branch kilo/spectral-beacon-gin, Android, Dutch, dark, 4% context, $7.36): the correct user message ("Cool, spawn a PR, assign me, let the CI handle tests") is followed by skill and tool rows, then the word "Continue" in the same yellow right-aligned user bubble with a small yellow stub above it, then the typed failure footer ("Het bericht kon niet worden bezorgd" / "De agent kon dit bericht niet verwerken", buttons "Opnieuw proberen" and "Naar het berichtveld kopieren"), then, in red, "Unauthorized: Unauthorized".

What production settled (read the record before the source)

Read with the workflow's production tools; these are reviewer facts and must be quoted in the PR body.

  • Read replica cli_sessions_v2: both rows exist, status idle. Report 1 created_at 2026-09-15T21:24:46.916Z, updated_at 21:38:57Z, cloud_agent_session_id workspace_9bf2c0d0-4e71-41d9-a2c1-cfafef4b7ef1. Report 2 created_at 22:15:47.336Z, updated_at 22:26:17.129Z, cloud_agent_session_id workspace_c3a5c3c6-00ac-4e77-a015-d2a9e8a308de, sandbox_id ses-5092b0e42508979ef156795ae2fc3f4b20a293097cd9dc9a. Both were created on cloud-agent-web.
  • Read replica cloud_agent_session_runs, report 2: four completed runs, then three FAILED runs — msg_0a72cbf8f000Ab0W20uOzcDzjS queued 22:25:23.836Z / terminal 22:25:25.114Z, msg_0a72d529d000X8PniCWrnurcvd queued 22:25:59.731Z, msg_0a72d4c1a000cWUX4xVkcBpmaO queued 22:26:00.992Z — each failure_code unclassified, error_message_redacted "Run failed without a classified cause". Report 1 has four completed runs and no failure, so report 1's bubble appeared during a healthy streaming turn.
  • Axiom cloudflare-logpush, ScriptName cloud-agent-next, at 22:25:21.412Z, 22:25:57.431Z and 22:25:59.068Z: POST /trpc/sendMessageV2, userId oauth/google:110119083409020777232, sessionId workspace_c3a5c3c6-00ac-4e77-a015-d2a9e8a308de, each followed by "Sending V2 message to existing session". So the three failed rows are three submissions from the user's own authenticated client, and the send path returned no 401.
  • Cloudflare R2 kilocode-sessions, logs/control/ses-5092b0e42508979ef156795ae2fc3f4b20a293097cd9dc9a/... (the wrapper's own trace, the only place a stuck session's record survives): 22:25:26.111Z session.prompt received and prompt_started + prompt_completed elapsedMs 353 for msg_0a72cbf8f...; 22:26:05.121Z two prompts with prompt_completed 311 and 283. The wrapper accepted and completed all three prompts. The same logs show the wrapper's event publication being rejected: "phase":"publication_summary" ... "outcome":"rejected", "reason":"event_batch_rejected" ... "rejectedCount": 732, "connectionClosedCount": 20 for report 2, and report 1's wrapper log reaches rejectedCount 18150.
  • Repo-wide search finds no code that writes the literal prompt "Continue" (only the UI label common.continue and test fixtures), so nothing in the product injects a synthetic "Continue" message.

Answers these facts establish, and the code must satisfy:

  1. "Continue" is a record the user's own client submitted through sendMessageV2, not something the product injects; the treatment question is therefore about the row the client materialises for a submission, not about the role of a stored user message.
  2. The doubled text is two records, not one message rendered twice (three distinct msg_* ids queued 22:25:23.836Z, 22:25:59.731Z, 22:26:00.992Z).
  3. The delivery failure followed the submission: the run supervisor marked the runs failed (failure_code unclassified) while the wrapper received and completed the prompts, so a submission can render as a delivered user bubble and then be recorded as failed.
  4. "Unauthorized: Unauthorized" is raw transport text. The transcript's own failure copy is fixed and safe (message-failure-state.ts: "Never surfaces raw provider or transport text"), so raw text in the transcript is a defect wherever it is rendered.

Requested behaviour

  1. An assistant message always renders with the assistant treatment, at every point in its life: before the first token, while it streams and after it completes. A message whose role is missing or unknown never falls back to the user treatment.
  2. A submission renders exactly once. The row the client materialises for a prompt reconciles with the server's authoritative record for that prompt, so the transcript never shows an empty yellow stub above the submitted text for one submission.
  3. A submission the server accepted and then failed shows the typed failure copy with Retry and "copy to the message field", and the transcript never shows raw transport text such as "Unauthorized: Unauthorized". Raw text stays available only through the copy action.
  4. Read production before the source. Every change is justified by a quoted production line with its timestamp, and a claim the record refutes is reported no_change with that evidence instead of a change.

Proof

  • A live device recording of a session where the assistant answer streams in and stays in the assistant treatment from the first frame to the last.
  • A live device recording of a failed submission: one row, typed copy, no raw transport text in the transcript.
  • Regression tests at the layer the cause is in: a render test that an assistant message (including one with no content yet and one with an undefined role) does not take the user treatment, and a test that a failed submission renders one row with the typed copy only. New copy reuses the existing agentChat.messageFailure.* keys.

E2E proof — log excerpts

[e3] Web + extension: a cloud-agent session that fails with insufficient credits -> pass :: Packed Chrome extension build passed the full e2e suite (142 passed, 16 skipped) including 'Agents new session shows credits error (402) with Add credits CTA' (e3-extension-e2e.log; isolated rerun 1 passed (3.4s) in e3-extension-credits-packed.log) with a stubbed backend payload mirroring the real 402; the fix's own behavior is pinned by the SDK differential - packed e3-sdk-packed.log '214 passed, 214 total' vs pre-fix file e3-sdk-prefix-differential.log '5 failed, 209 passed, 214 total' with '"message": "Message delivery failed"' received where '"message": "The message failed"' is expected. Limit named: a live insufficient-credits failure is unreachable here (e3-credits-reachability.log sho
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-extension-e2e.log
  ✓  138 tests/e2e/sidebar.test.ts:259:1 › closing the selected tab clears the target tab selection (4.0s)
  ✓  139 tests/e2e/sidebar.test.ts:286:1 › conversation survives side panel reload (1.6s)
  ✓  140 tests/e2e/tab-selection-default.test.ts:135:1 › create-path defaults to the activated content tab for each freeze fixture (6.5s)
  ✓  141 tests/e2e/tab-selection-default.test.ts:148:1 › manual target-tab pick survives poll cycles (4.3s)
  ✓  142 tests/e2e/tab-selection-default.test.ts:193:1 › single fixture tab is the first-conversation default (1.1s)
  ✓  143 tests/e2e/tab-selection-default.test.ts:216:1 › hydration race preserves a manual pick and freeze survives reload (1.9s)
  ✓  144 tests/e2e/tab-selection-default.test.ts:291:1 › empty inspectable list does not wipe a stored selectedTabId (8.1s)
  ✓  145 tests/e2e/web-mcp.test.ts:130:1 › safe mode omits the page double tool when WebMCP in safe mode is off (1.1s)
  -  146 tests/e2e/web-mcp.test.ts:162:1 › safe mode exposes and executes the page double tool when WebMCP in safe mode is on
  -  147 tests/e2e/web-mcp.test.ts:245:1 › dangerous mode sends the page double tool while the setting stays off
  ✓  148 tests/e2e/workflows.test.ts:195:1 › create workflow, approve card, and dry-run (4.6s)
  ✓  149 tests/e2e/workflows.test.ts:364:1 › run multi-page workflow from list with safe-mode toggle (1.6s)
  ✓  150 tests/e2e/workflows.test.ts:436:1 › workflow failure shows error without fabricated result (1.3s)
  ✓  151 tests/e2e/workflows.test.ts:475:1 › workflow refused when tab origin does not match scope (1.3s)
evalRequestCount: 3 evalBodyBytes: 51725 wfRequestCount: 1 wfBodyBytes: 17593
  ✓  152 tests/e2e/workflows.test.ts:520:1 › workflow uses fewer requests and fewer body bytes than eval rounds (5.5s)
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-extension-credits-packed.log
  ├─ .output/chrome-mv3/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2        25.96 kB
  ├─ .output/chrome-mv3/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2            18.75 kB
  ├─ .output/chrome-mv3/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2           11.23 kB
  ├─ .output/chrome-mv3/assets/inter-greek-wght-normal-CkhJZR-_.woff2               19 kB
  ├─ .output/chrome-mv3/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2           85.07 kB
  ├─ .output/chrome-mv3/assets/inter-latin-wght-normal-Dx4kXJAl.woff2               48.26 kB
  ├─ .output/chrome-mv3/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2          10.25 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-cyrillic-ext-wght-normal-BUDPrIko.woff2  35.91 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-cyrillic-wght-normal-HUlVHixE.woff2      18.59 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-greek-wght-normal-BJJTbwTT.woff2         14.04 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-latin-ext-wght-normal-QAYlOegK.woff2     22.92 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-latin-wght-normal-CZtBPCCa.woff2         32.8 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-vietnamese-wght-normal-DlC-zuDL.woff2    10.31 kB
  ├─ .output/chrome-mv3/icon/128.png                                                7.11 kB
  ├─ .output/chrome-mv3/icon/16.png                                                 1.48 kB
  ├─ .output/chrome-mv3/icon/32.png                                                 3.34 kB
  ├─ .output/chrome-mv3/icon/48.png                                                 4.76 kB
  ├─ .output/chrome-mv3/icon/96.png                                                 6.09 kB
  └─ .output/chrome-mv3/icon/icon.svg                                               1.02 kB
Σ Total size: 1.82 MB
✔ Finished in 1.470 s
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-sdk-packed.log
Test Suites: 2 passed, 2 total
Tests:       214 passed, 214 total
Snapshots:   0 total
Time:        0.569 s, estimated 1 s
Ran all test suites matching src/service-state.test.ts|src/session-phase.test.ts.
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-sdk-prefix-differential.log
      at Object.toMatchObject (src/session-phase.test.ts:928:26)
FAIL src/service-state.test.ts
  ● createServiceState › cloud.message.* per-message delivery state › terminal delivery failure resolves a stale preparing status
    expect(received).toEqual(expected) // deep equality
    - Expected  - 1
    + Received  + 1
      Object {
    -   "message": "Environment preparation failed",
    +   "message": "Message delivery failed",
        "type": "error",
      }
      1954 |       // render it; the failed row's typed footer and its Copy action keep the
      1955 |       // reader's copy.
    > 1956 |       expect(state.getCloudStatus()).toEqual({
           |                                      ^
      1957 |         type: 'error',
      1958 |         message: 'Environment preparation failed',
      1959 |       });
      at Object.toEqual (src/service-state.test.ts:1956:38)
Test Suites: 2 failed, 2 total
Tests:       5 failed, 209 passed, 214 total
Snapshots:   0 total
Time:        0.653 s, estimated 1 s
Ran all test suites matching src/service-state.test.ts|src/session-phase.test.ts.
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-credits-reachability.log
== e3 reachability probe 2026-09-16T09:55:58Z ==
-- zero-credit fixture user (kilocode_users):
e2e-credits-kwf-fix-review-51eb@example.com|2176|10000000|9997824
-- runs for sessions created by that user (fake model then kilo/z-ai/glm-5.3-flash):
ses_f5663a63bffeuDaaHfMx3hIrTH|msg_0a99c59c4000xEUj0TI9HcdHu2|completed|-|09:46:31.297|09:46:42.54
ses_f56627343ffdiDFXSXXrof2qvk|msg_0a99d8cbc0004mf2Fk6fyZRWBE|completed|-|09:47:49.878|09:48:07.327
-- second attempt: balance forced negative (used 11000000 > acquired 10000000) before creating a session; the harness grant is idempotent (only the 09:46:26 grant exists), so the run started unfunded:
e2e-credits-kwf-fix-review-51eb@example.com|11000000|10000000|-1000000|1
workspace_6f5cf641-52bd-426d-a707-43ca3b9ad14f|completed|no-failure
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/e3-extension-credits-prefix.log
  ├─ .output/chrome-mv3/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2        25.96 kB
  ├─ .output/chrome-mv3/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2            18.75 kB
  ├─ .output/chrome-mv3/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2           11.23 kB
  ├─ .output/chrome-mv3/assets/inter-greek-wght-normal-CkhJZR-_.woff2               19 kB
  ├─ .output/chrome-mv3/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2           85.07 kB
  ├─ .output/chrome-mv3/assets/inter-latin-wght-normal-Dx4kXJAl.woff2               48.26 kB
  ├─ .output/chrome-mv3/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2          10.25 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-cyrillic-ext-wght-normal-BUDPrIko.woff2  35.91 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-cyrillic-wght-normal-HUlVHixE.woff2      18.59 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-greek-wght-normal-BJJTbwTT.woff2         14.04 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-latin-ext-wght-normal-QAYlOegK.woff2     22.92 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-latin-wght-normal-CZtBPCCa.woff2         32.8 kB
  ├─ .output/chrome-mv3/assets/roboto-mono-vietnamese-wght-normal-DlC-zuDL.woff2    10.31 kB
  ├─ .output/chrome-mv3/icon/128.png                                                7.11 kB
  ├─ .output/chrome-mv3/icon/16.png                                                 1.48 kB
  ├─ .output/chrome-mv3/icon/32.png                                                 3.34 kB
  ├─ .output/chrome-mv3/icon/48.png                                                 4.76 kB
  ├─ .output/chrome-mv3/icon/96.png                                                 6.09 kB
  └─ .output/chrome-mv3/icon/icon.svg                                               1.02 kB
Σ Total size: 1.82 MB
✔ Finished in 1.434 s
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-cli/runbook-probe.log
== runbook probe 2026-09-16T09:18:53Z ==
-- command -v bun:
/home/igor_kilocode_ai/.bun/bin/bun
-- packages/opencode exists:
NO
-- @kilocode/cli package:
NO
-- bun run --cwd packages/opencode build:
ENOENT: Could not change directory to "packages/opencode"
-- bun turbo test:ci --filter=@kilocode/cli:
error: Script not found "turbo"
[e1] Mobile (Android): with a session whose SDK status is a connection loss, the -> pass :: Android emulator-5554: with the session 'e1-conn-loss investigation' open and the cloud-agent-next fault in place, the digest shows the status slot rendering the SDK's own fixed copy — e1-scene8.log line 22 'android.widget.TextView Agent connection lost tappable [92,2099][416,2145]', beside the reconnect banner on line 9 'android.view.ViewGroup Reconnecting… tappable [0,305][1080,360]' — and the generic fallback line the finding described is absent from all 26 digest lines, so the classifier did not replace it; no UX-DEFECT observed on the session-detail screens visited (the earlier slow-load and load-error states came from a wedged cloud-agent-next and cleared on its restart), capture e1-co
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-51eb/e2e-mobile-app/e1-scene8.log
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.Button Go back tappable [0,163][101,264]
android.widget.Button Rename session: e1-conn-loss investigation tappable [111,149][827,278]
android.view.View e1-conn-loss investigation tappable [111,180][827,245]
android.widget.Button Context 28 of 200,000 tokens, 0% used. Tap to view context details. tappable [854,156][1043,271]
android.widget.TextView 0% tappable [976,195][1013,232]
android.view.ViewGroup Reconnecting… tappable [0,305][1080,360]
android.widget.TextView Reconnecting… tappable [466,314][658,351]
android.widget.TextView 10:10 AM tappable [466,1399][614,1438]
android.view.ViewGroup e1-conn-loss-probe, User message tappable [0,1457][1080,1595]
android.widget.TextView e1-conn-loss-probe tappable [651,1494][1011,1557]
android.view.ViewGroup fake:echo:e1-conn-loss, User message tappable [0,1595][1080,1733]
android.widget.TextView fake:echo:e1-conn-loss tappable [577,1632][1011,1695]
android.widget.Button Preparation complete tappable [40,1754][1042,1855]
android.widget.TextView Preparation complete tappable [188,1781][506,1827]
android.view.ViewGroup e1-conn-loss, Assistant message tappable [0,1876][1080,1968]
android.widget.TextView e1-conn-loss tappable [37,1890][1045,1953]
android.view.ViewGroup e1-conn-loss-probe, Assistant message tappable [0,1968][1080,2060]
android.widget.TextView e1-conn-loss-probe tappable [37,1982][1045,2045]
android.widget.TextView Agent connection lost tappable [92,2099][416,2145]
android.widget.Button Add attachment tappable [28,2213][101,2287]
android.widget.EditText Message tappable [126,2190][800,2310]
android.widget.Button Start voice input tappable [835,2204][926,2296]
android.widget.Button Send message [926,2187][1052,2313]

@iscekic
iscekic marked this pull request as draft September 16, 2026 08:24
Comment thread apps/mobile/src/components/agents/session-status-indicator.tsx
Comment thread packages/cloud-agent-sdk/src/service-state.ts Outdated
Comment thread apps/mobile/src/components/agents/session-terminal-error.ts Outdated
Comment thread apps/mobile/src/components/agents/session-transcript.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up commit resolves all four prior findings: it restores the Durable Object's event.error as the SDK status message, allows the SDK's own fixed error and delivery strings through the mobile status classifier, and narrows the transcript drop rule to zero-part synthetic rows. No new issues were found in the changed lines.

Files Reviewed (8 files)
  • apps/mobile/src/components/agents/session-status-indicator.mounted.test.tsx
  • apps/mobile/src/components/agents/session-status-indicator.tsx
  • apps/mobile/src/components/agents/session-terminal-error.test.ts
  • apps/mobile/src/components/agents/session-terminal-error.ts
  • apps/mobile/src/components/agents/session-transcript.ts
  • packages/cloud-agent-sdk/src/service-state.test.ts
  • packages/cloud-agent-sdk/src/service-state.ts
  • packages/cloud-agent-sdk/src/session-phase.test.ts
Previous Review Summary (commit 4be8859)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 4be8859)

Status: 4 Issues Found | Recommendation: Address before merge

Executive Summary

The shared SDK now collapses every failed delivery to one fixed status string, which silently degrades the web and browser-extension status surfaces (including the extension's credits affordance), while the mobile status slot re-maps the SDK's own accurate status copy to a generic failure line.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/session-status-indicator.tsx 37 Error indicators now map through sessionStatusErrorMessage; the SDK's own fixed copy (Agent connection lost, Session terminated, Failed to stop execution) matches no classifier rule and renders the generic "The response failed."
packages/cloud-agent-sdk/src/service-state.ts 675 event.error (the DO's safe projection: credits, repo auth, model missing, workspace setup) is replaced by a constant, so web (SessionStatusIndicator.tsx:19) loses the specific reason and the extension's credits detection (isCreditsStatus) no longer matches. Also at line 688.

SUGGESTION

File Line Issue
apps/mobile/src/components/agents/session-terminal-error.ts 129 The delivery special case tests Message failed to deliver, but the new status string is Message delivery failed, so the delivery-specific copy is skipped for the cloud-status/all-active-turn paths.
apps/mobile/src/components/agents/session-transcript.ts 109 !message.parts.some(partRendersContent) is redundant with messageRendersContent; the only new drop is a zero-part synthetic row, and the comment overstates the rule's scope.
Files Reviewed (25 files)
  • apps/mobile/src/components/agents/child-session-sheet-recovery.mounted.test.tsx
  • apps/mobile/src/components/agents/message-bubble.test.ts
  • apps/mobile/src/components/agents/message-details-content.ts
  • apps/mobile/src/components/agents/message-details-sheet.test.ts
  • apps/mobile/src/components/agents/message-details-sheet.tsx
  • apps/mobile/src/components/agents/message-failure-state.test.ts
  • apps/mobile/src/components/agents/message-failure-state.ts
  • apps/mobile/src/components/agents/session-detail-content-helpers.test.ts
  • apps/mobile/src/components/agents/session-detail-content-helpers.ts
  • apps/mobile/src/components/agents/session-detail-content.tsx
  • apps/mobile/src/components/agents/session-detail-queue.test.ts
  • apps/mobile/src/components/agents/session-status-indicator.mounted.test.tsx
  • apps/mobile/src/components/agents/session-status-indicator.tsx - 1 issue
  • apps/mobile/src/components/agents/session-terminal-error.test.ts
  • apps/mobile/src/components/agents/session-terminal-error.ts - 1 issue
  • apps/mobile/src/components/agents/session-transcript.test.ts
  • apps/mobile/src/components/agents/session-transcript.ts - 1 issue
  • packages/app-shared/src/opencode.gen.ts
  • packages/cloud-agent-sdk/src/chat-processor.ts
  • packages/cloud-agent-sdk/src/service-state.test.ts
  • packages/cloud-agent-sdk/src/service-state.ts - 1 issue
  • packages/cloud-agent-sdk/src/session-manager.test.ts
  • packages/cloud-agent-sdk/src/session-manager.ts
  • packages/cloud-agent-sdk/src/session-phase.test.ts
  • packages/session-ingest-contracts/src/rpc-contract.ts

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic
iscekic force-pushed the kwf/assistant-message-rendered-as-user-eb6a branch from 9c1ef64 to f01f12b Compare September 16, 2026 11:54
@iscekic
iscekic marked this pull request as ready for review September 16, 2026 12:06
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 16, 2026
@iscekic iscekic self-assigned this Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants