Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `goclaw agents evolution update` now maps `--action=accept|reject` to the server-compatible `status=approved|rejected` payload.

**P6 — Backend-unblocked surfaces (gateway `v3.12.0-beta.20`+)**
- `goclaw traces list --q --agent-query --channel-query --from --to --min-input-tokens --max-input-tokens --min-output-tokens --max-output-tokens --min-tool-calls --max-tool-calls --tool-name --has-tool-calls` — forwards the trace search and advanced filters added by server PR #155 while preserving existing `--agent` as `agent_id`.
- `goclaw traces follow --session-key|--agent [--since RFC3339] [--limit N]` — one-shot incremental trace polling (`GET /v1/traces/follow`). Re-invoke with returned cursor to advance; no WS stream, no watch loop.
- `goclaw traces timeline <run-id> [--session-key K] [--limit N] [--offset N]` — read archived run timeline items (`GET /v1/runs/{runID}/timeline`) without replaying or mutating a run.
- `goclaw providers reconnect <provider-id>` — hot-reconnect a provider, bumping the registry without touching credentials (`POST /v1/providers/{id}/reconnect`).
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ plus the run timeline archive endpoint:
# Paginated trace listing with server-supported filters
goclaw traces list [--agent <id>] [--user <id>] [--session-key <key>] \
[--status <status>] [--channel <name>] [--limit <n>] [--offset <n>]
goclaw traces list --q "refund error" [--agent-query <text>] [--channel-query <text>] \
[--from <RFC3339>] [--to <RFC3339>] [--min-input-tokens <n>] \
[--max-input-tokens <n>] [--min-output-tokens <n>] [--max-output-tokens <n>] \
[--min-tool-calls <n>] [--max-tool-calls <n>] [--tool-name <text>] \
[--has-tool-calls <true|false>]

