Skip to main content

gproxy_protocol/adapt/generate/stream/event/
claude.rs

1use super::*;
2use crate::{
3    transform::generate::stream::claude::{ClaudeStreamCollector, ClaudeStreamLimits},
4    wire::claude::{generate_content as c, stream as s},
5};
6
7impl sealed::Event for s::StreamEvent {}
8impl NativeEvent for s::StreamEvent {
9    type Full = c::GenerateContentResponseBody;
10    type Collector = ClaudeStreamCollector;
11    const DIALECT: Dialect = Dialect::Claude;
12    fn collector(_: IdentityFlow, _: TargetIdPolicy, limits: EventLimits) -> Self::Collector {
13        ClaudeStreamCollector::new(ClaudeStreamLimits {
14            max_json_bytes: limits.max_bytes,
15            max_text_bytes: limits.max_bytes,
16        })
17    }
18    fn collect(collector: &mut Self::Collector, event: Self) -> Result<(), TransformError> {
19        collector.push(event)
20    }
21    fn collected(
22        collector: Self::Collector,
23    ) -> Result<Converted<Collected<Self::Full>>, TransformError> {
24        let value = collector.finish()?;
25        Ok(Converted {
26            value: Collected::native(value.value),
27            report: value.report,
28        })
29    }
30    fn event_name(&self) -> Option<&'static str> {
31        Some(match self {
32            Self::MessageStart(_) => "message_start",
33            Self::ContentBlockStart(_) => "content_block_start",
34            Self::ContentBlockDelta(_) => "content_block_delta",
35            Self::ContentBlockStop(_) => "content_block_stop",
36            Self::MessageDelta(_) => "message_delta",
37            Self::MessageStop(_) => "message_stop",
38            Self::Ping(_) => "ping",
39            Self::Error(_) => "error",
40        })
41    }
42    fn is_terminal(&self) -> bool {
43        matches!(self, Self::MessageStop(_) | Self::Error(_))
44    }
45    fn tool_declarations(
46        &self,
47        _complete_tool_names: bool,
48    ) -> Vec<(String, ToolCallKind, Option<String>)> {
49        let blocks: Vec<&c::ResponseContentBlock> = match self {
50            Self::MessageStart(event) => event.message.content.iter().collect(),
51            // Native start blocks use the same declared content enum.
52            Self::ContentBlockStart(event) => {
53                return match &event.content_block {
54                    c::ResponseContentBlock::ToolUse(tool) => vec![(
55                        tool.id.clone(),
56                        ToolCallKind::Function,
57                        Some(tool.name.clone()),
58                    )],
59                    _ => Vec::new(),
60                };
61            }
62            _ => Vec::new(),
63        };
64        blocks
65            .into_iter()
66            .filter_map(|block| match block {
67                c::ResponseContentBlock::ToolUse(tool) => Some((
68                    tool.id.clone(),
69                    ToolCallKind::Function,
70                    Some(tool.name.clone()),
71                )),
72                _ => None,
73            })
74            .collect()
75    }
76}