-
Notifications
You must be signed in to change notification settings - Fork 409
bskiser/add agent crate #3150
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
bskiser/add agent crate #3150
Conversation
dingfeli
left a comment
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.
LGTM
| agent | ||
| .send_prompt(SendPromptArgs { | ||
| content: vec![ContentChunk::Text(initial_prompt)], | ||
| should_continue_turn: None, | ||
| }) | ||
| .await?; |
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.
Do we always assume there is an initial prompt?
| print!("{}", text); | ||
| let _ = std::io::stdout().flush(); |
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.
Is this subject to change? I see here we are just logging to stdout. Is the plan to instead write to some sort of listener that is in charge of eventually displaying it.
| /// | ||
| /// Note that a turn can continue even after a [AgentEvent::Stop] for when the agent encounters | ||
| /// an error, and the next prompt chooses to continue the turn. | ||
| EndTurn(UserTurnMetadata), |
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.
Is a request - response considered a user turn?
I see this is referenced in [RunArgs::main_loop], and it looks like this is a condition that would end the execution of main_loop.
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.
Though I was only following the code path starting from main.rs. I am guessing that's only one use case (looks like non-interactive?).
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.
A user turn consists of all requests up until either a non-retryable error, or the model responds with no tool uses
| } | ||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum McpManagerRequest { |
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.
Should we also have a variant for Shutting down server. i.e. during unloading of an agent for example.
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.
Nvm, as I had discovered in https://github.com/aws/amazon-q-developer-cli/pull/3150/files#r2479586268, each agent is to have their own McpManager. There is no concept of unloading agent to McpManager since McpManager has the same lifetime as the associated agent.
We wouldn't need a variant for unloading mcp server unless we support hot loading agent config in the future or something.
| tokio::select! { | ||
| req = self.request_rx.recv() => { | ||
| std::mem::drop(initializing_servers); | ||
| std::mem::drop(initialized_servers); | ||
| let Some(req) = req else { | ||
| warn!("Tool manager request channel has closed, exiting"); | ||
| break; | ||
| }; | ||
| let res = self.handle_mcp_manager_request(req.payload).await; | ||
| respond!(req, res); | ||
| }, | ||
| res = initializing_servers.next(), if !initializing_servers.is_empty() => { | ||
| std::mem::drop(initializing_servers); | ||
| std::mem::drop(initialized_servers); | ||
| if let Some((name, evt)) = res { | ||
| self.handle_initializing_mcp_actor_event(name, evt).await; | ||
| } | ||
| }, | ||
| res = initialized_servers.next(), if !initialized_servers.is_empty() => { | ||
| std::mem::drop(initializing_servers); | ||
| std::mem::drop(initialized_servers); | ||
| if let Some((name, evt)) = res { | ||
| self.handle_mcp_actor_event(name, evt).await; | ||
| } | ||
| }, |
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.
Would the unordered future not be dropped anyway? Not that there is anything wrong with doing that explicitly.
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.
There were borrow checker errors without the explicit drop for some reason - this is an area of the code that could definitely use some testing to ensure no messages are dropped (FuturesUnordered should be cancel safe so long as all of the futures it contains are cancel safe, which they are since mpsc is cancel safe)
I imagine there has to be a cleaner way to do this
| } | ||
| }; | ||
|
|
||
| let agent = Agent::new(snapshot, model, McpManager::new().spawn()).await?.spawn(); |
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.
So the paradigm is that each Agent would have its own McpManager?
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.
An agent has a handle to an MCP manager, meaning that multiple agents could potentially share the same MCP manager
| enum McpServerActorResponse { | ||
| Tools(Vec<ToolSpec>), | ||
| Prompts(Vec<Prompt>), | ||
| ExecuteTool(oneshot::Receiver<ExecuteToolResult>), | ||
| } |
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 think missing from this is the prompt "hydration" result. Prompt here is just metadata about the prompt. The actual filled in prompt would need its own variant as well.
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.
What is prompt hydration? If you mean the request that actually expands the prompt, then yeah that wasn't included in this enum yet. It would be the same as the execute tool flow though
| #[serde(untagged)] | ||
| pub enum McpServerConfig { | ||
| Local(LocalMcpServerConfig), | ||
| StreamableHTTP(StreamableHTTPMcpServerConfig), |
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 think we can just name this variant remote (as well as StreamableHTTPMcpServerConfig to just RemoteMcpServerConfig). We won't be differentiating bewteen SSE and Streamable HTTP from the config.
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.
SSE + Streamable have the same exact config structure? Then yeah sounds good.
| pub struct StreamableHTTPMcpServerConfig { | ||
| /// The URL endpoint for HTTP-based MCP servers | ||
| pub url: String, | ||
| /// HTTP headers to include when communicating with HTTP-based MCP servers | ||
| #[serde(default)] | ||
| pub headers: HashMap<String, String>, | ||
| /// Timeout for each mcp request in ms | ||
| #[serde(alias = "timeout")] | ||
| #[serde(default = "default_timeout")] | ||
| pub timeout_ms: u64, | ||
| } |
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.
Missing here is the auth related attributes. I'll add that in once this merges.
* Revert "feat: Updates models to match latest, including endpoint resolver (#3262)" (#3288) This reverts commit 884b27f. * chore: bump version to 1.19.2 * fix: racing condition on conduit when printing (#3308) * chore: version bump to 1.19.3 (#3310) * refactor: migrate from directories to hierarchical paths module (#3309) - Replace directories module with new paths module using PathResolver pattern - Add workspace and global path scopes with clear separation of concerns - Implement static path methods to avoid circular dependencies in Database/Settings - Centralize all path constants and patterns in dedicated modules This refactoring improves path management consistency and provides a cleaner, more maintainable architecture for handling file system paths throughout the application. * Add auth login failure telemetry for cli (#3317) * add auth login failure telemetry * fix: expand ~ in prompt file:// URIs (#3301) * Refactor /Usage into smaller modules (#3324) Co-authored-by: Akhilesh Bontala <[email protected]> * feat: add agent crate (#3150) * refactor: centralize environment variable access (#3315) * Shim layer for env variable access * feat: warn when duplicate agents are found during load (#3335) * Upgrade delegate with better UX for notifications and change the file dependence. (#3337) * chore: move RTS code from agent crate to chat-cli (#3340) * fix: block dangerous patterns for tool calls (#3313) * first commit * disallowed dangerous patterns as a first priority for executing tools * recovered hooks help * got rid of removeme * got rid of space * refactored requires_acceptance to ensure correct ordering of safeguards and allowed commands * formatted for cargo again * chore: remove duplicate and unused API code from the agent crate (#3342) * Revert "feat: rebrand paths from .aws/amazonq/ and .amazonq/ to .kiro-cli/" This reverts commit 44dad82. * Revert "feat: rebrand environment variables from Q_/AMAZON_Q_ to KIRO_" This reverts commit 49cbe8e. --------- Co-authored-by: Brandon Kiser <[email protected]> Co-authored-by: Brandon Kiser <[email protected]> Co-authored-by: Felix Ding <[email protected]> Co-authored-by: abhraina-aws <[email protected]> Co-authored-by: Jonathan Little <[email protected]> Co-authored-by: Akhilesh Bontala <[email protected]> Co-authored-by: Akhilesh Bontala <[email protected]> Co-authored-by: ekang7 <[email protected]>
Description of changes:
agentthat implements the agent config. This crate is based on an actor model where an agent can be interacted with using anAgentHandle, from which messages (send prompt, approve tool use, etc.) are sent and events are received.runCLI is provided which illustrates the APIThis contains substantial code duplication from
chat-clifor the API client and database since this was developed in isolation from the rest of the code (see fast follows below).A lot of this is still WIP, the goal here is to get this pushed and incrementally develop this crate while working on the
/delegatetool and overall chat refactor.Todos (as of now):
fs_readandfs_write, and the experimental tools we have today.There are a lot of details that will be uncovered as more work is done adding this crate to the main
chat-clicode base.Fast Follows:
Agentwould instead just have aBox<dyn Model>passed to it. All of thertsimplementation forModelshould be moved tochat-cliinstead.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.