sim_lib_openai_server/codec_openai/
mod.rs1use std::sync::Arc;
2
3use sim_codec::{
4 CodecDefaultDecode, CodecRuntime, Decoder, Encoder, Input, Output, ReadCx, codec_value,
5};
6use sim_kernel::{CodecId, DefaultFactory, Error, Factory, Linker, Result, Symbol, WriteCx};
7
8pub mod decode;
10pub mod encode;
12pub mod shapes;
14pub mod streaming;
16
17pub use decode::{decode_openai_request, decode_openai_response};
18pub use encode::{encode_openai_request, encode_openai_response, encode_openai_responses_response};
19pub use shapes::{ChatTranscript, OpenAiCodecOptions, OpenAiRequestOptions};
20pub use streaming::{
21 GatewayEventData, OpenAiSseSurface, StreamSink, encode_gateway_events_sse,
22 gateway_event_data_from_packet, gateway_event_data_kind, gateway_event_data_packets,
23};
24
25const OPENAI_CODEC_RUNTIME_ID: CodecId = CodecId(0);
26
27pub struct OpenAiCodec;
29
30impl Decoder for OpenAiCodec {
31 fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<sim_kernel::Expr> {
32 decode::decode_openai_request_for_codec(cx.codec, input)
33 }
34}
35
36impl Encoder for OpenAiCodec {
37 fn encode(&self, cx: &mut WriteCx<'_>, expr: &sim_kernel::Expr) -> Result<Output> {
38 encode::encode_openai_response_for_codec(cx.codec, expr).map(Output::Text)
39 }
40}
41
42pub fn openai_codec_symbol() -> Symbol {
44 Symbol::qualified("codec", "openai")
45}
46
47pub fn install_openai_codec(linker: &mut Linker<'_>) -> Result<()> {
50 let factory = DefaultFactory;
51 let expr_shape = linker
52 .registry()
53 .shape_by_symbol(&Symbol::qualified("codec", "ChatTranscript"))
54 .or_else(|| {
55 linker
56 .registry()
57 .shape_by_symbol(&Symbol::qualified("core", "Expr"))
58 })
59 .or_else(|| {
60 linker
61 .registry()
62 .shape_by_symbol(&Symbol::qualified("core", "Any"))
63 })
64 .cloned()
65 .unwrap_or(factory.nil()?);
66 let options_shape = linker
67 .registry()
68 .shape_by_symbol(&Symbol::qualified("codec", "OpenAiCodecOptions"))
69 .or_else(|| {
70 linker
71 .registry()
72 .shape_by_symbol(&Symbol::qualified("core", "EncodeOptions"))
73 })
74 .or_else(|| {
75 linker
76 .registry()
77 .shape_by_symbol(&Symbol::qualified("core", "Any"))
78 })
79 .cloned()
80 .unwrap_or(factory.nil()?);
81
82 let symbol = openai_codec_symbol();
83 linker.codec_value(
84 symbol.clone(),
85 codec_value(CodecRuntime {
86 id: OPENAI_CODEC_RUNTIME_ID,
87 symbol,
88 decoder: Some(Arc::new(OpenAiCodec)),
89 located_decoder: None,
90 tree_decoder: None,
91 encoder: Some(Arc::new(OpenAiCodec)),
92 located_encoder: None,
93 tree_encoder: None,
94 expr_shape,
95 options_shape,
96 default_decode: CodecDefaultDecode::Datum,
97 }),
98 )?;
99 Ok(())
100}
101
102pub(crate) fn input_text(codec: CodecId, input: Input) -> Result<String> {
103 match input {
104 Input::Text(text) => Ok(text),
105 Input::Bytes(bytes) => String::from_utf8(bytes).map_err(|err| codec_error(codec, err)),
106 }
107}
108
109pub(crate) fn codec_error(codec: CodecId, message: impl ToString) -> Error {
110 Error::CodecError {
111 codec,
112 message: message.to_string(),
113 }
114}