tiny_agent_rs/types/
response.rs1use std::any::{type_name, TypeId};
2
3use serde_json::Value;
4
5use crate::{
6 error::{AgentError, Result},
7 schemas::{CompletionSchema, SchemaHandle},
8};
9
10#[derive(Clone, Debug)]
11pub struct StructuredPayload {
12 schema: SchemaHandle,
13 value: Value,
14}
15
16impl StructuredPayload {
17 pub fn new(schema: SchemaHandle, value: Value) -> Self {
18 Self { schema, value }
19 }
20
21 pub fn schema(&self) -> &SchemaHandle {
22 &self.schema
23 }
24
25 pub fn value(&self) -> &Value {
26 &self.value
27 }
28
29 pub fn into_inner(self) -> (SchemaHandle, Value) {
30 (self.schema, self.value)
31 }
32
33 pub fn deserialize<T>(&self) -> Result<T>
34 where
35 T: CompletionSchema,
36 {
37 deserialize_structured_response::<T>(&self.value, &self.schema)
38 }
39}
40
41pub fn deserialize_structured_response<T>(payload: &Value, schema: &SchemaHandle) -> Result<T>
42where
43 T: CompletionSchema,
44{
45 ensure_schema_matches::<T>(schema)?;
46
47 let raw = payload.to_string();
48 let mut deserializer = serde_json::Deserializer::from_str(&raw);
49 let value = serde_path_to_error::deserialize(&mut deserializer).map_err(|err| {
50 let path = err.path().to_string();
51 let location = if path.is_empty() {
52 "<root>".to_string()
53 } else {
54 path
55 };
56 AgentError::Validation(format!(
57 "failed to deserialize `{}` at {}: {}",
58 schema.schema_name(),
59 location,
60 err
61 ))
62 })?;
63
64 Ok(value)
65}
66
67fn ensure_schema_matches<T: 'static>(schema: &SchemaHandle) -> Result<()> {
68 let expected = TypeId::of::<T>();
69 if schema.type_id() != expected {
70 return Err(AgentError::Validation(format!(
71 "schema `{}` does not match target type `{}`",
72 schema.schema_name(),
73 type_name::<T>(),
74 )));
75 }
76 Ok(())
77}