proto becomes bxcore, the one shared crate (M5b task 00)

Done the way the owner asked and the spike mapped: the crate and the
manifests renamed, then what the build reported fixed. Layers: 138
"proto unresolved" errors across 169 files; cargo fmt reordering
imports; six fixture paths built as strings in brokerd's and bxctl's
tests, which the compiler cannot see, and comments naming
crates/proto/; the crate-dependency check and its self-test. One more
the spike did not reach: a `\nproto =` key inside a printf format in
the self-test, which a word-boundary replacement skips because `n` and
`p` are both word characters.

make gate: gate: ok, 944 tests; no new entry in /tmp.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-26 01:48:38 -07:00
co-authored by Claude Opus 5.5
parent 727e027fcf
commit 2b3ae080b4
311 changed files with 426 additions and 410 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ publish.workspace = true
workspace = true
[dependencies]
proto.workspace = true
bxcore.workspace = true
serde.workspace = true
serde_json.workspace = true
toml.workspace = true
+1 -1
View File
@@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
use crate::config::Config;
use crate::llama::{ChatMessage, ToolSchema};
use crate::tools::Registry;
use proto::{Hash32, LogRecord, sha256};
use bxcore::{Hash32, LogRecord, sha256};
use serde::Deserialize;
use serde::Serialize;
+1 -1
View File
@@ -8,7 +8,7 @@ use std::path::PathBuf;
use std::time::{Duration, Instant};
use crate::tools::{Pending, ToolPort};
use proto::{
use bxcore::{
Envelope, FrameError, Message, PROTOCOL_VERSION, Timestamp, ToolRequest, ToolResponse,
read_frame, write_frame,
};
+1 -1
View File
@@ -14,7 +14,7 @@ use crate::memory::MemorySource;
use crate::session::{Session, SessionError};
use crate::tools::{Registry, ToolPort};
use crate::turn::{Runtime, TurnError, run_turn};
use proto::{
use bxcore::{
Envelope, ErrorCode, FrameError, Message, PROTOCOL_VERSION, SessionId, TurnDone, WireError,
read_frame, write_frame,
};
+1 -1
View File
@@ -23,7 +23,7 @@ pub struct Slots {
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Expect {
pub template_sha256: proto::Hash32,
pub template_sha256: bxcore::Hash32,
pub n_ctx: u64,
pub slots: u32,
}
+1 -1
View File
@@ -201,7 +201,7 @@ impl Assembler {
));
}
};
tool_calls.push(proto::ToolCall {
tool_calls.push(bxcore::ToolCall {
id,
name,
arguments: call.arguments,
+2 -2
View File
@@ -18,7 +18,7 @@ pub enum ChatMessage {
Assistant {
content: Option<String>,
reasoning_content: Option<String>,
tool_calls: Vec<proto::ToolCall>,
tool_calls: Vec<bxcore::ToolCall>,
},
Tool {
tool_call_id: String,
@@ -93,7 +93,7 @@ pub struct Completion {
pub id: String,
pub content: Option<String>,
pub reasoning_content: Option<String>,
pub tool_calls: Vec<proto::ToolCall>,
pub tool_calls: Vec<bxcore::ToolCall>,
pub finish_reason: FinishReason,
pub timings: Timings,
pub reasoning_tokens: u64,
+1 -1
View File
@@ -73,7 +73,7 @@ fn serialize_message(message: &ChatMessage) -> Result<serde_json::Value, serde_j
}
}
fn serialized_call(call: &proto::ToolCall) -> SerializedToolCall {
fn serialized_call(call: &bxcore::ToolCall) -> SerializedToolCall {
SerializedToolCall {
id: call.id.clone(),
kind: "function",
+1 -1
View File
@@ -6,7 +6,7 @@ use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::time::Duration;
use proto::{
use bxcore::{
Empty, Envelope, Message, PROTOCOL_VERSION, SessionId, SessionUpdated, read_frame, write_frame,
};
+1 -1
View File
@@ -75,7 +75,7 @@ fn server_matches(client: &Client) -> Result<(), SelfTestError> {
let expect = &client.config().expect;
let expected = expect.template_sha256;
let got = proto::sha256(props.chat_template.as_bytes()).map_err(|_| SelfTestError::Hash)?;
let got = bxcore::sha256(props.chat_template.as_bytes()).map_err(|_| SelfTestError::Hash)?;
if expected != got {
return Err(SelfTestError::Mismatch {
what: "chat template sha256",
+3 -3
View File
@@ -6,7 +6,7 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use crate::baseline::{Baseline, BaselineError};
use proto::{CallId, Epoch, LogRecord, SessionId, Timestamp};
use bxcore::{CallId, Epoch, LogRecord, SessionId, Timestamp};
/// Creating, opening, appending and resuming a session, and the errors each can raise.
#[derive(Debug)]
@@ -193,7 +193,7 @@ impl Session {
id
}
pub fn last_usage(&self) -> Option<proto::Usage> {
pub fn last_usage(&self) -> Option<bxcore::Usage> {
for record in self.records.iter().rev() {
if let LogRecord::Usage {
cache_n,
@@ -204,7 +204,7 @@ impl Session {
..
} = record
{
return Some(proto::Usage {
return Some(bxcore::Usage {
cache_n: *cache_n,
prompt_n: *prompt_n,
predicted_n: *predicted_n,
+27 -25
View File
@@ -11,16 +11,16 @@ pub trait ToolPort: Send + Sync {
/// for the owner, the port calls `on_pending` once and goes on waiting.
fn call(
&self,
request: &proto::ToolRequest,
request: &bxcore::ToolRequest,
on_pending: &mut dyn FnMut(&Pending),
) -> proto::ToolResponse;
) -> bxcore::ToolResponse;
}
/// One waiting call, as the broker reports it.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pending {
pub approval: u64,
pub expires: proto::Timestamp,
pub expires: bxcore::Timestamp,
}
#[derive(Debug, Clone, PartialEq)]
@@ -281,7 +281,7 @@ pub fn dispatch(registry: &Registry, name: &str, arguments: &str) -> Dispatch {
return dispatch_call_tool(registry, arguments);
}
if name == CLOCK {
return Dispatch::Local(proto::Timestamp::now().to_rfc3339());
return Dispatch::Local(bxcore::Timestamp::now().to_rfc3339());
}
Dispatch::Port {
tool: name.to_string(),
@@ -351,33 +351,35 @@ pub fn cap_result(text: &str, cap: usize) -> (String, bool) {
}
/// The one fixed sentence a denial reaches the model as, named by its reason.
pub fn denial_text(reason: proto::DenyReason) -> &'static str {
pub fn denial_text(reason: bxcore::DenyReason) -> &'static str {
match reason {
proto::DenyReason::NoGrant => "Denied: no grant allows this call.",
proto::DenyReason::GrantExpired => "Denied: the grant for this call has expired.",
proto::DenyReason::TaintTooHigh => {
bxcore::DenyReason::NoGrant => "Denied: no grant allows this call.",
bxcore::DenyReason::GrantExpired => "Denied: the grant for this call has expired.",
bxcore::DenyReason::TaintTooHigh => {
"Denied: this session has seen data too sensitive for this call."
}
proto::DenyReason::DeniedByGrant => "Denied: a grant forbids this call.",
proto::DenyReason::ApprovalRefused => "Denied: the owner refused this call.",
proto::DenyReason::ApprovalExpired => {
bxcore::DenyReason::DeniedByGrant => "Denied: a grant forbids this call.",
bxcore::DenyReason::ApprovalRefused => "Denied: the owner refused this call.",
bxcore::DenyReason::ApprovalExpired => {
"Denied: the approval request expired without an answer."
}
proto::DenyReason::InvalidArguments => "Denied: the arguments are not valid for this tool.",
proto::DenyReason::GrantsInvalid => {
bxcore::DenyReason::InvalidArguments => {
"Denied: the arguments are not valid for this tool."
}
bxcore::DenyReason::GrantsInvalid => {
"Denied: the grant files have an error; the owner has been told."
}
proto::DenyReason::AuditUnavailable => {
bxcore::DenyReason::AuditUnavailable => {
"Denied: the audit log cannot be written; the owner has been told."
}
proto::DenyReason::StateUnreadable => {
bxcore::DenyReason::StateUnreadable => {
"Denied: this session's broker state is damaged; the owner has been told."
}
}
}
pub struct FakeTools {
calls: Mutex<Vec<proto::ToolRequest>>,
calls: Mutex<Vec<bxcore::ToolRequest>>,
}
impl Default for FakeTools {
@@ -393,7 +395,7 @@ impl FakeTools {
}
}
pub fn calls(&self) -> Vec<proto::ToolRequest> {
pub fn calls(&self) -> Vec<bxcore::ToolRequest> {
self.calls.lock().unwrap_or_else(|p| p.into_inner()).clone()
}
}
@@ -401,9 +403,9 @@ impl FakeTools {
impl ToolPort for FakeTools {
fn call(
&self,
request: &proto::ToolRequest,
request: &bxcore::ToolRequest,
_on_pending: &mut dyn FnMut(&Pending),
) -> proto::ToolResponse {
) -> bxcore::ToolResponse {
self.calls
.lock()
.unwrap_or_else(|p| p.into_inner())
@@ -413,23 +415,23 @@ impl ToolPort for FakeTools {
"echo" => match serde_json::from_str::<serde_json::Value>(&request.arguments) {
Ok(serde_json::Value::Object(obj)) => {
match obj.get("text").and_then(|v| v.as_str()) {
Some(text) => proto::ToolResponse::Result {
Some(text) => bxcore::ToolResponse::Result {
content: text.to_string(),
class: proto::DataClass::Public,
class: bxcore::DataClass::Public,
untrusted: false,
truncated: false,
},
None => proto::ToolResponse::Failed {
None => bxcore::ToolResponse::Failed {
message: "missing text argument".to_string(),
},
}
}
_ => proto::ToolResponse::Failed {
_ => bxcore::ToolResponse::Failed {
message: "arguments must be a JSON object".to_string(),
},
},
_ => proto::ToolResponse::Denied {
reason: proto::DenyReason::NoGrant,
_ => bxcore::ToolResponse::Denied {
reason: bxcore::DenyReason::NoGrant,
},
}
}
+4 -2
View File
@@ -8,7 +8,9 @@ use crate::llama::info::{CacheOutcome, cache_outcome};
use crate::llama::{ChatEvent, ChatRequest, Client, InferError};
use crate::session::{Session, SessionError};
use crate::tools::{Registry, ToolPort, cap_result, denial_text, dispatch};
use proto::{CallId, DataClass, LogRecord, Timestamp, ToolRequest, ToolResponse, TurnEvent, Usage};
use bxcore::{
CallId, DataClass, LogRecord, Timestamp, ToolRequest, ToolResponse, TurnEvent, Usage,
};
/// What one turn can fail with, beyond the inference server.
#[derive(Debug)]
@@ -258,7 +260,7 @@ pub fn run_turn(
fn run_call(
rt: &Runtime<'_>,
session: &Session,
call: &proto::ToolCall,
call: &bxcore::ToolCall,
call_id: CallId,
on_event: &mut dyn FnMut(&TurnEvent),
) -> (String, DataClass, bool) {
+2 -2
View File
@@ -2,10 +2,10 @@
mod support;
use bxcore::{CallId, DataClass, Epoch, Hash32, LogRecord, SessionId, Timestamp, ToolCall};
use loopd::baseline::{Baseline, messages};
use loopd::llama::ChatMessage;
use loopd::tools::Registry;
use proto::{CallId, DataClass, Epoch, Hash32, LogRecord, SessionId, Timestamp, ToolCall};
use std::path::Path;
use support::Home;
@@ -67,7 +67,7 @@ fn json_round_trip_and_hash() {
assert_eq!(Baseline::from_json(&text).unwrap(), b);
assert_eq!(
b.hash().unwrap(),
proto::sha256(text.as_bytes()).unwrap(),
bxcore::sha256(text.as_bytes()).unwrap(),
"the hash is of the JSON as written"
);
assert_ne!(b.hash().unwrap(), Hash32::ZERO);
+4 -4
View File
@@ -9,12 +9,12 @@ use std::os::unix::net::UnixListener;
use std::thread;
use std::time::Duration;
use bxcore::{
DenyReason, Message, PROTOCOL_VERSION, Timestamp, ToolResponse, read_frame, write_frame,
};
use fake::{assert_unavailable, broker, call, frame, in_ms, request, result, send, socket_path};
use loopd::broker_port::{BrokerPort, NoBroker, POINTER, TOO_LARGE};
use loopd::tools::{Pending, ToolPort};
use proto::{
DenyReason, Message, PROTOCOL_VERSION, Timestamp, ToolResponse, read_frame, write_frame,
};
#[test]
fn a_result_comes_back_as_it_was_sent() {
@@ -259,7 +259,7 @@ fn a_request_too_large_for_a_frame_is_its_own_failure() {
let _ = std::fs::remove_file(&path);
let _listener = UnixListener::bind(&path).unwrap();
let mut big = request();
big.arguments = format!(r#"{{"path":"/{}"}}"#, "a".repeat(proto::MAX_FRAME));
big.arguments = format!(r#"{{"path":"/{}"}}"#, "a".repeat(bxcore::MAX_FRAME));
let got = call(path.to_path_buf(), 1_000, &big);
assert_eq!(
got.response,
+3 -1
View File
@@ -9,8 +9,10 @@ use std::os::unix::net::UnixStream;
use std::thread;
use std::time::Duration;
use bxcore::{
Envelope, ErrorCode, Message, PROTOCOL_VERSION, ToolResponse, WireError, write_frame,
};
use fake::{assert_unavailable, broker, call, frame, in_ms, request, result, send};
use proto::{Envelope, ErrorCode, Message, PROTOCOL_VERSION, ToolResponse, WireError, write_frame};
#[test]
fn frames_that_break_the_protocol_are_unavailable() {
+1 -1
View File
@@ -9,10 +9,10 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use bxcore::{Timestamp, ToolResponse};
use fake::{broker, request, send};
use loopd::broker_port::{BrokerPort, MAX_PENDING_WAIT, UNAVAILABLE};
use loopd::tools::ToolPort;
use proto::{Timestamp, ToolResponse};
#[test]
fn the_default_cap_is_a_day() {
+11 -11
View File
@@ -5,14 +5,14 @@
mod support;
use bxcore::{
Envelope, ErrorCode, Message, PROTOCOL_VERSION, SessionId, Turn, TurnEvent, read_frame,
write_frame,
};
use loopd::channel::{Context, serve};
use loopd::llama::Client;
use loopd::memory::NoMemory;
use loopd::tools::Registry;
use proto::{
Envelope, ErrorCode, Message, PROTOCOL_VERSION, SessionId, Turn, TurnEvent, read_frame,
write_frame,
};
use std::os::unix::net::{UnixListener, UnixStream};
use std::path::PathBuf;
use std::sync::Arc;
@@ -30,7 +30,7 @@ struct Loopd {
home: Home,
}
fn start(replies: Vec<proto::ToolResponse>) -> Loopd {
fn start(replies: Vec<bxcore::ToolResponse>) -> Loopd {
let home = Home::new();
let server = FakeServer::start();
let cfg = home.config(&server.socket);
@@ -177,7 +177,7 @@ fn tool_calls_are_reported_by_name_only() {
tool_events[1],
&TurnEvent::ToolResult {
name: "read_file".to_string(),
class: proto::DataClass::Private,
class: bxcore::DataClass::Private,
truncated: false
}
);
@@ -292,7 +292,7 @@ fn bad_frames_get_an_error_and_a_close() {
stream
.set_read_timeout(Some(Duration::from_secs(5)))
.unwrap();
let msg = Message::Error(proto::WireError {
let msg = Message::Error(bxcore::WireError {
code: ErrorCode::Internal,
detail: String::new(),
});
@@ -311,7 +311,7 @@ fn bad_frames_get_an_error_and_a_close() {
assert!(
matches!(
reply.msg,
Message::Error(proto::WireError {
Message::Error(bxcore::WireError {
code: ErrorCode::BadMessage,
..
})
@@ -319,7 +319,7 @@ fn bad_frames_get_an_error_and_a_close() {
"{reply:?}"
);
assert!(
matches!(read_frame(&mut stream), Err(proto::FrameError::Closed)),
matches!(read_frame(&mut stream), Err(bxcore::FrameError::Closed)),
"then the connection is closed"
);
@@ -333,7 +333,7 @@ fn bad_frames_get_an_error_and_a_close() {
assert!(
matches!(
reply.msg,
Message::Error(proto::WireError {
Message::Error(bxcore::WireError {
code: ErrorCode::BadMessage,
..
})
@@ -365,7 +365,7 @@ fn bad_frames_get_an_error_and_a_close() {
assert!(
matches!(
reply.msg,
Message::Error(proto::WireError {
Message::Error(bxcore::WireError {
code: ErrorCode::BadVersion,
..
})
+7 -7
View File
@@ -339,7 +339,7 @@ impl Served {
.to_string()
}
fn records(&self, session: &str) -> Vec<proto::LogRecord> {
fn records(&self, session: &str) -> Vec<bxcore::LogRecord> {
let text =
std::fs::read_to_string(self.home.join("sessions").join(session).join("0.jsonl"))
.unwrap();
@@ -441,7 +441,7 @@ fn a_conversation_uses_tools_survives_a_restart_and_keeps_its_cache() {
let tool_names: Vec<String> = records
.iter()
.filter_map(|r| match r {
proto::LogRecord::Assistant { tool_calls, .. } => Some(
bxcore::LogRecord::Assistant { tool_calls, .. } => Some(
tool_calls
.iter()
.map(|c| c.name.clone())
@@ -459,16 +459,16 @@ fn a_conversation_uses_tools_survives_a_restart_and_keeps_its_cache() {
);
let usages = records
.iter()
.filter(|r| matches!(r, proto::LogRecord::Usage { .. }))
.filter(|r| matches!(r, bxcore::LogRecord::Usage { .. }))
.count();
let assistants = records
.iter()
.filter(|r| matches!(r, proto::LogRecord::Assistant { .. }))
.filter(|r| matches!(r, bxcore::LogRecord::Assistant { .. }))
.count();
assert_eq!(usages, assistants, "one usage record per completion");
let losses: Vec<&proto::LogRecord> = records
let losses: Vec<&bxcore::LogRecord> = records
.iter()
.filter(|r| matches!(r, proto::LogRecord::CacheLoss { .. }))
.filter(|r| matches!(r, bxcore::LogRecord::CacheLoss { .. }))
.collect();
assert!(
losses.is_empty(),
@@ -476,7 +476,7 @@ fn a_conversation_uses_tools_survives_a_restart_and_keeps_its_cache() {
);
let results = records
.iter()
.filter(|r| matches!(r, proto::LogRecord::ToolResult { .. }))
.filter(|r| matches!(r, bxcore::LogRecord::ToolResult { .. }))
.count();
assert!(
results >= 3,
+3 -3
View File
@@ -12,15 +12,15 @@ use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};
use std::time::{Duration, Instant};
use bxcore::{
AuditEvent, AuditRecord, ChainVerifier, DecisionRecord, DenyReason, SessionId, TurnEvent,
};
use loopd::baseline::Baseline;
use loopd::broker_port::BrokerPort;
use loopd::llama::Client;
use loopd::session::Session;
use loopd::tools::Registry;
use loopd::turn::{Runtime, run_turn};
use proto::{
AuditEvent, AuditRecord, ChainVerifier, DecisionRecord, DenyReason, SessionId, TurnEvent,
};
use support::{FakeServer, Home, Reply};
const CHAT: &str = "/v1/chat/completions";
+1 -1
View File
@@ -56,7 +56,7 @@ fn reads_a_recorded_chunked_response() {
// The hash recorded in docs/inference-contract.md. If the de-chunking were off by a byte,
// this would not match.
assert_eq!(
proto::sha256(template.as_bytes()).unwrap().to_hex(),
bxcore::sha256(template.as_bytes()).unwrap().to_hex(),
"f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
);
}
+1 -1
View File
@@ -30,7 +30,7 @@ fn props_slots_and_tokenize_read_the_recorded_responses() {
assert_eq!(props.n_ctx, 131_072);
assert_eq!(props.total_slots, 2);
assert_eq!(
proto::sha256(props.chat_template.as_bytes())
bxcore::sha256(props.chat_template.as_bytes())
.unwrap()
.to_hex(),
"f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
+1 -1
View File
@@ -5,9 +5,9 @@ mod support;
#[path = "support/turn.rs"]
mod turn_support;
use bxcore::{LogRecord, SessionId, TurnEvent};
use loopd::session::Session;
use loopd::turn::TurnError;
use proto::{LogRecord, SessionId, TurnEvent};
use support::{Reply, ScriptedPort, ok_result};
use turn_support::{setup, types, without_cache_loss};
+3 -3
View File
@@ -9,13 +9,13 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use bxcore::{
Envelope, ErrorCode, Message, PROTOCOL_VERSION, SessionId, Turn, read_frame, write_frame,
};
use loopd::channel::{Context, serve};
use loopd::llama::Client;
use loopd::memory::{MemorySource, UNAVAILABLE};
use loopd::tools::Registry;
use proto::{
Envelope, ErrorCode, Message, PROTOCOL_VERSION, SessionId, Turn, read_frame, write_frame,
};
use support::{FakeServer, Home, Reply, ScriptedPort};
const CHAT: &str = "/v1/chat/completions";
+6 -6
View File
@@ -8,12 +8,12 @@ use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::time::Duration;
use bxcore::SessionId;
use loopd::baseline::Baseline;
use loopd::broker_port::{not_configured_line, unavailable_line};
use loopd::memory::{MemoryPort, MemorySource};
use loopd::session::{Session, SessionError};
use loopd::tools::Registry;
use proto::SessionId;
use support::{FakeServer, Home, Reply};
// `want` is the whole pointer, written out: scripts/check-runbook.sh reads the anchors of every
@@ -78,17 +78,17 @@ fn memoryd_unreachable_or_refusing_names_the_memory_entry() {
let listener = std::os::unix::net::UnixListener::bind(&socket).unwrap();
std::thread::spawn(move || {
let (mut stream, _) = listener.accept().unwrap();
let env = proto::read_frame(&mut stream).unwrap();
let reply = proto::Envelope {
let env = bxcore::read_frame(&mut stream).unwrap();
let reply = bxcore::Envelope {
v: 1,
id: env.id,
r#final: true,
msg: proto::Message::Error(proto::WireError {
code: proto::ErrorCode::Internal,
msg: bxcore::Message::Error(bxcore::WireError {
code: bxcore::ErrorCode::Internal,
detail: "memory/user.md: 1,376 characters; its limit is 1,375".to_string(),
}),
};
proto::write_frame(&mut stream, &reply).unwrap();
bxcore::write_frame(&mut stream, &reply).unwrap();
});
let message = MemoryPort::new(socket, Duration::from_secs(5))
.block()
+1 -1
View File
@@ -83,7 +83,7 @@ fn thinking_off_and_tools() {
/// here on purpose: they are rendered differently.
#[test]
fn every_kind_of_message() {
let call = proto::ToolCall {
let call = bxcore::ToolCall {
id: "call_1".to_string(),
name: "read_file".to_string(),
arguments: r#"{"path":"/etc/hostname"}"#.to_string(),
+2 -2
View File
@@ -84,10 +84,10 @@ fn the_main_slot_comes_from_the_config() {
#[test]
fn each_expected_value_is_checked() {
let zero = proto::Hash32::ZERO;
let zero = bxcore::Hash32::ZERO;
let cases: [(&str, Edit); 3] = [
("chat template sha256", |c| {
c.expect.template_sha256 = proto::Hash32::ZERO
c.expect.template_sha256 = bxcore::Hash32::ZERO
}),
("context per slot", |c| c.expect.n_ctx = 4096),
("slot count", |c| c.expect.slots = 3),
+1 -1
View File
@@ -2,9 +2,9 @@
mod support;
use bxcore::{CallId, DataClass, Epoch, LogRecord, SessionId, Timestamp};
use loopd::baseline::Baseline;
use loopd::session::{Session, SessionError};
use proto::{CallId, DataClass, Epoch, LogRecord, SessionId, Timestamp};
use support::Home;
fn baseline() -> Baseline {
+3 -3
View File
@@ -12,12 +12,12 @@ use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::{Duration, Instant};
use loopd::broker_port::{BrokerPort, UNAVAILABLE};
use loopd::tools::{Pending, ToolPort};
use proto::{
use bxcore::{
CallId, DataClass, Envelope, Message, PROTOCOL_VERSION, SessionId, Timestamp, ToolRequest,
ToolResponse, read_frame, write_frame,
};
use loopd::broker_port::{BrokerPort, UNAVAILABLE};
use loopd::tools::{Pending, ToolPort};
static NEXT: AtomicU32 = AtomicU32::new(0);
+16 -16
View File
@@ -94,7 +94,7 @@ impl Home {
}
/// The records of a session's log, epoch 0.
pub fn records(&self, session: &str) -> Vec<proto::LogRecord> {
pub fn records(&self, session: &str) -> Vec<bxcore::LogRecord> {
let text = self.read(&format!("sessions/{session}/0.jsonl"));
text.lines()
.map(|l| serde_json::from_str(l).unwrap())
@@ -104,37 +104,37 @@ impl Home {
/// A tool port that answers from a script and records what it was asked.
pub struct ScriptedPort {
replies: Mutex<VecDeque<proto::ToolResponse>>,
calls: Mutex<Vec<proto::ToolRequest>>,
replies: Mutex<VecDeque<bxcore::ToolResponse>>,
calls: Mutex<Vec<bxcore::ToolRequest>>,
}
impl ScriptedPort {
/// Replies are given in order; when they run out, every call gets `fallback`.
pub fn new(replies: Vec<proto::ToolResponse>) -> ScriptedPort {
pub fn new(replies: Vec<bxcore::ToolResponse>) -> ScriptedPort {
ScriptedPort {
replies: Mutex::new(replies.into()),
calls: Mutex::new(Vec::new()),
}
}
pub fn calls(&self) -> Vec<proto::ToolRequest> {
pub fn calls(&self) -> Vec<bxcore::ToolRequest> {
self.calls.lock().unwrap().clone()
}
}
pub fn ok_result(content: &str) -> proto::ToolResponse {
proto::ToolResponse::Result {
pub fn ok_result(content: &str) -> bxcore::ToolResponse {
bxcore::ToolResponse::Result {
content: content.to_string(),
class: proto::DataClass::Private,
class: bxcore::DataClass::Private,
untrusted: true,
truncated: false,
}
}
pub fn pending(approval: u64, expires: &str) -> proto::ToolResponse {
proto::ToolResponse::PendingApproval {
pub fn pending(approval: u64, expires: &str) -> bxcore::ToolResponse {
bxcore::ToolResponse::PendingApproval {
approval,
expires: proto::Timestamp::parse(expires).unwrap(),
expires: bxcore::Timestamp::parse(expires).unwrap(),
}
}
@@ -144,13 +144,13 @@ impl loopd::tools::ToolPort for ScriptedPort {
/// `ReturnsPendingPort` for a port that breaks the rule and returns one.
fn call(
&self,
request: &proto::ToolRequest,
request: &bxcore::ToolRequest,
on_pending: &mut dyn FnMut(&loopd::tools::Pending),
) -> proto::ToolResponse {
) -> bxcore::ToolResponse {
self.calls.lock().unwrap().push(request.clone());
let mut replies = self.replies.lock().unwrap();
let mut reply = replies.pop_front();
if let Some(proto::ToolResponse::PendingApproval { approval, expires }) = reply {
if let Some(bxcore::ToolResponse::PendingApproval { approval, expires }) = reply {
on_pending(&loopd::tools::Pending { approval, expires });
reply = replies.pop_front();
}
@@ -164,9 +164,9 @@ pub struct ReturnsPendingPort;
impl loopd::tools::ToolPort for ReturnsPendingPort {
fn call(
&self,
_request: &proto::ToolRequest,
_request: &bxcore::ToolRequest,
_on_pending: &mut dyn FnMut(&loopd::tools::Pending),
) -> proto::ToolResponse {
) -> bxcore::ToolResponse {
pending(1, "2026-09-18T12:00:00.000Z")
}
}
+1 -1
View File
@@ -5,12 +5,12 @@
#![allow(dead_code)]
use crate::support::{FakeServer, Home, ScriptedPort};
use bxcore::{LogRecord, SessionId, ToolResponse, TurnEvent};
use loopd::baseline::Baseline;
use loopd::llama::Client;
use loopd::session::Session;
use loopd::tools::Registry;
use loopd::turn::{Runtime, TurnError, run_turn};
use proto::{LogRecord, SessionId, ToolResponse, TurnEvent};
pub struct Setup {
pub home: Home,
+4 -4
View File
@@ -3,10 +3,10 @@
mod support;
use bxcore::{CallId, DenyReason, SessionId, ToolRequest, ToolResponse};
use loopd::tools::{
Dispatch, FakeTools, Pending, Registry, ToolPort, cap_result, denial_text, dispatch,
};
use proto::{CallId, DenyReason, SessionId, ToolRequest, ToolResponse};
fn req(tool: &str, arguments: &str) -> ToolRequest {
ToolRequest {
@@ -125,10 +125,10 @@ fn any_other_tool_goes_to_the_port_as_it_is() {
fn the_clock_is_answered_locally_whatever_its_arguments() {
for registry in [Registry::m2b(), Registry::m3a(), Registry::new(vec![])] {
for arguments in ["{}", r#"{"zone":"UTC"}"#, "not json", ""] {
let before = proto::Timestamp::now();
let before = bxcore::Timestamp::now();
match dispatch(&registry, "clock", arguments) {
Dispatch::Local(text) => {
let time = proto::Timestamp::parse(&text)
let time = bxcore::Timestamp::parse(&text)
.unwrap_or_else(|e| panic!("an RFC 3339 time, got {text:?}: {e:?}"));
assert!(time >= before, "{text}");
assert!(text.ends_with('Z'), "UTC: {text}");
@@ -283,7 +283,7 @@ fn fake_tools_answer_echo_deny_the_rest_and_record_calls() {
truncated,
} => {
assert_eq!(content, "box");
assert_eq!(class, proto::DataClass::Public);
assert_eq!(class, bxcore::DataClass::Public);
assert!(!untrusted && !truncated);
}
other => panic!("{other:?}"),
+3 -3
View File
@@ -6,8 +6,8 @@ mod support;
#[path = "support/turn.rs"]
mod turn_support;
use bxcore::{DataClass, LogRecord, SessionId, ToolResponse, TurnEvent};
use loopd::tools::Registry;
use proto::{DataClass, LogRecord, SessionId, ToolResponse, TurnEvent};
use support::{Reply, ok_result};
use turn_support::{setup, types};
@@ -102,7 +102,7 @@ fn a_tool_turn_goes_through_the_port_and_records_everything() {
"arguments are passed on unparsed"
);
assert_eq!(calls[0].session, SessionId::new("a").unwrap());
assert_eq!(calls[0].call, proto::CallId(1));
assert_eq!(calls[0].call, bxcore::CallId(1));
match &session.records()[4] {
LogRecord::ToolResult {
@@ -114,7 +114,7 @@ fn a_tool_turn_goes_through_the_port_and_records_everything() {
truncated,
..
} => {
assert_eq!(*call, proto::CallId(1));
assert_eq!(*call, bxcore::CallId(1));
assert_eq!(
tool_call_id, "wgE8iFI58Zni4WCTiCMNp4TzCcM8ou7F",
"the server's id, so the template can pair it"
+1 -1
View File
@@ -5,7 +5,7 @@ mod support;
#[path = "support/turn.rs"]
mod turn_support;
use proto::{DataClass, DenyReason, LogRecord, Timestamp, ToolResponse, TurnEvent};
use bxcore::{DataClass, DenyReason, LogRecord, Timestamp, ToolResponse, TurnEvent};
use support::{Reply, ReturnsPendingPort, ok_result, pending};
use turn_support::{setup, types};