Skip to content

fix(public-chat): a failed turn shows visitors a plain message, never the raw execution error (#3461) - #3478

Merged
vybe merged 1 commit into
devfrom
feature/3461-public-chat-failure-rendering
Oct 9, 2026
Merged

vybe merged 1 commit into
devfrom
feature/3461-public-chat-failure-rendering

Conversation

@trinity-ability

Copy link
Copy Markdown
Contributor

Description

  • Backend: the unauthenticated GET /api/public/executions/{token}/{id}/status returned execution.error verbatim for a failed row. It now answers the fixed line the synchronous public path already uses; the detail stays on the row for the operator. test_679_public_poll_cancel.py pinned the raw string for failed rows and now pins the fixed line.
  • Frontend: PublicChat.vue shows a plain failure message and restores the visitor's message into the input for a retry; it never renders the status route's error for a failed row.

Part of the UI sweep epic #3471.

Related Issue

Fixes #3461

Journey Impact

Journey Impact: none: bug fix to existing behaviour found by the UI sweep; no journey promise is added or changed

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Testing

  • I have tested this locally
  • New tests added (if applicable)
  • All existing tests pass
  • Every new test executes the changed path

Mutation: publicChatFailureMessage.spec.js — 4 red with the view change reverted. tests/unit/test_3461_public_status_failure_text.py — 2 red with the route change reverted (plus the updated #679 case). Restored byte-identical.

UI verification: on an isolated stack built from this change with a seeded failed execution whose stored error carries an exit code and operator remediation: the real /status response has error: "Failed to process your request. Please try again.", the page shows the plain banner, restores the message into the input, and none of the raw strings appear in the DOM or console; checked at 1440 and 768, light and dark. The submit response was simulated in the browser because the seeded agent has no container; polling, status and rendering were real.

Checklist

  • My code follows the project's style guidelines
  • I have updated the documentation (if applicable)
  • I have not committed any sensitive data (API keys, credentials, etc.)

🤖 Generated with Claude Code

…never the operator's error (#3461)

A public link's failed turn rendered the execution row's own `error` in
the chat banner: the agent server's diagnosis ("Execution failed with no
output (exit code 1): ...") followed by remediation addressed to the
operator. The page is read by anonymous visitors.

Two layers, because the page was only the last hop:

- `GET /api/public/executions/{token}/{id}/status` is unauthenticated and
  returned `execution.error` verbatim for a `failed` row. It now answers
  the fixed line the synchronous public path already answers; the detail
  stays on the row for the operator. A cancel reason (#679) and a skill
  gate's notice (trinity#3274) are written for the visitor and still pass
  through.
- `PublicChat.vue` no longer renders the status route's `error` for a
  failed turn at all. It shows one plain line and puts the visitor's
  message back in the input, so sending again is the retry.

Tests, each red with its fix reverted and green with it restored:
- src/frontend/tests/unit/publicChatFailureMessage.spec.js (mounted; 4/4
  red under mutation, incl. "never renders the execution row's own error
  text")
- tests/unit/test_3461_public_status_failure_text.py (2 red under
  mutation; the cancel and gate pass-through cases stay green)
- tests/unit/test_679_public_poll_cancel.py: the `failed` case pinned the
  raw string and now pins the fixed line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@vybe vybe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

merge-train: batch validated on train/20261009-2324-b (#3504)

@vybe
vybe merged commit c68b487 into dev Oct 9, 2026
25 checks passed
vybe pushed a commit that referenced this pull request Oct 23, 2026
…the operator's error (#3603) (#3839)

* fix(channels): a failed turn tells the chat so in plain words, never the operator's error (#3603)

The router posted the execution's own error into the channel: "Authentication
failure: Not logged in · Please run /login. Check subscription token or API
key configuration." In a Telegram group every member saw it; Slack, WhatsApp
and DMs took the same path. A failed turn now sends the fixed line the
router's exception branch already used; the error stays on the execution row
and in the router's log line. A cancelled turn still sends its cancel reason
(#679), or a cancelled line when it has none. Public chat got the same fix in
#3478.

test_slack_timeout_fix.py's TestErrorMessageRouting re-implemented the old
#221 forwarding logic instead of calling the router, so it could not fail; it
is replaced by tests that drive the real _run_agent_task. Mutation: restoring
the forwarding turns 14 of 19 new tests red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(channels): a cancelled turn always sends the fixed cancelled line (#3603)

On a pull-pilot agent a terminated turn keeps the failure body's content
and the pull sink stores it as the cancelled row's error, so forwarding a
cancelled row's error could still post the operator's error to the chat.
The cancelled branch now always sends CHANNEL_CANCELLED_MESSAGE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants