mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
update
This commit is contained in:
@@ -120,10 +120,10 @@ use crate::mcp::effective_mcp_servers;
|
||||
use crate::mcp::maybe_prompt_and_install_mcp_dependencies;
|
||||
use crate::mcp::with_codex_apps_mcp;
|
||||
use crate::mcp_connection_manager::McpConnectionManager;
|
||||
use crate::mentions::CollectedToolMentions;
|
||||
use crate::mentions::build_connector_slug_counts;
|
||||
use crate::mentions::build_skill_name_counts;
|
||||
use crate::mentions::collect_explicit_app_paths;
|
||||
use crate::mentions::collect_tool_mentions_from_messages;
|
||||
use crate::mentions::collect_app_ids_from_mentions;
|
||||
use crate::model_provider_info::CHAT_WIRE_API_DEPRECATION_SUMMARY;
|
||||
use crate::project_doc::get_user_instructions;
|
||||
use crate::protocol::AgentMessageContentDeltaEvent;
|
||||
@@ -170,9 +170,7 @@ use crate::skills::SkillsManager;
|
||||
use crate::skills::build_skill_injections;
|
||||
use crate::skills::collect_env_var_dependencies;
|
||||
use crate::skills::collect_explicit_skill_mentions;
|
||||
use crate::skills::injection::ToolMentionKind;
|
||||
use crate::skills::injection::app_id_from_path;
|
||||
use crate::skills::injection::tool_kind_for_path;
|
||||
use crate::skills::collect_explicit_skill_mentions_from_mentions;
|
||||
use crate::skills::resolve_skill_dependencies_for_turn;
|
||||
use crate::state::ActiveTurn;
|
||||
use crate::state::SessionServices;
|
||||
@@ -1755,6 +1753,7 @@ impl Session {
|
||||
) {
|
||||
let mut state = self.state.lock().await;
|
||||
state.record_items(items.iter(), turn_context.truncation_policy);
|
||||
state.update_mentions_from_items(items);
|
||||
}
|
||||
|
||||
pub(crate) async fn record_model_warning(&self, message: impl Into<String>, ctx: &TurnContext) {
|
||||
@@ -2021,6 +2020,10 @@ impl Session {
|
||||
// those spans, and `record_response_item_and_emit_turn_item` would drop them.
|
||||
self.record_conversation_items(turn_context, std::slice::from_ref(&response_item))
|
||||
.await;
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
state.update_mentions_from_user_input(input);
|
||||
}
|
||||
let turn_item = TurnItem::UserMessage(UserMessageItem::new(input));
|
||||
self.emit_turn_item_started(turn_context, &turn_item).await;
|
||||
self.emit_turn_item_completed(turn_context, turn_item).await;
|
||||
@@ -3226,7 +3229,23 @@ pub(crate) async fn run_turn(
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
let mentioned_skills = skills_outcome.as_ref().map_or_else(Vec::new, |outcome| {
|
||||
let (history_mentions, injected_skill_paths) = {
|
||||
let state = sess.state.lock().await;
|
||||
(
|
||||
state.tool_mentions.clone(),
|
||||
state.injected_skill_paths.clone(),
|
||||
)
|
||||
};
|
||||
let mentioned_skills_from_history = skills_outcome.as_ref().map_or_else(Vec::new, |outcome| {
|
||||
collect_explicit_skill_mentions_from_mentions(
|
||||
&history_mentions,
|
||||
&outcome.skills,
|
||||
&outcome.disabled_paths,
|
||||
&skill_name_counts,
|
||||
&connector_slug_counts,
|
||||
)
|
||||
});
|
||||
let mentioned_skills_from_input = skills_outcome.as_ref().map_or_else(Vec::new, |outcome| {
|
||||
collect_explicit_skill_mentions(
|
||||
&input,
|
||||
&outcome.skills,
|
||||
@@ -3235,7 +3254,11 @@ pub(crate) async fn run_turn(
|
||||
&connector_slug_counts,
|
||||
)
|
||||
});
|
||||
let explicit_app_paths = collect_explicit_app_paths(&input);
|
||||
let mentioned_skills = merge_mentioned_skills(
|
||||
mentioned_skills_from_history,
|
||||
mentioned_skills_from_input,
|
||||
&injected_skill_paths,
|
||||
);
|
||||
|
||||
let config = turn_context.client.config();
|
||||
if config
|
||||
@@ -3310,8 +3333,12 @@ pub(crate) async fn run_turn(
|
||||
})
|
||||
.map(|user_message| user_message.message())
|
||||
.collect::<Vec<String>>();
|
||||
let tool_mentions = {
|
||||
let state = sess.state.lock().await;
|
||||
state.tool_mentions.clone()
|
||||
};
|
||||
let tool_selection = SamplingRequestToolSelection {
|
||||
explicit_app_paths: &explicit_app_paths,
|
||||
tool_mentions,
|
||||
skill_name_counts_lower: &skill_name_counts_lower,
|
||||
};
|
||||
match run_sampling_request(
|
||||
@@ -3394,18 +3421,15 @@ async fn run_auto_compact(sess: &Arc<Session>, turn_context: &Arc<TurnContext>)
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_connectors_for_input(
|
||||
fn filter_connectors_for_mentions(
|
||||
connectors: Vec<connectors::AppInfo>,
|
||||
input: &[ResponseItem],
|
||||
explicit_app_paths: &[String],
|
||||
mentions: &CollectedToolMentions,
|
||||
skill_name_counts_lower: &HashMap<String, usize>,
|
||||
) -> Vec<connectors::AppInfo> {
|
||||
let user_messages = collect_user_messages(input);
|
||||
if user_messages.is_empty() && explicit_app_paths.is_empty() {
|
||||
if mentions.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mentions = collect_tool_mentions_from_messages(&user_messages);
|
||||
let mention_names_lower = mentions
|
||||
.plain_names
|
||||
.iter()
|
||||
@@ -3413,16 +3437,7 @@ fn filter_connectors_for_input(
|
||||
.collect::<HashSet<String>>();
|
||||
|
||||
let connector_slug_counts = build_connector_slug_counts(&connectors);
|
||||
let mut allowed_connector_ids: HashSet<String> = HashSet::new();
|
||||
for path in explicit_app_paths
|
||||
.iter()
|
||||
.chain(mentions.paths.iter())
|
||||
.filter(|path| tool_kind_for_path(path) == ToolMentionKind::App)
|
||||
{
|
||||
if let Some(connector_id) = app_id_from_path(path) {
|
||||
allowed_connector_ids.insert(connector_id.to_string());
|
||||
}
|
||||
}
|
||||
let allowed_connector_ids = collect_app_ids_from_mentions(mentions);
|
||||
|
||||
connectors
|
||||
.into_iter()
|
||||
@@ -3461,6 +3476,33 @@ fn connector_inserted_in_messages(
|
||||
connector_count == 1 && skill_count == 0 && mention_names_lower.contains(&mention_slug)
|
||||
}
|
||||
|
||||
fn merge_mentioned_skills(
|
||||
history: Vec<SkillMetadata>,
|
||||
current: Vec<SkillMetadata>,
|
||||
injected_skill_paths: &HashSet<String>,
|
||||
) -> Vec<SkillMetadata> {
|
||||
let mut merged = Vec::with_capacity(history.len() + current.len());
|
||||
let mut seen_paths: HashSet<PathBuf> = HashSet::new();
|
||||
|
||||
for skill in history {
|
||||
let path_str = skill.path.to_string_lossy();
|
||||
if injected_skill_paths.contains(path_str.as_ref()) {
|
||||
continue;
|
||||
}
|
||||
if seen_paths.insert(skill.path.clone()) {
|
||||
merged.push(skill);
|
||||
}
|
||||
}
|
||||
|
||||
for skill in current {
|
||||
if seen_paths.insert(skill.path.clone()) {
|
||||
merged.push(skill);
|
||||
}
|
||||
}
|
||||
|
||||
merged
|
||||
}
|
||||
|
||||
fn filter_codex_apps_mcp_tools(
|
||||
mut mcp_tools: HashMap<String, crate::mcp_connection_manager::ToolInfo>,
|
||||
connectors: &[connectors::AppInfo],
|
||||
@@ -3488,7 +3530,7 @@ fn codex_apps_connector_id(tool: &crate::mcp_connection_manager::ToolInfo) -> Op
|
||||
}
|
||||
|
||||
struct SamplingRequestToolSelection<'a> {
|
||||
explicit_app_paths: &'a [String],
|
||||
tool_mentions: CollectedToolMentions,
|
||||
skill_name_counts_lower: &'a HashMap<String, usize>,
|
||||
}
|
||||
|
||||
@@ -3519,10 +3561,9 @@ async fn run_sampling_request(
|
||||
.await?;
|
||||
let connectors_for_tools = if turn_context.client.config().features.enabled(Feature::Apps) {
|
||||
let connectors = connectors::accessible_connectors_from_mcp_tools(&mcp_tools);
|
||||
Some(filter_connectors_for_input(
|
||||
Some(filter_connectors_for_mentions(
|
||||
connectors,
|
||||
&input,
|
||||
tool_selection.explicit_app_paths,
|
||||
&tool_selection.tool_mentions,
|
||||
tool_selection.skill_name_counts_lower,
|
||||
))
|
||||
} else {
|
||||
@@ -3941,6 +3982,7 @@ mod tests {
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::FunctionCallOutputPayload;
|
||||
|
||||
use crate::mentions::collect_tool_mentions_from_response_items;
|
||||
use crate::protocol::CompactedItem;
|
||||
use crate::protocol::CreditsSnapshot;
|
||||
use crate::protocol::InitialHistory;
|
||||
@@ -4080,15 +4122,11 @@ mod tests {
|
||||
make_connector("two", "Foo-Bar"),
|
||||
];
|
||||
let input = vec![user_message("use $foo-bar")];
|
||||
let explicit_app_paths = Vec::new();
|
||||
let mentions = collect_tool_mentions_from_response_items(&input);
|
||||
let skill_name_counts_lower = HashMap::new();
|
||||
|
||||
let selected = filter_connectors_for_input(
|
||||
connectors,
|
||||
&input,
|
||||
&explicit_app_paths,
|
||||
&skill_name_counts_lower,
|
||||
);
|
||||
let selected =
|
||||
filter_connectors_for_mentions(connectors, &mentions, &skill_name_counts_lower);
|
||||
|
||||
assert_eq!(selected, Vec::new());
|
||||
}
|
||||
@@ -4097,15 +4135,11 @@ mod tests {
|
||||
fn filter_connectors_for_input_skips_when_skill_name_conflicts() {
|
||||
let connectors = vec![make_connector("one", "Todoist")];
|
||||
let input = vec![user_message("use $todoist")];
|
||||
let explicit_app_paths = Vec::new();
|
||||
let mentions = collect_tool_mentions_from_response_items(&input);
|
||||
let skill_name_counts_lower = HashMap::from([("todoist".to_string(), 1)]);
|
||||
|
||||
let selected = filter_connectors_for_input(
|
||||
connectors,
|
||||
&input,
|
||||
&explicit_app_paths,
|
||||
&skill_name_counts_lower,
|
||||
);
|
||||
let selected =
|
||||
filter_connectors_for_mentions(connectors, &mentions, &skill_name_counts_lower);
|
||||
|
||||
assert_eq!(selected, Vec::new());
|
||||
}
|
||||
|
||||
@@ -59,6 +59,20 @@ impl SkillInstructions {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_path(message: &[ContentItem]) -> Option<String> {
|
||||
let [ContentItem::InputText { text }] = message else {
|
||||
return None;
|
||||
};
|
||||
let path_start = text.find("<path>")? + "<path>".len();
|
||||
let path_end = text[path_start..].find("</path>")? + path_start;
|
||||
let path = text.get(path_start..path_end)?;
|
||||
if path.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(path.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SkillInstructions> for ResponseItem {
|
||||
|
||||
@@ -2,18 +2,42 @@ use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
|
||||
use crate::compact::collect_user_messages;
|
||||
use crate::connectors;
|
||||
use crate::instructions::SkillInstructions;
|
||||
use crate::skills::SkillMetadata;
|
||||
use crate::skills::injection::ToolMentionKind;
|
||||
use crate::skills::injection::extract_tool_mentions;
|
||||
use crate::skills::injection::tool_kind_for_path;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct CollectedToolMentions {
|
||||
pub(crate) plain_names: HashSet<String>,
|
||||
pub(crate) paths: HashSet<String>,
|
||||
}
|
||||
|
||||
impl CollectedToolMentions {
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.plain_names.is_empty() && self.paths.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn extend_from(&mut self, other: &CollectedToolMentions) {
|
||||
self.plain_names.extend(other.plain_names.iter().cloned());
|
||||
self.paths.extend(other.paths.iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn collect_tool_mentions_from_messages(messages: &[String]) -> CollectedToolMentions {
|
||||
collect_tool_mentions_from_texts(messages.iter().map(String::as_str))
|
||||
}
|
||||
|
||||
pub(crate) fn collect_tool_mentions_from_texts<'a, I>(messages: I) -> CollectedToolMentions
|
||||
where
|
||||
I: IntoIterator<Item = &'a str>,
|
||||
{
|
||||
let mut plain_names = HashSet::new();
|
||||
let mut paths = HashSet::new();
|
||||
for message in messages {
|
||||
@@ -24,13 +48,59 @@ pub(crate) fn collect_tool_mentions_from_messages(messages: &[String]) -> Collec
|
||||
CollectedToolMentions { plain_names, paths }
|
||||
}
|
||||
|
||||
pub(crate) fn collect_explicit_app_paths(input: &[UserInput]) -> Vec<String> {
|
||||
input
|
||||
pub(crate) fn collect_structured_tool_mentions_from_user_input(
|
||||
input: &[UserInput],
|
||||
) -> CollectedToolMentions {
|
||||
let mut mentions = CollectedToolMentions::default();
|
||||
for item in input {
|
||||
match item {
|
||||
UserInput::Mention { name, path } => {
|
||||
mentions.plain_names.insert(name.clone());
|
||||
mentions.paths.insert(path.clone());
|
||||
}
|
||||
UserInput::Skill { name, path } => {
|
||||
mentions.plain_names.insert(name.clone());
|
||||
mentions.paths.insert(path.to_string_lossy().into_owned());
|
||||
}
|
||||
UserInput::Text { .. } | UserInput::Image { .. } | UserInput::LocalImage { .. } => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
mentions
|
||||
}
|
||||
|
||||
pub(crate) fn collect_tool_mentions_from_response_items(
|
||||
items: &[ResponseItem],
|
||||
) -> CollectedToolMentions {
|
||||
let messages = collect_user_messages(items);
|
||||
collect_tool_mentions_from_messages(&messages)
|
||||
}
|
||||
|
||||
pub(crate) fn collect_skill_instruction_paths(items: &[ResponseItem]) -> HashSet<String> {
|
||||
let mut paths = HashSet::new();
|
||||
for item in items {
|
||||
let ResponseItem::Message { role, content, .. } = item else {
|
||||
continue;
|
||||
};
|
||||
if role != "user" {
|
||||
continue;
|
||||
}
|
||||
let Some(path) = SkillInstructions::extract_path(content) else {
|
||||
continue;
|
||||
};
|
||||
paths.insert(path);
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
pub(crate) fn collect_app_ids_from_mentions(mentions: &CollectedToolMentions) -> HashSet<String> {
|
||||
mentions
|
||||
.paths
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
UserInput::Mention { path, .. } => Some(path.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|path| tool_kind_for_path(path) == ToolMentionKind::App)
|
||||
.filter_map(|path| crate::skills::injection::app_id_from_path(path))
|
||||
.map(str::to_string)
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::instructions::SkillInstructions;
|
||||
use crate::mentions::CollectedToolMentions;
|
||||
use crate::skills::SkillMetadata;
|
||||
use codex_otel::OtelManager;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
@@ -106,6 +107,34 @@ pub(crate) fn collect_explicit_skill_mentions(
|
||||
selected
|
||||
}
|
||||
|
||||
pub(crate) fn collect_explicit_skill_mentions_from_mentions(
|
||||
mentions: &CollectedToolMentions,
|
||||
skills: &[SkillMetadata],
|
||||
disabled_paths: &HashSet<PathBuf>,
|
||||
skill_name_counts: &HashMap<String, usize>,
|
||||
connector_slug_counts: &HashMap<String, usize>,
|
||||
) -> Vec<SkillMetadata> {
|
||||
let selection_context = SkillSelectionContext {
|
||||
skills,
|
||||
disabled_paths,
|
||||
skill_name_counts,
|
||||
connector_slug_counts,
|
||||
};
|
||||
let mut selected: Vec<SkillMetadata> = Vec::new();
|
||||
let mut seen_names: HashSet<String> = HashSet::new();
|
||||
let mut seen_paths: HashSet<PathBuf> = HashSet::new();
|
||||
|
||||
select_skills_from_collected_mentions(
|
||||
&selection_context,
|
||||
mentions,
|
||||
&mut seen_names,
|
||||
&mut seen_paths,
|
||||
&mut selected,
|
||||
);
|
||||
|
||||
selected
|
||||
}
|
||||
|
||||
struct SkillSelectionContext<'a> {
|
||||
skills: &'a [SkillMetadata],
|
||||
disabled_paths: &'a HashSet<PathBuf>,
|
||||
@@ -308,6 +337,76 @@ fn select_skills_from_mentions(
|
||||
}
|
||||
}
|
||||
|
||||
fn select_skills_from_collected_mentions(
|
||||
selection_context: &SkillSelectionContext<'_>,
|
||||
mentions: &CollectedToolMentions,
|
||||
seen_names: &mut HashSet<String>,
|
||||
seen_paths: &mut HashSet<PathBuf>,
|
||||
selected: &mut Vec<SkillMetadata>,
|
||||
) {
|
||||
if mentions.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mention_skill_paths: HashSet<&str> = mentions
|
||||
.paths
|
||||
.iter()
|
||||
.filter(|path| {
|
||||
!matches!(
|
||||
tool_kind_for_path(path),
|
||||
ToolMentionKind::App | ToolMentionKind::Mcp
|
||||
)
|
||||
})
|
||||
.map(|path| normalize_skill_path(path))
|
||||
.collect();
|
||||
|
||||
for skill in selection_context.skills {
|
||||
if selection_context.disabled_paths.contains(&skill.path)
|
||||
|| seen_paths.contains(&skill.path)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let path_str = skill.path.to_string_lossy();
|
||||
if mention_skill_paths.contains(path_str.as_ref()) {
|
||||
seen_paths.insert(skill.path.clone());
|
||||
seen_names.insert(skill.name.clone());
|
||||
selected.push(skill.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for skill in selection_context.skills {
|
||||
if selection_context.disabled_paths.contains(&skill.path)
|
||||
|| seen_paths.contains(&skill.path)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if !mentions.plain_names.contains(skill.name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let skill_count = selection_context
|
||||
.skill_name_counts
|
||||
.get(skill.name.as_str())
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
let connector_count = selection_context
|
||||
.connector_slug_counts
|
||||
.get(&skill.name.to_ascii_lowercase())
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
if skill_count != 1 || connector_count != 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if seen_names.insert(skill.name.clone()) {
|
||||
seen_paths.insert(skill.path.clone());
|
||||
selected.push(skill.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_linked_tool_mention<'a>(
|
||||
text: &'a str,
|
||||
text_bytes: &[u8],
|
||||
|
||||
@@ -11,6 +11,7 @@ pub(crate) use env_var_dependencies::resolve_skill_dependencies_for_turn;
|
||||
pub(crate) use injection::SkillInjections;
|
||||
pub(crate) use injection::build_skill_injections;
|
||||
pub(crate) use injection::collect_explicit_skill_mentions;
|
||||
pub(crate) use injection::collect_explicit_skill_mentions_from_mentions;
|
||||
pub use loader::load_skills;
|
||||
pub use manager::SkillsManager;
|
||||
pub use model::SkillError;
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
//! Session-wide mutable state.
|
||||
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::codex::SessionConfiguration;
|
||||
use crate::context_manager::ContextManager;
|
||||
use crate::mentions::CollectedToolMentions;
|
||||
use crate::mentions::collect_skill_instruction_paths;
|
||||
use crate::mentions::collect_structured_tool_mentions_from_user_input;
|
||||
use crate::mentions::collect_tool_mentions_from_response_items;
|
||||
use crate::protocol::RateLimitSnapshot;
|
||||
use crate::protocol::TokenUsage;
|
||||
use crate::protocol::TokenUsageInfo;
|
||||
@@ -19,6 +24,8 @@ pub(crate) struct SessionState {
|
||||
pub(crate) server_reasoning_included: bool,
|
||||
pub(crate) dependency_env: HashMap<String, String>,
|
||||
pub(crate) mcp_dependency_prompted: HashSet<String>,
|
||||
pub(crate) tool_mentions: CollectedToolMentions,
|
||||
pub(crate) injected_skill_paths: HashSet<String>,
|
||||
/// Whether the session's initial context has been seeded into history.
|
||||
///
|
||||
/// TODO(owen): This is a temporary solution to avoid updating a thread's updated_at
|
||||
@@ -37,6 +44,8 @@ impl SessionState {
|
||||
server_reasoning_included: false,
|
||||
dependency_env: HashMap::new(),
|
||||
mcp_dependency_prompted: HashSet::new(),
|
||||
tool_mentions: CollectedToolMentions::default(),
|
||||
injected_skill_paths: HashSet::new(),
|
||||
initial_context_seeded: false,
|
||||
}
|
||||
}
|
||||
@@ -56,6 +65,25 @@ impl SessionState {
|
||||
|
||||
pub(crate) fn replace_history(&mut self, items: Vec<ResponseItem>) {
|
||||
self.history.replace(items);
|
||||
self.rebuild_mentions_from_history();
|
||||
}
|
||||
|
||||
pub(crate) fn update_mentions_from_items(&mut self, items: &[ResponseItem]) {
|
||||
let mentions = collect_tool_mentions_from_response_items(items);
|
||||
self.tool_mentions.extend_from(&mentions);
|
||||
let skill_paths = collect_skill_instruction_paths(items);
|
||||
self.injected_skill_paths.extend(skill_paths);
|
||||
}
|
||||
|
||||
pub(crate) fn update_mentions_from_user_input(&mut self, input: &[UserInput]) {
|
||||
let mentions = collect_structured_tool_mentions_from_user_input(input);
|
||||
self.tool_mentions.extend_from(&mentions);
|
||||
}
|
||||
|
||||
fn rebuild_mentions_from_history(&mut self) {
|
||||
let items = self.history.raw_items();
|
||||
self.tool_mentions = collect_tool_mentions_from_response_items(items);
|
||||
self.injected_skill_paths = collect_skill_instruction_paths(items);
|
||||
}
|
||||
|
||||
pub(crate) fn set_token_info(&mut self, info: Option<TokenUsageInfo>) {
|
||||
|
||||
Reference in New Issue
Block a user