package openai import ( "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" ) // logicalRequestEndpoint keeps fingerprints from incompatible wire formats // distinct even when their JSON payloads happen to look alike. type logicalRequestEndpoint string const ( logicalRequestEndpointChat logicalRequestEndpoint = "chat_completions" logicalRequestEndpointAnthropic logicalRequestEndpoint = "anthropic_messages" ) // logicalRequestLineage is the immutable request prefix and tool contract // recorded when a logical request is admitted. It intentionally contains only // digests: raw prompts, tool schemas, and tool results never enter the store. type logicalRequestLineage struct { Endpoint logicalRequestEndpoint HistoryDigest string ToolsetDigest string } type logicalRequestContinuationLineage struct { Prefix logicalRequestLineage IssuedCallHash string ResultIDs []string Committed logicalRequestLineage } func newChatRequestLineage(raw json.RawMessage) (logicalRequestLineage, error) { fields, err := decodeLogicalRequestLineageEnvelope(raw) if err != nil { return logicalRequestLineage{}, err } rawMessages, ok := fields["messages"] if !ok { return logicalRequestLineage{}, fmt.Errorf("chat messages field is required") } if _, err := validateChatMessages(rawMessages); err != nil { return logicalRequestLineage{}, err } return newLogicalRequestLineageFromRawFields(fields, logicalRequestEndpointChat, []string{"model", "messages"}) } func newAnthropicRequestLineage(raw json.RawMessage) (logicalRequestLineage, error) { fields, err := decodeLogicalRequestLineageEnvelope(raw) if err != nil { return logicalRequestLineage{}, err } rawMessages, ok := fields["messages"] if !ok { return logicalRequestLineage{}, fmt.Errorf("anthropic messages field is required") } if _, err := validateAnthropicMessages(rawMessages); err != nil { return logicalRequestLineage{}, err } return newLogicalRequestLineageFromRawFields(fields, logicalRequestEndpointAnthropic, []string{"model", "system", "messages"}) } type chatMessageValidation struct { Role string `json:"role"` ToolCallID string `json:"tool_call_id"` ToolCalls []struct { ID string `json:"id"` } `json:"tool_calls"` } func validateChatMessages(rawMessages json.RawMessage) ([]json.RawMessage, error) { if len(rawMessages) == 0 { return nil, fmt.Errorf("chat messages field is required") } var msgList []json.RawMessage decoder := json.NewDecoder(bytes.NewReader(rawMessages)) decoder.UseNumber() if err := decoder.Decode(&msgList); err != nil { return nil, fmt.Errorf("chat messages must be an array: %w", err) } if len(msgList) == 0 { return nil, fmt.Errorf("chat messages array must not be empty") } validRoles := map[string]struct{}{ "system": {}, "developer": {}, "user": {}, "assistant": {}, "tool": {}, } globallySeenIssuedIDs := make(map[string]struct{}) pendingToolCallIDs := make(map[string]struct{}) for i, rawMsg := range msgList { var m chatMessageValidation if err := json.Unmarshal(rawMsg, &m); err != nil { return nil, fmt.Errorf("decode chat message at index %d: %w", i, err) } if _, ok := validRoles[m.Role]; !ok { return nil, fmt.Errorf("unknown chat message role %q at index %d", m.Role, i) } if m.Role == "tool" { if len(pendingToolCallIDs) == 0 { return nil, fmt.Errorf("orphan tool result message at index %d", i) } if m.ToolCallID == "" { return nil, fmt.Errorf("tool message at index %d has empty tool_call_id", i) } if _, ok := pendingToolCallIDs[m.ToolCallID]; !ok { return nil, fmt.Errorf("tool message at index %d has unexpected or duplicate tool_call_id %q", i, m.ToolCallID) } delete(pendingToolCallIDs, m.ToolCallID) } else { if len(pendingToolCallIDs) > 0 { return nil, fmt.Errorf("message at index %d with role %q appeared before all preceding tool_calls were satisfied", i, m.Role) } if m.Role == "assistant" && len(m.ToolCalls) > 0 { for tcIdx, tc := range m.ToolCalls { if tc.ID == "" { return nil, fmt.Errorf("assistant message at index %d tool call %d has empty id", i, tcIdx) } if _, duplicate := globallySeenIssuedIDs[tc.ID]; duplicate { return nil, fmt.Errorf("duplicate issued assistant tool call id %q at index %d", tc.ID, i) } globallySeenIssuedIDs[tc.ID] = struct{}{} pendingToolCallIDs[tc.ID] = struct{}{} } } } } if len(pendingToolCallIDs) > 0 { return nil, fmt.Errorf("message list ended before all assistant tool_calls were satisfied") } return msgList, nil } func validateAnthropicMessages(rawMessages json.RawMessage) ([]json.RawMessage, error) { if len(rawMessages) == 0 { return nil, fmt.Errorf("anthropic messages field is required") } var msgList []json.RawMessage decoder := json.NewDecoder(bytes.NewReader(rawMessages)) decoder.UseNumber() if err := decoder.Decode(&msgList); err != nil { return nil, fmt.Errorf("anthropic messages must be an array: %w", err) } if len(msgList) == 0 { return nil, fmt.Errorf("anthropic messages array must not be empty") } globallySeenToolUseIDs := make(map[string]struct{}) pendingToolUseIDs := make(map[string]struct{}) for i, rawMsg := range msgList { var m struct { Role string `json:"role"` Content json.RawMessage `json:"content"` } if err := json.Unmarshal(rawMsg, &m); err != nil { return nil, fmt.Errorf("decode anthropic message at index %d: %w", i, err) } if m.Role != "user" && m.Role != "assistant" { return nil, fmt.Errorf("invalid anthropic message role %q at index %d", m.Role, i) } if i == 0 && m.Role != "user" { return nil, fmt.Errorf("anthropic messages first message must have role user, got %q", m.Role) } if i > 0 { var prev struct { Role string `json:"role"` } _ = json.Unmarshal(msgList[i-1], &prev) if m.Role == prev.Role { return nil, fmt.Errorf("anthropic messages roles must alternate, repeated role %q at index %d", m.Role, i) } } blocks, err := decodeAnthropicContent(m.Content) if err != nil { return nil, fmt.Errorf("anthropic message %d: %w", i, err) } if m.Role == "assistant" { for bIdx, block := range blocks { if block.Type == "tool_result" || block.Type == "image" { return nil, fmt.Errorf("anthropic assistant message %d block %d has invalid type %q", i, bIdx, block.Type) } if block.Type == "tool_use" { if block.ID == "" { return nil, fmt.Errorf("anthropic assistant message %d tool_use block %d has empty id", i, bIdx) } if _, duplicate := globallySeenToolUseIDs[block.ID]; duplicate { return nil, fmt.Errorf("duplicate issued assistant tool_use id %q at message %d", block.ID, i) } globallySeenToolUseIDs[block.ID] = struct{}{} pendingToolUseIDs[block.ID] = struct{}{} } } } else if m.Role == "user" { if len(pendingToolUseIDs) > 0 { if len(blocks) != len(pendingToolUseIDs) { return nil, fmt.Errorf("anthropic user message %d tool results count (%d) does not match issued tool_use count (%d)", i, len(blocks), len(pendingToolUseIDs)) } for bIdx, block := range blocks { if block.Type != "tool_result" { return nil, fmt.Errorf("anthropic user message %d block %d has non-tool_result type %q when responding to tool_use", i, bIdx, block.Type) } if block.ToolUseID == "" { return nil, fmt.Errorf("anthropic user message %d tool_result block %d missing tool_use_id", i, bIdx) } if _, ok := pendingToolUseIDs[block.ToolUseID]; !ok { return nil, fmt.Errorf("anthropic user message %d tool_result tool_use_id %q not in issued tool_use blocks or duplicate", i, block.ToolUseID) } delete(pendingToolUseIDs, block.ToolUseID) } } else { for bIdx, block := range blocks { if block.Type == "tool_use" || block.Type == "thinking" { return nil, fmt.Errorf("anthropic user message %d block %d has invalid type %q", i, bIdx, block.Type) } if block.Type == "tool_result" { return nil, fmt.Errorf("orphan tool_result block in anthropic user message at index %d", i) } } } } } if len(pendingToolUseIDs) > 0 { return nil, fmt.Errorf("anthropic message list ended before tool_use blocks were satisfied") } return msgList, nil } func newChatContinuationLineage(raw json.RawMessage) (logicalRequestContinuationLineage, error) { fields, err := decodeLogicalRequestLineageEnvelope(raw) if err != nil { return logicalRequestContinuationLineage{}, err } rawMessages, ok := fields["messages"] if !ok { return logicalRequestContinuationLineage{}, fmt.Errorf("chat continuation messages field is required") } msgList, err := validateChatMessages(rawMessages) if err != nil { return logicalRequestContinuationLineage{}, err } var resultIDs []string seenResultIDs := make(map[string]struct{}) resultCount := 0 for i := len(msgList) - 1; i >= 0; i-- { var msg struct { Role string `json:"role"` ToolCallID string `json:"tool_call_id"` } if err := json.Unmarshal(msgList[i], &msg); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode message at index %d: %w", i, err) } if msg.Role == "tool" { if msg.ToolCallID == "" { return logicalRequestContinuationLineage{}, fmt.Errorf("tool message at index %d has empty tool_call_id", i) } if _, exists := seenResultIDs[msg.ToolCallID]; exists { return logicalRequestContinuationLineage{}, fmt.Errorf("duplicate tool_call_id %q in frontier", msg.ToolCallID) } seenResultIDs[msg.ToolCallID] = struct{}{} resultIDs = append([]string{msg.ToolCallID}, resultIDs...) resultCount++ } else { break } } if resultCount == 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("chat continuation must end with at least one tool result message") } assistantIndex := len(msgList) - resultCount - 1 if assistantIndex < 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("chat continuation missing issued assistant message before tool results") } var assistantMsg struct { Role string `json:"role"` ToolCalls []struct { ID string `json:"id"` } `json:"tool_calls"` } if err := json.Unmarshal(msgList[assistantIndex], &assistantMsg); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode assistant message: %w", err) } if assistantMsg.Role != "assistant" { return logicalRequestContinuationLineage{}, fmt.Errorf("expected assistant message before tool results, got role %q", assistantMsg.Role) } if len(assistantMsg.ToolCalls) == 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("issued assistant message must contain tool_calls") } expectedToolCallIDs := make(map[string]struct{}, len(assistantMsg.ToolCalls)) for _, tc := range assistantMsg.ToolCalls { if tc.ID == "" { return logicalRequestContinuationLineage{}, fmt.Errorf("issued assistant tool call has empty id") } if _, duplicate := expectedToolCallIDs[tc.ID]; duplicate { return logicalRequestContinuationLineage{}, fmt.Errorf("duplicate issued assistant tool call id %q", tc.ID) } expectedToolCallIDs[tc.ID] = struct{}{} } if len(expectedToolCallIDs) != len(seenResultIDs) { return logicalRequestContinuationLineage{}, fmt.Errorf("frontier tool results count (%d) does not match issued assistant tool_calls count (%d)", len(seenResultIDs), len(expectedToolCallIDs)) } for id := range seenResultIDs { if _, ok := expectedToolCallIDs[id]; !ok { return logicalRequestContinuationLineage{}, fmt.Errorf("frontier tool_call_id %q not in issued assistant tool_calls", id) } } issuedCallHash, err := fingerprintCanonicalJSON(logicalRequestEndpointChat, msgList[assistantIndex]) if err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("fingerprint issued assistant call: %w", err) } prefixMessagesRaw, err := json.Marshal(msgList[:assistantIndex]) if err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("marshal prefix messages: %w", err) } prefixHistory := map[string]json.RawMessage{ "model": fields["model"], "messages": prefixMessagesRaw, } prefixHistoryDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointChat, prefixHistory) if err != nil { return logicalRequestContinuationLineage{}, err } toolsetDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointChat, fields["tools"]) if err != nil { return logicalRequestContinuationLineage{}, err } prefixLineage := logicalRequestLineage{ Endpoint: logicalRequestEndpointChat, HistoryDigest: prefixHistoryDigest, ToolsetDigest: toolsetDigest, } committedHistory := map[string]json.RawMessage{ "model": fields["model"], "messages": fields["messages"], } committedHistoryDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointChat, committedHistory) if err != nil { return logicalRequestContinuationLineage{}, err } committedLineage := logicalRequestLineage{ Endpoint: logicalRequestEndpointChat, HistoryDigest: committedHistoryDigest, ToolsetDigest: toolsetDigest, } return logicalRequestContinuationLineage{ Prefix: prefixLineage, IssuedCallHash: issuedCallHash, ResultIDs: resultIDs, Committed: committedLineage, }, nil } func newAnthropicContinuationLineage(raw json.RawMessage) (logicalRequestContinuationLineage, error) { fields, err := decodeLogicalRequestLineageEnvelope(raw) if err != nil { return logicalRequestContinuationLineage{}, err } rawMessages, ok := fields["messages"] if !ok { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation messages field is required") } msgList, err := validateAnthropicMessages(rawMessages) if err != nil { return logicalRequestContinuationLineage{}, err } lastIndex := len(msgList) - 1 var lastMsg struct { Role string `json:"role"` Content json.RawMessage `json:"content"` } if err := json.Unmarshal(msgList[lastIndex], &lastMsg); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode last anthropic message: %w", err) } if lastMsg.Role != "user" { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation last message must have role user, got %q", lastMsg.Role) } var blocks []json.RawMessage if err := json.Unmarshal(lastMsg.Content, &blocks); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation user message content must be array of blocks: %w", err) } var resultIDs []string seenResultIDs := make(map[string]struct{}) for bIdx, blockRaw := range blocks { var block struct { Type string `json:"type"` ToolUseID string `json:"tool_use_id"` } if err := json.Unmarshal(blockRaw, &block); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode content block %d: %w", bIdx, err) } if block.Type != "tool_result" { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation trailing user message block %d has non-tool_result type %q", bIdx, block.Type) } if block.ToolUseID == "" { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic tool_result block %d missing tool_use_id", bIdx) } if _, exists := seenResultIDs[block.ToolUseID]; exists { return logicalRequestContinuationLineage{}, fmt.Errorf("duplicate tool_use_id %q in anthropic frontier", block.ToolUseID) } seenResultIDs[block.ToolUseID] = struct{}{} resultIDs = append(resultIDs, block.ToolUseID) } if len(resultIDs) == 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation trailing user message contains no tool_result blocks") } assistantIndex := lastIndex - 1 if assistantIndex < 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic continuation missing issued assistant message before tool results") } var assistantMsg struct { Role string `json:"role"` Content json.RawMessage `json:"content"` } if err := json.Unmarshal(msgList[assistantIndex], &assistantMsg); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode assistant message: %w", err) } if assistantMsg.Role != "assistant" { return logicalRequestContinuationLineage{}, fmt.Errorf("expected assistant message before tool results, got role %q", assistantMsg.Role) } var assistantBlocks []json.RawMessage if err := json.Unmarshal(assistantMsg.Content, &assistantBlocks); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("assistant message content must be array of blocks: %w", err) } expectedToolUseIDs := make(map[string]struct{}) for bIdx, blockRaw := range assistantBlocks { var block struct { Type string `json:"type"` ID string `json:"id"` } if err := json.Unmarshal(blockRaw, &block); err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("decode assistant content block %d: %w", bIdx, err) } if block.Type == "tool_use" { if block.ID == "" { return logicalRequestContinuationLineage{}, fmt.Errorf("issued assistant tool_use block has empty id") } if _, duplicate := expectedToolUseIDs[block.ID]; duplicate { return logicalRequestContinuationLineage{}, fmt.Errorf("duplicate issued assistant tool_use id %q", block.ID) } expectedToolUseIDs[block.ID] = struct{}{} } } if len(expectedToolUseIDs) == 0 { return logicalRequestContinuationLineage{}, fmt.Errorf("issued assistant message contains no tool_use blocks") } if len(expectedToolUseIDs) != len(seenResultIDs) { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic frontier tool results count (%d) does not match issued tool_use count (%d)", len(seenResultIDs), len(expectedToolUseIDs)) } for id := range seenResultIDs { if _, ok := expectedToolUseIDs[id]; !ok { return logicalRequestContinuationLineage{}, fmt.Errorf("anthropic tool_result tool_use_id %q not in issued assistant tool_use blocks", id) } } issuedCallHash, err := fingerprintCanonicalJSON(logicalRequestEndpointAnthropic, msgList[assistantIndex]) if err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("fingerprint issued assistant call: %w", err) } prefixMessagesRaw, err := json.Marshal(msgList[:assistantIndex]) if err != nil { return logicalRequestContinuationLineage{}, fmt.Errorf("marshal prefix messages: %w", err) } prefixHistory := map[string]json.RawMessage{ "model": fields["model"], "system": fields["system"], "messages": prefixMessagesRaw, } prefixHistoryDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointAnthropic, prefixHistory) if err != nil { return logicalRequestContinuationLineage{}, err } toolsetDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointAnthropic, fields["tools"]) if err != nil { return logicalRequestContinuationLineage{}, err } prefixLineage := logicalRequestLineage{ Endpoint: logicalRequestEndpointAnthropic, HistoryDigest: prefixHistoryDigest, ToolsetDigest: toolsetDigest, } committedHistory := map[string]json.RawMessage{ "model": fields["model"], "system": fields["system"], "messages": fields["messages"], } committedHistoryDigest, err := fingerprintCanonicalJSON(logicalRequestEndpointAnthropic, committedHistory) if err != nil { return logicalRequestContinuationLineage{}, err } committedLineage := logicalRequestLineage{ Endpoint: logicalRequestEndpointAnthropic, HistoryDigest: committedHistoryDigest, ToolsetDigest: toolsetDigest, } return logicalRequestContinuationLineage{ Prefix: prefixLineage, IssuedCallHash: issuedCallHash, ResultIDs: resultIDs, Committed: committedLineage, }, nil } func newLogicalRequestLineageFromRaw(raw json.RawMessage, endpoint logicalRequestEndpoint, historyFields []string) (logicalRequestLineage, error) { fields, err := decodeLogicalRequestLineageEnvelope(raw) if err != nil { return logicalRequestLineage{}, err } return newLogicalRequestLineageFromRawFields(fields, endpoint, historyFields) } func newLogicalRequestLineageFromRawFields(fields map[string]json.RawMessage, endpoint logicalRequestEndpoint, historyFields []string) (logicalRequestLineage, error) { history := make(map[string]json.RawMessage, len(historyFields)) for _, field := range historyFields { history[field] = fields[field] } historyDigest, err := fingerprintCanonicalJSON(endpoint, history) if err != nil { return logicalRequestLineage{}, err } toolsetDigest, err := fingerprintCanonicalJSON(endpoint, fields["tools"]) if err != nil { return logicalRequestLineage{}, err } return logicalRequestLineage{Endpoint: endpoint, HistoryDigest: historyDigest, ToolsetDigest: toolsetDigest}, nil } func decodeLogicalRequestLineageEnvelope(raw json.RawMessage) (map[string]json.RawMessage, error) { decoder := json.NewDecoder(bytes.NewReader(raw)) decoder.UseNumber() var fields map[string]json.RawMessage if err := decoder.Decode(&fields); err != nil { return nil, fmt.Errorf("decode logical request lineage envelope: %w", err) } if fields == nil { return nil, fmt.Errorf("logical request lineage envelope must be an object") } var extra any if err := decoder.Decode(&extra); err == nil { return nil, fmt.Errorf("logical request lineage envelope contains multiple JSON values") } else if err != io.EOF { return nil, fmt.Errorf("decode logical request lineage envelope: %w", err) } return fields, nil } // fingerprintCanonicalJSON normalizes nested JSON before hashing. Decoding // RawMessage values first prevents insignificant formatting differences in a // caller's schema or Anthropic content blocks from becoming new lineages. func fingerprintCanonicalJSON(endpoint logicalRequestEndpoint, value any) (string, error) { raw, err := json.Marshal(value) if err != nil { return "", fmt.Errorf("marshal logical request lineage: %w", err) } var canonical any decoder := json.NewDecoder(bytes.NewReader(raw)) decoder.UseNumber() if err := decoder.Decode(&canonical); err != nil { return "", fmt.Errorf("decode logical request lineage: %w", err) } normalized, err := json.Marshal(canonical) if err != nil { return "", fmt.Errorf("encode logical request lineage: %w", err) } sum := sha256.Sum256(append(append([]byte(endpoint), '\n'), normalized...)) return hex.EncodeToString(sum[:]), nil }