rucora 0.1.5

High-performance, type-safe LLM agent framework with built-in tools and multi-provider support
Documentation
//! Agent(智能体)模块
//!
//! # 概述
//!
//! 本模块提供多种预定义的 Agent 类型,每种类型针对不同的使用场景:
//!
//! ## 基础层 Agent(常用)
//!
//! | Agent 类型 | 职责 | 适用场景 |
//! |------------|------|----------|
//! | [`SimpleAgent`] | 简单问答 | 翻译、总结、一次性任务 |
//! | [`ChatAgent`] | 纯对话 | 客服、心理咨询、闲聊 |
//! | [`ToolAgent`] | 工具调用 | 执行具体任务(默认选择) |
//!
//! ## 进阶层 Agent(复杂任务)
//!
//! | Agent 类型 | 职责 | 适用场景 |
//! |------------|------|----------|
//! | [`ReActAgent`] | 推理 + 行动 | 多步推理任务 |
//! | [`ReflectAgent`] | 反思迭代 | 代码生成、写作 |
//!
//! # 快速开始
//!
//! ## 选择 Agent 类型
//!
//! ```text
//! 是否需要工具调用?
//!//!   ├─ 否 ──► 是否需要多轮对话历史?
//!   │           │
//!   │           ├─ 否 ──► SimpleAgent(简单问答)
//!   │           │
//!   │           └─ 是 ──► ChatAgent(对话)
//!//!   └─ 是 ──► 需要多少步?
//!//!             ├─ 1-2 步 ──► ToolAgent(默认选择)
//!//!             ├─ 3-5 步 ──► ReActAgent(推理 + 行动)
//!//!             ├─ 5+ 步 ──► PlanAgent(规划执行)
//!//!             └─ 需要高质量 ──► ReflectAgent(反思迭代)
//! ```
//!
//! ## 使用示例
//!
//! ### SimpleAgent - 简单问答
//!
//! ```rust,no_run
//! use rucora::agent::SimpleAgent;
//! use rucora::provider::OpenAiProvider;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = OpenAiProvider::from_env()?;
//!
//! let agent = SimpleAgent::builder()
//!     .provider(provider)
//!     .model("gpt-4o-mini")
//!     .system_prompt("你是一个翻译助手")
//!     .temperature(0.3)
//!     .try_build()?;
//!
//! let output = agent.run("把'Hello'翻译成中文").await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### ChatAgent - 多轮对话
//!
//! ```rust,no_run
//! use rucora::agent::ChatAgent;
//! use rucora::provider::OpenAiProvider;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = OpenAiProvider::from_env()?;
//!
//! let agent = ChatAgent::builder()
//!     .provider(provider)
//!     .model("gpt-4o-mini")
//!     .system_prompt("你是友好的助手")
//!     .with_conversation(true)
//!     .try_build()?;
//!
//! agent.run("你好").await?;
//! agent.run("今天天气怎么样?").await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### ToolAgent - 工具调用(推荐默认)
//!
//! ```rust,no_run
//! use rucora::agent::ToolAgent;
//! use rucora::provider::OpenAiProvider;
//! use rucora::tools::ShellTool;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = OpenAiProvider::from_env()?;
//!
//! let agent = ToolAgent::builder()
//!     .provider(provider)
//!     .model("gpt-4o-mini")
//!     .system_prompt("你是有用的助手")
//!     .tool(ShellTool)
//!     .try_build()?;
//!
//! let output = agent.run("帮我列出当前目录的文件").await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### ReActAgent - 推理 + 行动
//!
//! ```rust,no_run
//! use rucora::agent::ReActAgent;
//! use rucora::provider::OpenAiProvider;
//! use rucora::tools::{ShellTool, FileReadTool};
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = OpenAiProvider::from_env()?;
//!
//! let agent = ReActAgent::builder()
//!     .provider(provider)
//!     .model("gpt-4o-mini")
//!     .tools(vec![ShellTool, FileReadTool])
//!     .max_steps(15)
//!     .try_build()?;
//!
//! let output = agent.run("帮我分析这个项目的代码结构").await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### ReflectAgent - 反思迭代
//!
//! ```rust,no_run
//! use rucora::agent::ReflectAgent;
//! use rucora::provider::OpenAiProvider;
//! use rucora::tools::FileWriteTool;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = OpenAiProvider::from_env()?;
//!
//! let agent = ReflectAgent::builder()
//!     .provider(provider)
//!     .model("gpt-4o-mini")
//!     .tool(FileWriteTool)
//!     .max_iterations(3)
//!     .try_build()?;
//!
//! let output = agent.run("帮我写一个快速排序算法").await?;
//! # Ok(())
//! # }
//! ```
//!
//! # 架构设计
//!
//! ## 决策与执行分离
//!
//! ```
//! ┌─────────────────────────────────────────────────────────┐
//! │                      Agent Trait                        │
//! │  ┌─────────────────┐    ┌─────────────────────────┐    │
//! │  │   决策层        │    │   执行层(默认实现)     │    │
//! │  │   (think)       │    │   (run/run_stream)      │    │
//! │  │   负责"做什么"   │    │   负责"怎么做"          │    │
//! │  └─────────────────┘    └─────────────────────────┘    │
//! └─────────────────────────────────────────────────────────┘
//! ```
//!
//! - **决策层**:每个 Agent 类型有不同的思考策略
//! - **执行层**:所有 Agent 共享相同的执行能力([`DefaultExecution`])
//!
//! ## 共享执行能力
//!
//! 所有 Agent 类型都组合了 [`DefaultExecution`] 来获得执行能力:
//!
//! - 工具调用循环
//! - 流式执行
//! - 并发控制
//! - 策略检查
//! - 观测器协议
//!
//! # 向后兼容
//!
//! `DefaultAgent` 作为 [`ToolAgent`] 的别名保留,但已标记为 deprecated:
//!
//! ```rust
//! // 旧代码(仍然可用)
//! use rucora::agent::DefaultAgent;
//!
//! // 新代码(推荐)
//! use rucora::agent::ToolAgent;
//! ```

