diff --git a/.gitignore b/.gitignore index a61f406d..cf251f07 100644 --- a/.gitignore +++ b/.gitignore @@ -122,7 +122,7 @@ scripts .code-review-state #openspec/ code-reviews/ -#AGENTS.md +AGENTS.md backend/cmd/server/server deploy/docker-compose.override.yml .gocache/ diff --git a/backend/internal/service/openai_ws_forwarder.go b/backend/internal/service/openai_ws_forwarder.go index 023217b2..d1386b1b 100644 --- a/backend/internal/service/openai_ws_forwarder.go +++ b/backend/internal/service/openai_ws_forwarder.go @@ -1379,10 +1379,12 @@ func shouldInferIngressFunctionCallOutputPreviousResponseID( if signals.HasFunctionCallOutputMissingCallID { return false } - // If the client already sent tool-call context or item_reference anchors, - // treat this as a full replay / self-contained continuation payload rather - // than downgrading it into an inferred delta continuation. - if signals.HasToolCallContext || signals.HasItemReferenceForAllCallIDs { + // If the client already sent the actual tool-call context, treat this as + // a full replay / self-contained continuation payload rather than + // downgrading it into an inferred delta continuation. item_reference alone + // is not enough on the store=false WS path: it still needs a valid prior + // response anchor so upstream can resolve the referenced function_call. + if signals.HasToolCallContext { return false } return strings.TrimSpace(expectedPreviousResponseID) != "" diff --git a/backend/internal/service/openai_ws_forwarder_ingress_session_test.go b/backend/internal/service/openai_ws_forwarder_ingress_session_test.go index 701f069a..30fd4142 100644 --- a/backend/internal/service/openai_ws_forwarder_ingress_session_test.go +++ b/backend/internal/service/openai_ws_forwarder_ingress_session_test.go @@ -1488,7 +1488,7 @@ func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_StoreDisabledFun require.False(t, gjson.Get(requestToJSONString(captureConn.writes[1]), "previous_response_id").Exists(), "请求已包含 function_call 上下文时不应自动补齐 previous_response_id") } -func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_StoreDisabledFunctionCallOutputSkipsAutoAttachWhenItemReferencesPresent(t *testing.T) { +func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_StoreDisabledFunctionCallOutputAutoAttachWhenOnlyItemReferencesPresent(t *testing.T) { gin.SetMode(gin.TestMode) cfg := &config.Config{} @@ -1619,7 +1619,7 @@ func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_StoreDisabledFun require.Equal(t, 1, captureDialer.DialCount()) require.Len(t, captureConn.writes, 2) - require.False(t, gjson.Get(requestToJSONString(captureConn.writes[1]), "previous_response_id").Exists(), "请求已包含 item_reference 锚点时不应自动补齐 previous_response_id") + require.Equal(t, "resp_auto_prev_ref_1", gjson.Get(requestToJSONString(captureConn.writes[1]), "previous_response_id").String(), "仅有 item_reference 不足以自包含 function_call_output,应回填上一轮响应 ID") } func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_PreflightPingFailReconnectsBeforeTurn(t *testing.T) { diff --git a/backend/internal/service/openai_ws_forwarder_ingress_test.go b/backend/internal/service/openai_ws_forwarder_ingress_test.go index 08597f0c..c735f50a 100644 --- a/backend/internal/service/openai_ws_forwarder_ingress_test.go +++ b/backend/internal/service/openai_ws_forwarder_ingress_test.go @@ -303,12 +303,12 @@ func TestShouldInferIngressFunctionCallOutputPreviousResponseID(t *testing.T) { want: false, }, { - name: "skip_when_item_reference_already_covers_all_call_ids", + name: "infer_when_only_item_reference_covers_call_ids", storeDisabled: true, turn: 2, signals: ToolContinuationSignals{HasFunctionCallOutput: true, HasItemReferenceForAllCallIDs: true}, expectedPrevious: "resp_2", - want: false, + want: true, }, { name: "skip_when_function_call_output_missing_call_id",