Skip to main content

j_agent/agent/
thread_identity.rs

1//! 线程级 Agent 身份与工作目录隔离。
2//!
3//! 主 Agent、SubAgent、Teammate 各自运行在独立线程中,
4//! 通过 thread_local 记录当前线程所属的 agent 名称/类型以及工作目录覆盖。
5
6use crate::permission::queue::AgentType;
7use std::cell::RefCell;
8use std::path::{Path, PathBuf};
9
10// ========== Thread-local Agent Identity ==========
11
12thread_local! {
13    /// 当前线程所属的 agent 名称(主 agent 为 "Main",teammate 为其名称,subagent 为 sub_id)
14    static CURRENT_AGENT_NAME: RefCell<String> = RefCell::new("Main".to_string());
15    /// 当前线程所属的 agent 类型(默认 Main;teammate 设置为 Teammate,subagent 设置为 SubAgent)
16    static CURRENT_AGENT_TYPE: RefCell<AgentType> = const { RefCell::new(AgentType::Main) };
17    /// 当前线程的工作目录覆盖(worktree 模式下指向 worktree 路径)
18    static THREAD_CWD: RefCell<Option<PathBuf>> = const { RefCell::new(None) };
19}
20
21/// 设置当前线程的 agent 名称(在 teammate/subagent agent loop 启动时调用)
22///
23/// 约定:Main 返回 "Main",Teammate 返回 "Teammate@<name>",
24/// SubAgent 返回 "SubAgent@<description>"。
25/// 广播消息前缀 `<{current_agent_name()}>` 与此一致,
26/// 使 broadcast_compress 能通过 `extract_agent_source` 正确匹配自身。
27pub fn set_current_agent_name(name: &str) {
28    CURRENT_AGENT_NAME.with(|cell| {
29        *cell.borrow_mut() = name.to_string();
30    });
31}
32
33/// 设置当前线程的 agent 类型
34pub fn set_current_agent_type(agent_type: AgentType) {
35    CURRENT_AGENT_TYPE.with(|cell: &RefCell<AgentType>| {
36        *cell.borrow_mut() = agent_type;
37    });
38}
39
40/// 获取当前线程的 agent 名称(含类型前缀)
41///
42/// 返回值示例:"Main"、"Teammate@Frontend"、"SubAgent@search_for_auth"
43/// 与广播消息 `<Name>` 前缀中的 Name 一致,供 broadcast_compress 自身匹配。
44pub fn current_agent_name() -> String {
45    CURRENT_AGENT_NAME.with(|cell| cell.borrow().clone())
46}
47
48/// 获取当前线程的 agent 类型
49pub fn current_agent_type() -> AgentType {
50    CURRENT_AGENT_TYPE.with(|cell: &RefCell<AgentType>| cell.borrow().clone())
51}
52
53// ========== Thread-local CWD (worktree 隔离) ==========
54
55/// 设置当前线程的工作目录(进入 worktree 时调用)
56pub fn set_thread_cwd(path: &Path) {
57    THREAD_CWD.with(|cell| {
58        *cell.borrow_mut() = Some(path.to_path_buf());
59    });
60}
61
62/// 获取当前线程的工作目录覆盖(None 表示未进入 worktree)
63pub fn thread_cwd() -> Option<PathBuf> {
64    THREAD_CWD.with(|cell| cell.borrow().clone())
65}
66
67/// 清除当前线程的工作目录覆盖
68pub fn clear_thread_cwd() {
69    THREAD_CWD.with(|cell| {
70        *cell.borrow_mut() = None;
71    });
72}