// 执行能力模块
pub mod execution;

// 工具相关模块
pub mod loop_detector;
pub mod policy;
pub mod tool_call_config;
pub mod tool_execution;
pub mod tool_registry;

// 结构化数据提取模块
pub mod extractor;

// 基础层 Agent
pub mod chat;
pub mod simple;
pub mod tool;

// 进阶层 Agent
pub mod react;
pub mod reflect;

// 重新导出主要类型
pub use execution::DefaultExecution;
pub use loop_detector::{LoopDetectionResult, LoopDetector, LoopDetectorConfig};
pub use policy::{DefaultToolPolicy, ToolPolicy};
pub use tool_call_config::{
    CacheConfig, CircuitBreakerConfig, ConcurrencyConfig, RetryConfig, RetryStrategy,
    TimeoutConfig, ToolCallEnhancedConfig, ToolCallEnhancedRuntime,
};
pub use tool_registry::{ToolRegistry, ToolSource, ToolWrapper};

// 基础层
pub use chat::{ChatAgent, ChatAgentBuilder};
pub use simple::{SimpleAgent, SimpleAgentBuilder};
pub use tool::{ToolAgent, ToolAgentBuilder};

// 进阶层
pub use react::{ReActAgent, ReActAgentBuilder};
pub use reflect::{ReflectAgent, ReflectAgentBuilder};

// Extractor
pub use extractor::{ExtractionError, ExtractionResponse, Extractor, ExtractorBuilder, TokenUsage};

// 向后兼容
#[deprecated(
    since = "0.2.0",
    note = "DefaultAgent 已重命名为 ToolAgent,请使用 ToolAgent"
)]
pub use tool::ToolAgent as DefaultAgent;

// ========== 流式输出便捷类型 ==========

