feat(chat): direct-chat PWA (v1) — sessions, SSE streaming, /chat app - #3
Draft
tariqismail wants to merge 23 commits into
Draft
feat(chat): direct-chat PWA (v1) — sessions, SSE streaming, /chat app#3tariqismail wants to merge 23 commits into
tariqismail wants to merge 23 commits into
Conversation
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
…gress Includes smoke-test fixes: flex min-width for text truncation, poll sequence guard against duplicate logs, back button hidden on desktop. Co-Authored-By: Claude Fable 5 <[email protected]>
…l, retry 409 follow-ups The backend writes final_response ~15s before the job flips to completed (wrap-up work). The UI previously stopped polling at the reply and kept the composer locked on 'Arqis is working' forever. Now: polling continues until a terminal status, the composer and working indicators clear as soon as the reply text exists, and follow-ups sent during wrap-up quietly retry past the API's 409 instead of failing. Co-Authored-By: Claude Fable 5 <[email protected]>
Implement data model foundation for direct-chat feature: two new Postgres tables (chat_sessions, chat_messages) via 003_chat_sessions.sql migration, plus ChatStore class wrapping raw SQL access to them. All 8 methods specified by Task 5 interface are implemented. Covered by 6 passing unit tests. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Add three new configuration knobs under agent.chat for the direct-chat fast path: model (string, empty default), max_history_messages (int, default 20), and rate_limit_per_minute (int, default 20). Environment variable overrides and documentation included. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Implements the LLM fast-path for direct chat: turns session history + new user message into a stream of reply events (delta/escalated/done/error). Makes streamed OpenRouter chat-completion calls with escalate_to_job tool. Includes full SSE parsing, tool-call accumulation across chunks, and fallback to non-streamed LlmClient on stream setup failure. Includes 11 unit tests covering plain text, split tool args, malformed JSON, SSE parsing, message building, transcript condensing, and fallback path. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Wires Tasks 1-4 (ChatStore, agent.chat config, chat_responder,
create_workspace_job source tagging) together behind three endpoints:
POST /api/chat/sessions/{session_id}/messages (streaming SSE, rate-limited,
escalates to a workspace job when chat_responder signals it), GET
/api/chat/sessions, and GET /api/chat/sessions/{session_id}/messages.
Also folds chat_messages costs into usage_cost_summary()'s lifetime/month
totals alongside task_logs and deep_research_events.
- parseSSE async generator consumes ReadableStream body and yields JSON events
- Correctly handles SSE frames split across multiple stream reads
- Skips blank/comment lines per SSE spec
- streamChatMessage POSTs to /api/chat/sessions/{sessionId}/messages
- Throws ApiError on non-2xx responses, matching existing request() pattern
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Appended listChatSessions() and getChatSessionMessages(sessionId) to agent/frontend/src/chat/api.js for listing chat sessions and fetching transcript messages. Both use the existing request() helper, matching the style of listJobs and pollJob. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Adds mergeConversations(sessions, jobs) to combine chat sessions and job threads into a unified, activity-sorted conversation list. Includes session helpers (sessionTitle, sessionProcessing, sessionSnippet, sessionStatus) mirroring job-thread accessors. Sorts by most-recent activity using each session's last_message_at or job thread's latest job created_at. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Co-Authored-By: Claude Sonnet 5 <[email protected]>
…reads
New conversations now always go through streamChatMessage (POST
/api/chat/sessions/{id}/messages) instead of the old createJob/sendFollowUp
workspace-job endpoints, which are no longer called from the UI at all.
- Unified thread list merges chat sessions and legacy job threads via
mergeConversations, sorted newest-activity-first.
- Legacy job threads (metadata.source === "workspace") render read-only:
full history + live-poll-to-terminal as before, composer replaced with a
static notice.
- Chat session messages render as plain bubbles (kind: "chat") or job turns
with progress steps + reply (kind: "job_ref"), reusing the existing
/api/jobs/{id}/poll loop.
- Single pollingJobId derivation covers both a legacy thread's active job
and a session's active job_ref, feeding one poll effect instead of two.
- Composer disables only while the latest job_ref in the active session is
still processing without a final_response (awaitingSessionReply).
- Streaming replies show token-by-token via Bubble's streaming prop while
accumulating, then settle into a persisted bubble once the transcript is
refetched.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
…take them for its own Prefix job final_response content with "[Completed by the full task pipeline]" when folding it into job_ref history rows, and tell the quick-chat model (via QUICK_CHAT_INSTRUCTIONS) to treat such prefixed turns as real completed actions rather than something it said. Fixes a live bug where the tool-less quick-chat model saw an unmarked assistant turn describing a tool outcome, concluded it had hallucinated, apologized, and needlessly re-escalated a duplicate job.
Chat already links back to Admin via its panel header — this completes the round trip so you can jump to /chat from the dashboard too. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The email interface is great for most tasks, but there are times you want to work side by side with the assistant or quickly run something by it without composing an email and waiting on the job round-trip. This adds a direct-chat fast path for exactly those moments, while leaving the email/job workflow as the path for heavier work.
Summary
Adds an optional, installable
/chatPWA with live streaming responses. Lightweight turns are answered directly; anything that needs real work escalates into the existing workspace-job pipeline and the reply folds back into the conversation.What's included
Backend (by module boundary)
chat_store.py—chat_sessions/chat_messagestables + store (migration003_chat_sessions.sql)chat_responder.py— fast-path streaming responderapi.py— SSE session/message endpoints; escalation wiring (create_workspace_jobgains asourcetag,create_manual_joban optionalthread_id) so job replies fold back into chat contextconfig.py/config/agent.yaml—agent.chatconfig block (documented indocs/env-overrides.md)Frontend (
agent/frontend/src/chat/, second Vite entry)/chatapp: thread grouping, conversation view, composer, live progress, streaming cursor, markdown rendering, design tokensScope — this is v1
Deliberately kept focused. Known gaps, likely follow-ups:
Tests
test_config/test_ui_pagesadditions — 51 passed viapytest.--testsuite (stream,threads) — 18 passed.npm run build(vite) builds cleanly.Notes
/chatroute + admin link.chat.bundle.*are gitignored and not included (mirrors the existingworkspace.bundle.jsconvention).