Skip to main content

langsmith_rust/tracing/
scope.rs

1use crate::error::{LangSmithError, Result};
2use crate::models::run::RunType;
3use crate::tracing::tracer::Tracer;
4use crate::tracing::TraceContext;
5use crate::utils::serialization::{ensure_inputs_object, ensure_outputs_object};
6use serde::Serialize;
7use serde_json::Value;
8
9/// Ergonomic wrapper around `Tracer` that standardizes:
10/// - inputs/outputs serialization
11/// - post/end/patch flow
12/// - error handling (best-effort patching)
13///
14/// This is intended to keep application code small and declarative.
15pub struct RunScope {
16    tracer: Tracer,
17    posted: bool,
18}
19
20impl RunScope {
21    pub fn root<I: Serialize>(name: &str, run_type: RunType, inputs: I) -> Result<Self> {
22        let inputs_value =
23            ensure_inputs_object(inputs).map_err(LangSmithError::Serialization)?;
24        Ok(Self {
25            tracer: Tracer::new(name, run_type, inputs_value),
26            posted: false,
27        })
28    }
29
30    pub fn root_value(name: &str, run_type: RunType, inputs: Value) -> Self {
31        Self {
32            tracer: Tracer::new(name, run_type, inputs),
33            posted: false,
34        }
35    }
36
37    pub fn with_thread_id(mut self, thread_id: impl Into<String>) -> Self {
38        self.tracer = self.tracer.with_thread_id(thread_id.into());
39        self
40    }
41
42    pub fn with_context(mut self, ctx: &TraceContext) -> Self {
43        self.tracer = self.tracer.with_context(ctx);
44        self
45    }
46
47    pub fn tracer(&self) -> &Tracer {
48        &self.tracer
49    }
50
51    pub fn tracer_mut(&mut self) -> &mut Tracer {
52        &mut self.tracer
53    }
54
55    pub fn child<I: Serialize>(&self, name: &str, run_type: RunType, inputs: I) -> Result<Self> {
56        let inputs_value =
57            ensure_inputs_object(inputs).map_err(LangSmithError::Serialization)?;
58        Ok(Self {
59            tracer: self.tracer.create_child(name, run_type, inputs_value),
60            posted: false,
61        })
62    }
63
64    pub fn child_value(&self, name: &str, run_type: RunType, inputs: Value) -> Self {
65        Self {
66            tracer: self.tracer.create_child(name, run_type, inputs),
67            posted: false,
68        }
69    }
70
71    /// Posts the run start to LangSmith. Safe to call multiple times.
72    pub async fn post_start(&mut self) -> Result<()> {
73        if self.posted {
74            return Ok(());
75        }
76        self.tracer.post().await?;
77        self.posted = true;
78        Ok(())
79    }
80
81    /// Ends the run successfully and PATCHes it (best-effort).
82    pub async fn end_ok<O: Serialize>(mut self, outputs: O) -> Result<()> {
83        let outputs_value =
84            ensure_outputs_object(outputs).map_err(LangSmithError::Serialization)?;
85        self.tracer.end(outputs_value);
86        let _ = self.tracer.patch().await;
87        Ok(())
88    }
89
90    /// Ends the run with error and PATCHes it (best-effort).
91    pub async fn end_error(mut self, error: impl ToString, outputs: Option<Value>) -> Result<()> {
92        self.tracer.set_error(&error.to_string());
93        self.tracer.end(outputs.unwrap_or_else(|| serde_json::json!({})));
94        let _ = self.tracer.patch().await;
95        Ok(())
96    }
97}
98
99