Skip to content

Commit 1a40ef0

Browse files
committed
pkg/aflow/trajectory: add package
1 parent af6b70b commit 1a40ef0

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

pkg/aflow/trajectory/trajectory.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2025 syzkaller project authors. All rights reserved.
2+
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3+
4+
package trajectory
5+
6+
import (
7+
"fmt"
8+
"slices"
9+
"strings"
10+
"time"
11+
)
12+
13+
// Span describes one step in an aflow workflow execution.
14+
// Spans can be finished/unfinished (Finished field), and nested (Nesting field).
15+
type Span struct {
16+
Seq int
17+
Nesting int
18+
Type SpanType
19+
Name string // action/tool name
20+
Timestamp time.Time
21+
Finished bool
22+
Duration time.Duration // relevant if Finished
23+
Error string // relevant if Finished
24+
25+
// Args/results for actions/tools.
26+
Args map[string]any
27+
Results map[string]any
28+
29+
// Agent invocation.
30+
Instruction string
31+
Prompt string
32+
Reply string
33+
34+
// LLM invocation.
35+
Thoughts string
36+
}
37+
38+
type SpanType string
39+
40+
const (
41+
SpanFlow = SpanType("flow") // always the first outermost span
42+
SpanAction = SpanType("action")
43+
SpanAgent = SpanType("agent")
44+
SpanLLM = SpanType("llm")
45+
SpanTool = SpanType("tool")
46+
)
47+
48+
func (span *Span) String() string {
49+
// This is used for console logging only.
50+
sb := new(strings.Builder)
51+
if !span.Finished {
52+
fmt.Fprintf(sb, "starting %v %v (%v/%v)...\n",
53+
span.Type, span.Name, span.Nesting, span.Seq)
54+
switch span.Type {
55+
case SpanFlow:
56+
case SpanAction:
57+
case SpanAgent:
58+
fmt.Fprintf(sb, "instruction:\n%v\nprompt:\n%v\n", span.Instruction, span.Prompt)
59+
case SpanLLM:
60+
case SpanTool:
61+
printMap(sb, span.Args, "args")
62+
default:
63+
panic(fmt.Sprintf("unhandled span type %v", span.Type))
64+
}
65+
} else {
66+
fmt.Fprintf(sb, "finished %v %v (%v/%v) in %v\n",
67+
span.Type, span.Name, span.Nesting, span.Seq, span.Duration)
68+
switch span.Type {
69+
case SpanFlow:
70+
printMap(sb, span.Results, "results")
71+
case SpanAction:
72+
printMap(sb, span.Results, "results")
73+
case SpanAgent:
74+
if span.Results != nil {
75+
printMap(sb, span.Results, "results")
76+
}
77+
fmt.Fprintf(sb, "reply:\n%v\n", span.Reply)
78+
case SpanLLM:
79+
if span.Thoughts != "" {
80+
fmt.Fprintf(sb, "thoughts:\n%v\n", span.Thoughts)
81+
}
82+
case SpanTool:
83+
printMap(sb, span.Results, "results")
84+
default:
85+
panic(fmt.Sprintf("unhandled span type %v", span.Type))
86+
}
87+
}
88+
if span.Error != "" {
89+
fmt.Fprintf(sb, "error:\n%v\n", span.Error)
90+
}
91+
return sb.String()
92+
}
93+
94+
func printMap(sb *strings.Builder, m map[string]any, what string) {
95+
fmt.Fprintf(sb, "%v:\n", what)
96+
type nameVal struct {
97+
name string
98+
val any
99+
}
100+
var sorted []nameVal
101+
for k, v := range m {
102+
sorted = append(sorted, nameVal{k, v})
103+
}
104+
slices.SortFunc(sorted, func(a, b nameVal) int {
105+
return strings.Compare(a.name, b.name)
106+
})
107+
for _, kv := range sorted {
108+
fmt.Fprintf(sb, "\t%v: %v\n", kv.name, kv.val)
109+
}
110+
}

0 commit comments

Comments
 (0)