Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
138 lines
4.1 KiB
Go
138 lines
4.1 KiB
Go
//go:build unit
|
|
|
|
package service
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestFilterCodexInput_StripsFunctionCallItemID_WhenPreservingReferences
|
|
// verifies that function_call items with non-fc id (e.g. item_*) have their
|
|
// id stripped even when PreserveReferences is true. OpenAI upstream requires
|
|
// function_call ids to begin with "fc" and rejects item_* with 400:
|
|
// "Expected an ID that begins with 'fc'." (#3785)
|
|
func TestFilterCodexInput_StripsFunctionCallItemID_WhenPreservingReferences(t *testing.T) {
|
|
input := []any{
|
|
map[string]any{
|
|
"type": "function_call",
|
|
"id": "item_A9v0SNfS3VaLrfX0j3y4xhyK",
|
|
"call_id": "fc_abc123",
|
|
"name": "bash",
|
|
},
|
|
map[string]any{
|
|
"type": "function_call_output",
|
|
"call_id": "fc_abc123",
|
|
"output": "done",
|
|
},
|
|
}
|
|
|
|
filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
|
|
PreserveReferences: true,
|
|
})
|
|
|
|
require.Len(t, filtered, 2)
|
|
|
|
fc, ok := filtered[0].(map[string]any)
|
|
require.True(t, ok)
|
|
require.Equal(t, "function_call", fc["type"])
|
|
_, hasID := fc["id"]
|
|
require.False(t, hasID, "item_* id should be stripped from function_call")
|
|
require.Equal(t, "fc_abc123", fc["call_id"], "call_id must be preserved")
|
|
require.Equal(t, "bash", fc["name"])
|
|
}
|
|
|
|
// TestFilterCodexInput_KeepsFcID_WhenPreservingReferences
|
|
// verifies that function_call items with a valid fc* id are kept when
|
|
// PreserveReferences is true.
|
|
func TestFilterCodexInput_KeepsFcID_WhenPreservingReferences(t *testing.T) {
|
|
input := []any{
|
|
map[string]any{
|
|
"type": "function_call",
|
|
"id": "fc_validID123",
|
|
"call_id": "fc_validID123",
|
|
"name": "bash",
|
|
},
|
|
}
|
|
|
|
filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
|
|
PreserveReferences: true,
|
|
})
|
|
|
|
require.Len(t, filtered, 1)
|
|
fc, ok := filtered[0].(map[string]any)
|
|
require.True(t, ok)
|
|
require.Equal(t, "fc_validID123", fc["id"], "valid fc* id must be preserved")
|
|
}
|
|
|
|
// TestFilterCodexInput_StripsItemIDFromAllToolCallInputTypes verifies that
|
|
// item_* ids are stripped from all call-input types (not output types).
|
|
func TestFilterCodexInput_StripsItemIDFromAllToolCallInputTypes(t *testing.T) {
|
|
types := []string{"function_call", "tool_call", "local_shell_call", "custom_tool_call", "mcp_tool_call"}
|
|
|
|
for _, typ := range types {
|
|
input := []any{
|
|
map[string]any{
|
|
"type": typ,
|
|
"id": "item_xyz",
|
|
"call_id": "fc_001",
|
|
"name": "tool",
|
|
},
|
|
}
|
|
filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
|
|
PreserveReferences: true,
|
|
})
|
|
require.Len(t, filtered, 1)
|
|
item, ok := filtered[0].(map[string]any)
|
|
require.True(t, ok)
|
|
_, hasID := item["id"]
|
|
require.False(t, hasID, "item_* id should be stripped from %s", typ)
|
|
}
|
|
}
|
|
|
|
// TestFilterCodexInput_OutputTypeKeepsItemID ensures tool-output items
|
|
// (e.g. function_call_output) keep their id — only call-input types have
|
|
// the fc* constraint.
|
|
func TestFilterCodexInput_OutputTypeKeepsItemID(t *testing.T) {
|
|
input := []any{
|
|
map[string]any{
|
|
"type": "function_call_output",
|
|
"id": "o1",
|
|
"call_id": "fc_abc",
|
|
"output": "done",
|
|
},
|
|
}
|
|
|
|
filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
|
|
PreserveReferences: true,
|
|
})
|
|
|
|
require.Len(t, filtered, 1)
|
|
out, ok := filtered[0].(map[string]any)
|
|
require.True(t, ok)
|
|
require.Equal(t, "o1", out["id"], "output item id should be preserved")
|
|
}
|
|
|
|
// TestFilterCodexInput_NonToolCallItemKeepsID ensures items subject to neither
|
|
// the fc* (call-input) nor the msg* (message) prefix rule still keep their id
|
|
// when PreserveReferences is true.
|
|
// message is covered separately in openai_codex_message_item_id_test.go (#3981).
|
|
func TestFilterCodexInput_NonToolCallItemKeepsID(t *testing.T) {
|
|
input := []any{
|
|
map[string]any{
|
|
"type": "web_search_call",
|
|
"id": "ws_001",
|
|
},
|
|
}
|
|
|
|
filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
|
|
PreserveReferences: true,
|
|
})
|
|
|
|
require.Len(t, filtered, 1)
|
|
item, ok := filtered[0].(map[string]any)
|
|
require.True(t, ok)
|
|
require.Equal(t, "ws_001", item["id"], "unconstrained items keep their id in preserve mode")
|
|
}
|