agent-sessions 0.2.1

Stream Claude Code and Codex JSONL sessions as typed Rust events with source offsets
Documentation
use crate::parser::{Parsed, required, string, text};
use crate::{Event, EventKinds, LineErrorKind, ToolArgs, ToolCall, ToolResult};
use serde_json::Value;

pub(super) fn parse(content: &Value, p: &mut Parsed) -> Result<(), LineErrorKind> {
    if content.is_string() {
        return Ok(());
    }
    let blocks = content
        .as_array()
        .ok_or(LineErrorKind::InvalidField("content".into()))?;
    for (index, b) in blocks.iter().enumerate() {
        match required(b, "type")? {
            "tool_use" | "server_tool_use" if p.wants(EventKinds::TOOL_CALL) => p.emit(
                3 + index,
                Event::ToolCall(ToolCall {
                    kind: if b["type"] == "server_tool_use" {
                        crate::ToolCallKind::Server
                    } else {
                        crate::ToolCallKind::Function
                    },
                    id: string(b, "id"),
                    name: required(b, "name")?.to_owned(),
                    arguments: b
                        .get("input")
                        .map_or(ToolArgs::Missing, |v| ToolArgs::Json(v.clone())),
                }),
            ),
            "tool_result" if p.wants(EventKinds::TOOL_RESULT) => {
                let content = b
                    .get("content")
                    .ok_or(LineErrorKind::MissingField("tool_result.content"))?;
                let body = text(content, p)?;
                p.emit(
                    3 + index,
                    Event::ToolResult(ToolResult {
                        call_id: string(b, "tool_use_id"),
                        is_error: b.get("is_error").and_then(Value::as_bool),
                        text: body,
                    }),
                );
            }
            _ => {}
        }
    }
    Ok(())
}