use serde_json::{Map, Value, json};
use super::WsRow;
use crate::binding::WorkspaceKind;
use crate::git_tree::AgentState;
use crate::monitor::Check;
use crate::nav::convs::Tone;
use crate::nav::convs::{ConvRow, Flight};
use crate::opslog::OpRow;
use crate::projects::join::JoinRow;
use super::super::codec::join_token;
use super::super::codec::origin_token;
pub(crate) mod decode;
pub(super) fn ws_row(row: &WsRow) -> Value {
let mut map = Map::new();
map.insert("workspace".to_owned(), Value::String(row.workspace.clone()));
let kind = match &row.kind {
WorkspaceKind::Named { .. } => "named",
WorkspaceKind::Foreign => "foreign",
WorkspaceKind::Replay => "replay",
};
map.insert("kind".to_owned(), Value::String(kind.to_owned()));
map.insert("attention".to_owned(), json!(row.attention));
map.insert("agents".to_owned(), json!(row.agents));
map.insert("running".to_owned(), json!(row.running));
if let Some(rank) = row.pinned {
map.insert("pinned".to_owned(), json!(rank));
}
if let Some(tip) = &row.config_tip {
map.insert(
"config_tip".to_owned(),
json!({ "oid": tip.oid, "short_oid": tip.short_oid }),
);
}
Value::Object(map)
}
pub(super) fn lineage_row(row: &crate::config_edit::branch::Lineage) -> Value {
json!({
"name": row.branch.name,
"oid": row.branch.tip_oid,
"short_oid": row.branch.tip_short_oid,
"committed": row.branch.tip_timestamp_unix,
"files": row.files,
})
}
pub(super) fn conv_row(row: &ConvRow) -> Value {
let mut map = Map::new();
map.insert("root_id".to_owned(), json!(row.root_id));
map.insert("display".to_owned(), json!(row.display_name()));
if let Some(name) = row.name.as_ref().filter(|_| !row.name_display_only) {
map.insert("name".to_owned(), json!(name));
}
map.insert("display_only".to_owned(), json!(row.name_display_only));
map.insert("state".to_owned(), json!(state_token(row.state)));
map.insert("uncertain".to_owned(), json!(row.uncertain));
map.insert("preview".to_owned(), json!(row.preview));
map.insert("age_secs".to_owned(), json!(row.age_secs));
map.insert("last_active_unix".to_owned(), json!(row.last_active_unix));
if let Some(flight) = row.flight {
map.insert("flight".to_owned(), json!(flight_token(flight)));
}
map.insert("attention".to_owned(), json!(row.attention));
map.insert("members".to_owned(), json!(row.members));
map.insert("direct".to_owned(), json!(row.direct));
map.insert("stoppable".to_owned(), json!(row.stoppable));
map.insert("stop_children".to_owned(), json!(row.stop_children));
map.insert("depth".to_owned(), json!(row.depth));
map.insert("tone".to_owned(), json!(tone_token(row.tone)));
if let Some(says) = &row.failure {
map.insert("failure".to_owned(), json!(says));
}
if let Some(check) = &row.verdict {
map.insert("alignment".to_owned(), check_value(check));
}
if let Some(ball) = &row.ball {
let mut b = Map::new();
b.insert("id".to_owned(), json!(ball.id));
if let Some(state) = ball.state {
b.insert("state".to_owned(), json!(join_token(state)));
}
if let Some(title) = &ball.title {
b.insert("title".to_owned(), json!(title));
}
if let Some(badge) = &ball.badge {
b.insert("badge".to_owned(), json!(badge));
}
map.insert("ball".to_owned(), Value::Object(b));
}
Value::Object(map)
}
pub(super) fn join_row(row: &JoinRow) -> Value {
let mut map = Map::new();
map.insert("project".to_owned(), json!(row.project));
map.insert("ball_id".to_owned(), json!(row.ball_id));
map.insert("state".to_owned(), json!(join_token(row.state)));
if let Some(ws) = &row.workspace {
map.insert("workspace".to_owned(), json!(ws));
}
if let Some(claimant) = &row.claimant {
map.insert("claimant".to_owned(), json!(claimant));
}
if let Some(title) = &row.title {
map.insert("title".to_owned(), json!(title));
}
Value::Object(map)
}
pub(super) fn op_row(row: &OpRow) -> Value {
json!({
"ts": row.ts, "argv": row.argv, "cwd": row.cwd, "exit": row.exit,
"stdout": row.stdout, "stderr": row.stderr,
"origin": origin_token(row.origin),
})
}
pub(crate) fn state_token(state: AgentState) -> &'static str {
match state {
AgentState::Live => "live",
AgentState::InFlight => "in-flight",
AgentState::Quiescent => "quiescent",
AgentState::Stopped => "stopped",
}
}
pub(super) fn tone_token(tone: Tone) -> &'static str {
match tone {
Tone::Plain => "plain",
Tone::Weak => "weak",
Tone::Good => "good",
Tone::Bad => "bad",
Tone::Live => "live",
Tone::InFlight => "in-flight",
}
}
fn check_value(check: &Check) -> Value {
let mut map = Map::new();
map.insert("workspace".to_owned(), json!(check.workspace));
map.insert("agent".to_owned(), json!(check.agent));
map.insert("verdict".to_owned(), json!(check.verdict.token()));
map.insert("sha".to_owned(), json!(check.sha));
map.insert("reason".to_owned(), json!(check.reason));
map.insert("model".to_owned(), json!(check.model));
for (key, count) in [
("input_tokens", check.input_tokens),
("output_tokens", check.output_tokens),
] {
if let Some(count) = count {
map.insert(key.to_owned(), json!(count));
}
}
Value::Object(map)
}
pub(super) fn flight_token(flight: Flight) -> &'static str {
match flight {
Flight::Inference => "inference",
Flight::Tools => "tools",
Flight::Subagents => "subagents",
}
}
pub(super) fn provider_row(row: &crate::config_edit::brazen::ProviderRowView) -> Value {
json!({ "name": row.name, "fact": row.fact, "blocked": row.blocked,
"effort": row.effort, "priority": row.priority })
}
pub(super) fn role_row(row: &crate::model_pick::RoleModel) -> Value {
json!({ "role": row.role, "provider": row.provider, "model": row.model,
"effort": row.effort, "priority": row.priority })
}