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
26298c4a
"backend/internal/vscode:/vscode.git/clone" did not exist on "70836c700a5f4d249c008ab6deaa5908c151daa5"
Commit
26298c4a
authored
Jan 19, 2026
by
cyhhao
Browse files
fix(openai): emit OpenAI-compatible SSE error events
parent
eb7d8302
Changes
2
Hide whitespace changes
Inline
Side-by-side
backend/internal/service/openai_gateway_service.go
View file @
26298c4a
...
...
@@ -1067,7 +1067,9 @@ func (s *OpenAIGatewayService) handleStreamingResponse(ctx context.Context, resp
// 记录上次收到上游数据的时间,用于控制 keepalive 发送频率
lastDataAt
:=
time
.
Now
()
// 仅发送一次错误事件,避免多次写入导致协议混乱(写失败时尽力通知客户端)
// 仅发送一次错误事件,避免多次写入导致协议混乱。
// 注意:OpenAI `/v1/responses` streaming 事件必须符合 OpenAI Responses schema;
// 否则下游 SDK(例如 OpenCode)会因为类型校验失败而报错。
errorEventSent
:=
false
clientDisconnected
:=
false
// 客户端断开后继续 drain 上游以收集 usage
sendErrorEvent
:=
func
(
reason
string
)
{
...
...
@@ -1075,8 +1077,19 @@ func (s *OpenAIGatewayService) handleStreamingResponse(ctx context.Context, resp
return
}
errorEventSent
=
true
_
,
_
=
fmt
.
Fprintf
(
w
,
"event: error
\n
data: {
\"
error
\"
:
\"
%s
\"
}
\n\n
"
,
reason
)
flusher
.
Flush
()
payload
:=
map
[
string
]
any
{
"type"
:
"error"
,
"sequence_number"
:
0
,
"error"
:
map
[
string
]
any
{
"type"
:
"upstream_error"
,
"message"
:
reason
,
"code"
:
reason
,
},
}
if
b
,
err
:=
json
.
Marshal
(
payload
);
err
==
nil
{
_
,
_
=
fmt
.
Fprintf
(
w
,
"data: %s
\n\n
"
,
b
)
flusher
.
Flush
()
}
}
needModelReplace
:=
originalModel
!=
mappedModel
...
...
backend/internal/service/openai_gateway_service_test.go
View file @
26298c4a
...
...
@@ -188,8 +188,8 @@ func TestOpenAIStreamingTimeout(t *testing.T) {
if
err
==
nil
||
!
strings
.
Contains
(
err
.
Error
(),
"stream data interval timeout"
)
{
t
.
Fatalf
(
"expected stream timeout error, got %v"
,
err
)
}
if
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"stream_timeout"
)
{
t
.
Fatalf
(
"expected
stream_timeout
SSE e
rror
, got %q"
,
rec
.
Body
.
String
())
if
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"
\"
type
\"
:
\"
error
\"
"
)
||
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"stream_timeout"
)
{
t
.
Fatalf
(
"expected
OpenAI-compatible error
SSE e
vent
, got %q"
,
rec
.
Body
.
String
())
}
}
...
...
@@ -305,8 +305,8 @@ func TestOpenAIStreamingTooLong(t *testing.T) {
if
!
errors
.
Is
(
err
,
bufio
.
ErrTooLong
)
{
t
.
Fatalf
(
"expected ErrTooLong, got %v"
,
err
)
}
if
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"response_too_large"
)
{
t
.
Fatalf
(
"expected
response_too_large
SSE e
rror
, got %q"
,
rec
.
Body
.
String
())
if
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"
\"
type
\"
:
\"
error
\"
"
)
||
!
strings
.
Contains
(
rec
.
Body
.
String
(),
"response_too_large"
)
{
t
.
Fatalf
(
"expected
OpenAI-compatible error
SSE e
vent
, got %q"
,
rec
.
Body
.
String
())
}
}
...
...
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