Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
959af1c8
Commit
959af1c8
authored
Apr 24, 2026
by
song
Browse files
fix(openai): preserve codex tool call ids
parent
d162604f
Changes
4
Show whitespace changes
Inline
Side-by-side
backend/internal/service/openai_codex_transform.go
View file @
959af1c8
...
@@ -658,12 +658,14 @@ func filterCodexInput(input []any, preserveReferences bool) []any {
...
@@ -658,12 +658,14 @@ func filterCodexInput(input []any, preserveReferences bool) []any {
}
}
}
}
if
!
preserveReferences
{
ensureCopy
()
delete
(
newItem
,
"id"
)
if
!
isCodexToolCallItemType
(
typ
)
{
if
!
isCodexToolCallItemType
(
typ
)
{
ensureCopy
()
delete
(
newItem
,
"call_id"
)
delete
(
newItem
,
"call_id"
)
}
}
if
!
preserveReferences
{
ensureCopy
()
delete
(
newItem
,
"id"
)
}
}
filtered
=
append
(
filtered
,
newItem
)
filtered
=
append
(
filtered
,
newItem
)
...
@@ -672,10 +674,20 @@ func filterCodexInput(input []any, preserveReferences bool) []any {
...
@@ -672,10 +674,20 @@ func filterCodexInput(input []any, preserveReferences bool) []any {
}
}
func
isCodexToolCallItemType
(
typ
string
)
bool
{
func
isCodexToolCallItemType
(
typ
string
)
bool
{
if
typ
==
""
{
switch
typ
{
case
"function_call"
,
"tool_call"
,
"local_shell_call"
,
"tool_search_call"
,
"custom_tool_call"
,
"function_call_output"
,
"mcp_tool_call_output"
,
"custom_tool_call_output"
,
"tool_search_output"
:
return
true
default
:
return
false
return
false
}
}
return
strings
.
HasSuffix
(
typ
,
"_call"
)
||
strings
.
HasSuffix
(
typ
,
"_call_output"
)
}
}
func
normalizeCodexTools
(
reqBody
map
[
string
]
any
)
bool
{
func
normalizeCodexTools
(
reqBody
map
[
string
]
any
)
bool
{
...
...
backend/internal/service/openai_codex_transform_test.go
View file @
959af1c8
...
@@ -92,6 +92,78 @@ func TestApplyCodexOAuthTransform_ToolContinuationNormalizesToolReferenceIDsOnly
...
@@ -92,6 +92,78 @@ func TestApplyCodexOAuthTransform_ToolContinuationNormalizesToolReferenceIDsOnly
require
.
Equal
(
t
,
"fc1"
,
second
[
"call_id"
])
require
.
Equal
(
t
,
"fc1"
,
second
[
"call_id"
])
}
}
func
TestApplyCodexOAuthTransform_ToolSearchOutputPreservesCallID
(
t
*
testing
.
T
)
{
reqBody
:=
map
[
string
]
any
{
"model"
:
"gpt-5.2"
,
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"tool_search_output"
,
"call_id"
:
"call_1"
,
"output"
:
"ok"
},
},
}
applyCodexOAuthTransform
(
reqBody
,
false
,
false
)
input
,
ok
:=
reqBody
[
"input"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
input
,
1
)
first
,
ok
:=
input
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"tool_search_output"
,
first
[
"type"
])
require
.
Equal
(
t
,
"fc1"
,
first
[
"call_id"
])
}
func
TestApplyCodexOAuthTransform_CustomAndMCPToolOutputsPreserveCallID
(
t
*
testing
.
T
)
{
reqBody
:=
map
[
string
]
any
{
"model"
:
"gpt-5.2"
,
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"custom_tool_call_output"
,
"call_id"
:
"call_custom"
,
"output"
:
"ok"
},
map
[
string
]
any
{
"type"
:
"mcp_tool_call_output"
,
"call_id"
:
"call_mcp"
,
"output"
:
"ok"
},
},
}
applyCodexOAuthTransform
(
reqBody
,
false
,
false
)
input
,
ok
:=
reqBody
[
"input"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
input
,
2
)
first
,
ok
:=
input
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"fccustom"
,
first
[
"call_id"
])
second
,
ok
:=
input
[
1
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"fcmcp"
,
second
[
"call_id"
])
}
func
TestApplyCodexOAuthTransform_ImageAndWebSearchCallsDoNotGainCallID
(
t
*
testing
.
T
)
{
reqBody
:=
map
[
string
]
any
{
"model"
:
"gpt-5.2"
,
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"image_generation_call"
,
"id"
:
"ig_123"
,
"status"
:
"completed"
},
map
[
string
]
any
{
"type"
:
"web_search_call"
,
"call_id"
:
"call_bad"
,
"status"
:
"completed"
},
},
"tool_choice"
:
"auto"
,
}
applyCodexOAuthTransform
(
reqBody
,
false
,
false
)
input
,
ok
:=
reqBody
[
"input"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
input
,
2
)
first
,
ok
:=
input
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"ig_123"
,
first
[
"id"
])
_
,
hasCallID
:=
first
[
"call_id"
]
require
.
False
(
t
,
hasCallID
)
second
,
ok
:=
input
[
1
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
_
,
hasCallID
=
second
[
"call_id"
]
require
.
False
(
t
,
hasCallID
)
}
func
TestApplyCodexOAuthTransform_ExplicitStoreFalsePreserved
(
t
*
testing
.
T
)
{
func
TestApplyCodexOAuthTransform_ExplicitStoreFalsePreserved
(
t
*
testing
.
T
)
{
// 续链场景:显式 store=false 不再强制为 true,保持 false。
// 续链场景:显式 store=false 不再强制为 true,保持 false。
...
...
backend/internal/service/openai_tool_continuation.go
View file @
959af1c8
...
@@ -21,7 +21,7 @@ type FunctionCallOutputValidation struct {
...
@@ -21,7 +21,7 @@ type FunctionCallOutputValidation struct {
}
}
// NeedsToolContinuation 判定请求是否需要工具调用续链处理。
// NeedsToolContinuation 判定请求是否需要工具调用续链处理。
// 满足以下任一信号即视为续链:previous_response_id、input 内包含
function_call_output
/item_reference、
// 满足以下任一信号即视为续链:previous_response_id、input 内包含
工具输出
/item_reference、
// 或显式声明 tools/tool_choice。
// 或显式声明 tools/tool_choice。
func
NeedsToolContinuation
(
reqBody
map
[
string
]
any
)
bool
{
func
NeedsToolContinuation
(
reqBody
map
[
string
]
any
)
bool
{
if
reqBody
==
nil
{
if
reqBody
==
nil
{
...
@@ -46,7 +46,7 @@ func NeedsToolContinuation(reqBody map[string]any) bool {
...
@@ -46,7 +46,7 @@ func NeedsToolContinuation(reqBody map[string]any) bool {
continue
continue
}
}
itemType
,
_
:=
itemMap
[
"type"
]
.
(
string
)
itemType
,
_
:=
itemMap
[
"type"
]
.
(
string
)
if
i
temType
==
"function_call_output"
||
itemType
==
"item_reference"
{
if
i
sCodexToolCallItemType
(
itemType
)
||
itemType
==
"item_reference"
{
return
true
return
true
}
}
}
}
...
...
backend/internal/service/openai_tool_continuation_test.go
View file @
959af1c8
...
@@ -17,6 +17,9 @@ func TestNeedsToolContinuationSignals(t *testing.T) {
...
@@ -17,6 +17,9 @@ func TestNeedsToolContinuationSignals(t *testing.T) {
{
name
:
"previous_response_id"
,
body
:
map
[
string
]
any
{
"previous_response_id"
:
"resp_1"
},
want
:
true
},
{
name
:
"previous_response_id"
,
body
:
map
[
string
]
any
{
"previous_response_id"
:
"resp_1"
},
want
:
true
},
{
name
:
"previous_response_id_blank"
,
body
:
map
[
string
]
any
{
"previous_response_id"
:
" "
},
want
:
false
},
{
name
:
"previous_response_id_blank"
,
body
:
map
[
string
]
any
{
"previous_response_id"
:
" "
},
want
:
false
},
{
name
:
"function_call_output"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"function_call_output"
}}},
want
:
true
},
{
name
:
"function_call_output"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"function_call_output"
}}},
want
:
true
},
{
name
:
"tool_search_output"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"tool_search_output"
}}},
want
:
true
},
{
name
:
"custom_tool_call_output"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"custom_tool_call_output"
}}},
want
:
true
},
{
name
:
"mcp_tool_call_output"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"mcp_tool_call_output"
}}},
want
:
true
},
{
name
:
"item_reference"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"item_reference"
}}},
want
:
true
},
{
name
:
"item_reference"
,
body
:
map
[
string
]
any
{
"input"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"item_reference"
}}},
want
:
true
},
{
name
:
"tools"
,
body
:
map
[
string
]
any
{
"tools"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"function"
}}},
want
:
true
},
{
name
:
"tools"
,
body
:
map
[
string
]
any
{
"tools"
:
[]
any
{
map
[
string
]
any
{
"type"
:
"function"
}}},
want
:
true
},
{
name
:
"tools_empty"
,
body
:
map
[
string
]
any
{
"tools"
:
[]
any
{}},
want
:
false
},
{
name
:
"tools_empty"
,
body
:
map
[
string
]
any
{
"tools"
:
[]
any
{}},
want
:
false
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment