@@ -55,24 +55,57 @@ class AnthropicProvider extends Provider {
55
55
// For array content, we need special handling for tool use sequences
56
56
if ( msg . content . some ( ( item ) => item . type === "tool_use" ) ) {
57
57
// If this is a tool_use message, we only need the tool_use part to be valid
58
- return msg . content . some (
58
+ const hasValidToolUse = msg . content . some (
59
59
( item ) => item . type === "tool_use" && item . name && item . id
60
60
) ;
61
+
62
+ // Ensure there's at least one valid text content if tool_use exists
63
+ const hasValidText = msg . content . some (
64
+ ( item ) =>
65
+ item . type === "text" && item . text && item . text . trim ( ) . length > 0
66
+ ) ;
67
+
68
+ return hasValidToolUse && hasValidText ;
61
69
}
62
70
63
- // For other array content, ensure each item has required fields
71
+ // For other array content, ensure each item has required fields and is non-empty
64
72
return msg . content . every ( ( item ) => {
65
- if ( item . type === "text" )
73
+ if ( item . type === "text" ) {
66
74
return item . text && item . text . trim ( ) . length > 0 ;
67
- if ( item . type === "tool_result" )
68
- return item . tool_use_id && item . content ;
75
+ }
76
+ if ( item . type === "tool_result" ) {
77
+ return (
78
+ item . tool_use_id &&
79
+ item . content &&
80
+ ( typeof item . content === "string"
81
+ ? item . content . trim ( ) . length > 0
82
+ : JSON . stringify ( item . content ) . length > 2 )
83
+ ) ;
84
+ }
69
85
return false ;
70
86
} ) ;
71
87
}
72
88
return false ;
73
89
} )
74
90
. map ( ( msg ) => {
75
91
const { role, content } = msg ;
92
+ // For array content, ensure we have a valid text message
93
+ if (
94
+ Array . isArray ( content ) &&
95
+ content . some ( ( item ) => item . type === "tool_use" )
96
+ ) {
97
+ const textContent = content . find ( ( item ) => item . type === "text" ) ;
98
+ if (
99
+ ! textContent ||
100
+ ! textContent . text ||
101
+ ! textContent . text . trim ( ) . length
102
+ ) {
103
+ content . unshift ( {
104
+ type : "text" ,
105
+ text : "I'll use a tool to help answer this question." ,
106
+ } ) ;
107
+ }
108
+ }
76
109
return { role, content } ;
77
110
} ) ;
78
111
}
@@ -84,27 +117,27 @@ class AnthropicProvider extends Provider {
84
117
[ ...messages ] . forEach ( ( msg , i ) => {
85
118
if ( msg . role !== "function" ) return normalized . push ( msg ) ;
86
119
87
- // If the last message is a role "function" this is our special aibitat message node.
88
- // and we need to remove it from the array of messages.
89
- // Since Anthropic needs to have the tool call resolved, we look at the previous chat to "function"
90
- // and go through its content "thought" from ~ln:143 and get the tool_call id so we can resolve
91
- // this tool call properly.
92
120
const functionCompletion = msg ;
93
121
const toolCallId = messages [ i - 1 ] ?. content ?. find (
94
122
( msg ) => msg . type === "tool_use"
95
123
) ?. id ;
96
124
97
- // Append the Anthropic acceptable node to the message chain so function can resolve.
98
- normalized . push ( {
99
- role : "user" ,
100
- content : [
101
- {
102
- type : "tool_result" ,
103
- tool_use_id : toolCallId ,
104
- content : functionCompletion . content ,
105
- } ,
106
- ] ,
107
- } ) ;
125
+ // Skip if we can't find a matching tool_use
126
+ if ( ! toolCallId ) return ;
127
+
128
+ // Only add if we have actual content
129
+ if ( functionCompletion . content ) {
130
+ normalized . push ( {
131
+ role : "user" ,
132
+ content : [
133
+ {
134
+ type : "tool_result" ,
135
+ tool_use_id : toolCallId ,
136
+ content : functionCompletion . content ,
137
+ } ,
138
+ ] ,
139
+ } ) ;
140
+ }
108
141
} ) ;
109
142
return normalized ;
110
143
}
@@ -225,7 +258,7 @@ class AnthropicProvider extends Provider {
225
258
}
226
259
}
227
260
228
- if ( ! ! result . functionCall ) {
261
+ if ( result . functionCall ) {
229
262
result . functionCall . arguments = safeJsonParse (
230
263
result . functionCall . arguments ,
231
264
{ }
0 commit comments