Changeset 0.12.0 (#63)
This commit is contained in:
@@ -37,8 +37,14 @@ func (p *OpenAIProvider) ChatCompletion(ctx context.Context, cfg ProviderConfig,
|
||||
return nil, fmt.Errorf("no choices in response")
|
||||
}
|
||||
|
||||
// Extract content string from response (responses are always string, not array)
|
||||
var contentStr string
|
||||
if s, ok := resp.Choices[0].Message.Content.(string); ok {
|
||||
contentStr = s
|
||||
}
|
||||
|
||||
result := &CompletionResponse{
|
||||
Content: resp.Choices[0].Message.Content,
|
||||
Content: contentStr,
|
||||
Model: resp.Model,
|
||||
FinishReason: resp.Choices[0].FinishReason,
|
||||
InputTokens: resp.Usage.PromptTokens,
|
||||
@@ -360,11 +366,42 @@ func (p *OpenAIProvider) doRequest(ctx context.Context, cfg ProviderConfig, req
|
||||
})
|
||||
}
|
||||
|
||||
// Convert messages — handle all roles including tool
|
||||
// Convert messages — handle all roles including tool and multimodal
|
||||
for _, m := range req.Messages {
|
||||
oaiMsg := openaiMessage{
|
||||
Role: m.Role,
|
||||
Content: m.Content,
|
||||
Role: m.Role,
|
||||
}
|
||||
|
||||
// Build content: multimodal parts or plain string
|
||||
if len(m.ContentParts) > 0 && m.Role == "user" {
|
||||
// Multimodal: convert to OpenAI content array format
|
||||
parts := make([]openaiContentPart, 0, len(m.ContentParts))
|
||||
for _, p := range m.ContentParts {
|
||||
switch p.Type {
|
||||
case "image_url":
|
||||
if p.ImageURL != nil {
|
||||
detail := p.ImageURL.Detail
|
||||
if detail == "" {
|
||||
detail = "auto"
|
||||
}
|
||||
parts = append(parts, openaiContentPart{
|
||||
Type: "image_url",
|
||||
ImageURL: &openaiImageURL{
|
||||
URL: p.ImageURL.URL,
|
||||
Detail: detail,
|
||||
},
|
||||
})
|
||||
}
|
||||
default: // "text", "document" → text
|
||||
parts = append(parts, openaiContentPart{
|
||||
Type: "text",
|
||||
Text: p.Text,
|
||||
})
|
||||
}
|
||||
}
|
||||
oaiMsg.Content = parts
|
||||
} else {
|
||||
oaiMsg.Content = m.Content
|
||||
}
|
||||
|
||||
// Assistant messages with tool calls
|
||||
@@ -425,11 +462,24 @@ func (p *OpenAIProvider) doRequest(ctx context.Context, cfg ProviderConfig, req
|
||||
// ── OpenAI Wire Types ───────────────────────
|
||||
|
||||
type openaiMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ToolCalls []openaiToolCall `json:"tool_calls,omitempty"` // assistant requesting tools
|
||||
ToolCallID string `json:"tool_call_id,omitempty"` // role=tool result
|
||||
Name string `json:"name,omitempty"` // tool name for role=tool
|
||||
Role string `json:"role"`
|
||||
Content interface{} `json:"content,omitempty"` // string or []openaiContentPart
|
||||
ToolCalls []openaiToolCall `json:"tool_calls,omitempty"` // assistant requesting tools
|
||||
ToolCallID string `json:"tool_call_id,omitempty"` // role=tool result
|
||||
Name string `json:"name,omitempty"` // tool name for role=tool
|
||||
}
|
||||
|
||||
// openaiContentPart represents a single element in a multimodal content array.
|
||||
// OpenAI format: [{"type":"text","text":"..."}, {"type":"image_url","image_url":{"url":"..."}}]
|
||||
type openaiContentPart struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text,omitempty"`
|
||||
ImageURL *openaiImageURL `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
type openaiImageURL struct {
|
||||
URL string `json:"url"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
type openaiToolCallFunction struct {
|
||||
|
||||
Reference in New Issue
Block a user