diff --git a/apps/edge/internal/openai/hot_path_light.go b/apps/edge/internal/openai/hot_path_light.go index 77fe5aef..7c63117e 100644 --- a/apps/edge/internal/openai/hot_path_light.go +++ b/apps/edge/internal/openai/hot_path_light.go @@ -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 diff --git a/apps/edge/internal/openai/hot_path_light_test.go b/apps/edge/internal/openai/hot_path_light_test.go index 7a575af4..c39d7625 100644 --- a/apps/edge/internal/openai/hot_path_light_test.go +++ b/apps/edge/internal/openai/hot_path_light_test.go @@ -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")