diff --git a/crates/colibri-daemon/src/daemon.rs b/crates/colibri-daemon/src/daemon.rs index 1ecb1f4..839fedf 100644 --- a/crates/colibri-daemon/src/daemon.rs +++ b/crates/colibri-daemon/src/daemon.rs @@ -268,7 +268,17 @@ pub async fn heartbeat(state: &SharedState, _stall_timeout: Duration) { cost: u.cost(), success: status.success(), }; - let store = state.store.lock().unwrap(); + let store = match state.store.try_lock() { + Ok(s) => s, + Err(std::sync::TryLockError::WouldBlock) => { + warn!(task_id = %task_id, "store lock busy; cost capture deferred to next heartbeat"); + continue; + } + Err(std::sync::TryLockError::Poisoned(e)) => { + warn!(task_id = %task_id, "store lock poisoned (prior panic); recovering inner store"); + e.into_inner() + } + }; match store.set_task_cost(task_id, &tc) { Ok(t) => info!( task_id = %task_id, diff --git a/crates/colibri-mcp/src/lib.rs b/crates/colibri-mcp/src/lib.rs index 5e6391a..0225b1c 100644 --- a/crates/colibri-mcp/src/lib.rs +++ b/crates/colibri-mcp/src/lib.rs @@ -146,8 +146,8 @@ pub fn tool_list() -> Vec { })), ), json_tool( - "colibri_get_task_cost", - "Get per-task cost summary: tokens used, cache hit ratio, cost, success status", + "colibri_get_task", + "Get task details including per-task cost: tokens used, cache hit ratio, cost_usd, success status", Some(serde_json::json!({ "type": "object", "properties": { @@ -289,7 +289,7 @@ pub async fn dispatch_tool( "note": "Cost mode change is runtime-only/status-intent until live config mutation exists." }))) } - "colibri_get_task_cost" => { + "colibri_get_task" => { let task_id = require_string(arguments, "task_id")?; let all_tasks = client.list_tasks(None).await.map_err(map_client_error)?; let task = all_tasks diff --git a/crates/colibri-mcp/tests/tool_dispatch.rs b/crates/colibri-mcp/tests/tool_dispatch.rs index 54d5dfa..f5119a4 100644 --- a/crates/colibri-mcp/tests/tool_dispatch.rs +++ b/crates/colibri-mcp/tests/tool_dispatch.rs @@ -252,6 +252,6 @@ fn tool_list_has_all_phase1_tools() { assert!(names.contains(&"colibri_external_mcp_servers")); assert!(names.contains(&"colibri_external_mcp_list_tools")); assert!(names.contains(&"colibri_external_mcp_call_tool")); - assert!(names.contains(&"colibri_get_task_cost")); + assert!(names.contains(&"colibri_get_task")); assert_eq!(names.len(), 11); } diff --git a/docs/wiki/contracts.md b/docs/wiki/contracts.md index 19bfd95..6e44226 100644 --- a/docs/wiki/contracts.md +++ b/docs/wiki/contracts.md @@ -19,7 +19,8 @@ between Colibri (Rust) and Clawdie agents (TypeScript). It owns _schemas and | -------------------------------------- | --------------------- | -------------------------------------------------------------- | | `clawdie.interagent.run-manifest.v1` | `RunManifest` | Records a build/test run — role, agent, artifacts, summary. | | `clawdie.runtime-version-inventory.v1` | `RuntimeInventory` | Host runtime snapshot — OS, package versions, npm/node/zot/pi. | -| `clawdie.provider-test.result.v1` | `ProviderSmokeResult` | DeepSeek cache-hit probe result and token accounting. | +| `clawdie.provider-test.result.v1` | `ProviderSmokeResult` | DeepSeek cache-hit probe result and token accounting. | +| `clawdie.task-cost-summary.v1` | `TaskCostSummary` | Per-task cost breakdown — input/output/cache tokens, cost_usd. | Schema constants and structs live in `crates/colibri-contracts/src/lib.rs`.