feat(agent/analyze): add pattern_search tool for catalog browsing#242
Open
nghiadaulau wants to merge 1 commit into
Open
feat(agent/analyze): add pattern_search tool for catalog browsing#242nghiadaulau wants to merge 1 commit into
nghiadaulau wants to merge 1 commit into
Conversation
Adds a read-only tool to the analyze agent: `pattern_search`. It complements `pattern_history` (lookup-by-id only) by letting the model browse the learned-pattern catalog when it doesn't already have an id. Why it matters -------------- The analyze agent's catalog-side tools are: - `pattern_history` — needs a specific pattern id. - `describe_service` — limited to one service at a time. That leaves no way to answer questions like: - "Are there other patterns on this service that fired recently?" - "Show me every spike-verdict pattern in the last day." - "Has this template ever been classified before?" The model can't list and filter the catalog without one. Today it ends up asking the operator or making up ids. `pattern_search` closes that gap. Filter / sort surface --------------------- - `query` — case-insensitive substring on the template. - `service` — exact, case-insensitive. - `verdict` — enum: `known | unknown | spike`. - `rule_name` — exact (case-sensitive; rule names are operator authored identifiers). - `order_by` — enum: `count_desc` (default), `last_seen_desc`, `first_seen_desc`. Ties broken by id ascending so output is deterministic. - `limit` — default 20, clamped at 100. The result carries `total_matched` + `truncated` so the model knows when to narrow. Output uses the standard ToolResult envelope with `Found: true` even on zero matches, matching the convention used by `recent_incidents` and `recent_changes` (the empty list is itself a meaningful answer). Constraints honored ------------------- - Strictly read-only: only reads from `PatternCatalog` via the existing local interface in tools.go — no new imports, no storage mutations, no provider calls. The import-graph guard (TestTools_ImportGraphStaysReadOnly) passes. - No changes to `tools.yaml` — purely catalog-backed, no external config needed. Registered in `tools.Default` next to `pattern_history` so it's available whenever a catalog is wired. - No worker / detect-mode behaviour change — analyze-only. - Rebased on the find_runbook-era `Default` signature (embedder + runbooks params); registration slot capacity bumped 7 -> 8. Tests ----- - TestDefault_PatternSearchRegistration — registered when a catalog is wired, omitted when nil (same convention as the find_runbook registration test). - TestPatternSearch_Metadata — Name/Description/ArgsSchema shape. - TestPatternSearch_NilCatalog / BadArgs / InvalidEnums — input validation surfaces clear errors. - TestPatternSearch_QuerySubstringCaseInsensitive — `query=PANIC` matches `panic: runtime error <*>`. - TestPatternSearch_ServiceAndVerdictFilters — combined AND filtering. - TestPatternSearch_RuleNameExactMatch — case-sensitive rule_name (proves we do NOT case-fold operator-authored rule names). - TestPatternSearch_OrderByCountDescDefault / LastSeenDesc — both orderings produce the expected sequence. - TestPatternSearch_LimitTruncation — count/total_matched/truncated triple is filled correctly. - TestPatternSearch_LimitClamp — 9999 clamps to 100. - TestPatternSearch_EmptyResultStillFound — list-style "no match" returns Found=true with count=0 + truncated=false. The fake catalog used by the tests is hand-rolled in the test file (no dependency on pkg/agent) so the analyze/tools package stays import-cycle-free. Docs ---- - src/agent/ai-analyze-mode.md — added pattern_search to the inline tool list. - src/agent/analyze-tools/tools.md — full per-arg reference, use-case prompts, and the relationship to pattern_history. Pre-checks: gofmt clean, go vet clean, go build clean, go test -race green on every package (the one exception is TestGitChangeFeed_RealRepo_Eino, which requires live network access to clone github.com/cloudwego/eino and fails identically on a pristine upstream/main checkout in a sandboxed environment).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a read-only tool to the analyze agent:
pattern_search. Itcomplements
pattern_history(which requires a known pattern id) byletting the model browse the learned-pattern catalog with a small
filter / sort surface.
Why this is useful
The analyze agent's catalog-side tools today:
pattern_historydescribe_serviceThat leaves no way for the model to answer questions like:
The model can't list and filter the catalog without one — today it
either asks the operator or guesses ids.
pattern_searchcloses thatgap.
Filter / sort surface
{ "query": "connection refused", // case-insensitive substring on template "service": "orders", // exact, case-insensitive "verdict": "spike", // known | unknown | spike "rule_name": "oom", // exact, case-sensitive (operator-authored ids) "order_by": "count_desc", // count_desc (default) | last_seen_desc | first_seen_desc "limit": 20 // default 20, capped at 100 }Output uses the standard
ToolResultenvelope.Foundstaystrueon zero matches (matching the convention used by
recent_incidentsand
recent_changes— the empty list is itself an answer). Theresponse carries
count,total_matched, andtruncatedso themodel knows when to narrow.
Constraints honoured
PatternCatalogvia theexisting local interface in
tools.go— no new imports, no storagemutations, no provider calls. The import-graph guard
(
TestTools_ImportGraphStaysReadOnly) passes.tools.yamlchanges — purely catalog-backed, no externalconfig required. Registered in
tools.Defaultnext topattern_history, so it's available whenever a catalog is wired —same zero-config story as the other catalog tools.
find_runbook-eraDefaultsignature (embedderTests
TestDefault_PatternSearchRegistration(registration convention fromtools_default_test.go) +TestPatternSearch_*(11 cases): metadatashape, nil catalog, bad args, invalid enums, case-insensitive
query,combined service + verdict filter, case-sensitive
rule_name, bothorderings,
limittruncation withtotal_matched/truncated,limitclamp to 100, empty result stillFound=true.A hand-rolled in-memory
fakePatternCatalogkeeps the test file freeof any
pkg/agentimport — the analyze/tools package staysimport-cycle-free.
Docs
src/agent/ai-analyze-mode.md— addedpattern_searchto theinline tool list.
src/agent/analyze-tools/tools.md— per-arg reference, use-caseprompts, and the relationship to
pattern_history.Test plan
gofmt -lcleango vet ./...cleango build ./...cleango test -race -count=1 ./...green on every package(
TestGitChangeFeed_RealRepo_Einoneeds live network to clonecloudwego/einoand fails identically on a pristineupstream/maincheckout in a sandboxed env — unrelated)