-
Notifications
You must be signed in to change notification settings - Fork 0
cancellation - agent loop #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| self.hooks.invoke_callbacks(BidiAgentInitializedEvent(agent=self)) | ||
|
|
||
| # TODO: Determine if full support is required | ||
| self._interrupt_state = _InterruptState() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are to raise an exception with a clear error message whenever a users raises an interrupt in their tools, we need to add _interrupt_state to this agent.
| raise RuntimeError("loop not started | call start before receiving") | ||
|
|
||
| while True: | ||
| event = await self._event_queue.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will break out of this loop under two conditions:
- Exception raised from
run_modelorrun_tooltask. - User calls
cancelon their receive task that callsagent.receive(whether they call it directly or throughagent.run).- Cancel results in an asyncio.CancelledError being raised which will break out of this
await self._event_queue.get()call and the method as a whole. This is why we don't need the_stop_eventcheck anymore.
- Cancel results in an asyncio.CancelledError being raised which will break out of this
|
|
||
| self._tasks.add(task) | ||
|
|
||
| async def _run_model(self) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would encourage you to "Hide Whitespace" for this section.
| if event["is_final"]: | ||
| message: Message = {"role": event["role"], "content": [{"text": event["text"]}]} | ||
| self._agent.messages.append(message) | ||
| try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapping in try/except so we can place errors into the _event_queue and reraise them from receive.
| ) | ||
|
|
||
| async for event in tool_events: | ||
| if isinstance(event, ToolInterruptEvent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without setting _interrupt_state on agent, we wouldn't get this ToolInterruptEvent. Instead, we would get an "_interrupt_state attribute doesn't exist" error.
Description
Properly handle start, stop, cancellation, and error propagation in Agent loop.
Goal
agent.receiveruns indefinitely. With the changes made in this PR, users can now control exiting (cleanly) using the following patterns:Or
Or
Testing
hatch run prepare: Lint and mypy checks passing.Also tested that interrupts lead to an exception with the following:
The result of asking the agent to run this tool is
RuntimeError: interrupts=['test_interrupt'] | tool interrupts are not supported in bidi.