Replies: 4 comments 3 replies
|
Jacob Alber (@lokitoth) are you able to help with this? |
|
Correction: The original version of this comment was incorrect for The stream contains two representations of the same logical approval: an inner-agent Select only the workflow-facing requests and correlate by List<ToolApprovalRequestContent> approvalRequests = updates
.Where(update => update.RawRepresentation is RequestInfoEvent)
.SelectMany(update => update.Contents.OfType<ToolApprovalRequestContent>())
.DistinctBy(request => request.RequestId)
.ToList();Create the approval response from that exact request and send it as a user message on the restored session: List<ChatMessage> approvalResponses = approvalRequests
.Select(request => new ChatMessage(
ChatRole.User,
[request.CreateResponse(approved: true)]))
.ToList();
JsonElement serializedState = await agent.SerializeSessionAsync(session);
session = await agent.DeserializeSessionAsync(serializedState);
updates = await agent.RunStreamingAsync(approvalResponses, session).ToListAsync();
|
|
There are two different things being surfaced in this stream, even though they refer to the same underlying tool call:
Those can have the same For a workflow exposed through List<ToolApprovalRequestContent> approvalRequests = updates
.Where(update => update.RawRepresentation is RequestInfoEvent)
.SelectMany(update => update.Contents.OfType<ToolApprovalRequestContent>())
.DistinctBy(request => request.RequestId)
.ToList();Then create the response from that exact workflow-facing request: List<ChatMessage> approvalResponses = approvalRequests
.Select(request => new ChatMessage(
ChatRole.User,
[request.CreateResponse(approved: true)]))
.ToList();
JsonElement serializedState = await agent.SerializeSessionAsync(session);
session = await agent.DeserializeSessionAsync(serializedState);
updates = await agent.RunStreamingAsync(approvalResponses, session).ToListAsync();The ordering of serialization versus creating the response object is not important here; preserving the workflow-facing If the response was created from the inner streaming copy instead, the ID lookup misses. The response is then treated as ordinary input, which sends a new turn through the sequential workflow. That explains the behavior you observed: the approved function can execute while the restarted sequence also reaches the same approval again. The relevant implementation is in If this still reproduces after filtering to |
|
Thank you — this identifies the exact distinction I missed. I conflated the inner-agent approval update with the workflow-level copy emitted from
Filtering updates by |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Sequential Agent Workflow re-requesting HITL approvals on Session Resume
We are testing a sequential multi-agent workflow (AgentWorkflowBuilder.BuildSequential) consisting of a routing agent, summary agent, and an execution agent utilizing an
ApprovalRequiredAIFunction.We are running into two key issues with streaming and session state:
RunStreamingAsyncyields multipleToolApprovalRequestContentchunks sharing the sameCallId, causing naive chunk counts to fail assertions.CreateResponse(true)), the workflow restarts the sequence and prompts for the exact same tool approval a second time on top of executing the function.How do we properly inject a tool approval response into a sequential workflow session so that the downstream execution agent consumes it rather than re-triggering the tool call?
Code:
All reactions