@@ -2,6 +2,7 @@ package proxy
22
33import (
44 "encoding/json"
5+ "fmt"
56 "strings"
67
78 "github.com/dev2k6/command-code-proxy-server/internal/api"
@@ -10,24 +11,34 @@ import (
1011// Convert OpenAI messages to CommandCode format
1112func ConvertMessages (openAIMsgs []api.OpenAIMessage ) []api.CCMessage {
1213 var ccMsgs []api.CCMessage
14+ toolNames := map [string ]string {}
15+
1316 for _ , m := range openAIMsgs {
14- // Convert tool role to user with tool-result type
17+ for _ , tc := range m .ToolCalls {
18+ if tc .ID != "" && tc .Function .Name != "" {
19+ toolNames [tc .ID ] = tc .Function .Name
20+ }
21+ }
22+
1523 if m .Role == "tool" {
24+ toolName := m .Name
25+ if toolName == "" {
26+ toolName = toolNames [m .ToolCallID ]
27+ }
1628 ccMsgs = append (ccMsgs , api.CCMessage {
1729 Role : "user" ,
1830 Content : []api.CCContentPart {{
1931 Type : "tool-result" ,
2032 ToolCallID : strPtr (m .ToolCallID ),
21- ToolName : strPtr (m . Name ),
33+ ToolName : strPtr (toolName ),
2234 Text : strPtr (contentToString (m .Content )),
2335 }},
2436 })
2537 continue
2638 }
2739
28- // Convert assistant with tool_calls
2940 if m .Role == "assistant" && len (m .ToolCalls ) > 0 {
30- contentParts := parseContent (m .Content )
41+ contentParts := parseContent (m .Content , toolNames )
3142 for _ , tc := range m .ToolCalls {
3243 contentParts = append (contentParts , api.CCContentPart {
3344 Type : "tool_use" ,
@@ -36,18 +47,11 @@ func ConvertMessages(openAIMsgs []api.OpenAIMessage) []api.CCMessage {
3647 Input : parseToolInput (tc .Function .Arguments ),
3748 })
3849 }
39- ccMsgs = append (ccMsgs , api.CCMessage {
40- Role : m .Role ,
41- Content : contentParts ,
42- })
50+ ccMsgs = append (ccMsgs , api.CCMessage {Role : m .Role , Content : contentParts })
4351 continue
4452 }
4553
46- contentParts := parseContent (m .Content )
47- ccMsgs = append (ccMsgs , api.CCMessage {
48- Role : m .Role ,
49- Content : contentParts ,
50- })
54+ ccMsgs = append (ccMsgs , api.CCMessage {Role : m .Role , Content : parseContent (m .Content , toolNames )})
5155 }
5256 return ccMsgs
5357}
@@ -85,10 +89,7 @@ func ConvertTools(openAITools []any) []any {
8589 inputSchema = map [string ]any {"type" : "object" , "properties" : map [string ]any {}}
8690 }
8791
88- ccTool := map [string ]any {
89- "name" : name ,
90- "input_schema" : inputSchema ,
91- }
92+ ccTool := map [string ]any {"name" : name , "input_schema" : inputSchema }
9293 if description , ok := fn ["description" ].(string ); ok && description != "" {
9394 ccTool ["description" ] = description
9495 }
@@ -118,45 +119,72 @@ func strPtr(s string) *string {
118119
119120func contentToString (content interface {}) string {
120121 switch v := content .(type ) {
122+ case nil :
123+ return ""
121124 case string :
122125 return v
123126 case []any :
127+ var b strings.Builder
124128 for _ , part := range v {
125129 if partMap , ok := part .(map [string ]any ); ok {
126- if text , ok := partMap ["text" ].(string ); ok {
127- return text
130+ text := contentPartToString (partMap )
131+ if text != "" {
132+ b .WriteString (text )
128133 }
129134 }
130135 }
136+ return b .String ()
137+ default :
138+ data , err := json .Marshal (v )
139+ if err != nil {
140+ return ""
141+ }
142+ return string (data )
131143 }
132- return ""
133144}
134145
135146func contentPartToString (content any ) string {
136147 switch v := content .(type ) {
148+ case nil :
149+ return ""
137150 case string :
138151 return v
139152 case []any :
140153 var b strings.Builder
141154 for _ , item := range v {
142155 if m , ok := item .(map [string ]any ); ok {
143- if text , ok := m ["text" ].(string ); ok {
144- b .WriteString (text )
145- }
156+ b .WriteString (contentPartToString (m ))
146157 }
147158 }
148159 return b .String ()
149- default :
160+ case map [string ]any :
161+ for _ , key := range []string {"text" , "content" , "output_text" , "input_text" , "refusal" , "thinking" , "redacted_thinking" } {
162+ if text , ok := v [key ].(string ); ok {
163+ return text
164+ }
165+ }
166+ if imgURL , ok := v ["image_url" ].(map [string ]any ); ok {
167+ if url , ok := imgURL ["url" ].(string ); ok {
168+ return "[Image URL: " + url + "]"
169+ }
170+ }
171+ if url , ok := v ["image_url" ].(string ); ok {
172+ return "[Image URL: " + url + "]"
173+ }
150174 data , err := json .Marshal (v )
151175 if err != nil {
152176 return ""
153177 }
154178 return string (data )
179+ default :
180+ return fmt .Sprint (v )
155181 }
156182}
157183
158- func parseContent (content interface {}) []api.CCContentPart {
184+ func parseContent (content interface {}, toolNames map [ string ] string ) []api.CCContentPart {
159185 switch v := content .(type ) {
186+ case nil :
187+ return nil
160188 case string :
161189 if v == "" {
162190 return nil
@@ -171,24 +199,27 @@ func parseContent(content interface{}) []api.CCContentPart {
171199 }
172200 typ , _ := partMap ["type" ].(string )
173201 switch typ {
174- case "text" :
175- if text , ok := partMap [ "text" ].( string ); ok && text != "" {
202+ case "text" , "input_text" , "output_text" , "refusal" , "thinking" , "redacted_thinking" , "reasoning" , "document" , "search_result" :
203+ if text := contentPartToString ( partMap ); text != "" {
176204 parts = append (parts , api.CCContentPart {Type : "text" , Text : strPtr (text )})
177205 }
178- case "image_url" :
179- if imgURL , ok := partMap ["image_url" ].(map [string ]any ); ok {
180- if url , ok := imgURL ["url" ].(string ); ok && url != "" {
181- parts = append (parts , api.CCContentPart {Type : "text" , Text : strPtr ("[Image URL: " + url + "]" )})
182- }
206+ case "image_url" , "input_image" , "image" :
207+ if text := contentPartToString (partMap ); text != "" {
208+ parts = append (parts , api.CCContentPart {Type : "text" , Text : strPtr (text )})
183209 }
184210 case "tool_use" :
185211 id , _ := partMap ["id" ].(string )
186212 name , _ := partMap ["name" ].(string )
187- input := partMap ["input" ]
188- parts = append (parts , api.CCContentPart {Type : "tool_use" , ID : strPtr (id ), Name : strPtr (name ), Input : input })
213+ if id != "" && name != "" {
214+ toolNames [id ] = name
215+ }
216+ parts = append (parts , api.CCContentPart {Type : "tool_use" , ID : strPtr (id ), Name : strPtr (name ), Input : partMap ["input" ]})
189217 case "tool-call" :
190218 id , _ := partMap ["id" ].(string )
191219 name , _ := partMap ["name" ].(string )
220+ if id != "" && name != "" {
221+ toolNames [id ] = name
222+ }
192223 input := partMap ["input" ]
193224 if input == nil {
194225 input = partMap ["arguments" ]
@@ -200,12 +231,15 @@ func parseContent(content interface{}) []api.CCContentPart {
200231 toolID , _ = partMap ["toolCallId" ].(string )
201232 }
202233 toolName , _ := partMap ["toolName" ].(string )
234+ if toolName == "" {
235+ toolName = toolNames [toolID ]
236+ }
203237 parts = append (parts , api.CCContentPart {Type : "tool-result" , ToolCallID : strPtr (toolID ), ToolName : strPtr (toolName ), Text : strPtr (contentPartToString (partMap ["content" ]))})
204238 }
205239 }
206240 return parts
207241 default :
208- return nil
242+ return []api. CCContentPart {{ Type : "text" , Text : strPtr ( contentToString ( v ))}}
209243 }
210244}
211245
@@ -218,9 +252,7 @@ func ExtractSystem(msgs []api.OpenAIMessage) (string, []api.OpenAIMessage) {
218252 if system .Len () > 0 {
219253 system .WriteString ("\n " )
220254 }
221- if contentStr , ok := m .Content .(string ); ok {
222- system .WriteString (contentStr )
223- }
255+ system .WriteString (contentToString (m .Content ))
224256 } else {
225257 rest = append (rest , m )
226258 }
0 commit comments