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

140 lines
3.3 KiB
Go

package agentruntime
import (
"context"
"errors"
"sync"
activityshared "github.com/tutti-os/tutti/packages/agent/daemon/activity/events"
)
type providerInputUnitTracker struct {
mu sync.Mutex
nextToken uint64
bySession map[string]*trackedProviderInputUnit
}
type trackedProviderInputUnit struct {
token uint64
unit ProviderInputUnit
nextEventIndex uint64
}
type providerInputUnitError struct {
err error
unit ProviderInputUnit
}
func (e providerInputUnitError) Error() string {
return e.err.Error()
}
func (e providerInputUnitError) Unwrap() error {
return e.err
}
func providerInputUnitFromError(err error) (ProviderInputUnit, bool) {
var positioned providerInputUnitError
if !errors.As(err, &positioned) {
return ProviderInputUnit{}, false
}
return positioned.unit, true
}
func (t *providerInputUnitTracker) begin(
ctx context.Context,
agentSessionID string,
) func() {
if t == nil {
return func() {}
}
unit, ok := ProviderInputUnitFromContext(ctx)
if !ok || agentSessionID == "" || unit.Position.ConnectionID == "" {
return func() {}
}
t.mu.Lock()
if t.bySession == nil {
t.bySession = make(map[string]*trackedProviderInputUnit)
}
t.nextToken++
token := t.nextToken
t.bySession[agentSessionID] = &trackedProviderInputUnit{
token: token,
unit: unit,
}
t.mu.Unlock()
return func() {
t.mu.Lock()
if current := t.bySession[agentSessionID]; current != nil &&
current.token == token {
delete(t.bySession, agentSessionID)
}
t.mu.Unlock()
}
}
func (t *providerInputUnitTracker) stamp(
agentSessionID string,
events []activityshared.Event,
) []activityshared.Event {
if t == nil || len(events) == 0 {
return events
}
t.mu.Lock()
defer t.mu.Unlock()
current := t.bySession[agentSessionID]
if current == nil {
return events
}
for index := range events {
// Message handlers may stamp a reduction before handing it to the
// active-turn emitter. Keep the boundary idempotent so the same event
// is never assigned two observation indexes while traversing both
// paths.
if events[index].ProviderInputUnit != nil {
continue
}
current.nextEventIndex++
events[index].ProviderInputUnit = &activityshared.ProviderInputUnitContext{
RecordingID: current.unit.RecordingID,
ConnectionID: current.unit.Position.ConnectionID,
ChunkSeq: current.unit.Position.ChunkSeq,
UnitIndex: current.unit.Position.UnitIndex,
EventIndex: current.nextEventIndex,
UnitKind: string(current.unit.Kind),
}
}
return events
}
func providerInputUnitTrackerForTransport(
transport ProcessTransport,
) *providerInputUnitTracker {
tracking, ok := transport.(ProviderInputUnitTrackingTransport)
if !ok || !tracking.TracksProviderInputUnits() {
return nil
}
return &providerInputUnitTracker{}
}
func stampProviderInputUnitFromError(
err error,
events []activityshared.Event,
) []activityshared.Event {
unit, ok := providerInputUnitFromError(err)
if !ok || len(events) == 0 {
return events
}
for index := range events {
events[index].ProviderInputUnit = &activityshared.ProviderInputUnitContext{
RecordingID: unit.RecordingID,
ConnectionID: unit.Position.ConnectionID,
ChunkSeq: unit.Position.ChunkSeq,
UnitIndex: unit.Position.UnitIndex,
EventIndex: uint64(index + 1),
UnitKind: string(unit.Kind),
}
}
return events
}