- 06-02-SUMMARY.md: SSE streaming chat, InventoryContextBuilder, 3 endpoints
7.1 KiB
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 06-lab-advisor | 02 | api |
|
|
|
|
|
|
|
|
|
25min | 2026-04-10 |
Phase 06 Plan 02: Lab Advisor Backend Summary
SSE streaming advisor chat backed by Claude Opus via OpenRouter, with 60s-cached NetBox inventory context injected into every system prompt and full PostgreSQL persistence of conversations and messages.
Performance
- Duration: 25 min
- Started: 2026-04-10T07:11:00Z
- Completed: 2026-04-10T07:36:19Z
- Tasks: 2
- Files modified: 6 (2 created, 4 modified)
Accomplishments
- InventoryContextBuilder: fetches up to 200 devices from NetBox, builds a compact text summary (total count, category breakdown, recent 20 items), caches 60s under sync.Mutex, falls back to stale cache on NetBox error
- AdvisorHandler: StreamChat streams tokens from OpenRouter via go-openai CreateChatCompletionStream; each token delivered as
data: {"conversation_id":"...","token":"..."}SSE event; body limited to 64KB, message truncated to 8000 chars; API key never echoed - Full persistence: CreateConversation + AddMessage(user) before stream; AddMessage(assistant) after stream completes
- Three endpoints registered under /api/advisor/ with nil-guard for DB-unavailable graceful degradation
- Tier3 TierConfig added to AIConfig with HWLAB_AI_TIER3_* env bindings and OpenRouter/claude-opus-4 defaults
Task Commits
- Task 1: InventoryContextBuilder with 60s cache -
7b02e67(feat) - Task 2: AdvisorHandler SSE streaming + router wiring -
0190e85(feat)
Files Created/Modified
internal/advisor/context.go- InventoryContextBuilder with 60s cache and compact NetBox summaryinternal/advisor/handler.go- AdvisorHandler: StreamChat, GetConversations, GetConversationinternal/ai/types.go- Added Tier3 TierConfig field to AIConfiginternal/config/config.go- Tier3 defaults (OpenRouter, claude-opus-4, 120s timeout) + env bindingsinternal/api/router.go- /api/advisor routes with nil-guard; import advisor packagecmd/hwlab/main.go- Store init from HWLAB_DATABASE_URL, RunMigrations, AdvisorHandler wired
Decisions Made
- Tier3 config follows the same TierConfig struct as Tier1/Tier2 — no special advisor config type needed
- Per-request openai.Client construction (not cached) allows model field in ChatRequest to override model without server restart, satisfying ADV-05
- advisorHandler is nil when HWLAB_DATABASE_URL is absent; router nil-guard returns 503 on all three endpoints rather than panicking
- Stale inventory context returned on NetBox error (availability over freshness — homelab context)
Deviations from Plan
Auto-fixed Issues
1. [Rule 2 - Missing Critical] Added Tier3 to AIConfig struct
- Found during: Task 2 (AdvisorHandler implementation)
- Issue: Plan referenced
aiCfg.Tier3but AIConfig only had Tier1 and Tier2 fields — handler would not compile - Fix: Added
Tier3 TierConfigto AIConfig in internal/ai/types.go; added defaults and env bindings in config.go - Files modified: internal/ai/types.go, internal/config/config.go
- Verification: go build ./... passes; Tier3 config loads from HWLAB_AI_TIER3_* env vars
- Committed in:
0190e85(Task 2 commit)
2. [Rule 2 - Missing Critical] Nil-guard in router for missing DB
- Found during: Task 2 (router wiring)
- Issue: advisorHandler can be nil when HWLAB_DATABASE_URL is not set; registering nil method handlers would panic at request time
- Fix: Added nil check in router; returns 503 with descriptive message when advisor is disabled
- Files modified: internal/api/router.go
- Verification: go build ./... passes; server starts without DB configured
- Committed in:
0190e85(Task 2 commit)
Total deviations: 2 auto-fixed (2 missing critical) Impact on plan: Both fixes required for correctness and safe server startup. No scope creep.
Issues Encountered
.gitignoreentryhwlabmatched the directorycmd/hwlab/—git add cmd/hwlab/main.gofailed with "ignored file" warning. The file was already staged from a prior add, so commit proceeded normally. The gitignore entry targets the compiled binary, not the source directory; no fix needed.
Known Stubs
None — all three endpoints are fully wired. StreamChat requires HWLAB_AI_TIER3_API_KEY to be set with a valid OpenRouter key for actual AI responses; without it, OpenRouter returns 401 which is surfaced as a 502 to the client. This is expected behavior for a homelab tool.
Threat Flags
No new threat surface beyond what the plan's threat model covers. All mitigations from T-06-02-01 through T-06-02-03 are implemented (parameterized store calls, API key isolation, 64KB/8000-char input guards).
Next Phase Readiness
- All three /api/advisor/* endpoints ready for frontend integration
- Set HWLAB_DATABASE_URL + HWLAB_AI_TIER3_API_KEY to enable advisor
- Frontend advisor chat UI (Phase 07 or equivalent) can connect to POST /api/advisor/chat and consume the SSE token stream
Phase: 06-lab-advisor Completed: 2026-04-10