refactor(chat): refactor skill context deduplication and injection
- Extract push_unique_skill_context method to MessageBuilder - Merge built-in skills with DB skills in passive injection - Simplify code structure for both streaming/nonstreaming execution
This commit is contained in:
parent
5c1b14c26a
commit
60100a025c
@ -7,7 +7,7 @@ use crate::client::types::ChatRequestMessage;
|
|||||||
use crate::compact::CompactService;
|
use crate::compact::CompactService;
|
||||||
use crate::embed::EmbedService;
|
use crate::embed::EmbedService;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::perception::{PerceptionService, SkillEntry};
|
use crate::perception::{PerceptionService, SkillContext, SkillEntry};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MessageBuilder {
|
pub struct MessageBuilder {
|
||||||
@ -393,21 +393,25 @@ impl MessageBuilder {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut seen = std::collections::HashSet::new();
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for ctx in vector_skills {
|
|
||||||
if seen.insert(ctx.label.clone()) {
|
|
||||||
result.push(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ctx in keyword_skills {
|
for ctx in keyword_skills {
|
||||||
if seen.insert(ctx.label.clone()) {
|
Self::push_unique_skill_context(&mut result, ctx);
|
||||||
result.push(ctx);
|
}
|
||||||
}
|
for ctx in vector_skills {
|
||||||
|
Self::push_unique_skill_context(&mut result, ctx);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_unique_skill_context(result: &mut Vec<SkillContext>, ctx: SkillContext) {
|
||||||
|
let key = ctx.dedupe_key();
|
||||||
|
if result.iter().any(|existing| existing.dedupe_key() == key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result.push(ctx);
|
||||||
|
result.sort_by_key(|ctx| ctx.activation.rank());
|
||||||
|
}
|
||||||
|
|
||||||
async fn build_memory_context(
|
async fn build_memory_context(
|
||||||
&self,
|
&self,
|
||||||
request: &AiRequest,
|
request: &AiRequest,
|
||||||
|
|||||||
@ -94,22 +94,10 @@ pub async fn execute_process(
|
|||||||
.collect();
|
.collect();
|
||||||
let tool_names: Vec<String> = calls.iter().map(|call| call.name.clone()).collect();
|
let tool_names: Vec<String> = calls.iter().map(|call| call.name.clone()).collect();
|
||||||
|
|
||||||
let tool_messages = execute_tools(
|
let tool_messages =
|
||||||
&request,
|
execute_tools(&request, &calls, session_id, tool_registry, message_builder).await;
|
||||||
&calls,
|
|
||||||
session_id,
|
|
||||||
tool_registry,
|
|
||||||
message_builder,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
messages.extend(tool_messages);
|
messages.extend(tool_messages);
|
||||||
inject_passive_skills(
|
inject_passive_skills(&request, message_builder, &tool_names, &mut messages).await;
|
||||||
&request,
|
|
||||||
message_builder,
|
|
||||||
&tool_names,
|
|
||||||
&mut messages,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
tool_depth += 1;
|
tool_depth += 1;
|
||||||
if tool_depth >= max_tool_depth {
|
if tool_depth >= max_tool_depth {
|
||||||
@ -261,7 +249,7 @@ async fn inject_passive_skills(
|
|||||||
.all(&request.db)
|
.all(&request.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let skill_entries: Vec<SkillEntry> = skills
|
let mut skill_entries: Vec<SkillEntry> = skills
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| SkillEntry {
|
.map(|s| SkillEntry {
|
||||||
slug: s.slug,
|
slug: s.slug,
|
||||||
@ -270,6 +258,16 @@ async fn inject_passive_skills(
|
|||||||
content: s.content,
|
content: s.content,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
for built_in in crate::skills::all_skills() {
|
||||||
|
if !skill_entries.iter().any(|s| s.slug == built_in.slug) {
|
||||||
|
skill_entries.push(SkillEntry {
|
||||||
|
slug: built_in.slug.to_string(),
|
||||||
|
name: built_in.name.to_string(),
|
||||||
|
description: Some(built_in.description.to_string()),
|
||||||
|
content: built_in.content.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
let tool_events: Vec<ToolCallEvent> = tool_names
|
let tool_events: Vec<ToolCallEvent> = tool_names
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| ToolCallEvent {
|
.map(|name| ToolCallEvent {
|
||||||
@ -277,14 +275,18 @@ async fn inject_passive_skills(
|
|||||||
arguments: String::new(),
|
arguments: String::new(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
let mut contexts = Vec::new();
|
||||||
for event in &tool_events {
|
for event in &tool_events {
|
||||||
if let Some(ctx) = message_builder
|
if let Some(ctx) = message_builder
|
||||||
.perception_service
|
.perception_service
|
||||||
.passive
|
.passive
|
||||||
.detect(event, &skill_entries)
|
.detect(event, &skill_entries)
|
||||||
{
|
{
|
||||||
messages.push(ctx.to_system_message());
|
MessageBuilder::push_unique_skill_context(&mut contexts, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for ctx in contexts {
|
||||||
|
messages.push(ctx.to_system_message());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,9 @@ use super::message_builder::MessageBuilder;
|
|||||||
use super::service::StreamResult;
|
use super::service::StreamResult;
|
||||||
use super::session_recording::record_ai_session;
|
use super::session_recording::record_ai_session;
|
||||||
use super::{AiChunkType, AiRequest, AiStreamChunk, StreamCallback};
|
use super::{AiChunkType, AiRequest, AiStreamChunk, StreamCallback};
|
||||||
use crate::client::types::{ChatRequestMessage, ToolCall};
|
|
||||||
use crate::client::AiClientConfig;
|
use crate::client::AiClientConfig;
|
||||||
use crate::client::{call_stream, StreamChunk, StreamChunkType, StreamedToolCall};
|
use crate::client::types::{ChatRequestMessage, ToolCall};
|
||||||
|
use crate::client::{StreamChunk, StreamChunkType, StreamedToolCall, call_stream};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::perception::{SkillEntry, ToolCallEvent};
|
use crate::perception::{SkillEntry, ToolCallEvent};
|
||||||
use crate::tool::{ToolCall as AgentToolCall, ToolContext, ToolExecutor};
|
use crate::tool::{ToolCall as AgentToolCall, ToolContext, ToolExecutor};
|
||||||
@ -266,7 +266,8 @@ async fn drain_tool_call_notifications(
|
|||||||
chunk_type: AiChunkType::ToolCall,
|
chunk_type: AiChunkType::ToolCall,
|
||||||
metadata: Some(metadata),
|
metadata: Some(metadata),
|
||||||
children_id: None,
|
children_id: None,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
all_chunks.push(StreamChunk {
|
all_chunks.push(StreamChunk {
|
||||||
chunk_type: StreamChunkType::ToolCall,
|
chunk_type: StreamChunkType::ToolCall,
|
||||||
content: tool_display,
|
content: tool_display,
|
||||||
@ -467,7 +468,7 @@ async fn inject_passive_skills_stream(
|
|||||||
.all(&request.db)
|
.all(&request.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let skill_entries: Vec<SkillEntry> = skills
|
let mut skill_entries: Vec<SkillEntry> = skills
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| SkillEntry {
|
.map(|s| SkillEntry {
|
||||||
slug: s.slug,
|
slug: s.slug,
|
||||||
@ -476,6 +477,16 @@ async fn inject_passive_skills_stream(
|
|||||||
content: s.content,
|
content: s.content,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
for built_in in crate::skills::all_skills() {
|
||||||
|
if !skill_entries.iter().any(|s| s.slug == built_in.slug) {
|
||||||
|
skill_entries.push(SkillEntry {
|
||||||
|
slug: built_in.slug.to_string(),
|
||||||
|
name: built_in.name.to_string(),
|
||||||
|
description: Some(built_in.description.to_string()),
|
||||||
|
content: built_in.content.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
let tool_events: Vec<ToolCallEvent> = tool_calls
|
let tool_events: Vec<ToolCallEvent> = tool_calls
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tc| ToolCallEvent {
|
.map(|tc| ToolCallEvent {
|
||||||
@ -483,14 +494,18 @@ async fn inject_passive_skills_stream(
|
|||||||
arguments: tc.arguments.clone(),
|
arguments: tc.arguments.clone(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
let mut contexts = Vec::new();
|
||||||
for event in &tool_events {
|
for event in &tool_events {
|
||||||
if let Some(ctx) = message_builder
|
if let Some(ctx) = message_builder
|
||||||
.perception_service
|
.perception_service
|
||||||
.passive
|
.passive
|
||||||
.detect(event, &skill_entries)
|
.detect(event, &skill_entries)
|
||||||
{
|
{
|
||||||
messages.push(ctx.to_system_message());
|
MessageBuilder::push_unique_skill_context(&mut contexts, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for ctx in contexts {
|
||||||
|
messages.push(ctx.to_system_message());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user