Skip to content

Angular web chat UI #149

Description

@rghvgrv

Parent

#145 — Ask Splitzy: personal spending chatbot (self-hosted LLM)

What to build

The Angular web chat UI: a service that streams SSE responses from POST /api/chat/stream, a chat component (message list, input, streaming append, loading/error/refusal states), and an entry point from the dashboard. Consumes the full contract established by #148 (history + streaming).

Implementation Steps

  1. Endpoint + types — Add CHAT_STREAM: '/api/Chat/stream' to environment.endpoints in UI/src/environments/environment.ts (and any other environment files present, e.g. environment.prod.ts). Add ChatTurn, ChatRequest, and a client-side ChatMessage (role, content, streaming flag) type to UI/src/app/splitz/splitz.model.ts.
  2. Chat service — Create UI/src/app/splitz/services/chat.service.ts following the DI/auth pattern in UI/src/app/splitz/services/splitz.service.ts. Since EventSource cannot send custom headers, use fetch() with Authorization: Bearer <token> (via SplitzService.getToken()/TokenStorageService) and read the response body with a ReadableStream reader, parsing SSE frames and emitting tokens (e.g. via an Observable or async generator) as they arrive.
  3. Chat component — Create UI/src/app/splitz/dashboard/chat/chat.component.ts / .html / .css: message list (user + assistant turns), input box, appends streamed tokens to the in-progress assistant message, loading indicator while awaiting the first token, and a distinct visual style for refusal responses vs. data answers. Maintain the trimmed turn history client-side and send it with each request per Multi-turn conversation context (stateless history) #148's contract.
  4. Entry point — Add a chat entry point (button/icon) to the dashboard (UI/src/app/splitz/dashboard/) that opens the chat component, and a route if the component is a full page rather than a widget.
  5. Manual verification — Run the Angular dev server, ask a balance question, a category-spend question, a follow-up ("and last month?"), and an out-of-scope question; confirm streaming renders token-by-token and all four response types display correctly, per this repo's practice of manually verifying UI changes in-browser before considering the work done.

Agent Routing

agent_routing:
  complexity_hint: medium
  required_capability: balanced
  parallel_safe: true
  cost_preference: balanced
  speed_preference: balanced
  ownership_scope:
    - UI/src/app/splitz/services/chat.service.ts
    - UI/src/app/splitz/dashboard/chat/
    - UI/src/app/splitz/splitz.model.ts
    - UI/src/environments/
  verification:
    - ng build (or npm run build) succeeds
    - Manual browser walkthrough: balance / category / follow-up / refusal questions

Technical Context Snapshot

Current stack in scope

  • Angular 20, standalone components, Tailwind CSS. Existing service pattern: SplitzService (UI/src/app/splitz/services/splitz.service.ts) using HttpClient + BehaviorSubject for auth state, TokenStorageService for token retrieval.
  • No existing SSE/streaming consumer in this codebase — this is the first one; base it on standard fetch + ReadableStream, no new library needed.

Dependencies in scope

  • Reuse: @angular/common/http is present but not sufficient for authenticated SSE (no header support in EventSource), so this slice uses native fetch directly, consistent with browser-standard streaming — no new npm package required.
  • New dependency additions allowed for this slice: no.

Architecture alignment

  • Follow existing services/*.service.ts + standalone component conventions already used under UI/src/app/splitz/.
  • Auth token retrieval must go through SplitzService/TokenStorageService, not a new token mechanism.
  • create-git-issue provides routing hints only; it must not assign concrete agent/model names.
  • run-with-it remains the final runtime routing authority.

Integration touchpoints

Acceptance criteria

  • User can open the chat UI from the dashboard, ask a question, and see the answer stream in token-by-token.
  • A follow-up question in the same session is sent with prior turn history and answered in context.
  • Out-of-scope questions render visibly differently from real data answers (e.g. distinct styling/copy).

Blocked by

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-agentImplementation-ready slice for an AFK/agent to pick up

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions