Skip to content

feat(market): surface an LLM news-sentiment sub-score on stock analysis - #5656

Open
dyrach1o wants to merge 2 commits into
koala73:mainfrom
dyrach1o:feat/analyze-stock-news-sentiment
Open

feat(market): surface an LLM news-sentiment sub-score on stock analysis#5656
dyrach1o wants to merge 2 commits into
koala73:mainfrom
dyrach1o:feat/analyze-stock-news-sentiment

Conversation

@dyrach1o

Copy link
Copy Markdown
Contributor

Summary

The analyze-stock overlay model already reads the pulled news headlines but
only emits prose. This asks it for one extra JSON key — a signed
newsSentiment in [-1, 1] — in the same strict-JSON overlay call:

  • No extra LLM request, no new dependency, no external quota. The score
    comes from the headlines the overlay already receives.
  • Normalized server-side (clamp to [-1, 1], round to 2dp) via an exported
    pure normalizeNewsSentiment helper, then surfaced as optional
    AnalyzeStockResponse field 69.
  • Omitted when the analysis falls back to the deterministic rules overlay
    (no LLM), so the field only appears when a real sentiment reading exists.
  • Renders as a conditional "News" tile in the stock-analysis panel's stat
    grid (only when present).

Deliberately scoped: the score is not blended into the rating/composite
score (that is the concurrent fundamentals-blend PR's surface), and no news
corpus index is built — this is a self-contained additive signal.

Field 69 avoids a field-number collision with the in-flight rating-blend
PR (claims 61-62) and risk-analytics PR (claims 66-68); 63-65 are the merged
earnings join.

Type of change

  • New feature

Affected areas

  • Market Radar / Crypto
  • AI Insights / World Brief
  • API endpoints (/api/*)

Checklist

  • Tested on worldmonitor.app variant
  • Tested on tech.worldmonitor.app variant (if applicable)
  • New RSS feed domains added to api/rss-proxy.js allowlist (if adding feeds)
  • No API keys or secrets committed
  • TypeScript compiles without errors (npm run typecheck)

Also verified: npm run typecheck:api, npx biome lint on changed files, and
the stock-analysis test suite (24/24, including 7 new cases: the mocked-LLM
flow, prompt-instruction assertion, response present/omit mapping, and the
normalizeNewsSentiment round/clamp/undefined cases).

Documentation Alignment Checklist

  • Generated docs regenerated from proto where applicable (make generate — OpenAPI + client/server stubs)
  • Claim ledger attached or linked — N/A (no methodology/claim changes)
  • All required Audit Council role signoffs attached — N/A
  • Fixture-backed examples recomputed — N/A (OpenAPI examples auto-regenerated by make generate)
  • Redis writers/readers enumerated for every documented key — N/A (no Redis keys touched)

The analyze-stock overlay model already reads the pulled headlines but only
emits prose. Ask it for one extra key — a signed newsSentiment in [-1, 1] —
in the same strict-JSON call, so there is no extra LLM request, no new
dependency, and no external quota. Normalize (clamp + round) and surface it
as optional AnalyzeStockResponse field 69, plus a "News" tile in the panel.

Omitted when the analysis falls back to the deterministic rules overlay
(no LLM). Field 69 avoids a collision with the in-flight rating-blend
(61-62) and risk-analytics (66-68) PRs.
@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

@dyrach1o is attempting to deploy a commit to the World Monitor Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the trust:safe Brin: contributor trust score safe label Jul 26, 2026
@greptile-apps

greptile-apps Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds an optional LLM-derived news-sentiment score to stock analysis.

  • Extends the protobuf response contract and regenerates TypeScript and OpenAPI artifacts.
  • Normalizes the model score to a rounded value in [-1, 1].
  • Conditionally renders the score as a News tile in the stock-analysis panel.
  • Adds unit coverage for normalization, response mapping, and the mocked LLM flow.

Confidence Score: 3/5

The PR should not merge until analyses without headlines stop surfacing a synthetic neutral News reading.

The LLM is invoked with an empty headline list when news is disabled or unavailable, and the new prompt, normalization, response mapping, and UI collectively turn that absence into a visible neutral score.

Files Needing Attention: server/worldmonitor/market/v1/analyze-stock.ts

Important Files Changed

Filename Overview
server/worldmonitor/market/v1/analyze-stock.ts Adds prompt, normalization, and response mapping, but emits a synthetic neutral score when no headlines exist.
src/components/StockAnalysisPanel.ts Conditionally formats and renders the optional sentiment value with escaped output.
proto/worldmonitor/market/v1/analyze_stock.proto Adds the optional field 69 while preserving backward-compatible response semantics.
tests/stock-analysis.test.mts Covers normalization and field mapping but does not cover the empty-headline LLM path.
src/generated/client/worldmonitor/market/v1/service_client.ts Regenerates the client response interface with the optional numeric field.
src/generated/server/worldmonitor/market/v1/service_server.ts Regenerates the server response interface with the optional numeric field.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Analyze stock request] --> B[Fetch market data]
  A --> C{includeNews}
  C -->|true| D[Fetch headlines]
  C -->|false| E[Empty headline list]
  D --> F[LLM overlay]
  E --> F
  F --> G[Normalize newsSentiment]
  G --> H[AnalyzeStockResponse]
  H --> I[Conditional News tile]
Loading

Reviews (1): Last reviewed commit: "feat(market): surface an LLM news-sentim..." | Re-trigger Greptile

{
role: 'system',
content: 'You are a disciplined stock analyst. Weigh the fundamentals alongside the technicals and news — do not judge on price action alone. All margin, return, growth, and debtToEquity values are decimal ratios (0.25 means 25%; debtToEquity 1.5 means debt is 1.5x equity). totalCash, totalDebt, freeCashflow, and ebitda are denominated in fundamentals.financialCurrency. Treat missing values as unknown. Return strict JSON only with keys: summary, action, confidence, whyNow, technicalSummary, newsSummary, bullishFactors, riskFactors. Keep it concise, factual, and free of disclaimers.',
content: 'You are a disciplined stock analyst. Weigh the fundamentals alongside the technicals and news — do not judge on price action alone. All margin, return, growth, and debtToEquity values are decimal ratios (0.25 means 25%; debtToEquity 1.5 means debt is 1.5x equity). totalCash, totalDebt, freeCashflow, and ebitda are denominated in fundamentals.financialCurrency. Treat missing values as unknown. Return strict JSON only with keys: summary, action, confidence, whyNow, technicalSummary, newsSummary, bullishFactors, riskFactors, newsSentiment. newsSentiment is a signed number from -1 to 1 scoring how bullish the supplied news headlines are for the stock (-1 very bearish, 0 neutral or no material news, 1 very bullish); use 0 when no headlines are provided. Keep it concise, factual, and free of disclaimers.',

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.

P1 Synthetic sentiment without headlines

When news is disabled or headline retrieval returns an empty list, this instruction makes the LLM return zero, which is preserved by the response mapping and causes the panel to display “News — Neutral (+0.00)” even though no news was requested or available. Omit the sentiment unless at least one headline was supplied.

A news-disabled or empty-headline run still surfaced newsSentiment: 0,
showing a misleading "News — Neutral (+0.00)" tile for an analysis that
never looked at any news. Gate the response field on headlines.length > 0
so the score only appears when headlines were actually scored, and drop the
prompt's "use 0 when no headlines" instruction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trust:safe Brin: contributor trust score safe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant