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

823 lines
36 KiB
Go

package storesqlite
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"strings"
agentactivityprojection "github.com/tutti-os/tutti/packages/agent/store-sqlite/canonical"
)
const sessionGoalStateSelectSQL = `
SELECT workspace_id, agent_session_id, desired_json, observed_json, revision,
tombstoned, sync_status, COALESCE(pending_operation_id, ''),
execution_pending, last_evidence_json, last_error, COALESCE(observed_at_unix_ms, 0),
created_at_unix_ms, updated_at_unix_ms
FROM workspace_agent_session_goals`
const goalControlOperationSelectSQL = `
SELECT operation_id, workspace_id, agent_session_id, goal_revision, action,
objective, status, evidence_json, last_error, created_at_unix_ms,
updated_at_unix_ms, COALESCE(completed_at_unix_ms, 0), provider_phase,
COALESCE(lease_owner, ''), COALESCE(lease_expires_at_unix_ms, 0),
COALESCE(next_attempt_at_unix_ms, 0), attempt, repair_required, repair_epoch,
COALESCE(accepted_at_unix_ms, 0), accepted_attempt,
COALESCE(first_dispatched_at_unix_ms, 0), dispatched_attempt,
COALESCE(client_submit_id, '')
FROM workspace_agent_goal_control_operations`
func (s *Store) PrepareGoalControlOperation(ctx context.Context, input GoalControlOperationPrepare) (GoalControlOperation, SessionGoalState, bool, error) {
if s == nil || s.db == nil {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("workspace database is not initialized")
}
input.OperationID = strings.TrimSpace(input.OperationID)
input.WorkspaceID = strings.TrimSpace(input.WorkspaceID)
input.AgentSessionID = strings.TrimSpace(input.AgentSessionID)
input.Action = strings.TrimSpace(input.Action)
input.Objective = strings.TrimSpace(input.Objective)
input.ClientSubmitID = strings.TrimSpace(input.ClientSubmitID)
if input.OperationID == "" || input.WorkspaceID == "" || input.AgentSessionID == "" || input.OccurredAtUnixMS <= 0 {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("goal operation identity, scope, and occurred time are required")
}
if !isKnownGoalControlAction(input.Action) || input.Action == "reconcile" {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("unsupported goal control action %q", input.Action)
}
if input.Action == "set" && input.Objective == "" {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("goal objective is required")
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("begin goal control operation: %w", err)
}
committed := false
defer func() {
if !committed {
_ = tx.Rollback()
}
}()
if existing, found, err := getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
} else if found {
state, _, stateErr := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if stateErr != nil {
return GoalControlOperation{}, SessionGoalState{}, false, stateErr
}
if existing.AgentSessionID != input.AgentSessionID || existing.Action != input.Action || existing.Objective != input.Objective || existing.ClientSubmitID != input.ClientSubmitID {
return GoalControlOperation{}, SessionGoalState{}, false, ErrGoalOperationConflict
}
if _, err := s.commitTransaction(ctx, tx, input.WorkspaceID, nil); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
committed = true
return existing, state, false, nil
}
if err := requireSessionForkSourceWritableTx(
ctx,
tx,
input.WorkspaceID,
input.AgentSessionID,
); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, found, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
if !found {
state, err = bootstrapSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID, input.OccurredAtUnixMS)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
}
if input.ExpectedRevision > 0 && state.Revision != input.ExpectedRevision {
return GoalControlOperation{}, state, false, ErrGoalGenerationSuperseded
}
desired := cloneJSONMap(state.Desired)
tombstoned := false
switch input.Action {
case "set":
desired = map[string]any{
"objective": input.Objective,
"status": "active",
"startedAtUnixMs": input.OccurredAtUnixMS,
}
case "clear":
desired = nil
tombstoned = true
case "pause", "resume":
if len(desired) == 0 {
desired = cloneJSONMap(state.Observed)
}
if len(desired) == 0 {
return GoalControlOperation{}, SessionGoalState{}, false, ErrGoalStateAbsent
}
if input.Action == "pause" {
desired["status"] = "paused"
} else {
desired["status"] = "active"
}
}
revision := state.Revision + 1
desiredJSON, err := marshalNullableJSONMap(desired)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
if state.PendingOperationID != "" {
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_goal_control_operations
SET status = ?, updated_at_unix_ms = ?, completed_at_unix_ms = ?
WHERE workspace_id = ? AND operation_id = ? AND status IN (?, ?)
`, GoalOperationStatusSuperseded, input.OccurredAtUnixMS, input.OccurredAtUnixMS,
input.WorkspaceID, state.PendingOperationID, GoalOperationStatusPrepared, GoalOperationStatusDispatched); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("supersede prior goal operation: %w", err)
}
}
if _, err := tx.ExecContext(ctx, `
INSERT INTO workspace_agent_session_goals (
workspace_id, agent_session_id, desired_json, observed_json, revision,
tombstoned, sync_status, pending_operation_id, execution_pending, last_evidence_json,
last_error, observed_at_unix_ms, created_at_unix_ms, updated_at_unix_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?, '', ?, ?, ?)
ON CONFLICT(workspace_id, agent_session_id) DO UPDATE SET
desired_json = excluded.desired_json,
revision = excluded.revision,
tombstoned = excluded.tombstoned,
sync_status = excluded.sync_status,
pending_operation_id = excluded.pending_operation_id,
execution_pending = 0,
last_error = '',
updated_at_unix_ms = excluded.updated_at_unix_ms
`, input.WorkspaceID, input.AgentSessionID, desiredJSON, nullableJSONMap(state.Observed), revision,
boolInt(tombstoned), GoalSyncStatusPending, input.OperationID, marshalJSONMapOrEmpty(state.LastEvidence),
nullInt64(state.ObservedAtUnixMS), state.CreatedAtUnixMS, input.OccurredAtUnixMS); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("write desired goal state: %w", err)
}
if _, err := tx.ExecContext(ctx, `
INSERT INTO workspace_agent_goal_control_operations (
operation_id, workspace_id, agent_session_id, goal_revision, action,
objective, status, provider_phase, next_attempt_at_unix_ms,
created_at_unix_ms, updated_at_unix_ms, client_submit_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, input.OperationID, input.WorkspaceID, input.AgentSessionID, revision, input.Action,
input.Objective, GoalOperationStatusPrepared, GoalProviderPhasePrepared, input.OccurredAtUnixMS,
input.OccurredAtUnixMS, input.OccurredAtUnixMS, input.ClientSubmitID); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("insert goal control operation: %w", err)
}
auditMessage, accepted, _, err := s.upsertAgentMessageTx(
ctx,
tx,
input.WorkspaceID,
input.AgentSessionID,
goalControlAuditMessageUpdate(input, revision),
input.OccurredAtUnixMS,
false,
true,
)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("insert goal control audit: %w", err)
} else if !accepted {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("goal control audit was not accepted")
}
op, _, err := getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, _, err = getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
delta, err := s.commitTransaction(ctx, tx, input.WorkspaceID, []TransactionMutation{
transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityGoalState, input.AgentSessionID, "upsert", revision),
transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityGoalOperation, input.OperationID, "prepare", op.UpdatedAtUnixMS),
transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityMessage, auditMessage.MessageID, "insert", int64(auditMessage.Version)),
})
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, fmt.Errorf("commit goal control operation: %w", err)
}
committed = true
op.CommitTransactionID = delta.TransactionID
op.CommitDelta = delta
state.CommitTransactionID = delta.TransactionID
state.CommitDelta = delta
return op, state, true, nil
}
func (s *Store) GetGoalControlAudit(
ctx context.Context,
workspaceID string,
agentSessionID string,
operationID string,
) (Message, bool, error) {
if s == nil || s.db == nil {
return Message{}, false, errors.New("workspace database is not initialized")
}
workspaceID = strings.TrimSpace(workspaceID)
agentSessionID = strings.TrimSpace(agentSessionID)
operationID = strings.TrimSpace(operationID)
if workspaceID == "" || agentSessionID == "" || operationID == "" {
return Message{}, false, nil
}
row := s.db.QueryRowContext(ctx, `
SELECT id, agent_session_id, message_id, version, turn_id, role, kind, status,
semantics_json, payload_json, occurred_at_unix_ms, started_at_unix_ms, completed_at_unix_ms,
created_at_unix_ms, updated_at_unix_ms
FROM workspace_agent_messages
WHERE workspace_id = ? AND agent_session_id = ? AND message_id = ? AND deleted_at_unix_ms = 0
`, workspaceID, agentSessionID, "goal-control:"+operationID)
message, err := scanAgentMessage(row)
if errors.Is(err, sql.ErrNoRows) {
return Message{}, false, nil
}
if err != nil {
return Message{}, false, fmt.Errorf("get goal control audit: %w", err)
}
return message, true, nil
}
func (s *Store) MarkGoalControlOperationDispatched(ctx context.Context, workspaceID, operationID string, occurredAt int64) (GoalControlOperation, bool, error) {
workspaceID, operationID = strings.TrimSpace(workspaceID), strings.TrimSpace(operationID)
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return GoalControlOperation{}, false, err
}
defer func() { _ = tx.Rollback() }()
result, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_goal_control_operations
SET status = ?, provider_phase = ?, updated_at_unix_ms = ?,
first_dispatched_at_unix_ms = COALESCE(first_dispatched_at_unix_ms, ?),
dispatched_attempt = CASE WHEN first_dispatched_at_unix_ms IS NULL THEN attempt ELSE dispatched_attempt END
WHERE workspace_id = ? AND operation_id = ? AND status = ?
`, GoalOperationStatusDispatched, GoalProviderPhaseDispatched, occurredAt, occurredAt, workspaceID, operationID, GoalOperationStatusPrepared)
if err != nil {
return GoalControlOperation{}, false, fmt.Errorf("dispatch goal control operation: %w", err)
}
changed, _ := result.RowsAffected()
op, found, err := getGoalControlOperationTx(ctx, tx, workspaceID, operationID)
if err != nil || !found {
return GoalControlOperation{}, false, err
}
if changed > 0 {
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_session_goals
SET sync_status = ?, updated_at_unix_ms = ?
WHERE workspace_id = ? AND agent_session_id = ? AND pending_operation_id = ?
`, GoalSyncStatusApplying, occurredAt, workspaceID, op.AgentSessionID, operationID); err != nil {
return GoalControlOperation{}, false, fmt.Errorf("mark goal state applying: %w", err)
}
}
mutations := []TransactionMutation{}
if changed > 0 {
mutations = append(mutations,
transactionMutation(workspaceID, op.AgentSessionID, MutationEntityGoalOperation, operationID, "dispatch", op.UpdatedAtUnixMS),
transactionMutation(workspaceID, op.AgentSessionID, MutationEntityGoalState, op.AgentSessionID, "upsert", op.GoalRevision),
)
}
delta, err := s.commitTransaction(ctx, tx, workspaceID, mutations)
if err != nil {
return GoalControlOperation{}, false, err
}
op.CommitTransactionID = delta.TransactionID
op.CommitDelta = delta
return op, changed > 0, nil
}
// AcknowledgeGoalControlOperation records transport/provider acceptance
// without claiming that the command has been consumed or applied. The
// operation deliberately remains dispatched and the Goal remains applying.
func (s *Store) AcknowledgeGoalControlOperation(ctx context.Context, input GoalControlOperationAcknowledge) (GoalControlOperation, SessionGoalState, bool, error) {
input.WorkspaceID, input.OperationID = strings.TrimSpace(input.WorkspaceID), strings.TrimSpace(input.OperationID)
if input.WorkspaceID == "" || input.OperationID == "" || input.OccurredAtUnixMS <= 0 {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("goal acknowledgement identity and occurred time are required")
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
defer func() { _ = tx.Rollback() }()
op, found, err := getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID)
if err != nil || !found {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, stateFound, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, op.AgentSessionID)
if err != nil || !stateFound {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
if op.Status != GoalOperationStatusDispatched || state.PendingOperationID != input.OperationID {
if _, err := s.commitTransaction(ctx, tx, input.WorkspaceID, nil); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
return op, state, false, nil
}
if op.RepairRequired && input.RepairEpoch != op.RepairEpoch {
if _, err := s.commitTransaction(ctx, tx, input.WorkspaceID, nil); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
return op, state, false, nil
}
evidenceJSON := marshalJSONMapOrEmpty(input.Evidence)
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_goal_control_operations
SET evidence_json = ?, provider_phase = ?, lease_owner = NULL,
lease_expires_at_unix_ms = NULL, next_attempt_at_unix_ms = ?, updated_at_unix_ms = ?,
accepted_at_unix_ms = COALESCE(accepted_at_unix_ms, ?),
accepted_attempt = CASE WHEN accepted_at_unix_ms IS NULL THEN attempt ELSE accepted_attempt END
WHERE workspace_id = ? AND operation_id = ? AND status = ?
`, evidenceJSON, GoalProviderPhaseAccepted, input.OccurredAtUnixMS+5000, input.OccurredAtUnixMS, input.OccurredAtUnixMS,
input.WorkspaceID, input.OperationID, GoalOperationStatusDispatched); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_session_goals
SET sync_status = ?, execution_pending = ?, last_evidence_json = ?, updated_at_unix_ms = ?
WHERE workspace_id = ? AND agent_session_id = ? AND pending_operation_id = ?
`, GoalSyncStatusApplying, boolInt(input.ExecutionPending), evidenceJSON, input.OccurredAtUnixMS,
input.WorkspaceID, op.AgentSessionID, input.OperationID); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
op, _, err = getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, _, err = getSessionGoalStateTx(ctx, tx, input.WorkspaceID, op.AgentSessionID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
delta, err := s.commitTransaction(ctx, tx, input.WorkspaceID, []TransactionMutation{
transactionMutation(input.WorkspaceID, op.AgentSessionID, MutationEntityGoalOperation, op.OperationID, "acknowledge", op.UpdatedAtUnixMS),
transactionMutation(input.WorkspaceID, op.AgentSessionID, MutationEntityGoalState, op.AgentSessionID, "upsert", state.Revision),
})
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
op.CommitTransactionID = delta.TransactionID
op.CommitDelta = delta
state.CommitTransactionID = delta.TransactionID
state.CommitDelta = delta
return op, state, true, nil
}
func (s *Store) CompleteGoalControlOperation(ctx context.Context, input GoalControlOperationComplete) (GoalControlOperation, SessionGoalState, bool, error) {
input.WorkspaceID, input.OperationID = strings.TrimSpace(input.WorkspaceID), strings.TrimSpace(input.OperationID)
if input.WorkspaceID == "" || input.OperationID == "" || input.OccurredAtUnixMS <= 0 {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("goal completion identity and occurred time are required")
}
if input.Mode == "" {
input.Mode = GoalControlCompletionModeProvider
}
if input.Mode != GoalControlCompletionModeProvider && input.Mode != GoalControlCompletionModeLocalStop {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("unsupported goal completion mode")
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
defer func() { _ = tx.Rollback() }()
op, found, err := getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID)
if err != nil || !found {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, stateFound, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, op.AgentSessionID)
if err != nil || !stateFound {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
localStop := input.Mode == GoalControlCompletionModeLocalStop
if localStop && (!input.Succeeded || op.Action != "clear") {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("local stop completion requires a successful clear operation")
}
if localStop && state.Revision < op.GoalRevision {
return GoalControlOperation{}, SessionGoalState{}, false, errors.New("local stop clear revision exceeds current goal state")
}
if op.Status == GoalOperationStatusCompleted || op.Status == GoalOperationStatusSuperseded ||
(op.Status == GoalOperationStatusFailed && !localStop) {
if _, err := s.commitTransaction(ctx, tx, input.WorkspaceID, nil); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
return op, state, false, nil
}
if op.RepairRequired && input.RepairEpoch != op.RepairEpoch && !localStop {
if _, err := s.commitTransaction(ctx, tx, input.WorkspaceID, nil); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
return op, state, false, nil
}
if localStop {
input.Observed = cloneJSONMap(state.Observed)
} else {
input.Observed = normalizeObservedGoalTiming(input.Observed, state, input.OccurredAtUnixMS)
}
supersededLocalStop := localStop && state.Revision > op.GoalRevision
terminalFence := false
if !supersededLocalStop {
terminalFence, err = goalRevisionTerminalFenceTx(ctx, tx, state.WorkspaceID, state.AgentSessionID, state.Revision)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
}
status := GoalOperationStatusFailed
syncStatus := GoalSyncStatusFailed
if supersededLocalStop {
status = GoalOperationStatusSuperseded
syncStatus = state.SyncStatus
} else if input.Succeeded {
status = GoalOperationStatusCompleted
if localStop {
syncStatus = GoalSyncStatusUnknown
} else if goalStateConverged(state.Desired, input.Observed, state.Tombstoned) {
syncStatus = GoalSyncStatusSynced
} else {
syncStatus = GoalSyncStatusDiverged
}
}
stateLastError := strings.TrimSpace(input.LastError)
if supersededLocalStop {
stateLastError = state.LastError
} else {
syncStatus, stateLastError = terminalGoalSyncState(state, syncStatus, stateLastError, terminalFence)
}
evidenceJSON := marshalJSONMapOrEmpty(input.Evidence)
providerPhase := providerPhaseForCompletion(input.Succeeded)
observedAtUnixMS := input.OccurredAtUnixMS
if localStop {
providerPhase = GoalProviderPhaseUnknown
observedAtUnixMS = state.ObservedAtUnixMS
}
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_goal_control_operations
SET status = ?, evidence_json = ?, last_error = ?, provider_phase = ?,
lease_owner = NULL, lease_expires_at_unix_ms = NULL, next_attempt_at_unix_ms = NULL,
repair_required = 0,
updated_at_unix_ms = ?, completed_at_unix_ms = ?
WHERE workspace_id = ? AND operation_id = ?
`, status, evidenceJSON, strings.TrimSpace(input.LastError), providerPhase, input.OccurredAtUnixMS,
input.OccurredAtUnixMS, input.WorkspaceID, input.OperationID); err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
stateChanged, err := updateGoalStateForOperationCompletionTx(
ctx, tx, input, op, syncStatus, evidenceJSON, stateLastError,
observedAtUnixMS, localStop, supersededLocalStop,
)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
op, _, err = getGoalControlOperationTx(ctx, tx, input.WorkspaceID, input.OperationID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
state, _, err = getSessionGoalStateTx(ctx, tx, input.WorkspaceID, op.AgentSessionID)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
operationMutationAction := "complete"
if supersededLocalStop {
operationMutationAction = "supersede"
}
mutations := []TransactionMutation{
transactionMutation(input.WorkspaceID, op.AgentSessionID, MutationEntityGoalOperation, op.OperationID, operationMutationAction, op.UpdatedAtUnixMS),
}
if stateChanged {
mutations = append(mutations,
transactionMutation(input.WorkspaceID, op.AgentSessionID, MutationEntityGoalState, op.AgentSessionID, "upsert", state.Revision),
)
}
delta, err := s.commitTransaction(ctx, tx, input.WorkspaceID, mutations)
if err != nil {
return GoalControlOperation{}, SessionGoalState{}, false, err
}
op.CommitTransactionID = delta.TransactionID
op.CommitDelta = delta
state.CommitTransactionID = delta.TransactionID
state.CommitDelta = delta
return op, state, true, nil
}
func (s *Store) GetSessionGoalState(ctx context.Context, workspaceID, agentSessionID string) (SessionGoalState, bool, error) {
if s == nil || s.db == nil {
return SessionGoalState{}, false, errors.New("workspace database is not initialized")
}
return getSessionGoalState(ctx, s.db, strings.TrimSpace(workspaceID), strings.TrimSpace(agentSessionID))
}
func (s *Store) ReconcileSessionGoalObservation(ctx context.Context, input GoalObservationReconcile) (SessionGoalState, error) {
input.WorkspaceID, input.AgentSessionID = strings.TrimSpace(input.WorkspaceID), strings.TrimSpace(input.AgentSessionID)
if input.WorkspaceID == "" || input.AgentSessionID == "" || input.OccurredAtUnixMS <= 0 {
return SessionGoalState{}, errors.New("goal observation scope and occurred time are required")
}
// SQLite serializes writers, but the explicit revision/pending/timestamp
// predicate is still the state-machine contract and protects alternative
// repository implementations from a stale read-modify-write.
for attempt := 0; attempt < 4; attempt++ {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return SessionGoalState{}, err
}
state, found, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
if input.Expected != nil && input.Expected.Exists != found {
_ = tx.Rollback()
return SessionGoalState{}, ErrGoalReconcileConflict
}
if !found {
state, err = bootstrapSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID, input.OccurredAtUnixMS)
if err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
}
if input.Expected != nil && input.Expected.Exists && (state.Revision != input.Expected.Revision ||
state.PendingOperationID != strings.TrimSpace(input.Expected.PendingOperationID) ||
state.ObservedAtUnixMS != input.Expected.ObservedAtUnixMS) {
_ = tx.Rollback()
return SessionGoalState{}, ErrGoalReconcileConflict
}
if state.ObservedAtUnixMS > input.OccurredAtUnixMS {
_ = tx.Rollback()
return state, nil
}
input.Observed = normalizeObservedGoalTiming(input.Observed, state, input.OccurredAtUnixMS)
terminalFence, err := goalRevisionTerminalFenceTx(ctx, tx, input.WorkspaceID, input.AgentSessionID, state.Revision)
if err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
forceUnknown := input.ForceSyncUnknown || terminalFence
lastError := strings.TrimSpace(input.LastError)
converged := goalStateConverged(state.Desired, input.Observed, state.Tombstoned)
syncStatus := GoalSyncStatusUnknown
completePending := false
if !forceUnknown {
if state.PendingOperationID != "" {
syncStatus = GoalSyncStatusApplying
pending, pendingFound, pendingErr := getGoalControlOperationTx(ctx, tx, input.WorkspaceID, state.PendingOperationID)
if pendingErr != nil {
_ = tx.Rollback()
return SessionGoalState{}, pendingErr
}
completePending = converged && pendingFound && goalEvidenceAuthoritativeForPending(input.Evidence, state, pending)
if completePending {
syncStatus = GoalSyncStatusSynced
}
} else if converged {
syncStatus = GoalSyncStatusSynced
} else if state.Revision > 0 {
syncStatus = GoalSyncStatusDiverged
}
}
syncStatus, lastError = terminalGoalSyncState(state, syncStatus, lastError, terminalFence)
expectedPending := state.PendingOperationID
pendingValue := any(expectedPending)
if expectedPending == "" || completePending {
pendingValue = nil
}
result, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_session_goals
SET observed_json = ?, sync_status = ?, pending_operation_id = ?, last_evidence_json = ?,
execution_pending = ?, last_error = ?, observed_at_unix_ms = ?, updated_at_unix_ms = ?
WHERE workspace_id = ? AND agent_session_id = ? AND revision = ?
AND COALESCE(pending_operation_id, '') = ? AND COALESCE(observed_at_unix_ms, 0) = ?
`, nullableJSONMap(input.Observed), syncStatus, pendingValue, marshalJSONMapOrEmpty(input.Evidence),
boolInt(goalExecutionPendingAfterObservation(state.ExecutionPending, input.Observed, syncStatus)), lastError,
input.OccurredAtUnixMS, input.OccurredAtUnixMS, input.WorkspaceID, input.AgentSessionID,
state.Revision, expectedPending, state.ObservedAtUnixMS)
if err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
changed, err := rowsWereAffected(result, "reconcile goal observation CAS")
if err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
if !changed {
_ = tx.Rollback()
continue
}
if completePending {
if _, err := tx.ExecContext(ctx, `
UPDATE workspace_agent_goal_control_operations
SET status = ?, provider_phase = ?, evidence_json = ?, lease_owner = NULL,
lease_expires_at_unix_ms = NULL, next_attempt_at_unix_ms = NULL,
repair_required = 0,
updated_at_unix_ms = ?, completed_at_unix_ms = ?
WHERE workspace_id = ? AND operation_id = ? AND goal_revision = ? AND status IN (?, ?)
`, GoalOperationStatusCompleted, GoalProviderPhaseApplied, marshalJSONMapOrEmpty(input.Evidence),
input.OccurredAtUnixMS, input.OccurredAtUnixMS, input.WorkspaceID, expectedPending,
state.Revision, GoalOperationStatusPrepared, GoalOperationStatusDispatched); err != nil {
_ = tx.Rollback()
return SessionGoalState{}, err
}
}
updated, _, err := getSessionGoalStateTx(ctx, tx, input.WorkspaceID, input.AgentSessionID)
if err == nil {
mutations := []TransactionMutation{
transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityGoalState, input.AgentSessionID, "reconcile", updated.Revision),
}
if completePending {
mutations = append(mutations, transactionMutation(input.WorkspaceID, input.AgentSessionID, MutationEntityGoalOperation, expectedPending, "complete", input.OccurredAtUnixMS))
}
var delta TransactionDelta
delta, err = s.commitTransaction(ctx, tx, input.WorkspaceID, mutations)
updated.CommitTransactionID = delta.TransactionID
updated.CommitDelta = delta
} else {
_ = tx.Rollback()
}
return updated, err
}
return SessionGoalState{}, errors.New("goal observation reconcile CAS did not converge")
}
func goalEvidenceAuthoritativeForPending(evidence map[string]any, state SessionGoalState, op GoalControlOperation) bool {
if op.RepairRequired && jsonMapInt64(evidence, "repairEpoch") != op.RepairEpoch {
return false
}
if strings.TrimSpace(asJSONMapString(evidence, "confidence")) == "authoritative" {
return true
}
return strings.TrimSpace(asJSONMapString(evidence, "phase")) == GoalProviderPhaseApplied &&
strings.TrimSpace(asJSONMapString(evidence, "operationId")) == state.PendingOperationID &&
jsonMapInt64(evidence, "revision") == state.Revision
}
func bootstrapSessionGoalStateTx(ctx context.Context, tx *sql.Tx, workspaceID, agentSessionID string, now int64) (SessionGoalState, error) {
var metadataJSON string
if err := tx.QueryRowContext(ctx, `SELECT session_metadata_json FROM workspace_agent_sessions WHERE workspace_id = ? AND agent_session_id = ? AND deleted_at_unix_ms = 0`, workspaceID, agentSessionID).Scan(&metadataJSON); err != nil {
return SessionGoalState{}, err
}
metadata, err := unmarshalJSONMap(metadataJSON)
if err != nil {
return SessionGoalState{}, err
}
observed, _ := metadata["goal"].(map[string]any)
desired := cloneJSONMap(observed)
syncStatus := GoalSyncStatusUnknown
if len(observed) > 0 {
syncStatus = GoalSyncStatusSynced
}
if _, err := tx.ExecContext(ctx, `
INSERT OR IGNORE INTO workspace_agent_session_goals (
workspace_id, agent_session_id, desired_json, observed_json, revision,
tombstoned, sync_status, last_evidence_json, observed_at_unix_ms,
created_at_unix_ms, updated_at_unix_ms
) VALUES (?, ?, ?, ?, 0, 0, ?, '{}', ?, ?, ?)
`, workspaceID, agentSessionID, nullableJSONMap(desired), nullableJSONMap(observed), syncStatus,
nullInt64(now), now, now); err != nil {
return SessionGoalState{}, err
}
state, _, err := getSessionGoalStateTx(ctx, tx, workspaceID, agentSessionID)
return state, err
}
// reconcileObservedGoalFromSessionTx is the bottom-up synchronization path:
// accepted runtime session snapshots update only the observed side. A pending
// upper intent stays applying until its own operation completes, preventing a
// late provider snapshot from erasing a newer desired revision/tombstone.
func reconcileObservedGoalFromSessionTx(ctx context.Context, tx *sql.Tx, session agentactivityprojection.SessionSnapshot, occurredAt int64) error {
workspaceID, agentSessionID := strings.TrimSpace(session.WorkspaceID), strings.TrimSpace(session.AgentSessionID)
if workspaceID == "" || agentSessionID == "" {
return nil
}
metadata, _, _, err := splitSessionRuntimeContext(session.RuntimeContext)
if err != nil {
return err
}
var observed map[string]any
if metadata.Goal != nil {
if err := remarshalJSON(metadata.Goal, &observed); err != nil {
return err
}
}
state, found, err := getSessionGoalStateTx(ctx, tx, workspaceID, agentSessionID)
if err != nil {
return err
}
observed = normalizeObservedGoalTiming(observed, state, occurredAt)
if !found {
syncStatus := GoalSyncStatusUnknown
if len(observed) > 0 {
syncStatus = GoalSyncStatusSynced
}
_, err = tx.ExecContext(ctx, `
INSERT INTO workspace_agent_session_goals (
workspace_id, agent_session_id, desired_json, observed_json, revision,
tombstoned, sync_status, last_evidence_json, observed_at_unix_ms,
created_at_unix_ms, updated_at_unix_ms
) VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?)
`, workspaceID, agentSessionID, nullableJSONMap(observed), nullableJSONMap(observed), syncStatus,
`{"source":"runtime_session_report","confidence":"provider_observed"}`,
nullInt64(occurredAt), occurredAt, occurredAt)
return err
}
terminalFence, err := goalRevisionTerminalFenceTx(ctx, tx, workspaceID, agentSessionID, state.Revision)
if err != nil {
return err
}
if state.ObservedAtUnixMS > occurredAt {
return nil
}
var syncStatus string
if state.PendingOperationID != "" {
syncStatus = GoalSyncStatusApplying
} else if goalStateConverged(state.Desired, observed, state.Tombstoned) {
syncStatus = GoalSyncStatusSynced
} else if state.Revision > 0 {
syncStatus = GoalSyncStatusDiverged
} else {
syncStatus = GoalSyncStatusUnknown
}
syncStatus, lastError := terminalGoalSyncState(state, syncStatus, state.LastError, terminalFence)
_, err = tx.ExecContext(ctx, `
UPDATE workspace_agent_session_goals
SET observed_json = ?, sync_status = ?, last_evidence_json = ?, last_error = ?,
execution_pending = ?, observed_at_unix_ms = ?, updated_at_unix_ms = ?
WHERE workspace_id = ? AND agent_session_id = ? AND revision = ?
AND COALESCE(pending_operation_id, '') = ? AND COALESCE(observed_at_unix_ms, 0) = ?
`, nullableJSONMap(observed), syncStatus,
`{"source":"runtime_session_report","confidence":"provider_observed"}`,
lastError, boolInt(goalExecutionPendingAfterObservation(state.ExecutionPending, observed, syncStatus)),
occurredAt, occurredAt, workspaceID, agentSessionID, state.Revision,
state.PendingOperationID, state.ObservedAtUnixMS)
return err
}
func jsonMapInt64(value map[string]any, key string) int64 {
switch number := value[key].(type) {
case int64:
return number
case int:
return int64(number)
case float64:
return int64(number)
case json.Number:
result, _ := number.Int64()
return result
default:
return 0
}
}
func getSessionGoalState(ctx context.Context, q rowQueryer, workspaceID, agentSessionID string) (SessionGoalState, bool, error) {
return scanSessionGoalState(q.QueryRowContext(ctx, sessionGoalStateSelectSQL+` WHERE workspace_id = ? AND agent_session_id = ?`, workspaceID, agentSessionID))
}
func getSessionGoalStateTx(ctx context.Context, tx *sql.Tx, workspaceID, agentSessionID string) (SessionGoalState, bool, error) {
return getSessionGoalState(ctx, tx, workspaceID, agentSessionID)
}
func scanSessionGoalState(row *sql.Row) (SessionGoalState, bool, error) {
var state SessionGoalState
var desiredJSON, observedJSON sql.NullString
var evidenceJSON string
var tombstoned, executionPending int
if err := row.Scan(&state.WorkspaceID, &state.AgentSessionID, &desiredJSON, &observedJSON,
&state.Revision, &tombstoned, &state.SyncStatus, &state.PendingOperationID,
&executionPending, &evidenceJSON, &state.LastError, &state.ObservedAtUnixMS,
&state.CreatedAtUnixMS, &state.UpdatedAtUnixMS); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return SessionGoalState{}, false, nil
}
return SessionGoalState{}, false, err
}
state.Tombstoned = tombstoned != 0
state.ExecutionPending = executionPending != 0
state.Desired = unmarshalNullableJSONMap(desiredJSON)
state.Observed = unmarshalNullableJSONMap(observedJSON)
state.LastEvidence, _ = unmarshalJSONMap(evidenceJSON)
return state, true, nil
}
func getGoalControlOperation(ctx context.Context, q rowQueryer, workspaceID, operationID string) (GoalControlOperation, bool, error) {
return scanGoalControlOperation(q.QueryRowContext(ctx, goalControlOperationSelectSQL+` WHERE workspace_id = ? AND operation_id = ?`, workspaceID, operationID))
}
func getGoalControlOperationTx(ctx context.Context, tx *sql.Tx, workspaceID, operationID string) (GoalControlOperation, bool, error) {
return getGoalControlOperation(ctx, tx, workspaceID, operationID)
}
func scanGoalControlOperation(row *sql.Row) (GoalControlOperation, bool, error) {
var op GoalControlOperation
var evidenceJSON string
var repairRequired int
if err := row.Scan(&op.OperationID, &op.WorkspaceID, &op.AgentSessionID, &op.GoalRevision,
&op.Action, &op.Objective, &op.Status, &evidenceJSON, &op.LastError,
&op.CreatedAtUnixMS, &op.UpdatedAtUnixMS, &op.CompletedAtUnixMS, &op.ProviderPhase,
&op.LeaseOwner, &op.LeaseExpiresAtMS, &op.NextAttemptAtMS, &op.Attempt,
&repairRequired, &op.RepairEpoch, &op.AcceptedAtUnixMS, &op.AcceptedAttempt,
&op.FirstDispatchedAtUnixMS, &op.DispatchedAttempt, &op.ClientSubmitID); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return GoalControlOperation{}, false, nil
}
return GoalControlOperation{}, false, err
}
op.Evidence, _ = unmarshalJSONMap(evidenceJSON)
op.RepairRequired = repairRequired != 0
return op, true, nil
}