fix(api): invalidate analytics cache on MCP conversation writes - #415
fix(api): invalidate analytics cache on MCP conversation writes#415duyetbot wants to merge 2 commits into
Conversation
MCP store_conversation writes the same conversations/messages tables as REST but skipped the invalidateAnalyticsCache() helper added in #370. Dashboard analytics could stay stale for the full cache TTL. Call the helper from mcp-conversations create/delete, matching REST, and cover the live MCP write path in the existing analytics suite. Closes #372 Co-Authored-By: Duyet Le <me@duyet.net> Co-Authored-By: duyetbot <bot@duyet.net>
Reviewer's GuideThis PR ensures MCP conversation writes invalidate the analytics cache just like REST, by threading execution context and cache into the MCP tools and wiring invalidateAnalyticsCache into the MCP conversations service, plus a regression test to guard against stale analytics after MCP store_conversation. Sequence diagram for MCP store_conversation analytics cache invalidationsequenceDiagram
actor MCPClient
participant StoreConversationTool as store_conversation_tool
participant ConversationsService as conversationsService
participant AnalyticsCache as AUTH_CACHE
MCPClient->>StoreConversationTool: invoke handler
StoreConversationTool->>ConversationsService: createConversation(db, input, executionCtx, AUTH_CACHE)
ConversationsService->>ConversationsService: insert conversations
ConversationsService->>ConversationsService: insert messages
ConversationsService->>AnalyticsCache: invalidateAnalyticsCache(AUTH_CACHE, executionCtx, projectId)
ConversationsService-->>StoreConversationTool: CreateConversationResult
StoreConversationTool-->>MCPClient: conversation id, project_id
File-Level Changes
Assessment against linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Review limit reached
Next review available in: 113 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The new
createConversation/deleteConversationsignatures inmcp-conversationsaddexecutionCtxandcacheparameters; consider either providing sensible defaults or a backwards-compatible wrapper to avoid breaking existing internal callers. - The analytics test for MCP
store_conversationhardcodes the expected token delta (10); making the assertion derive from thetoken_countvalues in the test input would make it less brittle if message/token handling changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `createConversation`/`deleteConversation` signatures in `mcp-conversations` add `executionCtx` and `cache` parameters; consider either providing sensible defaults or a backwards-compatible wrapper to avoid breaking existing internal callers.
- The analytics test for MCP `store_conversation` hardcodes the expected token delta (10); making the assertion derive from the `token_count` values in the test input would make it less brittle if message/token handling changes.
## Individual Comments
### Comment 1
<location path="packages/api/test/analytics.test.ts" line_range="206" />
<code_context>
+
+ expect(after.summary.total_conversations).toBe(baseConvs + 1);
+ expect(after.summary.total_messages).toBe(baseMsgs + 2);
+ expect(after.summary.total_tokens).toBe(baseTokens + 10);
+ });
+
</code_context>
<issue_to_address>
**suggestion (testing):** Derive the expected token delta from the request payload instead of hardcoding `10`.
This test couples the assertion to the current payload by hardcoding `10` as the token delta. Instead, derive the expected delta from the `messages` array (e.g., sum their `token_count` values) and assert against `baseTokens + expectedTokenDelta`. That keeps the test validating that analytics mirror the stored conversation while remaining resilient to future changes in message content or token-counting logic.
Suggested implementation:
```typescript
expect(after.summary.total_conversations).toBe(baseConvs + 1);
expect(after.summary.total_messages).toBe(baseMsgs + 2);
const expectedTokenDelta = messages.reduce(
(sum, message) => sum + (message.token_count ?? 0),
0,
);
expect(after.summary.total_tokens).toBe(baseTokens + expectedTokenDelta);
```
The above edit assumes there is a `messages` array in scope corresponding to the request payload used in the `store` call (each element having a `token_count` field). You may need to:
1. Ensure the `messages` variable is defined in this test and matches the structure sent in the POST body (e.g., extracted or reused from the payload object).
2. Adjust the reducer if the shape is different (for example, `message.token_count` might live under `message.metadata.token_count` or similar).
3. If the request payload is not directly accessible here, derive `messages` from whatever object you use to construct the POST body, and place its definition above these expectations within the same `it` block.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Address Sourcery review on the #372 cache-invalidation test. Co-Authored-By: Duyet Le <me@duyet.net> Co-Authored-By: duyetbot <bot@duyet.net>
Summary
MCP
store_conversationwrites the sameconversations/messagestables as REST but skippedinvalidateAnalyticsCache(). Dashboard analytics could stay stale for the full cache TTL (60–300s).mcp-conversationscreate/delete, matching REST#370c.executionCtxandc.env.AUTH_CACHEfrom the MCPstore_conversationtoolCloses #372
Test plan
cd packages/api && bunx vitest run test/analytics.test.ts test/mcp.test.ts(20 passed)Summary by Sourcery
Invalidate analytics cache when MCP conversations are created or deleted to keep dashboard metrics in sync with MCP writes.
Bug Fixes:
Enhancements:
Tests: