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

115 lines
3.1 KiB
Go

package agentruntime
import (
"strings"
agentsessionstore "github.com/tutti-os/tutti/packages/agent/daemon/activity"
activityshared "github.com/tutti-os/tutti/packages/agent/daemon/activity/events"
"github.com/tutti-os/tutti/packages/agent/store-sqlite/canonical"
)
func entityPatchFromSessionEvent(
source canonical.EventSource,
event activityshared.Event,
sessionID string,
timestamp int64,
item agentsessionstore.WorkspaceAgentTimelineItem,
) *agentsessionstore.WorkspaceAgentStatePatch {
if strings.TrimSpace(item.CallID) == "" && strings.TrimSpace(item.Name) == "" {
return nil
}
entity := agentsessionstore.WorkspaceAgentEntityPatch{
CallID: strings.TrimSpace(item.CallID),
TurnID: strings.TrimSpace(item.TurnID),
CallType: firstNonEmptyString(item.CallType, "tool"),
Name: strings.TrimSpace(item.Name),
Status: strings.TrimSpace(item.Status),
}
switch event.Type {
case activityshared.EventCallStarted:
entity.Input = clonePayload(event.Payload.Input)
entity.StartedAtUnixMS = timestamp
case activityshared.EventCallCompleted:
entity.Output = clonePayload(event.Payload.Output)
entity.CompletedAtUnixMS = timestamp
case activityshared.EventCallFailed:
if len(event.Payload.Output) > 0 {
entity.Output = clonePayload(event.Payload.Output)
}
entity.Error = clonePayload(event.Payload.Error)
entity.CompletedAtUnixMS = timestamp
}
return &agentsessionstore.WorkspaceAgentStatePatch{
AgentSessionID: strings.TrimSpace(sessionID),
Provider: firstNonEmptyString(string(event.Provider), source.Provider),
ProviderSessionID: firstNonEmptyString(event.ProviderSessionID, source.ProviderSessionID),
CWD: firstNonEmptyString(event.Payload.CWD, source.CWD),
OccurredAtUnixMS: timestamp,
Entities: []agentsessionstore.WorkspaceAgentEntityPatch{entity},
}
}
func payloadWithCallBody(key string, payload map[string]any, metadata map[string]any) map[string]any {
out := clonePayload(metadata)
if out == nil {
out = map[string]any{}
}
if len(payload) > 0 {
out[key] = clonePayload(payload)
}
if len(out) == 0 {
return nil
}
return out
}
func payloadValueIsEmpty(value any) bool {
switch typed := value.(type) {
case nil:
return true
case string:
return strings.TrimSpace(typed) == ""
case []any:
return len(typed) == 0
case map[string]any:
return len(typed) == 0
default:
return false
}
}
func clonePayloadValue(value any) any {
switch typed := value.(type) {
case map[string]any:
out := make(map[string]any, len(typed))
for key, item := range typed {
out[key] = clonePayloadValue(item)
}
return out
case []any:
out := make([]any, len(typed))
for index, item := range typed {
out[index] = clonePayloadValue(item)
}
return out
default:
return value
}
}
func stringFromPayload(payload map[string]any, key string) string {
if len(payload) == 0 {
return ""
}
return asString(payload[key])
}
func firstNonEmptyString(values ...string) string {
for _, value := range values {
if strings.TrimSpace(value) != "" {
return strings.TrimSpace(value)
}
}
return ""
}