595 lines · 21.0 KB · Go
RawDownload
package interactions import (	"bytes"	"context"	"fmt"	"strings"	"time" 	translatorcommon "github.com/router-for-me/CLIProxyAPI/v7/internal/translator/common"	"github.com/tidwall/gjson"	"github.com/tidwall/sjson") type codexToInteractionsStreamState struct {	Started          bool	Completed        bool	Done             bool	ActiveStepOpen   bool	ActiveStepType   string	ActiveStepIndex  int	StepIndex        int	ID               string	Model            string	CreatedAt        int64	HasOutputText    bool	FunctionCallName string	FunctionCallID   string} func ConvertCodexResponseToInteractions(ctx context.Context, modelName string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, param *any) [][]byte {	_ = ctx	_ = originalRequestRawJSON	_ = requestRawJSON	if param == nil {		var local any		param = &local	}	if *param == nil {		*param = &codexToInteractionsStreamState{			ID:    fmt.Sprintf("interaction_%d", time.Now().UnixNano()),			Model: modelName,		}	}	st := (*param).(*codexToInteractionsStreamState)	payload := codexStreamPayload(rawJSON)	if bytes.Equal(payload, []byte("[DONE]")) {		out := appendCodexInteractionsStepStop(nil, st)		if !st.Completed {			out = appendCodexInteractionsCompleted(out, st, gjson.Result{})		}		return appendCodexInteractionsDone(out, st)	}	if len(payload) == 0 {		return nil	}	root := gjson.ParseBytes(payload)	switch root.Get("type").String() {	case "response.created":		return appendCodexInteractionsCreated(nil, st, root.Get("response"))	case "response.output_item.added":		return codexOutputItemAddedToInteractions(st, root)	case "response.output_text.delta":		return codexOutputTextDeltaToInteractions(st, root)	case "response.reasoning_summary_text.delta", "response.reasoning_text.delta":		return codexReasoningDeltaToInteractions(st, root)	case "response.function_call_arguments.delta":		return codexFunctionArgumentsDeltaToInteractions(st, root)	case "response.output_item.done":		return codexOutputItemDoneToInteractions(st, root.Get("item"))	case "response.completed", "response.incomplete":		out := appendCodexInteractionsCreated(nil, st, root.Get("response"))		out = appendCodexInteractionsStepStop(out, st)		out = appendCodexInteractionsCompleted(out, st, root.Get("response"))		return appendCodexInteractionsDone(out, st)	default:		return nil	}} func ConvertCodexResponseToInteractionsNonStream(ctx context.Context, modelName string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, _ *any) []byte {	_ = ctx	_ = originalRequestRawJSON	_ = requestRawJSON	root := gjson.ParseBytes(rawJSON)	response := root.Get("response")	if !response.Exists() {		response = root	}	out := []byte(`{"id":"","object":"interaction","status":"completed","model":"","steps":[]}`)	if status := response.Get("status").String(); status != "" {		out, _ = sjson.SetBytes(out, "status", status)	}	id := response.Get("id").String()	if id == "" {		id = fmt.Sprintf("interaction_%d", time.Now().UnixNano())	}	out, _ = sjson.SetBytes(out, "id", id)	if model := response.Get("model").String(); model != "" {		out, _ = sjson.SetBytes(out, "model", model)	} else {		out, _ = sjson.SetBytes(out, "model", modelName)	}	var steps [][]byte	response.Get("output").ForEach(func(_, item gjson.Result) bool {		switch item.Get("type").String() {		case "message":			if step := buildCodexMessageItemToInteractions(item); len(step) > 0 {				steps = append(steps, step)			}		case "reasoning":			if step := buildCodexReasoningItemToInteractions(item); len(step) > 0 {				steps = append(steps, step)			}		case "function_call", "tool_call":			if step := buildCodexFunctionCallItemToInteractions(item); len(step) > 0 {				steps = append(steps, step)			}		case "image_generation_call":			if step := buildCodexImageItemToInteractions(item); len(step) > 0 {				steps = append(steps, step)			}		}		return true	})	if len(steps) > 0 {		out = translatorcommon.SetRawArrayItems(out, "steps", steps)	}	out = setCodexInteractionsUsage(out, "usage", response.Get("usage"), false)	return out} func codexStreamPayload(rawJSON []byte) []byte {	rawJSON = bytes.TrimSpace(rawJSON)	if bytes.HasPrefix(rawJSON, []byte("data:")) {		rawJSON = bytes.TrimSpace(rawJSON[len("data:"):])	}	return rawJSON} func codexStreamEventType(rawJSON []byte) string {	payload := codexStreamPayload(rawJSON)	if len(payload) == 0 || bytes.Equal(payload, []byte("[DONE]")) {		return ""	}	return gjson.GetBytes(payload, "type").String()} func appendCodexInteractionsCreated(out [][]byte, st *codexToInteractionsStreamState, response gjson.Result) [][]byte {	if st.Started {		return out	}	if id := response.Get("id").String(); id != "" {		st.ID = id	}	if model := response.Get("model").String(); model != "" {		st.Model = model	}	if createdAt := response.Get("created_at"); createdAt.Exists() {		st.CreatedAt = createdAt.Int()	}	created := []byte(`{"interaction":{"id":"","status":"in_progress","object":"interaction","model":""},"event_type":"interaction.created"}`)	created, _ = sjson.SetBytes(created, "interaction.id", st.ID)	created, _ = sjson.SetBytes(created, "interaction.model", st.Model)	out = append(out, translatorcommon.SSEEventData("interaction.created", created))	statusUpdate := []byte(`{"interaction_id":"","status":"in_progress","event_type":"interaction.status_update"}`)	statusUpdate, _ = sjson.SetBytes(statusUpdate, "interaction_id", st.ID)	out = append(out, translatorcommon.SSEEventData("interaction.status_update", statusUpdate))	st.Started = true	return out} func appendCodexInteractionsCompleted(out [][]byte, st *codexToInteractionsStreamState, response gjson.Result) [][]byte {	if st.Completed {		return out	}	created := time.Now().UTC()	if st.CreatedAt > 0 {		created = time.Unix(st.CreatedAt, 0).UTC()	}	completed := []byte(`{"interaction":{"id":"","status":"completed","usage":{},"created":"","updated":"","service_tier":"standard","object":"interaction","model":""},"event_type":"interaction.completed"}`)	completed, _ = sjson.SetBytes(completed, "interaction.id", st.ID)	completed, _ = sjson.SetBytes(completed, "interaction.created", created.Format(time.RFC3339))	completed, _ = sjson.SetBytes(completed, "interaction.updated", time.Now().UTC().Format(time.RFC3339))	completed, _ = sjson.SetBytes(completed, "interaction.model", st.Model)	if status := response.Get("status").String(); status != "" {		completed, _ = sjson.SetBytes(completed, "interaction.status", status)	}	completed = setCodexInteractionsUsage(completed, "interaction.usage", response.Get("usage"), true)	out = append(out, translatorcommon.SSEEventData("interaction.completed", completed))	st.Completed = true	return out} func appendCodexInteractionsDone(out [][]byte, st *codexToInteractionsStreamState) [][]byte {	if st.Done {		return out	}	out = append(out, translatorcommon.SSEEventData("done", []byte("[DONE]")))	st.Done = true	return out} func codexOutputItemAddedToInteractions(st *codexToInteractionsStreamState, root gjson.Result) [][]byte {	out := appendCodexInteractionsCreated(nil, st, root.Get("response"))	item := root.Get("item")	switch item.Get("type").String() {	case "message":		return ensureCodexInteractionsStep(out, st, "model_output", item)	case "reasoning":		return ensureCodexInteractionsStep(out, st, "thought", item)	case "function_call", "tool_call":		st.FunctionCallName = item.Get("name").String()		st.FunctionCallID = codexItemCallID(item)		return ensureCodexInteractionsStep(out, st, "function_call", item)	}	return out} func codexOutputTextDeltaToInteractions(st *codexToInteractionsStreamState, root gjson.Result) [][]byte {	out := appendCodexInteractionsCreated(nil, st, root.Get("response"))	out = ensureCodexInteractionsStep(out, st, "model_output", gjson.Result{})	delta := []byte(`{"index":0,"delta":{"text":"","type":"text"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.text", root.Get("delta").String())	st.HasOutputText = true	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func codexReasoningDeltaToInteractions(st *codexToInteractionsStreamState, root gjson.Result) [][]byte {	out := appendCodexInteractionsCreated(nil, st, root.Get("response"))	out = ensureCodexInteractionsStep(out, st, "thought", gjson.Result{})	delta := []byte(`{"index":0,"delta":{"content":{"text":"","type":"text"},"type":"thought_summary"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.content.text", root.Get("delta").String())	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func codexFunctionArgumentsDeltaToInteractions(st *codexToInteractionsStreamState, root gjson.Result) [][]byte {	out := appendCodexInteractionsCreated(nil, st, root.Get("response"))	out = ensureCodexInteractionsStep(out, st, "function_call", root.Get("item"))	delta := []byte(`{"index":0,"delta":{"arguments":"","type":"arguments_delta"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.arguments", root.Get("delta").String())	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func codexOutputItemDoneToInteractions(st *codexToInteractionsStreamState, item gjson.Result) [][]byte {	out := appendCodexInteractionsCreated(nil, st, gjson.Result{})	switch item.Get("type").String() {	case "message":		if st.HasOutputText {			return appendCodexInteractionsStepStop(out, st)		}		out = appendCodexMessageItemToInteractionsStream(out, st, item)		return appendCodexInteractionsStepStop(out, st)	case "reasoning":		out = appendCodexReasoningItemToInteractionsStream(out, st, item)		return appendCodexInteractionsStepStop(out, st)	case "function_call", "tool_call":		out = appendCodexFunctionCallItemToInteractionsStream(out, st, item)		return appendCodexInteractionsStepStop(out, st)	case "image_generation_call":		out = appendCodexImageItemToInteractionsStream(out, st, item)		return appendCodexInteractionsStepStop(out, st)	}	return out} func ensureCodexInteractionsStep(out [][]byte, st *codexToInteractionsStreamState, stepType string, item gjson.Result) [][]byte {	if st.ActiveStepOpen && st.ActiveStepType == stepType {		return out	}	out = appendCodexInteractionsStepStop(out, st)	return appendCodexInteractionsStepStart(out, st, stepType, item)} func appendCodexInteractionsStepStart(out [][]byte, st *codexToInteractionsStreamState, stepType string, item gjson.Result) [][]byte {	st.ActiveStepIndex = st.StepIndex	st.StepIndex++	st.ActiveStepOpen = true	st.ActiveStepType = stepType	stepStart := []byte(`{"index":0,"step":{"type":""},"event_type":"step.start"}`)	stepStart, _ = sjson.SetBytes(stepStart, "index", st.ActiveStepIndex)	stepStart, _ = sjson.SetBytes(stepStart, "step.type", stepType)	if stepType == "function_call" {		name := item.Get("name").String()		if name == "" {			name = st.FunctionCallName		}		callID := codexItemCallID(item)		if callID == "" {			callID = st.FunctionCallID		}		if callID == "" {			callID = fmt.Sprintf("step_%d", time.Now().UnixNano())		}		stepStart, _ = sjson.SetBytes(stepStart, "step.id", callID)		stepStart, _ = sjson.SetBytes(stepStart, "step.call_id", callID)		stepStart, _ = sjson.SetBytes(stepStart, "step.name", name)		stepStart, _ = sjson.SetRawBytes(stepStart, "step.arguments", []byte(`{}`))	}	return append(out, translatorcommon.SSEEventData("step.start", stepStart))} func appendCodexInteractionsStepStop(out [][]byte, st *codexToInteractionsStreamState) [][]byte {	if !st.ActiveStepOpen {		return out	}	stepStop := []byte(`{"index":0,"event_type":"step.stop"}`)	stepStop, _ = sjson.SetBytes(stepStop, "index", st.ActiveStepIndex)	out = append(out, translatorcommon.SSEEventData("step.stop", stepStop))	st.ActiveStepOpen = false	st.ActiveStepType = ""	return out} func buildCodexMessageItemToInteractions(item gjson.Result) []byte {	var contents [][]byte	item.Get("content").ForEach(func(_, content gjson.Result) bool {		if contentItem := codexContentToInteractionsContent(content); len(contentItem) > 0 {			contents = append(contents, contentItem)		}		return true	})	if len(contents) == 0 {		return nil	}	step := []byte(`{"type":"model_output","content":[]}`)	return translatorcommon.SetRawArrayItems(step, "content", contents)} func buildCodexReasoningItemToInteractions(item gjson.Result) []byte {	text := codexReasoningText(item)	if text == "" {		return nil	}	step := []byte(`{"type":"thought","content":[{"type":"text","text":""}]}`)	step, _ = sjson.SetBytes(step, "content.0.text", text)	return step} func buildCodexFunctionCallItemToInteractions(item gjson.Result) []byte {	step := []byte(`{"type":"function_call","name":"","arguments":{}}`)	step, _ = sjson.SetBytes(step, "name", item.Get("name").String())	if callID := codexItemCallID(item); callID != "" {		step, _ = sjson.SetBytes(step, "call_id", callID)	}	if args := codexArgumentsJSON(item.Get("arguments")); len(args) > 0 {		step, _ = sjson.SetRawBytes(step, "arguments", args)	}	return step} func buildCodexImageItemToInteractions(item gjson.Result) []byte {	result := item.Get("result").String()	if result == "" {		return nil	}	step := []byte(`{"type":"model_output","content":[{"type":"image","mime_type":"","data":""}]}`)	step, _ = sjson.SetBytes(step, "content.0.mime_type", mimeTypeFromCodexOutputFormat(item.Get("output_format").String()))	step, _ = sjson.SetBytes(step, "content.0.data", result)	return step} func appendCodexMessageItemToInteractions(out []byte, item gjson.Result) []byte {	if step := buildCodexMessageItemToInteractions(item); len(step) > 0 {		out, _ = sjson.SetRawBytes(out, "steps.-1", step)	}	return out} func appendCodexReasoningItemToInteractions(out []byte, item gjson.Result) []byte {	if step := buildCodexReasoningItemToInteractions(item); len(step) > 0 {		out, _ = sjson.SetRawBytes(out, "steps.-1", step)	}	return out} func appendCodexFunctionCallItemToInteractions(out []byte, item gjson.Result) []byte {	if step := buildCodexFunctionCallItemToInteractions(item); len(step) > 0 {		out, _ = sjson.SetRawBytes(out, "steps.-1", step)	}	return out} func appendCodexImageItemToInteractions(out []byte, item gjson.Result) []byte {	if step := buildCodexImageItemToInteractions(item); len(step) > 0 {		out, _ = sjson.SetRawBytes(out, "steps.-1", step)	}	return out} func appendCodexMessageItemToInteractionsStream(out [][]byte, st *codexToInteractionsStreamState, item gjson.Result) [][]byte {	item.Get("content").ForEach(func(_, content gjson.Result) bool {		if text := codexContentText(content); text != "" {			out = ensureCodexInteractionsStep(out, st, "model_output", item)			delta := []byte(`{"index":0,"delta":{"text":"","type":"text"},"event_type":"step.delta"}`)			delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)			delta, _ = sjson.SetBytes(delta, "delta.text", text)			out = append(out, translatorcommon.SSEEventData("step.delta", delta))		}		return true	})	return out} func appendCodexReasoningItemToInteractionsStream(out [][]byte, st *codexToInteractionsStreamState, item gjson.Result) [][]byte {	text := codexReasoningText(item)	if text == "" {		return out	}	out = ensureCodexInteractionsStep(out, st, "thought", item)	delta := []byte(`{"index":0,"delta":{"content":{"text":"","type":"text"},"type":"thought_summary"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.content.text", text)	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func appendCodexFunctionCallItemToInteractionsStream(out [][]byte, st *codexToInteractionsStreamState, item gjson.Result) [][]byte {	out = ensureCodexInteractionsStep(out, st, "function_call", item)	delta := []byte(`{"index":0,"delta":{"arguments":"","type":"arguments_delta"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.arguments", item.Get("arguments").String())	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func appendCodexImageItemToInteractionsStream(out [][]byte, st *codexToInteractionsStreamState, item gjson.Result) [][]byte {	result := item.Get("result").String()	if result == "" {		return out	}	out = ensureCodexInteractionsStep(out, st, "model_output", item)	delta := []byte(`{"index":0,"delta":{"content":{"type":"image","mime_type":"","data":""},"type":"content"},"event_type":"step.delta"}`)	delta, _ = sjson.SetBytes(delta, "index", st.ActiveStepIndex)	delta, _ = sjson.SetBytes(delta, "delta.content.mime_type", mimeTypeFromCodexOutputFormat(item.Get("output_format").String()))	delta, _ = sjson.SetBytes(delta, "delta.content.data", result)	return append(out, translatorcommon.SSEEventData("step.delta", delta))} func codexContentToInteractionsContent(content gjson.Result) []byte {	if text := codexContentText(content); text != "" {		item := []byte(`{"type":"text","text":""}`)		item, _ = sjson.SetBytes(item, "text", text)		return item	}	return nil} func codexContentText(content gjson.Result) string {	for _, path := range []string{"text", "content"} {		if value := content.Get(path); value.Exists() && value.Type == gjson.String {			return value.String()		}	}	return ""} func codexReasoningText(item gjson.Result) string {	if content := item.Get("content"); content.Exists() {		if content.Type == gjson.String {			return content.String()		}		if content.IsArray() {			var builder strings.Builder			content.ForEach(func(_, part gjson.Result) bool {				text := codexContentText(part)				if text == "" {					text = part.Get("summary_text").String()				}				if text == "" {					return true				}				if builder.Len() > 0 {					builder.WriteByte('\n')				}				builder.WriteString(text)				return true			})			return builder.String()		}	}	if summary := item.Get("summary"); summary.Exists() {		if summary.Type == gjson.String {			return summary.String()		}		if summary.IsArray() {			var builder strings.Builder			summary.ForEach(func(_, part gjson.Result) bool {				text := codexContentText(part)				if text == "" {					return true				}				if builder.Len() > 0 {					builder.WriteByte('\n')				}				builder.WriteString(text)				return true			})			return builder.String()

Lines 1–500 of 595.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t