fix(agent): restore hook safety checks after rebase

This commit is contained in:
xj 2026-02-26 23:03:22 -08:00
parent 70f812d358
commit 0d2c4f9368
2 changed files with 80 additions and 5 deletions

View file

@ -264,11 +264,18 @@ func (al *AgentLoop) SetHooks(h *hooks.HookRegistry) error {
// SetPluginManager installs a plugin manager and routes its hook registry into the loop. // SetPluginManager installs a plugin manager and routes its hook registry into the loop.
// Must be called before Run starts. // Must be called before Run starts.
func (al *AgentLoop) SetPluginManager(pm *plugin.Manager) error { func (al *AgentLoop) SetPluginManager(pm *plugin.Manager) error {
al.pluginManager = pm
if pm == nil { if pm == nil {
return al.SetHooks(nil) if err := al.SetHooks(nil); err != nil {
return err
}
al.pluginManager = nil
return nil
} }
return al.SetHooks(pm.HookRegistry()) if err := al.SetHooks(pm.HookRegistry()); err != nil {
return err
}
al.pluginManager = pm
return nil
} }
// EnablePlugins is a convenience helper to build and install a plugin manager. // EnablePlugins is a convenience helper to build and install a plugin manager.
@ -848,13 +855,17 @@ func (al *AgentLoop) runLLMIteration(
toolResult = tools.ErrorResult(reason) toolResult = tools.ErrorResult(reason)
} }
tc.Arguments = btcEvent.Args tc.Arguments = btcEvent.Args
if tc.Arguments == nil {
tc.Arguments = make(map[string]any)
}
} }
toolStart := time.Now() var toolDuration time.Duration
if !toolCanceled { if !toolCanceled {
toolStart := time.Now()
toolResult = agent.Tools.ExecuteWithContext(ctx, tc.Name, tc.Arguments, opts.Channel, opts.ChatID, asyncCallback) toolResult = agent.Tools.ExecuteWithContext(ctx, tc.Name, tc.Arguments, opts.Channel, opts.ChatID, asyncCallback)
toolDuration = time.Since(toolStart)
} }
toolDuration := time.Since(toolStart)
// Fire after_tool_call hook (fires for both executed and canceled calls) // Fire after_tool_call hook (fires for both executed and canceled calls)
if al.hooks != nil { if al.hooks != nil {

View file

@ -11,6 +11,8 @@ import (
"github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/config"
"github.com/sipeed/picoclaw/pkg/hooks" "github.com/sipeed/picoclaw/pkg/hooks"
"github.com/sipeed/picoclaw/pkg/plugin" "github.com/sipeed/picoclaw/pkg/plugin"
"github.com/sipeed/picoclaw/pkg/providers"
"github.com/sipeed/picoclaw/pkg/tools"
) )
type blockingPlugin struct{} type blockingPlugin struct{}
@ -32,6 +34,68 @@ func (p blockingPlugin) Register(r *hooks.HookRegistry) error {
return nil return nil
} }
type nilArgsProvider struct {
calls int
}
func (p *nilArgsProvider) Chat(
_ context.Context,
_ []providers.Message,
_ []providers.ToolDefinition,
_ string,
_ map[string]any,
) (*providers.LLMResponse, error) {
if p.calls == 0 {
p.calls++
return &providers.LLMResponse{
Content: "",
ToolCalls: []providers.ToolCall{
{
ID: "tc-1",
Type: "function",
Name: "nil_args_tool",
Arguments: map[string]any{"seed": "value"},
},
},
}, nil
}
p.calls++
return &providers.LLMResponse{
Content: "done",
ToolCalls: []providers.ToolCall{},
}, nil
}
func (p *nilArgsProvider) GetDefaultModel() string {
return "test-model"
}
type nilArgsCaptureTool struct {
receivedNil bool
}
func (t *nilArgsCaptureTool) Name() string {
return "nil_args_tool"
}
func (t *nilArgsCaptureTool) Description() string {
return "captures whether args are nil"
}
func (t *nilArgsCaptureTool) Parameters() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{},
}
}
func (t *nilArgsCaptureTool) Execute(_ context.Context, args map[string]any) *tools.ToolResult {
if args == nil {
t.receivedNil = true
}
return tools.SilentResult("ok")
}
func TestSetPluginManagerInstallsHookRegistry(t *testing.T) { func TestSetPluginManagerInstallsHookRegistry(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "agent-plugin-test-*") tmpDir, err := os.MkdirTemp("", "agent-plugin-test-*")
if err != nil { if err != nil {