Files
tutti/packages/agent/daemon/runtime/codex_appserver_goal_claim.go
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

90 lines
3.0 KiB
Go

package agentruntime
import "strings"
type codexGoalContinuationClaim struct {
identity goalOperationIdentity
ready bool
}
// armGoalContinuationClaim establishes a single-use compatibility claim for
// the next unowned provider turn. Codex orders external Goal mutation as:
// response, session-scoped goal update, then any continuation turn. Current
// releases omit turnId from that update, so the successful RPC plus the
// immutable durable operation identity is the narrowest available causal
// boundary. Claims never survive adapter restart and cannot cross a newer Goal
// operation identity.
func (a *CodexAppServerAdapter) armGoalContinuationClaim(agentSessionID string, identity goalOperationIdentity) {
if a == nil || !identity.valid() {
return
}
agentSessionID = strings.TrimSpace(agentSessionID)
a.mu.Lock()
appSession := a.sessions[agentSessionID]
if appSession == nil || appSession.provenanceDegraded {
a.mu.Unlock()
return
}
current := goalOperationIdentity{
operationID: appSession.goalOperationID,
revision: appSession.goalRevision,
repairEpoch: appSession.goalRepairEpoch,
}
if current != identity || strings.TrimSpace(asString(appSession.goal["status"])) != "active" {
a.mu.Unlock()
return
}
appSession.goalContinuationClaim = &codexGoalContinuationClaim{
identity: identity,
ready: true,
}
pendingTurnIDs := make([]string, 0, len(appSession.pendingGoalTurns))
for providerTurnID := range appSession.pendingGoalTurns {
pendingTurnIDs = append(pendingTurnIDs, providerTurnID)
}
a.mu.Unlock()
for _, providerTurnID := range pendingTurnIDs {
a.tryResolvePendingGoalTurn(agentSessionID, providerTurnID)
}
}
// prepareGoalContinuationClaim keeps an unowned turn buffered while the
// triggering Goal RPC response and durable generation binding are still in
// flight. A prepared claim is never adoptable; armGoalContinuationClaim is the
// only transition that makes it consumable.
func (a *CodexAppServerAdapter) prepareGoalContinuationClaim(agentSessionID string, identity goalOperationIdentity) {
if a == nil || !identity.valid() {
return
}
a.mu.Lock()
defer a.mu.Unlock()
appSession := a.sessions[strings.TrimSpace(agentSessionID)]
if appSession == nil || appSession.provenanceDegraded {
return
}
current := goalOperationIdentity{
operationID: appSession.goalOperationID,
revision: appSession.goalRevision,
repairEpoch: appSession.goalRepairEpoch,
}
if current == identity {
appSession.goalContinuationClaim = &codexGoalContinuationClaim{identity: identity}
}
}
func (a *CodexAppServerAdapter) clearPreparedGoalContinuationClaim(agentSessionID string, identity goalOperationIdentity) {
if a == nil || !identity.valid() {
return
}
a.mu.Lock()
defer a.mu.Unlock()
appSession := a.sessions[strings.TrimSpace(agentSessionID)]
if appSession == nil {
return
}
claim := appSession.goalContinuationClaim
if claim != nil && claim.identity == identity && !claim.ready {
appSession.goalContinuationClaim = nil
}
}