feat: 新增专家提示词核心模块,支持文件发现、CRUD与运行时选择
- 新增 src/experts/mod.rs 模块,镜像 skills/subagents 模式 - 支持 user/project 双 scope 从 EXPERT.md 文件发现专家 - ExpertRuntime 维护 session→expert 映射与禁用列表,持久化到 expert-state.json - ExpertPromptProvider 实现系统提示词注入,未选中时返回 None - 包含 16 个单元测试覆盖 frontmatter 解析、discover 优先级、CRUD、select/clear、disable 场景
This commit is contained in:
parent
8d30ccd020
commit
c2d9bf8b5e
@ -67,6 +67,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
subagent_task_id: None,
|
||||
});
|
||||
return outbounds;
|
||||
}
|
||||
@ -197,6 +198,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
code: "RESPONSE_ERROR".to_string(),
|
||||
message: msg.content.clone(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
subagent_task_id: None,
|
||||
},
|
||||
_ => WsOutbound::AssistantResponse {
|
||||
id: response.request_id.to_string(),
|
||||
|
||||
1484
src/experts/mod.rs
Normal file
1484
src/experts/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -267,6 +267,7 @@ async fn handle_socket(ws: WebSocket, state: Arc<GatewayState>) {
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code:"SESSION_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
subagent_task_id: None,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@ -278,6 +279,7 @@ async fn handle_socket(ws: WebSocket, state: Arc<GatewayState>) {
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code:"PARSE_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
subagent_task_id: None,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@ -370,6 +372,7 @@ async fn handle_inbound(
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code: "INVALID_COMMAND".to_string(),
|
||||
message: "Invalid command payload".to_string(),
|
||||
subagent_task_id: None,
|
||||
})
|
||||
.await;
|
||||
return Ok(());
|
||||
@ -380,6 +383,7 @@ async fn handle_inbound(
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code: "PARSE_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
subagent_task_id: None,
|
||||
})
|
||||
.await;
|
||||
return Ok(());
|
||||
@ -796,6 +800,12 @@ fn set_subagent_task_id(outbound: &mut WsOutbound, task_id: &str) {
|
||||
}
|
||||
| WsOutbound::ToolPending {
|
||||
subagent_task_id, ..
|
||||
}
|
||||
| WsOutbound::StreamDelta {
|
||||
subagent_task_id, ..
|
||||
}
|
||||
| WsOutbound::StreamEnd {
|
||||
subagent_task_id, ..
|
||||
} => {
|
||||
*subagent_task_id = Some(task_id.to_string());
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ pub mod client;
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
pub mod domain;
|
||||
pub mod experts;
|
||||
pub mod gateway;
|
||||
pub mod logging;
|
||||
pub mod mcp;
|
||||
|
||||
@ -209,6 +209,8 @@ pub enum WsOutbound {
|
||||
message: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
subagent_task_id: Option<String>,
|
||||
},
|
||||
#[serde(rename = "task_started")]
|
||||
TaskStarted {
|
||||
@ -301,6 +303,8 @@ pub enum WsOutbound {
|
||||
topic_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
subagent_task_id: Option<String>,
|
||||
},
|
||||
#[serde(rename = "todo_list")]
|
||||
TodoList {
|
||||
|
||||
@ -172,6 +172,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
code: "AGENT_ERROR".to_string(),
|
||||
message: message.content.clone(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
subagent_task_id: message.metadata.get("subagent_task_id").cloned(),
|
||||
}],
|
||||
OutboundEventKind::TaskStarted => vec![WsOutbound::TaskStarted {
|
||||
task_id: message.metadata.get("task_id").cloned().unwrap_or_default(),
|
||||
@ -197,6 +198,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
OutboundEventKind::ExecutionCompleted => vec![WsOutbound::ExecutionCompleted {
|
||||
topic_id: message.metadata.get("topic_id").cloned(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
subagent_task_id: message.metadata.get("subagent_task_id").cloned(),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user