Skip to content

Commit 69608e7

Browse files
authored
Merge pull request #71 from dexhorthy/dexter/eng-1116-delegation-to-sub-agents
sub-agent delegation
2 parents 75232a6 + 89cc325 commit 69608e7

25 files changed

+1158
-298
lines changed

README.md

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ ACP (Agent Control Plane) is a cloud-native orchestrator for AI Agents built on
3333
- [Creating an Agent and Running your first task](#creating-an-agent-and-running-your-first-task)
3434
- [Adding Tools with MCP](#adding-tools-with-mcp)
3535
- [Using other language models](#using-other-language-models)
36+
- [Delegating to a Sub-Agent](#delegating-to-a-sub-agent)
3637
- [Incorporating Human Approval](#incorporating-human-approval)
3738
- [Incorporating Humans as Tools](#humans-as-tools)
3839
- [Cleaning Up](#cleaning-up)
@@ -908,6 +909,107 @@ NAME READY STATUS PHASE PREVIEW OUTPUT
908909
claude-task true Ready FinalAnswer I am Claude, an AI assistant created by Anthropic. My primary directive is to be helpful while being direct and honest in my interactions. I aim to help users with their tasks while adhering to ethical principles.
909910
```
910911

912+
### Delegating to a Sub-Agent
913+
914+
We can compose agents together to create more complex behaviors and make longer workflows more reliable.
915+
916+
Let's create a web search agent that can use the fetch tool we created in the previous example.
917+
918+
```bash
919+
cat <<EOF | kubectl apply -f -
920+
apiVersion: acp.humanlayer.dev/v1alpha1
921+
kind: Agent
922+
metadata:
923+
name: web-search
924+
spec:
925+
llmRef:
926+
name: gpt-4o
927+
system: |
928+
You are a helpful assistant. Your job is to help the user with their tasks.
929+
mcpServers:
930+
- name: fetch
931+
EOF
932+
```
933+
934+
next, we can create a router agent that can delegate to the web search agent.
935+
936+
```bash
937+
cat <<EOF | kubectl apply -f -
938+
apiVersion: acp.humanlayer.dev/v1alpha1
939+
kind: Agent
940+
metadata:
941+
name: manager
942+
spec:
943+
llmRef:
944+
name: gpt-4o
945+
system: |
946+
You are a helpful assistant. Your job is to help the user with their tasks.
947+
subAgents:
948+
- name: web-search
949+
EOF
950+
```
951+
952+
From here, let's create a task that uses the manager agent.
953+
954+
```bash
955+
cat <<EOF | kubectl apply -f -
956+
apiVersion: acp.humanlayer.dev/v1alpha1
957+
kind: Task
958+
metadata:
959+
name: manager-task
960+
spec:
961+
agentRef:
962+
name: manager
963+
userMessage: "what is the data at https://lotrapi.co/api/v1/characters/2?"
964+
EOF
965+
```
966+
967+
While this is running, you can run the following a few times to see how the parent agent calls a `delegate` tool which then spawns a new task that uses the `web-fetch` agent
968+
969+
```
970+
kubectl get agent,task,toolcall
971+
```
972+
973+
974+
975+
976+
The following diagram shows the relationship between Agents, subagents, and created tasks:
977+
978+
```mermaid
979+
graph RL
980+
981+
982+
subgraph ManagerAgent
983+
subAgents
984+
end
985+
986+
subgraph WebFetchAgent
987+
MCPServers
988+
end
989+
990+
991+
992+
subgraph ManagerTask
993+
agentRef
994+
end
995+
996+
subgraph DelegationTask
997+
userMessage
998+
agentRef2
999+
end
1000+
1001+
DelegationTask --> parentTask --> ManagerTask
1002+
agentRef2 --> WebFetchAgent
1003+
1004+
agentRef --> ManagerAgent
1005+
1006+
subgraph MCPServer
1007+
fetch[fetch server]
1008+
end
1009+
1010+
MCPServers --> MCPServer
1011+
```
1012+
9111013
### Incorporating Human Approval
9121014

9131015
For certain classes of MCP tools, you may want to incorporate human approval into an agent's workflow.
@@ -1198,7 +1300,7 @@ kind delete cluster
11981300
| MCP stdio Support | Alpha ✅ |
11991301
| Task Execution History via Kubernetes Events | Alpha ✅ |
12001302
| Better MCP Scheduling | Planned 🗺️ |
1201-
| Delegation to Sub Agents | Planned 🗺️ |
1303+
| Delegation to Sub Agents | In Progress 🚧 |
12021304
| Human approval for MCP Tools | Alpha ✅ |
12031305
| Contact human as a tool | In Progress 🚧 |
12041306
| Tiered approval (once, just for this task, or always) | Planned 🗺️ |

acp/api/v1alpha1/agent_types.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ type AgentSpec struct {
2222
// +kubebuilder:validation:Required
2323
// +kubebuilder:validation:MinLength=1
2424
System string `json:"system"`
25+
26+
// SubAgents is a list of local object references to other Agents
27+
// that can be delegated to as sub-agents.
28+
// +optional
29+
SubAgents []LocalObjectReference `json:"subAgents,omitempty"`
30+
31+
// Description is an optional description for an agent.
32+
// If present, it's included in any "delegateToAgent" tool descriptions
33+
// +optional
34+
Description string `json:"description,omitempty"`
2535
}
2636

2737
// LocalObjectReference contains enough information to locate the referenced resource in the same namespace
@@ -32,14 +42,22 @@ type LocalObjectReference struct {
3242
Name string `json:"name"`
3343
}
3444

45+
type AgentStatusType string
46+
47+
const (
48+
AgentStatusReady AgentStatusType = "Ready"
49+
AgentStatusError AgentStatusType = "Error"
50+
AgentStatusPending AgentStatusType = "Pending"
51+
)
52+
3553
// AgentStatus defines the observed state of Agent
3654
type AgentStatus struct {
3755
// Ready indicates if the agent's dependencies (LLM and Tools) are valid and ready
3856
Ready bool `json:"ready,omitempty"`
3957

4058
// Status indicates the current status of the agent
4159
// +kubebuilder:validation:Enum=Ready;Error;Pending
42-
Status string `json:"status,omitempty"`
60+
Status AgentStatusType `json:"status,omitempty"`
4361

4462
// StatusDetail provides additional details about the current status
4563
StatusDetail string `json:"statusDetail,omitempty"`
@@ -51,6 +69,10 @@ type AgentStatus struct {
5169
// ValidHumanContactChannels is the list of human contact channels that were successfully validated
5270
// +optional
5371
ValidHumanContactChannels []ResolvedContactChannel `json:"validHumanContactChannels,omitempty"`
72+
73+
// ValidSubAgents is the list of sub-agents that were successfully validated
74+
// +optional
75+
ValidSubAgents []ResolvedSubAgent `json:"validSubAgents,omitempty"`
5476
}
5577

5678
type ResolvedMCPServer struct {
@@ -73,6 +95,12 @@ type ResolvedContactChannel struct {
7395
Type string `json:"type"`
7496
}
7597

98+
type ResolvedSubAgent struct {
99+
// Name of the sub-agent
100+
// +kubebuilder:validation:Required
101+
Name string `json:"name"`
102+
}
103+
76104
// +kubebuilder:object:root=true
77105
// +kubebuilder:subresource:status
78106
// +kubebuilder:printcolumn:name="Ready",type="boolean",JSONPath=".status.ready"

acp/api/v1alpha1/task_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ const (
157157

158158
// +kubebuilder:object:root=true
159159
// +kubebuilder:subresource:status
160+
// +kubebuilder:printcolumn:name="Agent",type="string",JSONPath=".spec.agentRef.name"
160161
// +kubebuilder:printcolumn:name="Ready",type="boolean",JSONPath=".status.ready"
161162
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.status"
162163
// +kubebuilder:printcolumn:name="Detail",type="string",JSONPath=".status.statusDetail",priority=1

acp/api/v1alpha1/toolcall_types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ const (
1313
ToolCallStatusTypeSucceeded ToolCallStatusType = "Succeeded"
1414
)
1515

16-
// ToolType identifies the type of the tool (Standard, MCP, HumanContact)
16+
// ToolType identifies the type of the tool (Standard, MCP, HumanContact, DelegateToAgent)
1717
type ToolType string
1818

1919
const (
20-
ToolTypeMCP ToolType = "MCP"
21-
ToolTypeHumanContact ToolType = "HumanContact"
20+
ToolTypeMCP ToolType = "MCP"
21+
ToolTypeHumanContact ToolType = "HumanContact"
22+
ToolTypeDelegateToAgent ToolType = "DelegateToAgent"
2223
)
2324

2425
// ToolCallSpec defines the desired state of ToolCall

acp/api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

acp/config/crd/bases/acp.humanlayer.dev_agents.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ spec:
5050
spec:
5151
description: AgentSpec defines the desired state of Agent
5252
properties:
53+
description:
54+
description: |-
55+
Description is an optional description for an agent.
56+
If present, it's included in any "delegateToAgent" tool descriptions
57+
type: string
5358
humanContactChannels:
5459
description: HumanContactChannels is a list of ContactChannel resources
5560
that can be used for human interactions
@@ -89,6 +94,22 @@ spec:
8994
- name
9095
type: object
9196
type: array
97+
subAgents:
98+
description: |-
99+
SubAgents is a list of local object references to other Agents
100+
that can be delegated to as sub-agents.
101+
items:
102+
description: LocalObjectReference contains enough information to
103+
locate the referenced resource in the same namespace
104+
properties:
105+
name:
106+
description: Name of the referent
107+
minLength: 1
108+
type: string
109+
required:
110+
- name
111+
type: object
112+
type: array
92113
system:
93114
description: System is the system prompt for the agent
94115
minLength: 1
@@ -148,6 +169,18 @@ spec:
148169
- name
149170
type: object
150171
type: array
172+
validSubAgents:
173+
description: ValidSubAgents is the list of sub-agents that were successfully
174+
validated
175+
items:
176+
properties:
177+
name:
178+
description: Name of the sub-agent
179+
type: string
180+
required:
181+
- name
182+
type: object
183+
type: array
151184
type: object
152185
type: object
153186
served: true

acp/config/crd/bases/acp.humanlayer.dev_tasks.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ spec:
1515
scope: Namespaced
1616
versions:
1717
- additionalPrinterColumns:
18+
- jsonPath: .spec.agentRef.name
19+
name: Agent
20+
type: string
1821
- jsonPath: .status.ready
1922
name: Ready
2023
type: boolean

acp/config/manager/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ images:
77
- name: controller
88
newName: ghcr.io/humanlayer/agentcontrolplane
99
newTag: v0.5.1
10+

0 commit comments

Comments
 (0)