Merge pull request #7 from dj-oyu/fix/think-tag-leak-and-search-log
fix: strip think tags from heartbeat and log web search provider
This commit is contained in:
commit
9008f3fc72
4 changed files with 43 additions and 7 deletions
|
|
@ -80,6 +80,11 @@ func gatewayCmd(debug bool, orchestration bool, enableStats bool) error {
|
||||||
toolsInfo := startupInfo["tools"].(map[string]any)
|
toolsInfo := startupInfo["tools"].(map[string]any)
|
||||||
skillsInfo := startupInfo["skills"].(map[string]any)
|
skillsInfo := startupInfo["skills"].(map[string]any)
|
||||||
fmt.Printf(" • Tools: %d loaded\n", toolsInfo["count"])
|
fmt.Printf(" • Tools: %d loaded\n", toolsInfo["count"])
|
||||||
|
if wsProvider, ok := toolsInfo["web_search_provider"].(string); ok {
|
||||||
|
fmt.Printf(" • Web search: %s\n", wsProvider)
|
||||||
|
} else {
|
||||||
|
fmt.Println(" • Web search: disabled")
|
||||||
|
}
|
||||||
fmt.Printf(" • Skills: %d/%d available\n",
|
fmt.Printf(" • Skills: %d/%d available\n",
|
||||||
skillsInfo["available"],
|
skillsInfo["available"],
|
||||||
skillsInfo["total"])
|
skillsInfo["total"])
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,14 @@ func registerSharedTools(
|
||||||
Proxy: cfg.Tools.Web.Proxy,
|
Proxy: cfg.Tools.Web.Proxy,
|
||||||
}); searchTool != nil {
|
}); searchTool != nil {
|
||||||
agent.Tools.Register(searchTool)
|
agent.Tools.Register(searchTool)
|
||||||
|
logger.InfoCF("agent", "Web search provider registered", map[string]any{
|
||||||
|
"agent_id": agentID,
|
||||||
|
"provider": searchTool.ProviderName(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.WarnCF("agent", "No web search provider configured", map[string]any{
|
||||||
|
"agent_id": agentID,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
agent.Tools.Register(tools.NewWebFetchToolWithProxy(50000, cfg.Tools.Web.Proxy))
|
agent.Tools.Register(tools.NewWebFetchToolWithProxy(50000, cfg.Tools.Web.Proxy))
|
||||||
|
|
||||||
|
|
@ -2775,7 +2783,7 @@ func (al *AgentLoop) runLLMIteration(
|
||||||
"prompt_cache_key": agent.ID,
|
"prompt_cache_key": agent.ID,
|
||||||
})
|
})
|
||||||
if forceErr == nil && forceResp.Content != "" {
|
if forceErr == nil && forceResp.Content != "" {
|
||||||
finalContent = forceResp.Content
|
finalContent = utils.StripThinkBlocks(forceResp.Content)
|
||||||
if forceResp.Usage != nil && al.stats != nil {
|
if forceResp.Usage != nil && al.stats != nil {
|
||||||
al.stats.RecordUsage(
|
al.stats.RecordUsage(
|
||||||
forceResp.Usage.PromptTokens,
|
forceResp.Usage.PromptTokens,
|
||||||
|
|
@ -2896,10 +2904,17 @@ func (al *AgentLoop) GetStartupInfo() map[string]any {
|
||||||
|
|
||||||
// Tools info
|
// Tools info
|
||||||
toolsList := agent.Tools.List()
|
toolsList := agent.Tools.List()
|
||||||
info["tools"] = map[string]any{
|
toolsMap := map[string]any{
|
||||||
"count": len(toolsList),
|
"count": len(toolsList),
|
||||||
"names": toolsList,
|
"names": toolsList,
|
||||||
}
|
}
|
||||||
|
// Report web search provider if registered
|
||||||
|
if t, ok := agent.Tools.Get("web_search"); ok {
|
||||||
|
if wst, ok := t.(*tools.WebSearchTool); ok {
|
||||||
|
toolsMap["web_search_provider"] = wst.ProviderName()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info["tools"] = toolsMap
|
||||||
|
|
||||||
// Skills info
|
// Skills info
|
||||||
info["skills"] = agent.ContextBuilder.GetSkillsInfo()
|
info["skills"] = agent.ContextBuilder.GetSkillsInfo()
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/sipeed/picoclaw/pkg/logger"
|
"github.com/sipeed/picoclaw/pkg/logger"
|
||||||
"github.com/sipeed/picoclaw/pkg/state"
|
"github.com/sipeed/picoclaw/pkg/state"
|
||||||
"github.com/sipeed/picoclaw/pkg/tools"
|
"github.com/sipeed/picoclaw/pkg/tools"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -308,8 +309,11 @@ Add your heartbeat tasks below this line:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendResponse sends the heartbeat response to the last channel
|
// sendResponse sends the heartbeat response to the last channel.
|
||||||
|
// Think blocks are stripped as a safety net to prevent LLM reasoning
|
||||||
|
// artifacts from leaking into user-facing messages.
|
||||||
func (hs *HeartbeatService) sendResponse(response string) {
|
func (hs *HeartbeatService) sendResponse(response string) {
|
||||||
|
response = utils.StripThinkBlocks(response)
|
||||||
hs.mu.RLock()
|
hs.mu.RLock()
|
||||||
msgBus := hs.bus
|
msgBus := hs.bus
|
||||||
hs.mu.RUnlock()
|
hs.mu.RUnlock()
|
||||||
|
|
|
||||||
|
|
@ -387,8 +387,14 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebSearchTool struct {
|
type WebSearchTool struct {
|
||||||
provider SearchProvider
|
provider SearchProvider
|
||||||
maxResults int
|
providerName string
|
||||||
|
maxResults int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderName returns the name of the active search provider (e.g. "brave", "perplexity").
|
||||||
|
func (t *WebSearchTool) ProviderName() string {
|
||||||
|
return t.providerName
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebSearchToolOptions struct {
|
type WebSearchToolOptions struct {
|
||||||
|
|
@ -409,16 +415,19 @@ type WebSearchToolOptions struct {
|
||||||
|
|
||||||
func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
|
func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
|
||||||
var provider SearchProvider
|
var provider SearchProvider
|
||||||
|
var providerName string
|
||||||
maxResults := 5
|
maxResults := 5
|
||||||
|
|
||||||
// Priority: Perplexity > Brave > Tavily > DuckDuckGo
|
// Priority: Perplexity > Brave > Tavily > DuckDuckGo
|
||||||
if opts.PerplexityEnabled && opts.PerplexityAPIKey != "" {
|
if opts.PerplexityEnabled && opts.PerplexityAPIKey != "" {
|
||||||
provider = &PerplexitySearchProvider{apiKey: opts.PerplexityAPIKey, proxy: opts.Proxy}
|
provider = &PerplexitySearchProvider{apiKey: opts.PerplexityAPIKey, proxy: opts.Proxy}
|
||||||
|
providerName = "perplexity"
|
||||||
if opts.PerplexityMaxResults > 0 {
|
if opts.PerplexityMaxResults > 0 {
|
||||||
maxResults = opts.PerplexityMaxResults
|
maxResults = opts.PerplexityMaxResults
|
||||||
}
|
}
|
||||||
} else if opts.BraveEnabled && opts.BraveAPIKey != "" {
|
} else if opts.BraveEnabled && opts.BraveAPIKey != "" {
|
||||||
provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey, proxy: opts.Proxy}
|
provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey, proxy: opts.Proxy}
|
||||||
|
providerName = "brave"
|
||||||
if opts.BraveMaxResults > 0 {
|
if opts.BraveMaxResults > 0 {
|
||||||
maxResults = opts.BraveMaxResults
|
maxResults = opts.BraveMaxResults
|
||||||
}
|
}
|
||||||
|
|
@ -428,11 +437,13 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
|
||||||
baseURL: opts.TavilyBaseURL,
|
baseURL: opts.TavilyBaseURL,
|
||||||
proxy: opts.Proxy,
|
proxy: opts.Proxy,
|
||||||
}
|
}
|
||||||
|
providerName = "tavily"
|
||||||
if opts.TavilyMaxResults > 0 {
|
if opts.TavilyMaxResults > 0 {
|
||||||
maxResults = opts.TavilyMaxResults
|
maxResults = opts.TavilyMaxResults
|
||||||
}
|
}
|
||||||
} else if opts.DuckDuckGoEnabled {
|
} else if opts.DuckDuckGoEnabled {
|
||||||
provider = &DuckDuckGoSearchProvider{proxy: opts.Proxy}
|
provider = &DuckDuckGoSearchProvider{proxy: opts.Proxy}
|
||||||
|
providerName = "duckduckgo"
|
||||||
if opts.DuckDuckGoMaxResults > 0 {
|
if opts.DuckDuckGoMaxResults > 0 {
|
||||||
maxResults = opts.DuckDuckGoMaxResults
|
maxResults = opts.DuckDuckGoMaxResults
|
||||||
}
|
}
|
||||||
|
|
@ -441,8 +452,9 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &WebSearchTool{
|
return &WebSearchTool{
|
||||||
provider: provider,
|
provider: provider,
|
||||||
maxResults: maxResults,
|
providerName: providerName,
|
||||||
|
maxResults: maxResults,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue