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

88 lines
2.8 KiB
Go

package agentruntime
import (
"context"
"errors"
"strings"
activityshared "github.com/tutti-os/tutti/packages/agent/daemon/activity/events"
)
// ProviderTurnAcceptanceInput is an authoritative history observation. This
// path only repairs the durable projection; it never dispatches provider work.
type ProviderTurnAcceptanceInput struct {
RoomID string
AgentSessionID string
Provider string
RootTurnID string
ExpectedProviderSessionID string
ExpectedProviderTurnID string
// ClientUserMessageID is opaque provider correlation evidence and must be
// distinct from the canonical RootTurnID.
ClientUserMessageID string
}
func (c *Controller) ReconcileProviderTurnAcceptance(
ctx context.Context,
input ProviderTurnAcceptanceInput,
) error {
input.RoomID = strings.TrimSpace(input.RoomID)
input.AgentSessionID = strings.TrimSpace(input.AgentSessionID)
input.Provider = strings.TrimSpace(input.Provider)
input.RootTurnID = strings.TrimSpace(input.RootTurnID)
input.ExpectedProviderSessionID = strings.TrimSpace(input.ExpectedProviderSessionID)
input.ExpectedProviderTurnID = strings.TrimSpace(input.ExpectedProviderTurnID)
input.ClientUserMessageID = strings.TrimSpace(input.ClientUserMessageID)
if c == nil || input.RoomID == "" || input.AgentSessionID == "" ||
input.RootTurnID == "" || input.ExpectedProviderSessionID == "" ||
input.ExpectedProviderTurnID == "" ||
input.ClientUserMessageID == "" ||
input.ClientUserMessageID == input.RootTurnID {
return errors.New("valid provider turn acceptance evidence is required")
}
session, found := c.get(input.RoomID, input.AgentSessionID)
if !found {
return ErrSessionNotFound
}
if strings.TrimSpace(session.ProviderSessionID) != input.ExpectedProviderSessionID ||
(input.Provider != "" && strings.TrimSpace(session.Provider) != input.Provider) {
return errors.New("provider turn acceptance session identity changed")
}
eventContext, ok := activityEventContext(
session,
"root-provider-turn-started:"+input.ExpectedProviderTurnID,
input.RootTurnID,
)
if !ok {
return ErrSessionDisconnected
}
accepted := activityshared.NewRootProviderTurnStarted(
eventContext,
input.RootTurnID,
input.ExpectedProviderTurnID,
)
accepted.Payload.ProviderTurnBindingJSON = c.providerTurnBindingJSON(
ctx,
session,
ProviderTurnBindingWriteInput{
Kind: ProviderTurnBindingWriteRecovered,
ProviderTurnID: input.ExpectedProviderTurnID,
},
)
accepted.Payload.Metadata = map[string]any{
"acceptanceSource": string(AcceptanceSourceHistoryRead),
}
reported, err := c.reportProviderAcceptanceDurable(
ctx,
session,
[]activityshared.Event{accepted},
)
if err != nil {
return err
}
if !reported {
return errors.New("durable provider acceptance reporter is unavailable")
}
return nil
}