Agent: durable turn and queue state, visible inbox closure, OpenAI phase; prompt fixes; fetch/bench fixes

This commit is contained in:
2026-10-15 11:54:41 +01:00
parent 1cd8971aa3
commit 69cf80a114
7 changed files with 296 additions and 103 deletions
+19 -6
View File
@@ -25,7 +25,11 @@ pub struct Config {
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Entry {
User { text: String },
Assistant { text: String },
Assistant {
text: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
phase: Option<String>,
},
ToolCall { id: String, name: String, arguments: String },
ToolResult { id: String, output: String },
/// A provider item that only this API shape understands (OpenAI reasoning).
@@ -68,7 +72,13 @@ async fn openai(cfg: &Config, system: &str, tools: &[Tool], history: &[Entry]) -
for e in history {
match e {
Entry::User { text } => input.push(json!({"role": "user", "content": text})),
Entry::Assistant { text } => input.push(json!({"role": "assistant", "content": text})),
Entry::Assistant { text, phase } => {
let mut item = json!({"role": "assistant", "content": text});
if let Some(phase) = phase {
item["phase"] = json!(phase);
}
input.push(item);
}
Entry::ToolCall { id, name, arguments } => {
input.push(json!({"type": "function_call", "call_id": id, "name": name, "arguments": arguments}))
}
@@ -113,8 +123,9 @@ async fn openai(cfg: &Config, system: &str, tools: &[Tool], history: &[Entry]) -
.collect()
})
.unwrap_or_default();
if !text.is_empty() {
out.push(Entry::Assistant { text });
let phase = item["phase"].as_str().map(str::to_string);
if !text.is_empty() || phase.is_some() {
out.push(Entry::Assistant { text, phase });
}
}
Some("function_call") => out.push(Entry::ToolCall {
@@ -142,7 +153,9 @@ async fn anthropic(cfg: &Config, system: &str, tools: &[Tool], history: &[Entry]
for e in history {
match e {
Entry::User { text } => push("user", json!({"type": "text", "text": text})),
Entry::Assistant { text } => push("assistant", json!({"type": "text", "text": text})),
Entry::Assistant { text, .. } => {
push("assistant", json!({"type": "text", "text": text}))
}
Entry::ToolCall { id, name, arguments } => {
let input: Value = serde_json::from_str(arguments).unwrap_or(json!({}));
push("assistant", json!({"type": "tool_use", "id": id, "name": name, "input": input}))
@@ -178,7 +191,7 @@ async fn anthropic(cfg: &Config, system: &str, tools: &[Tool], history: &[Entry]
Some("text") => {
let text = block["text"].as_str().unwrap_or_default().to_string();
if !text.is_empty() {
out.push(Entry::Assistant { text });
out.push(Entry::Assistant { text, phase: None });
}
}
Some("tool_use") => out.push(Entry::ToolCall {