cursor / services /response_output.go
cacode's picture
Upload 48 files
1766992 verified
package services
import (
"github.com/libaxuan/cursor2api-go/models"
"github.com/libaxuan/cursor2api-go/utils"
"encoding/json"
"strings"
)
// BuildResponseOutputFromMessage converts a chat completion message into response output items.
func BuildResponseOutputFromMessage(message models.Message, adapter *ResponseToolAdapter) ([]interface{}, string) {
output := make([]interface{}, 0, 1+len(message.ToolCalls))
var outputText string
text := message.GetStringContent()
if text != "" {
msgItem := buildResponseMessageItem(text)
output = append(output, msgItem)
outputText = text
}
for _, toolCall := range message.ToolCalls {
output = append(output, buildResponseToolCallItem(toolCall, adapter))
}
return output, outputText
}
func buildResponseMessageItem(text string) models.ResponseOutputMessage {
return models.ResponseOutputMessage{
ID: utils.GenerateResponseItemID("msg_"),
Type: "message",
Status: "completed",
Role: "assistant",
Content: []models.ResponseOutputTextContent{
{
Type: "output_text",
Text: text,
Annotations: []interface{}{},
},
},
}
}
func buildResponseToolCallItem(toolCall models.ToolCall, adapter *ResponseToolAdapter) interface{} {
name := strings.TrimSpace(toolCall.Function.Name)
if name == "" {
name = "tool"
}
if adapter == nil || adapter.ToolTypesByName == nil {
return buildFunctionCallItem(toolCall, name)
}
switch adapterType := adapter.ToolTypesByName[name]; adapterType {
case "apply_patch":
return buildApplyPatchCallItem(toolCall)
case "shell":
return buildShellCallItem(toolCall, adapter.ShellEnvironment)
case "local_shell":
return buildLocalShellCallItem(toolCall)
default:
return buildFunctionCallItem(toolCall, name)
}
}
func buildFunctionCallItem(toolCall models.ToolCall, name string) models.ResponseFunctionCall {
args := strings.TrimSpace(toolCall.Function.Arguments)
if args == "" {
args = "{}"
}
callID := toolCall.ID
if callID == "" {
callID = utils.GenerateResponseItemID("call_")
}
return models.ResponseFunctionCall{
ID: utils.GenerateResponseItemID("fc_"),
Type: "function_call",
Status: "completed",
CallID: callID,
Name: name,
Arguments: args,
}
}
func buildApplyPatchCallItem(toolCall models.ToolCall) models.ResponseApplyPatchCall {
op := parseOperation(toolCall.Function.Arguments)
callID := toolCall.ID
if callID == "" {
callID = utils.GenerateResponseItemID("call_")
}
return models.ResponseApplyPatchCall{
ID: utils.GenerateResponseItemID("apc_"),
Type: "apply_patch_call",
Status: "completed",
CallID: callID,
Operation: op,
}
}
func buildShellCallItem(toolCall models.ToolCall, environment interface{}) models.ResponseShellCall {
action := parseShellAction(toolCall.Function.Arguments)
callID := toolCall.ID
if callID == "" {
callID = utils.GenerateResponseItemID("call_")
}
return models.ResponseShellCall{
ID: utils.GenerateResponseItemID("sc_"),
Type: "shell_call",
Status: "completed",
CallID: callID,
Action: action,
Environment: environment,
}
}
func buildLocalShellCallItem(toolCall models.ToolCall) models.ResponseLocalShellCall {
action := parseLocalShellAction(toolCall.Function.Arguments)
callID := toolCall.ID
if callID == "" {
callID = utils.GenerateResponseItemID("call_")
}
return models.ResponseLocalShellCall{
ID: utils.GenerateResponseItemID("lsc_"),
Type: "local_shell_call",
Status: "completed",
CallID: callID,
Action: action,
}
}
func parseOperation(arguments string) map[string]interface{} {
args := strings.TrimSpace(arguments)
if args == "" {
return map[string]interface{}{}
}
var payload map[string]interface{}
if err := json.Unmarshal([]byte(args), &payload); err == nil {
if op, ok := payload["operation"].(map[string]interface{}); ok {
return op
}
if hasKeys(payload, "type", "path") {
return payload
}
return payload
}
return map[string]interface{}{
"diff": args,
}
}
func parseShellAction(arguments string) map[string]interface{} {
args := strings.TrimSpace(arguments)
if args == "" {
return map[string]interface{}{"commands": []string{}}
}
var payload map[string]interface{}
if err := json.Unmarshal([]byte(args), &payload); err == nil {
if action, ok := payload["action"].(map[string]interface{}); ok {
return normalizeShellAction(action)
}
return normalizeShellAction(payload)
}
return map[string]interface{}{
"commands": []string{args},
}
}
func parseLocalShellAction(arguments string) map[string]interface{} {
args := strings.TrimSpace(arguments)
if args == "" {
return map[string]interface{}{"command": ""}
}
var payload map[string]interface{}
if err := json.Unmarshal([]byte(args), &payload); err == nil {
if action, ok := payload["action"].(map[string]interface{}); ok {
return normalizeLocalShellAction(action)
}
return normalizeLocalShellAction(payload)
}
return map[string]interface{}{
"command": args,
}
}
func normalizeShellAction(payload map[string]interface{}) map[string]interface{} {
action := map[string]interface{}{}
if cmds, ok := payload["commands"]; ok {
action["commands"] = normalizeStringSlice(cmds)
} else if cmd, ok := payload["command"]; ok {
action["commands"] = normalizeStringSlice(cmd)
}
if timeout, ok := payload["timeout_ms"]; ok {
action["timeout_ms"] = timeout
}
if maxOut, ok := payload["max_output_length"]; ok {
action["max_output_length"] = maxOut
}
if _, exists := action["commands"]; !exists {
action["commands"] = []string{}
}
return action
}
func normalizeLocalShellAction(payload map[string]interface{}) map[string]interface{} {
action := map[string]interface{}{}
if cmd, ok := payload["command"]; ok {
action["command"] = cmd
} else if cmds, ok := payload["commands"]; ok {
action["command"] = cmds
}
if timeout, ok := payload["timeout_ms"]; ok {
action["timeout_ms"] = timeout
}
if wd, ok := payload["working_directory"]; ok {
action["working_directory"] = wd
}
if env, ok := payload["env"]; ok {
action["env"] = env
}
if maxOut, ok := payload["max_output_length"]; ok {
action["max_output_length"] = maxOut
}
if _, exists := action["command"]; !exists {
action["command"] = ""
}
return action
}
func normalizeStringSlice(value interface{}) []string {
switch v := value.(type) {
case []interface{}:
result := make([]string, 0, len(v))
for _, item := range v {
if text, ok := item.(string); ok {
result = append(result, text)
}
}
return result
case []string:
return v
case string:
return []string{v}
default:
return []string{}
}
}
func hasKeys(payload map[string]interface{}, keys ...string) bool {
for _, key := range keys {
if _, ok := payload[key]; !ok {
return false
}
}
return true
}