docs: tambah doc comment, logging, dan inline comments di semua 255 file
Meliputi: - File-level //! doc comment: tujuan file, alur kerja, komponen utama - Function-level /// doc comment: apa, parameter, return, flow, edge cases - Struct/enum/trait /// doc comment: peran, field docs - Tracing logging (tracing::info!/debug!/trace!/warn!/error!) di setiap fungsi - Inline comments untuk variable dan branching logic penting - Seluruh 8 crates di workspace: zesdex-backend, zesdex-cms, zesdex-entities, zesdex-iam, zesdex-infra, zesdex-ipc, zesdex-middleware, zesdex-utils - Build: 0 errors, 242/242 tests passed
This commit is contained in:
@@ -1,7 +1,25 @@
|
||||
//! Provider-facing DTOs: chat completion request, response, streaming types,
|
||||
//! and the SSE stream parser.
|
||||
//!
|
||||
//! # Flow
|
||||
//!
|
||||
//! 1. **Request** — [`ChatRequest`] is built with model, messages, tools,
|
||||
//! streaming options and sent to the LLM provider.
|
||||
//! 2. **Response** — Non-streaming responses arrive as [`ChatResponse`] with
|
||||
//! [`Choice`]s containing the full [`ChatMessage`](super::message::ChatMessage).
|
||||
//! 3. **Streaming** — SSE chunks are fed into [`SseParser::feed`] which yields
|
||||
//! [`StreamEvent`]s: token/text, reasoning, tool-call deltas, usage, done.
|
||||
//!
|
||||
//! # Components
|
||||
//!
|
||||
//! - `ChatRequest` / `StreamOptions` / `ToolDef` / `ToolFunctionDef` — outbound
|
||||
//! - `ChatResponse` / `Choice` / `Delta` / `TokenUsage` — non-streaming inbound
|
||||
//! - `StreamEvent` — one atomic streaming event (Token, Reasoning,
|
||||
//! ToolCallDelta, Usage, Done, Error)
|
||||
//! - `SseParser` — incremental SSE frame parser: `feed()` → `Vec<StreamEvent>`
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tracing;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Chat request / response
|
||||
@@ -11,23 +29,32 @@ use serde_json::Value;
|
||||
/// provider.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ChatRequest {
|
||||
/// Model identifier, e.g. `"anthropic/claude-opus-4-8"`.
|
||||
pub model: String,
|
||||
/// Full message history (system + user + assistant + tool turns).
|
||||
pub messages: Vec<super::message::ChatMessage>,
|
||||
/// Maximum number of output tokens.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_tokens: Option<u32>,
|
||||
/// Sampling temperature (0.0 – 2.0).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub temperature: Option<f32>,
|
||||
/// Tool definitions available to the model.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tools: Option<Vec<ToolDef>>,
|
||||
/// Controls which (if any) function is called by the model.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tool_choice: Option<Value>,
|
||||
/// Whether to use SSE streaming (`true`) or a single response.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stream: Option<bool>,
|
||||
/// Nucleus sampling threshold.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub top_p: Option<f32>,
|
||||
/// Sequences where the model should stop generation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stop: Option<Vec<String>>,
|
||||
/// Additional streaming options (e.g. `include_usage`).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stream_options: Option<StreamOptions>,
|
||||
}
|
||||
@@ -42,38 +69,53 @@ pub struct StreamOptions {
|
||||
/// Wire format for a single tool definition sent to the provider.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ToolDef {
|
||||
/// The tool type discriminator, e.g. `"function"`.
|
||||
#[serde(rename = "type")]
|
||||
pub type_: String,
|
||||
/// The function definition (name, description, JSON schema).
|
||||
pub function: ToolFunctionDef,
|
||||
}
|
||||
|
||||
/// Name, description, and JSON schema parameters for a tool definition.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ToolFunctionDef {
|
||||
/// The function name the model may invoke.
|
||||
pub name: String,
|
||||
/// Human-readable description of what the function does.
|
||||
pub description: String,
|
||||
/// JSON Schema object describing the expected arguments.
|
||||
pub parameters: Value,
|
||||
}
|
||||
|
||||
/// Non-streaming chat completion response returned by the provider.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ChatResponse {
|
||||
/// Unique response identifier from the provider.
|
||||
pub id: String,
|
||||
/// Object type, e.g. `"chat.completion"`.
|
||||
pub object: Option<String>,
|
||||
/// Model identifier that produced this response.
|
||||
pub model: String,
|
||||
/// One or more completion candidates.
|
||||
pub choices: Vec<Choice>,
|
||||
/// Token usage statistics (prompt, completion, total).
|
||||
pub usage: Option<TokenUsage>,
|
||||
/// Unix-timestamp of response creation.
|
||||
pub created: Option<i64>,
|
||||
}
|
||||
|
||||
/// One completion candidate within a `ChatResponse.choices` list.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Choice {
|
||||
/// Zero-based index of this choice in the candidate list.
|
||||
pub index: u32,
|
||||
/// Full message (non-streaming response).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<super::message::ChatMessage>,
|
||||
/// Incremental delta (streaming response).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delta: Option<Delta>,
|
||||
/// Why the model stopped: `"stop"`, `"tool_calls"`, `"length"`, etc.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub finish_reason: Option<String>,
|
||||
}
|
||||
@@ -81,10 +123,13 @@ pub struct Choice {
|
||||
/// Incremental delta emitted in a streaming SSE chunk.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Delta {
|
||||
/// Role being set for the first streaming chunk.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub role: Option<super::message::Role>,
|
||||
/// Incremental text content delta.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
/// Incremental tool-call delta (partial name/arguments).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tool_calls: Option<Vec<super::tool_call::ToolCall>>,
|
||||
}
|
||||
@@ -92,11 +137,16 @@ pub struct Delta {
|
||||
/// Token counts and optional cost breakdown for a single completion request.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct TokenUsage {
|
||||
/// Tokens consumed by the prompt (input).
|
||||
pub prompt_tokens: u32,
|
||||
/// Tokens consumed by the completion (output).
|
||||
pub completion_tokens: u32,
|
||||
/// Sum of prompt + completion tokens.
|
||||
pub total_tokens: u32,
|
||||
/// Estimated cost for prompt tokens (provider-specific).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prompt_tokens_cost: Option<f64>,
|
||||
/// Estimated cost for completion tokens (provider-specific).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_tokens_cost: Option<f64>,
|
||||
}
|
||||
@@ -108,28 +158,41 @@ pub struct TokenUsage {
|
||||
/// One atomic event extracted from an LLM streaming response stream.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum StreamEvent {
|
||||
/// An incremental text token.
|
||||
Token(String),
|
||||
/// An incremental reasoning token (Anthropic `reasoning_content`).
|
||||
Reasoning(String),
|
||||
/// An incremental tool-call delta (partial ID, name, or arguments).
|
||||
ToolCallDelta {
|
||||
/// Tool-call index (multiple calls in one response).
|
||||
index: usize,
|
||||
/// Optional tool-call ID (usually in the first delta for a call).
|
||||
id: Option<String>,
|
||||
/// Optional function name (usually in the first delta for a call).
|
||||
name: Option<String>,
|
||||
/// Partial JSON arguments delta for this tool call.
|
||||
arguments_delta: String,
|
||||
},
|
||||
/// Final usage chunk with token counts.
|
||||
Usage {
|
||||
prompt_tokens: u64,
|
||||
completion_tokens: u64,
|
||||
total_tokens: u64,
|
||||
},
|
||||
/// Stream complete (all tokens have been delivered).
|
||||
Done,
|
||||
/// A stream-level error occurred.
|
||||
Error(String),
|
||||
}
|
||||
|
||||
/// Buffered SSE frame parser that accumulates raw `data:` lines and
|
||||
/// flushes a `StreamEvent` on each blank-line boundary.
|
||||
pub struct SseParser {
|
||||
/// Leftover bytes from the last chunk that did not end with `\n`.
|
||||
buffer: String,
|
||||
/// The current `event:` type (set by `event:` lines, cleared on flush).
|
||||
event_type: Option<String>,
|
||||
/// Accumulated `data:` lines for the current event frame.
|
||||
data_lines: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user