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
6acb9f79
Unverified
Commit
6acb9f79
authored
Mar 09, 2026
by
Wesley Liddick
Committed by
GitHub
Mar 09, 2026
Browse files
Merge pull request #864 from StarryKira/fix/clear-thinking-context-management
[Fix] Fix issue #851
parents
97aaa247
fa72f194
Changes
2
Hide whitespace changes
Inline
Side-by-side
backend/internal/service/gateway_request.go
View file @
6acb9f79
...
@@ -259,6 +259,7 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
...
@@ -259,6 +259,7 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
if
!
hasEmptyContent
&&
!
containsThinkingBlocks
{
if
!
hasEmptyContent
&&
!
containsThinkingBlocks
{
if
topThinking
:=
gjson
.
Get
(
jsonStr
,
"thinking"
);
topThinking
.
Exists
()
{
if
topThinking
:=
gjson
.
Get
(
jsonStr
,
"thinking"
);
topThinking
.
Exists
()
{
if
out
,
err
:=
sjson
.
DeleteBytes
(
body
,
"thinking"
);
err
==
nil
{
if
out
,
err
:=
sjson
.
DeleteBytes
(
body
,
"thinking"
);
err
==
nil
{
out
=
removeThinkingDependentContextStrategies
(
out
)
return
out
return
out
}
}
return
body
return
body
...
@@ -396,6 +397,10 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
...
@@ -396,6 +397,10 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
}
else
{
}
else
{
return
body
return
body
}
}
// Removing "thinking" makes any context_management strategy that requires it invalid
// (e.g. clear_thinking_20251015). Strip those entries so the retry request does not
// receive a 400 "strategy requires thinking to be enabled or adaptive".
out
=
removeThinkingDependentContextStrategies
(
out
)
}
}
if
modified
{
if
modified
{
msgsBytes
,
err
:=
json
.
Marshal
(
messages
)
msgsBytes
,
err
:=
json
.
Marshal
(
messages
)
...
@@ -410,6 +415,49 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
...
@@ -410,6 +415,49 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
return
out
return
out
}
}
// removeThinkingDependentContextStrategies 从 context_management.edits 中移除
// 需要 thinking 启用的策略(如 clear_thinking_20251015)。
// 当顶层 "thinking" 字段被禁用时必须调用,否则上游会返回
// "strategy requires thinking to be enabled or adaptive"。
func
removeThinkingDependentContextStrategies
(
body
[]
byte
)
[]
byte
{
jsonStr
:=
*
(
*
string
)(
unsafe
.
Pointer
(
&
body
))
editsRes
:=
gjson
.
Get
(
jsonStr
,
"context_management.edits"
)
if
!
editsRes
.
Exists
()
||
!
editsRes
.
IsArray
()
{
return
body
}
var
filtered
[]
json
.
RawMessage
hasRemoved
:=
false
editsRes
.
ForEach
(
func
(
_
,
v
gjson
.
Result
)
bool
{
if
v
.
Get
(
"type"
)
.
String
()
==
"clear_thinking_20251015"
{
hasRemoved
=
true
return
true
}
filtered
=
append
(
filtered
,
json
.
RawMessage
(
v
.
Raw
))
return
true
})
if
!
hasRemoved
{
return
body
}
if
len
(
filtered
)
==
0
{
if
b
,
err
:=
sjson
.
DeleteBytes
(
body
,
"context_management.edits"
);
err
==
nil
{
return
b
}
return
body
}
filteredBytes
,
err
:=
json
.
Marshal
(
filtered
)
if
err
!=
nil
{
return
body
}
if
b
,
err
:=
sjson
.
SetRawBytes
(
body
,
"context_management.edits"
,
filteredBytes
);
err
==
nil
{
return
b
}
return
body
}
// FilterSignatureSensitiveBlocksForRetry is a stronger retry filter for cases where upstream errors indicate
// FilterSignatureSensitiveBlocksForRetry is a stronger retry filter for cases where upstream errors indicate
// signature/thought_signature validation issues involving tool blocks.
// signature/thought_signature validation issues involving tool blocks.
//
//
...
@@ -445,6 +493,28 @@ func FilterSignatureSensitiveBlocksForRetry(body []byte) []byte {
...
@@ -445,6 +493,28 @@ func FilterSignatureSensitiveBlocksForRetry(body []byte) []byte {
if
_
,
exists
:=
req
[
"thinking"
];
exists
{
if
_
,
exists
:=
req
[
"thinking"
];
exists
{
delete
(
req
,
"thinking"
)
delete
(
req
,
"thinking"
)
modified
=
true
modified
=
true
// Remove context_management strategies that require thinking to be enabled
// (e.g. clear_thinking_20251015), otherwise upstream returns 400.
if
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
);
ok
{
if
edits
,
ok
:=
cm
[
"edits"
]
.
([]
any
);
ok
{
filtered
:=
make
([]
any
,
0
,
len
(
edits
))
for
_
,
edit
:=
range
edits
{
if
editMap
,
ok
:=
edit
.
(
map
[
string
]
any
);
ok
{
if
editMap
[
"type"
]
==
"clear_thinking_20251015"
{
continue
}
}
filtered
=
append
(
filtered
,
edit
)
}
if
len
(
filtered
)
!=
len
(
edits
)
{
if
len
(
filtered
)
==
0
{
delete
(
cm
,
"edits"
)
}
else
{
cm
[
"edits"
]
=
filtered
}
}
}
}
}
}
messages
,
ok
:=
req
[
"messages"
]
.
([]
any
)
messages
,
ok
:=
req
[
"messages"
]
.
([]
any
)
...
...
backend/internal/service/gateway_request_test.go
View file @
6acb9f79
...
@@ -439,6 +439,210 @@ func TestFilterSignatureSensitiveBlocksForRetry_DowngradesTools(t *testing.T) {
...
@@ -439,6 +439,210 @@ func TestFilterSignatureSensitiveBlocksForRetry_DowngradesTools(t *testing.T) {
require
.
Contains
(
t
,
content1
[
"text"
],
"tool_result"
)
require
.
Contains
(
t
,
content1
[
"text"
],
"tool_result"
)
}
}
// ============ Group 6b: context_management.edits 清理测试 ============
// removeThinkingDependentContextStrategies — 边界用例
func
TestRemoveThinkingDependentContextStrategies_NoContextManagement
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{"thinking":{"type":"enabled"},"messages":[]}`
)
out
:=
removeThinkingDependentContextStrategies
(
input
)
require
.
Equal
(
t
,
input
,
out
,
"无 context_management 字段时应原样返回"
)
}
func
TestRemoveThinkingDependentContextStrategies_EmptyEdits
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{"context_management":{"edits":[]},"messages":[]}`
)
out
:=
removeThinkingDependentContextStrategies
(
input
)
require
.
Equal
(
t
,
input
,
out
,
"edits 为空数组时应原样返回"
)
}
func
TestRemoveThinkingDependentContextStrategies_NoClearThinkingEntry
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{"context_management":{"edits":[{"type":"other_strategy"}]},"messages":[]}`
)
out
:=
removeThinkingDependentContextStrategies
(
input
)
require
.
Equal
(
t
,
input
,
out
,
"edits 中无 clear_thinking_20251015 时应原样返回"
)
}
func
TestRemoveThinkingDependentContextStrategies_RemovesSingleEntry
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{"context_management":{"edits":[{"type":"clear_thinking_20251015"}]},"messages":[]}`
)
out
:=
removeThinkingDependentContextStrategies
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
_
,
hasEdits
:=
cm
[
"edits"
]
require
.
False
(
t
,
hasEdits
,
"所有 edits 均为 clear_thinking_20251015 时应删除 edits 键"
)
}
func
TestRemoveThinkingDependentContextStrategies_MixedEntries
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{"context_management":{"edits":[{"type":"clear_thinking_20251015"},{"type":"other_strategy","param":1}]},"messages":[]}`
)
out
:=
removeThinkingDependentContextStrategies
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
edits
,
ok
:=
cm
[
"edits"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
edits
,
1
,
"仅移除 clear_thinking_20251015,保留其他条目"
)
edit0
,
ok
:=
edits
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"other_strategy"
,
edit0
[
"type"
])
}
// FilterThinkingBlocksForRetry — 包含 context_management 的场景
func
TestFilterThinkingBlocksForRetry_RemovesClearThinkingStrategy_FastPath
(
t
*
testing
.
T
)
{
// 快速路径:messages 中无 thinking 块,仅有顶层 thinking 字段
// 这条路径曾因提前 return 跳过 removeThinkingDependentContextStrategies 而存在 bug
input
:=
[]
byte
(
`{
"thinking":{"type":"enabled","budget_tokens":1024},
"context_management":{"edits":[{"type":"clear_thinking_20251015"}]},
"messages":[
{"role":"user","content":[{"type":"text","text":"Hello"}]}
]
}`
)
out
:=
FilterThinkingBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
_
,
hasThinking
:=
req
[
"thinking"
]
require
.
False
(
t
,
hasThinking
,
"顶层 thinking 应被移除"
)
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
_
,
hasEdits
:=
cm
[
"edits"
]
require
.
False
(
t
,
hasEdits
,
"fast path 下 clear_thinking_20251015 应被移除,edits 键应被删除"
)
}
func
TestFilterThinkingBlocksForRetry_RemovesClearThinkingStrategy_WithThinkingBlocks
(
t
*
testing
.
T
)
{
// 完整路径:messages 中有 thinking 块(非 fast path)
input
:=
[]
byte
(
`{
"thinking":{"type":"enabled","budget_tokens":1024},
"context_management":{"edits":[{"type":"clear_thinking_20251015"},{"type":"keep_this"}]},
"messages":[
{"role":"assistant","content":[
{"type":"thinking","thinking":"some thought","signature":"sig"},
{"type":"text","text":"Answer"}
]}
]
}`
)
out
:=
FilterThinkingBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
_
,
hasThinking
:=
req
[
"thinking"
]
require
.
False
(
t
,
hasThinking
,
"顶层 thinking 应被移除"
)
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
edits
,
ok
:=
cm
[
"edits"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
edits
,
1
,
"仅移除 clear_thinking_20251015,保留 keep_this"
)
edit0
,
ok
:=
edits
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"keep_this"
,
edit0
[
"type"
])
}
func
TestFilterThinkingBlocksForRetry_NoContextManagement_Unaffected
(
t
*
testing
.
T
)
{
// 无 context_management 时不应报错,且 thinking 正常被移除
input
:=
[]
byte
(
`{
"thinking":{"type":"enabled"},
"messages":[{"role":"user","content":[{"type":"text","text":"Hi"}]}]
}`
)
out
:=
FilterThinkingBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
_
,
hasThinking
:=
req
[
"thinking"
]
require
.
False
(
t
,
hasThinking
)
_
,
hasCM
:=
req
[
"context_management"
]
require
.
False
(
t
,
hasCM
)
}
// FilterSignatureSensitiveBlocksForRetry — 包含 context_management 的场景
func
TestFilterSignatureSensitiveBlocksForRetry_RemovesClearThinkingStrategy
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{
"thinking":{"type":"enabled","budget_tokens":1024},
"context_management":{"edits":[{"type":"clear_thinking_20251015"}]},
"messages":[
{"role":"assistant","content":[
{"type":"thinking","thinking":"thought","signature":"sig"}
]}
]
}`
)
out
:=
FilterSignatureSensitiveBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
_
,
hasThinking
:=
req
[
"thinking"
]
require
.
False
(
t
,
hasThinking
,
"顶层 thinking 应被移除"
)
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
if
rawEdits
,
hasEdits
:=
cm
[
"edits"
];
hasEdits
{
edits
,
ok
:=
rawEdits
.
([]
any
)
require
.
True
(
t
,
ok
)
for
_
,
e
:=
range
edits
{
em
,
ok
:=
e
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
NotEqual
(
t
,
"clear_thinking_20251015"
,
em
[
"type"
],
"clear_thinking_20251015 应被移除"
)
}
}
}
func
TestFilterSignatureSensitiveBlocksForRetry_PreservesNonThinkingStrategies
(
t
*
testing
.
T
)
{
input
:=
[]
byte
(
`{
"thinking":{"type":"enabled"},
"context_management":{"edits":[{"type":"clear_thinking_20251015"},{"type":"other_edit"}]},
"messages":[
{"role":"assistant","content":[
{"type":"thinking","thinking":"t","signature":"s"}
]}
]
}`
)
out
:=
FilterSignatureSensitiveBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
edits
,
ok
:=
cm
[
"edits"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
edits
,
1
,
"仅移除 clear_thinking_20251015,保留 other_edit"
)
edit0
,
ok
:=
edits
[
0
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
require
.
Equal
(
t
,
"other_edit"
,
edit0
[
"type"
])
}
func
TestFilterSignatureSensitiveBlocksForRetry_NoThinkingField_ContextManagementUntouched
(
t
*
testing
.
T
)
{
// 没有顶层 thinking 字段时,context_management 不应被修改
input
:=
[]
byte
(
`{
"context_management":{"edits":[{"type":"clear_thinking_20251015"}]},
"messages":[
{"role":"assistant","content":[
{"type":"thinking","thinking":"t","signature":"s"}
]}
]
}`
)
out
:=
FilterSignatureSensitiveBlocksForRetry
(
input
)
var
req
map
[
string
]
any
require
.
NoError
(
t
,
json
.
Unmarshal
(
out
,
&
req
))
cm
,
ok
:=
req
[
"context_management"
]
.
(
map
[
string
]
any
)
require
.
True
(
t
,
ok
)
edits
,
ok
:=
cm
[
"edits"
]
.
([]
any
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
edits
,
1
,
"无顶层 thinking 时 context_management 不应被修改"
)
}
// ============ Group 7: ParseGatewayRequest 补充单元测试 ============
// ============ Group 7: ParseGatewayRequest 补充单元测试 ============
// Task 7.1 — 类型校验边界测试
// Task 7.1 — 类型校验边界测试
...
...
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