-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdebug.go
More file actions
108 lines (92 loc) · 3.46 KB
/
Copy pathdebug.go
File metadata and controls
108 lines (92 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package chainforge
import (
"context"
"fmt"
"io"
"github.com/lioarce01/chainforge/pkg/core"
)
// DebugEventKind identifies the stage of the agent loop a DebugEvent describes.
type DebugEventKind string
const (
// DebugLLMRequest fires just before a Chat or ChatStream call.
// DebugEvent.Messages contains the full message slice sent to the provider.
DebugLLMRequest DebugEventKind = "llm_request"
// DebugLLMResponse fires immediately after a successful Chat or ChatStream call.
// DebugEvent.Response is set.
DebugLLMResponse DebugEventKind = "llm_response"
// DebugToolCall fires before each individual tool is invoked.
// DebugEvent.ToolCall is set.
DebugToolCall DebugEventKind = "tool_call"
// DebugToolResult fires after each individual tool returns.
// DebugEvent.ToolCall, DebugEvent.ToolOutput, and DebugEvent.ToolError are set.
DebugToolResult DebugEventKind = "tool_result"
// DebugHITLRequest fires when a HITL gateway approval is requested for a tool call.
// DebugEvent.ToolCall is set. DebugEvent.Iteration is the current loop iteration.
DebugHITLRequest DebugEventKind = "hitl_request"
// DebugHITLResponse fires after the HITL gateway returns its decision.
// DebugEvent.ToolCall is set. DebugEvent.ToolOutput contains "approved=true|false".
DebugHITLResponse DebugEventKind = "hitl_response"
)
// DebugEvent carries the state of a single step in the agent loop.
type DebugEvent struct {
Kind DebugEventKind
Iteration int
// LLMRequest: full message slice sent to the provider.
Messages []core.Message
// LLMResponse: the provider response.
Response *core.ChatResponse
// ToolCall / ToolResult: the tool invocation.
ToolCall *core.ToolCall
ToolOutput string
ToolError error
}
// DebugHandler is called synchronously at each significant step of the agent loop.
// It must not block. Use it for logging, recording, or printing during development.
type DebugHandler func(ctx context.Context, event DebugEvent)
// PrettyPrintDebugHandler returns a DebugHandler that writes a human-readable
// transcript of every agent loop step to w.
//
// chainforge.WithDebugHandler(chainforge.PrettyPrintDebugHandler(os.Stderr))
func PrettyPrintDebugHandler(w io.Writer) DebugHandler {
return func(_ context.Context, ev DebugEvent) {
switch ev.Kind {
case DebugLLMRequest:
fmt.Fprintf(w, "[iter %d] → LLM (%d messages)\n", ev.Iteration, len(ev.Messages))
case DebugLLMResponse:
if ev.Response != nil {
fmt.Fprintf(w, "[iter %d] ← LLM stop=%s %q\n",
ev.Iteration, ev.Response.StopReason,
truncate(ev.Response.Message.Content, 120))
}
case DebugToolCall:
if ev.ToolCall != nil {
fmt.Fprintf(w, "[iter %d] ⚙ tool=%s input=%s\n",
ev.Iteration, ev.ToolCall.Name, truncate(ev.ToolCall.Input, 80))
}
case DebugToolResult:
if ev.ToolError != nil {
fmt.Fprintf(w, "[iter %d] ✗ tool=%s err=%v\n",
ev.Iteration, ev.ToolCall.Name, ev.ToolError)
} else {
fmt.Fprintf(w, "[iter %d] ✓ tool=%s result=%s\n",
ev.Iteration, ev.ToolCall.Name, truncate(ev.ToolOutput, 80))
}
case DebugHITLRequest:
if ev.ToolCall != nil {
fmt.Fprintf(w, "[iter %d] ⏸ hitl_request tool=%s\n",
ev.Iteration, ev.ToolCall.Name)
}
case DebugHITLResponse:
if ev.ToolCall != nil {
fmt.Fprintf(w, "[iter %d] ⏵ hitl_response tool=%s %s\n",
ev.Iteration, ev.ToolCall.Name, ev.ToolOutput)
}
}
}
}
func truncate(s string, n int) string {
if len(s) <= n {
return s
}
return s[:n] + "…"
}