diff --git a/rust/crates/commands/src/lib.rs b/rust/crates/commands/src/lib.rs index 454888d7..5e8f5eba 100644 --- a/rust/crates/commands/src/lib.rs +++ b/rust/crates/commands/src/lib.rs @@ -2490,6 +2490,13 @@ pub fn classify_skills_slash_command(args: Option<&str>) -> SkillSlashDispatch { None | Some("list" | "help" | "-h" | "--help" | "show" | "info" | "describe") => { SkillSlashDispatch::Local } + Some(args) + if args + .split_whitespace() + .any(|part| matches!(part, "-h" | "--help")) => + { + SkillSlashDispatch::Local + } Some(args) if args == "install" || args.starts_with("install ") => { SkillSlashDispatch::Local } diff --git a/rust/crates/tools/src/lib.rs b/rust/crates/tools/src/lib.rs index 9e669f5e..eb4a3905 100644 --- a/rust/crates/tools/src/lib.rs +++ b/rust/crates/tools/src/lib.rs @@ -4638,13 +4638,21 @@ async fn stream_with_provider( let mut stream = client.stream_message(message_request).await?; let mut events = Vec::new(); let mut pending_tools: BTreeMap = BTreeMap::new(); + let mut pending_thinking: BTreeMap)> = BTreeMap::new(); let mut saw_stop = false; while let Some(event) = stream.next_event().await? { match event { ApiStreamEvent::MessageStart(start) => { for block in start.message.content { - push_output_block(block, 0, &mut events, &mut pending_tools, true); + push_output_block( + block, + 0, + &mut events, + &mut pending_tools, + &mut pending_thinking, + true, + ); } } ApiStreamEvent::ContentBlockStart(start) => { @@ -4653,6 +4661,7 @@ async fn stream_with_provider( start.index, &mut events, &mut pending_tools, + &mut pending_thinking, true, ); } @@ -4667,10 +4676,23 @@ async fn stream_with_provider( input.push_str(&partial_json); } } - ContentBlockDelta::ThinkingDelta { .. } - | ContentBlockDelta::SignatureDelta { .. } => {} + ContentBlockDelta::ThinkingDelta { thinking } => { + if let Some((pending, _)) = pending_thinking.get_mut(&delta.index) { + pending.push_str(&thinking); + } + } + ContentBlockDelta::SignatureDelta { signature } => { + if let Some((_, pending_signature)) = pending_thinking.get_mut(&delta.index) { + pending_signature + .get_or_insert_with(String::new) + .push_str(&signature); + } + } }, ApiStreamEvent::ContentBlockStop(stop) => { + if let Some((thinking, signature)) = pending_thinking.remove(&stop.index) { + events.push(AssistantEvent::Thinking { thinking, signature }); + } if let Some((id, name, input)) = pending_tools.remove(&stop.index) { events.push(AssistantEvent::ToolUse { id, name, input }); } @@ -4767,8 +4789,12 @@ fn convert_messages(messages: &[ConversationMessage]) -> Vec { .iter() .map(|block| match block { ContentBlock::Text { text } => InputContentBlock::Text { text: text.clone() }, - ContentBlock::Thinking { .. } => InputContentBlock::Text { - text: String::new(), + ContentBlock::Thinking { + thinking, + signature, + } => InputContentBlock::Thinking { + thinking: thinking.clone(), + signature: signature.clone(), }, ContentBlock::ToolUse { id, name, input } => InputContentBlock::ToolUse { id: id.clone(), @@ -4806,6 +4832,7 @@ fn push_output_block( block_index: u32, events: &mut Vec, pending_tools: &mut BTreeMap, + pending_thinking: &mut BTreeMap)>, streaming_tool_input: bool, ) { match block { @@ -4825,17 +4852,35 @@ fn push_output_block( }; pending_tools.insert(block_index, (id, name, initial_input)); } - OutputContentBlock::Thinking { .. } | OutputContentBlock::RedactedThinking { .. } => {} + OutputContentBlock::Thinking { + thinking, + signature, + } => { + if streaming_tool_input { + pending_thinking.insert(block_index, (thinking, signature)); + } else { + events.push(AssistantEvent::Thinking { thinking, signature }); + } + } + OutputContentBlock::RedactedThinking { .. } => {} } } fn response_to_events(response: MessageResponse) -> Vec { let mut events = Vec::new(); let mut pending_tools = BTreeMap::new(); + let mut pending_thinking = BTreeMap::new(); for (index, block) in response.content.into_iter().enumerate() { let index = u32::try_from(index).expect("response block index overflow"); - push_output_block(block, index, &mut events, &mut pending_tools, false); + push_output_block( + block, + index, + &mut events, + &mut pending_tools, + &mut pending_thinking, + false, + ); if let Some((id, name, input)) = pending_tools.remove(&index) { events.push(AssistantEvent::ToolUse { id, name, input }); } @@ -7259,6 +7304,7 @@ mod tests { fn pending_tools_preserve_multiple_streaming_tool_calls_by_index() { let mut events = Vec::new(); let mut pending_tools = BTreeMap::new(); + let mut pending_thinking = BTreeMap::new(); push_output_block( OutputContentBlock::ToolUse { @@ -7269,6 +7315,7 @@ mod tests { 1, &mut events, &mut pending_tools, + &mut pending_thinking, true, ); push_output_block( @@ -7280,6 +7327,7 @@ mod tests { 2, &mut events, &mut pending_tools, + &mut pending_thinking, true, );