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

635 lines
20 KiB
Go

package liveprotocol
import (
"encoding/json"
"errors"
"reflect"
"strings"
"testing"
"time"
)
func TestFrameRoundTripCarriesReadyAndGoalControls(t *testing.T) {
t.Parallel()
frame := Frame{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 7,
Deliveries: []Delivery{
{
Seq: 1,
Kind: DeliveryKindStreamReady,
StreamReady: &StreamReady{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
},
},
{
Seq: 2,
Kind: DeliveryKindGoalChanged,
GoalChanged: &GoalChanged{
WorkspaceID: "workspace-1",
AgentSessionID: "session-1",
Revision: 3,
},
},
},
}
encoded, err := EncodeFrame(frame)
if err != nil {
t.Fatal(err)
}
decoded, err := DecodeFrame(encoded)
if err != nil {
t.Fatal(err)
}
if decoded.Epoch != 7 || decoded.Deliveries[0].StreamReady.BindingID != "binding-1" ||
decoded.Deliveries[1].GoalChanged.Revision != 3 {
t.Fatalf("decoded frame = %#v", decoded)
}
}
func TestFrameRoundTripCarriesAttachmentRecoveryFence(t *testing.T) {
t.Parallel()
frame := Frame{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 7,
Deliveries: []Delivery{
{
Seq: 1,
Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnID: "canonical-turn-1", CanonicalTurnIDs: []string{"canonical-turn-1", "child-turn-1"},
CallerTurnID: "caller-turn-1", CurrentInteractionRootTurnID: "canonical-turn-1",
AttachmentRevision: 3,
},
},
{
Seq: 2,
Kind: DeliveryKindAttachmentCaughtUp,
AttachmentCaughtUp: &AttachmentCaughtUp{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnID: "canonical-turn-1", CanonicalTurnIDs: []string{"canonical-turn-1", "child-turn-1"},
CallerTurnID: "caller-turn-1", CurrentInteractionRootTurnID: "canonical-turn-1",
AttachmentRevision: 3,
},
},
},
}
encoded, err := EncodeFrame(frame)
if err != nil {
t.Fatal(err)
}
decoded, err := DecodeFrame(encoded)
if err != nil {
t.Fatal(err)
}
if changed := decoded.Deliveries[0].AttachmentChanged; changed == nil ||
changed.AttachmentRevision != 3 || changed.CallerTurnID != "caller-turn-1" ||
changed.CurrentInteractionRootTurnID != "canonical-turn-1" ||
len(changed.CanonicalTurnIDs) != 2 || changed.CanonicalTurnIDs[1] != "child-turn-1" {
t.Fatalf("decoded attachment changed = %#v", changed)
}
if caughtUp := decoded.Deliveries[1].AttachmentCaughtUp; caughtUp == nil ||
caughtUp.AttachmentRevision != 3 || caughtUp.CanonicalTurnID != "canonical-turn-1" ||
caughtUp.CurrentInteractionRootTurnID != "canonical-turn-1" {
t.Fatalf("decoded attachment caught up = %#v", caughtUp)
}
}
func TestFrameRoundTripCarriesTurnlessGoalAuthorizationSet(t *testing.T) {
t.Parallel()
frame := Frame{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 7,
Deliveries: []Delivery{{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnIDs: []string{"goal-turn-1", "goal-turn-2"},
CurrentInteractionRootTurnID: "goal-turn-2", AttachmentRevision: 3,
},
}},
}
encoded, err := EncodeFrame(frame)
if err != nil {
t.Fatal(err)
}
decoded, err := DecodeFrame(encoded)
if err != nil {
t.Fatal(err)
}
changed := decoded.Deliveries[0].AttachmentChanged
if changed == nil || changed.CanonicalTurnID != "" || changed.CallerTurnID != "" ||
changed.CurrentInteractionRootTurnID != "goal-turn-2" ||
!reflect.DeepEqual(changed.CanonicalTurnIDs, []string{"goal-turn-1", "goal-turn-2"}) {
t.Fatalf("decoded turnless Goal attachment = %#v", changed)
}
}
func TestAttachmentRecoveryControlsRejectInvalidIdentityOrRevision(t *testing.T) {
t.Parallel()
for _, delivery := range []Delivery{
{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentCaughtUp,
AttachmentCaughtUp: &AttachmentCaughtUp{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnID: "canonical-turn-1", AttachmentRevision: 1,
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentCaughtUp,
AttachmentCaughtUp: &AttachmentCaughtUp{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CallerTurnID: "caller-turn-1", AttachmentRevision: 1,
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnIDs: []string{"goal-turn-1", "goal-turn-1"}, AttachmentRevision: 1,
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnIDs: []string{"goal-turn-1", "goal-turn-2"}, AttachmentRevision: 1,
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentCaughtUp,
AttachmentCaughtUp: &AttachmentCaughtUp{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnIDs: []string{"goal-turn-1", "goal-turn-2"},
CurrentInteractionRootTurnID: "unproven-turn", AttachmentRevision: 1,
},
},
{
Seq: 1, Kind: DeliveryKindAttachmentChanged,
AttachmentChanged: &AttachmentChanged{
BindingID: "binding-1", WorkspaceID: "workspace-1", AgentSessionID: "session-1",
CanonicalTurnID: "canonical-turn-1", CanonicalTurnIDs: []string{"canonical-turn-1", "child-turn-1"},
CallerTurnID: "caller-turn-1", CurrentInteractionRootTurnID: "child-turn-1",
AttachmentRevision: 1,
},
},
} {
if _, err := encodeDelivery(delivery); !errors.Is(err, ErrInvalidFrame) {
t.Fatalf("encodeDelivery(%v) error = %v, want %v", delivery.Kind, err, ErrInvalidFrame)
}
}
}
func TestAttachmentRecoveryControlDecodeRequiresExplicitCurrentInteractionRoot(t *testing.T) {
t.Parallel()
for name, raw := range map[string][]byte{
"missing": []byte(`{"bindingId":"binding-1","workspaceId":"workspace-1","agentSessionId":"session-1","attachmentRevision":1}`),
"null": []byte(`{"bindingId":"binding-1","workspaceId":"workspace-1","agentSessionId":"session-1","currentInteractionRootTurnId":null,"attachmentRevision":1}`),
} {
for _, target := range []any{&AttachmentChanged{}, &AttachmentCaughtUp{}} {
if err := strictControlDecode(raw, target); !errors.Is(err, ErrInvalidFrame) {
t.Fatalf("strictControlDecode(%T) %s root error = %v, want %v", target, name, err, ErrInvalidFrame)
}
}
}
// Empty is a meaningful value for a turnless attachment that has not yet
// observed a Goal Turn; the field itself must still be present on the wire.
explicitEmptyRoot := []byte(`{"bindingId":"binding-1","workspaceId":"workspace-1","agentSessionId":"session-1","currentInteractionRootTurnId":"","attachmentRevision":1}`)
for _, target := range []any{&AttachmentChanged{}, &AttachmentCaughtUp{}} {
if err := strictControlDecode(explicitEmptyRoot, target); err != nil {
t.Fatalf("strictControlDecode(%T) explicit empty root error = %v", target, err)
}
}
}
func TestTypedRevisionRejectionDecodesAcrossRevisionMismatch(t *testing.T) {
t.Parallel()
frame := Frame{
ProtocolRevision: "sha256:older",
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 1,
Deliveries: []Delivery{{
Seq: 1,
Kind: DeliveryKindRejected,
Rejected: &Rejected{
Reason: RejectionProtocolRevisionMismatch,
ExpectedRevision: ProtocolRevision,
ReceivedRevision: "sha256:older",
},
}},
}
encoded, err := EncodeFrame(frame)
if err != nil {
t.Fatal(err)
}
decoded, err := DecodeFrame(encoded)
if err != nil {
t.Fatal(err)
}
if decoded.Deliveries[0].Rejected.Reason != RejectionProtocolRevisionMismatch {
t.Fatalf("decoded rejection = %#v", decoded)
}
}
func TestDecodeEventRejectsDuplicateAndUnknownFields(t *testing.T) {
t.Parallel()
duplicate := []byte(`{"workspaceId":"w","workspaceId":"w2","agentSessionId":"s","eventType":"message_delta","data":{}}`)
if _, err := DecodeEvent(duplicate); !errors.Is(err, ErrInvalidLiveEvent) {
t.Fatalf("duplicate error = %v", err)
}
event := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"hello"`),
})
raw, err := MarshalEvent(event)
if err != nil {
t.Fatal(err)
}
raw = []byte(strings.Replace(string(raw), `"eventType"`, `"unknown":true,"eventType"`, 1))
if _, err := DecodeEvent(raw); !errors.Is(err, ErrInvalidLiveEvent) {
t.Fatalf("unknown-field error = %v", err)
}
}
func TestPublisherCoalescesAdjacentAppendAndReplays(t *testing.T) {
t.Parallel()
now := time.Unix(100, 0)
publisher, err := NewPublisher(PublisherConfig{
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 2,
Now: func() time.Time { return now },
})
if err != nil {
t.Fatal(err)
}
set := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"H"`),
})
if frames, err := publisher.Publish(PublishInput{Event: &set}); err != nil || len(frames) != 0 {
t.Fatalf("set frames=%#v err=%v", frames, err)
}
for _, text := range []string{"el", "lo"} {
appendEvent := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "append_text",
Text: text,
})
if frames, err := publisher.Publish(PublishInput{Event: &appendEvent}); err != nil || len(frames) != 0 {
t.Fatalf("append frames=%#v err=%v", frames, err)
}
}
frame, err := publisher.Flush()
if err != nil {
t.Fatal(err)
}
if frame == nil || len(frame.Deliveries) != 2 {
t.Fatalf("frame = %#v, want set + coalesced append", frame)
}
_, appended, ok := messageAppendFromRaw(frame.Deliveries[1].Event)
if !ok || appended.Content.Text != "ello" {
t.Fatalf("coalesced append = %#v", appended)
}
resume, err := publisher.Resume(ResumeRequest{Epoch: 2, AfterSeq: 1})
if err != nil {
t.Fatal(err)
}
if !resume.Hit || len(resume.Frames) != 1 ||
len(resume.Frames[0].Deliveries) != 1 ||
resume.Frames[0].Deliveries[0].Seq != 2 {
t.Fatalf("resume = %#v", resume)
}
}
func TestPublisherResumePartitionsReplayAtEncodedFrameBoundary(t *testing.T) {
t.Parallel()
const frameMaxBytes = 256
publisher, err := NewPublisher(PublisherConfig{
StreamID: "stream-1", BindingID: "binding-1", Epoch: 4,
FrameMaxBytes: frameMaxBytes,
})
if err != nil {
t.Fatal(err)
}
for revision := int64(1); revision <= 12; revision++ {
frames, err := publisher.Publish(PublishInput{
GoalChanged: &GoalChanged{
WorkspaceID: "workspace-1", AgentSessionID: "session-1",
Revision: revision,
},
Immediate: true,
})
if err != nil || len(frames) != 1 {
t.Fatalf("publish revision %d frames=%#v error=%v", revision, frames, err)
}
}
resume, err := publisher.Resume(ResumeRequest{Epoch: 4})
if err != nil {
t.Fatal(err)
}
if !resume.Hit || len(resume.Frames) < 2 {
t.Fatalf("resume did not partition replay: %#v", resume)
}
var nextSeq uint64 = 1
for _, frame := range resume.Frames {
encoded, err := EncodeFrame(frame)
if err != nil {
t.Fatal(err)
}
if len(encoded) > frameMaxBytes {
t.Fatalf("encoded replay frame bytes=%d, max=%d", len(encoded), frameMaxBytes)
}
for _, delivery := range frame.Deliveries {
if delivery.Seq != nextSeq {
t.Fatalf("replay sequence=%d, want %d", delivery.Seq, nextSeq)
}
nextSeq++
}
}
if nextSeq != 13 {
t.Fatalf("replayed through seq=%d, want 12", nextSeq-1)
}
}
func TestSubscriberDetectsGapWithoutAcceptingLaterDelivery(t *testing.T) {
t.Parallel()
subscriber, err := NewSubscriber(SubscriberConfig{})
if err != nil {
t.Fatal(err)
}
event := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"hello"`),
})
raw, _ := MarshalEvent(event)
result := subscriber.Apply(Frame{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 1,
Deliveries: []Delivery{{
Seq: 2,
Kind: DeliveryKindEvent,
Event: raw,
}},
})
if !result.ReconcileRequired || result.Reason != "sequence_gap" || len(result.Accepted) != 0 {
t.Fatalf("apply = %#v", result)
}
}
func TestSubscriberDropsDuplicateDelivery(t *testing.T) {
t.Parallel()
subscriber, err := NewSubscriber(SubscriberConfig{})
if err != nil {
t.Fatal(err)
}
event := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"hello"`),
})
raw, _ := MarshalEvent(event)
frame := Frame{
ProtocolRevision: ProtocolRevision,
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 1,
Deliveries: []Delivery{{Seq: 1, Kind: DeliveryKindEvent, Event: raw}},
}
if result := subscriber.Apply(frame); len(result.Accepted) != 1 {
t.Fatalf("first apply = %#v", result)
}
if result := subscriber.Apply(frame); result.DuplicateCount != 1 || len(result.Accepted) != 0 {
t.Fatalf("duplicate apply = %#v", result)
}
}
func TestPublisherReplacesOversizeEventWithScopedDiscontinuity(t *testing.T) {
t.Parallel()
publisher, err := NewPublisher(PublisherConfig{
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 1,
DeliveryMaxBytes: 256,
})
if err != nil {
t.Fatal(err)
}
event := mustMessageDelta(t, "message-large", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"` + strings.Repeat("x", 1024) + `"`),
})
frames, err := publisher.Publish(PublishInput{Event: &event})
if err != nil {
t.Fatal(err)
}
if len(frames) != 1 || len(frames[0].Deliveries) != 1 {
t.Fatalf("frames = %#v", frames)
}
delivery := frames[0].Deliveries[0]
if delivery.Seq != 1 || delivery.Kind != DeliveryKindDiscontinuity ||
delivery.Discontinuity.Reason != "delivery_too_large" ||
len(delivery.Discontinuity.ReconcileKeys) != 1 ||
delivery.Discontinuity.ReconcileKeys[0].MessageID != "message-large" {
t.Fatalf("oversize delivery = %#v", delivery)
}
}
func TestPublisherTerminalFenceFlushesAndRejectsLateTurnContent(t *testing.T) {
t.Parallel()
publisher, err := NewPublisher(PublisherConfig{
StreamID: "stream-1",
BindingID: "binding-1",
Epoch: 1,
})
if err != nil {
t.Fatal(err)
}
message := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: json.RawMessage(`"hello"`),
})
if frames, err := publisher.Publish(PublishInput{Event: &message}); err != nil || len(frames) != 0 {
t.Fatalf("message frames=%#v err=%v", frames, err)
}
terminal := mustTerminalTurnUpdate(t)
frames, err := publisher.Publish(PublishInput{Event: &terminal})
if err != nil {
t.Fatal(err)
}
if len(frames) != 1 || len(frames[0].Deliveries) != 2 ||
frames[0].Deliveries[1].Seq != 2 {
t.Fatalf("terminal frame = %#v", frames)
}
late := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "append_text",
Text: " too late",
})
frames, err = publisher.Publish(PublishInput{Event: &late})
if err != nil {
t.Fatal(err)
}
if len(frames) != 1 || frames[0].Deliveries[0].Seq != 3 ||
frames[0].Deliveries[0].Kind != DeliveryKindDiscontinuity ||
frames[0].Deliveries[0].Discontinuity.Reason != "late_after_terminal" {
t.Fatalf("late frame = %#v", frames)
}
}
func TestRecipientProjectorPreservesNestedBusinessIdentity(t *testing.T) {
t.Parallel()
value := json.RawMessage(`{"workspaceId":"owner-workspace","agentSessionId":"owner-session","turnId":"owner-turn","path":"/same/sandbox/file"}`)
event := mustMessageDelta(t, "message-1", &MessageContentOperation{
Operation: "set",
Value: value,
})
projector, err := NewRecipientProjector(ProjectionContext{
OwnerWorkspaceID: "owner-workspace",
OwnerAgentSessionID: "owner-session",
CanonicalTurnID: "owner-turn",
RecipientWorkspaceID: "caller-workspace",
RecipientAgentSessionID: "caller-session",
CallerTurnID: "caller-turn",
})
if err != nil {
t.Fatal(err)
}
projected, err := projector.Project(event)
if err != nil {
t.Fatal(err)
}
var data MessageDeltaData
if err := json.Unmarshal(projected.Data, &data); err != nil {
t.Fatal(err)
}
if data.WorkspaceID != "caller-workspace" || data.AgentSessionID != "caller-session" || data.TurnID != "caller-turn" {
t.Fatalf("projected identity = %#v", data)
}
var business map[string]any
if err := json.Unmarshal(data.Content.Value, &business); err != nil {
t.Fatal(err)
}
if business["workspaceId"] != "owner-workspace" || business["agentSessionId"] != "owner-session" ||
business["turnId"] != "owner-turn" || business["path"] != "/same/sandbox/file" {
t.Fatalf("business payload was rewritten: %#v", business)
}
}
func mustMessageDelta(t *testing.T, messageID string, operation *MessageContentOperation) Event {
t.Helper()
event, err := NewMessageDeltaEvent(MessageDeltaData{
WorkspaceID: "owner-workspace",
AgentSessionID: "owner-session",
MessageID: messageID,
TurnID: "owner-turn",
Role: "assistant",
Kind: "text",
OccurredAtUnixMS: 10,
Content: operation,
})
if err != nil {
t.Fatal(err)
}
return event
}
func TestMessageToolOutputOperationValidation(t *testing.T) {
t.Parallel()
base := MessageDeltaData{
WorkspaceID: "workspace-1", AgentSessionID: "session-1",
MessageID: "tool-1", TurnID: "turn-1", Role: "assistant",
Kind: "tool_call", OccurredAtUnixMS: 10,
}
offset := int64(3)
valid := base
valid.ToolOutput = &MessageToolOutputOperation{
Operation: "append_text", Text: "好", OffsetBytes: &offset,
}
if _, err := NewMessageDeltaEvent(valid); err != nil {
t.Fatalf("valid tool output rejected: %v", err)
}
for name, mutate := range map[string]func(*MessageDeltaData){
"missing offset": func(data *MessageDeltaData) {
data.ToolOutput = &MessageToolOutputOperation{Operation: "append_text", Text: "x"}
},
"wrong kind": func(data *MessageDeltaData) {
data.Kind = "text"
data.ToolOutput = &MessageToolOutputOperation{Operation: "set", Text: "x"}
},
"set with offset": func(data *MessageDeltaData) {
data.ToolOutput = &MessageToolOutputOperation{
Operation: "set", Text: "x", OffsetBytes: &offset,
}
},
} {
t.Run(name, func(t *testing.T) {
data := base
mutate(&data)
if _, err := NewMessageDeltaEvent(data); err == nil {
t.Fatalf("invalid tool output accepted: %#v", data.ToolOutput)
}
})
}
}
func mustTerminalTurnUpdate(t *testing.T) Event {
t.Helper()
outcome := "completed"
settledAt := int64(20)
data := TurnUpdateData{
WorkspaceID: "owner-workspace",
AgentSessionID: "owner-session",
EventType: EventTypeTurnUpdate,
OccurredAtUnixMS: 20,
ActiveTurnID: nil,
Turn: EventTurn{
TurnID: "owner-turn",
AgentSessionID: "owner-session",
Phase: "settled",
Origin: "user_prompt",
Outcome: &outcome,
FileChanges: json.RawMessage(`null`),
StartedAtUnixMS: 10,
SettledAtUnixMS: &settledAt,
UpdatedAtUnixMS: 20,
},
}
raw, err := json.Marshal(data)
if err != nil {
t.Fatal(err)
}
event := Event{
WorkspaceID: "owner-workspace",
AgentSessionID: "owner-session",
EventType: EventTypeTurnUpdate,
Data: raw,
}
if _, err := MarshalEvent(event); err != nil {
t.Fatal(err)
}
return event
}