Refactor view modules for improved readability and consistency
- Updated markdown rendering logic to use more concise methods for obtaining vector lengths. - Changed review status display to use the correct flag from settings. - Cleaned up sidebar rendering code for better formatting and readability. - Enhanced status bar rendering with improved string formatting and consistent style application. - Refined workflow panel rendering, ensuring consistent style usage and improved readability. - Added architecture overview and detailed documentation for backend, data, dependencies, and frontend structures.
This commit is contained in:
+28
-15
@@ -1,11 +1,10 @@
|
||||
//! Blocking HTTP client for OpenAI/Anthropic-compatible chat completion APIs,
|
||||
//! supporting both non-streaming and SSE-streaming requests with automatic retry.
|
||||
|
||||
use std::time::Duration;
|
||||
use anyhow::Result;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::app::runtime::stream::{SseParser, StreamEvent};
|
||||
use crate::app::runtime::stream::turn::StreamedTurn;
|
||||
use crate::app::runtime::stream::{SseParser, StreamEvent};
|
||||
use crate::dto::chat::message::ChatMessage;
|
||||
use crate::dto::provider::request::{ChatRequest, StreamOptions, ToolDef};
|
||||
|
||||
@@ -76,7 +75,9 @@ impl LlmClient {
|
||||
LlmClient {
|
||||
client,
|
||||
api_key,
|
||||
base_url: base_url.filter(|s| !s.is_empty()).unwrap_or_else(|| DEFAULT_BASE_URL.to_string()),
|
||||
base_url: base_url
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or_else(|| DEFAULT_BASE_URL.to_string()),
|
||||
model,
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,8 @@ impl LlmClient {
|
||||
loop {
|
||||
attempt += 1;
|
||||
|
||||
let mut http_req = self.client
|
||||
let mut http_req = self
|
||||
.client
|
||||
.post(&url)
|
||||
.header("Content-Type", "application/json");
|
||||
|
||||
@@ -142,7 +144,10 @@ impl LlmClient {
|
||||
|
||||
let data: crate::dto::provider::response::ChatResponse = resp.json()?;
|
||||
let usage = data.usage.map(|u| {
|
||||
(u64::from(u.prompt_tokens.unwrap_or(0)), u64::from(u.completion_tokens.unwrap_or(0)))
|
||||
(
|
||||
u64::from(u.prompt_tokens.unwrap_or(0)),
|
||||
u64::from(u.completion_tokens.unwrap_or(0)),
|
||||
)
|
||||
});
|
||||
let message = data
|
||||
.choices
|
||||
@@ -158,7 +163,8 @@ impl LlmClient {
|
||||
Err(e) => {
|
||||
let err_str = e.to_string();
|
||||
let err_lower = err_str.to_lowercase();
|
||||
let is_auth_error = err_str.contains("401") || err_str.contains("403")
|
||||
let is_auth_error = err_str.contains("401")
|
||||
|| err_str.contains("403")
|
||||
|| err_lower.contains("unauthorized")
|
||||
|| err_lower.contains("forbidden")
|
||||
|| err_lower.contains("authentication failed");
|
||||
@@ -195,7 +201,9 @@ impl LlmClient {
|
||||
stream: Some(true),
|
||||
top_p: None,
|
||||
stop: None,
|
||||
stream_options: Some(StreamOptions { include_usage: true }),
|
||||
stream_options: Some(StreamOptions {
|
||||
include_usage: true,
|
||||
}),
|
||||
};
|
||||
|
||||
let url = format!("{}/chat/completions", self.base_url);
|
||||
@@ -217,7 +225,8 @@ impl LlmClient {
|
||||
Err(e) => {
|
||||
let err_str = e.to_string();
|
||||
let err_lower = err_str.to_lowercase();
|
||||
let is_auth_error = err_str.contains("401") || err_str.contains("403")
|
||||
let is_auth_error = err_str.contains("401")
|
||||
|| err_str.contains("403")
|
||||
|| err_lower.contains("unauthorized")
|
||||
|| err_lower.contains("forbidden")
|
||||
|| err_lower.contains("authentication failed");
|
||||
@@ -250,7 +259,8 @@ impl LlmClient {
|
||||
) -> Result<(ChatMessage, Option<(u64, u64)>)> {
|
||||
use std::io::Read;
|
||||
|
||||
let mut http_req = self.client
|
||||
let mut http_req = self
|
||||
.client
|
||||
.post(url)
|
||||
.header("Content-Type", "application/json");
|
||||
if !self.api_key.is_empty() {
|
||||
@@ -281,7 +291,8 @@ impl LlmClient {
|
||||
let mut chunk_buf = [0u8; 4096];
|
||||
|
||||
loop {
|
||||
let n = reader.read(&mut chunk_buf)
|
||||
let n = reader
|
||||
.read(&mut chunk_buf)
|
||||
.map_err(|e| anyhow::anyhow!("stream read error: {e}"))?;
|
||||
if n == 0 {
|
||||
break;
|
||||
@@ -302,7 +313,11 @@ impl LlmClient {
|
||||
anyhow::bail!("aborted");
|
||||
}
|
||||
match &event {
|
||||
StreamEvent::Usage { prompt_tokens, completion_tokens, .. } => {
|
||||
StreamEvent::Usage {
|
||||
prompt_tokens,
|
||||
completion_tokens,
|
||||
..
|
||||
} => {
|
||||
usage = Some((*prompt_tokens, *completion_tokens));
|
||||
}
|
||||
StreamEvent::Error(msg) => {
|
||||
@@ -326,9 +341,7 @@ impl LlmClient {
|
||||
// into a tool call that will misbehave (e.g. a `write` call with a
|
||||
// half-written file body).
|
||||
if let Some((name, err)) = turn.incomplete_tool_call() {
|
||||
anyhow::bail!(
|
||||
"stream ended before tool call '{name}' arguments were complete: {err}"
|
||||
);
|
||||
anyhow::bail!("stream ended before tool call '{name}' arguments were complete: {err}");
|
||||
}
|
||||
|
||||
turn.is_complete = true;
|
||||
|
||||
Reference in New Issue
Block a user