Skip to content

Filter agent-compose logs by event id (daemon-side) - #81

Merged
innomentats merged 5 commits into
chaitin:mainfrom
yorkew-east8:feat/cli-logs-event-id-filter
Sep 24, 2026
Merged

innomentats merged 5 commits into
chaitin:mainfrom
yorkew-east8:feat/cli-logs-event-id-filter

Conversation

@yorkew-east8

@yorkew-east8 yorkew-east8 commented Sep 21, 2026 •

Copy link
Copy Markdown

Summary

agent-compose logs --event <evt-id> now delegates event→run resolution to the daemon. The CLI sends one ListRuns call carrying the new event_id field and replays the returned runs; it no longer fetches the event trace, resolves scheduler runs, or merges run lists locally.

Depends on chaitin/agent-compose#712 (adds ListRunsRequest.event_id, daemon-side event scope filtering, and the ListRunsResponse.event_scope_truncated flag). The vendored proto snapshot in products/agentcompose/proto/SOURCE is pinned to agent-compose@85ba5a4185e907c1306beb588d3800e570a610b0; after #712 merges we can re-pin to the merge commit and the generated code should be byte-identical.

Changes

  • proto snapshot: SOURCE pin + sha256 updated; gen/ regenerated via task agent-compose:proto:sync + task agent-compose:proto:generate (new event_id field 13 on ListRunsRequest, new event_scope_truncated field 3 on ListRunsResponse). Generated code is committed per repo convention; CI does not regenerate.
  • logs_event.go rewritten: single paged ListRuns{ProjectId, AgentName, EventId, Limit:200} loop advancing offset until total is reached. Deleted the client-side trace REST calls, resolveEventLogSchedulerRunIDs, resolveEventLogRuns, and eventLogReplayRuns. Kept: evt_ prefix validation (fast fail), selector mutual exclusion (--run/--sandbox/positional vs --event), resolveAgent reference normalization (a CLI concern, not run filtering), empty-result stderr notice (text) / {"runs":[]} (JSON), and per-run --follow replay.
  • truncation signal: when the daemon reports event_scope_truncated (event scope hit its 1000-event cap), the CLI prints a warning on stderr in both text and JSON mode, exit code unchanged.
  • replay order: runs are sorted oldest-first by started_at as time.Time (daemon order kept as tie-breaker). The previous RFC3339Nano string key misordered mixed fraction precision (.1Z vs .15Z).
  • tests rewritten: assert event_id/AgentName passthrough, unknown event maps to not_found (exit 5), paging loop over a 200+1 stub, oldest-first replay, JSON NDJSON output, empty notices, and the truncation warning. The test server helper now accepts the outer handler value so embedded-stub overrides dispatch correctly.

User-visible behavior

Unchanged from the previous iteration of this PR: full evt_ id required, mutually exclusive selectors, --agent narrowing, --follow snapshot semantics, empty-result notice with exit 0, JSON output shape. Unknown event ids now surface as not_found (exit 5) from the daemon instead of a client-side message. Truncated event scopes surface as a stderr warning with exit 0.

