108 lines
2.3 KiB
Go
108 lines
2.3 KiB
Go
package agent
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"ollie/embedding"
|
|
"ollie/skills"
|
|
"ollie/toolsrv/protocol"
|
|
)
|
|
|
|
// Tool matching configuration.
|
|
const (
|
|
toolMatchThreshold = 0.35
|
|
toolMatchLimit = 5
|
|
)
|
|
|
|
var (
|
|
// Shared embedding model for tool matching.
|
|
toolEmbedModel *embedding.Model
|
|
toolEmbedErr error
|
|
toolEmbedOnce sync.Once
|
|
)
|
|
|
|
// getToolEmbedModel returns the shared embedding model, loading it on first call.
|
|
func getToolEmbedModel() *embedding.Model {
|
|
toolEmbedOnce.Do(func() {
|
|
toolEmbedModel, toolEmbedErr = embedding.LoadModel(skills.DefaultModelDir())
|
|
})
|
|
return toolEmbedModel
|
|
}
|
|
|
|
// matchTools finds tools relevant to the user's input from the loaded tools
|
|
// and returns a hint block telling the model to call them.
|
|
func matchTools(input string, tools []protocol.ToolInfo) string {
|
|
if len(tools) == 0 {
|
|
return ""
|
|
}
|
|
|
|
model := getToolEmbedModel()
|
|
if model == nil {
|
|
return ""
|
|
}
|
|
|
|
// Convert tools to embedding items
|
|
items := make([]embedding.Item, 0, len(tools))
|
|
for _, ti := range tools {
|
|
if ti.Description == "" {
|
|
continue
|
|
}
|
|
searchText := ti.Description
|
|
if ti.Prompt != "" {
|
|
searchText += " Usage: " + ti.Prompt
|
|
}
|
|
items = append(items, embedding.Item{
|
|
Name: ti.Name,
|
|
Description: searchText,
|
|
})
|
|
}
|
|
if len(items) == 0 {
|
|
return ""
|
|
}
|
|
|
|
// Build index and match
|
|
idx, err := embedding.NewIndex(model, items)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
workflowText := normalizeWorkflow(input).SearchText()
|
|
workflow := normalizeWorkflow(input)
|
|
searchInput := input
|
|
if workflowText != "" {
|
|
searchInput += " Workflow: " + workflowText
|
|
}
|
|
|
|
results, err := idx.Match(searchInput, toolMatchThreshold, toolMatchLimit)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
// Apply workflow adjustments
|
|
for i := range results {
|
|
results[i].Score += workflowToolAdjustment(results[i].Item.Name, workflow)
|
|
}
|
|
sort.SliceStable(results, func(i, j int) bool {
|
|
return results[i].Score > results[j].Score
|
|
})
|
|
|
|
if len(results) == 0 {
|
|
return ""
|
|
}
|
|
|
|
var sb strings.Builder
|
|
sb.WriteString("<tool-hints>\n")
|
|
sb.WriteString("Relevant tools for this request:\n\n")
|
|
for _, r := range results {
|
|
sb.WriteString("→ `")
|
|
sb.WriteString(r.Item.Name)
|
|
sb.WriteString("({...})` — ")
|
|
sb.WriteString(r.Item.Description)
|
|
sb.WriteString("\n")
|
|
}
|
|
sb.WriteString("</tool-hints>\n")
|
|
return sb.String()
|
|
}
|