feat: add streaming support for Claude Code CLI provider (#6833)

Signed-off-by: rabi <ramishra@redhat.com>
This commit is contained in:
Rabi Mishra
2026-02-13 20:58:32 +05:30
committed by GitHub
parent 6a7adb4e94
commit ed3c08590a
6 changed files with 486 additions and 372 deletions
+15 -70
View File
@@ -409,51 +409,6 @@ impl CodexProvider {
Ok((message, usage))
}
/// Generate a simple session description without calling subprocess
fn generate_simple_session_description(
&self,
messages: &[Message],
) -> Result<(Message, ProviderUsage), ProviderError> {
// Extract the first user message text
let description = messages
.iter()
.find(|m| m.role == Role::User)
.and_then(|m| {
m.content.iter().find_map(|c| match c {
MessageContent::Text(text_content) => Some(&text_content.text),
_ => None,
})
})
.map(|text| {
// Take first few words, limit to 4 words
text.split_whitespace()
.take(4)
.collect::<Vec<_>>()
.join(" ")
})
.unwrap_or_else(|| "Simple task".to_string());
if std::env::var("GOOSE_CODEX_DEBUG").is_ok() {
println!("=== CODEX PROVIDER DEBUG ===");
println!("Generated simple session description: {}", description);
println!("Skipped subprocess call for session description");
println!("============================");
}
let message = Message::new(
Role::Assistant,
chrono::Utc::now().timestamp(),
vec![MessageContent::text(description.clone())],
);
let usage = Usage::default();
Ok((
message,
ProviderUsage::new(self.model.model_name.clone(), usage),
))
}
}
/// Builds the text prompt and extracts images to temp files in a single pass.
@@ -724,9 +679,11 @@ impl Provider for CodexProvider {
messages: &[Message],
tools: &[Tool],
) -> Result<(Message, ProviderUsage), ProviderError> {
// Check if this is a session description request
if system.contains("four words or less") || system.contains("4 words or less") {
return self.generate_simple_session_description(messages);
if super::cli_common::is_session_description_request(system) {
return super::cli_common::generate_simple_session_description(
&model_config.model_name,
messages,
);
}
let lines = self.execute_command(system, messages, tools).await?;
@@ -1192,15 +1149,6 @@ mod tests {
#[test]
fn test_session_description_generation() {
let provider = CodexProvider {
command: PathBuf::from("codex"),
model: ModelConfig::new("gpt-5.2-codex").unwrap(),
name: "codex".to_string(),
reasoning_effort: "high".to_string(),
skip_git_check: false,
mcp_config_overrides: Vec::new(),
};
let messages = vec![Message::new(
Role::User,
chrono::Utc::now().timestamp(),
@@ -1209,12 +1157,15 @@ mod tests {
)],
)];
let result = provider.generate_simple_session_description(&messages);
let result = crate::providers::cli_common::generate_simple_session_description(
"gpt-5.2-codex",
&messages,
);
assert!(result.is_ok());
let (message, _usage) = result.unwrap();
let (message, usage) = result.unwrap();
assert_eq!(usage.model, "gpt-5.2-codex");
if let MessageContent::Text(text) = &message.content[0] {
// Should be truncated to 4 words
let word_count = text.text.split_whitespace().count();
assert!(word_count <= 4);
} else {
@@ -1224,18 +1175,12 @@ mod tests {
#[test]
fn test_session_description_empty_messages() {
let provider = CodexProvider {
command: PathBuf::from("codex"),
model: ModelConfig::new("gpt-5.2-codex").unwrap(),
name: "codex".to_string(),
reasoning_effort: "high".to_string(),
skip_git_check: false,
mcp_config_overrides: Vec::new(),
};
let messages: Vec<Message> = vec![];
let result = provider.generate_simple_session_description(&messages);
let result = crate::providers::cli_common::generate_simple_session_description(
"gpt-5.2-codex",
&messages,
);
assert!(result.is_ok());
let (message, _usage) = result.unwrap();