You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
tracking(widget): clarification form submission failure family
Umbrella for the customer-reported "Widget forms do not submit" incident: a visitor answers an agent's clarification/interaction form (e.g. parameters for a pending tool/MCP call), the submit fails with a generic "Failed to send response", and the task stays parked in WAITING_FOR_USER — the pending tool call never runs. Production triage found multiple independent failure legs plus adjacent defects discovered while fixing them. This issue tracks the whole family so nothing gets lost across the two repos.
PR xorbitsai/xagent-saas#687 — route parked-task chat frames to the interaction continuation
xorbitsai/xagent-saas#651 — fix(widget-session): the widget can show an ask-user question but has no frame to answer it — same customer incident, second framing; see "Open question" below
PR xorbitsai/xagent-saas#658 — closed, split into the stack below (4.5k lines)
PR xorbitsai/xagent-saas#699 — bound the input-continuation turn id to the delivery column (APPROVED, conflicted — root of the stack)
PR xorbitsai/xagent-saas#700 — hold agent ownership through the input-continuation dispatch
PR xorbitsai/xagent-saas#712 — make one logical answer claimable exactly once
Delivery identity is caller-supplied (delivery_turn_id, saas#713) rather than derived, so a client-chosen dedup key probes the id space its delivery was recorded in. Every continuation caller must adopt it; a caller that keeps the derived id re-delivers on ack loss.
Landing order (updated 2026-08-20)
Every open PR in this family is either conflicted, un-reviewed, or the base of another PR, so the order matters more than the count.
Wave 0 — unblock the trains. saas#699 (approved, needs a rebase; root of a 5-PR stack) · saas#713 (clean, needs review; #687 waits on it) · #1476 (base of #1480) · #1514 (needs human review; contract dependency for #1472).
Wave 1 — the legs, in dependency order.#1480 (after #1476) · #1472 (after #1514) · #1484 (fold in or immediately follow #1499) · saas#687 (after #713, rebased and shrunk to routing) · saas#700 → saas#712 (after #699).
Wave 2 — P0 items with no PR yet.#1470 · #1500 · and a disposition for #1479 (does #1514 close it, or does it stay open for the residual?).
Wave 3 — P1.#1482 · #1485 · saas#685 · saas#663 · saas#675 · saas#682 · #1518 · plus the CI debt (#1492, saas#709) so the legs' own tests stop flaking.
Both issues are the same customer report ("Failed to send response" in a session-mode widget) approached from opposite ends, and both now have open PRs that add parked-task routing to session_websocket.py (#687 from the #680 side; #702/#703 from the #651 side) and change answer/delivery identity in external_tasks.py (#713 vs #712). They will conflict textually and may overlap semantically. Decide one owner for the routing change and one for answer identity before any of them merges, and close the loser as superseded. Secondary cleanup: #701 is closed but is still the git base of #702 and #703.
Non-code follow-ups (ops, tracked here so they are not lost)
A form submission on both widget transports either delivers (with retries absorbing transient storage faults and reservation contention) or fails with a specific, actionable, non-sensitive message — and never strands a task in WAITING_FOR_USER silently. The form must also become re-answerable when its turn does not run (#1500), and an answer must never be delivered twice or against a superseded question (saas#712, saas#713).
tracking(widget): clarification form submission failure family
Umbrella for the customer-reported "Widget forms do not submit" incident: a visitor answers an agent's clarification/interaction form (e.g. parameters for a pending tool/MCP call), the submit fails with a generic "Failed to send response", and the task stays parked in
WAITING_FOR_USER— the pending tool call never runs. Production triage found multiple independent failure legs plus adjacent defects discovered while fixing them. This issue tracks the whole family so nothing gets lost across the two repos.Failure legs (seed issues)
mainonly after fix(files): log the provider cause behind durable-storage faults #1476 lands)Derived while fixing (spawned issues)
Split out of the durable-storage reviews (#1476 / #1480)
Split out of the WebSocket redaction work (#1479 / #1497)
str.translate— mergedSplit out of the saas continuation work (saas#651 / saas#680)
Test/CI debt this family created
Adjacent, deliberately not in this family
Cross-PR contracts (agreed so parallel work does not conflict)
message_rejectedackmessagefield is always user-presentable text; the frontend renders it verbatim (fix(frontend): clarification form gives up on transient upload failures and hides the real rejection reason #1468 ↔ fix(web): form-response command fails permanently after ~19s when the resume reservation is held #1469 ↔ saas#680). Security caveat: security(websocket): agent RuntimeError text is surfaced verbatim to public chat visitors #1479/security(websocket): raw exception text still reaches chat clients through unrecognized producer shapes #1497 define what must NOT flow into that field — the redaction (PR security(websocket): redact incidental exception text from chat clients #1514) must land before or with fix(frontend): retry transient clarification uploads and surface the real failure reason #1472, or the frontend change turns a storage fault into a tenant-internals disclosure.delivery_turn_id, saas#713) rather than derived, so a client-chosen dedup key probes the id space its delivery was recorded in. Every continuation caller must adopt it; a caller that keeps the derived id re-delivers on ack loss.Landing order (updated 2026-08-20)
Every open PR in this family is either conflicted, un-reviewed, or the base of another PR, so the order matters more than the count.
Wave 0 — unblock the trains. saas#699 (approved, needs a rebase; root of a 5-PR stack) · saas#713 (clean, needs review; #687 waits on it) · #1476 (base of #1480) · #1514 (needs human review; contract dependency for #1472).
Wave 1 — the legs, in dependency order. #1480 (after #1476) · #1472 (after #1514) · #1484 (fold in or immediately follow #1499) · saas#687 (after #713, rebased and shrunk to routing) · saas#700 → saas#712 (after #699).
Wave 2 — P0 items with no PR yet. #1470 · #1500 · and a disposition for #1479 (does #1514 close it, or does it stay open for the residual?).
Wave 3 — P1. #1482 · #1485 · saas#685 · saas#663 · saas#675 · saas#682 · #1518 · plus the CI debt (#1492, saas#709) so the legs' own tests stop flaking.
Wave 4 — P2 hygiene. #1471 · #1473 · #1489 · #1515 · #1516 · #1517 · #1519 · #1520 · #1521 · #1490.
Open question: saas#651 vs saas#680
Both issues are the same customer report ("Failed to send response" in a session-mode widget) approached from opposite ends, and both now have open PRs that add parked-task routing to
session_websocket.py(#687 from the #680 side; #702/#703 from the #651 side) and change answer/delivery identity inexternal_tasks.py(#713 vs #712). They will conflict textually and may overlap semantically. Decide one owner for the routing change and one for answer identity before any of them merges, and close the loser as superseded. Secondary cleanup: #701 is closed but is still the git base of #702 and #703.Non-code follow-ups (ops, tracked here so they are not lost)
WAITING_FOR_USER(support follow-up, internal).Related / upstream
Done means
A form submission on both widget transports either delivers (with retries absorbing transient storage faults and reservation contention) or fails with a specific, actionable, non-sensitive message — and never strands a task in
WAITING_FOR_USERsilently. The form must also become re-answerable when its turn does not run (#1500), and an answer must never be delivered twice or against a superseded question (saas#712, saas#713).