cursor / models /models.go
cacode's picture
Upload 48 files
1766992 verified
// Copyright (c) 2025-2026 libaxuan
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package models
import (
"encoding/json"
"time"
)
// ChatCompletionRequest OpenAI聊天完成请求
type ChatCompletionRequest struct {
Model string `json:"model" binding:"required"`
Messages []Message `json:"messages" binding:"required"`
Stream bool `json:"stream,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
MaxTokens *int `json:"max_tokens,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
Stop []string `json:"stop,omitempty"`
User string `json:"user,omitempty"`
Tools []Tool `json:"tools,omitempty"`
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
}
// Message 消息结构
type Message struct {
Role string `json:"role" binding:"required"`
Content interface{} `json:"content"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Name string `json:"name,omitempty"`
}
// ContentPart 消息内容部分(用于多模态内容)
type ContentPart struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
URL string `json:"url,omitempty"`
}
// Tool OpenAI工具定义
type Tool struct {
Type string `json:"type"`
Function FunctionDefinition `json:"function"`
}
// FunctionDefinition OpenAI函数定义
type FunctionDefinition struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty"`
}
// ToolCall OpenAI工具调用
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function FunctionCall `json:"function"`
}
// FunctionCall OpenAI函数调用信息
type FunctionCall struct {
Name string `json:"name"`
Arguments string `json:"arguments"`
}
// ToolChoiceObject OpenAI tool_choice 对象形式
type ToolChoiceObject struct {
Type string `json:"type"`
Function *ToolChoiceFunction `json:"function,omitempty"`
}
// ToolChoiceFunction tool_choice 中的函数名
type ToolChoiceFunction struct {
Name string `json:"name"`
}
// ChatCompletionResponse OpenAI聊天完成响应
type ChatCompletionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []Choice `json:"choices"`
Usage Usage `json:"usage"`
}
// ChatCompletionStreamResponse 流式响应
type ChatCompletionStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []StreamChoice `json:"choices"`
}
// Choice 选择结构
type Choice struct {
Index int `json:"index"`
Message Message `json:"message"`
FinishReason string `json:"finish_reason"`
}
// StreamChoice 流式选择结构
type StreamChoice struct {
Index int `json:"index"`
Delta StreamDelta `json:"delta"`
FinishReason *string `json:"finish_reason"`
}
// StreamDelta 流式增量数据
type StreamDelta struct {
Role string `json:"role,omitempty"`
Content string `json:"content,omitempty"`
ToolCalls []ToolCallDelta `json:"tool_calls,omitempty"`
}
// ToolCallDelta 流式工具调用增量
type ToolCallDelta struct {
Index int `json:"index"`
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Function *FunctionCallDelta `json:"function,omitempty"`
}
// FunctionCallDelta 流式函数调用增量
type FunctionCallDelta struct {
Name string `json:"name,omitempty"`
Arguments string `json:"arguments,omitempty"`
}
// Usage 使用统计
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
}
// Model 模型信息
type Model struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
MaxTokens int `json:"max_tokens,omitempty"`
ContextWindow int `json:"context_window,omitempty"`
}
// ModelsResponse 模型列表响应
type ModelsResponse struct {
Object string `json:"object"`
Data []Model `json:"data"`
}
// ErrorResponse 错误响应
type ErrorResponse struct {
Error ErrorDetail `json:"error"`
}
// ErrorDetail 错误详情
type ErrorDetail struct {
Message string `json:"message"`
Type string `json:"type"`
Code string `json:"code,omitempty"`
}
// CursorMessage Cursor消息格式
type CursorMessage struct {
Role string `json:"role"`
Parts []CursorPart `json:"parts"`
}
// CursorPart Cursor消息部分
type CursorPart struct {
Type string `json:"type"`
Text string `json:"text"`
}
// CursorRequest Cursor请求格式
type CursorRequest struct {
Context []interface{} `json:"context"`
Model string `json:"model"`
ID string `json:"id"`
Messages []CursorMessage `json:"messages"`
Trigger string `json:"trigger"`
}
// CursorEventData Cursor事件数据
type CursorEventData struct {
Type string `json:"type"`
Delta string `json:"delta,omitempty"`
ErrorText string `json:"errorText,omitempty"`
MessageMetadata *CursorMessageMetadata `json:"messageMetadata,omitempty"`
}
// CursorMessageMetadata Cursor消息元数据
type CursorMessageMetadata struct {
Usage *CursorUsage `json:"usage,omitempty"`
}
// CursorUsage Cursor使用统计
type CursorUsage struct {
InputTokens int `json:"inputTokens"`
OutputTokens int `json:"outputTokens"`
TotalTokens int `json:"totalTokens"`
}
// SSEEvent 服务器发送事件
type SSEEvent struct {
Data string `json:"data"`
Event string `json:"event,omitempty"`
ID string `json:"id,omitempty"`
}
// CursorParseConfig 定义上游文本协议解析选项
type CursorParseConfig struct {
TriggerSignal string
ThinkingEnabled bool
}
// AssistantEventKind 助手输出事件类型
type AssistantEventKind string
const (
AssistantEventText AssistantEventKind = "text"
AssistantEventThinking AssistantEventKind = "thinking"
AssistantEventToolCall AssistantEventKind = "tool_call"
)
// AssistantEvent 是内部流式解析事件
type AssistantEvent struct {
Kind AssistantEventKind
Text string
Thinking string
ToolCall *ToolCall
}
// GetStringContent 获取消息的字符串内容
func (m *Message) GetStringContent() string {
if m.Content == nil {
return ""
}
switch content := m.Content.(type) {
case string:
return content
case []ContentPart:
var text string
for _, part := range content {
if part.Type == "text" {
text += part.Text
}
}
return text
case []interface{}:
var text string
for _, item := range content {
if part, ok := item.(map[string]interface{}); ok {
if partType, exists := part["type"].(string); exists && partType == "text" {
if textContent, exists := part["text"].(string); exists {
text += textContent
}
}
}
}
return text
default:
if data, err := json.Marshal(content); err == nil {
return string(data)
}
return ""
}
}
// ToCursorMessages 将OpenAI消息转换为Cursor格式
func ToCursorMessages(messages []Message, systemPromptInject string) []CursorMessage {
var result []CursorMessage
if systemPromptInject != "" {
if len(messages) > 0 && messages[0].Role == "system" {
content := messages[0].GetStringContent()
content += "\n" + systemPromptInject
result = append(result, CursorMessage{
Role: "system",
Parts: []CursorPart{
{Type: "text", Text: content},
},
})
messages = messages[1:]
} else {
result = append(result, CursorMessage{
Role: "system",
Parts: []CursorPart{
{Type: "text", Text: systemPromptInject},
},
})
}
} else if len(messages) > 0 && messages[0].Role == "system" {
result = append(result, CursorMessage{
Role: "system",
Parts: []CursorPart{
{Type: "text", Text: messages[0].GetStringContent()},
},
})
messages = messages[1:]
}
for _, msg := range messages {
if msg.Role == "" {
continue
}
result = append(result, CursorMessage{
Role: msg.Role,
Parts: []CursorPart{
{
Type: "text",
Text: msg.GetStringContent(),
},
},
})
}
return result
}
// NewChatCompletionResponse 创建聊天完成响应
func NewChatCompletionResponse(id, model string, message Message, finishReason string, usage Usage) *ChatCompletionResponse {
return &ChatCompletionResponse{
ID: id,
Object: "chat.completion",
Created: time.Now().Unix(),
Model: model,
Choices: []Choice{
{
Index: 0,
Message: message,
FinishReason: finishReason,
},
},
Usage: usage,
}
}
// NewChatCompletionStreamResponse 创建流式响应
func NewChatCompletionStreamResponse(id, model string, delta StreamDelta, finishReason *string) *ChatCompletionStreamResponse {
return &ChatCompletionStreamResponse{
ID: id,
Object: "chat.completion.chunk",
Created: time.Now().Unix(),
Model: model,
Choices: []StreamChoice{
{
Index: 0,
Delta: delta,
FinishReason: finishReason,
},
},
}
}
// NewErrorResponse 创建错误响应
func NewErrorResponse(message, errorType, code string) *ErrorResponse {
return &ErrorResponse{
Error: ErrorDetail{
Message: message,
Type: errorType,
Code: code,
},
}
}