tiny_agent/tools/default_tools/
spawn_agent.rs1use crate::{
2 core::{Agent, AgentRunTime, AgentRuntimeConfig},
3 sandbox::Sandbox,
4 tools::{ToolOutcome, ToolRegistry},
5};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use serde_json::{Value, json};
9use std::sync::Arc;
10use tokio_util::sync::CancellationToken;
11
12#[derive(Debug, Deserialize, JsonSchema)]
13pub struct SpawnAgentArgs {
14 task: String,
16}
17
18#[derive(Debug, Serialize)]
19struct SpawnAgentOutput {
20 status: String,
21 child_session_id: String,
22 final_resp: Option<String>,
23 detail: Value,
24}
25
26pub fn register_spawn_agent(registry: &mut ToolRegistry, child_config: AgentRuntimeConfig) {
27 registry.register(
28 "spawn_agent",
29 "启动一个子 agent runtime 执行独立子任务。子 agent 使用独立会话历史,但共享父 agent 当前 sandbox,返回子会话 id 和最终结果",
30 false,
31 move |sandbox, args: SpawnAgentArgs| {
32 let child_config = child_config.clone();
33 async move { spawn_agent(child_config, sandbox, args).await }
34 },
35 );
36}
37
38async fn spawn_agent(
39 mut child_config: AgentRuntimeConfig,
40 parent_sandbox: Arc<dyn Sandbox>,
41 args: SpawnAgentArgs,
42) -> Result<ToolOutcome, String> {
43 child_config.sandbox = parent_sandbox;
45 let runtime = AgentRunTime::from_config(child_config).map_err(|e| e.to_string())?;
46 let child_session_id = runtime.create_session().await.map_err(|e| e.to_string())?;
47 let ready = runtime
48 .submit(&child_session_id, args.task)
49 .await
50 .map_err(|e| e.to_string())?;
51 let outcome = runtime
52 .run(ready, CancellationToken::new())
53 .await
54 .map_err(|e| e.to_string())?;
55
56 let output = match outcome {
57 Agent::Success(ctx) => SpawnAgentOutput {
58 status: "success".to_string(),
59 child_session_id,
60 final_resp: ctx.final_resp,
61 detail: json!({}),
62 },
63 Agent::Fail(_, failure) => SpawnAgentOutput {
64 status: "failed".to_string(),
65 child_session_id,
66 final_resp: None,
67 detail: json!({
68 "kind": failure.kind.as_str(),
69 "message": failure.message,
70 }),
71 },
72 Agent::WaitingForUser(_, interaction) => SpawnAgentOutput {
73 status: "waiting_for_user".to_string(),
74 child_session_id,
75 final_resp: None,
76 detail: json!({
77 "interaction": interaction,
78 }),
79 },
80 Agent::Interrupted(_) => SpawnAgentOutput {
81 status: "interrupted".to_string(),
82 child_session_id,
83 final_resp: None,
84 detail: json!({}),
85 },
86 other => SpawnAgentOutput {
87 status: "stopped".to_string(),
88 child_session_id,
89 final_resp: None,
90 detail: json!({
91 "state": format!("{other:?}"),
92 }),
93 },
94 };
95 let value = serde_json::to_value(output).map_err(|e| e.to_string())?;
96 Ok(value.into())
97}