docs(06-lab-advisor-02): complete advisor backend plan
- 06-02-SUMMARY.md: SSE streaming chat, InventoryContextBuilder, 3 endpoints
This commit is contained in:
parent
0190e8583c
commit
ae34bc73fe
1 changed files with 143 additions and 0 deletions
143
.planning/phases/06-lab-advisor/06-02-SUMMARY.md
Normal file
143
.planning/phases/06-lab-advisor/06-02-SUMMARY.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
---
|
||||
phase: 06-lab-advisor
|
||||
plan: "02"
|
||||
subsystem: api
|
||||
tags: [go, sse, openrouter, claude, advisor, streaming, postgresql, chi]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 06-lab-advisor-01
|
||||
provides: store.Store, CreateConversation, AddMessage, GetConversation, ListConversations, RunMigrations
|
||||
- phase: 04-usb-events
|
||||
provides: SSE pattern (text/event-stream headers, Flush loop)
|
||||
provides:
|
||||
- POST /api/advisor/chat — SSE streaming chat backed by Claude Opus via OpenRouter
|
||||
- GET /api/advisor/conversations — list past conversations from PostgreSQL
|
||||
- GET /api/advisor/conversations/{id} — full message thread
|
||||
- InventoryContextBuilder — 60s-cached compact NetBox inventory summary for system prompt
|
||||
- Tier3 config field in AIConfig for OpenRouter lab-advisor model
|
||||
affects: [07-frontend-advisor, future-ai-tiers]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "SSE streaming via go-openai CreateChatCompletionStream + http.Flusher.Flush per token"
|
||||
- "Nil-guard in router: advisorHandler==nil returns 503 instead of panic"
|
||||
- "Stale cache on NetBox error: return cached context rather than failing the chat request"
|
||||
- "Body size guard: http.MaxBytesReader(64KB) + message truncation at 8000 chars"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- internal/advisor/context.go
|
||||
- internal/advisor/handler.go
|
||||
modified:
|
||||
- internal/ai/types.go
|
||||
- internal/config/config.go
|
||||
- internal/api/router.go
|
||||
- cmd/hwlab/main.go
|
||||
|
||||
key-decisions:
|
||||
- "Tier3 config added to AIConfig struct (not a separate config) for consistency with Tier1/Tier2"
|
||||
- "advisorHandler nil-guard in router returns 503 — graceful degradation when DB not configured"
|
||||
- "Stale InventoryContext served on NetBox error rather than failing chat — availability over freshness"
|
||||
- "HWLAB_DATABASE_URL absence is non-fatal; advisor endpoints return 503 rather than crashing server"
|
||||
|
||||
patterns-established:
|
||||
- "SSE pattern: Content-Type: text/event-stream + Cache-Control: no-cache + X-Accel-Buffering: no + Flush per write"
|
||||
- "Per-request openai.Client construction from Tier3 config allows model override without restart"
|
||||
|
||||
requirements-completed: [ADV-01, ADV-02, ADV-03, ADV-05]
|
||||
|
||||
# Metrics
|
||||
duration: 25min
|
||||
completed: 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
|
||||
|
||||
1. **Task 1: InventoryContextBuilder with 60s cache** - `7b02e67` (feat)
|
||||
2. **Task 2: AdvisorHandler SSE streaming + router wiring** - `0190e85` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `internal/advisor/context.go` - InventoryContextBuilder with 60s cache and compact NetBox summary
|
||||
- `internal/advisor/handler.go` - AdvisorHandler: StreamChat, GetConversations, GetConversation
|
||||
- `internal/ai/types.go` - Added Tier3 TierConfig field to AIConfig
|
||||
- `internal/config/config.go` - Tier3 defaults (OpenRouter, claude-opus-4, 120s timeout) + env bindings
|
||||
- `internal/api/router.go` - /api/advisor routes with nil-guard; import advisor package
|
||||
- `cmd/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.Tier3` but AIConfig only had Tier1 and Tier2 fields — handler would not compile
|
||||
- **Fix:** Added `Tier3 TierConfig` to 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
|
||||
|
||||
- `.gitignore` entry `hwlab` matched the directory `cmd/hwlab/` — `git add cmd/hwlab/main.go` failed 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*
|
||||
Loading…
Add table
Reference in a new issue