Skip to content

feat: Ask Quantic — always-present AI chat (+ informational AI framing, radar sort)#109

Merged
fleveque merged 8 commits into
mainfrom
feat/ai-portfolio-chat
Jun 19, 2026
Merged

feat: Ask Quantic — always-present AI chat (+ informational AI framing, radar sort)#109
fleveque merged 8 commits into
mainfrom
feat/ai-portfolio-chat

Conversation

@fleveque

@fleveque fleveque commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Ask Quantic — an always-present AI chat

Adds a conversational AI assistant that's present on every signed-in page and answers natural-language questions about the user's portfolio, radar, and dividends. It reuses the existing chat engine (Quantic.AI.chat_as/3 + the seven scoped tools the Telegram bot already uses) — no new AI infrastructure, no new runtime. Plain Elixir/Phoenix.

What it does

  • Always present — a floating widget mounted once in Layouts.app as a sticky nested LiveView, so the conversation survives navigation between pages.
  • Persistent — open state + conversation are mirrored to localStorage, so they also survive a refresh or a cross-live_session navigation.
  • Page-aware — a handle_params on_mount hook (QuanticWeb.AskContext) broadcasts the current page over PubSub so answers can bias to what you're looking at.
  • Stock logos — each answer renders <.stock_logo> chips for the stocks it referenced, using the model's actual tool_calls (not a regex on prose).
  • Brand-emerald styling matching the logo gradient, with a subtle attention pulse.
  • Seven languages.

Safety & cost

  • Informational, not advice — the chat, the per-stock AI Summary, and the portfolio/radar insights describe stocks on dividend criteria (yield, payout ratio, P/E, MA200, 52-week position) but never give a buy/sell verdict, a "good/bad buy" rating, or a "buying opportunities" list — matching the app's own footer disclaimer ("not a recommendation to buy or sell any security"). An in-widget "not financial advice" note is shown.
  • Demo accounts never spend money — they get a canned reply instead of a provider call.
  • No-cost failures don't burn quota — a pre-flight failure (e.g. missing API key) that never reached the provider no longer counts against the daily limit; real calls still do.
  • Daily limit raised 3 → 5 (config-overridable; test env pinned to 3 for deterministic rate-limit tests).

Also in here

  • refactor(ai) — moved the seven tools out of the Telegram namespace to Quantic.AI.PortfolioTools (shared by both front doors) and added payout_ratio to the tool context.
  • feat(radar) — aligned the radar toolbar with the portfolio page and added a persisted sort select (Opportunity / Symbol / Dividend yield / Dividend score).

Commits

  1. refactor(ai): move chat tools to Quantic.AI.PortfolioTools
  2. feat(ai): always-present Ask Quantic chat widget
  3. refactor(ai): make the per-stock AI summary informational
  4. feat(ai): don't charge quota for no-cost failures; raise daily limit to 5
  5. feat(radar): match the portfolio toolbar + add a sort select
  6. feat(ai): show logo chips for stocks an answer references
  7. refactor(ai): reframe insights "Buying opportunities" as neutral observations
  8. docs: document the Ask Quantic chat widget + informational AI framing

Testing

mix precommit green — 415 tests pass (compile warnings-as-errors, format, full suite). New AskLiveTest covers mount/availability, happy path, rate-limit, provider failure, multi-turn, persistence/restore, demo canned reply (no provider call), and logo chips.

🤖 Generated with Claude Code

fleveque and others added 8 commits June 19, 2026 21:00
The seven scoped portfolio tools have no Telegram coupling but lived in
the Telegram namespace. Move them to Quantic.AI.PortfolioTools so both
the Telegram bot and the (incoming) web chat widget can share them, and
add payout_ratio to the tool quote context — the key dividend
sustainability signal the per-stock summary already uses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A sticky nested LiveView mounted once in Layouts.app, so a conversational
assistant is present on every signed-in page and its conversation
survives navigation. Reuses Quantic.AI.chat_as/3 + PortfolioTools (the
same engine as the Telegram bot) — no new AI infrastructure.

- Persists open state + conversation to localStorage (survives refresh
  and cross-session navigation).
- Page-aware via a handle_params on_mount hook (QuanticWeb.AskContext).
- Brand-emerald styling matching the logo gradient; attention pulse.
- Demo accounts get a canned reply — never a paid provider call.
- Informational framing only: describes a stock on dividend criteria,
  never a buy/sell recommendation, with an in-widget 'not financial
  advice' note. Seven languages.
- HomePage showcase card + README/architecture docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the strong_buy→avoid verdict from stock_summary (schema, prompt,
system message, and the badge component + its now-dead helpers). Aligns
the feature with the app's own footer disclaimer ('not a recommendation
to buy or sell any security') and with the chat widget's informational
framing — present the data and trade-offs, let the user decide.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…to 5

A failure that never reached the provider (e.g. a missing API key) spent
no money, so it no longer counts against the user's daily quota; real
provider calls — success or provider-side error — still count. Also bump
the default daily limit 3 → 5 (the test env is pinned to 3 so the
rate-limit tests stay deterministic, independent of the prod default).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the radar controls (AI insights, public page, view toggle) out of
the title row into a controls row below the search, matching the
portfolio page, and add a persisted sort select — Opportunity (default),
Symbol, Dividend yield, Dividend score — reusing the shared sort_select
component. Also wires the Ask Quantic widget onto the radar page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Under each chat answer, render <.stock_logo> chips for the stocks it
mentions. The symbol set comes from the model's actual tool calls
(ChatResult.tool_calls) — what the tools really returned — then narrowed
to tickers present in the reply text. Reliable by construction: no
regex-guessing tickers out of prose (which misfires on AI/EU/USD).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rvations

The portfolio/radar AI insights presented a directive 'Buying
opportunities' section, which reads as a buy recommendation — the same
issue the per-stock verdict removal addressed, and a contradiction of
the app's 'not a recommendation to buy or sell' disclaimer. Rename the
schema field buyingOpportunities -> observations (reason -> note),
reword the prompts to describe what's notable without recommending a
buy, drop the 'actionable' framing from the analyst system prompt, and
relabel the UI section 'Worth noting' (neutral colour). Seven locales.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Promote Ask Quantic to its own README feature; correct the architecture
AI section (5/day quota, record-on-real-call, demo no-provider, the
not-financial-advice-by-construction stance, localStorage persistence,
and tool-call-derived logo chips).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@fleveque fleveque merged commit 0d7e8ed into main Jun 19, 2026
1 check passed
@fleveque fleveque deleted the feat/ai-portfolio-chat branch June 19, 2026 19:17
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