Swapping agent involves the following: - Dropping all of the clients first to avoid resource contention - Clearing fields that are already referenced by background tasks. We can't simply spawn new instances of these fields because one or more background tasks are already depending on it - Building a new tool manager builder from the current tool manager - Building a tool manager from said tool man
(&mut self, os: &mut Os, output: &mut impl Write, agent: &Agent)
| 647 | /// function) |
| 648 | /// - Calling load tools |
| 649 | pub async fn swap_agent(&mut self, os: &mut Os, output: &mut impl Write, agent: &Agent) -> eyre::Result<()> { |
| 650 | let to_evict = self.clients.drain().collect::<Vec<_>>(); |
| 651 | tokio::spawn(async move { |
| 652 | for (server_name, initialized_client) in to_evict { |
| 653 | info!("Evicting {server_name} due to agent swap"); |
| 654 | match initialized_client { |
| 655 | InitializedMcpClient::Pending(handle) => { |
| 656 | let server_name_clone = server_name.clone(); |
| 657 | tokio::spawn(async move { |
| 658 | match handle.await { |
| 659 | Ok(Ok(client)) => { |
| 660 | let InnerService::Original(client) = client.inner_service else { |
| 661 | unreachable!(); |
| 662 | }; |
| 663 | match client.cancel().await { |
| 664 | Ok(_) => info!("Server {server_name_clone} evicted due to agent swap"), |
| 665 | Err(e) => error!("Server {server_name_clone} has failed to cancel: {e}"), |
| 666 | } |
| 667 | }, |
| 668 | Ok(Err(_)) | Err(_) => { |
| 669 | error!("Server {server_name_clone} has failed to cancel"); |
| 670 | }, |
| 671 | } |
| 672 | }); |
| 673 | }, |
| 674 | InitializedMcpClient::Ready(running_service) => { |
| 675 | let InnerService::Original(client) = running_service.inner_service else { |
| 676 | unreachable!(); |
| 677 | }; |
| 678 | match client.cancel().await { |
| 679 | Ok(_) => info!("Server {server_name} evicted due to agent swap"), |
| 680 | Err(e) => error!("Server {server_name} has failed to cancel: {e}"), |
| 681 | } |
| 682 | }, |
| 683 | } |
| 684 | } |
| 685 | }); |
| 686 | |
| 687 | let mut agent_lock = self.agent.lock().await; |
| 688 | *agent_lock = agent.clone(); |
| 689 | drop(agent_lock); |
| 690 | |
| 691 | self.mcp_load_record.lock().await.clear(); |
| 692 | |
| 693 | let builder = ToolManagerBuilder::from(&mut *self); |
| 694 | let mut new_tool_manager = builder.build(os, Box::new(std::io::sink()), true).await?; |
| 695 | std::mem::swap(self, &mut new_tool_manager); |
| 696 | |
| 697 | self.load_tools(os, output).await?; |
| 698 | |
| 699 | Ok(()) |
| 700 | } |
| 701 | |
| 702 | pub async fn load_tools( |
| 703 | &mut self, |
nothing calls this directly
no test coverage detected