Add the channel messages and the usage record to proto

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
2026-09-18 17:30:51 -07:00
parent e156975649
commit 06298d6a8e
13 changed files with 376 additions and 6 deletions
+3 -3
View File
@@ -15,8 +15,8 @@ pub use frame::{FrameError, MAX_FRAME, read_frame, write_frame};
pub use grant::{Constraints, Grant, Mode};
pub use hash::{HashError, Sha256, sha256};
pub use ids::{CallId, Epoch, Hash32, SessionId, Timestamp, ValueError};
pub use log::{LogRecord, ToolCall};
pub use log::{LogRecord, ToolCall, Usage};
pub use wire::{
DenyReason, Envelope, ErrorCode, Message, PROTOCOL_VERSION, ToolRequest, ToolResponse,
WireError,
DenyReason, Envelope, ErrorCode, Message, PROTOCOL_VERSION, ToolRequest, ToolResponse, Turn,
TurnDone, TurnEvent, WireError,
};
+19
View File
@@ -12,6 +12,17 @@ pub struct ToolCall {
pub arguments: String,
}
/// What one completion cost. The same five numbers as `LogRecord::Usage`, without the time.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Usage {
pub cache_n: u64,
pub prompt_n: u64,
pub predicted_n: u64,
pub reasoning_tokens: u64,
pub thinking_capped: bool,
}
// JSON: {"type":"user","time":"…","content":"…"} ; the tag sits beside the fields; types are snake_case
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
@@ -42,6 +53,14 @@ pub enum LogRecord {
untrusted: bool,
truncated: bool,
},
Usage {
time: Timestamp,
cache_n: u64,
prompt_n: u64,
predicted_n: u64,
reasoning_tokens: u64,
thinking_capped: bool,
},
CacheLoss {
time: Timestamp,
expected: u64,
+70 -1
View File
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::{CallId, DataClass, SessionId, Timestamp};
use crate::{CallId, DataClass, SessionId, Timestamp, Usage};
pub const PROTOCOL_VERSION: u32 = 1;
@@ -24,6 +24,9 @@ pub enum Message {
ToolRequest(ToolRequest),
ToolResponse(ToolResponse),
Error(WireError),
Turn(Turn),
TurnEvent(TurnEvent),
TurnDone(TurnDone),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -40,6 +43,12 @@ pub enum ErrorCode {
BadVersion,
BadMessage,
Internal,
SessionFull,
TurnLimit,
SessionBusy,
NoSuchSession,
SessionExists,
Inference,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -82,3 +91,63 @@ pub enum DenyReason {
ApprovalRefused,
ApprovalExpired,
}
// JSON: {"kind":"turn","body":{"session":"…","content":"…","resume":false}}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Turn {
pub session: SessionId,
pub content: String,
pub resume: bool,
}
// JSON: {"event":"content","text":"…"} — the tag sits beside the fields, snake_case
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "event", deny_unknown_fields, rename_all = "snake_case")]
pub enum TurnEvent {
Queued {
ahead: u64,
},
Waiting {
slot_busy: bool,
},
Progress {
total: u64,
cache: u64,
processed: u64,
},
Reasoning {
text: String,
},
Content {
text: String,
},
ToolCallStarted {
name: String,
},
ToolResult {
name: String,
class: DataClass,
truncated: bool,
},
ThinkingCapped {
tokens: u64,
},
Retrying {
attempt: u32,
after_ms: u64,
error: String,
},
CacheLoss {
expected: u64,
got: u64,
},
}
// JSON: {"kind":"turn_done","body":{"content":"…","usage":{…}}}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TurnDone {
pub content: String,
pub usage: Usage,
}