Files
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

143 lines
4.3 KiB
Go

package agentsessionstore
import (
"context"
"encoding/json"
"strings"
"testing"
replay "github.com/tutti-os/tutti/packages/agent/session-replay"
)
func TestReportActivityAsSessionUpdatesRejectsDroppedReplayCommitContext(
t *testing.T,
) {
t.Parallel()
_, err := ReportActivityAsSessionUpdates(
context.Background(),
&captureSessionReporter{},
ReportActivityInput{
WorkspaceID: "workspace-1",
Source: EventSource{
AgentID: "session-1",
SessionOrigin: WorkspaceAgentSessionOriginRuntime,
},
StatePatches: []WorkspaceAgentStatePatch{{
AgentSessionID: "session-1",
}},
ProviderObservations: []replay.ProviderObservationBatch{{
RecordingID: "recording-1",
ConnectionID: "provider-1",
ChunkSeq: 1,
UnitIndex: 1,
}},
},
)
if err == nil ||
!strings.Contains(err.Error(), "does not support Replay commit context") {
t.Fatalf("ReportActivityAsSessionUpdates() error = %v", err)
}
}
func TestSessionMessageDecodesDurableSequenceAsInternalID(t *testing.T) {
t.Parallel()
var message WorkspaceAgentSessionMessage
if err := json.Unmarshal([]byte(`{
"sequence": 42,
"agentSessionId": "session-1",
"messageId": "message-1",
"role": "assistant",
"kind": "text",
"occurredAtUnixMs": 100,
"version": 7
}`), &message); err != nil {
t.Fatal(err)
}
if message.ID != 42 {
t.Fatalf("ID = %d, want sequence 42", message.ID)
}
}
func TestSessionMessageUpdateFromActivityUpdateUsesLifecycleTimeBeforeSeq(t *testing.T) {
t.Parallel()
update := SessionMessageUpdateFromActivityUpdate(WorkspaceAgentMessageUpdate{
MessageID: "message-1",
Seq: 42,
TurnID: "turn-1",
Role: "assistant",
Kind: "text",
StartedAtUnixMS: 1717200001000,
})
if update.OccurredAtUnixMS != 1717200001000 {
t.Fatalf("OccurredAtUnixMS = %d, want lifecycle timestamp", update.OccurredAtUnixMS)
}
}
func TestReportActivityAsSessionUpdatesRejectsTurnlessMessageUpdate(t *testing.T) {
t.Parallel()
reporter := &captureSessionReporter{}
_, err := ReportActivityAsSessionUpdates(context.Background(), reporter, ReportActivityInput{
WorkspaceID: "workspace-1",
Source: EventSource{
AgentID: "agent-session-1",
},
MessageUpdates: []WorkspaceAgentMessageUpdate{{
MessageID: "message-1",
Seq: 42,
Role: "assistant",
Kind: "text",
OccurredAtUnixMS: 1717200001000,
}},
})
if err == nil {
t.Fatal("ReportActivityAsSessionUpdates() error = nil, want missing turnId error")
}
if !strings.Contains(err.Error(), `message_update "message-1" is missing turnId`) {
t.Fatalf("ReportActivityAsSessionUpdates() error = %v", err)
}
if len(reporter.inputs) != 0 {
t.Fatalf("ReportSessionMessages calls = %d, want 0", len(reporter.inputs))
}
}
func TestReportActivityAsSessionUpdatesEncodesSessionAuditWithoutTurn(t *testing.T) {
t.Parallel()
reporter := &captureSessionReporter{}
reply, err := ReportActivityAsSessionUpdates(context.Background(), reporter, ReportActivityInput{
WorkspaceID: "workspace-1",
Source: EventSource{AgentID: "agent-session-1", SessionOrigin: WorkspaceAgentSessionOriginRuntime},
SessionAudits: []WorkspaceAgentSessionAuditUpdate{{
AuditID: "goal-control:op-1", Role: "user", Content: "/goal clear",
Payload: map[string]any{"goalControl": true}, OccurredAtUnixMS: 1717200001000,
}},
})
if err != nil {
t.Fatalf("ReportActivityAsSessionUpdates() error = %v", err)
}
if reply.AcceptedSessionAuditCount != 1 || len(reporter.inputs) != 1 || len(reporter.inputs[0].Updates) != 1 {
t.Fatalf("reply=%#v inputs=%#v", reply, reporter.inputs)
}
update := reporter.inputs[0].Updates[0]
if update.Kind != "session_audit" || update.TurnID != "" || update.MessageID != "goal-control:op-1" {
t.Fatalf("audit compatibility update = %#v", update)
}
}
func TestDecodeReportActivityJSONPreservesFirstClassSessionAudit(t *testing.T) {
t.Parallel()
input, err := DecodeReportActivityJSON([]byte(`{"sessionAudits":[{"auditId":"audit-1","role":"user","content":"/goal clear","occurredAtUnixMs":10}]}`))
if err != nil {
t.Fatalf("DecodeReportActivityJSON() error = %v", err)
}
if len(input.SessionAudits) != 1 || input.SessionAudits[0].AuditID != "audit-1" {
t.Fatalf("session audits = %#v", input.SessionAudits)
}
}