Skip to content

fix: filter agent executions with a structured startTime query (#97) - #111

Open
mp-orkes wants to merge 1 commit into
mainfrom
fix/issue-97-agent-execution-time-filter
Open

fix: filter agent executions with a structured startTime query (#97)#111
mp-orkes wants to merge 1 commit into
mainfrom
fix/issue-97-agent-execution-time-filter

Conversation

@mp-orkes

@mp-orkes mp-orkes commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Issue

Every time-filtered search was empty while the unfiltered one listed rows - #97.

What changed

agent execution --since/--window built freeText=startTime:[<ms> TO *].

  • SQLite turns freeText into json_data LIKE '%startTime:[…]%', which never matches.
  • Elasticsearch passes it to queryStringQuery and returns 0.

Search now goes through /workflow/search with classifier=agent&topLevelOnly=true. Same as Conductor UI on Agent Executions view.

Why not /agent/executions? That endpoint builds its search query internally and exposes no time-range parameter. A caller-supplied query is ignored.

How to test

conductor agent run --config agent.yaml "hi" --no-stream
conductor agent execution --since 1h        # was empty, now lists the run
conductor agent execution --window now-7d
conductor agent execution --name <agent> --since 1d
sleep 6 && conductor agent execution --since 2s   # correctly empty

Review notes

  • > only. >= is rejected by both query parsers with a 500 (For input string: "=<ms>"), because neither defines the operator.
  • Quoted values are rejected. Values are embedded as field='value'. A value containing a quote would change what the expression means, so it errors instead.
  • Non-agent rows are dropped. A server whose index predates the classifier field ignores the filter and returns plain workflows. The mapper skips rows whose classifier is not agent.
  • The SDK cannot express this. WorkflowResourceApiSearchOpts has no classifier or topLevelOnly.

🤖 Generated with Claude Code

`agent execution --since/--window` built `freeText=startTime:[<ms> TO *]`, a
range no Conductor index backend honors. SQLite turns freeText into
`json_data LIKE '%…%'`, and Elasticsearch returns nothing for the range, so
every time-filtered search came back empty while the unfiltered one listed rows.

Search now goes through `/workflow/search` with `classifier=agent` and
`topLevelOnly=true`, carrying the bounds in the structured `query` expression
(`startTime><ms>`) — the same call the Conductor UI makes for its own Agent
Executions view. `/agent/executions` cannot serve this: it builds its query
internally and ignores a caller-supplied `query`.

Notes:
- Only `>` and `<` are used. `>=` is rejected by both query parsers with a 500.
- Values are single-quoted, so a value containing a quote is rejected rather
  than silently changing what the expression means.
- Results whose `classifier` is not `agent` are dropped, in case a server's
  index ignores the parameter and returns plain workflows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mp-orkes
mp-orkes force-pushed the fix/issue-97-agent-execution-time-filter branch from 3869b91 to eb86b7d Compare August 7, 2026 17:24
@mp-orkes
mp-orkes marked this pull request as ready for review August 7, 2026 17:54
@mp-orkes mp-orkes self-assigned this Aug 7, 2026
@mp-orkes

mp-orkes commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author
Screenshot 2026-08-07 at 15 10 36

@ambiorix2099 ambiorix2099 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Left questions for your consideration as a single comment.

Comment thread internal/agent/client.go
Comment on lines +347 to +353
func (r workflowSearchResult) toExecutionPage() ExecutionPage {
page := ExecutionPage{TotalHits: r.TotalHits}
for _, w := range r.Results {
// A server that ignores the classifier param returns plain workflows too.
if w.Classifier != "" && w.Classifier != classifierAgent {
continue
}

@ambiorix2099 ambiorix2099 Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LTGM. The below are simply questions for your consideration.

TotalHits comes from the server here but Results gets filtered just below, so the %d of %d line in cmd/agent.go can end up printing something like 3 of 50.

Q1. Adjust the count when we drop rows, or not filter client-side at all?

Related: the notes say the mapper skips non-agent rows, but w.Classifier != "" keeps them when the field is absent, which is exactly the pre-classifier server case you're describing.

Q2. Intentional?

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