Skip to content

Post workflow results back into chat and answer follow-ups from them #1546

Description

@paullizer

Summary

Part of #1543 (Phase 6). When a plan starts a workflow run from a private chat, the plan ends right away ("Started Weekly digest. I'll post the results here when it finishes."). When the run finishes, even hours later with the browser closed, the server posts an AI answer to the original request into that chat. Follow up lets the user ask questions that are answered from the stored run result.

User Value

A chat plan can't wait for a long workflow. Its deadline is 900 s by default and 7,200 s at most, while a durable run can take 24 hours. Posting the results later means the answer arrives where the user asked, with the same unread dot and notices as a normal reply, and the user can keep asking about it without re-running the workflow.

Proposed Behavior

6a: results reader and Follow up (depends on Phase 4)

  • One server reader for workflow results in chat. It authorizes through authorize_workflow_run_read and authorize_workflow_task_result_read (functions_workflow_results.py:358-530), reads bounded pages from the result store, and returns a snapshot descriptor with the run, status, completion time and result SHA-256. Personal workflows only.
  • Follow up, modeled on saved-analysis follow-ups (functions_saved_analysis.py, V2 lib/savedAnalysis.ts):
    • a composer chip: "Answering from the Weekly digest run of Mon 9:02 AM — not re-running the workflow"
    • the request sends workflow_result_context. Other sources are off for that turn, reads are bound to the result SHA, and later turns inherit the context.
    • clear messages when the result changed or access was lost
    • entry points: the delivered message, the run card, the recurring-workflow card, and Ask in chat on a run in the V2 Workflows page
  • A read-only planner capability, workflow_results, for questions like "what did my Monday digest find last week?"
  • Follow up and workflow_results are unavailable in shared and collaborative chats.

6b: post-back delivery, run card and chat-list indicator (depends on Phase 5, 6a and N1)

  • A chat_delivery record on the run (personal_workflow_runs, so no new container and no deployer change) with the origin conversation, request message, requester, model selection, status and expiry.
  • Workflow finalization triggers delivery, and a background sweep with a distributed lock picks up anything missed. Delivery:
    1. claims a lease
    2. re-checks that the chat is still personal, private and owned by the requester, and that the requester can still read the run
    3. waits for the next sweep if a reply is streaming in that chat
    4. composes from a bounded excerpt, with run output fenced as untrusted content
    5. creates the message with a deterministic ID
    6. marks the chat unread and creates the "AI responded" notice idempotently
  • A failed or cancelled run posts a short note with Open run and Retry.
  • If the result can't be delivered (chat deleted, made shared, access lost, or expired), nothing is posted and the bell gets one notice that links to the run.
  • An owner-only, batched status route for the user's chat-linked runs.
  • V2:
    • a WorkflowRunCard with Running, Needs you, Finished and Failed states
    • one tracker in the app shell
    • a WorkflowRunningTag spinner in the chat list
    • a recurring-workflow card for approved Phase 4 proposals
    • a run deep link, such as /workspace/workflows/:workflowId/runs/:runId

6c: in-plan wait (later, optional)

  • A saved_workflow_run wait kind for quick runs, added only if planners need a workflow's output later in the same plan.

Acceptance Criteria

  • 6a: Follow up answers only from the stored run result, a changed result or lost access shows the unavailable message, "what did my digest find last Monday?" reads the right run, and shared chats can't read workflow results.
  • 6b: a run started from a private chat posts exactly one answer through restarts, retries and concurrent sweeps.
  • 6b: closing the browser, reloading, or pinning the chat and coming back later all work. The unread dot appears, with no extra pop-ups.
  • 6b: the card moves through Running, Needs you, and Finished or Failed, and Check now works.
  • 6b: a deleted or shared chat, or lost access, gets no post and exactly one bell notice, and a delivery never lands mid-stream.
  • Functional tests, route policy tests for new routes, Playwright coverage, a feature doc, release notes and a config.py version bump for each part.

Notes

Activity

  1. 15 remaining items

  2. paullizer commented on Oct 8, 2026

    @paullizer
    ContributorAuthor

    Phase 6 complete (6a and 6b)

    6a and 6b are merged into paullizer-react-v2-ui. 6c, the in-plan wait, is deferred (see Follow-ups).

    Acceptance criteria

    • 6a: Follow up answers only from the stored run result. Reads are bound to the result's SHA-256, so a changed result or lost access shows the unavailable message. "What did my digest find last Monday?" reads the right run through workflow_results (Read saved workflow results from chat orchestration (workflow_results) #1607). Every turn checks that the chat is private, so shared, collaborative and converted chats can't read workflow results.
    • 6b: a run started from a private chat posts exactly one answer. The message ID is a hash of the run, the chat and the delivery generation. A lease and a sweep lock keep concurrent sweeps from posting twice, and a delivery reopens only when the durable run resumes.
    • 6b: the server marks the chat unread before it creates the message, so the unread dot is there after the browser was closed. The tracker keeps a baseline for each chat, so a reload doesn't announce the same run twice, and there's no extra pop-up. No test pins the chat first.
    • 6b: the card shows Queued, Running, Needs you, Completed, Partly completed, Failed, Timed out, Cancelled or Status unavailable, and Check now reads the run again. In a visible tab the tracker checks at 15 s, 30 s, 1 min and 2 min, then every 5 min. A hidden tab checks every 5 min, and only while desktop notifications are on and a run is in flight.
    • 6b: a deleted or shared chat, or lost access, gets no post and one bell notice. While a reply is streaming in the chat, the delivery waits for the next sweep.
    • Functional tests, route policy tests for the new routes (route_tests/test_workflow_result_context_policy.py, plus the route inventory and unauthenticated-contract entries), Playwright coverage (test_v2_workflow_run_card.py, test_chat_workflow_results.py and test_v2_workflow_run_tracker_spa.py), the feature docs CHAT_WORKFLOW_RESULTS_FOLLOW_UP.md, CHAT_ORCHESTRATION_WORKFLOW_RESULTS.md and CHAT_WORKFLOW_RESULT_DELIVERY.md, release notes and a version for each part.

    Verified from tests and review, not on a live tenant.

    Where it differs from the issue

    • Run deep link: /workspace/workflows?workflow_id=…&run_id=…. The proposed /workspace/workflows/:workflowId/runs/:runId would collide with the /workspace/:section/:resourceId route.
    • Needs you: the card doesn't approve anything. Review and approve opens the run, which shows the approval prompt.
    • Retry resumes the same durable run. Cancelled and skipped runs can't be retried.
    • Follow up starts from the delivered message, the recurring-workflow card (Open latest results and Follow up), Ask in chat on a run, and Ask about this on a workflow alert. The run card has Open run, Check now, Review and approve, Retry and Cancel, but not Follow up.
    • The card doesn't show which step a run is on, because the status route always returns an empty step name.
    • In a chat with more than 20 chat-started runs, the older runs show only Phase 5's links.
    • Follow up on a v3 workflow run is refused with workflow_result_unsupported, except for a hand-off's report.
    • If the workflow is deleted or its runtime control is missing, the delivery closes without a notice.

    Validation on each PR's final head

    Follow-ups (not blocking)

    • 6c, the in-plan wait, is deferred. The issue says to add it only if planners need a workflow's output later in the same plan.
    • Add a test that pins the chat before a delivery lands.
    • Gotcha 34, where detached orchestration answers don't mark the chat unread, wasn't in 6b's scope and hasn't been re-checked.
    • The remaining items in each PR's Follow-ups section.

    This issue is ready to close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

P1Priority 1: urgent, address before P2 workenhancementNew feature or request

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions