Files
William Valentin 3434db3c59 feat: complete agent monitoring - hook, UI, and backend filter
- Add event_type and framework filters to events query endpoint
- Add /agents SPA route to web-ui server
- Add Agents nav link and route in frontend
- Add agents page CSS (timeline, VM pills, stats panel)
- Build VM status strip, activity timeline, and real-time stats
- Add agentmon hook for OpenClaw (HOOK.md + handler.ts)
- Add docker-compose, Dockerfile, and supporting infra files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 00:26:42 -07:00

212 lines
4.9 KiB
Markdown

# Agentmon SDK
The agentmon SDK provides a Go client for sending telemetry events to the agentmon backend.
## Installation
```bash
go get agentmon/internal/sdk
```
## Quick Start
```go
package main
import (
"context"
"log"
"agentmon/internal/sdk"
)
func main() {
emitter, err := sdk.NewEmitter(sdk.Config{
ServerURL: "http://localhost:8080",
Framework: "my-agent",
ClientID: "my-client-001",
Host: "localhost",
BufferSize: 100,
})
if err != nil {
log.Fatal(err)
}
defer emitter.Close(context.Background())
ctx := context.Background()
sessionID := "session-123"
// Start a session
sessionStart := sdk.NewSessionStart(sessionID, sdk.WithSource(emitter))
if err := emitter.Emit(ctx, sessionStart); err != nil {
log.Printf("Error: %v", err)
}
// ... do work ...
// End the session
sessionEnd := sdk.NewSessionEnd(sessionID, sdk.WithSource(emitter))
if err := emitter.Emit(ctx, sessionEnd); err != nil {
log.Printf("Error: %v", err)
}
// Flush buffered events
if err := emitter.Flush(ctx); err != nil {
log.Printf("Error: %v", err)
}
}
```
## Configuration
The `Config` struct configures the emitter:
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `ServerURL` | string | Yes | - | URL of the ingest gateway (e.g., `http://localhost:8080`) |
| `APIKey` | string | No | - | Optional API key for authentication |
| `Framework` | string | Yes | - | Name of the framework (e.g., `opencode`, `claude-code`) |
| `ClientID` | string | Yes | - | Stable identifier for this emitter instance |
| `Host` | string | No | `localhost` | Hostname where events originate |
| `BufferSize` | int | No | `100` | Max number of events to buffer before flushing |
| `UseWebSocket` | bool | No | `false` | Enable WebSocket streaming mode |
| `EnableLogging` | bool | No | `false` | Enable debug logging |
## Event Types
### Session Events
```go
// Start a session
sessionStart := sdk.NewSessionStart(sessionID,
sdk.WithSource(emitter),
sdk.WithAttributes(map[string]any{
"cwd": "/home/user/project",
"repo": "myrepo",
"branch": "main",
}),
)
// End a session
sessionEnd := sdk.NewSessionEnd(sessionID,
sdk.WithSource(emitter),
)
```
### Run Events
```go
// Start a run
runStart := sdk.NewRunStart(sessionID, runID,
sdk.WithSource(emitter),
sdk.WithAttributes(map[string]any{
"command": "my-command",
"agent": "my-agent",
}),
)
// End a run
runEnd := sdk.NewRunEnd(sessionID, runID, "success", 60000,
sdk.WithSource(emitter),
sdk.WithLLMUsage("claude-3-opus", 1000, 500, 0.015),
)
```
### Span Events
```go
// Start a span
spanStart := sdk.NewSpanStart(sessionID, runID, traceID, spanID,
sdk.WithSource(emitter),
sdk.WithSpanKind("tool"),
sdk.WithName("Bash"),
sdk.WithAttributes(map[string]any{
"command": "echo hello",
}),
)
// End a span
spanEnd := sdk.NewSpanEnd(sessionID, runID, traceID, spanID, "success", 1000,
sdk.WithSource(emitter),
sdk.WithSpanKind("tool"),
sdk.WithName("Bash"),
)
```
### Error Events
```go
errEvent := sdk.NewError(sessionID, runID, traceID, spanID,
"validation", "invalid input",
sdk.WithSource(emitter),
sdk.WithErrorDetails("VAL001", false),
)
```
### Metric Snapshots
```go
metrics := sdk.NewMetricSnapshot(sessionID, runID, map[string]any{
"tokens_in": 1000.0,
"tokens_out": 500.0,
"cost_usd": 0.015,
"latency_ms": 300.0,
"error_count": 0,
})
```
## Event Options
Event options are functions that modify events before sending:
- `WithSource(emitter)` - Add source information (framework, client_id, host)
- `WithAttributes(attrs)` - Add arbitrary attributes
- `WithSpanKind(kind)` - Set the span_kind attribute (`llm`, `tool`, `skill`, `internal`)
- `WithName(name)` - Set the name attribute
- `WithParentSpanID(parentID)` - Set the parent span ID
- `WithPayload(payload)` - Set custom payload
- `WithSeq(seq)` - Set sequence number (for WebSocket mode)
- `WithLLMUsage(model, inTokens, outTokens, costUSD)` - Add LLM usage to run.end or span.end
- `WithErrorDetails(code, retryable)` - Add error details
## Span Kinds
Common span kinds:
- `llm` - LLM API calls
- `tool` - Tool/function calls
- `skill` - Skill execution
- `internal` - Internal operations
## WebSocket Mode
For real-time streaming, enable WebSocket mode:
```go
emitter, err := sdk.NewEmitter(sdk.Config{
ServerURL: "http://localhost:8080",
Framework: "my-agent",
ClientID: "my-client-001",
Host: "localhost",
UseWebSocket: true,
})
```
In WebSocket mode, events are sent immediately rather than buffered.
## Example
See `examples/sdk-example/main.go` for a complete example.
## Testing
Run tests with:
```bash
go test ./internal/sdk/...
```
## License
Same license as the agentmon project.