switchyard_protocol/codex_namespaces.rs
1// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Reads the Codex tool namespaces that a Responses request decoder records.
5//!
6//! Codex groups tools into `namespace` containers. The Responses codec in
7//! `switchyard-translation` flattens each child to `<namespace>__<tool>` and
8//! stores the mapping in the request's [`ProviderExtensions`]. Code that does not
9//! depend on the translation crate uses these helpers to recover the tool name.
10
11use serde_json::{Map, Value};
12
13use crate::ProviderExtensions;
14
15/// Separator between a namespace and a tool name in a qualified wire name.
16pub const NAMESPACE_SEPARATOR: &str = "__";
17
18/// Request extension key holding the qualified-name to namespace mapping.
19///
20/// Prefixed so it cannot collide with a real provider field, and so a codec that
21/// allowlists provider fields never forwards it.
22pub const TOOL_NAMESPACES_KEY: &str = "switchyard_codex_tool_namespaces";
23
24/// Reads the mapping back off a request's extensions.
25pub fn tool_namespaces(extensions: &ProviderExtensions) -> Option<&Map<String, Value>> {
26 extensions
27 .fields
28 .get(TOOL_NAMESPACES_KEY)
29 .and_then(Value::as_object)
30}
31
32/// Splits a qualified wire name back into its tool name and namespace.
33///
34/// Returns `None` for a name the request never qualified, so an unrecognized
35/// call is left alone rather than attributed to the wrong namespace. The tool
36/// name may itself contain the separator, so the namespace is matched as a
37/// prefix rather than by splitting on it.
38pub fn split_qualified_name<'a>(
39 namespaces: &'a Map<String, Value>,
40 qualified: &'a str,
41) -> Option<(&'a str, &'a str)> {
42 let value = namespaces.get(qualified)?;
43 let namespace = value
44 .as_str()
45 .or_else(|| value.get("namespace").and_then(Value::as_str))?;
46 let tool = qualified
47 .strip_prefix(namespace)?
48 .strip_prefix(NAMESPACE_SEPARATOR)?;
49 Some((tool, namespace))
50}