|
1 | 1 | package conversation |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "strings" |
4 | 5 | "time" |
5 | 6 |
|
6 | 7 | "ccgo/internal/api/anthropic" |
@@ -46,13 +47,98 @@ func (r Runner) buildRequest(history []contracts.Message, model string, relevant |
46 | 47 | if err != nil { |
47 | 48 | return anthropic.Request{}, err |
48 | 49 | } |
| 50 | + definitions = applyDiscoveredToolReferences(definitions, history) |
49 | 51 | if len(definitions) > 0 { |
50 | 52 | request.Tools = anthropic.ToolsFromContracts(definitions) |
51 | 53 | } |
52 | 54 | } |
53 | 55 | return request, nil |
54 | 56 | } |
55 | 57 |
|
| 58 | +func applyDiscoveredToolReferences(definitions []contracts.ToolDefinition, history []contracts.Message) []contracts.ToolDefinition { |
| 59 | + discovered := discoveredToolReferenceNames(history) |
| 60 | + if len(discovered) == 0 || len(definitions) == 0 { |
| 61 | + return definitions |
| 62 | + } |
| 63 | + out := make([]contracts.ToolDefinition, len(definitions)) |
| 64 | + copy(out, definitions) |
| 65 | + for i := range out { |
| 66 | + if toolDefinitionDiscovered(out[i], discovered) { |
| 67 | + out[i].AlwaysLoad = true |
| 68 | + out[i].ShouldDefer = false |
| 69 | + } |
| 70 | + } |
| 71 | + return out |
| 72 | +} |
| 73 | + |
| 74 | +func toolDefinitionDiscovered(definition contracts.ToolDefinition, discovered map[string]struct{}) bool { |
| 75 | + if _, ok := discovered[strings.ToLower(definition.Name)]; ok { |
| 76 | + return true |
| 77 | + } |
| 78 | + for _, alias := range definition.Aliases { |
| 79 | + if _, ok := discovered[strings.ToLower(alias)]; ok { |
| 80 | + return true |
| 81 | + } |
| 82 | + } |
| 83 | + return false |
| 84 | +} |
| 85 | + |
| 86 | +func discoveredToolReferenceNames(history []contracts.Message) map[string]struct{} { |
| 87 | + discovered := map[string]struct{}{} |
| 88 | + for _, message := range history { |
| 89 | + for _, block := range message.Content { |
| 90 | + if block.Type != contracts.ContentToolResult { |
| 91 | + continue |
| 92 | + } |
| 93 | + collectToolReferenceNames(block.Content, discovered) |
| 94 | + } |
| 95 | + } |
| 96 | + return discovered |
| 97 | +} |
| 98 | + |
| 99 | +func collectToolReferenceNames(content any, discovered map[string]struct{}) { |
| 100 | + switch typed := content.(type) { |
| 101 | + case contracts.ToolReference: |
| 102 | + addDiscoveredToolReference(typed.ToolName, discovered) |
| 103 | + case []contracts.ToolReference: |
| 104 | + for _, reference := range typed { |
| 105 | + addDiscoveredToolReference(reference.ToolName, discovered) |
| 106 | + } |
| 107 | + case map[string]any: |
| 108 | + if toolName, ok := stringMapField(typed, "tool_name", "toolName", "name"); ok && toolReferenceType(typed) { |
| 109 | + addDiscoveredToolReference(toolName, discovered) |
| 110 | + } |
| 111 | + case []map[string]any: |
| 112 | + for _, item := range typed { |
| 113 | + collectToolReferenceNames(item, discovered) |
| 114 | + } |
| 115 | + case []any: |
| 116 | + for _, item := range typed { |
| 117 | + collectToolReferenceNames(item, discovered) |
| 118 | + } |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +func toolReferenceType(item map[string]any) bool { |
| 123 | + value, ok := stringMapField(item, "type") |
| 124 | + return ok && value == "tool_reference" |
| 125 | +} |
| 126 | + |
| 127 | +func stringMapField(item map[string]any, names ...string) (string, bool) { |
| 128 | + for _, name := range names { |
| 129 | + if value, ok := item[name].(string); ok && strings.TrimSpace(value) != "" { |
| 130 | + return strings.TrimSpace(value), true |
| 131 | + } |
| 132 | + } |
| 133 | + return "", false |
| 134 | +} |
| 135 | + |
| 136 | +func addDiscoveredToolReference(toolName string, discovered map[string]struct{}) { |
| 137 | + if trimmed := strings.TrimSpace(toolName); trimmed != "" { |
| 138 | + discovered[strings.ToLower(trimmed)] = struct{}{} |
| 139 | + } |
| 140 | +} |
| 141 | + |
56 | 142 | func appendRelevantMemoryPrefetch(history []contracts.Message, result memory.RelevantMemoryPrefetchResult) []contracts.Message { |
57 | 143 | if len(result.Memories) == 0 { |
58 | 144 | return history |
|
0 commit comments