From 800bff4ccefaf699ff1940640231e6d1416da50e Mon Sep 17 00:00:00 2001 From: dawn <90008@klbr.net> Date: Wed, 1 Jul 2026 11:52:12 +0300 Subject: [PATCH] share ipc dto types --- .beads/interactions.jsonl | 1 + .beads/issues.jsonl | 2 +- Cargo.lock | 1 + klbr-core/src/memory.rs | 2 +- klbr-daemon/src/daemon.rs | 62 +++------------------------------------ klbr-ipc/Cargo.toml | 1 + klbr-ipc/src/lib.rs | 57 ++++------------------------------- 7 files changed, 15 insertions(+), 111 deletions(-) diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index a0adcc2..efe23dd 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -87,3 +87,4 @@ {"id":"int-c575a8f2","kind":"field_change","created_at":"2026-06-30T22:20:51.577686369Z","actor":"dawn","issue_id":"klbr-x1i","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Replaced klbr-bench raw argv dispatch with clap-derived commands and structured runner options"}} {"id":"int-96f16ee3","kind":"field_change","created_at":"2026-06-30T22:27:11.180142339Z","actor":"dawn","issue_id":"klbr-rds","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Split klbr-bench main.rs into cli, continuous_loop, and longmem modules while preserving bench behavior"}} {"id":"int-5c780dfb","kind":"field_change","created_at":"2026-06-30T22:34:06.198966004Z","actor":"dawn","issue_id":"klbr-f8w","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Split Discord formatting, inbox storage, and tool schema builders into modules and deduplicated batch row rendering prep"}} +{"id":"int-1f1c3a07","kind":"field_change","created_at":"2026-07-01T08:52:06.275727261Z","actor":"dawn","issue_id":"klbr-5h3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Re-exported core DTO types from klbr-ipc and removed daemon field-by-field mappers"}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 235f7b4..7fe38d1 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -47,7 +47,7 @@ {"_type":"issue","id":"klbr-rds","title":"bench: split 6700-line main.rs monolith into logical submodules","description":"klbr-bench main.rs is currently over 6700 lines of code. It contains benchmark suites for passive recall, continuous loop, router, sweep, and command line parsing. Needs to be split into domain submodules (cli.rs, sweep.rs, passive_recall.rs, continuous_loop.rs, etc.).","status":"closed","priority":2,"issue_type":"task","assignee":"dawn","owner":"90008@klbr.net","created_at":"2026-06-30T21:42:03Z","created_by":"dawn","updated_at":"2026-06-30T22:27:11Z","started_at":"2026-06-30T22:21:17Z","closed_at":"2026-06-30T22:27:11Z","close_reason":"Split klbr-bench main.rs into cli, continuous_loop, and longmem modules while preserving bench behavior","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"klbr-f8w","title":"discord: decompose monolithic lib.rs and deduplicate batch formatting","description":"klbr-discord lib.rs is a 2150-line monolith containing gateway loop, state database, formatting styles, and tools. Split into logical submodules, and deduplicate bracket/xml string formatting loops.","status":"closed","priority":2,"issue_type":"task","assignee":"dawn","owner":"90008@klbr.net","created_at":"2026-06-30T21:40:14Z","created_by":"dawn","updated_at":"2026-06-30T22:34:06Z","started_at":"2026-06-30T22:27:44Z","closed_at":"2026-06-30T22:34:06Z","close_reason":"Split Discord formatting, inbox storage, and tool schema builders into modules and deduplicated batch row rendering prep","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"klbr-41z","title":"daemon: fix blocking std::fs calls and secure default WS bind address","description":"DumpMemories handler in daemon.rs blocks the tokio runtime thread using sync std::fs::write. Fix to tokio::fs::write. Also, change default WS bind address to 127.0.0.1 for local-only safety.","status":"closed","priority":2,"issue_type":"task","assignee":"dawn","owner":"90008@klbr.net","created_at":"2026-06-30T21:40:08Z","created_by":"dawn","updated_at":"2026-06-30T22:04:39Z","started_at":"2026-06-30T22:03:35Z","closed_at":"2026-06-30T22:04:39Z","close_reason":"Changed daemon default websocket bind from 0.0.0.0:8765 to 127.0.0.1:8765 and replaced DumpMemories std::fs::write with tokio::fs::write(...).await. Verified rg for old patterns, cargo fmt --check, and cargo test -p klbr-daemon.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"klbr-5h3","title":"ipc/daemon: eliminate duplicate DTO structs and field mapping boilerplate","description":"HistoryEntry, ToolCall, CompactionRecord, and ResolutionEventDto are identical duplicates between klbr-ipc and klbr-core. The daemon has extensive boilerplate mapping them field-by-field. Share or re-export these types.","status":"open","priority":2,"issue_type":"task","owner":"90008@klbr.net","created_at":"2026-06-30T21:40:01Z","created_by":"dawn","updated_at":"2026-06-30T21:40:01Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"klbr-5h3","title":"ipc/daemon: eliminate duplicate DTO structs and field mapping boilerplate","description":"HistoryEntry, ToolCall, CompactionRecord, and ResolutionEventDto are identical duplicates between klbr-ipc and klbr-core. The daemon has extensive boilerplate mapping them field-by-field. Share or re-export these types.","status":"closed","priority":2,"issue_type":"task","assignee":"dawn","owner":"90008@klbr.net","created_at":"2026-06-30T21:40:01Z","created_by":"dawn","updated_at":"2026-07-01T08:52:06Z","started_at":"2026-06-30T22:34:30Z","closed_at":"2026-07-01T08:52:06Z","close_reason":"Re-exported core DTO types from klbr-ipc and removed daemon field-by-field mappers","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"klbr-2kc","title":"core: reduce KDL config parser boilerplate in parser.rs","description":"parser.rs contains ~20 copy-pasted optional_*_node helpers that share identical structure. Simplify with macros or generic helpers. Also resolve duplicate deserialize_usize.","status":"open","priority":2,"issue_type":"task","owner":"90008@klbr.net","created_at":"2026-06-30T21:39:55Z","created_by":"dawn","updated_at":"2026-06-30T21:39:55Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"klbr-zue","title":"core: fix shell.rs unsafe byte-slice truncation","description":"shell.rs truncates command output using byte offsets on a lossy UTF-8 string (e.g. stdout[..20_000]), which can panic if slicing in the middle of a multi-byte character. Truncate by char count or indices instead.","status":"closed","priority":2,"issue_type":"task","assignee":"dawn","owner":"90008@klbr.net","created_at":"2026-06-30T21:39:48Z","created_by":"dawn","updated_at":"2026-06-30T22:03:16Z","started_at":"2026-06-30T22:02:13Z","closed_at":"2026-06-30T22:03:16Z","close_reason":"Replaced shell stdout/stderr byte slicing with char-boundary truncation helper and added UTF-8 regression tests. Verified cargo test -p klbr-core shell_truncation, full cargo test -p klbr-core (168 passed, 1 ignored), cargo fmt --check, git diff --check, and rg confirms the unsafe stdout/stderr slices are gone.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"klbr-3ha","title":"core: refactor models.rs media stripping and SSE parser duplication","description":"strip_media_urls and replace_media_urls_with_placeholders share near-identical regex parsing logic. Also, complete() and stream() duplicate manual SSE chunk parsing. Clean these up.","status":"open","priority":2,"issue_type":"task","owner":"90008@klbr.net","created_at":"2026-06-30T21:39:42Z","created_by":"dawn","updated_at":"2026-06-30T21:39:42Z","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/Cargo.lock b/Cargo.lock index ce69ed1..7be05d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1428,6 +1428,7 @@ dependencies = [ name = "klbr-ipc" version = "0.1.0" dependencies = [ + "klbr-core", "serde", "serde_json", ] diff --git a/klbr-core/src/memory.rs b/klbr-core/src/memory.rs index aa77651..4182ad7 100644 --- a/klbr-core/src/memory.rs +++ b/klbr-core/src/memory.rs @@ -13,7 +13,7 @@ const ANCHOR_SOURCE_REF: &str = "system:soul"; pub const EDGE_DERIVED_FROM: MemoryEdgeType = MemoryEdgeType::DerivedFrom; pub const EDGE_SUPERSEDES: MemoryEdgeType = MemoryEdgeType::Supersedes; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct HistoryEntry { pub id: i64, pub timestamp: i64, diff --git a/klbr-daemon/src/daemon.rs b/klbr-daemon/src/daemon.rs index 7ba52ac..c2d544d 100644 --- a/klbr-daemon/src/daemon.rs +++ b/klbr-daemon/src/daemon.rs @@ -11,10 +11,7 @@ use klbr_core::{ memory::MemoryStore, AgentEvent, MetricsSnapshot, }; -use klbr_ipc::{ - ClientMsg, CompactionRecord as IpcCompactionRecord, HistoryEntry as IpcHistoryEntry, ServerMsg, - ToolCall as IpcToolCall, ToolCallFunction as IpcToolCallFunction, -}; +use klbr_ipc::{ClientMsg, ServerMsg}; const HISTORY_PAGE: usize = 50; const WS_BIND_ADDR: &str = "127.0.0.1:8765"; @@ -90,7 +87,6 @@ async fn handle( // push current context window so tui starts with history let turns = memory.recent_turns(history_window).unwrap_or_default(); - let turns = turns.into_iter().map(map_history).collect(); send_msg(&mut ws_tx, &ServerMsg::History { turns }).await?; // send last known metrics so status bar is populated immediately @@ -153,7 +149,6 @@ async fn handle( ClientMsg::FetchHistory { before_id, limit } => { let limit = limit.min(HISTORY_PAGE); let turns = memory.turns_before(before_id, limit).unwrap_or_default(); - let turns = turns.into_iter().map(map_history).collect(); send_msg(&mut ws_tx, &ServerMsg::History { turns }).await?; } ClientMsg::Compact => { @@ -246,18 +241,7 @@ async fn handle( ClientMsg::FetchResolutionEvents { limit } => { match memory.get_resolution_events(limit) { Ok(events) => { - let dtos = events.into_iter().map(|ev| klbr_ipc::ResolutionEventDto { - event_id: ev.event_id, - turn_id: ev.turn_id, - created_at: ev.created_at, - input_ref_count: ev.input_ref_count, - candidate_ref_count: ev.candidate_ref_count, - injected_ref_count: ev.injected_ref_count, - omitted_ref_count: ev.omitted_ref_count, - total_token_estimate: ev.total_token_estimate, - trace_json: ev.trace_json, - }).collect(); - send_msg(&mut ws_tx, &ServerMsg::ResolutionEvents { events: dtos }).await?; + send_msg(&mut ws_tx, &ServerMsg::ResolutionEvents { events }).await?; } Err(e) => { send_msg( @@ -300,9 +284,7 @@ async fn handle( AgentEvent::CompactionThinkToken(content) => { ServerMsg::CompactionThinkToken { content } } - AgentEvent::CompactionRecord(record) => ServerMsg::CompactionRecord { - record: map_compaction_record(record), - }, + AgentEvent::CompactionRecord(record) => ServerMsg::CompactionRecord { record }, AgentEvent::DebugReflectRequest(content) => { ServerMsg::DebugReflectRequest { content } } @@ -323,9 +305,7 @@ async fn handle( generation_ms: m.generation_ms, bridge_processing_ms: m.bridge_processing_ms, }, - AgentEvent::UserTurn(entry) => ServerMsg::Turn { - entry: map_history(entry), - }, + AgentEvent::UserTurn(entry) => ServerMsg::Turn { entry }, AgentEvent::ExternalEvent { source, conversation_id, @@ -346,37 +326,3 @@ async fn handle( Ok(()) } - -fn map_history(e: klbr_core::memory::HistoryEntry) -> IpcHistoryEntry { - IpcHistoryEntry { - id: e.id, - timestamp: e.timestamp, - role: e.role, - content: e.content, - reasoning: e.reasoning, - tool_calls: e.tool_calls.map(|calls| { - calls - .into_iter() - .map(|call| IpcToolCall { - id: call.id, - kind: call.kind, - function: IpcToolCallFunction { - name: call.function.name, - arguments: call.function.arguments, - }, - }) - .collect() - }), - tool_call_id: e.tool_call_id, - } -} - -fn map_compaction_record(record: klbr_core::CompactionRecord) -> IpcCompactionRecord { - IpcCompactionRecord { - recollection: record.recollection, - compacted: record.compacted, - memory_id: record.memory_id, - drained_turns: record.drained_turns, - kept_turns: record.kept_turns, - } -} diff --git a/klbr-ipc/Cargo.toml b/klbr-ipc/Cargo.toml index 47a9161..e39cadd 100644 --- a/klbr-ipc/Cargo.toml +++ b/klbr-ipc/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +klbr-core = { path = "../klbr-core" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/klbr-ipc/src/lib.rs b/klbr-ipc/src/lib.rs index 879c8ec..62914d4 100644 --- a/klbr-ipc/src/lib.rs +++ b/klbr-ipc/src/lib.rs @@ -1,5 +1,11 @@ use serde::{Deserialize, Serialize}; +pub use klbr_core::{ + memory::{HistoryEntry, ResolutionEventData as ResolutionEventDto}, + models::{ToolCall, ToolCallFunction}, + CompactionRecord, +}; + /// client → daemon #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] @@ -40,44 +46,6 @@ pub enum ClientMsg { }, } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(rename_all = "snake_case")] -pub struct HistoryEntry { - pub id: i64, - pub timestamp: i64, - pub role: String, - pub content: String, - pub reasoning: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_calls: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_call_id: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ToolCallFunction { - pub name: String, - pub arguments: String, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ToolCall { - pub id: String, - #[serde(rename = "type")] - pub kind: String, - pub function: ToolCallFunction, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct CompactionRecord { - #[serde(alias = "summary")] - pub recollection: String, - pub compacted: String, - pub memory_id: i64, - pub drained_turns: usize, - pub kept_turns: usize, -} - /// daemon → client #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", rename_all = "snake_case")] @@ -170,19 +138,6 @@ pub enum ServerMsg { }, } -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ResolutionEventDto { - pub event_id: i64, - pub turn_id: Option, - pub created_at: i64, - pub input_ref_count: i64, - pub candidate_ref_count: i64, - pub injected_ref_count: i64, - pub omitted_ref_count: i64, - pub total_token_estimate: i64, - pub trace_json: String, -} - pub const DEFAULT_WS_URL: &str = "ws://127.0.0.1:8765"; pub fn ws_url() -> &'static str { -- 2.51.2