One intentional difference from the built-in CLI (chaitin/agent-compose#712): chaitin-cli maps CodeNotFound to exit code 5 per its own error vocabulary, while agent-compose's CLI uses exit 2 (usage) for the same condition.

Backward compatibility

proto3 unknown fields are ignored by older daemons: a new CLI against an old daemon sends event_id that is silently dropped, and the daemon returns unfiltered runs. Daemon and CLI must be upgraded together; called out in #712 as well.

Verification

  • task fmt:check, task lint, task build, task test — all pass (including products/agentcompose package suite).
  • go vet clean.
  • Pre-existing failures on clean main in this repo are unrelated (tzdata/LLM-config environment tests) and were confirmed in the earlier draft iteration.

Resolve an event-bus event id (evt_...) via the daemon event trace
REST endpoint and replay the agent runs recorded against it, using
the existing ListRuns scheduler_run_id filter. The flag accepts full
event ids only, is mutually exclusive with --run, --sandbox, and
positional targets, composes with --agent (resolved to the canonical
agent name before narrowing), and reports events without runs on
stderr (empty runs array with --json).
@yorkew-east8 yorkew-east8 changed the title Add --event filter to agent-compose logs Filter agent-compose logs by event id (daemon-side) Sep 22, 2026
Sync the proto snapshot pinned to agent-compose@99bd5586 which adds
ListRunsRequest.event_id, and drop the client-side trace resolution,
run filtering and merge logic from logs --event. The command now sends
one ListRuns call with the event id and the daemon resolves the event
scope (event itself, descendants, correlation siblings) and its runs.

- regenerate gen/ for the new event_id field (field 13)
- rewrite logs_event.go: single paged ListRuns (limit 200, offset until
  total), keep evt_ validation, selector mutual exclusion, agent
  reference resolution, empty-result notices and NDJSON output
- replay order: sort by started_at as time.Time with daemon order as
  tie-breaker (the previous iteration replayed delivery order; sorting
  by RFC3339Nano string key would misorder mixed fraction precision)
- rewrite tests: assert event_id/agent passthrough, not-found maps to
  exit 5, paging loop, oldest-first replay; server helper takes the
  outer handler value so embedded stub overrides dispatch
@yorkew-east8
yorkew-east8 force-pushed the feat/cli-logs-event-id-filter branch from 9438108 to ce1d68d Compare September 22, 2026 05:21
@yorkew-east8
yorkew-east8 marked this pull request as ready for review September 22, 2026 07:31
@yorkew-east8

Copy link
Copy Markdown
Author

@monkeyscan 评审下这个 PR

@monkeyscan

monkeyscan Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

@yorkew-east8 wrote:
@monkeyscan 评审下这个 PR

处理失败,请稍后重试。

@yorkew-east8

Copy link
Copy Markdown
Author

@monkeyscan 评审下这个 PR

@monkeyscan

monkeyscan Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

@yorkew-east8 wrote:
@monkeyscan 评审下这个 PR

处理失败,请稍后重试。

Sync the proto snapshot pinned to agent-compose@85ba5a41 which adds
ListRunsResponse.event_scope_truncated, and warn on stderr when the
daemon reports that the event scope hit its 1000-event cap, so runs
recorded only against events beyond the cap are missing from the
output. The warning prints in both text and JSON mode.
@yorkew-east8

Copy link
Copy Markdown
Author

@monkeyscan 评审下这个 PR

@monkeyscan

monkeyscan Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

PR Title: Filter agent-compose logs by event id (daemon-side...

Commit: 613d203

整体评估

本次变更给 agentcompose 的 logs 命令新增了 --event,按事件 id 在 daemon 侧过滤并回放关联 run 的日志,包含新实现文件、配套测试,以及协议快照与生成代码的同步(协议里还夹带了一个与本功能无关的枚举新增)。分页、排序、not_found 映射与截断告警等核心逻辑都有针对性测试覆盖,整体方向一致,可在小幅修正后合并。

总结

整体实现可用、方向正确,主要风险集中在机器可读输出契约与对服务端版本的耦合。最需要修的是 logs --event --json 在空结果时输出 {"runs":[]} 对象、有结果时却输出 NDJSON 记录,解析方无法用统一逻辑处理,应统一为单一契约;其次是该特性依赖尚未发布的 daemon 字段(README 标注 pending v2609.3.1+),旧 daemon 会静默忽略 event_id 并返回整个项目的 run,需补充能力/版本校验或明确最低版本要求。

Findings (1)

  • 🟡 [MEDIUM] products/agentcompose/logs_event.go:72 — logs --event --json 空结果时输出对象而非 NDJSON,机器可读契约随结果是否为空而变化
Prompt To Fix All With AI
# Review 1

This is a comment left during a code review.
Repository: https://github.com/chaitin/chaitin-cli
Path: products/agentcompose/logs_event.go
Line: 39-45

Comment:
--event 未做 daemon 能力校验,旧 daemon 会静默忽略 event_id 并返回整个项目的 run

ListRunsRequest.event_id 是本次新增字段,其事件解析语义完全由 daemon 实现,proto 快照来自提交 85ba5a4185e907c1306beb588d3800e570a610b0,README 明确标注 feat/cli-logs-event-id-filter; pending v2609.3.1+,即该 API 尚未随版本发布(连“未知事件返回 NOT_FOUND”也是新行为)。protobuf 服务端默认忽略未知请求字段,因此当本 CLI 连到尚未支持该字段的 daemon 时,ListRuns 既不会按事件过滤也不会报错,而是返回该项目(以及 --agent 过滤后)的全部 run;CLI 随后把这些 run 当作该事件的 run 回放并以成功退出,用户拿到的是看似正常但内容错误的结果,且没有任何提示。

# Review 2

This is a comment left during a code review.
Repository: https://github.com/chaitin/chaitin-cli
Path: products/agentcompose/logs_event.go
Line: 64-72

Comment:
logs --event --json 空结果时输出对象而非 NDJSON,机器可读契约随结果是否为空而变化

当事件没有任何关联 run 且启用 --json 时,executeLogsForEvent 会向 stdout 写出单个对象 {"runs":[]}(logs_event.go:64-68);而同一命令在存在 run 时是经由 followOneRun 逐条输出 NDJSON 记录(字段包括 run_id/content/is_final 等),新增测试自身也把这些行称作 NDJSON 行。也就是说 --json 的输出结构取决于结果集是否为空,下游解析器无法用统一逻辑处理,空与非空两侧必须各写一套分支。此外普通 logs --json 在无目标时是空输出(executeLogs 直接 return nil),该对象也与既有输出约定不一致,容易让脚本把 {"runs":[]} 误当成一条日志记录。
---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread products/agentcompose/logs_event.go Resolved
--json is a record stream (followOneRun NDJSON records); an empty
result now writes no records, matching logs --json with no targets,
instead of switching to a wrapper object that scripts would have to
parse differently from the non-empty case.
@innomentats
innomentats merged commit 06786ea into chaitin:main Sep 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants