mirror of
https://github.com/instructkr/claw-code.git
synced 2026-05-19 14:01:26 +08:00
fix: REPL display, /compact panic, identity leak, DeepSeek reasoning, thinking blocks
Five interrelated fixes from parallel Hephaestus sessions: 1. fix(repl): display assistant text after spinner (#2981, #2982, #2937) - Added final_assistant_text() call after run_turn spinner completes - REPL now shows response text like run_prompt_json does 2. fix(compact): handle Thinking content blocks (#2985) - Added ContentBlock::Thinking variant throughout compact summarizer - Prevents panic when /compact encounters thinking blocks 3. fix(prompt): provider-aware model identity (#2822) - New ModelFamilyIdentity enum (Claude vs Generic) - Non-Anthropic models no longer say 'I am Claude' - model_family_identity_for() detects provider and sets identity 4. fix(openai): preserve DeepSeek reasoning_content (#2821) - Stream parser now captures reasoning_content from OpenAI-compat - Emits ThinkingDelta/SignatureDelta events for reasoning models - Thinking blocks included in conversation history for re-send 5. feat(runtime): Thinking block support across codebase - AssistantEvent::Thinking variant in conversation.rs - ContentBlock::Thinking in session serialization - Thinking-aware compact summarization - Tests for thinking block ordering and content Closes #2981, #2982, #2937, #2985, #2822, #2821
This commit is contained in:
@@ -30,6 +30,10 @@ pub enum ContentBlock {
|
||||
Text {
|
||||
text: String,
|
||||
},
|
||||
Thinking {
|
||||
thinking: String,
|
||||
signature: Option<String>,
|
||||
},
|
||||
ToolUse {
|
||||
id: String,
|
||||
name: String,
|
||||
@@ -737,6 +741,22 @@ impl ContentBlock {
|
||||
object.insert("type".to_string(), JsonValue::String("text".to_string()));
|
||||
object.insert("text".to_string(), JsonValue::String(text.clone()));
|
||||
}
|
||||
Self::Thinking {
|
||||
thinking,
|
||||
signature,
|
||||
} => {
|
||||
object.insert(
|
||||
"type".to_string(),
|
||||
JsonValue::String("thinking".to_string()),
|
||||
);
|
||||
object.insert("thinking".to_string(), JsonValue::String(thinking.clone()));
|
||||
if let Some(signature) = signature {
|
||||
object.insert(
|
||||
"signature".to_string(),
|
||||
JsonValue::String(signature.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Self::ToolUse { id, name, input } => {
|
||||
object.insert(
|
||||
"type".to_string(),
|
||||
@@ -783,6 +803,13 @@ impl ContentBlock {
|
||||
"text" => Ok(Self::Text {
|
||||
text: required_string(object, "text")?,
|
||||
}),
|
||||
"thinking" => Ok(Self::Thinking {
|
||||
thinking: required_string(object, "thinking")?,
|
||||
signature: object
|
||||
.get("signature")
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(String::from),
|
||||
}),
|
||||
"tool_use" => Ok(Self::ToolUse {
|
||||
id: required_string(object, "id")?,
|
||||
name: required_string(object, "name")?,
|
||||
@@ -1208,6 +1235,36 @@ mod tests {
|
||||
assert_eq!(restored.session_id, session.session_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persists_assistant_thinking_block_round_trip_through_jsonl() {
|
||||
// given
|
||||
let mut session = Session::new();
|
||||
session
|
||||
.push_message(ConversationMessage::assistant(vec![
|
||||
ContentBlock::Thinking {
|
||||
thinking: "trace the path through session persistence".to_string(),
|
||||
signature: Some("sig-123".to_string()),
|
||||
},
|
||||
]))
|
||||
.expect("thinking block should append");
|
||||
let path = temp_session_path("thinking-jsonl");
|
||||
|
||||
// when
|
||||
session.save_to_path(&path).expect("session should save");
|
||||
let restored = Session::load_from_path(&path).expect("session should load");
|
||||
fs::remove_file(&path).expect("temp file should be removable");
|
||||
|
||||
// then
|
||||
assert_eq!(restored, session);
|
||||
assert_eq!(
|
||||
restored.messages[0].blocks[0],
|
||||
ContentBlock::Thinking {
|
||||
thinking: "trace the path through session persistence".to_string(),
|
||||
signature: Some("sig-123".to_string()),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loads_legacy_session_json_object() {
|
||||
let path = temp_session_path("legacy");
|
||||
|
||||
Reference in New Issue
Block a user