ci: add GitHub Actions workflows with semantic-release auto-versioning
chore: fix all 702 clippy warnings across codebase - auto-fix 475 via cargo clippy --fix - fix remaining 227 manually: uninlined_format_args, redundant_closure, match_same_arms, underscore_binding, format_push_string, items_after_statements, needless_pass_by_value, clone_on_copy, case_sensitive_extension, single_match/let-else, write_with_newline, and other clippy lints
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_precision_loss, clippy::cast_possible_wrap)]
|
||||
//! SSE stream parser: converts SSE- or JSON-chunked LLM responses into
|
||||
//! typed `StreamEvent` variants (tokens, reasoning, tool calls, usage, done).
|
||||
pub mod turn;
|
||||
@@ -88,6 +89,7 @@ impl SseParser {
|
||||
/// provider-specific parsing layer.
|
||||
///
|
||||
/// Return: 0, 1, or more `StreamEvent`s from the flushed frame.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn flush_event(&mut self) -> Vec<StreamEvent> {
|
||||
let data = self.data_lines.join("\n");
|
||||
self.data_lines.clear();
|
||||
@@ -107,15 +109,15 @@ impl SseParser {
|
||||
};
|
||||
if let Some(usage) = value.get("usage") {
|
||||
if !usage.is_null() {
|
||||
let prompt_tokens = usage.get("prompt_tokens").and_then(|v| v.as_u64()).unwrap_or_else(|| {
|
||||
let prompt_tokens = usage.get("prompt_tokens").and_then(serde_json::Value::as_u64).unwrap_or_else(|| {
|
||||
tracing::warn!("[stream] prompt_tokens missing in usage chunk");
|
||||
0
|
||||
});
|
||||
let completion_tokens = usage.get("completion_tokens").and_then(|v| v.as_u64()).unwrap_or_else(|| {
|
||||
let completion_tokens = usage.get("completion_tokens").and_then(serde_json::Value::as_u64).unwrap_or_else(|| {
|
||||
tracing::warn!("[stream] completion_tokens missing in usage chunk");
|
||||
0
|
||||
});
|
||||
let total_tokens = usage.get("total_tokens").and_then(|v| v.as_u64())
|
||||
let total_tokens = usage.get("total_tokens").and_then(serde_json::Value::as_u64)
|
||||
.unwrap_or_else(|| {
|
||||
tracing::warn!("[stream] total_tokens missing in usage chunk");
|
||||
prompt_tokens + completion_tokens
|
||||
@@ -126,12 +128,11 @@ impl SseParser {
|
||||
// in the same chunk; emitting both prevents content loss.
|
||||
let has_other_content = value.get("choices")
|
||||
.and_then(|c| c.as_array())
|
||||
.map(|arr| arr.iter().any(|ch| {
|
||||
.is_some_and(|arr| arr.iter().any(|ch| {
|
||||
ch.get("delta").and_then(|d| d.get("content")).is_some()
|
||||
|| ch.get("delta").and_then(|d| d.get("reasoning_content")).is_some()
|
||||
|| ch.get("delta").and_then(|d| d.get("tool_calls")).is_some()
|
||||
}))
|
||||
.unwrap_or(false);
|
||||
}));
|
||||
if !has_other_content {
|
||||
return vec![StreamEvent::Usage { prompt_tokens, completion_tokens, total_tokens }];
|
||||
}
|
||||
@@ -139,21 +140,11 @@ impl SseParser {
|
||||
}
|
||||
match event_type.as_str() {
|
||||
"message.stop" => vec![StreamEvent::Done],
|
||||
"message.start" => vec![],
|
||||
"message.delta" | "" => {
|
||||
let delta = match value.get("delta").or_else(|| value.get("choices")) {
|
||||
Some(d) => d,
|
||||
None => return vec![],
|
||||
};
|
||||
let Some(delta) = value.get("delta").or_else(|| value.get("choices")) else { return vec![] };
|
||||
if let Some(choices) = delta.as_array() {
|
||||
let choice = match choices.first() {
|
||||
Some(c) => c,
|
||||
None => return vec![],
|
||||
};
|
||||
let d = match choice.get("delta") {
|
||||
Some(v) => v,
|
||||
None => return vec![],
|
||||
};
|
||||
let Some(choice) = choices.first() else { return vec![] };
|
||||
let Some(d) = choice.get("delta") else { return vec![] };
|
||||
|
||||
// Content token
|
||||
if let Some(content) = d.get("content").and_then(|c| c.as_str()) {
|
||||
@@ -169,15 +160,15 @@ impl SseParser {
|
||||
if let Some(tool_calls) = d.get("tool_calls").and_then(|tc| tc.as_array()) {
|
||||
let mut events = Vec::with_capacity(tool_calls.len());
|
||||
for tc in tool_calls {
|
||||
let index = tc.get("index").and_then(|i| i.as_u64()).unwrap_or_else(|| {
|
||||
let index = tc.get("index").and_then(serde_json::Value::as_u64).unwrap_or_else(|| {
|
||||
tracing::warn!("[stream] tool call delta missing index, defaulting to 0");
|
||||
0
|
||||
}) as usize;
|
||||
let id = tc.get("id").and_then(|i| i.as_str()).map(|s| s.to_string());
|
||||
let id = tc.get("id").and_then(|i| i.as_str()).map(std::string::ToString::to_string);
|
||||
let name = tc.get("function")
|
||||
.and_then(|f| f.get("name"))
|
||||
.and_then(|n| n.as_str())
|
||||
.map(|s| s.to_string());
|
||||
.map(std::string::ToString::to_string);
|
||||
let args_delta = tc.get("function")
|
||||
.and_then(|f| f.get("arguments"))
|
||||
.and_then(|a| a.as_str())
|
||||
@@ -253,15 +244,15 @@ pub fn parse_stream_chunk(data: &str) -> Option<StreamEvent> {
|
||||
}
|
||||
if let Some(tool_calls) = delta.get("tool_calls").and_then(|tc| tc.as_array()) {
|
||||
if let Some(tc) = tool_calls.first() {
|
||||
let index = tc.get("index").and_then(|i| i.as_u64()).unwrap_or_else(|| {
|
||||
let index = tc.get("index").and_then(serde_json::Value::as_u64).unwrap_or_else(|| {
|
||||
tracing::warn!("[stream] fallback parser: tool call missing index, defaulting to 0");
|
||||
0
|
||||
}) as usize;
|
||||
let id = tc.get("id").and_then(|i| i.as_str()).map(|s| s.to_string());
|
||||
let id = tc.get("id").and_then(|i| i.as_str()).map(std::string::ToString::to_string);
|
||||
let name = tc.get("function")
|
||||
.and_then(|f| f.get("name"))
|
||||
.and_then(|n| n.as_str())
|
||||
.map(|s| s.to_string());
|
||||
.map(std::string::ToString::to_string);
|
||||
let args = tc.get("function")
|
||||
.and_then(|f| f.get("arguments"))
|
||||
.and_then(|a| a.as_str())
|
||||
|
||||
Reference in New Issue
Block a user