7777CLIMessageType = MessageType
7878
7979
80+ def _python_to_value (value : Any ) -> Any :
81+ """Convert Python value to protobuf Value."""
82+ from betterproto .lib .google .protobuf import ListValue , Value
83+
84+ if value is None :
85+ from betterproto .lib .google .protobuf import NullValue
86+
87+ return Value (null_value = NullValue .NULL_VALUE ) # type: ignore[arg-type]
88+ elif isinstance (value , bool ):
89+ return Value (bool_value = value )
90+ elif isinstance (value , (int , float )):
91+ return Value (number_value = float (value ))
92+ elif isinstance (value , str ):
93+ return Value (string_value = value )
94+ elif isinstance (value , dict ):
95+ from betterproto .lib .google .protobuf import Struct
96+
97+ struct = Struct ()
98+ struct .fields = {k : _python_to_value (v ) for k , v in value .items ()}
99+ return Value (struct_value = struct )
100+ elif isinstance (value , (list , tuple )):
101+ list_val = ListValue (values = [_python_to_value (item ) for item in value ])
102+ return Value (list_value = list_val )
103+ else :
104+ return Value (string_value = str (value ))
105+
106+
107+ def _dict_to_struct (data : dict [str , Any ]) -> Any :
108+ """Convert Python dict to protobuf Struct."""
109+ from betterproto .lib .google .protobuf import Struct
110+
111+ struct = Struct ()
112+ if data :
113+ struct .fields = {k : _python_to_value (v ) for k , v in data .items ()}
114+ return struct
115+
116+
80117@dataclass
81118class ConnectRequest :
82119 """Initial connection request from SDK to CLI.
@@ -102,11 +139,18 @@ class ConnectRequest:
102139
103140 def to_proto (self ) -> ProtoConnectRequest :
104141 """Convert to protobuf message."""
142+ from betterproto .lib .google .protobuf import Struct
143+
144+ # Convert metadata dict to protobuf Struct
145+ metadata_struct = Struct ()
146+ if self .metadata :
147+ metadata_struct .fields = {k : _python_to_value (v ) for k , v in self .metadata .items ()}
148+
105149 return ProtoConnectRequest (
106150 service_id = self .service_id ,
107151 sdk_version = self .sdk_version ,
108152 min_cli_version = self .min_cli_version ,
109- metadata = self . metadata ,
153+ metadata = metadata_struct ,
110154 )
111155
112156
@@ -129,10 +173,12 @@ class ConnectResponse:
129173 @classmethod
130174 def from_proto (cls , proto : ProtoConnectResponse ) -> ConnectResponse :
131175 """Create from protobuf message."""
176+ # Note: ProtoConnectResponse only has success and error fields
177+ # cli_version and session_id are SDK-only extensions not in the protobuf schema
132178 return cls (
133179 success = proto .success ,
134- cli_version = proto . cli_version or None ,
135- session_id = proto . session_id or None ,
180+ cli_version = None ,
181+ session_id = None ,
136182 error = proto .error or None ,
137183 )
138184
@@ -164,7 +210,7 @@ class GetMockRequest:
164210
165211 def to_proto (self ) -> ProtoGetMockRequest :
166212 """Convert to protobuf message."""
167- span = dict_to_span (self .outbound_span ) if self .outbound_span else None
213+ span = dict_to_span (self .outbound_span ) if self .outbound_span else ProtoSpan ()
168214 return ProtoGetMockRequest (
169215 request_id = self .request_id ,
170216 test_id = self .test_id ,
@@ -253,7 +299,8 @@ def dict_to_span(data: dict[str, Any]) -> ProtoSpan:
253299 message = status_data .get ("message" , "" ),
254300 )
255301 else :
256- status = ProtoSpanStatus (code = ProtoStatusCode .UNSET )
302+ # UNSET is not a valid StatusCode in the proto - use UNSPECIFIED (0)
303+ status = ProtoSpanStatus (code = ProtoStatusCode .UNSPECIFIED )
257304
258305 return ProtoSpan (
259306 trace_id = data .get ("trace_id" , data .get ("traceId" , "" )),
@@ -263,8 +310,8 @@ def dict_to_span(data: dict[str, Any]) -> ProtoSpan:
263310 package_name = data .get ("package_name" , data .get ("packageName" , "" )),
264311 instrumentation_name = data .get ("instrumentation_name" , data .get ("instrumentationName" , "" )),
265312 submodule_name = data .get ("submodule_name" , data .get ("submoduleName" , "" )),
266- input_value = data .get ("input_value" , data .get ("inputValue" , {})),
267- output_value = data .get ("output_value" , data .get ("outputValue" , {})),
313+ input_value = _dict_to_struct ( data .get ("input_value" , data .get ("inputValue" , {}) )),
314+ output_value = _dict_to_struct ( data .get ("output_value" , data .get ("outputValue" , {}) )),
268315 input_schema_hash = data .get ("input_schema_hash" , data .get ("inputSchemaHash" , "" )),
269316 output_schema_hash = data .get ("output_schema_hash" , data .get ("outputSchemaHash" , "" )),
270317 input_value_hash = data .get ("input_value_hash" , data .get ("inputValueHash" , "" )),
@@ -306,8 +353,8 @@ def span_to_proto(span: Any) -> ProtoSpan:
306353 package_name = span .package_name or "" ,
307354 instrumentation_name = span .instrumentation_name or "" ,
308355 submodule_name = span .submodule_name or "" ,
309- input_value = span .input_value or {},
310- output_value = span .output_value or {},
356+ input_value = _dict_to_struct ( span .input_value or {}) ,
357+ output_value = _dict_to_struct ( span .output_value or {}) ,
311358 input_schema_hash = span .input_schema_hash or "" ,
312359 output_schema_hash = span .output_schema_hash or "" ,
313360 input_value_hash = span .input_value_hash or "" ,
0 commit comments