use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ManagedProcessStatus {
Running,
Exited,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ManagedProcess {
pub id: String,
pub pid: u32,
pub command: String,
pub cwd: Option<String>,
pub log_path: String,
pub detected_url: Option<String>,
pub status: ManagedProcessStatus,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ToolRunMetadata {
#[serde(default)]
pub detail: ToolMetadata,
pub line_count: Option<usize>,
pub byte_count: Option<usize>,
pub result_count: Option<usize>,
pub duration_secs: Option<f64>,
pub process: Option<ManagedProcess>,
#[serde(default)]
pub display_diff: Option<String>,
#[serde(default)]
pub diff_truncated: bool,
#[serde(default)]
pub lines_added: usize,
#[serde(default)]
pub lines_removed: usize,
#[serde(default)]
pub artifacts: Vec<ToolArtifact>,
#[serde(default)]
pub token_usage: Option<crate::models::TokenUsage>,
#[serde(default)]
pub plan_file_written: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolStatus {
Success,
Error,
Cancelled,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ToolMetadata {
#[default]
None,
ReadFile {
paths: Vec<String>,
line_count: usize,
byte_count: usize,
truncated: bool,
},
WriteFile {
path: String,
line_count: usize,
byte_count: usize,
created: Option<bool>,
},
ApplyPatch {
added: Vec<String>,
modified: Vec<String>,
deleted: Vec<String>,
renamed: Vec<(String, String)>,
fuzzy: bool,
},
DeleteFile {
path: String,
},
CreateDirectory {
path: String,
},
WebSearch {
queries: Vec<String>,
requested_count: usize,
result_count: usize,
sources: Vec<String>,
#[serde(default)]
backend: String,
#[serde(default)]
succeeded_queries: usize,
#[serde(default)]
failed_queries: usize,
#[serde(default)]
partial: bool,
#[serde(default)]
truncated: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
failures: Vec<WebSearchFailure>,
},
WebFetch {
url: String,
#[serde(default)]
final_url: Option<String>,
#[serde(default)]
status: Option<u16>,
#[serde(default)]
error_kind: Option<String>,
#[serde(default)]
media_type: Option<String>,
#[serde(default)]
charset: Option<String>,
#[serde(default)]
backend: String,
#[serde(default)]
extraction: String,
title: Option<String>,
line_count: usize,
byte_count: usize,
#[serde(default)]
source_byte_count: usize,
#[serde(default)]
output_byte_count: usize,
#[serde(default)]
truncated: bool,
#[serde(default)]
pattern: Option<String>,
#[serde(default)]
context_lines: Option<usize>,
#[serde(default)]
match_count: Option<usize>,
#[serde(default)]
snapshot_id: Option<String>,
},
ExecuteCommand {
command: String,
working_dir: Option<String>,
exit_code: Option<i32>,
timed_out: bool,
background: bool,
stdout_lines: usize,
stderr_lines: usize,
detected_urls: Vec<String>,
pid: Option<u32>,
log_path: Option<String>,
#[serde(default)]
denied_by_sandbox: bool,
},
ComputerUse {
action: String,
params: Value,
},
Mcp {
server: String,
tool: String,
},
Subagent {
model_id: String,
#[serde(default)]
agent_id: String,
},
Tasks {
action: String,
completed: u32,
total: u32,
},
Questions {
answers: Vec<crate::question::QuestionAnswer>,
#[serde(default)]
remembered: bool,
},
Plan {
path: String,
body: String,
#[serde(default)]
start: bool,
#[serde(default)]
fresh: bool,
#[serde(default)]
fork: bool,
#[serde(default)]
model: Option<String>,
},
Custom {
name: String,
data: Value,
},
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct WebSearchFailure {
pub query_index: usize,
pub error: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ToolArtifact {
Image { data: String },
File { path: String },
Log { path: String },
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct OllamaContextInfo {
pub model_max: Option<usize>,
pub effective: Option<usize>,
pub source: Option<crate::models::adapters::ollama_sizing::NumCtxSource>,
}
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct OllamaPlacement {
pub size_vram_bytes: u64,
pub total_bytes: u64,
}
impl OllamaPlacement {
pub fn offloaded(&self) -> bool {
self.size_vram_bytes < self.total_bytes
}
pub fn percent_on_cpu(&self) -> u8 {
if self.total_bytes == 0 {
return 0;
}
let on_cpu = self.total_bytes.saturating_sub(self.size_vram_bytes);
(on_cpu.saturating_mul(100) / self.total_bytes) as u8
}
}