2d0d5c1592
新增 7 个示例覆盖全 Phase 公共 API(不依赖 API key 即可运行): - agent_session_demo:AgentBuilder → AgentSession → SessionMemory - custom_tool:BaseTool 注册 + invoke/invoke_all + 权限检查 - prompt_composer:PromptTemplate + PromptComposer + validate_messages - task_agent_demo:JsonPlanParser + Step 状态机 + 错误路径 - conversation_memory_demo:滑动窗口 + 多角色 + 隔离 - knowledge_search_demo:KnowledgeStore + 关键词检索 + 停用词过滤 - streaming_events_demo:submit_stream 事件消费 + 队列耗尽错误路径
113 lines
4.8 KiB
Rust
113 lines
4.8 KiB
Rust
//! task_agent_demo —— Plan 解析、Step 状态机、错误路径。
|
||
//!
|
||
//! 演示:
|
||
//! 1. `JsonPlanParser::parse` 解析合法 JSON 输入
|
||
//! 2. `Plan` / `Step` 数据结构遍历
|
||
//! 3. `StepStatus` 状态机:Pending → Running → Completed / Failed / Skipped
|
||
//! 4. `is_pending()` / `is_terminal()` 语义
|
||
//! 5. 错误路径:非法 JSON / 空 steps / 缺字段 → `AgentError::PlanParse`
|
||
//!
|
||
//! 运行:`cargo run --example task_agent_demo`
|
||
//!
|
||
//! ## 已知技术债(v0.2 迁移指南)
|
||
//!
|
||
//! 本示例使用 `#[deprecated]` 标记的旧 wire-format 类型:
|
||
//! - `ChatResponse`、`OpenaiChatMessage`、`FinishReason` —— `OpenaiChatProvider::chat_inner()`
|
||
//! 内部转换层仍在使用(参见 `docs/10a-phase0-types-and-trait.md` §2.5.1),
|
||
//! 故结构体定义保留。
|
||
//! - `StepStatus::Completed(ChatResponse)` —— 因为 `Step` 的"已完成"变体需携带
|
||
//! provider 响应,目前沿用旧的 `ChatResponse`。
|
||
//!
|
||
//! **触发迁移的条件**:v0.2 引入 IR 层的 `StepResult` / 切换为 `MessageResponse`。
|
||
//! **迁移路径**:将本文件 `ChatResponse`/`OpenaiChatMessage`/`FinishReason` 替换为
|
||
//! `MessageResponse`/`Message`/`StopReason`,移除顶部 `#![allow(deprecated)]`。
|
||
//! 上层应用代码(`TaskAgent` 消费者)也可同步迁移。
|
||
|
||
#![allow(deprecated)]
|
||
|
||
use agcore::agent::{AgentError, JsonPlanParser, PlanParser, Step, StepStatus};
|
||
use agcore::llm::types::openai_message::OpenaiChatMessage;
|
||
use agcore::llm::types::shared::FinishReason;
|
||
use agcore::llm::types::{ChatResponse, Usage};
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
// 1. JsonPlanParser 解析合法 JSON
|
||
println!("=== JsonPlanParser 解析合法 JSON ===");
|
||
let parser = JsonPlanParser;
|
||
let input = r#"{
|
||
"steps": [
|
||
{"description": "查询北京天气"},
|
||
{"description": "根据天气计算穿衣建议"},
|
||
{"description": "生成最终回复"}
|
||
]
|
||
}"#;
|
||
let plan = parser
|
||
.parse(input, "为用户生成今日出行建议")
|
||
.await
|
||
.expect("合法 JSON 应解析成功");
|
||
println!("Plan goal: {}", plan.goal);
|
||
println!("Plan id: {}", plan.id);
|
||
println!("Steps: {}", plan.steps.len());
|
||
for (i, step) in plan.steps.iter().enumerate() {
|
||
println!(
|
||
" [{}] {} (pending={}, terminal={})",
|
||
i,
|
||
step.description,
|
||
step.status.is_pending(),
|
||
step.status.is_terminal()
|
||
);
|
||
}
|
||
assert!(plan.steps.iter().all(|s| s.status.is_pending()));
|
||
|
||
// 2. Step 状态机:Pending → Running → Completed
|
||
println!("\n=== Step 状态机:Pending → Running → Completed ===");
|
||
let mut step = plan.steps.into_iter().next().expect("应有 step");
|
||
println!("初始: pending={}", step.status.is_pending());
|
||
assert!(step.status.is_pending());
|
||
|
||
step.status = StepStatus::Running;
|
||
println!("Running: pending={}, terminal={}", step.status.is_pending(), step.status.is_terminal());
|
||
|
||
step.status = StepStatus::Completed(ChatResponse {
|
||
message: OpenaiChatMessage::assistant_text("天气:晴,22°C"),
|
||
usage: Usage::from_input_output(5, 10),
|
||
stop_reason: Some(FinishReason::Stop),
|
||
});
|
||
println!("Completed: pending={}, terminal={}", step.status.is_pending(), step.status.is_terminal());
|
||
assert!(step.status.is_terminal());
|
||
|
||
// 3. 失败路径
|
||
println!("\n=== Step 状态机:失败路径 ===");
|
||
let mut fail_step = Step::new(0, "调用天气 API");
|
||
fail_step.status = StepStatus::Failed(AgentError::Other("API 不可用".into()));
|
||
println!("Failed: pending={}, terminal={}", fail_step.status.is_pending(), fail_step.status.is_terminal());
|
||
assert!(fail_step.status.is_terminal());
|
||
|
||
// 4. 跳过路径
|
||
let mut skipped = Step::new(0, "可选步骤");
|
||
skipped.status = StepStatus::Skipped;
|
||
println!("Skipped: terminal={}", skipped.status.is_terminal());
|
||
assert!(skipped.status.is_terminal());
|
||
|
||
// 5. 错误路径 1:非法 JSON
|
||
println!("\n=== 错误路径:非法 JSON ===");
|
||
let err = parser.parse("not json", "goal").await.unwrap_err();
|
||
println!("错误: {err}");
|
||
assert!(matches!(err, AgentError::PlanParse(_)));
|
||
|
||
// 6. 错误路径 2:空 steps
|
||
println!("\n=== 错误路径:空 steps ===");
|
||
let err = parser.parse(r#"{"steps": []}"#, "goal").await.unwrap_err();
|
||
println!("错误: {err}");
|
||
assert!(matches!(err, AgentError::PlanParse(_)));
|
||
|
||
// 7. 错误路径 3:缺 description 字段
|
||
println!("\n=== 错误路径:缺 description 字段 ===");
|
||
let bad_input = r#"{"steps": [{"description": "ok"}, {"no_desc": true}]}"#;
|
||
let err = parser.parse(bad_input, "goal").await.unwrap_err();
|
||
println!("错误: {err}");
|
||
assert!(matches!(err, AgentError::PlanParse(_)));
|
||
|
||
println!("\n✓ task_agent_demo 完成");
|
||
} |