Problem
The built-in Chat UI calls GET /agents/{slug}/workflows every 3 seconds while the page is visible and workflow support is enabled. Polling continues after every workflow in the current agent/session has reached a terminal state, producing repeated Functions executions and unnecessary Durable status queries.
The UI already recognizes terminal states (Completed, Failed, Canceled, and Terminated) and avoids re-rendering an unchanged terminal card, but the interval itself continues indefinitely.
Current implementation
src/azure_functions_agents/public/index.html
TERMINAL_WORKFLOW_STATES defines the terminal set.
pollWorkflowsOnce() fetches the session-wide /workflows endpoint and upserts every returned envelope.
startWorkflowPolling() creates an unconditional 3-second setInterval.
- polling currently stops only for unsupported workflow endpoints, hidden tabs, session/app changes, or history replay.
src/azure_functions_agents/workflows/tools.py
fetch_session_workflows() calls Durable get_status_all(), filters by (workflow_agent_slug, session_id), sorts, and returns up to the configured result cap.
Because /workflows is session-wide rather than one request per workflow, the useful optimization is to stop the whole timer when the latest successful response contains no non-terminal workflow—not merely to skip individual terminal cards.
Proposed behavior
- Continue polling every 3 seconds while at least one returned workflow is non-terminal.
- After a successful response where every workflow is terminal (and terminal notification processing has been queued), stop the interval.
- Perform an initial one-shot poll on page/session restore so active workflows are rediscovered.
- Restart polling when a new workflow may have been created, including after a chat turn that calls
start_workflow or after a relevant app/session transition.
- Preserve current hidden-tab, epoch, capability-probe, failure-warning, and terminal auto-notification behavior.
Design considerations
startWorkflowPolling() is currently called before chat submission. If an immediate poll sees only old terminal workflows and stops, a workflow started by that chat turn could be missed. Restart should therefore occur after the turn completes or when a successful start_workflow tool result is observed.
- A workflow may be started externally or from another browser tab using the same session. Permanent idle shutdown would not discover it without another UI event. Decide whether to accept event-driven restart or use a low-frequency idle backoff as a safety probe.
- Empty workflow lists should stop high-frequency polling after the initial capability/session probe.
- Completion notifications must still fire exactly once for fast workflows that start and finish between poll intervals.
- The endpoint currently calls app-wide Durable
get_status_all() before filtering. A separate follow-up may optimize backend querying if SDK support for instance-prefix/status filters is available.
Acceptance criteria
- No repeated 3-second
/workflows requests after the current session has no non-terminal workflows.
- Polling restarts reliably for a newly started workflow in the same Chat UI session.
- Active workflows continue updating at the current cadence.
Completed, Failed, Canceled, and Terminated all stop active polling when no other workflow remains active.
- Terminal auto-notifications still occur once and are not lost during the stop transition.
- Page visibility, session switching, history replay, unsupported endpoint handling, and transient failure behavior remain correct.
- Tests cover all-terminal, mixed active/terminal, empty list, fast completion, and restart-after-chat-start scenarios.
Problem
The built-in Chat UI calls
GET /agents/{slug}/workflowsevery 3 seconds while the page is visible and workflow support is enabled. Polling continues after every workflow in the current agent/session has reached a terminal state, producing repeated Functions executions and unnecessary Durable status queries.The UI already recognizes terminal states (
Completed,Failed,Canceled, andTerminated) and avoids re-rendering an unchanged terminal card, but the interval itself continues indefinitely.Current implementation
src/azure_functions_agents/public/index.htmlTERMINAL_WORKFLOW_STATESdefines the terminal set.pollWorkflowsOnce()fetches the session-wide/workflowsendpoint and upserts every returned envelope.startWorkflowPolling()creates an unconditional 3-secondsetInterval.src/azure_functions_agents/workflows/tools.pyfetch_session_workflows()calls Durableget_status_all(), filters by(workflow_agent_slug, session_id), sorts, and returns up to the configured result cap.Because
/workflowsis session-wide rather than one request per workflow, the useful optimization is to stop the whole timer when the latest successful response contains no non-terminal workflow—not merely to skip individual terminal cards.Proposed behavior
start_workflowor after a relevant app/session transition.Design considerations
startWorkflowPolling()is currently called before chat submission. If an immediate poll sees only old terminal workflows and stops, a workflow started by that chat turn could be missed. Restart should therefore occur after the turn completes or when a successfulstart_workflowtool result is observed.get_status_all()before filtering. A separate follow-up may optimize backend querying if SDK support for instance-prefix/status filters is available.Acceptance criteria
/workflowsrequests after the current session has no non-terminal workflows.Completed,Failed,Canceled, andTerminatedall stop active polling when no other workflow remains active.