feat: Add real-time autocorrect updates via SSE#1071
feat: Add real-time autocorrect updates via SSE#1071KijtIlHijrow wants to merge 17 commits intoblinkospace:mainfrom
Conversation
Implemented manual tool execution to bypass Mastra's validation errors when using Ollama models (qwen2.5, llama3.2) with function calling. Changes: - Added error handling in AI post-processing to catch validation failures - Parse tool calls from Ollama's raw response body - Manually execute updateBlinkoTool when Mastra validation fails - Added debug logging for troubleshooting AI processing issues - Removed unused advancedFormat plugin from dayjs configuration This allows Ollama models to successfully edit blinkos directly via AI post-processing in custom mode, working around incompatibilities between Ollama's response format and Mastra's Zod validation.
Switched from unreliable function calling to text-only AI responses for autocorrection. AI now returns corrected text which is manually passed to upsertBlinkoTool, ensuring consistent capitalisation and grammar fixes regardless of model's function calling capability.
Add Server-Sent Events architecture to push note updates when AI autocorrection completes, eliminating manual refresh requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Prepare for git worktree usage to isolate feature development. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Connection management with max limit per user - Broadcast functionality for events - Heartbeat to detect dead connections - Helper method for note update events 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add cleanup() method to close all connections on shutdown - Register SIGTERM/SIGINT handlers for graceful exit - Use connectedAt timestamp to find truly oldest connection - Prevents memory leaks and ensures deterministic behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- /api/sse/connect endpoint for client connections - /api/sse/stats endpoint for monitoring connection stats - Authentication check before connection using existing getTokenFromRequest helper - Proper SSE headers with nginx buffering disabled - Client disconnect handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use req.ctx.id from middleware instead of custom auth - Remove try-catch blocks as not in spec - Match exact type annotations and imports - Simplify to match planned implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use getTokenFromRequest() matching codebase pattern - Restore error handling in both endpoints - Add authentication to /sse/stats endpoint - Fix type safety for userId (convert to Number) - Previous "spec fix" used non-existent req.ctx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Emit note-updated event when custom processing completes - Graceful error handling for SSE failures 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Skip SSE broadcast if note has no accountId - Prevents broadcasting to wrong user (userId=0) - Add warning log for skipped broadcasts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Auto-reconnection with exponential backoff - Event emission to eventBus for loose coupling - Toast notifications for connection status - Heartbeat handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Check reconnect attempts before resetting to zero - Allows toast to display when connection is restored - Fixed logic bug from original spec 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Listen for note-updated events from eventBus - Refetch and update notes in list view - Update currently selected note - Toast notification on auto-update 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Call useSseConnection hook on app mount - Completes real-time autocorrect update feature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add connection-restored translation - Add connection-lost translation - Add note-auto-updated translation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- 18 comprehensive test cases - Covers functionality, edge cases, performance - Ready for manual testing verification 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Thank you very much for your contribution to this project! During my local testing, I encountered two issues that prevent the new features from working properly:
Thanks again for your efforts! |
blinko-space
left a comment
There was a problem hiding this comment.
Review: Needs rebase + scope split before deep review 🔄
This PR has merge conflicts with main (mergeable: CONFLICTING, mergeStateStatus: DIRTY), so I'm holding the runtime/code review until that's resolved. A few things to address before re-requesting review:
Please rebase first
Conflicts exist with main. Until those are resolved I can't reliably check whether the SSE wiring still composes with what's been merged since you opened this PR. Please rebase onto current main and force-push.
Scope creep — please split into multiple PRs
The PR title says "real-time autocorrect updates via SSE" but the diff touches 35 files including several that have nothing to do with SSE:
.gitignore— drive-bydockerfile— infra change unrelated to SSEdocker-compose.dev.yml— sameapp/src/lib/dayjs.tsandshared/lib/dayjs.ts— what does dayjs have to do with SSE? If this is a dependency cleanup, it belongs in its own PRserver/aiServer/providers/LLMProvider.ts— please justify how this relates to the SSE featureserver/aiServer/tools/createBlinko.ts— same question
The 16 locale files + the actual SSE code (sseService.ts, sse.ts, useSseConnection.ts, blinkoStore.tsx, App.tsx, aiServer/index.ts, routerTrpc/note.ts, server/index.ts) are clearly in scope. The rest should be moved out.
Smaller, focused PRs are much easier to review and roll back if needed. Suggested split:
- PR A (this one, after pruning): SSE infrastructure + autocorrect integration + i18n keys
- PR B: Dockerfile / docker-compose changes
- PR C: dayjs refactor
- PR D: Anything else that's unrelated cleanup
Build is broken
The PR body says:
Build tests currently fail in both main and feature branch due to pre-existing esbuild configuration issue (unrelated to this PR).
If the build is failing on main, that's a separate issue we should track and fix first — please open an issue for it. But also: how was this PR validated end-to-end if the build doesn't pass? The manual test plan references a working binary; please clarify how those tests were actually executed.
What I will check on the next round
Once the PR is rebased + scope-pruned, I'll do a deep review of:
- SSE service: connection accounting (max 5 per user), heartbeat correctness, graceful shutdown, memory leak risk
- Auth on
/api/sse/connect(token must be validated; no anonymous connections) - Cross-user isolation (broadcast routing must not leak between users)
- Reconnection backoff: bounds, jitter, give-up condition
- Integration with
aiServer/postProcessNote— error isolation as claimed - Frontend hook lifecycle (cleanup on unmount, no double-subscribe under StrictMode)
- i18n keys consistency across all 16 locales
Looking forward to the rebased version. 👍
Summary
Adds Server-Sent Events (SSE) infrastructure to push note updates when AI autocorrection completes, eliminating the need for manual refresh.
Key Changes:
/api/sse/connect,/api/sse/stats)Architecture
postProcessNotebroadcasts via SSE when autocorrection completesImplementation Details
Backend (Tasks 1-3):
server/lib/sseService.ts- Core SSE service with graceful shutdownserver/routerExpress/sse.ts- SSE endpoints with authenticationserver/aiServer/index.ts- Broadcast integration with error isolationFrontend (Tasks 4-6):
app/src/lib/useSseConnection.ts- React hook with auto-reconnectionapp/src/store/blinkoStore.tsx- Event handler for note updatesapp/src/App.tsx- Hook integration on app mountLocalization (Task 7):
Documentation (Task 8):
docs/plans/2026-01-07-realtime-autocorrect-updates-design.md- Design documentdocs/plans/2026-01-07-realtime-autocorrect-updates.md- Implementation plandocs/testing/sse-manual-tests.md- 18 comprehensive test casesTest Plan
Note: Build tests currently fail in both main and feature branch due to pre-existing esbuild configuration issue (unrelated to this PR).
Manual testing required per
docs/testing/sse-manual-tests.md:Breaking Changes
None - this is a purely additive feature.
Commits
Related Issues
Fixes real-time update requirement for autocorrection feature.
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com