Skip to main content

agent_context/
lib.rs

1//! # agent-context
2//!
3//! 通用、后端无关的 LLM 对话上下文管理器,基于 [kameo](https://crates.io/crates/kameo) Actor 模型构建。
4//!
5//! ## 核心概念
6//!
7//! ### 三区 + Scratch 消息模型
8//!
9//! 上下文消息按可变性分为三个存储区域,加上一个不存储的 Scratch 层,按序拼接为完整对话:
10//!
11//! | 区域 | 容器 | 可变性 | 用途 |
12//! |------|------|--------|------|
13//! | **immutable** | [`ReadOnly`] | 不可变 | 系统提示词、预设上下文等构造后不变的消息 |
14//! | **compressed** | `Vec` | 仅压缩时写入 | 历史对话压缩后的摘要 |
15//! | **incremental** | `Vec` | 完全可变 | 当前活跃对话,支持增删改查 |
16//! | **scratch** | — | 不存储 | 每轮刷新的临时元数据(时间、工作目录等),通过 [`ScratchOpts`] 配置 |
17//!
18//! 拼接顺序:immutable → compressed → incremental → scratch(如有)。
19//! Scratch 由调用方在每次 [`SendMsg`]/[`SendStreamMsg`] 时通过 Opts 传入,
20//! 不存入任何区域,不触发变更事件,不参与序列化。
21//!
22//! ### 后端 trait
23//!
24//! [`ContextBackend`] 是核心抽象,封装 LLM 后端的:
25//!
26//! - **消息工厂**:[`user_message`](ContextBackend::user_message)、[`system_message`](ContextBackend::system_message)、[`tool_message`](ContextBackend::tool_message)
27//! - **格式转换**:[`to_system_message`](ContextBackend::to_system_message)、[`to_request_messages`](ContextBackend::to_request_messages)
28//! - **响应解析**:[`extract_messages_from_backend_response`](ContextBackend::extract_messages_from_backend_response)
29//! - **模型对话**:[`send`](ContextBackend::send)、[`send_stream`](ContextBackend::send_stream)、[`estimate_tokens`](ContextBackend::estimate_tokens)
30//! - **配置信息**:[`context_window`](ContextBackend::context_window)
31//!
32//! 实现 `ContextBackend` 即可让 AC 支持任意 LLM 后端(DeepSeek、智谱、OpenAI 等)。
33//!
34//! ### 变更通知
35//!
36//! 通过 [`with_on_change`](AgentContext::with_on_change) 注册回调,监听 [`ChangeEvent`] 实时追踪消息变化。
37//!
38//! ### 上下文压缩
39//!
40//! 当对话过长时,通过 [`CompressMsg`] 触发压缩。支持 [`CompressStrategy::Summarize`] 策略:保留最近 N 条,
41//! 将更早的消息交由后端 LLM 生成摘要存入 compressed 区。
42//!
43//! ## 快速开始
44//!
45//! ```ignore
46//! use agent_context::{AgentContext, AppendMsg, SendMsg, MessagesMsg, ContextBackend, ScratchOpts};
47//!
48//! // 1. 实现 ContextBackend(以你的 LLM SDK 类型)+ ScratchOpts
49//! // 2. 创建 Actor
50//! let ctx = AgentContext::new(my_backend, vec![backend.system_message("You are a helpful assistant.")]);
51//! let actor = AgentContext::spawn(ctx);
52//!
53//! // 3. 发送消息(scratch 通过 opts 传入)
54//! actor.ask(AppendMsg { message: user_msg }).await?;
55//! actor.ask(SendMsg { opts: my_opts }).await?;
56//!
57//! // 4. 读取全部消息
58//! let all: Vec<_> = actor.ask(MessagesMsg).await?;
59//! ```
60
61#![forbid(
62    unused_must_use,
63    clippy::panic,
64    clippy::let_underscore_must_use,
65    clippy::disallowed_types,
66    clippy::disallowed_methods,
67    clippy::allow_attributes,
68    unfulfilled_lint_expectations
69)]
70#![deny(clippy::unwrap_used, clippy::expect_used)]
71
72mod context;
73mod error;
74mod message;
75mod readonly;
76mod role;
77
78pub use context::{
79    AgentContext, AgentSendStream, AppendMsg, ChangeEvent, ClearMsg, CompressMsg, CompressStrategy,
80    CompressedMsg, ContextBackend, ContextBackendResponse, EstimateTokensMsg, ExtendMsg,
81    FindByRoleMsg, FromJsonlMsg, Get, ImmutableMsg, IncrementalMsg, InsertMsg, IsEmpty, IsFullMsg,
82    Len, MessagesMsg, PopMsg, RemoveMsg, ResponseType, RetainMsg, ScratchOpts, SendMsg,
83    SendStreamMsg, SilentAppendMsg, StreamEvent, ToJsonlMsg, ToolCallInfo, UpdateMsg,
84};
85pub use error::AgentError;
86pub use message::ContextMessage;
87pub use readonly::ReadOnly;
88pub use role::Role;