use futures_util::stream::BoxStream;
use rucora_core::channel::types::ChannelEvent;
use rucora_core::error::AgentError;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Agent 流式输出包装器。
///
/// 包装 `BoxStream`,提供便捷的 `.next()` 和 `.collect_text()` 方法。
///
/// # 使用方式
///
/// ## 方式 1:直接包装 `run_stream()` 的返回值
///
/// ```rust,no_run
/// use rucora::agent::{AgentStream, SimpleAgent};
/// use rucora::prelude::*;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let agent = SimpleAgent::builder()
/// #     .provider(rucora::provider::OpenAiProvider::from_env()?)
/// #     .model("gpt-4o-mini")
/// #     .build();
/// let mut stream = AgentStream::new(agent.run_stream("你好".into()));
/// while let Some(event) = stream.next().await {
///     match event? {
///         ChannelEvent::TokenDelta(delta) => print!("{}", delta.delta),
///         _ => {}
///     }
/// }
/// # Ok(())
/// # }
/// ```
///
/// ## 方式 2:使用 `.collect_text()` 直接获取拼接文本
///
/// ```rust,no_run
/// use rucora::agent::AgentStream;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let agent = rucora::agent::SimpleAgent::builder()
/// #     .provider(rucora::provider::OpenAiProvider::from_env()?)
/// #     .model("gpt-4o-mini")
/// #     .build();
/// let text = AgentStream::new(agent.run_stream("你好".into())).collect_text().await?;
/// # Ok(())
/// # }
/// ```
///
/// ## 方式 3(推荐):直接使用 Agent 上的 `run_stream_text()`
///
/// 如果只需要最终文本,每个 Agent 类型都提供了 `run_stream_text()` 方法:
///
/// ```rust,no_run
/// use rucora::prelude::*;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let agent = rucora::agent::SimpleAgent::builder()
/// #     .provider(rucora::provider::OpenAiProvider::from_env()?)
/// #     .model("gpt-4o-mini")
/// #     .build();
/// let text = agent.run_stream_text("你好").await?;
/// # Ok(())
/// # }
/// ```
pub struct AgentStream(BoxStream<'static, Result<ChannelEvent, AgentError>>);

impl AgentStream {
    /// 创建新的流式输出包装器。
    pub fn new(stream: BoxStream<'static, Result<ChannelEvent, AgentError>>) -> Self {
        Self(stream)
    }

    /// 获取下一个事件。
    ///
    /// 等同于 `.0.next().await`,但用户不需要引入 `futures_util::StreamExt`。
    pub async fn next(&mut self) -> Option<Result<ChannelEvent, AgentError>> {
        futures_util::StreamExt::next(&mut self.0).await
    }

    /// 消费流,收集所有 `TokenDelta` 并拼接为完整文本返回。
    ///
    /// 忽略 `ToolCall`、`ToolResult`、`Message` 等非文本事件。
    /// 遇到 `Error` 事件时立即返回错误。
    ///
    /// # 示例
    ///
    /// ```rust,no_run
    /// use rucora::prelude::*;
    ///
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let agent = rucora::agent::SimpleAgent::builder()
    /// #     .provider(rucora::provider::OpenAiProvider::from_env()?)
    /// #     .model("gpt-4o-mini")
    /// #     .build();
    /// let text = agent.run_stream("你好".into()).collect_text().await?;
    /// println!("{}", text);
    /// # Ok(())
    /// # }
    /// ```
    pub async fn collect_text(mut self) -> Result<String, AgentError> {
        let mut text = String::new();

        while let Some(event) = futures_util::StreamExt::next(&mut self.0).await {
            match event? {
                ChannelEvent::TokenDelta(delta) => {
                    text.push_str(&delta.delta);
                }
                ChannelEvent::Error(err) => {
                    return Err(AgentError::Message(err.message));
                }
                _ => {}
            }
        }

        Ok(text)
    }
}

impl futures_util::Stream for AgentStream {
    type Item = Result<ChannelEvent, AgentError>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.0.as_mut().poll_next(cx)
    }
}

/// Re-export `futures_util::StreamExt`,方便用户使用 `.next().await`。
///
/// 使用 `use rucora::prelude::StreamExt;` 或 `use rucora::agent::StreamExt;` 即可。
pub use futures_util::StreamExt;