feat(setbuilder): persist agent sidebar history + compact LLM context#440
Conversation
…story # Conflicts: # dashboard/app/(dj)/setbuilder/components/ChatSidebar.tsx
The null-agent-result regression test from #434 mocked the pre-history chat response shape (top-level tool_calls, no assistant_message). After merging main, the agent sidebar history contract returns an assistant_message envelope and renders readable tool summaries instead of raw JSON, so update the fixture and assertions to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds server-side persistence of per-DJ/set agent chat sessions and messages via new SQLAlchemy models and an Alembic migration. Introduces an ChangesAgent Sidebar History + Compaction
Sequence Diagram(s)sequenceDiagram
participant Browser as Browser (ChatSidebar)
participant DashboardAPI as ApiClient
participant SetbuilderAPI as FastAPI /setbuilder
participant AgentHistory as agent_history service
participant Pass2Agent as pass2_agent
participant DB as Database
rect rgba(100, 149, 237, 0.5)
note over Browser,DB: Sidebar opens — load persisted history
Browser->>DashboardAPI: getSetAgentHistory(setId)
DashboardAPI->>SetbuilderAPI: GET /sets/{set_id}/agent/history
SetbuilderAPI->>AgentHistory: get_or_create_session(set_id, user_id)
AgentHistory->>DB: query/insert SetAgentSession
SetbuilderAPI->>AgentHistory: list_messages(session)
AgentHistory->>DB: SELECT SetAgentMessage ORDER BY id
SetbuilderAPI-->>DashboardAPI: AgentChatHistoryOut (messages + metadata)
DashboardAPI-->>Browser: render persisted messages + historyMeta banner
end
rect rgba(144, 238, 144, 0.5)
note over Browser,DB: User sends a new message
Browser->>DashboardAPI: chatWithSetAgent(setId, {message})
DashboardAPI->>SetbuilderAPI: POST /sets/{set_id}/agent/chat {message}
SetbuilderAPI->>AgentHistory: context_messages(set_obj, session, message)
AgentHistory-->>SetbuilderAPI: bounded message list (context + current)
SetbuilderAPI->>AgentHistory: append_message(user, commit=False)
SetbuilderAPI->>Pass2Agent: chat_with_agent(messages=context, commit=False)
Pass2Agent->>DB: flush tool mutations (reorder/swap/remove/…)
Pass2Agent-->>SetbuilderAPI: AgentChatResult + display_summary per tool
SetbuilderAPI->>AgentHistory: append_message(assistant, commit=False)
SetbuilderAPI->>AgentHistory: compact_if_needed(session)
SetbuilderAPI->>DB: commit + refresh assistant_message
SetbuilderAPI-->>DashboardAPI: AgentChatOut + assistant_message
DashboardAPI-->>Browser: replace pending entry with assistant_message
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
dashboard/app/(dj)/setbuilder/components/ChatSidebar.tsx (1)
74-93:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winGuard against null/undefined
display_summarybefore calling.trim().If
tool.display_summaryisnullorundefined, the.trim()call on line 77 will throw aTypeError. The fallback chain suggests missing values are expected.🐛 Proposed fix
function ToolCard({ tool }: { tool: AppliedToolCall }) { const toolName = tool.name.replaceAll('_', ' '); const rationale = tool.rationale?.trim() ?? ''; - const summary = tool.display_summary.trim() || rationale || toolName; + const summary = tool.display_summary?.trim() || rationale || toolName;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dashboard/app/`(dj)/setbuilder/components/ChatSidebar.tsx around lines 74 - 93, In the ToolCard function, the `summary` constant assignment calls `.trim()` directly on `tool.display_summary` without checking if it's null or undefined first, which will throw a TypeError if the value is missing. Since the fallback chain (rationale || toolName) indicates that missing values are expected, add optional chaining before calling `.trim()` on `tool.display_summary`, similar to how it's already done for `tool.rationale?.trim()` on the line above.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@dashboard/app/`(dj)/setbuilder/components/ChatSidebar.tsx:
- Around line 74-93: In the ToolCard function, the `summary` constant assignment
calls `.trim()` directly on `tool.display_summary` without checking if it's null
or undefined first, which will throw a TypeError if the value is missing. Since
the fallback chain (rationale || toolName) indicates that missing values are
expected, add optional chaining before calling `.trim()` on
`tool.display_summary`, similar to how it's already done for
`tool.rationale?.trim()` on the line above.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1ddac495-1b17-478f-9990-f7f75c703281
📒 Files selected for processing (22)
dashboard/app/(dj)/setbuilder/components/ChatSidebar.tsxdashboard/app/(dj)/setbuilder/components/__tests__/ChatSidebar.test.tsxdashboard/app/(dj)/setbuilder/setbuilder.module.cssdashboard/lib/__tests__/api.test.tsdashboard/lib/api-types.generated.tsdashboard/lib/api-types.tsdashboard/lib/api.tsdocs/superpowers/plans/2026-06-15-agent-sidebar-history-compaction.mddocs/superpowers/specs/2026-06-15-agent-sidebar-history-compaction-design.mdserver/alembic/versions/060_add_set_agent_history.pyserver/app/api/setbuilder.pyserver/app/models/__init__.pyserver/app/models/set.pyserver/app/models/set_agent.pyserver/app/schemas/setbuilder.pyserver/app/services/setbuilder/agent_history.pyserver/app/services/setbuilder/curve.pyserver/app/services/setbuilder/pass1_deterministic.pyserver/app/services/setbuilder/pass2_agent.pyserver/openapi.jsonserver/tests/test_setbuilder_pass2.pyserver/tests/test_setbuilder_pass_api.py
Use optional chaining before .trim() on the applied tool's display_summary so a missing value falls back to rationale/tool name instead of throwing, matching the adjacent tool.rationale?.trim() handling. Addresses CodeRabbit outside-diff-range review on PR #440. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the CodeRabbit outside-diff-range comment on
Fixed in commit 6fa5d42 — |
Why
The WrzDJSet agent sidebar conversation was ephemeral — held only in React state, so a page reload wiped the whole transcript. That also meant the client resent the full history every turn and the entire transcript was fed to the LLM (a cost/scale risk called out in the WrzDJSet exec summary), while applied tool calls rendered as raw JSON noise.
What
Moves agent conversation ownership to the backend and bounds what the model sees:
SetAgentSession/SetAgentMessagemodels + migration060, scoped per DJ + set.GET .../agent/historyrehydrates the sidebar with no LLM call; chat turns are stored atomically (request + response together).display_summary(e.g. "Locked slot 1."); the sidebar renders that instead of raw JSON.Frontend
ChatSidebarloads persisted history, posts only the new message, and renders the readable summaries.Integration notes
This branch was developed before #433/#434/#435 landed and has now been merged up to current
main. The only conflict was inChatSidebar.tsx, resolved to keep both this branch's readable summaries and #434's locked-slot skip reasons /formatAgentErrorhandling. #434's null-agent-result regression test was reconciled to the new chat contract.Testing
2869 passed, coverage87.99%(gate 85%)1229 passed(89 files)tsc --noEmitall cleanalembic upgrade head(…059 → 060) +alembic check→ "No new upgrade operations detected"🤖 Co-authored by Claude (Opus 4.8). Closes #439.
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes