@@ -108,7 +108,7 @@ import { getMessagesSinceLastSummary, summarizeConversation } from "../condense"
108
108
import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
109
109
import { restoreTodoListForTask } from "../tools/updateTodoListTool"
110
110
import { AutoApprovalHandler } from "./AutoApprovalHandler"
111
- import { StreamingToolCallProcessor , handleOpenaiToolCallStreaming } from "./tool-call-helper"
111
+ import { StreamingToolCallProcessor , ToolCallParam , handleOpenaiToolCallStreaming } from "./tool-call-helper"
112
112
import { ToolArgs } from "../prompts/tools/types"
113
113
114
114
const MAX_EXPONENTIAL_BACKOFF_SECONDS = 600 // 10 minutes
@@ -272,7 +272,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
272
272
assistantMessageContent : AssistantMessageContent [ ] = [ ]
273
273
presentAssistantMessageLocked = false
274
274
presentAssistantMessageHasPendingUpdates = false
275
- userMessageContent : ( Anthropic . TextBlockParam | Anthropic . ImageBlockParam ) [ ] = [ ]
275
+ userMessageContent : ( Anthropic . TextBlockParam | Anthropic . ImageBlockParam | Anthropic . ToolResultBlockParam ) [ ] = [ ]
276
276
userMessageContentReady = false
277
277
didRejectTool = false
278
278
didAlreadyUseTool = false
@@ -1211,41 +1211,41 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1211
1211
// Make sure that the api conversation history can be resumed by the API,
1212
1212
// even if it goes out of sync with cline messages.
1213
1213
let existingApiConversationHistory : ApiMessage [ ] = await this . getSavedApiConversationHistory ( )
1214
-
1215
- // v2.0 xml tags refactor caveat: since we don't use tools anymore, we need to replace all tool use blocks with a text block since the API disallows conversations with tool uses and no tool schema
1216
- const conversationWithoutToolBlocks = existingApiConversationHistory . map ( ( message ) => {
1217
- if ( Array . isArray ( message . content ) ) {
1218
- const newContent = message . content . map ( ( block ) => {
1219
- if ( block . type === "tool_use" ) {
1220
- // It's important we convert to the new tool schema
1221
- // format so the model doesn't get confused about how to
1222
- // invoke tools.
1223
- const inputAsXml = Object . entries ( block . input as Record < string , string > )
1224
- . map ( ( [ key , value ] ) => `< ${ key } >\n ${ value } \n</ ${ key } >` )
1225
- . join ( "\n" )
1226
- return {
1227
- type : "text" ,
1228
- text : `< ${ block . name } >\n ${ inputAsXml } \n</ ${ block . name } >` ,
1229
- } as Anthropic . Messages . TextBlockParam
1230
- } else if ( block . type === "tool_result" ) {
1231
- // Convert block.content to text block array, removing images
1232
- const contentAsTextBlocks = Array . isArray ( block . content )
1233
- ? block . content . filter ( ( item ) => item . type === "text" )
1234
- : [ { type : "text" , text : block . content } ]
1235
- const textContent = contentAsTextBlocks . map ( ( item ) => item . text ) . join ( "\n\n" )
1236
- const toolName = findToolName ( block . tool_use_id , existingApiConversationHistory )
1237
- return {
1238
- type : "text" ,
1239
- text : `[ ${ toolName } Result]\n\n ${ textContent } ` ,
1240
- } as Anthropic . Messages . TextBlockParam
1241
- }
1242
- return block
1243
- } )
1244
- return { ... message , content : newContent }
1245
- }
1246
- return message
1247
- } )
1248
- existingApiConversationHistory = conversationWithoutToolBlocks
1214
+ if ( this . apiConfiguration . toolCallEnabled !== true ) {
1215
+ const conversationWithoutToolBlocks = existingApiConversationHistory . map ( ( message ) => {
1216
+ if ( Array . isArray ( message . content ) ) {
1217
+ const newContent = message . content . map ( ( block ) => {
1218
+ if ( block . type === "tool_use" ) {
1219
+ // It's important we convert to the new tool schema
1220
+ // format so the model doesn't get confused about how to
1221
+ // invoke tools.
1222
+ const inputAsXml = Object . entries ( block . input as Record < string , string > )
1223
+ . map ( ( [ key , value ] ) => `< ${ key } >\n ${ value } \n</ ${ key } >` )
1224
+ . join ( "\n" )
1225
+ return {
1226
+ type : "text" ,
1227
+ text : `< ${ block . name } >\n ${ inputAsXml } \n</ ${ block . name } >` ,
1228
+ } as Anthropic . Messages . TextBlockParam
1229
+ } else if ( block . type === "tool_result" ) {
1230
+ // Convert block.content to text block array, removing images
1231
+ const contentAsTextBlocks = Array . isArray ( block . content )
1232
+ ? block . content . filter ( ( item ) => item . type === "text" )
1233
+ : [ { type : "text" , text : block . content } ]
1234
+ const textContent = contentAsTextBlocks . map ( ( item ) => item . text ) . join ( "\n\n" )
1235
+ const toolName = findToolName ( block . tool_use_id , existingApiConversationHistory )
1236
+ return {
1237
+ type : "text" ,
1238
+ text : `[ ${ toolName } Result]\n\n ${ textContent } ` ,
1239
+ } as Anthropic . Messages . TextBlockParam
1240
+ }
1241
+ return block
1242
+ } )
1243
+ return { ... message , content : newContent }
1244
+ }
1245
+ return message
1246
+ } )
1247
+ existingApiConversationHistory = conversationWithoutToolBlocks
1248
+ }
1249
1249
1250
1250
// FIXME: remove tool use blocks altogether
1251
1251
@@ -1794,13 +1794,15 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1794
1794
case "text" :
1795
1795
case "tool_call" : {
1796
1796
let chunkContent
1797
+ let toolParam : ToolCallParam | undefined
1797
1798
if ( chunk . type == "tool_call" ) {
1798
- chunkContent =
1799
+ toolParam =
1799
1800
handleOpenaiToolCallStreaming (
1800
1801
this . streamingToolCallProcessor ,
1801
1802
chunk . toolCalls ,
1802
1803
chunk . toolCallType ,
1803
1804
) ?? ""
1805
+ chunkContent = toolParam . chunkContent
1804
1806
} else {
1805
1807
chunkContent = chunk . text
1806
1808
}
@@ -1809,11 +1811,13 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1809
1811
// Parse raw assistant message chunk into content blocks.
1810
1812
const prevLength = this . assistantMessageContent . length
1811
1813
if ( this . isAssistantMessageParserEnabled && this . assistantMessageParser ) {
1812
- this . assistantMessageContent =
1813
- this . assistantMessageParser . processChunk ( chunkContent )
1814
+ this . assistantMessageContent = this . assistantMessageParser . processChunk (
1815
+ chunkContent ,
1816
+ toolParam ,
1817
+ )
1814
1818
} else {
1815
1819
// Use the old parsing method when experiment is disabled
1816
- this . assistantMessageContent = parseAssistantMessage ( assistantMessage )
1820
+ this . assistantMessageContent = parseAssistantMessage ( assistantMessage , toolParam )
1817
1821
}
1818
1822
1819
1823
if ( this . assistantMessageContent . length > prevLength ) {
@@ -2107,10 +2111,34 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
2107
2111
let didEndLoop = false
2108
2112
2109
2113
if ( assistantMessage . length > 0 ) {
2110
- await this . addToApiConversationHistory ( {
2111
- role : "assistant" ,
2112
- content : [ { type : "text" , text : assistantMessage } ] ,
2113
- } )
2114
+ if ( this . apiConfiguration . toolCallEnabled !== true ) {
2115
+ await this . addToApiConversationHistory ( {
2116
+ role : "assistant" ,
2117
+ content : [ { type : "text" , text : assistantMessage } ] ,
2118
+ } )
2119
+ } else {
2120
+ for ( const block of this . assistantMessageContent ) {
2121
+ if ( block . type === "text" && block . content ) {
2122
+ await this . addToApiConversationHistory ( {
2123
+ role : "assistant" ,
2124
+ content : [ { type : "text" , text : block . content } ] ,
2125
+ } )
2126
+ }
2127
+ if ( block . type === "tool_use" && block . toolUseId && block . toolUseParam ) {
2128
+ await this . addToApiConversationHistory ( {
2129
+ role : "assistant" ,
2130
+ content : [
2131
+ {
2132
+ type : "tool_use" ,
2133
+ id : block . toolUseId ,
2134
+ name : block . name ,
2135
+ input : block . toolUseParam . input ,
2136
+ } ,
2137
+ ] ,
2138
+ } )
2139
+ }
2140
+ }
2141
+ }
2114
2142
2115
2143
TelemetryService . instance . captureConversationMessage ( this . taskId , "assistant" )
2116
2144
0 commit comments