fix(openai): hybrid 도구 응답을 pending receipt로 연결한다

This commit is contained in:
toki 2026-08-15 15:59:47 +09:00
parent 74b6f0b99c
commit a200e0051c
2 changed files with 24 additions and 2 deletions

View file

@ -670,7 +670,10 @@ func (s *hotPathLightStore) consume(ownerEdgeID, principalRef, protocol string,
byPublic[result.callID] = result
}
snap, err := coordinator.consumeContinuationByLineage(ownerEdgeID, principalRef, lineage)
// Command-mode SDKs may reserialize earlier message history between tool
// turns. The pending receipt already binds this continuation to the exact
// request, owner, principal, endpoint, toolset, issued calls, and result IDs.
snap, err := coordinator.consumeArtifactContinuationByLineage(record.requestID, ownerEdgeID, principalRef, lineage)
if err != nil {
return logicalRequestSnapshot{}, hotPathLightDisposition{}, true, err
}
@ -838,7 +841,7 @@ func (s *hotPathLightStore) matchRecordLocked(ownerEdgeID, principalRef, protoco
if record.protocol != protocol {
return nil, true, fmt.Errorf("%w: protocol changed", errLogicalRequestLineage)
}
if record.lineage != lineage.Prefix {
if record.lineage.Endpoint != lineage.Prefix.Endpoint || record.lineage.ToolsetDigest != lineage.Prefix.ToolsetDigest {
return nil, true, describeArtifactPrefixMismatch(record.lineage, lineage.Prefix)
}
return record, true, nil

View file

@ -78,6 +78,25 @@ func TestHotPathStageOrdinaryWorkspacePathPassesThrough(t *testing.T) {
}
}
func TestHotPathLightMatchesPendingReceiptAfterSDKHistoryRewrite(t *testing.T) {
store := &hotPathLightStore{records: map[string]*hotPathLightRecord{
"req_history_rewrite": {
requestID: "req_history_rewrite", ownerEdgeID: "edge", principalRef: "principal", protocol: "anthropic",
lineage: logicalRequestLineage{Endpoint: "anthropic", HistoryDigest: "before", ToolsetDigest: "tools"},
pending: map[string]hotPathPendingCall{"call_pending": {publicCallID: "call_pending"}}, pendingHash: "issued",
consumedHashes: map[string]struct{}{}, consumedIDs: map[string]struct{}{},
},
}}
lineage := logicalRequestContinuationLineage{
Prefix: logicalRequestLineage{Endpoint: "anthropic", HistoryDigest: "rewritten", ToolsetDigest: "tools"},
IssuedCallHash: "issued", ResultIDs: []string{"call_pending"},
}
record, matched, err := store.matchRecordLocked("edge", "principal", "anthropic", lineage)
if err != nil || !matched || record == nil || record.requestID != "req_history_rewrite" {
t.Fatalf("pending receipt match: record=%+v matched=%t err=%v", record, matched, err)
}
}
func TestWorkerReviewReadIsNotClassifiedAsHandoffWrite(t *testing.T) {
binding := mustBinding(t, fullWorkspaceAlternative("workspace", "workspace", false), []any{openAIChatTool("workspace", structuredSchema())})
paths := newReservedPaths("req_review_read")