📦 deps(thirdparty): update snapshots
This commit is contained in:
+315
@@ -0,0 +1,315 @@
|
||||
# Observability Templates
|
||||
|
||||
Templates for agent observability infrastructure.
|
||||
|
||||
Advanced profile only. Load this reference only when the user explicitly requests agent execution
|
||||
traces, observability hooks, metrics, or debugging of long-running agent sessions. Do not create
|
||||
`harness/trace` or observability hooks as part of the default core harness.
|
||||
|
||||
## Trace Format
|
||||
|
||||
Standard format for recording agent execution sessions.
|
||||
|
||||
```go
|
||||
// harness/trace/format.go
|
||||
package trace
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AgentTrace captures a complete agent execution session
|
||||
type AgentTrace struct {
|
||||
SessionID string `json:"session_id"`
|
||||
AgentType string `json:"agent_type"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
EndTime time.Time `json:"end_time"`
|
||||
Prompt string `json:"prompt"`
|
||||
SystemPrompt string `json:"system_prompt,omitempty"`
|
||||
WorkingDir string `json:"working_dir"`
|
||||
Messages []MessageTrace `json:"messages"`
|
||||
ToolCalls []ToolTrace `json:"tool_calls"`
|
||||
TokenUsage TokenUsage `json:"token_usage"`
|
||||
Outcome Outcome `json:"outcome"`
|
||||
Result string `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type MessageTrace struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
type ToolTrace struct {
|
||||
ID string `json:"id"`
|
||||
Tool string `json:"tool"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
Output string `json:"output"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
IsError bool `json:"is_error"`
|
||||
ErrCode int `json:"err_code,omitempty"`
|
||||
}
|
||||
|
||||
type TokenUsage struct {
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
}
|
||||
|
||||
type Outcome string
|
||||
|
||||
const (
|
||||
OutcomeSuccess Outcome = "success"
|
||||
OutcomeError Outcome = "error"
|
||||
OutcomeTimeout Outcome = "timeout"
|
||||
OutcomeCancelled Outcome = "cancelled"
|
||||
OutcomeMaxTurns Outcome = "max_turns"
|
||||
OutcomeMaxToolCalls Outcome = "max_tool_calls"
|
||||
)
|
||||
|
||||
// TraceBuilder constructs traces incrementally
|
||||
type TraceBuilder struct {
|
||||
trace AgentTrace
|
||||
}
|
||||
|
||||
func NewTraceBuilder(sessionID, agentType string) *TraceBuilder {
|
||||
return &TraceBuilder{
|
||||
trace: AgentTrace{
|
||||
SessionID: sessionID,
|
||||
AgentType: agentType,
|
||||
StartTime: time.Now(),
|
||||
Messages: make([]MessageTrace, 0),
|
||||
ToolCalls: make([]ToolTrace, 0),
|
||||
Metadata: make(map[string]any),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *TraceBuilder) AddMessage(msg MessageTrace) { b.trace.Messages = append(b.trace.Messages, msg) }
|
||||
func (b *TraceBuilder) AddToolCall(tc ToolTrace) { b.trace.ToolCalls = append(b.trace.ToolCalls, tc) }
|
||||
|
||||
func (b *TraceBuilder) Build() AgentTrace {
|
||||
b.trace.EndTime = time.Now()
|
||||
return b.trace
|
||||
}
|
||||
|
||||
func (t *AgentTrace) Export(path string) error {
|
||||
data, err := json.MarshalIndent(t, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
func Load(path string) (*AgentTrace, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var trace AgentTrace
|
||||
return &trace, json.Unmarshal(data, &trace)
|
||||
}
|
||||
```
|
||||
|
||||
## Self-Test Framework
|
||||
|
||||
Framework for testing agent behavior with validation.
|
||||
|
||||
```go
|
||||
// harness/selftest/runner.go
|
||||
package selftest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestCase defines a single agent test
|
||||
type TestCase struct {
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
Prompt string `json:"prompt"`
|
||||
InitFiles map[string]string `json:"init_files,omitempty"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
MaxTurns int `json:"max_turns,omitempty"`
|
||||
Expected *Expectations `json:"expected,omitempty"`
|
||||
Validators []Validator `json:"-"`
|
||||
}
|
||||
|
||||
type Expectations struct {
|
||||
Files map[string]FileExpectation `json:"files,omitempty"`
|
||||
ToolCalls []ToolCallExpectation `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type FileExpectation struct {
|
||||
MustExist bool `json:"must_exist"`
|
||||
MustContain []string `json:"must_contain,omitempty"`
|
||||
MustNotContain []string `json:"must_not_contain,omitempty"`
|
||||
}
|
||||
|
||||
type ToolCallExpectation struct {
|
||||
Tool string `json:"tool"`
|
||||
MustOccur bool `json:"must_occur,omitempty"`
|
||||
MustNotOccur bool `json:"must_not_occur,omitempty"`
|
||||
}
|
||||
|
||||
type Validator func(result *AgentResult) error
|
||||
|
||||
type AgentResult struct {
|
||||
TestName string `json:"test_name"`
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
ToolCalls []ToolCallRecord `json:"tool_calls"`
|
||||
}
|
||||
|
||||
type ToolCallRecord struct {
|
||||
Tool string `json:"tool"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
Output string `json:"output"`
|
||||
IsError bool `json:"is_error"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
}
|
||||
|
||||
type Runner struct {
|
||||
WorkDir string
|
||||
DefaultTimeout time.Duration
|
||||
}
|
||||
|
||||
func NewRunner(workDir string) *Runner {
|
||||
return &Runner{WorkDir: workDir, DefaultTimeout: 2 * time.Minute}
|
||||
}
|
||||
|
||||
func (r *Runner) Run(ctx context.Context, tc TestCase) (*AgentResult, error) {
|
||||
result := &AgentResult{
|
||||
TestName: tc.Name,
|
||||
ToolCalls: make([]ToolCallRecord, 0),
|
||||
}
|
||||
start := time.Now()
|
||||
defer func() { result.Duration = time.Since(start) }()
|
||||
|
||||
// TODO: Integrate with actual agent execution
|
||||
return result, fmt.Errorf("not yet integrated with agent")
|
||||
}
|
||||
```
|
||||
|
||||
## Observability Hook
|
||||
|
||||
Hook that records tool calls for analysis and replay.
|
||||
|
||||
```go
|
||||
// hooks/observability/observability.go
|
||||
package observability
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ToolTrace struct {
|
||||
Tool string `json:"tool"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
Output string `json:"output"`
|
||||
IsError bool `json:"is_error"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// TraceRecorder collects tool traces
|
||||
type TraceRecorder struct {
|
||||
mu sync.RWMutex
|
||||
traces []ToolTrace
|
||||
sessionId string
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
func NewTraceRecorder(sessionId string) *TraceRecorder {
|
||||
return &TraceRecorder{
|
||||
traces: make([]ToolTrace, 0),
|
||||
sessionId: sessionId,
|
||||
startTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *TraceRecorder) Record(trace ToolTrace) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.traces = append(r.traces, trace)
|
||||
}
|
||||
|
||||
func (r *TraceRecorder) GetTraces() []ToolTrace {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
result := make([]ToolTrace, len(r.traces))
|
||||
copy(result, r.traces)
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *TraceRecorder) ExportJSON() ([]byte, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
return json.MarshalIndent(map[string]any{
|
||||
"session_id": r.sessionId,
|
||||
"start_time": r.startTime,
|
||||
"end_time": time.Now(),
|
||||
"traces": r.traces,
|
||||
}, "", " ")
|
||||
}
|
||||
|
||||
// Summary returns aggregate statistics
|
||||
func (r *TraceRecorder) Summary() TraceSummary {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
summary := TraceSummary{
|
||||
TotalCalls: len(r.traces),
|
||||
ToolCounts: make(map[string]int),
|
||||
}
|
||||
for _, t := range r.traces {
|
||||
summary.ToolCounts[t.Tool]++
|
||||
if t.IsError {
|
||||
summary.TotalErrors++
|
||||
}
|
||||
summary.TotalDuration += t.Duration
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
type TraceSummary struct {
|
||||
TotalCalls int `json:"total_calls"`
|
||||
TotalErrors int `json:"total_errors"`
|
||||
TotalDuration time.Duration `json:"total_duration"`
|
||||
ToolCounts map[string]int `json:"tool_counts"`
|
||||
}
|
||||
```
|
||||
|
||||
## Integration Pattern
|
||||
|
||||
To wire the observability hook into an existing agent:
|
||||
|
||||
```go
|
||||
// In agent initialization:
|
||||
recorder := observability.NewTraceRecorder(sessionId)
|
||||
hook := observability.NewObservabilityHook(recorder)
|
||||
|
||||
// Register as PostToolUse hook
|
||||
agent.AddPostToolUseHook(hook)
|
||||
|
||||
// After agent completes:
|
||||
traces := recorder.GetTraces()
|
||||
summary := recorder.Summary()
|
||||
summary.Print()
|
||||
|
||||
// Export for analysis
|
||||
data, _ := recorder.ExportJSON()
|
||||
os.WriteFile("trace.json", data, 0644)
|
||||
```
|
||||
Reference in New Issue
Block a user