Skip to main content

aither_core/llm/tool/
identity.rs

1//! Who made a tool call: the call's id and the agent behind it.
2//!
3//! The agent loop attaches a [`CallIdentity`] to the [`ToolContext`](super::ToolContext)
4//! of every call it dispatches, so a tool, and any command the tool runs on its
5//! behalf, can attribute what it did to the exact call and agent.
6
7use alloc::boxed::Box;
8use alloc::string::String;
9use core::fmt::{self, Display};
10
11/// The id a model provider gave one tool call.
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct ToolCallId(String);
14
15impl ToolCallId {
16    /// Wraps a provider-assigned tool call id.
17    #[must_use]
18    pub fn new(id: impl Into<String>) -> Self {
19        Self(id.into())
20    }
21
22    /// The id as the provider spelled it.
23    #[must_use]
24    pub fn as_str(&self) -> &str {
25        &self.0
26    }
27}
28
29impl Display for ToolCallId {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.write_str(&self.0)
32    }
33}
34
35/// A subagent: its type and the call that started it.
36///
37/// The starting call's identity makes the subagent unique across nested
38/// subagents and ties it to the call that launched it.
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct SubagentIdentity {
41    name: String,
42    started_by: Option<Box<CallIdentity>>,
43}
44
45impl SubagentIdentity {
46    /// A subagent of type `name` started by `started_by`; `None` when the
47    /// dispatcher of the starting call attached no identity.
48    #[must_use]
49    pub fn new(name: impl Into<String>, started_by: Option<CallIdentity>) -> Self {
50        Self {
51            name: name.into(),
52            started_by: started_by.map(Box::new),
53        }
54    }
55
56    /// The subagent type it runs as.
57    #[must_use]
58    pub fn name(&self) -> &str {
59        &self.name
60    }
61
62    /// The call that started this subagent, if its dispatcher identified it.
63    #[must_use]
64    pub fn started_by(&self) -> Option<&CallIdentity> {
65        self.started_by.as_deref()
66    }
67}
68
69/// The agent making a tool call.
70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub enum AgentIdentity {
72    /// The main agent.
73    Main,
74    /// A subagent, at any nesting depth.
75    Subagent(SubagentIdentity),
76}
77
78/// What identifies one tool call: its id and the agent that made it.
79#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub struct CallIdentity {
81    call: ToolCallId,
82    agent: AgentIdentity,
83}
84
85impl CallIdentity {
86    /// The identity of call `call` made by `agent`.
87    #[must_use]
88    pub const fn new(call: ToolCallId, agent: AgentIdentity) -> Self {
89        Self { call, agent }
90    }
91
92    /// The call's id.
93    #[must_use]
94    pub const fn call(&self) -> &ToolCallId {
95        &self.call
96    }
97
98    /// The agent that made the call.
99    #[must_use]
100    pub const fn agent(&self) -> &AgentIdentity {
101        &self.agent
102    }
103}