Skip to content

Category/overall spend + transaction-count intents #147

Description

@rghvgrv

Parent

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

What to build

Extend the chat router and query layer from #146 with three more fixed intents: category spend totals, overall spend totals, and transaction counts — each distinguishing "my share of the split" from "what I paid". Adds the grocery/groceries → ExpenseCategory.Food synonym mapping the router uses to resolve informal category words.

Implementation Steps

  1. Router prompt update — Extend the router prompt (backend/splitzy-dotnet/Services/Chat/Prompts/) and RouterResult intent enum from Chat foundation: streaming balance intent + router skeleton #146 with CategoryTotal, OverallTotal, TransactionCount, each carrying params { Metric: share|paid, Category?, From, To }. Add a category synonym map to the prompt (e.g. "grocery"/"groceries" → Food) covering the existing ExpenseCategory enum values in backend/splitzy-dotnet/Models/Expense.cs. [HITL]: confirm the grocery→Food mapping with product — flag it as a comment in the prompt template so it's easy to change later.
  2. Category total query — Add Task<decimal> CategoryTotal(int userId, SpendMetric metric, ExpenseCategory category, DateTime from, DateTime to) to IChatQueryService/ChatQueryService (backend/splitzy-dotnet/Services/Chat/). share sums ExpenseSplit.OwedAmount where UserId = userId joined to Expense.Category; paid sums Expense.Amount where PaidByUserId = userId and Category matches. Both filter Expense.CreatedAt within [from, to].
  3. Overall total + transaction count queries — Add Task<decimal> OverallTotal(int userId, SpendMetric metric, DateTime from, DateTime to) (same share/paid distinction, no category filter) and Task<int> TransactionCount(int userId, ExpenseCategory? category, DateTime from, DateTime to) to the same service.
  4. Orchestrator dispatch — Update ChatOrchestrator.AskAsync (from Chat foundation: streaming balance intent + router skeleton #146) to dispatch the three new intents to the corresponding ChatQueryService methods before synthesis.
  5. Tests — Extend backend/spllitzy-dotnet-tests/ChatControllerTests.cs (or a new ChatQueryServiceTests.cs following the same NUnit + TestHelper.CreateTestContext() pattern): category total correctness for both share and paid metrics against seeded fixture data, overall total correctness, transaction count correctness, and a router test proving "how much did I spend on groceries" resolves to CategoryTotal with Category = Food.

Agent Routing

agent_routing:
  complexity_hint: medium
  required_capability: balanced
  parallel_safe: false
  cost_preference: balanced
  speed_preference: balanced
  ownership_scope:
    - backend/splitzy-dotnet/Services/Chat/
    - backend/spllitzy-dotnet-tests/
  verification:
    - dotnet test backend/spllitzy-dotnet-tests
    - Manual Swagger call: "how much did I spend on groceries this month" and "how much have I paid overall this year"

Technical Context Snapshot

Current stack in scope

  • Same backend stack as Chat foundation: streaming balance intent + router skeleton #146 (ASP.NET Core 8, EF Core 8 + Npgsql). This slice is additive to the Services/Chat/ module created there — no new infrastructure.
  • Reuses ExpenseCategory enum (backend/splitzy-dotnet/Models/Expense.cs), ExpenseSplit.OwedAmount, Expense.Amount/Expense.PaidByUserId/Expense.CreatedAt.

Dependencies in scope

  • Reuse only: EF Core LINQ querying, no new packages.
  • New dependency additions allowed for this slice: no.

Architecture alignment

  • Extends IChatQueryService/ChatQueryService and the router/orchestrator from Chat foundation: streaming balance intent + router skeleton #146 rather than introducing parallel structures.
  • userId continues to be resolved server-side only, never taken from router/LLM output.
  • 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

  • "How much did I spend on groceries this month" returns the correct Food-category share total for the authenticated user.
  • "How much have I paid overall this year" returns the correct paid-total (not share-total) figure.
  • Transaction count queries return the correct count for a given category/date range.

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