| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- //go:build unit
- package service
- import (
- "testing"
- "github.com/stretchr/testify/require"
- )
- // TestFilterCodexInput_StripsMessageItemID_WhenPreservingReferences
- // verifies that message items with a non-msg id (e.g. item_*) have their id
- // stripped even when PreserveReferences is true. OpenAI upstream requires
- // message ids to begin with "msg" and rejects item_* with 400:
- // "Expected an ID that begins with 'msg'." (#3981)
- func TestFilterCodexInput_StripsMessageItemID_WhenPreservingReferences(t *testing.T) {
- input := []any{
- map[string]any{
- "type": "message",
- "id": "item_3bc5a3fa8ccde25f1c0000d4",
- "role": "user",
- "content": []any{
- map[string]any{"type": "input_text", "text": "hello"},
- },
- },
- }
- filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
- PreserveReferences: true,
- })
- require.Len(t, filtered, 1)
- msg, ok := filtered[0].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "message", msg["type"])
- _, hasID := msg["id"]
- require.False(t, hasID, "item_* id should be stripped from message")
- require.Equal(t, "user", msg["role"], "role must be preserved")
- require.NotNil(t, msg["content"], "content must be preserved")
- }
- // TestFilterCodexInput_KeepsMsgID_WhenPreservingReferences
- // verifies that message items with a valid msg* id are kept when
- // PreserveReferences is true, so context references are not lost.
- func TestFilterCodexInput_KeepsMsgID_WhenPreservingReferences(t *testing.T) {
- input := []any{
- map[string]any{
- "type": "message",
- "id": "msg_validID123",
- "role": "assistant",
- },
- }
- filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
- PreserveReferences: true,
- })
- require.Len(t, filtered, 1)
- msg, ok := filtered[0].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "msg_validID123", msg["id"], "valid msg* id must be preserved")
- }
- // TestFilterCodexInput_StripsMessageIDWhenNotPreservingReferences ensures the
- // non-continuation path still drops every message id regardless of prefix.
- func TestFilterCodexInput_StripsMessageIDWhenNotPreservingReferences(t *testing.T) {
- for _, id := range []string{"item_abc", "msg_validID123"} {
- input := []any{
- map[string]any{
- "type": "message",
- "id": id,
- "role": "user",
- },
- }
- filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
- PreserveReferences: false,
- })
- require.Len(t, filtered, 1)
- msg, ok := filtered[0].(map[string]any)
- require.True(t, ok)
- _, hasID := msg["id"]
- require.False(t, hasID, "id %q should be stripped when not preserving references", id)
- }
- }
- // TestFilterCodexInput_MessageIDStripDoesNotMutateInput ensures the original
- // input map is not modified in place when the id is stripped.
- func TestFilterCodexInput_MessageIDStripDoesNotMutateInput(t *testing.T) {
- original := map[string]any{
- "type": "message",
- "id": "item_abc",
- "role": "user",
- }
- filtered := filterCodexInputWithOptions([]any{original}, codexInputFilterOptions{
- PreserveReferences: true,
- })
- require.Len(t, filtered, 1)
- require.Equal(t, "item_abc", original["id"], "original input must not be mutated")
- }
- // TestFilterCodexInput_MessageStripKeepsFunctionCallBehavior guards against a
- // regression of #3785: message and function_call id rules are independent.
- func TestFilterCodexInput_MessageStripKeepsFunctionCallBehavior(t *testing.T) {
- input := []any{
- map[string]any{
- "type": "message",
- "id": "item_msg_001",
- "role": "user",
- },
- map[string]any{
- "type": "function_call",
- "id": "fc_validID123",
- "call_id": "fc_validID123",
- "name": "bash",
- },
- map[string]any{
- "type": "function_call",
- "id": "item_A9v0SNfS3VaLrfX0j3y4xhyK",
- "call_id": "fc_abc123",
- "name": "bash",
- },
- map[string]any{
- "type": "function_call_output",
- "id": "o1",
- "call_id": "fc_abc123",
- "output": "done",
- },
- }
- filtered := filterCodexInputWithOptions(input, codexInputFilterOptions{
- PreserveReferences: true,
- })
- require.Len(t, filtered, 4)
- msg, ok := filtered[0].(map[string]any)
- require.True(t, ok)
- _, hasID := msg["id"]
- require.False(t, hasID, "message item_* id should be stripped")
- fcValid, ok := filtered[1].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "fc_validID123", fcValid["id"], "valid fc* id must be preserved")
- fcBad, ok := filtered[2].(map[string]any)
- require.True(t, ok)
- _, hasID = fcBad["id"]
- require.False(t, hasID, "function_call item_* id should still be stripped")
- require.Equal(t, "fc_abc123", fcBad["call_id"], "call_id pairing must survive")
- out, ok := filtered[3].(map[string]any)
- require.True(t, ok)
- require.Equal(t, "o1", out["id"], "output item id should be preserved")
- require.Equal(t, "fc_abc123", out["call_id"], "call_id pairing must survive")
- }
|