Skip to content

refactor(api): extract shared session and message helpers for chat routers - #1072

Merged
lfnovo merged 3 commits into
mainfrom
refactor/chat-session-helpers
Jul 11, 2026
Merged

refactor(api): extract shared session and message helpers for chat routers#1072
lfnovo merged 3 commits into
mainfrom
refactor/chat-session-helpers

Conversation

@lfnovo

@lfnovo lfnovo commented Jul 11, 2026

Copy link
Copy Markdown
Owner

What

api/routers/chat.py and api/routers/source_chat.py were heavy copy-paste of each other. This extracts the shared pieces into a new api/routers/_chat_shared.py and replaces every duplicated site in both routers. No behavior change — same status codes, same response shapes, same error messages (including the known missing-relation-becomes-500 quirk, deliberately preserved as-is for a later error-handling PR).

What was deduplicated

  • normalize_record_id(table, id) — the x if x.startswith("table:") else f"table:{x}" idiom, previously inlined 12 times across both routers (including twice in the same handler: get_session and update_session recomputed full_session_id identically)
  • get_session_or_404 / get_source_or_404 / get_verified_source_session — the "verify source exists → normalize session id → fetch session → verify refers_to relation" block, copy-pasted 4 times in full and 2 times partially in source_chat.py, plus the session-fetch variant repeated 4 times in chat.py
  • extract_chat_messages — the LangGraph state → ChatMessage conversion loop, written 3 times (2× chat, 1× source_chat; the SSE streaming loop has a different output shape and was left alone)
  • ChatMessage and SuccessResponse pydantic models — previously defined twice, now a single definition

Tests-first approach

Since this is a delicate refactor, characterization tests were written first (commit 1) and run green against the unchanged code, then the extraction (commit 2) was verified against them:

  • ID normalization edge cases (bare id vs already-prefixed id, for both routers)
  • Missing source / missing session → 404 with the exact existing detail strings
  • Missing refers_to relation → existing behavior pinned as-is: 500 wrapping the inner 404 on get/delete, real 404 on send-message (which re-raises HTTPException)
  • Message extraction shapes, including the type/content/positional-id fallbacks and the empty-state path

The only test change in commit 2 is repointing mock patch targets to the new module.

Line delta

+156 / −265 in the refactor commit: the two routers shed 250 lines (chat.py −92, source_chat.py −158) for 94 lines of shared module.

Verification

  • uv run pytest tests/ — 415 passed (403 baseline + 12 new)
  • ruff check . — clean
  • mypy — 197 errors before and after (the 4 pre-existing errors in these two files are unchanged; none in the new module)

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Confidence score: 5/5

  • Safe to merge after the addressed issues were fixed.

You’re at about 96% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread api/routers/source_chat.py Outdated
lfnovo added 3 commits July 11, 2026 18:57
The session handlers only need the verified session; the source-level
verification happens inside get_verified_source_session. Underscore the
unused binding in get/update/delete to make that explicit.
@lfnovo
lfnovo force-pushed the refactor/chat-session-helpers branch from 7053b0f to 233102e Compare July 11, 2026 21:57
@lfnovo

lfnovo commented Jul 11, 2026

Copy link
Copy Markdown
Owner Author

Fixed in 233102e: the three session handlers (get/update/delete) now unpack _full_source_id, making explicit that only the verified session is needed there — the source-level verification happens inside get_verified_source_session() itself, so there was no enforcement gap. send_message keeps using full_source_id (it passes it to the graph).

@lfnovo
lfnovo merged commit fc03cf3 into main Jul 11, 2026
10 checks passed
@lfnovo
lfnovo deleted the refactor/chat-session-helpers branch September 2, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant