1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-License-Identifier: AGPL-3.0-only
//! Self-tool dispatch.
//!
//! The agentic loop's tools come from connected MCP servers *plus* agentd's own
//! self-tools (`subagent.spawn`, …). A [`SelfHandler`] supplies those tool
//! definitions and handles their calls in-process — distinct from the MCP
//! dispatch path. This is the seam through which the model **self-orchestrates**:
//! it calls `subagent.spawn` to split its instruction into delegated child
//! agents. The model only *asks*; the supervisor is what enforces the depth and
//! concurrency caps and narrows the child's scope, so a compromised model
//! cannot widen its own budget through this seam.
use crateToolDef;
use Value;
/// The classes of tool the agentic loop offers the model. This boundary is what
/// keeps two invariants true: a task tool reaches the model ONLY by being
/// exported from a registered MCP server or registered in code by the embedder,
/// and nothing in the catalogue shells out to a local command. EVERY tool the
/// loop advertises is exactly one of these classes; there is no third "general
/// capability library" that could smuggle in an unaudited capability.
/// * [`Mcp`](ToolClass::Mcp) — a tool discovered from a connected MCP server
/// (`tools/list`). Dispatched by routing the call BACK to its owning server
/// ([`dispatch_tool`](crate::agentloop::runner)); agentd never runs it locally.
/// * [`SelfControl`](ToolClass::SelfControl) — agentd's OWN orchestration
/// primitives (see [`SELF_CONTROL_TOOLS`]): delegation (`subagent.*`,
/// `a2a.delegate`), reactivity (root-only `schedule`/`subscribe`/`unsubscribe`),
/// and resource attention (`resource.read`). These are handled in-process by a
/// [`SelfHandler`] / the runner — NONE shells out. This is the named
/// "self/control" class: the agent's own control surface, structurally distinct
/// from the MCP task-tool catalogue (a different code path assembles each).
/// The authoritative membership of the [`ToolClass::SelfControl`] class: every
/// self/control primitive name agentd may offer the model. The
/// [`SelfHandler`] advertises a depth-/feature-conditioned SUBSET of this set
/// (`a2a.delegate` only with peers; `schedule`/`subscribe`/`unsubscribe` only at
/// the root; the `subagent.*` delegation tools only within the depth budget), and
/// the runner adds `resource.read` when any resource is readable. A test asserts
/// that everything a handler can advertise appears in this list, so a new
/// self-tool cannot silently escape the class boundary. By construction the set
/// contains no local-execution primitive.
pub const SELF_CONTROL_TOOLS: & = &;
/// Provides agentd's in-process self-tools to the loop. The loop tries the
/// self-handler first; a `None` result means "not a self-tool — fall through to
/// MCP".