Files
tutti/packages/agent/store-sqlite/activity_submit_provenance_test.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

131 lines
5.2 KiB
Go

package storesqlite
import (
"context"
"strings"
"testing"
)
func TestReportActivityStateTreatsSemanticExistingMessageAsSubmitProvenanceReplay(t *testing.T) {
t.Parallel()
store := openTestStore(t, testOptions(&staticProjectPaths{}))
ctx := context.Background()
if _, err := store.ReportSessionState(ctx, SessionStateReport{
WorkspaceID: "ws-1", AgentSessionID: "session-1", Origin: "runtime",
Provider: "codex", ProviderSessionID: "provider-1", Status: "active", CurrentPhase: "working", OccurredAtUnixMS: 1,
}); err != nil {
t.Fatal(err)
}
if _, accepted, err := store.RecordTurnTransition(ctx, TurnTransition{
WorkspaceID: "ws-1", AgentSessionID: "session-1", TurnID: "turn-1",
Phase: TurnPhaseRunning, Origin: TurnOriginUserPrompt, OccurredAtUnixMS: 2,
}); err != nil || !accepted {
t.Fatalf("RecordTurnTransition() accepted=%v error=%v", accepted, err)
}
message := MessageUpdate{
MessageID: "client-submit:user:submit-1", TurnID: "turn-1",
Role: "user", Kind: "text", Status: "completed", OccurredAtUnixMS: 3,
Payload: map[string]any{
"clientSubmitId": "submit-1",
"clientSubmittedAtUnixMs": int64(2),
"content": []map[string]any{{
"type": "text",
"text": "hello",
}},
"contentMode": "snapshot",
"sequence": int64(1),
"source": "runtime",
"text": "hello",
},
}
ordinary, err := store.ReportSessionMessages(ctx, SessionMessageReport{
WorkspaceID: "ws-1", AgentSessionID: "session-1", Origin: "runtime",
Provider: "codex",
Messages: []MessageUpdate{message},
})
if err != nil || ordinary.AcceptedCount != 1 || ordinary.LatestVersion != 1 {
t.Fatalf("ordinary report result=%#v error=%v", ordinary, err)
}
provenanceMessage := message
provenanceMessage.OccurredAtUnixMS = 4
provenanceMessage.Payload = map[string]any{
"clientSubmitId": "submit-1",
"content": []map[string]any{{
"type": "text",
"text": "hello",
}},
"contentMode": "snapshot",
"clientSubmittedAtUnixMs": int64(4),
"sequence": int64(9),
"source": "host",
"text": "hello",
}
provenance, err := store.ReportActivityState(ctx, ActivityStateReport{
Session: SessionStateReport{
WorkspaceID: "ws-1", AgentSessionID: "session-1", Origin: "runtime",
Provider: "codex", ProviderSessionID: "provider-1", Status: "active", CurrentPhase: "working", OccurredAtUnixMS: 4,
},
Messages: []MessageUpdate{provenanceMessage},
})
if err != nil {
t.Fatalf("submit provenance replay error=%v", err)
}
if provenance.Messages.AcceptedCount != 1 || provenance.Messages.LatestVersion != 1 ||
len(provenance.Messages.Messages) != 1 ||
provenance.Messages.Messages[0].Version != 1 {
t.Fatalf("submit provenance replay result=%#v, want existing message version 1", provenance.Messages)
}
content, ok := provenance.Messages.Messages[0].Payload["content"].([]any)
if !ok || len(content) != 1 {
t.Fatalf("canonical content=%#v, want one-element []any", provenance.Messages.Messages[0].Payload["content"])
}
if block, ok := content[0].(map[string]any); !ok || block["type"] != "text" || block["text"] != "hello" {
t.Fatalf("canonical content block=%#v", content[0])
}
if sequence, ok := provenance.Messages.Messages[0].Payload["sequence"].(float64); !ok || sequence != 1 {
t.Fatalf("canonical sequence=%#v, want original float64(1)", provenance.Messages.Messages[0].Payload["sequence"])
}
if submittedAt, ok := provenance.Messages.Messages[0].Payload["clientSubmittedAtUnixMs"].(float64); !ok || submittedAt != 2 {
t.Fatalf("canonical client submitted time=%#v, want original float64(2)", provenance.Messages.Messages[0].Payload["clientSubmittedAtUnixMs"])
}
conflicting := message
conflicting.Payload = map[string]any{
"clientSubmitId": "submit-1",
"content": []map[string]any{{"type": "text", "text": "changed"}},
"contentMode": "snapshot",
"sequence": int64(1),
"source": "runtime",
"text": "changed",
}
_, err = store.ReportActivityState(ctx, ActivityStateReport{
Session: SessionStateReport{
WorkspaceID: "ws-1", AgentSessionID: "session-1", Origin: "runtime",
Provider: "codex", ProviderSessionID: "provider-1", Status: "active", CurrentPhase: "working", OccurredAtUnixMS: 5,
},
Messages: []MessageUpdate{conflicting},
})
if err == nil || !strings.Contains(err.Error(), "conflicts with durable submit provenance") {
t.Fatalf("conflicting submit provenance error=%v", err)
}
conflictingSemantics := provenanceMessage
conflictingSemantics.Semantics = &MessageSemantics{TurnSettling: true}
_, err = store.ReportActivityState(ctx, ActivityStateReport{
Session: SessionStateReport{
WorkspaceID: "ws-1", AgentSessionID: "session-1", Origin: "runtime",
Provider: "codex", ProviderSessionID: "provider-1", Status: "active", CurrentPhase: "working", OccurredAtUnixMS: 6,
},
Messages: []MessageUpdate{conflictingSemantics},
})
if err == nil || !strings.Contains(err.Error(), "conflicts with durable submit provenance") {
t.Fatalf("semantically conflicting submit provenance error=%v", err)
}
session, ok, err := store.GetSession(ctx, "ws-1", "session-1")
if err != nil || !ok || session.MessageVersion != 1 {
t.Fatalf("session after conflict=%#v found=%v error=%v", session, ok, err)
}
}