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

105 lines
4.5 KiB
Go

package storesqlite
import (
"context"
"database/sql"
"errors"
"strings"
)
const goalRepairBudgetExhaustedError = "goal repair incident budget exhausted"
// goalRevisionTerminalFenceTx is the single transaction-scoped read for the
// revision terminal fence. Every bottom-up path that derives sync_status must
// consult it before claiming convergence.
func goalRevisionTerminalFenceTx(ctx context.Context, tx *sql.Tx, workspaceID, agentSessionID string, revision int64) (bool, error) {
if revision <= 0 {
return false, nil
}
var terminal int
err := tx.QueryRowContext(ctx, `SELECT terminal FROM workspace_agent_goal_repair_incidents
WHERE workspace_id=? AND agent_session_id=? AND goal_revision=?`, workspaceID, agentSessionID, revision).Scan(&terminal)
if errors.Is(err, sql.ErrNoRows) {
return false, nil
}
return terminal != 0, err
}
func setGoalRevisionTerminalFenceTx(ctx context.Context, tx *sql.Tx, state SessionGoalState, generationCount int, sourceID, lastError string, occurredAt int64) error {
if generationCount <= maxGoalRepairIncidentGenerations {
generationCount = maxGoalRepairIncidentGenerations + 1
}
lastError = strings.TrimSpace(lastError)
if lastError == "" {
lastError = goalRepairBudgetExhaustedError
}
if _, err := tx.ExecContext(ctx, `INSERT INTO workspace_agent_goal_repair_incidents
(workspace_id,agent_session_id,goal_revision,generation_count,terminal,last_source_id,updated_at_unix_ms)
VALUES(?,?,?,?,1,?,?) ON CONFLICT(workspace_id,agent_session_id,goal_revision) DO UPDATE SET
generation_count=MAX(workspace_agent_goal_repair_incidents.generation_count,excluded.generation_count),terminal=1,
last_source_id=excluded.last_source_id,updated_at_unix_ms=excluded.updated_at_unix_ms`,
state.WorkspaceID, state.AgentSessionID, state.Revision, generationCount, strings.TrimSpace(sourceID), occurredAt); err != nil {
return err
}
_, err := tx.ExecContext(ctx, `UPDATE workspace_agent_session_goals
SET sync_status=?,last_error=?,pending_operation_id=NULL,execution_pending=0,updated_at_unix_ms=?
WHERE workspace_id=? AND agent_session_id=? AND revision=?`, GoalSyncStatusUnknown, lastError, occurredAt,
state.WorkspaceID, state.AgentSessionID, state.Revision)
return err
}
func terminalGoalSyncState(state SessionGoalState, candidateStatus, candidateLastError string, terminal bool) (string, string) {
if !terminal {
return candidateStatus, strings.TrimSpace(candidateLastError)
}
lastError := strings.TrimSpace(state.LastError)
if lastError == "" {
lastError = strings.TrimSpace(candidateLastError)
}
if lastError == "" {
lastError = goalRepairBudgetExhaustedError
}
return GoalSyncStatusUnknown, lastError
}
func (s *Store) MarkGoalRevisionTerminalIncident(ctx context.Context, input GoalTerminalIncidentInput) (SessionGoalState, error) {
input.WorkspaceID = strings.TrimSpace(input.WorkspaceID)
input.AgentSessionID = strings.TrimSpace(input.AgentSessionID)
input.SourceID = strings.TrimSpace(input.SourceID)
if input.WorkspaceID == "" || input.AgentSessionID == "" || input.Revision <= 0 || input.SourceID == "" || input.OccurredAtUnixMS <= 0 {
return SessionGoalState{}, errors.New("valid goal terminal incident identity is required")
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return SessionGoalState{}, err
}
defer func() { _ = tx.Rollback() }()
state, found, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err != nil {
return SessionGoalState{}, err
}
if !found || state.Revision != input.Revision {
return SessionGoalState{}, ErrGoalReconcileConflict
}
if input.Expected != nil && (!input.Expected.Exists || state.Revision != input.Expected.Revision ||
state.PendingOperationID != strings.TrimSpace(input.Expected.PendingOperationID) || state.ObservedAtUnixMS != input.Expected.ObservedAtUnixMS) {
return SessionGoalState{}, ErrGoalReconcileConflict
}
if err := setGoalRevisionTerminalFenceTx(ctx, tx, state, maxGoalRepairIncidentGenerations+1, input.SourceID, input.LastError, input.OccurredAtUnixMS); err != nil {
return SessionGoalState{}, err
}
state, _, err = getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err != nil {
return SessionGoalState{}, err
}
delta, err := s.commitTransaction(ctx, tx, input.WorkspaceID, []TransactionMutation{
transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityGoalState, input.AgentSessionID, "terminal", state.Revision),
})
if err != nil {
return SessionGoalState{}, err
}
state.CommitTransactionID = delta.TransactionID
state.CommitDelta = delta
return state, nil
}