cursor / services /response_response.go
cacode's picture
Upload 48 files
1766992 verified
package services
import (
"bytes"
"github.com/libaxuan/cursor2api-go/models"
"github.com/libaxuan/cursor2api-go/utils"
"encoding/json"
"time"
)
// BuildResponseUsage converts chat-completions usage into responses usage.
func BuildResponseUsage(usage models.Usage) *models.ResponseUsage {
if usage.PromptTokens == 0 && usage.CompletionTokens == 0 && usage.TotalTokens == 0 {
return nil
}
return &models.ResponseUsage{
InputTokens: usage.PromptTokens,
OutputTokens: usage.CompletionTokens,
TotalTokens: usage.TotalTokens,
OutputTokensDetails: &models.ResponseOutputTokensDetails{
ReasoningTokens: 0,
},
}
}
// NewResponseFromRequest builds a Responses API response with shared request metadata.
func NewResponseFromRequest(req *models.ResponseRequest, id string, createdAt int64, status string, output []interface{}, outputText string, usage *models.ResponseUsage, completedAt *int64) models.Response {
if output == nil {
output = []interface{}{}
}
resp := models.Response{
ID: id,
Object: "response",
CreatedAt: createdAt,
Status: status,
CompletedAt: completedAt,
Background: req.Background,
Instructions: decodeRaw(req.Instructions),
MaxOutputTokens: req.MaxOutputTokens,
MaxToolCalls: req.MaxToolCalls,
Model: req.Model,
Output: output,
OutputText: outputText,
ParallelToolCalls: resolveParallelToolCalls(req.ParallelToolCalls),
PreviousResponseID: req.PreviousResponseID,
Reasoning: decodeReasoning(req.Reasoning),
Store: req.Store,
Temperature: req.Temperature,
Text: decodeRaw(req.Text),
ToolChoice: decodeRaw(req.ToolChoice),
Tools: req.Tools,
TopP: req.TopP,
Truncation: req.Truncation,
Usage: usage,
User: req.User,
Metadata: req.Metadata,
}
return resp
}
// BuildCompletedResponse builds a completed response with a generated ID.
func BuildCompletedResponse(req *models.ResponseRequest, output []interface{}, outputText string, usage *models.ResponseUsage) models.Response {
now := time.Now().Unix()
complete := now
return NewResponseFromRequest(req, utils.GenerateResponseID(), now, "completed", output, outputText, usage, &complete)
}
func resolveParallelToolCalls(raw *bool) bool {
if raw == nil {
return false
}
return *raw
}
func decodeRaw(raw json.RawMessage) interface{} {
trimmed := bytes.TrimSpace(raw)
if len(trimmed) == 0 || string(trimmed) == "null" {
return nil
}
var val interface{}
if err := json.Unmarshal(trimmed, &val); err != nil {
return nil
}
return val
}
func decodeReasoning(raw json.RawMessage) *models.ResponseReasoning {
trimmed := bytes.TrimSpace(raw)
if len(trimmed) == 0 || string(trimmed) == "null" {
return nil
}
var val map[string]interface{}
if err := json.Unmarshal(trimmed, &val); err != nil {
return nil
}
reasoning := &models.ResponseReasoning{}
if effort, ok := val["effort"].(string); ok {
reasoning.Effort = &effort
}
if summary, ok := val["summary"]; ok {
reasoning.Summary = summary
}
return reasoning
}