Files
vibe-kanban/crates/executors/src/logs/utils/patch.rs
Louis Knight-Webb 0fdc73f8b7 Improve normalized logs (#455)
* Increase broadcast channel size

* Use stdout_lines_stream

* WIP fix amp logs containing all previous conversation turns

* Mark raw and normalized log streams from the DB as finished

* Update event source manager to handle removed entries

* Clippy

* Cargo fmt
2025-08-12 16:31:56 +01:00

116 lines
3.4 KiB
Rust

use json_patch::Patch;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, json};
use ts_rs::TS;
use utils::diff::Diff;
use crate::logs::NormalizedEntry;
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, TS)]
#[serde(rename_all = "lowercase")]
enum PatchOperation {
Add,
Replace,
Remove,
}
#[derive(Serialize, TS)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE", tag = "type", content = "content")]
pub enum PatchType {
NormalizedEntry(NormalizedEntry),
Stdout(String),
Stderr(String),
Diff(Diff),
}
#[derive(Serialize)]
struct PatchEntry {
op: PatchOperation,
path: String,
value: PatchType,
}
pub fn escape_json_pointer_segment(s: &str) -> String {
s.replace('~', "~0").replace('/', "~1")
}
/// Helper functions to create JSON patches for conversation entries
pub struct ConversationPatch;
impl ConversationPatch {
/// Create an ADD patch for a new conversation entry at the given index
pub fn add_normalized_entry(entry_index: usize, entry: NormalizedEntry) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Add,
path: format!("/entries/{entry_index}"),
value: PatchType::NormalizedEntry(entry),
};
from_value(json!([patch_entry])).unwrap()
}
/// Create an ADD patch for a new string at the given index
pub fn add_stdout(entry_index: usize, entry: String) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Add,
path: format!("/entries/{entry_index}"),
value: PatchType::Stdout(entry),
};
from_value(json!([patch_entry])).unwrap()
}
/// Create an ADD patch for a new string at the given index
pub fn add_stderr(entry_index: usize, entry: String) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Add,
path: format!("/entries/{entry_index}"),
value: PatchType::Stderr(entry),
};
from_value(json!([patch_entry])).unwrap()
}
/// Create an ADD patch for a new diff at the given index
pub fn add_diff(entry_index: String, diff: Diff) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Add,
path: format!("/entries/{entry_index}"),
value: PatchType::Diff(diff),
};
from_value(json!([patch_entry])).unwrap()
}
/// Create an ADD patch for a new diff at the given index
pub fn replace_diff(entry_index: String, diff: Diff) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Replace,
path: format!("/entries/{entry_index}"),
value: PatchType::Diff(diff),
};
from_value(json!([patch_entry])).unwrap()
}
/// Create a REMOVE patch for removing a diff
pub fn remove_diff(entry_index: String) -> Patch {
from_value(json!([{
"op": PatchOperation::Remove,
"path": format!("/entries/{entry_index}"),
}]))
.unwrap()
}
/// Create a REPLACE patch for updating an existing conversation entry at the given index
pub fn replace(entry_index: usize, entry: NormalizedEntry) -> Patch {
let patch_entry = PatchEntry {
op: PatchOperation::Replace,
path: format!("/entries/{entry_index}"),
value: PatchType::NormalizedEntry(entry),
};
from_value(json!([patch_entry])).unwrap()
}
}