Skip to content

Commit a6acfe7

Browse files
committed
fix
1 parent 7025145 commit a6acfe7

File tree

5 files changed

+126
-9
lines changed

5 files changed

+126
-9
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ go run cmd/example/codemode_utcp_workflow/main.go
119119

120120
# Agent-to-Agent Communication via UTCP
121121
go run cmd/example/agent_as_tool/main.go
122+
go run cmd/example/agent_as_utcp_codemode/main.go
122123
```
123124

124125
#### Example Descriptions
@@ -128,6 +129,7 @@ go run cmd/example/agent_as_tool/main.go
128129
- **`cmd/example/codemode_utcp_workflow/main.go`**: Shows orchestrating multi-step workflows where multiple specialist agents (analyst, writer, reviewer) work together through UTCP tool calls.
129130

130131
- **`cmd/example/agent_as_tool/main.go`**: Demonstrates exposing agents as UTCP tools using `RegisterAsUTCPProvider()`, enabling agent-to-agent communication and hierarchical agent architectures.
132+
- **`cmd/example/agent_as_utcp_codemode/main.go`**: Shows an agent exposed as a UTCP tool and orchestrated via CodeMode, illustrating natural language to tool call generation.
131133

132134

133135
## Project Structure

agent_tool.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,20 @@ func (t *agentCLITransport) RegisterToolProvider(ctx context.Context, prov base.
8181
}
8282
list, ok := t.tools[p.Name]
8383
if !ok {
84+
if t.inner != nil {
85+
return t.inner.RegisterToolProvider(ctx, prov)
86+
}
8487
return nil, fmt.Errorf("agent tools not found for provider %s", p.Name)
8588
}
8689
return list, nil
8790
}
8891

8992
func (t *agentCLITransport) DeregisterToolProvider(ctx context.Context, prov base.Provider) error {
9093
if p, ok := prov.(*cli.CliProvider); ok {
91-
delete(t.tools, p.Name)
92-
return nil
94+
if _, ok := t.tools[p.Name]; ok {
95+
delete(t.tools, p.Name)
96+
return nil
97+
}
9398
}
9499
if t.inner != nil {
95100
return t.inner.DeregisterToolProvider(ctx, prov)
@@ -99,14 +104,19 @@ func (t *agentCLITransport) DeregisterToolProvider(ctx context.Context, prov bas
99104

100105
func (t *agentCLITransport) CallTool(ctx context.Context, toolName string, args map[string]any, prov base.Provider, _ *string) (any, error) {
101106
if p, ok := prov.(*cli.CliProvider); ok {
102-
for _, tool := range t.tools[p.Name] {
103-
if tool.Name == toolName || strings.HasSuffix(tool.Name, "."+toolName) {
104-
if tool.Handler == nil {
105-
return nil, fmt.Errorf("tool %s has no handler", toolName)
107+
if list, ok := t.tools[p.Name]; ok {
108+
for _, tool := range list {
109+
if tool.Name == toolName || strings.HasSuffix(tool.Name, "."+toolName) {
110+
if tool.Handler == nil {
111+
return nil, fmt.Errorf("tool %s has no handler", toolName)
112+
}
113+
return tool.Handler(ctx, args)
106114
}
107-
return tool.Handler(ctx, args)
108115
}
109116
}
117+
if t.inner != nil {
118+
return t.inner.CallTool(ctx, toolName, args, prov, nil)
119+
}
110120
return nil, fmt.Errorf("tool %s not found for provider %s", toolName, p.Name)
111121
}
112122
if t.inner != nil {
@@ -117,7 +127,9 @@ func (t *agentCLITransport) CallTool(ctx context.Context, toolName string, args
117127

118128
func (t *agentCLITransport) CallToolStream(ctx context.Context, toolName string, args map[string]any, prov base.Provider) (transports.StreamResult, error) {
119129
if p, ok := prov.(*cli.CliProvider); ok {
120-
return nil, fmt.Errorf("streaming not supported for tool %s (provider %s)", toolName, p.Name)
130+
if _, ok := t.tools[p.Name]; ok {
131+
return nil, fmt.Errorf("streaming not supported for tool %s (provider %s)", toolName, p.Name)
132+
}
121133
}
122134
if t.inner != nil {
123135
return t.inner.CallToolStream(ctx, toolName, args, prov)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
"github.com/Protocol-Lattice/go-agent"
9+
"github.com/Protocol-Lattice/go-agent/src/adk"
10+
"github.com/Protocol-Lattice/go-agent/src/adk/modules"
11+
"github.com/Protocol-Lattice/go-agent/src/memory"
12+
"github.com/Protocol-Lattice/go-agent/src/memory/engine"
13+
"github.com/Protocol-Lattice/go-agent/src/models"
14+
"github.com/universal-tool-calling-protocol/go-utcp"
15+
)
16+
17+
func main() {
18+
ctx := context.Background()
19+
20+
// 1. Initialise a UTCP client – this is the shared tool bus.
21+
client, err := utcp.NewUTCPClient(ctx, &utcp.UtcpClientConfig{}, nil, nil)
22+
if err != nil {
23+
log.Fatalf("Failed to create UTCP client: %v", err)
24+
}
25+
26+
// 2. Create a specialist agent that will be exposed as a UTCP tool.
27+
// Use a real Gemini model
28+
specialistModel, err := models.NewGeminiLLM(ctx, "gemini-3-pro-preview", "You are a specialist that can answer trivia questions.")
29+
if err != nil {
30+
log.Fatalf("Failed to create specialist model: %v", err)
31+
}
32+
33+
specialist, err := agent.New(agent.Options{
34+
Model: specialistModel,
35+
Memory: memory.NewSessionMemory(memory.NewMemoryBankWithStore(memory.NewInMemoryStore()), 8),
36+
SystemPrompt: "You are a versatile specialist agent that can help with various tasks.",
37+
})
38+
if err != nil {
39+
log.Fatalf("Failed to create specialist agent: %v", err)
40+
}
41+
42+
// 3. Register the specialist as a UTCP provider.
43+
err = specialist.RegisterAsUTCPProvider(ctx, client, "specialist", "Answers trivia via UTCP")
44+
if err != nil {
45+
log.Fatalf("Failed to register specialist: %v", err)
46+
}
47+
fmt.Println("✅ Registered specialist as UTCP tool 'specialist'")
48+
49+
// 4. Build an orchestrator agent with CodeMode enabled.
50+
51+
// Use a real Gemini model for the orchestrator
52+
orchestratorModel, err := models.NewGeminiLLM(ctx, "gemini-3-pro-preview", "You orchestrate workflows using CodeMode. Generate ONLY valid Go code. Do not include package main or imports. Use codemode.CallTool to invoke tools.")
53+
if err != nil {
54+
log.Fatalf("Failed to create orchestrator model: %v", err)
55+
}
56+
57+
memOpts := engine.DefaultOptions()
58+
kit, err := adk.New(ctx,
59+
adk.WithDefaultSystemPrompt("You orchestrate workflows using CodeMode. Generate ONLY valid Go code. Do not include package main or imports. Use codemode.CallTool to invoke tools."),
60+
adk.WithModules(
61+
modules.NewModelModule("model", func(_ context.Context) (models.Agent, error) { return orchestratorModel, nil }),
62+
modules.InMemoryMemoryModule(10000, memory.AutoEmbedder(), &memOpts),
63+
),
64+
// Enable CodeMode – it will generate calls to codemode.CallTool which under the hood uses the UTCP client.
65+
adk.WithCodeModeUtcp(client, orchestratorModel),
66+
)
67+
if err != nil {
68+
log.Fatalf("Failed to initialise ADK: %v", err)
69+
}
70+
orchestrator, err := kit.BuildAgent(ctx)
71+
if err != nil {
72+
log.Fatalf("Failed to build orchestrator: %v", err)
73+
}
74+
fmt.Println("✅ Orchestrator with CodeMode ready")
75+
76+
// Register the orchestrator itself as a UTCP provider so it can be called recursively or for summarization
77+
err = orchestrator.RegisterAsUTCPProvider(ctx, client, "orchestrator", "Orchestrates workflows and summarizes information")
78+
if err != nil {
79+
log.Fatalf("Failed to register orchestrator: %v", err)
80+
}
81+
fmt.Println("✅ Registered orchestrator as UTCP tool 'orchestrator'")
82+
83+
// 5. Run a natural‑language request that the orchestrator will turn into a CodeMode workflow.
84+
// This prompt describes a multi-step process that the agent would convert into a Go script
85+
// calling the respective UTCP tools (e.g. http.echo, http.timestamp, etc.).
86+
userPrompt := `
87+
Step 1: Ask for a fun fact about the Eiffel Tower using the specialist tool.
88+
Step 2: Ask for a fun fact about the Great Wall of China using the specialist tool.
89+
Step 3: Use the orchestrator tool to summarize the facts from Step 1 and Step 2.
90+
`
91+
fmt.Printf("\nUser Prompt:\n%s\n", userPrompt)
92+
93+
// Invoke the orchestrator.
94+
// In a real scenario, the Orchestrator (powered by an LLM) would generate Go code
95+
// to execute these steps sequentially, passing data between them.
96+
resp, err := orchestrator.Generate(ctx, "session-orchestrator", userPrompt)
97+
if err != nil {
98+
log.Fatalf("Orchestrator failed: %v", err)
99+
}
100+
fmt.Printf("Orchestrator response: %v\n", resp)
101+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ require (
7676
github.com/tidwall/pretty v1.2.1 // indirect
7777
github.com/tidwall/sjson v1.2.5 // indirect
7878
github.com/traefik/yaegi v0.16.1 // indirect
79-
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251121205150-bbc1fca17054 // indirect
79+
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251122105709-d312bed2b74a // indirect
8080
github.com/wlynxg/anet v0.0.3 // indirect
8181
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
8282
github.com/xdg-go/scram v1.1.2 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251121143300-143ea
202202
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251121143300-143eaff821f3/go.mod h1:cUtuDZi5YOJsZEqfjt1tb9rgmFL03vLI+OWthuDrkT8=
203203
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251121205150-bbc1fca17054 h1:JeArJ3juSGnJu3XqeQpTqEgdKBtpfspXW7++sJax//8=
204204
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251121205150-bbc1fca17054/go.mod h1:cUtuDZi5YOJsZEqfjt1tb9rgmFL03vLI+OWthuDrkT8=
205+
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251122105709-d312bed2b74a h1:JRBOZ42bLycRm01dPCXB6Jlcwc+2pIk5cKU5cFCjwg0=
206+
github.com/universal-tool-calling-protocol/go-utcp v1.7.5-0.20251122105709-d312bed2b74a/go.mod h1:cUtuDZi5YOJsZEqfjt1tb9rgmFL03vLI+OWthuDrkT8=
205207
github.com/universal-tool-calling-protocol/go-utcp v1.7.5 h1:hmgWrAgOGBUYyZ8M6nr7+JyG8BtVbWYG3OBjEB3ZW9M=
206208
github.com/universal-tool-calling-protocol/go-utcp v1.7.5/go.mod h1:JXha8vzmC6LOv9jCBYDhNMkSgKdsbuy3Wx0wkZUYqTQ=
207209
github.com/universal-tool-calling-protocol/go-utcp v1.7.6 h1:dm+nppZD9GVAtMuGLXjiKDCQ+odxqvRqP7aQzszC4MY=

0 commit comments

Comments
 (0)