Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-03-13 19:58:02 +01:00
parent d80a0fa7e4
commit deac1538e5

View File

@@ -394,6 +394,67 @@ func TestAgentTool_Execute(t *testing.T) {
)
}
type nestedApprovalFixture struct {
innerProvider *mockProvider
outerProvider *mockProvider
outerAgent *agent.Agent
}
func noopDeleteFile(_ context.Context, _ struct{}) (agent.ToolResult, error) {
return agent.ToolResult{Content: "file deleted"}, nil
}
func newNestedApprovalFixture(
t *testing.T,
deleteFunc func(context.Context, struct{}) (agent.ToolResult, error),
innerResponses []*llm.ChatCompletionResponse,
outerResponses []*llm.ChatCompletionResponse,
outerOpts ...agent.Option,
) nestedApprovalFixture {
t.Helper()
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
deleteFunc,
)
require.NoError(t, err)
innerProvider := &mockProvider{responses: innerResponses}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{responses: outerResponses}
opts := append(
[]agent.Option{
agent.WithModel("test-model"),
agent.WithTools(innerAgent.AsTool("file_expert", "Manage files")),
},
outerOpts...,
)
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
opts...,
)
return nestedApprovalFixture{
innerProvider: innerProvider,
outerProvider: outerProvider,
outerAgent: outerAgent,
}
}
func TestAgentTool_Execute_NestedApproval(t *testing.T) {
t.Parallel()
@@ -402,51 +463,24 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
func(t *testing.T) {
t.Parallel()
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
return agent.ToolResult{Content: "file deleted"}, nil
},
)
require.NoError(t, err)
innerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
f := newNestedApprovalFixture(
t,
noopDeleteFile,
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "inner_tc1",
Function: llm.FunctionCall{Name: "delete_file", Arguments: `{}`},
}),
},
}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "outer_tc1",
Function: llm.FunctionCall{Name: "file_expert", Arguments: `{"input":"delete the file"}`},
}),
},
}
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
agent.WithModel("test-model"),
agent.WithTools(innerAgent.AsTool("file_expert", "Manage files")),
)
_, err = outerAgent.Run(
_, err := f.outerAgent.Run(
context.Background(),
[]llm.Message{userMessage("Delete the file")},
)
@@ -467,54 +501,29 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
var toolExecuted bool
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
f := newNestedApprovalFixture(
t,
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
toolExecuted = true
return agent.ToolResult{Content: "file deleted"}, nil
},
)
require.NoError(t, err)
innerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "inner_tc1",
Function: llm.FunctionCall{Name: "delete_file", Arguments: `{}`},
}),
stopResponse("File has been deleted."),
},
}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "outer_tc1",
Function: llm.FunctionCall{Name: "file_expert", Arguments: `{"input":"delete the file"}`},
}),
stopResponse("Done, the file has been deleted."),
},
}
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
agent.WithModel("test-model"),
agent.WithTools(innerAgent.AsTool("file_expert", "Manage files")),
)
_, err = outerAgent.Run(
_, err := f.outerAgent.Run(
context.Background(),
[]llm.Message{userMessage("Delete the file")},
)
@@ -545,54 +554,29 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
func(t *testing.T) {
t.Parallel()
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
f := newNestedApprovalFixture(
t,
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
t.Fatal("tool should not be called")
return agent.ToolResult{}, nil
},
)
require.NoError(t, err)
innerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "inner_tc1",
Function: llm.FunctionCall{Name: "delete_file", Arguments: `{}`},
}),
stopResponse("OK, I won't delete the file."),
},
}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "outer_tc1",
Function: llm.FunctionCall{Name: "file_expert", Arguments: `{"input":"delete the file"}`},
}),
stopResponse("The file manager declined."),
},
}
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
agent.WithModel("test-model"),
agent.WithTools(innerAgent.AsTool("file_expert", "Manage files")),
)
_, err = outerAgent.Run(
_, err := f.outerAgent.Run(
context.Background(),
[]llm.Message{userMessage("Delete the file")},
)
@@ -634,37 +618,17 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
)
require.NoError(t, err)
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
return agent.ToolResult{Content: "file deleted"}, nil
},
)
require.NoError(t, err)
innerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
f := newNestedApprovalFixture(
t,
noopDeleteFile,
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "inner_tc1",
Function: llm.FunctionCall{Name: "delete_file", Arguments: `{}`},
}),
stopResponse("File has been deleted."),
},
}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(
llm.ToolCall{
ID: "outer_tc1",
@@ -677,19 +641,10 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
),
stopResponse("Files listed and deleted."),
},
}
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
agent.WithModel("test-model"),
agent.WithTools(
siblingTool,
innerAgent.AsTool("file_expert", "Manage files"),
),
agent.WithTools(siblingTool),
)
_, err = outerAgent.Run(
_, err = f.outerAgent.Run(
context.Background(),
[]llm.Message{userMessage("List and delete files")},
)
@@ -818,54 +773,27 @@ func TestAgentTool_Execute_NestedApproval(t *testing.T) {
func(t *testing.T) {
t.Parallel()
deleteTool, err := agent.FunctionTool[struct{}](
"delete_file",
"Delete a file",
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
return agent.ToolResult{Content: "file deleted"}, nil
},
)
require.NoError(t, err)
hook := &recordingHook{}
innerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
f := newNestedApprovalFixture(
t,
noopDeleteFile,
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "inner_tc1",
Function: llm.FunctionCall{Name: "delete_file", Arguments: `{}`},
}),
},
}
innerAgent := agent.New(
"file_manager",
newTestClient(innerProvider),
agent.WithModel("test-model"),
agent.WithTools(deleteTool),
agent.WithApproval(agent.ApprovalConfig{
ToolNames: []string{"delete_file"},
}),
)
outerProvider := &mockProvider{
responses: []*llm.ChatCompletionResponse{
[]*llm.ChatCompletionResponse{
toolCallResponse(llm.ToolCall{
ID: "outer_tc1",
Function: llm.FunctionCall{Name: "file_expert", Arguments: `{"input":"delete the file"}`},
}),
},
}
hook := &recordingHook{}
outerAgent := agent.New(
"assistant",
newTestClient(outerProvider),
agent.WithModel("test-model"),
agent.WithTools(innerAgent.AsTool("file_expert", "Manage files")),
agent.WithHooks(hook),
)
_, err = outerAgent.Run(
_, err := f.outerAgent.Run(
context.Background(),
[]llm.Message{userMessage("Delete the file")},
)