fix: Forgot to automatically add the bidirectional communication back up to parent agents from sub-agents (i.e. need to be able to check inbox and send messages)
This commit is contained in:
+7
-1
@@ -6,6 +6,9 @@ use crate::{
|
|||||||
function::{Functions, run_llm_function},
|
function::{Functions, run_llm_function},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::config::prompts::{
|
||||||
|
DEFAULT_SPAWN_INSTRUCTIONS, DEFAULT_TEAMMATE_INSTRUCTIONS, DEFAULT_TODO_INSTRUCTIONS,
|
||||||
|
};
|
||||||
use crate::vault::SECRET_RE;
|
use crate::vault::SECRET_RE;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use fancy_regex::Captures;
|
use fancy_regex::Captures;
|
||||||
@@ -13,7 +16,6 @@ use inquire::{Text, validator::Validation};
|
|||||||
use rust_embed::Embed;
|
use rust_embed::Embed;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{ffi::OsStr, path::Path};
|
use std::{ffi::OsStr, path::Path};
|
||||||
use crate::config::prompts::{DEFAULT_SPAWN_INSTRUCTIONS, DEFAULT_TODO_INSTRUCTIONS};
|
|
||||||
|
|
||||||
const DEFAULT_AGENT_NAME: &str = "rag";
|
const DEFAULT_AGENT_NAME: &str = "rag";
|
||||||
|
|
||||||
@@ -200,6 +202,8 @@ impl Agent {
|
|||||||
functions.append_supervisor_functions();
|
functions.append_supervisor_functions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
functions.append_teammate_functions();
|
||||||
|
|
||||||
agent_config.replace_tools_placeholder(&functions);
|
agent_config.replace_tools_placeholder(&functions);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -340,6 +344,8 @@ impl Agent {
|
|||||||
output.push_str(DEFAULT_SPAWN_INSTRUCTIONS);
|
output.push_str(DEFAULT_SPAWN_INSTRUCTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output.push_str(DEFAULT_TEAMMATE_INSTRUCTIONS);
|
||||||
|
|
||||||
self.interpolate_text(&output)
|
self.interpolate_text(&output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -29,8 +29,6 @@ pub(in crate::config) const DEFAULT_SPAWN_INSTRUCTIONS: &str = indoc! {"
|
|||||||
| `agent__collect` | Blocking wait: wait for an agent to finish, return its output. |
|
| `agent__collect` | Blocking wait: wait for an agent to finish, return its output. |
|
||||||
| `agent__list` | List all spawned agents and their status. |
|
| `agent__list` | List all spawned agents and their status. |
|
||||||
| `agent__cancel` | Cancel a running agent by ID. |
|
| `agent__cancel` | Cancel a running agent by ID. |
|
||||||
| `agent__send_message` | Send a text message to a sibling or child agent's inbox. |
|
|
||||||
| `agent__check_inbox` | Check your own inbox for messages from other agents. |
|
|
||||||
| `agent__task_create` | Create a task in the dependency-aware task queue. |
|
| `agent__task_create` | Create a task in the dependency-aware task queue. |
|
||||||
| `agent__task_list` | List all tasks and their status/dependencies. |
|
| `agent__task_list` | List all tasks and their status/dependencies. |
|
||||||
| `agent__task_complete` | Mark a task done; returns any newly unblocked tasks. Auto-dispatches agents for tasks with a designated agent. |
|
| `agent__task_complete` | Mark a task done; returns any newly unblocked tasks. Auto-dispatches agents for tasks with a designated agent. |
|
||||||
@@ -69,14 +67,6 @@ pub(in crate::config) const DEFAULT_SPAWN_INSTRUCTIONS: &str = indoc! {"
|
|||||||
|
|
||||||
**NEVER spawn sequentially when tasks are independent.** Parallel is always better.
|
**NEVER spawn sequentially when tasks are independent.** Parallel is always better.
|
||||||
|
|
||||||
### Teammate Messaging
|
|
||||||
|
|
||||||
Sibling agents (spawned by the same parent) can communicate directly:
|
|
||||||
- `agent__send_message --to <agent_id> --content \"your message\"`: Send to a running sibling
|
|
||||||
- `agent__check_inbox`: Check for messages from siblings or parent
|
|
||||||
|
|
||||||
Use teammate messaging when agents need to coordinate or share intermediate findings.
|
|
||||||
|
|
||||||
### Task Queue (for complex dependency chains)
|
### Task Queue (for complex dependency chains)
|
||||||
|
|
||||||
When tasks have ordering requirements, use the task queue:
|
When tasks have ordering requirements, use the task queue:
|
||||||
@@ -95,3 +85,16 @@ pub(in crate::config) const DEFAULT_SPAWN_INSTRUCTIONS: &str = indoc! {"
|
|||||||
agent__task_complete --task_id task_1
|
agent__task_complete --task_id task_1
|
||||||
```
|
```
|
||||||
"};
|
"};
|
||||||
|
|
||||||
|
pub(in crate::config) const DEFAULT_TEAMMATE_INSTRUCTIONS: &str = indoc! {"
|
||||||
|
## Teammate Messaging
|
||||||
|
|
||||||
|
You have tools to communicate with other agents running alongside you:
|
||||||
|
- `agent__send_message --id <agent_id> --message \"...\"`: Send a message to a sibling or parent agent.
|
||||||
|
- `agent__check_inbox`: Check for messages sent to you by other agents.
|
||||||
|
|
||||||
|
If you are working alongside other agents (e.g. reviewing different files, exploring different areas):
|
||||||
|
- **Check your inbox** before finalizing your work to incorporate any cross-cutting findings from teammates.
|
||||||
|
- **Send messages** to teammates when you discover something that affects their work.
|
||||||
|
- Messages are delivered to the agent's inbox and read on their next `check_inbox` call."
|
||||||
|
};
|
||||||
|
|||||||
@@ -276,6 +276,11 @@ impl Functions {
|
|||||||
.extend(supervisor::supervisor_function_declarations());
|
.extend(supervisor::supervisor_function_declarations());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append_teammate_functions(&mut self) {
|
||||||
|
self.declarations
|
||||||
|
.extend(supervisor::teammate_function_declarations());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear_mcp_meta_functions(&mut self) {
|
pub fn clear_mcp_meta_functions(&mut self) {
|
||||||
self.declarations.retain(|d| {
|
self.declarations.retain(|d| {
|
||||||
!d.name.starts_with(MCP_INVOKE_META_FUNCTION_NAME_PREFIX)
|
!d.name.starts_with(MCP_INVOKE_META_FUNCTION_NAME_PREFIX)
|
||||||
|
|||||||
+42
-37
@@ -118,43 +118,6 @@ pub fn supervisor_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
},
|
},
|
||||||
agent: false,
|
agent: false,
|
||||||
},
|
},
|
||||||
FunctionDeclaration {
|
|
||||||
name: format!("{SUPERVISOR_FUNCTION_PREFIX}send_message"),
|
|
||||||
description: "Send a text message to a running subagent's inbox.".to_string(),
|
|
||||||
parameters: JsonSchema {
|
|
||||||
type_value: Some("object".to_string()),
|
|
||||||
properties: Some(IndexMap::from([
|
|
||||||
(
|
|
||||||
"id".to_string(),
|
|
||||||
JsonSchema {
|
|
||||||
type_value: Some("string".to_string()),
|
|
||||||
description: Some("The target agent ID".into()),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"message".to_string(),
|
|
||||||
JsonSchema {
|
|
||||||
type_value: Some("string".to_string()),
|
|
||||||
description: Some("The message text to send".into()),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
])),
|
|
||||||
required: Some(vec!["id".to_string(), "message".to_string()]),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
agent: false,
|
|
||||||
},
|
|
||||||
FunctionDeclaration {
|
|
||||||
name: format!("{SUPERVISOR_FUNCTION_PREFIX}check_inbox"),
|
|
||||||
description: "Check for and drain all pending messages in your inbox.".to_string(),
|
|
||||||
parameters: JsonSchema {
|
|
||||||
type_value: Some("object".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
agent: false,
|
|
||||||
},
|
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{SUPERVISOR_FUNCTION_PREFIX}task_create"),
|
name: format!("{SUPERVISOR_FUNCTION_PREFIX}task_create"),
|
||||||
description: "Create a task in the task queue. Returns the task ID.".to_string(),
|
description: "Create a task in the task queue. Returns the task ID.".to_string(),
|
||||||
@@ -241,6 +204,48 @@ pub fn supervisor_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn teammate_function_declarations() -> Vec<FunctionDeclaration> {
|
||||||
|
vec![
|
||||||
|
FunctionDeclaration {
|
||||||
|
name: format!("{SUPERVISOR_FUNCTION_PREFIX}send_message"),
|
||||||
|
description: "Send a text message to a sibling or child agent's inbox. Use to share cross-cutting findings or coordinate with teammates.".to_string(),
|
||||||
|
parameters: JsonSchema {
|
||||||
|
type_value: Some("object".to_string()),
|
||||||
|
properties: Some(IndexMap::from([
|
||||||
|
(
|
||||||
|
"id".to_string(),
|
||||||
|
JsonSchema {
|
||||||
|
type_value: Some("string".to_string()),
|
||||||
|
description: Some("The target agent ID".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"message".to_string(),
|
||||||
|
JsonSchema {
|
||||||
|
type_value: Some("string".to_string()),
|
||||||
|
description: Some("The message text to send".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
required: Some(vec!["id".to_string(), "message".to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
agent: false,
|
||||||
|
},
|
||||||
|
FunctionDeclaration {
|
||||||
|
name: format!("{SUPERVISOR_FUNCTION_PREFIX}check_inbox"),
|
||||||
|
description: "Check for and drain all pending messages in your inbox from sibling agents or your parent.".to_string(),
|
||||||
|
parameters: JsonSchema {
|
||||||
|
type_value: Some("object".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
agent: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_supervisor_tool(
|
pub async fn handle_supervisor_tool(
|
||||||
config: &GlobalConfig,
|
config: &GlobalConfig,
|
||||||
cmd_name: &str,
|
cmd_name: &str,
|
||||||
|
|||||||
Reference in New Issue
Block a user