@@ -7,32 +7,58 @@ const SYNTHETIC_MESSAGE_ID = "msg_01234567890123456789012345"
77const SYNTHETIC_PART_ID = "prt_01234567890123456789012345"
88const SYNTHETIC_CALL_ID = "call_01234567890123456789012345"
99
10+ const isGeminiModel = ( modelID : string ) : boolean => {
11+ const lowerModelID = modelID . toLowerCase ( )
12+ return lowerModelID . includes ( "gemini" )
13+ }
14+
1015export const createSyntheticAssistantMessageWithToolPart = (
1116 baseMessage : WithParts ,
1217 content : string ,
1318 variant ?: string ,
1419) : WithParts => {
1520 const userInfo = baseMessage . info as UserMessage
1621 const now = Date . now ( )
17- return {
18- info : {
19- id : SYNTHETIC_MESSAGE_ID ,
20- sessionID : userInfo . sessionID ,
21- role : "assistant" ,
22- agent : userInfo . agent || "code" ,
23- parentID : userInfo . id ,
24- modelID : userInfo . model . modelID ,
25- providerID : userInfo . model . providerID ,
26- mode : "default" ,
27- path : {
28- cwd : "/" ,
29- root : "/" ,
30- } ,
31- time : { created : now , completed : now } ,
32- cost : 0 ,
33- tokens : { input : 0 , output : 0 , reasoning : 0 , cache : { read : 0 , write : 0 } } ,
34- ...( variant !== undefined && { variant } ) ,
22+
23+ const baseInfo = {
24+ id : SYNTHETIC_MESSAGE_ID ,
25+ sessionID : userInfo . sessionID ,
26+ role : "assistant" as const ,
27+ agent : userInfo . agent || "code" ,
28+ parentID : userInfo . id ,
29+ modelID : userInfo . model . modelID ,
30+ providerID : userInfo . model . providerID ,
31+ mode : "default" ,
32+ path : {
33+ cwd : "/" ,
34+ root : "/" ,
3535 } ,
36+ time : { created : now , completed : now } ,
37+ cost : 0 ,
38+ tokens : { input : 0 , output : 0 , reasoning : 0 , cache : { read : 0 , write : 0 } } ,
39+ ...( variant !== undefined && { variant } ) ,
40+ }
41+
42+ // For Gemini models, inject as text to avoid thought signature requirements
43+ // Gemini 3+ has strict validation requiring thoughtSignature on functionCall parts
44+ if ( isGeminiModel ( userInfo . model . modelID ) ) {
45+ return {
46+ info : baseInfo ,
47+ parts : [
48+ {
49+ id : SYNTHETIC_PART_ID ,
50+ sessionID : userInfo . sessionID ,
51+ messageID : SYNTHETIC_MESSAGE_ID ,
52+ type : "text" ,
53+ text : content ,
54+ } ,
55+ ] ,
56+ }
57+ }
58+
59+ // For other models, use tool part for cleaner context
60+ return {
61+ info : baseInfo ,
3662 parts : [
3763 {
3864 id : SYNTHETIC_PART_ID ,
@@ -207,23 +233,3 @@ export const isIgnoredUserMessage = (message: WithParts): boolean => {
207233
208234 return true
209235}
210-
211- export const hasReasoningInCurrentAssistantTurn = ( messages : WithParts [ ] ) : boolean => {
212- for ( let i = messages . length - 1 ; i >= 0 ; i -- ) {
213- const message = messages [ i ]
214- if ( message . info ?. role === "user" ) {
215- if ( isIgnoredUserMessage ( message ) ) {
216- continue
217- }
218- return false
219- }
220- if ( message . info ?. role === "assistant" && message . parts ) {
221- for ( const part of message . parts ) {
222- if ( part . type === "reasoning" ) {
223- return true
224- }
225- }
226- }
227- }
228- return false
229- }
0 commit comments