# Incremental trace polling (one shot; rerun with returned cursor)
goclaw traces follow --session-key <key> [--since <RFC3339>] [--limit <n>]
Expand Down
41 changes: 41 additions & 0 deletions cmd/traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ var tracesListCmd = &cobra.Command{
if v, _ := cmd.Flags().GetString("channel"); v != "" {
q.Set("channel", v)
}
setStringQueryFlag(cmd, q, "q", "q")
setStringQueryFlag(cmd, q, "agent-query", "agent")
setStringQueryFlag(cmd, q, "channel-query", "channel_query")
setStringQueryFlag(cmd, q, "from", "from")
setStringQueryFlag(cmd, q, "to", "to")
setChangedIntQueryFlag(cmd, q, "min-input-tokens", "min_input_tokens")
setChangedIntQueryFlag(cmd, q, "max-input-tokens", "max_input_tokens")
setChangedIntQueryFlag(cmd, q, "min-output-tokens", "min_output_tokens")
setChangedIntQueryFlag(cmd, q, "max-output-tokens", "max_output_tokens")
setChangedIntQueryFlag(cmd, q, "min-tool-calls", "min_tool_calls")
setChangedIntQueryFlag(cmd, q, "max-tool-calls", "max_tool_calls")
setStringQueryFlag(cmd, q, "tool-name", "tool_name")
setStringQueryFlag(cmd, q, "has-tool-calls", "has_tool_calls")
if v, _ := cmd.Flags().GetInt("limit"); v > 0 {
q.Set("limit", fmt.Sprintf("%d", v))
}
Expand Down Expand Up @@ -115,6 +128,21 @@ func validateTraceID(id string) error {
return nil
}

func setStringQueryFlag(cmd *cobra.Command, q url.Values, flagName, queryName string) {
v, _ := cmd.Flags().GetString(flagName)
if v != "" {
q.Set(queryName, v)
}
}

func setChangedIntQueryFlag(cmd *cobra.Command, q url.Values, flagName, queryName string) {
if !cmd.Flags().Changed(flagName) {
return
}
v, _ := cmd.Flags().GetInt(flagName)
q.Set(queryName, fmt.Sprintf("%d", v))
}

var tracesExportCmd = &cobra.Command{
Use: "export <traceID>", Short: "Export trace to file", Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -308,6 +336,19 @@ func init() {
tracesListCmd.Flags().String("session-key", "", "Filter by session key")
tracesListCmd.Flags().String("status", "", "Filter: running, success, error")
tracesListCmd.Flags().String("channel", "", "Filter by channel")
tracesListCmd.Flags().String("q", "", "Search trace id, previews, session/channel labels, agent/channel labels, and span previews")
tracesListCmd.Flags().String("agent-query", "", "Search agent display name or key")
tracesListCmd.Flags().String("channel-query", "", "Search channel instance name, display name, or type")
tracesListCmd.Flags().String("from", "", "Filter traces from RFC3339 start time")
tracesListCmd.Flags().String("to", "", "Filter traces up to RFC3339 start time")
tracesListCmd.Flags().Int("min-input-tokens", 0, "Minimum total input tokens")
tracesListCmd.Flags().Int("max-input-tokens", 0, "Maximum total input tokens")
tracesListCmd.Flags().Int("min-output-tokens", 0, "Minimum total output tokens")
tracesListCmd.Flags().Int("max-output-tokens", 0, "Maximum total output tokens")
tracesListCmd.Flags().Int("min-tool-calls", 0, "Minimum tool-call count")
tracesListCmd.Flags().Int("max-tool-calls", 0, "Maximum tool-call count")
tracesListCmd.Flags().String("tool-name", "", "Search span tool names")
tracesListCmd.Flags().String("has-tool-calls", "", "Filter traces by tool-call presence: true or false")
tracesListCmd.Flags().Int("limit", 20, "Max results")
tracesListCmd.Flags().Int("offset", 0, "Pagination offset")
tracesListCmd.Flags().String("since", "", "Deprecated: use traces follow --since")
Expand Down
12 changes: 11 additions & 1 deletion cmd/traces_contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@ func rawJSON(t *testing.T, w http.ResponseWriter, payload any) {

func resetTracesListFlags(t *testing.T) {
t.Helper()
for _, name := range []string{"agent", "user", "session-key", "status", "channel", "since"} {
for _, name := range []string{
"agent", "user", "session-key", "status", "channel", "since",
"q", "agent-query", "channel-query", "from", "to", "tool-name", "has-tool-calls",
} {
resetTestFlag(tracesListCmd, name, "")
}
resetTestFlag(tracesListCmd, "root-only", "false")
resetTestFlag(tracesListCmd, "limit", "20")
resetTestFlag(tracesListCmd, "offset", "0")
for _, name := range []string{
"min-input-tokens", "max-input-tokens",
"min-output-tokens", "max-output-tokens",
"min-tool-calls", "max-tool-calls",
} {
resetTestFlag(tracesListCmd, name, "0")
}
}

func assertNoTracesReplayCommand(t *testing.T) {
Expand Down
72 changes: 65 additions & 7 deletions cmd/traces_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,46 @@ func TestTracesList_ServerFilters(t *testing.T) {
"--session-key=session-1",
"--status=failed",
"--channel=telegram",
"--q=trace_%",
"--agent-query=helper",
"--channel-query=ops",
"--from=2026-06-10T01:02:03Z",
"--to=2026-06-11T04:05:06Z",
"--min-input-tokens=10",
"--max-input-tokens=20",
"--min-output-tokens=30",
"--max-output-tokens=40",
"--min-tool-calls=1",
"--max-tool-calls=3",
"--tool-name=web_%",
"--has-tool-calls=true",
"--limit=5",
"--offset=10",
)
if err != nil {
t.Fatalf("traces list: %v", err)
}
want := map[string]string{
"agent_id": "agent-1",
"user_id": "user-1",
"session_key": "session-1",
"status": "failed",
"channel": "telegram",
"limit": "5",
"offset": "10",
"agent_id": "agent-1",
"user_id": "user-1",
"session_key": "session-1",
"status": "failed",
"channel": "telegram",
"q": "trace_%",
"agent": "helper",
"channel_query": "ops",
"from": "2026-06-10T01:02:03Z",
"to": "2026-06-11T04:05:06Z",
"min_input_tokens": "10",
"max_input_tokens": "20",
"min_output_tokens": "30",
"max_output_tokens": "40",
"min_tool_calls": "1",
"max_tool_calls": "3",
"tool_name": "web_%",
"has_tool_calls": "true",
"limit": "5",
"offset": "10",
}
for key, val := range want {
if got := query.Get(key); got != val {
Expand All @@ -112,6 +138,38 @@ func TestTracesList_ServerFilters(t *testing.T) {
}
}

func TestTracesList_ServerFiltersForwardExplicitFalseAndZero(t *testing.T) {
t.Cleanup(func() { resetTracesListFlags(t) })
var query url.Values
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
query = r.URL.Query()
rawJSON(t, w, traceListFixture())
}))
defer srv.Close()
t.Setenv("GOCLAW_SERVER", srv.URL)
t.Setenv("GOCLAW_TOKEN", "test-token")
t.Setenv("GOCLAW_OUTPUT", "json")

err := runCmd(t, "traces", "list",
"--min-input-tokens=0",
"--max-tool-calls=0",
"--has-tool-calls=false",
)
if err != nil {
t.Fatalf("traces list: %v", err)
}
want := map[string]string{
"min_input_tokens": "0",
"max_tool_calls": "0",
"has_tool_calls": "false",
}
for key, val := range want {
if got := query.Get(key); got != val {
t.Fatalf("%s = %q, want %q; query=%s", key, got, val, query.Encode())
}
}
}

func TestTracesReplayCommandAbsent(t *testing.T) {
assertNoTracesReplayCommand(t)
}
Expand Down
4 changes: 2 additions & 2 deletions docs/codebase-summary.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# GoClaw CLI - Codebase Summary

**Generated from:** `repomix-output.xml` (2026-04-15), updated manually 2026-06-12
**Phase Status:** P0-P4 Complete (AI-First Expansion); Super Admin API Parity Complete; Domain Coverage P5 + P6 (Backend-Unblocked) Implemented; Runtime & Packages CLI Parity Implemented
**Phase Status:** P0-P4 Complete (AI-First Expansion); Super Admin API Parity Complete; Domain Coverage P5 + P6 (Backend-Unblocked) Implemented; Runtime & Packages CLI Parity Implemented; Trace Search/Filter CLI Implemented
**Total Files:** 80+
**Estimated Tokens:** 80,000+
**Total Size:** 220+ KB
Expand All @@ -10,7 +10,7 @@

## Overview

GoClaw CLI is a production-ready Go application providing comprehensive command-line management for GoClaw AI agent gateway servers. Built with Cobra framework, it supports 30+ command groups across modular command files with dual modes: interactive (human) and automation (CI/agent). Phases 0-4 (AI-first expansion) add AI ergonomics, admin/ops, migration, vault, and advanced agent/team/memory support. The 2026-05-18 super-admin parity work adds gateway upgrade, package updates, workstations, webhooks, MCP user credentials, secure env reveal, media/TTS/storage/channel fillers, and focused route-contract tests. The 2026-05-19 P3/P4 filler pass adds first-class profile commands, `GOCLAW_PROFILE`, `sessions compact`, WS health, trace filter polish, `codex-pool`, `api-keys rotate`, `config defaults`, chat session convenience wrappers, and `tools invoke --args`. The 2026-05-20 P5 filler pass adds team attachment download, skill-specific evolution suggestion apply, and fixes evolution update payload compatibility. The 2026-05-27 P6 backend-unblocked pass adds seven new surfaces wired to backend PRs `#37` and `#44`: `traces follow`, `providers reconnect`, `sessions branch`, `sessions follow`, `channels writers test`, `activity aggregate`, and `logs aggregate` — all one-shot HTTP commands (no new watch loops; reuse the existing `client.FollowStream` only for true streaming surfaces). The 2026-06-11 traces contract pass aligns `traces list/get/follow/export` with server `dev` envelopes and adds `traces timeline`. The 2026-06-12 Runtime & Packages parity pass aligns `packages` and secure `credentials` command envelopes with server `dev`, adds `credentials agent-credentials`, and preserves raw object payloads for machine output.
GoClaw CLI is a production-ready Go application providing comprehensive command-line management for GoClaw AI agent gateway servers. Built with Cobra framework, it supports 30+ command groups across modular command files with dual modes: interactive (human) and automation (CI/agent). Phases 0-4 (AI-first expansion) add AI ergonomics, admin/ops, migration, vault, and advanced agent/team/memory support. The 2026-05-18 super-admin parity work adds gateway upgrade, package updates, workstations, webhooks, MCP user credentials, secure env reveal, media/TTS/storage/channel fillers, and focused route-contract tests. The 2026-05-19 P3/P4 filler pass adds first-class profile commands, `GOCLAW_PROFILE`, `sessions compact`, WS health, trace filter polish, `codex-pool`, `api-keys rotate`, `config defaults`, chat session convenience wrappers, and `tools invoke --args`. The 2026-05-20 P5 filler pass adds team attachment download, skill-specific evolution suggestion apply, and fixes evolution update payload compatibility. The 2026-05-27 P6 backend-unblocked pass adds seven new surfaces wired to backend PRs `#37` and `#44`: `traces follow`, `providers reconnect`, `sessions branch`, `sessions follow`, `channels writers test`, `activity aggregate`, and `logs aggregate` — all one-shot HTTP commands (no new watch loops; reuse the existing `client.FollowStream` only for true streaming surfaces). The 2026-06-11 traces contract pass aligns `traces list/get/follow/export` with server `dev` envelopes and adds `traces timeline`. The 2026-06-12 Runtime & Packages parity pass aligns `packages` and secure `credentials` command envelopes with server `dev`, adds `credentials agent-credentials`, and preserves raw object payloads for machine output. The 2026-06-12 trace search/filter pass exposes server PR #155 filters on `traces list` with `--q`, `--agent-query`, `--channel-query`, date ranges, token ranges, tool-call ranges, `--tool-name`, and `--has-tool-calls`.

**Key Metrics:**
- **70+ command files** in `cmd/` (modularized for maintainability)
Expand Down
18 changes: 16 additions & 2 deletions docs/project-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,22 @@

**Last Updated:** 2026-06-12
**Phase Structure:** Legacy Phases 1-9 (bootstrap → CI/CD) + AI-First Expansion Phases 0-5 (2026-04-15)
**Current Status:** Legacy Phases 1-9 ✓ COMPLETE; P0-P4 ✓ COMPLETE; Super Admin API Parity ✓ COMPLETE; Domain Coverage P5/P6 ✓ COMPLETE; Runtime & Packages CLI parity implemented pending beta ship.
**Next Phase:** Ship Runtime & Packages parity PR to `dev` and verify beta release.
**Current Status:** Legacy Phases 1-9 ✓ COMPLETE; P0-P6 ✓ COMPLETE; Super Admin API Parity ✓ COMPLETE; Runtime & Packages CLI parity implemented; trace contract and trace search/filter CLI support implemented.
**Next Phase:** Ship trace search/filter CLI PR to `dev` and verify beta release.

---

## 2026-06-12: Trace Search/Filter CLI IMPLEMENTED

**Objective:** Expose server PR #155 trace search and advanced filters through `goclaw traces list`.

**Deliverables:**
- [x] Added `traces list --q --agent-query --channel-query --from --to --min-input-tokens --max-input-tokens --min-output-tokens --max-output-tokens --min-tool-calls --max-tool-calls --tool-name --has-tool-calls`.
- [x] Preserved existing `--agent` as `agent_id` for backward compatibility; `--agent-query` maps to the server `agent` text search.
- [x] Added focused tests for full query forwarding, explicit `false`, explicit zero values, and replay absence.
- [x] Synced README, changelog, codebase summary, and plan artifacts.

**Validation:** `/usr/local/go/bin/go test -count=1 ./cmd -run 'TestTracesList|TestTracesReplayCommandAbsent'`; `/usr/local/go/bin/go test -count=1 ./cmd`; `/usr/local/go/bin/go test -count=1 ./...`; `/usr/local/go/bin/go vet ./...`; `/usr/local/go/bin/go build ./...`.

---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
phase: 1
title: Contract Lock
status: completed
priority: P1
effort: 1h
dependencies: []
---

# Phase 1: Contract Lock

## Overview

Lock the merged server contract from `digitopvn/goclaw#155` before implementation. The output of this phase is a testable list of query mappings and explicit exclusions.

## Requirements

- Functional: map every new server list filter to one CLI flag.
- Non-functional: preserve existing `traces list` automation contract and avoid speculative server behavior.

## Architecture

`traces list` remains a one-shot `GET /v1/traces` command. The CLI only builds `url.Values`; all matching semantics, wildcard escaping, date parsing, and tenant scoping stay server-side.

## Related Code Files

- Modify: `cmd/traces_contract_test.go`
- Read: `cmd/traces.go`
- Read: `cmd/traces_list_test.go`
- Read: upstream `digitopvn/goclaw#155`

## Implementation Steps

1. Verify the server PR is merged and capture exact query names.
2. Add or update a contract test helper that resets all trace list flags, including new ones.
3. Confirm existing replay-absence coverage stays in place.

## Todo List

- [x] Capture exact query parameter names from server PR #155.
- [x] Update `resetTracesListFlags` for all new flags.
- [x] Keep `TestTracesReplayCommandAbsent` green.

## Success Criteria

- [x] Contract test names all new query params.
- [x] No plan or test implies `traces replay` exists.
- [x] No unresolved scope questions remain.

## Risk Assessment

Misnaming `agent` as `agent_id` would silently change semantics. The test must assert both `--agent` and `--agent-query` mappings to keep ID and query search distinct.

## Security Considerations

No credentials or live traces are used. Tests use synthetic `httptest` requests and server-shaped fixtures only.

## Next Steps

Proceed to Phase 2 only after focused contract tests fail for missing flags.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
phase: 2
title: TDD Implementation
status: completed
priority: P1
effort: 2h
dependencies:
- 1
---

# Phase 2: TDD Implementation

## Overview

Add focused failing tests for the new trace list filters, then implement the smallest CLI change in `cmd/traces.go`.

## Requirements

- Functional: `traces list` forwards all PR #155 filter flags when supplied.
- Functional: zero-valued numeric filters can be forwarded when the user explicitly sets them.
- Functional: `--has-tool-calls=false` is forwarded, not dropped.
- Non-functional: no output shape or command behavior changes outside list query construction.

## Architecture

The command keeps using `url.Values`. A small helper may copy changed string/int/bool-like string flags to query params if it reduces repetitive flag handling without creating a generic framework.

## Related Code Files

- Modify: `cmd/traces.go`
- Modify: `cmd/traces_list_test.go`
- Modify: `cmd/traces_contract_test.go`

## Implementation Steps

1. Extend `TestTracesList_ServerFilters` to include all new flags and expected query names.
2. Add a focused test for false/zero explicit forwarding:
`--has-tool-calls=false`, `--min-tool-calls=0`, `--min-input-tokens=0`.
3. Run focused tests and confirm failure before implementation.
4. Add flags to `tracesListCmd`:
`--q`, `--agent-query`, `--channel-query`, `--from`, `--to`,
`--min-input-tokens`, `--max-input-tokens`,
`--min-output-tokens`, `--max-output-tokens`,
`--min-tool-calls`, `--max-tool-calls`,
`--tool-name`, `--has-tool-calls`.
5. Map flags to server params:
`q -> q`, `agent-query -> agent`, `channel-query -> channel_query`,
ranges to snake_case names, `has-tool-calls -> has_tool_calls`.
6. Run focused tests again and fix only failures in this scope.

## Todo List

- [x] Add red tests for new filter forwarding.
- [x] Add explicit false/zero forwarding test.
- [x] Implement flag registration and query mapping.
- [x] Keep existing basic filter test green.

## Success Criteria

- [x] Focused trace list tests pass.
- [x] No changes to `traces follow`, `get`, `export`, or `timeline`.
- [x] `cmd/traces.go` remains compilable and has no duplicated large blocks.

## Risk Assessment

The main regression risk is accidentally changing `--agent` from agent ID to label search. Keep `--agent` as `agent_id` for backward compatibility and add `--agent-query` for the server `agent` query.

## Security Considerations

User-provided filter strings are only URL query values encoded through `url.Values`. No shell execution, path usage, or local file reads are introduced.

## Next Steps

After focused tests pass, update README and docs in Phase 3.
Loading
Loading