Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/components/OracleChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from '@/lib/api';
import { useChatJob } from '@/hooks/queries';
import StepTimeline from './chat/StepTimeline';
import ModelOutputNotice from '@/components/ui/ModelOutputNotice';
import { toStepRow, toStoredSteps, type ChatStep } from '@/lib/chat-job';

type ResponseStyle = 'concise' | 'detailed';
Expand Down Expand Up @@ -732,6 +733,7 @@ export default function OracleChatPage() {
whether there is a reasoning pass — rather than the old line,
which described detailed mode whichever one was selected. */}
<p className="text-center text-xs text-fg-subtle mt-2">{mode.blurb}</p>
<ModelOutputNotice className="text-center mt-1.5" />
</form>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions frontend/components/OraclePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
TrendingUp,
} from 'lucide-react';
import type { EvidenceItem, NewsAnalysis, PrecedentAnalogy } from '@/lib/api';
import ModelOutputNotice from '@/components/ui/ModelOutputNotice';

type Sentiment = 'bullish' | 'bearish' | 'neutral';

Expand Down Expand Up @@ -453,6 +454,8 @@ function AnalysisBody({
</>
)}
</div>

<ModelOutputNotice className="px-1 pb-1" />
</div>
);
}
2 changes: 2 additions & 0 deletions frontend/components/analysis/ReportView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { AlertTriangle, ArrowLeft, Calendar, Loader2, RotateCw } from 'lucide-react';
import type { AnalysisJob, AnalysisReport, TimeFrame } from '@/lib/api';
import ReportMarkdown from './ReportMarkdown';
import ModelOutputNotice from '@/components/ui/ModelOutputNotice';

interface ReportViewProps {
timeframe: TimeFrame;
Expand Down Expand Up @@ -89,6 +90,7 @@ export default function ReportView({
</div>
)}
<ReportMarkdown content={report.content} />
<ModelOutputNotice className="mt-6 border-t border-line pt-3" />
</>
) : (
<p className="text-base text-fg-subtle">
Expand Down
8 changes: 8 additions & 0 deletions frontend/components/landing/LandingFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ export default function LandingFooter() {
</a>
</nav>
</div>

{/* The landing page carries no model output of its own, so this states
what the product is rather than caveating a specific answer. The
per-surface notice inside the terminal is `ui/ModelOutputNotice`. */}
<p className="mt-2 max-w-3xl text-2xs text-fg-subtle">
Oracle-X is a research terminal. It reports market data and model-generated commentary —
nothing it produces is investment advice.
</p>
</footer>
);
}
26 changes: 26 additions & 0 deletions frontend/components/ui/ModelOutputNotice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* The standing caveat under anything a language model wrote.
*
* The prompts already tell the model to describe its own output as research
* commentary — `prompts/chat/system.md`, `prompts/analysis/stage2_report.md`
* and `prompts/news/system_sentiment.md` all carry the line. But an instruction
* is not a guarantee: a model that omits it, or a fallback provider that
* phrases it away, leaves the screen with no caveat at all. Rendering it from
* the client makes it independent of what the model chose to say.
*
* Deliberately not a band in `ClientShell`. That shell is a fixed-height,
* non-scrolling layout, so a permanent row there would cost height on all
* thirteen routes — including the heatmap and the live feed, which show no
* model output to caveat. This attaches to the surfaces that carry it instead.
*
* The border and spacing are left to the caller: the report footer wants a rule
* above it, the chat composer already sits under one.
*/
export default function ModelOutputNotice({ className = '' }: { className?: string }) {
return (
<p className={`text-2xs text-fg-subtle ${className}`.trim()}>
Model-generated and can be wrong — verify anything you act on. Research commentary, not
personalised investment advice.
</p>
);
}