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": {
|
"tools": {
|
||||||
|
"enable_notifications": false,
|
||||||
"web": {
|
"web": {
|
||||||
"brave": {
|
"brave": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
|
|
||||||
|
|
@ -668,6 +668,28 @@ func (al *AgentLoop) runLLMIteration(
|
||||||
"iteration": iteration,
|
"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
|
// Create async callback for tools that implement AsyncTool
|
||||||
// NOTE: Following openclaw's design, async tools do NOT send results directly to users.
|
// 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
|
// Instead, they notify the agent via PublishInbound, and the agent decides
|
||||||
|
|
|
||||||
|
|
@ -468,6 +468,7 @@ type ExecConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolsConfig struct {
|
type ToolsConfig struct {
|
||||||
|
EnableNotifications bool `json:"enable_notifications" env:"PICOCLAW_TOOLS_ENABLE_NOTIFICATIONS"`
|
||||||
Web WebToolsConfig `json:"web"`
|
Web WebToolsConfig `json:"web"`
|
||||||
Cron CronToolsConfig `json:"cron"`
|
Cron CronToolsConfig `json:"cron"`
|
||||||
Exec ExecConfig `json:"exec"`
|
Exec ExecConfig `json:"exec"`
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,7 @@ func DefaultConfig() *Config {
|
||||||
Port: 18790,
|
Port: 18790,
|
||||||
},
|
},
|
||||||
Tools: ToolsConfig{
|
Tools: ToolsConfig{
|
||||||
|
EnableNotifications: false,
|
||||||
Web: WebToolsConfig{
|
Web: WebToolsConfig{
|
||||||
Proxy: "",
|
Proxy: "",
|
||||||
Brave: BraveConfig{
|
Brave: BraveConfig{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,12 @@ type ContextualTool interface {
|
||||||
SetContext(channel, chatID string)
|
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.
|
// 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.
|
// When an async tool finishes its work, it calls this callback with the result.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sipeed/picoclaw/pkg/config"
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExecTool struct {
|
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 {
|
func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult {
|
||||||
command, ok := args["command"].(string)
|
command, ok := args["command"].(string)
|
||||||
if !ok {
|
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 {
|
func (t *WebSearchTool) Execute(ctx context.Context, args map[string]any) *ToolResult {
|
||||||
query, ok := args["query"].(string)
|
query, ok := args["query"].(string)
|
||||||
if !ok {
|
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 {
|
func (t *WebFetchTool) extractText(htmlContent string) string {
|
||||||
re := regexp.MustCompile(`<script[\s\S]*?</script>`)
|
re := regexp.MustCompile(`<script[\s\S]*?</script>`)
|
||||||
result := re.ReplaceAllLiteralString(htmlContent, "")
|
result := re.ReplaceAllLiteralString(htmlContent, "")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue