Skip to content

Claude/chat stream mechanics pq hs8#166

Open
mwcyu wants to merge 12 commits into
willchen96:mainfrom
mwcyu:claude/chat-stream-mechanics-pqHS8
Open

Claude/chat stream mechanics pq hs8#166
mwcyu wants to merge 12 commits into
willchen96:mainfrom
mwcyu:claude/chat-stream-mechanics-pqHS8

Conversation

@mwcyu
Copy link
Copy Markdown

@mwcyu mwcyu commented Jun 2, 2026

adding funcitonality

claude added 12 commits May 31, 2026 06:49
Replace the hand-rolled fetch + SSE parsing in the OpenAI adapter with the
official openai package. client.responses.create({ stream: true }) returns a
typed async-iterable of events, eliminating the manual TextDecoder/buffer and
extractSseJson machinery. Behavior, exports, and the tool-call loop are
unchanged.
The Claude, OpenAI, and Gemini adapters each re-implemented the same
agentic streaming loop (iterate to maxIterations, stream a turn,
accumulate fullText, run tools, feed results back). That triplication
let the loop logic drift between providers.

Introduce backend/src/lib/llm/driver.ts owning the loop, break
conditions, the runTools call, and the single fullText accumulation.
Each provider becomes a thin session factory (create{Claude,OpenAI,
Gemini}Session) that owns its SDK call, event parsing, follow-up
message state, and all callback firing. Public stream* signatures are
unchanged, so callers stay untouched.

Behavior is preserved: per-provider callback ordering, the OpenAI
pre-tool preamble drop, Claude's stop_reason hard-stop, Gemini's
verbatim thoughtSignature replay, and OpenAI instructions-on-iter-0.
Chat history persistence (route-level, fed by callbacks + fullText) is
unaffected. Typecheck passes.
Enable each provider's built-in, server-executed web search so the main
chat can browse the internet:
- Claude: native web_search_20250305 server tool
- OpenAI Responses: web_search built-in tool
- Gemini: googleSearch grounding tool

These run server-side (the provider performs the search and folds
results into its answer), so they bypass the runTools function-call
loop. A new enableWebSearch flag on StreamChatParams gates them; only
the interactive main chat (runLLMStream) opts in, leaving tabular
review and bulk extraction untouched.

Surface searches to the UI via a new onWebSearch callback that each
adapter fires when a search starts — Claude on the server_tool_use
contentBlock, OpenAI on the web_search_call output item, Gemini on
groundingMetadata.webSearchQueries. runLLMStream streams a web_search
event and persists it to the assistant message (unlike the transient
tool_call_start), so reloaded chats still show "Searched the web for
…". Added the web_search variant to the backend and frontend
AssistantEvent unions, a stream handler, and a WebSearchBlock renderer.

Backend and frontend typecheck clean.
Introduce a supertest-based integration suite covering user, chat,
projectChat, projects, documents, tabular, workflows and downloads
routes (77 tests). Supabase, auth, storage and the LLM/chat tooling are
mocked; streaming SSE endpoints and the signed-download token round-trip
are exercised end to end.

Refactor src/index.ts to export createApp() and only bind a port when run
directly, and skip rate limiters under NODE_ENV=test so the suite is
deterministic. Add vitest + supertest dev deps and test scripts.
…prompt

Add a free-text practice profile to user_profiles (firm positions, house
style, escalation rules) that is injected into the assistant system prompt
for the chat and project-chat routes, so ported legal workflows can rely on
the user's configured playbook instead of assuming defaults. Mirrors the
per-team CLAUDE.md profiles used by the claude-for-legal skill set.

- schema.sql + migrations/001_practice_profile.sql add user_profiles.practice_profile
- getUserPracticeProfile loader and formatPracticeProfile prompt-block helper
- GET/PATCH /user/profile expose and validate the field (20k char cap)
- tests for serialization, validation, the formatter, and the loader
Add a Practice Profile textarea to the account page (with a 20k char
counter and save state) wired through UserProfileContext.updatePracticeProfile
to PATCH /user/profile. Extend the UserProfile API/context types with the
practiceProfile field.
…flows

Add an importer (backend/scripts/import-skills.ts) that adapts Anthropic's
claude-for-legal skills (Apache-2.0) into Mike "assistant" workflows, and run
it for the commercial-legal area. It selects the user-invocable document tasks
(promoting the vendor/NDA/SaaS review playbooks that are sub-skills upstream),
drops plugin-runtime/config skills, and rewrites upstream references — the
per-team CLAUDE.md profile becomes Mike's per-user Practice Profile, external
CLM/e-sign connectors become Mike's document tools, and slash-commands point at
the corresponding workflows.

Generated catalogues (portedLegalWorkflows.ts) are merged into the backend
BUILTIN_WORKFLOWS (so read_workflow can inject them) and the frontend
BUILT_IN_WORKFLOWS (so they appear in the picker). Adds attribution in
THIRD_PARTY_NOTICES.md and tests for selection and body adaptation.
Port all nine professional practice areas from claude-for-legal (90 built-in
workflows across AI Governance, Commercial, Corporate/M&A, Employment, IP,
Litigation, Privacy, Product, Regulatory). The importer now hardens the
denylist (onboarding/customize/workspace + scheduled watchers/trackers) and
rewrites every ~/.claude working-file path — not just CLAUDE.md — to Mike's
project documents / Practice Profile. Educational/meta plugins (law-student,
legal-clinic, legal-builder-hub) are intentionally excluded.

Make the practice profile per-area: alongside the always-injected general
profile, user_profiles.practice_profiles holds an area-keyed map, and the
profile for the *active workflow's* practice area is injected with it. Adds
a canonical PRACTICE_AREAS list, resolveWorkflowPractice (built-in map +
workflows-table fallback), buildPracticeProfileBlock, GET/PATCH validation,
and a per-area editor in Account settings.

migrations/002 adds practice_profiles jsonb. Tests cover area selection,
injection, validation, and the expanded catalogue (94 passing).
Add the two educational claude-for-legal plugins as practice areas — 15 more
built-in workflows (case briefing, IRAC/Socratic drilling, flashcards, outline
building, bar prep; clinic intake, client letters, drafts, memos, research).
Bringing the catalogue to 105.

Extend the importer's denylist to drop their session/workspace-state skills
(study sessions, deadline trackers, semester handoff, supervisor queue, comms
log, guide builder) and skip skills the upstream marks DEPRECATED. Add the two
areas to the canonical PRACTICE_AREAS list (backend + frontend) and expand the
acronym map (IRAC, DPA, DSAR, PIA, FTO, OSS, AIA, Q&A).

legal-builder-hub stays excluded — it's skill-marketplace meta-tooling.
Wire the practice profile into both tabular endpoints, completing coverage
across all assistant-facing routes:

- /tabular-review/:reviewId/chat — append the profile block to the tabular
  chat system prompt.
- /tabular-review/:reviewId/generate — pass the profile into
  queryTabularAllColumns so the firm's positions inform cell flags
  (green/yellow/red) and house style during extraction.

A review's practice area is resolved from its workflow_id, so the general
profile plus the matching area profile are injected (reviewPracticeProfileBlock
helper). Adds a test asserting the profile reaches the tabular LLM call.
The assistant workflow picker now renders workflows under sticky
practice-area headers (ordered by the canonical PRACTICE_AREAS list, then
any other areas alphabetically, with untagged workflows under "Other"),
with titles sorted within each group. Makes the 100+ built-in legal
workflows navigable. Search filters within the grouping.
- Extract the duplicated load-profiles + resolve-area + build-block logic from
  the chat, project-chat, and tabular routes into one buildWorkflowPracticeBlock
  helper in userSettings; parallelize its two reads.
- Static-import builtinWorkflows in resolveWorkflowPractice instead of a
  per-call dynamic import.
- Collapse the per-field profile type/length checks in user.ts into a shared
  validateProfileText helper.
- Factor the four near-identical account save handlers into one runSave flow;
  memoize areasDirty.
- Memoize + single-pass the workflow-picker grouping (drops repeated Map.get).
- Drift-guard the importer's area labels against the canonical PRACTICE_AREAS.
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.

2 participants