源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
package storesqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSessionInteractionTreeSnapshotIncludesRootAndDescendantLatestTurns(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
||||
ctx := context.Background()
|
||||
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 1,
|
||||
}, "root-turn", 2)
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", Kind: SessionKindChild,
|
||||
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "call-child",
|
||||
Provider: "claude-code", OccurredAtUnixMS: 3,
|
||||
}, "child-old", 4)
|
||||
seedTreeInteraction(t, store, "child", "child-old", "old-request", InteractionStatusPending, 5)
|
||||
if _, accepted, err := store.RecordTurnTransition(ctx, TurnTransition{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", TurnID: "child-old",
|
||||
Phase: TurnPhaseSettled, Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 6,
|
||||
}); err != nil || !accepted {
|
||||
t.Fatalf("settle child old turn: accepted=%v err=%v", accepted, err)
|
||||
}
|
||||
if _, accepted, err := store.RecordTurnTransition(ctx, TurnTransition{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", TurnID: "child-latest",
|
||||
Phase: TurnPhaseRunning, OccurredAtUnixMS: 7,
|
||||
}); err != nil || !accepted {
|
||||
t.Fatalf("start child latest turn: accepted=%v err=%v", accepted, err)
|
||||
}
|
||||
seedTreeInteraction(t, store, "child", "child-latest", "child-pending", InteractionStatusPending, 8)
|
||||
seedTreeInteraction(t, store, "root", "root-turn", "root-answered", InteractionStatusPending, 9)
|
||||
seedTreeInteraction(t, store, "root", "root-turn", "root-answered", InteractionStatusAnswered, 10)
|
||||
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "nested", Kind: SessionKindChild,
|
||||
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
ParentAgentSessionID: "child", ParentTurnID: "child-latest", ParentToolCallID: "call-nested",
|
||||
Provider: "claude-code", OccurredAtUnixMS: 11,
|
||||
}, "nested-turn", 12)
|
||||
seedTreeInteraction(t, store, "nested", "nested-turn", "nested-pending", InteractionStatusPending, 13)
|
||||
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "other-root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 14,
|
||||
}, "other-turn", 15)
|
||||
seedTreeInteraction(t, store, "other-root", "other-turn", "other-pending", InteractionStatusPending, 16)
|
||||
|
||||
snapshot, found, err := store.GetSessionInteractionTreeSnapshot(ctx, SessionInteractionTreeQuery{
|
||||
WorkspaceID: " ws-tree ", RootAgentSessionID: " root ",
|
||||
})
|
||||
if err != nil || !found {
|
||||
t.Fatalf("GetSessionInteractionTreeSnapshot() found=%v err=%v", found, err)
|
||||
}
|
||||
if snapshot.RootTurnID != "root-turn" {
|
||||
t.Fatalf("RootTurnID=%q, want root-turn", snapshot.RootTurnID)
|
||||
}
|
||||
wantRequests := []string{"child-pending", "nested-pending", "root-answered"}
|
||||
if len(snapshot.Interactions) != len(wantRequests) {
|
||||
t.Fatalf("Interactions=%#v, want requests %v", snapshot.Interactions, wantRequests)
|
||||
}
|
||||
for index, want := range wantRequests {
|
||||
if snapshot.Interactions[index].RequestID != want {
|
||||
t.Fatalf("Interactions[%d]=%#v, want request %q", index, snapshot.Interactions[index], want)
|
||||
}
|
||||
}
|
||||
if len(snapshot.PendingInteractions) != 2 ||
|
||||
snapshot.PendingInteractions[0].RequestID != "child-pending" ||
|
||||
snapshot.PendingInteractions[1].RequestID != "nested-pending" {
|
||||
t.Fatalf("PendingInteractions=%#v", snapshot.PendingInteractions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionInteractionTreeSnapshotValidatesExplicitRootTurn(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 1,
|
||||
}, "root-turn", 2)
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "other-root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 3,
|
||||
}, "other-turn", 4)
|
||||
|
||||
for _, turnID := range []string{"missing", "other-turn"} {
|
||||
_, _, err := store.GetSessionInteractionTreeSnapshot(context.Background(), SessionInteractionTreeQuery{
|
||||
WorkspaceID: "ws-tree", RootAgentSessionID: "root", RootTurnID: turnID,
|
||||
})
|
||||
if !errors.Is(err, ErrInteractionTreeRootTurnNotFound) {
|
||||
t.Fatalf("turn %q error=%v, want %v", turnID, err, ErrInteractionTreeRootTurnNotFound)
|
||||
}
|
||||
}
|
||||
if _, err := store.db.Exec(`
|
||||
UPDATE workspace_agent_turn_history
|
||||
SET history_state = 'retracted', retracted_by_operation_id = 'operation-1',
|
||||
updated_at_unix_ms = 5
|
||||
WHERE workspace_id = 'ws-tree' AND agent_session_id = 'root' AND turn_id = 'root-turn'
|
||||
`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _, err := store.GetSessionInteractionTreeSnapshot(context.Background(), SessionInteractionTreeQuery{
|
||||
WorkspaceID: "ws-tree", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
})
|
||||
if !errors.Is(err, ErrInteractionTreeRootTurnNotFound) {
|
||||
t.Fatalf("retracted turn error=%v, want %v", err, ErrInteractionTreeRootTurnNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionInteractionTreeSnapshotPlanRanksTurnsBeforeJoiningInteractions(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
||||
rows, err := store.db.Query(
|
||||
"EXPLAIN QUERY PLAN "+sessionInteractionTreeSnapshotSQL,
|
||||
"ws-tree", "root", "root-turn", "ws-tree", "root", "root-turn",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var details []string
|
||||
for rows.Next() {
|
||||
var id, parent, unused int
|
||||
var detail string
|
||||
if err := rows.Scan(&id, &parent, &unused, &detail); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
details = append(details, detail)
|
||||
}
|
||||
plan := strings.Join(details, "\n")
|
||||
if strings.Count(plan, "CORRELATED SCALAR SUBQUERY") != 1 ||
|
||||
strings.Index(plan, "SCAN ranked_descendant_turns") > strings.Index(plan, "SEARCH interaction") {
|
||||
t.Fatalf("interaction tree plan does not rank effective turns before joining interactions:\n%s", plan)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInteractionTreeDirtyFactCoversLatestTurnSettleRetractAndDelete(t *testing.T) {
|
||||
participant := &testTransactionParticipant{}
|
||||
store := openParticipantTestStore(t, participant)
|
||||
ctx := context.Background()
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 1,
|
||||
}, "root-turn", 2)
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", Kind: SessionKindChild,
|
||||
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "call-child",
|
||||
Provider: "claude-code", OccurredAtUnixMS: 3,
|
||||
}, "child-old", 4)
|
||||
seedTreeInteraction(t, store, "child", "child-old", "old-request", InteractionStatusPending, 5)
|
||||
|
||||
if _, accepted, err := store.RecordTurnTransition(ctx, TurnTransition{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", TurnID: "child-old",
|
||||
Phase: TurnPhaseSettled, Outcome: TurnOutcomeCompleted, OccurredAtUnixMS: 6,
|
||||
}); err != nil || !accepted {
|
||||
t.Fatalf("settle old child turn: accepted=%v err=%v", accepted, err)
|
||||
}
|
||||
assertLatestInteractionTreeDirty(t, participant, "root", "root-turn")
|
||||
|
||||
if _, accepted, err := store.RecordTurnTransition(ctx, TurnTransition{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", TurnID: "child-latest",
|
||||
Phase: TurnPhaseRunning, OccurredAtUnixMS: 7,
|
||||
}); err != nil || !accepted {
|
||||
t.Fatalf("start latest child turn: accepted=%v err=%v", accepted, err)
|
||||
}
|
||||
assertLatestInteractionTreeDirty(t, participant, "root", "root-turn")
|
||||
seedTreeInteraction(t, store, "child", "child-latest", "latest-request", InteractionStatusPending, 8)
|
||||
|
||||
tx, err := store.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE workspace_agent_turn_history
|
||||
SET history_state = 'retracted', retracted_by_operation_id = 'operation-1', updated_at_unix_ms = 9
|
||||
WHERE workspace_id = 'ws-tree' AND agent_session_id = 'child' AND turn_id = 'child-latest'
|
||||
`); err != nil {
|
||||
_ = tx.Rollback()
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := store.commitTransaction(ctx, tx, "ws-tree", []TransactionMutation{
|
||||
transactionMutation("ws-tree", "child", MutationEntityTurn, "child-latest", "retract", 9),
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertLatestInteractionTreeDirty(t, participant, "root", "root-turn")
|
||||
snapshot, found, err := store.GetSessionInteractionTreeSnapshot(ctx, SessionInteractionTreeQuery{
|
||||
WorkspaceID: "ws-tree", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
})
|
||||
if err != nil || !found || len(snapshot.Interactions) != 1 ||
|
||||
snapshot.Interactions[0].RequestID != "old-request" {
|
||||
t.Fatalf("snapshot after child retract = %#v found=%v err=%v", snapshot, found, err)
|
||||
}
|
||||
|
||||
if _, err := store.DeleteSession(ctx, "ws-tree", "child"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertLatestInteractionTreeDirty(t, participant, "root", "root-turn")
|
||||
snapshot, found, err = store.GetSessionInteractionTreeSnapshot(ctx, SessionInteractionTreeQuery{
|
||||
WorkspaceID: "ws-tree", RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
})
|
||||
if err != nil || !found || len(snapshot.Interactions) != 0 {
|
||||
t.Fatalf("snapshot after child delete = %#v found=%v err=%v", snapshot, found, err)
|
||||
}
|
||||
}
|
||||
|
||||
func assertLatestInteractionTreeDirty(
|
||||
t *testing.T,
|
||||
participant *testTransactionParticipant,
|
||||
rootAgentSessionID string,
|
||||
rootTurnID string,
|
||||
) {
|
||||
t.Helper()
|
||||
if len(participant.deltas) == 0 {
|
||||
t.Fatal("interaction tree mutation did not participate")
|
||||
}
|
||||
for _, mutation := range participant.deltas[len(participant.deltas)-1].Mutations {
|
||||
if mutation.EntityKind == MutationEntityInteractionTree &&
|
||||
mutation.RootAgentSessionID == rootAgentSessionID && mutation.RootTurnID == rootTurnID {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("latest delta lacks interaction tree dirty fact: %#v", participant.deltas[len(participant.deltas)-1])
|
||||
}
|
||||
|
||||
func TestSessionInteractionTreeSnapshotRejectsChildRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "root", Kind: SessionKindRoot,
|
||||
Provider: "claude-code", OccurredAtUnixMS: 1,
|
||||
}, "root-turn", 2)
|
||||
reportSessionWithTurn(t, store, SessionStateReport{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: "child", Kind: SessionKindChild,
|
||||
RootAgentSessionID: "root", RootTurnID: "root-turn",
|
||||
ParentAgentSessionID: "root", ParentTurnID: "root-turn", ParentToolCallID: "call-child",
|
||||
Provider: "claude-code", OccurredAtUnixMS: 3,
|
||||
}, "child-turn", 4)
|
||||
|
||||
_, _, err := store.GetSessionInteractionTreeSnapshot(context.Background(), SessionInteractionTreeQuery{
|
||||
WorkspaceID: "ws-tree", RootAgentSessionID: "child",
|
||||
})
|
||||
if !errors.Is(err, ErrInteractionTreeRootRequired) {
|
||||
t.Fatalf("error=%v, want %v", err, ErrInteractionTreeRootRequired)
|
||||
}
|
||||
}
|
||||
|
||||
func seedTreeInteraction(t *testing.T, store *Store, sessionID, turnID, requestID, status string, occurredAt int64) {
|
||||
t.Helper()
|
||||
_, result, err := store.UpsertInteraction(context.Background(), InteractionUpsert{
|
||||
WorkspaceID: "ws-tree", AgentSessionID: sessionID, TurnID: turnID,
|
||||
RequestID: requestID, Kind: InteractionKindQuestion, Status: status,
|
||||
OccurredAtUnixMS: occurredAt,
|
||||
})
|
||||
if err != nil || result != InteractionTransitionApplied {
|
||||
t.Fatalf("seed interaction %s: result=%v err=%v", requestID, result, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user