use std::fmt::Write as _;
use serde_json::{json, Value};
use crate::canonical::{CanonicalError, Usage};
use crate::ingress::state::IngressState;
pub(super) fn emit(state: &mut IngressState, delta: Value, finish: Option<&str>) -> Vec<u8> {
if !state.stream {
return Vec::new();
}
let chunk = json!({
"choices": [{"delta": delta, "finish_reason": finish, "index": 0}],
"created": state.created,
"id": state.wire_id(),
"model": state.wire_model(),
"object": "chat.completion.chunk",
});
let chunk = with_usage_slot(chunk, state);
frame(state, &chunk)
}
fn with_usage_slot(mut chunk: Value, state: &IngressState) -> Value {
if state.include_usage {
chunk["usage"] = Value::Null;
}
chunk
}
pub(super) fn emit_usage(state: &mut IngressState) -> Vec<u8> {
if !state.stream {
return Vec::new();
}
let chunk = json!({
"choices": [],
"created": state.created,
"id": state.wire_id(),
"model": state.wire_model(),
"object": "chat.completion.chunk",
"usage": state.usage.clone(),
});
frame(state, &chunk)
}
pub(super) fn sentinel(state: &mut IngressState) -> Vec<u8> {
format!("{}data: [DONE]\n\n", comments(state)).into_bytes()
}
fn frame(state: &mut IngressState, payload: &Value) -> Vec<u8> {
format!("{}data: {payload}\n\n", comments(state)).into_bytes()
}
fn comments(state: &mut IngressState) -> String {
let mut out = String::new();
for name in state.pending.drain(..) {
let _ = writeln!(out, ": brazen adaptation={name}");
}
out
}
pub(super) fn usage_json(u: &Usage) -> Value {
let input = u64::from(u.input_tokens.unwrap_or(0));
let output = u64::from(u.output_tokens.unwrap_or(0));
let mut v = json!({
"completion_tokens": output,
"prompt_tokens": input,
"total_tokens": input + output,
});
if let Some(c) = u.cache_read_tokens {
v["prompt_tokens_details"] = json!({"cached_tokens": c});
}
v
}
pub(super) fn error(e: &CanonicalError, state: &mut IngressState) -> Vec<u8> {
let status = e.kind.http_status();
let envelope = json!({"error": {
"code": status,
"message": e.message,
"param": null,
"type": error_type(status),
}});
state.status = Some(status);
let out = if state.stream {
frame(state, &envelope)
} else {
Vec::new()
};
state.error = Some(envelope);
out
}
fn error_type(status: u16) -> &'static str {
match status {
401 | 403 => "authentication_error",
429 => "rate_limit_error",
400..=499 => "invalid_request_error",
_ => "server_error",
}
}
pub(super) fn body(state: &IngressState) -> Vec<u8> {
let mut v = match &state.error {
Some(e) => e.clone(),
None => success_body(state),
};
if !state.adaptations.is_empty() {
v["brazen"] = json!({"adaptations": state.adaptations});
}
v.to_string().into_bytes()
}
fn success_body(state: &IngressState) -> Value {
let mut message = json!({
"content": or_null(&state.text),
"refusal": or_null(&state.refusal),
"role": "assistant",
});
if !state.tools.is_empty() {
message["tool_calls"] = Value::Array(
state
.tools
.iter()
.map(|t| {
json!({
"function": {"arguments": t.args, "name": t.name},
"id": t.id, "type": "function",
})
})
.collect(),
);
}
json!({
"choices": [{"finish_reason": state.finish, "index": 0, "message": message}],
"created": state.created,
"id": state.wire_id(),
"model": state.wire_model(),
"object": "chat.completion",
"usage": state.usage,
})
}
fn or_null(s: &str) -> Value {
if s.is_empty() {
Value::Null
} else {
s.into()
}
}