Skip to main content

nemo_relay/api/runtime/
callbacks.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Callback type aliases used by the runtime middleware pipeline.
5//!
6//! The public middleware registration APIs accept callback closures with the
7//! signatures defined in this module. These aliases centralize those signatures
8//! so the runtime can compose tool and LLM middleware consistently across
9//! bindings.
10
11use std::future::Future;
12use std::pin::Pin;
13use std::sync::Arc;
14
15use tokio_stream::Stream;
16
17use crate::api::event::Event;
18use crate::api::llm::LlmRequest;
19use crate::codec::request::AnnotatedLlmRequest;
20use crate::error::Result;
21use crate::json::Json;
22
23/// Sanitize a tool request payload before the runtime records it.
24///
25/// Tool sanitize callbacks are used only for observability payloads. They can
26/// rewrite the JSON arguments recorded on tool-start events without changing
27/// the caller-owned request that is passed to the tool implementation.
28///
29/// # Parameters
30/// - First argument: Tool name associated with the request payload.
31/// - Second argument: JSON payload to sanitize for observability.
32///
33/// # Returns
34/// Sanitized JSON payload for the emitted event.
35pub type ToolSanitizeFn = Arc<dyn Fn(&str, Json) -> Json + Send + Sync>;
36/// Decide whether a tool call is allowed to continue.
37///
38/// The callback receives the tool name and the current argument payload. It can
39/// return `Ok(None)` to allow execution, `Ok(Some(reason))` to reject the call
40/// with a guardrail message, or an error to abort evaluation entirely.
41///
42/// This alias is [`Arc`]-backed so the runtime can clone conditional
43/// guardrails into an evaluation snapshot and invoke them after registry locks
44/// are released.
45///
46/// # Parameters
47/// - First argument: Tool name being evaluated.
48/// - Second argument: Current tool argument payload.
49///
50/// # Returns
51/// A [`Result`] containing `Ok(None)` when execution is allowed or
52/// `Ok(Some(reason))` when the guardrail rejects the call.
53///
54/// # Errors
55/// The callback can return any [`FlowError`](crate::error::FlowError) to abort
56/// guardrail evaluation.
57pub type ToolConditionalFn = Arc<dyn Fn(&str, &Json) -> Result<Option<String>> + Send + Sync>;
58/// Rewrite tool arguments before execution.
59///
60/// Tool request intercepts run in priority order and can transform the JSON
61/// payload that is eventually passed into the tool execution callback.
62///
63/// # Parameters
64/// - First argument: Tool name associated with the request.
65/// - Second argument: JSON argument payload to transform.
66///
67/// # Returns
68/// A [`Result`] containing the transformed JSON argument payload.
69///
70/// # Errors
71/// The callback can return any [`FlowError`](crate::error::FlowError) to abort
72/// the request-intercept chain.
73pub type ToolInterceptFn = Arc<dyn Fn(&str, Json) -> Result<Json> + Send + Sync>;
74/// Continuation type invoked by tool execution intercepts.
75///
76/// Execution intercepts receive this callable as their `next` continuation and
77/// can call it with modified arguments, wrap it, or skip it entirely.
78///
79/// # Parameters
80/// - First argument: JSON argument payload to pass to the remaining execution
81///   chain.
82///
83/// # Returns
84/// A future resolving to the tool result JSON.
85///
86/// # Errors
87/// The future resolves to an error when the remaining execution chain fails.
88pub type ToolExecutionNextFn =
89    Arc<dyn Fn(Json) -> Pin<Box<dyn Future<Output = Result<Json>> + Send>> + Send + Sync>;
90/// Wrap or replace tool execution.
91///
92/// A tool execution intercept receives the tool name, the current argument
93/// payload, and the continuation representing the rest of the chain.
94///
95/// # Parameters
96/// - First argument: Tool name associated with the execution.
97/// - Second argument: Current JSON argument payload.
98/// - Third argument: Continuation for the remaining execution chain.
99///
100/// # Returns
101/// A future resolving to the tool result JSON.
102///
103/// # Errors
104/// The future resolves to an error when the intercept or remaining execution
105/// chain fails.
106pub type ToolExecutionFn = Arc<
107    dyn Fn(&str, Json, ToolExecutionNextFn) -> Pin<Box<dyn Future<Output = Result<Json>> + Send>>
108        + Send
109        + Sync,
110>;
111
112/// Sanitize an LLM request before the runtime records it.
113///
114/// LLM request sanitizers affect the serialized request payload emitted on
115/// start events. They do not mutate the caller-owned [`LlmRequest`] unless a
116/// separate request intercept does so.
117///
118/// # Parameters
119/// - First argument: LLM request payload to sanitize for observability.
120///
121/// # Returns
122/// Sanitized [`LlmRequest`] for the emitted event.
123pub type LlmSanitizeRequestFn = Arc<dyn Fn(LlmRequest) -> LlmRequest + Send + Sync>;
124/// Sanitize an LLM response before the runtime records it.
125///
126/// These callbacks rewrite the JSON response payload captured on LLM-end
127/// events, which is useful for redaction or payload normalization.
128///
129/// # Parameters
130/// - First argument: JSON response payload to sanitize for observability.
131///
132/// # Returns
133/// Sanitized JSON response payload for the emitted event.
134pub type LlmSanitizeResponseFn = Arc<dyn Fn(Json) -> Json + Send + Sync>;
135/// Decide whether an LLM call is allowed to continue.
136///
137/// The callback receives the current [`LlmRequest`] and can allow execution,
138/// reject it with a guardrail reason, or return an error.
139///
140/// This alias is [`Arc`]-backed so the runtime can clone conditional
141/// guardrails into an evaluation snapshot and invoke them after registry locks
142/// are released.
143///
144/// # Parameters
145/// - First argument: Current [`LlmRequest`] being evaluated.
146///
147/// # Returns
148/// A [`Result`] containing `Ok(None)` when execution is allowed or
149/// `Ok(Some(reason))` when the guardrail rejects the call.
150///
151/// # Errors
152/// The callback can return any [`FlowError`](crate::error::FlowError) to abort
153/// guardrail evaluation.
154pub type LlmConditionalFn = Arc<dyn Fn(&LlmRequest) -> Result<Option<String>> + Send + Sync>;
155/// Rewrite or annotate an LLM request before execution.
156///
157/// Request intercepts can transform the wire request, attach or replace a
158/// normalized [`AnnotatedLlmRequest`], or both.
159///
160/// # Parameters
161/// - First argument: Logical provider or model family name.
162/// - Second argument: LLM request to transform.
163/// - Third argument: Optional normalized request annotation to carry forward.
164///
165/// # Returns
166/// A [`Result`] containing the transformed request and optional annotation.
167///
168/// # Errors
169/// The callback can return any [`FlowError`](crate::error::FlowError) to abort
170/// the request-intercept chain.
171pub type LlmRequestInterceptFn = Arc<
172    dyn Fn(
173            &str,
174            LlmRequest,
175            Option<AnnotatedLlmRequest>,
176        ) -> Result<(LlmRequest, Option<AnnotatedLlmRequest>)>
177        + Send
178        + Sync,
179>;
180/// Continuation type invoked by non-streaming LLM execution intercepts.
181///
182/// Execution intercepts use this callable to continue the non-streaming LLM
183/// pipeline after applying their own logic.
184///
185/// # Parameters
186/// - First argument: LLM request to pass to the remaining execution chain.
187///
188/// # Returns
189/// A future resolving to the provider response JSON.
190///
191/// # Errors
192/// The future resolves to an error when the remaining execution chain fails.
193pub type LlmExecutionNextFn =
194    Arc<dyn Fn(LlmRequest) -> Pin<Box<dyn Future<Output = Result<Json>> + Send>> + Send + Sync>;
195/// Wrap or replace non-streaming LLM execution.
196///
197/// A non-streaming execution intercept receives the logical provider name, the
198/// current request, and the continuation representing the rest of the chain.
199///
200/// # Parameters
201/// - First argument: Logical provider or model family name.
202/// - Second argument: Current LLM request.
203/// - Third argument: Continuation for the remaining execution chain.
204///
205/// # Returns
206/// A future resolving to the provider response JSON.
207///
208/// # Errors
209/// The future resolves to an error when the intercept or remaining execution
210/// chain fails.
211pub type LlmExecutionFn = Arc<
212    dyn Fn(
213            &str,
214            LlmRequest,
215            LlmExecutionNextFn,
216        ) -> Pin<Box<dyn Future<Output = Result<Json>> + Send>>
217        + Send
218        + Sync,
219>;
220/// Stream of JSON chunks produced by the managed streaming LLM pipeline.
221pub type LlmJsonStream = Pin<Box<dyn Stream<Item = Result<Json>> + Send>>;
222/// Per-chunk collector used by the streaming LLM runtime.
223///
224/// # Parameters
225/// - First argument: One JSON chunk emitted by the provider stream.
226///
227/// # Returns
228/// A [`Result`] that is `Ok(())` when the chunk was collected.
229///
230/// # Errors
231/// The callback can return any [`FlowError`](crate::error::FlowError) to abort
232/// stream processing.
233pub type LlmCollectorFn = Box<dyn FnMut(Json) -> Result<()> + Send>;
234/// Finalizer used to synthesize the aggregate streaming response payload.
235///
236/// # Parameters
237/// This callback takes no arguments.
238///
239/// # Returns
240/// Aggregate response JSON synthesized from collected stream chunks.
241pub type LlmFinalizerFn = Box<dyn FnOnce() -> Json + Send>;
242/// Scope-local registry references passed into streaming execution-chain builders.
243///
244/// # Returns
245/// A shared reference to a scope-local streaming execution registry.
246pub(crate) type LlmStreamExecutionRegistryRef<'a> = &'a crate::registry::SortedRegistry<
247    crate::api::registry::ExecutionIntercept<LlmStreamExecutionFn>,
248>;
249/// Slice of scope-local streaming execution registries.
250///
251/// # Returns
252/// A borrowed slice of scope-local streaming execution registry references.
253pub(crate) type LlmStreamExecutionRegistryRefs<'a> = &'a [LlmStreamExecutionRegistryRef<'a>];
254
255/// Continuation type invoked by streaming LLM execution intercepts.
256///
257/// This callable represents the remainder of the streaming LLM execution chain
258/// and resolves to a stream of JSON response chunks.
259///
260/// # Parameters
261/// - First argument: LLM request to pass to the remaining streaming execution
262///   chain.
263///
264/// # Returns
265/// A future resolving to a JSON chunk stream.
266///
267/// # Errors
268/// The future resolves to an error when the remaining streaming execution
269/// chain fails.
270pub type LlmStreamExecutionNextFn = Arc<
271    dyn Fn(LlmRequest) -> Pin<Box<dyn Future<Output = Result<LlmJsonStream>> + Send>> + Send + Sync,
272>;
273/// Wrap or replace streaming LLM execution.
274///
275/// A streaming execution intercept can observe or modify the request before
276/// invoking the continuation, and it can also replace the returned stream.
277///
278/// # Parameters
279/// - First argument: Logical provider or model family name.
280/// - Second argument: Current LLM request.
281/// - Third argument: Continuation for the remaining streaming execution chain.
282///
283/// # Returns
284/// A future resolving to a JSON chunk stream.
285///
286/// # Errors
287/// The future resolves to an error when the intercept or remaining streaming
288/// execution chain fails.
289pub type LlmStreamExecutionFn = Arc<
290    dyn Fn(
291            &str,
292            LlmRequest,
293            LlmStreamExecutionNextFn,
294        ) -> Pin<Box<dyn Future<Output = Result<LlmJsonStream>> + Send>>
295        + Send
296        + Sync,
297>;
298
299/// Consume runtime lifecycle events after they are emitted.
300///
301/// Event subscribers are invoked for scope, tool, LLM, and mark events after
302/// the runtime has built the final event payload.
303///
304/// # Parameters
305/// - First argument: Runtime event that was just emitted.
306///
307/// # Returns
308/// `()`.
309pub type EventSubscriberFn = Arc<dyn Fn(&Event) + Send + Sync>;