Files
picoclaw/pkg/agent/prompt_contributors.go
T

140 lines
3.2 KiB
Go

package agent
import (
"context"
"fmt"
"strings"
)
type toolDiscoveryPromptContributor struct {
useBM25 bool
useRegex bool
}
func (c toolDiscoveryPromptContributor) PromptSource() PromptSourceDescriptor {
return PromptSourceDescriptor{
ID: PromptSourceToolDiscovery,
Owner: "tools",
Description: "Tool discovery instructions",
Allowed: []PromptPlacement{{Layer: PromptLayerCapability, Slot: PromptSlotTooling}},
StableByDefault: true,
}
}
func (c toolDiscoveryPromptContributor) ContributePrompt(
_ context.Context,
_ PromptBuildRequest,
) ([]PromptPart, error) {
content := formatToolDiscoveryRule(c.useBM25, c.useRegex)
if strings.TrimSpace(content) == "" {
return nil, nil
}
return []PromptPart{
{
ID: "capability.tool_discovery",
Layer: PromptLayerCapability,
Slot: PromptSlotTooling,
Source: PromptSource{ID: PromptSourceToolDiscovery, Name: "tool_registry:discovery"},
Title: "tool discovery",
Content: content,
Stable: true,
Cache: PromptCacheEphemeral,
},
}, nil
}
type mcpServerPromptContributor struct {
serverName string
toolCount int
deferred bool
}
func (c mcpServerPromptContributor) PromptSource() PromptSourceDescriptor {
return PromptSourceDescriptor{
ID: mcpPromptSourceID(c.serverName),
Owner: "mcp",
Description: fmt.Sprintf("MCP server %q capability prompt", c.serverName),
Allowed: []PromptPlacement{{Layer: PromptLayerCapability, Slot: PromptSlotMCP}},
StableByDefault: true,
}
}
func (c mcpServerPromptContributor) ContributePrompt(
_ context.Context,
_ PromptBuildRequest,
) ([]PromptPart, error) {
serverName := strings.TrimSpace(c.serverName)
if serverName == "" || c.toolCount <= 0 {
return nil, nil
}
availability := "available as native tools"
if c.deferred {
availability = "hidden behind tool discovery until unlocked"
}
return []PromptPart{
{
ID: "capability.mcp." + promptSourceComponent(serverName),
Layer: PromptLayerCapability,
Slot: PromptSlotMCP,
Source: PromptSource{ID: mcpPromptSourceID(serverName), Name: "mcp:" + serverName},
Title: "MCP server capability",
Content: fmt.Sprintf(
"MCP server `%s` is connected. It contributes %d tool(s), currently %s.",
serverName,
c.toolCount,
availability,
),
Stable: true,
Cache: PromptCacheEphemeral,
},
}, nil
}
func mcpPromptSourceID(serverName string) PromptSourceID {
return PromptSourceID("mcp:" + promptSourceComponent(serverName))
}
func promptSourceComponent(value string) string {
const maxLen = 64
value = strings.ToLower(strings.TrimSpace(value))
if value == "" {
return "unnamed"
}
var b strings.Builder
lastWasSep := false
for _, r := range value {
switch {
case r >= 'a' && r <= 'z':
b.WriteRune(r)
lastWasSep = false
case r >= '0' && r <= '9':
b.WriteRune(r)
lastWasSep = false
case r == '-' || r == '_':
if !lastWasSep && b.Len() > 0 {
b.WriteRune(r)
lastWasSep = true
}
default:
if !lastWasSep && b.Len() > 0 {
b.WriteRune('_')
lastWasSep = true
}
}
}
result := strings.Trim(b.String(), "_")
if result == "" {
return "unnamed"
}
if len(result) > maxLen {
return result[:maxLen]
}
return result
}