homelabby/.planning/phases/07-research-agent-search/07-01-SUMMARY.md

4.7 KiB

phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
07-research-agent-search 01 research-agent
research
searxng
ai-enrichment
background-worker
requires provides affects
internal/ai
internal/netbox
internal/inventory
internal/config
internal/research
internal/api/handlers/research
cmd/hwlab/main.go
internal/api/router.go
added patterns
internal/research package
interface-injection for testability
TDD red-green
background ticker worker
created modified
internal/research/searxng.go
internal/research/searxng_test.go
internal/research/agent.go
internal/research/agent_test.go
internal/api/handlers/research.go
internal/ai/client.go
internal/netbox/client.go
internal/config/config.go
internal/api/router.go
cmd/hwlab/main.go
Used interface injection (NetBoxer, TextCompleter, CatalogTransitioner) in Agent instead of concrete types to enable stub-based unit tests without live NetBox
Added TierClient.TextComplete as separate method rather than reusing AnalyzePhotos to keep vision and text paths distinct
SanitizeQuery exported (capitalised) to allow external test package verification of T-07-01 mitigation
Agent.RunOnce returns (int, error) rather than just error so callers and tests can assert enrichment count
duration_seconds completed_date tasks_completed tasks_total files_created files_modified
256 2026-04-10 2 2 5 5

Phase 07 Plan 01: SearXNG Client + ResearchAgent Summary

One-liner: SearXNG HTTP client + background ResearchAgent that polls NetBox for needs_research items, enriches via SearXNG search + Tier 2 LLM text completion, patches NetBox custom fields, and transitions status to researched every 10 minutes or on-demand via POST /api/research/trigger.

Tasks Completed

Task Name Commit Key Files
1 SearXNG client + netbox.ListDevicesWithStatus 30cd279 internal/research/searxng.go, internal/netbox/client.go, internal/config/config.go
2 ResearchAgent worker + main.go wiring + trigger endpoint 0072aa4 internal/research/agent.go, internal/api/handlers/research.go, internal/api/router.go, cmd/hwlab/main.go

Decisions Made

  1. Interface injection for Agent dependenciesNetBoxer, TextCompleter, and CatalogTransitioner interfaces in internal/research/agent.go allow stub injection in tests without a live NetBox or LLM. The concrete *netbox.Client and *ai.TierClient satisfy these interfaces automatically.

  2. TierClient.TextComplete as distinct method — Rather than forcing research prompts through AnalyzePhotos (which builds a vision multipart message), added a clean TextComplete(ctx, prompt) (string, error) method on TierClient that posts a simple single-user-message ChatCompletion. This keeps the vision and text paths separate and makes intent clear.

  3. SanitizeQuery exported — The T-07-01 threat mitigation (strip [^a-zA-Z0-9 .\-_]+ before SearXNG dispatch) is tested from the _test package, which requires the function to be exported. Consistent with the plan's explicit mention of adversarial input testing.

  4. Product URL fallback — If the LLM does not return a product_url in its JSON response, the agent falls back to the first SearXNG result URL. This ensures product_url is populated even when the LLM provides incomplete JSON.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Test expectation for sanitizeQuery with / character

  • Found during: Task 2 GREEN phase
  • Issue: Test case "Dell<script>alert(1)</script>" expected "Dell script alert 1 /script " but / is correctly stripped by the [^a-zA-Z0-9 .\-_]+ regex
  • Fix: Updated test expectation to "Dell script alert 1 script" (correct behavior)
  • Files modified: internal/research/agent_test.go
  • Commit: 0072aa4

None otherwise — plan executed as written.

Known Stubs

None. All interfaces are fully implemented. The NoOpResearchClient in internal/ai/research.go is still present but is no longer used — it has been superseded by research.SearXNGClient wired in main.go.

Threat Surface Scan

No new trust boundaries introduced beyond those documented in the plan's threat model. T-07-01 (query sanitization) is mitigated and tested. T-07-03 (trigger DoS) is mitigated — RunOnce is bounded per-item with no queuing amplification.

Self-Check: PASSED

  • internal/research/searxng.go: FOUND
  • internal/research/agent.go: FOUND
  • internal/api/handlers/research.go: FOUND
  • Commit 30cd279: FOUND
  • Commit 0072aa4: FOUND
  • go build ./...: PASSES
  • go test ./internal/research/...: 9/9 PASS