Add contact name filter to SMS search tool + misc improvements
- sms search tool: accept contact name, trim/validate, skip when contact_id is set, pass to API client - sms_client: new contact field in SmsSearchParams, URL-encode on wire - Tool description clarifies contact_id takes precedence when both given - Add parse_title_body helper for LLM response parsing - llamacpp backend improvements
This commit is contained in:
1 parent
b9175e2718
commit
0a627f4880
4 files changed
+165
-67
No files matched your search
@@ -354,6 +354,8 @@ impl LlamaCppClient {
|
||||
.and_then(|v| v.as_i64())
|
||||
.map(|n| n as i32);
|
||||
|
||||
log_timings(&parsed, prompt_tokens, completion_tokens);
|
||||
|
||||
Ok((chat_msg, prompt_tokens, completion_tokens))
|
||||
}
|
||||
}
|
||||
@@ -456,6 +458,7 @@ impl LlmClient for LlamaCppClient {
|
||||
let mut role = "assistant".to_string();
|
||||
let mut prompt_tokens: Option<i32> = None;
|
||||
let mut completion_tokens: Option<i32> = None;
|
||||
let mut last_frame: Option<Value> = None;
|
||||
let mut done_seen = false;
|
||||
|
||||
while let Some(chunk) = byte_stream.next().await {
|
||||
@@ -505,6 +508,7 @@ impl LlmClient for LlamaCppClient {
|
||||
.get("completion_tokens")
|
||||
.and_then(|n| n.as_i64())
|
||||
.map(|n| n as i32);
|
||||
last_frame = Some(v.clone());
|
||||
}
|
||||
|
||||
let Some(choices) = v.get("choices").and_then(|c| c.as_array())
|
||||
@@ -587,6 +591,10 @@ impl LlmClient for LlamaCppClient {
|
||||
Some(v)
|
||||
};
|
||||
|
||||
if let Some(ref frame) = last_frame {
|
||||
log_timings(frame, prompt_tokens, completion_tokens);
|
||||
}
|
||||
|
||||
let message = ChatMessage {
|
||||
role,
|
||||
content: accumulated_content,
|
||||
@@ -720,6 +728,44 @@ impl LlamaCppClient {
|
||||
/// Extract a diagnostic fragment from a llama-swap / llama-server response
|
||||
/// that doesn't match the expected `{choices: [...]}` shape. llama-server
|
||||
/// returns errors as `{"error": {"message": "...", "code": N, "type": "..."}}`;
|
||||
fn log_timings(parsed: &Value, prompt_tokens: Option<i32>, completion_tokens: Option<i32>) {
|
||||
let timings = match parsed.get("timings") {
|
||||
Some(t) => t,
|
||||
None => return,
|
||||
};
|
||||
let prompt_tps = timings.get("prompt_per_second").and_then(|v| v.as_f64());
|
||||
let gen_tps = timings.get("predicted_per_second").and_then(|v| v.as_f64());
|
||||
let prompt_ms = timings.get("prompt_ms").and_then(|v| v.as_f64());
|
||||
let gen_ms = timings.get("predicted_ms").and_then(|v| v.as_f64());
|
||||
|
||||
let mut parts: Vec<String> = Vec::new();
|
||||
if let Some(c) = prompt_tokens {
|
||||
let mut s = format!("prompt={} tok", c);
|
||||
if let Some(ms) = prompt_ms {
|
||||
s.push_str(&format!(" ({:.0} ms", ms));
|
||||
if let Some(tps) = prompt_tps {
|
||||
s.push_str(&format!(", {:.1} tok/s", tps));
|
||||
}
|
||||
s.push(')');
|
||||
}
|
||||
parts.push(s);
|
||||
}
|
||||
if let Some(c) = completion_tokens {
|
||||
let mut s = format!("gen={} tok", c);
|
||||
if let Some(ms) = gen_ms {
|
||||
s.push_str(&format!(" ({:.0} ms", ms));
|
||||
if let Some(tps) = gen_tps {
|
||||
s.push_str(&format!(", {:.1} tok/s", tps));
|
||||
}
|
||||
s.push(')');
|
||||
}
|
||||
parts.push(s);
|
||||
}
|
||||
if !parts.is_empty() {
|
||||
log::info!("llama-swap chat metrics — {}", parts.join(", "));
|
||||
}
|
||||
}
|
||||
|
||||
/// llama-swap itself sometimes wraps subprocess failures with its own
|
||||
/// `{"error": "..."}` flat shape. Surface either when present, otherwise fall
|
||||
/// back to a truncated raw-JSON view.
|
||||
|
||||
Reference in new issue
Block a user