feat(tool) show tool usage via channel
This commit is contained in:
parent
094d65916d
commit
eca4ede77e
7 changed files with 57 additions and 4 deletions
|
|
@ -203,6 +203,7 @@
|
|||
}
|
||||
},
|
||||
"tools": {
|
||||
"enable_notifications": false,
|
||||
"web": {
|
||||
"brave": {
|
||||
"enabled": false,
|
||||
|
|
|
|||
|
|
@ -668,6 +668,28 @@ func (al *AgentLoop) runLLMIteration(
|
|||
"iteration": iteration,
|
||||
})
|
||||
|
||||
// notify tool use on channel
|
||||
if al.cfg.Tools.EnableNotifications && !constants.IsInternalChannel(opts.Channel) {
|
||||
var notification string
|
||||
|
||||
if tool, ok := agent.Tools.Get(tc.Name); ok {
|
||||
// check the tool implements the interface
|
||||
if notifier, isNotifier := tool.(tools.NotificationFormatter); isNotifier {
|
||||
notification = notifier.FormatNotification(tc.Arguments)
|
||||
} else if tc.Name != "message" {
|
||||
notification = fmt.Sprintf("🛠️ Tool use: `%s`", tc.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if notification != "" {
|
||||
al.bus.PublishOutbound(bus.OutboundMessage{
|
||||
Channel: opts.Channel,
|
||||
ChatID: opts.ChatID,
|
||||
Content: notification,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Create async callback for tools that implement AsyncTool
|
||||
// NOTE: Following openclaw's design, async tools do NOT send results directly to users.
|
||||
// Instead, they notify the agent via PublishInbound, and the agent decides
|
||||
|
|
|
|||
|
|
@ -468,6 +468,7 @@ type ExecConfig struct {
|
|||
}
|
||||
|
||||
type ToolsConfig struct {
|
||||
EnableNotifications bool `json:"enable_notifications" env:"PICOCLAW_TOOLS_ENABLE_NOTIFICATIONS"`
|
||||
Web WebToolsConfig `json:"web"`
|
||||
Cron CronToolsConfig `json:"cron"`
|
||||
Exec ExecConfig `json:"exec"`
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@ func DefaultConfig() *Config {
|
|||
Port: 18790,
|
||||
},
|
||||
Tools: ToolsConfig{
|
||||
EnableNotifications: false,
|
||||
Web: WebToolsConfig{
|
||||
Proxy: "",
|
||||
Brave: BraveConfig{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ type ContextualTool interface {
|
|||
SetContext(channel, chatID string)
|
||||
}
|
||||
|
||||
// NotificationFormatter allows a tool to generate a custom
|
||||
// message to be shown to the user before execution.
|
||||
type NotificationFormatter interface {
|
||||
FormatNotification(args map[string]any) string
|
||||
}
|
||||
|
||||
// AsyncCallback is a function type that async tools use to notify completion.
|
||||
// When an async tool finishes its work, it calls this callback with the result.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/utils"
|
||||
)
|
||||
|
||||
type ExecTool struct {
|
||||
|
|
@ -134,6 +135,13 @@ func (t *ExecTool) Parameters() map[string]any {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *ExecTool) FormatNotification(args map[string]any) string {
|
||||
if cmd, ok := args["command"].(string); ok {
|
||||
return fmt.Sprintf("🛠️ Exec: `%s`", utils.Truncate(cmd, 500))
|
||||
}
|
||||
return "🛠️ Shell command execution in progress"
|
||||
}
|
||||
|
||||
func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult {
|
||||
command, ok := args["command"].(string)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -471,6 +471,13 @@ func (t *WebSearchTool) Parameters() map[string]any {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *WebSearchTool) FormatNotification(args map[string]any) string {
|
||||
if query, ok := args["query"].(string); ok {
|
||||
return fmt.Sprintf("🛠️ Web search: \"%s\"", query)
|
||||
}
|
||||
return "🛠️ Web search in progress"
|
||||
}
|
||||
|
||||
func (t *WebSearchTool) Execute(ctx context.Context, args map[string]any) *ToolResult {
|
||||
query, ok := args["query"].(string)
|
||||
if !ok {
|
||||
|
|
@ -653,6 +660,13 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolRe
|
|||
}
|
||||
}
|
||||
|
||||
func (t *WebFetchTool) FormatNotification(args map[string]any) string {
|
||||
if u, ok := args["url"].(string); ok {
|
||||
return fmt.Sprintf("🛠️ Fetching page: \"%s\"", u)
|
||||
}
|
||||
return "🛠️ Fetching web page in progress"
|
||||
}
|
||||
|
||||
func (t *WebFetchTool) extractText(htmlContent string) string {
|
||||
re := regexp.MustCompile(`<script[\s\S]*?</script>`)
|
||||
result := re.ReplaceAllLiteralString(htmlContent, "")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue