From 8b608781c9aaa4e086473d7c0d4e5ebd1f2af84a Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Sun, 19 Jul 2026 09:00:14 +0800 Subject: [PATCH 1/2] feat: enforce commercial Jyotish workflow contracts --- .../scripts/run_ashtakavarga_compare.py | 2 +- .../jyotish/scripts/run_shadbala_compare.py | 12 +- ...tish-invocation-optimization-2026-07-19.md | 136 ++++++++++++++++++ ...cial-repository-optimization-2026-07-19.md | 82 +++++++++++ frontend/src/app/api/consult/route.ts | 12 +- frontend/src/app/page.tsx | 14 +- frontend/src/lib/stream-text-response.ts | 2 + frontend/src/mastra/index.ts | 82 ++++++++++- frontend/tests/consultation-context.test.ts | 20 +++ .../consultation-workflow-contract.test.ts | 28 ++++ .../jyotish-api-reachability-contract.test.ts | 29 ++++ .../tests/rectification-lazy-loading.test.ts | 13 ++ tests/test_ashtakavarga_compare_compat.py | 31 ++++ tests/test_shadbala_compare_compat.py | 23 +++ 14 files changed, 470 insertions(+), 16 deletions(-) create mode 100644 docs/superpowers/plans/commercial-jyotish-invocation-optimization-2026-07-19.md create mode 100644 docs/superpowers/plans/commercial-repository-optimization-2026-07-19.md create mode 100644 frontend/tests/consultation-workflow-contract.test.ts create mode 100644 frontend/tests/jyotish-api-reachability-contract.test.ts create mode 100644 frontend/tests/rectification-lazy-loading.test.ts create mode 100644 tests/test_ashtakavarga_compare_compat.py create mode 100644 tests/test_shadbala_compare_compat.py diff --git a/benchmarks/jyotish/scripts/run_ashtakavarga_compare.py b/benchmarks/jyotish/scripts/run_ashtakavarga_compare.py index a82efd0a..83e97f30 100644 --- a/benchmarks/jyotish/scripts/run_ashtakavarga_compare.py +++ b/benchmarks/jyotish/scripts/run_ashtakavarga_compare.py @@ -22,7 +22,7 @@ OUT = ROOT / 'outputs' CANON = OUT / 'canonical' REPORT = OUT / 'jyotish_benchmark_round6_ashtakavarga_compare.md' MATRIX = OUT / 'ashtakavarga_comparison_matrix.csv' -SKILL_SCRIPTS = Path(__file__).resolve().parents[2] / 'scripts' +SKILL_SCRIPTS = Path(__file__).resolve().parents[3] / 'scripts' PYJHORA_SITE = Path(__import__('os').environ.get('PYJHORA_SITE', '')) PYJHORA_COMPAT = ROOT / 'scripts/pyjhora_compat' diff --git a/benchmarks/jyotish/scripts/run_shadbala_compare.py b/benchmarks/jyotish/scripts/run_shadbala_compare.py index 46b58e45..8f653566 100644 --- a/benchmarks/jyotish/scripts/run_shadbala_compare.py +++ b/benchmarks/jyotish/scripts/run_shadbala_compare.py @@ -13,7 +13,7 @@ from shadbala import calc_shadbala, NAISARGIKA_BALA from jhora import const, utils from jhora.panchanga import drik from jhora.horoscope.chart import charts -from jhora.horoscope.strength import shadbala as pj_shadbala +from jhora.horoscope.chart import strength as pj_strength TEST_CASES = [ {"id": "beijing_1990_noon", "year":1990, "month":6, "day":15, "hour":12, "minute":0, "lat":39.9, "lon":116.4, "tz":8}, @@ -56,8 +56,8 @@ def run_benchmark(): sign = pp[pid + 1][1][0] deg = pp[pid + 1][1][1] house = (sign - asc_sign_idx) % 12 + 1 - retro = pp[pid + 1][4] # retrograde flag in PyJHora - speed = pp[pid + 1][3] # speed in degrees/day + retro = pp[pid + 1][4] if len(pp[pid + 1]) > 4 else False + speed = pp[pid + 1][3] if len(pp[pid + 1]) > 3 else 1.0 planets[pname] = { 'sign': SIGNS[sign], 'degree': sign * 30 + deg, @@ -73,7 +73,7 @@ def run_benchmark(): # PyJHora Shadbala try: - pj = pj_shadbala.get_shadbala_scores(jd, place, divisional_chart_factor=1) + pj_total_rupas = pj_strength.shad_bala(jd, place)[7] except: print(f" PyJHora shadbala failed for {case['id']}") continue @@ -87,9 +87,7 @@ def run_benchmark(): continue our_rupas = our['planets'][pname]['total_rupas'] - pj_rupas = pj.get(pname, {}).get('shadbala', {}).get('total', 0) - if isinstance(pj_rupas, dict): - pj_rupas = pj_rupas.get('rupas', 0) + pj_rupas = pj_total_rupas[PLANET_NAMES.index(pname)] total_planets += 1 if pj_rupas > 0: diff --git a/docs/superpowers/plans/commercial-jyotish-invocation-optimization-2026-07-19.md b/docs/superpowers/plans/commercial-jyotish-invocation-optimization-2026-07-19.md new file mode 100644 index 00000000..11f52c40 --- /dev/null +++ b/docs/superpowers/plans/commercial-jyotish-invocation-optimization-2026-07-19.md @@ -0,0 +1,136 @@ +# Commercial Jyotish Invocation Optimization Plan + +## Scope + +This plan optimizes the commercial repository's actual Jyotish skill execution and the results returned to paying users. It does not modify, reorganize, or treat the research repository as a runtime dependency. Generic frontend, account, billing, and deployment work is out of scope unless it directly prevents an astrology capability from being invoked, verified, or truthfully surfaced. + +## Verified Runtime Chain + +```text +POST /api/consult + -> getJyotishAgent(model) + -> consultationTool / runConsultationWorkflow + -> POST ${JYOTISH_API_BASE}/api/consultation_workflow + -> JyotishHandler._compute_consultation_workflow + -> UnifiedConsultationOrchestrator route selection + strict workflow + -> chart/evidence/technique/dasha/oracle layers + -> consumer_context + auditable response + -> language model renders the bounded user answer +``` + +Other live product paths: + +- Daily guidance: `frontend/src/app/api/daily-starlanguage/route.ts` -> Python `/api/chart` and daily guidance logic. +- Synastry: `frontend/src/app/api/synastry/route.ts` -> Python `/api/chart` for both charts and `/api/synastry`. +- Birth-time flows call the bounded guide/rectification routes and must not obtain unrestricted consultation authority. + +Verified baseline: + +- `python3 scripts/user_invocation_acceptance_check.py`: pass. Strict routes available: career, relationship, finance. +- Core API and external adapters are available; the official VedAstro snapshot is not ready in this environment (`fast_local_fallback`, premium key absent). This is an explicit degraded external layer, not a failed local calculation. +- `skills/jyotish-vedic-astrology/SKILL.md` exists and is the default Mastra skill path. +- The Python server has many registered endpoints, but only the paths above are currently commercial-user reachable. Registered-but-unreachable techniques are not treated as product capability. + +## Non-Negotiable Product Truth Rules + +1. A user-facing claim must originate from a computed invocation result, never from an LLM choosing to improvise chart facts. +2. For career, relationship, wealth, timing, health, or event claims, the returned evidence must contain the domain-required strict workflow layers and an explicit status for every missing layer. +3. The commercial response may simplify language, but it may not drop a `blocked`, `degraded`, conflict, ayanamsa/node-mode, Dasha-boundary, functional-benefic/malefic, or external-evidence limitation that materially changes the claim. +4. Local engine success, external-engine availability, executed raw coverage, parity, and predictive calibration remain separate states. No response upgrades one state into another. +5. No research checkout/path, raw private case, oracle credential, or unapproved source artifact becomes a commercial runtime dependency. + +## Phase 0: Make Invocation Deterministic + +### Problem + +The chat agent receives instructions to call `consultationTool`, but model tool choice is probabilistic. An instruction-level requirement is not a server-side guarantee that a new chart claim has traversed the Jyotish engine. + +### Work + +1. Extract a deterministic `requiresJyotishWorkflow(question, profile, conversationState)` classifier in the commercial server layer. +2. For a new chart claim, call `runConsultationWorkflow` before streaming model output, then inject only the validated `consumer_context`/evidence projection into the agent. Do not depend on the model to decide whether to call the tool. +3. Preserve tool use for follow-ups only when the stored invocation result covers the request; otherwise re-run the workflow with an explicit reason. +4. Add an invocation receipt to the stream metadata: immutable request ID, workflow version, route, entry mode, local/external status, and evidence-packet ID. Never include birth data, question text, prompts, or secrets. +5. Define explicit `not_astrology`, `needs_profile`, `computed`, `degraded`, and `blocked` branches. Non-astrology conversation must not spend a calculation; incomplete birth data must not produce synthetic chart claims. + +### Tests + +- Contract tests prove career, relationship, wealth, and timing questions invoke `/api/consultation_workflow` exactly once before text is emitted. +- Follow-up reuse is allowed only for matching chart/configuration/version; differing birth data, reference date, ayanamsa, node mode, or required domain invalidates reuse. +- Model-mock tests prove a model cannot bypass a required invocation. +- Stream tests prove receipts contain no personal or secret fields. + +## Phase 1: Enforce Route-Specific Skill Completeness + +1. Create one versioned TypeScript schema for the commercial projection of the Python workflow response. Parse it in `frontend/src/mastra/index.ts`; reject malformed or incomplete results instead of passing untyped records to the model. +2. Build an executable route matrix from `SKILL.md`, strict-workflow contracts, and the technique registry. At minimum enforce: + - career: D10 + A10 and functional benefic/malefic; + - relationship: D9 + UL and functional benefic/malefic; + - wealth: D2/D11 and functional benefic/malefic; + - timing/event: Vimshottari + Narayana Dasha, required Dasha boundaries, transit status, and external-evidence status. +3. The API projection carries technique `used/not_used/blocked`, missing layers, conflict resolution, confidence boundary, and the raw-evidence identifiers required by the selected route. +4. Add a Python-to-TypeScript golden fixture for every route and every terminal status (`ready`, `degraded`, `blocked`). Fixtures must use public synthetic cases only. +5. Cross-check the frontend-reachable endpoint inventory against Python dispatch. Fail CI when a new user-reachable operation has no handler, no schema, or no capability contract. + +### Tests + +- Golden parity for route projection and error/status preservation. +- Negative tests delete each required layer and assert the commercial answer cannot make the corresponding claim. +- Endpoint reachability inventory test includes `/api/consultation_workflow`, daily guidance, synastry, and all birth-time routes. + +## Phase 2: Truthful External-Oracle Degradation + +1. Treat the current `fast_local_fallback` as a first-class execution state in the commercial response contract, not an incidental log value. +2. Map external layers independently: PyJHora/JHora comparison, jyotishganit, VedAstro official raw snapshot, parity status, and real-case calibration. Preserve license boundaries. +3. When a premium key or official snapshot is unavailable, retain local computation but force the exact affected conclusion to `degraded` or `blocked` according to the strict-workflow contract. Do not silently say an external check ran. +4. Add a configurable official-snapshot budget/timeout with a circuit state and sanitized telemetry. The fallback must be deterministic, bounded, and visible to audit metadata. +5. Add a deployment gate that runs the existing adapter diagnostics and a selected public-synthetic same-chart replay. It must report `unavailable`, `partial_verified`, and `mismatch` distinctly rather than failing open. + +### Tests + +- No-key, timeout, malformed-provider, parity-mismatch, and fully-available fixtures. +- Assertions that the language-model context never upgrades `partial_verified` to verified or hides a material blocked layer. +- License/attribution snapshot test for every enabled external adapter. + +## Phase 3: Optimize Real Engine Cost And Reliability + +1. Instrument only actual entrypoints (`consultation_workflow`, chart, synastry, daily guidance, high-rigor workflow) with sanitized elapsed-time spans: routing, ephemeris/chart, divisional charts, dasha, Shadbala/Ashtakavarga, external adapters, serialization. +2. Benchmark public synthetic charts by route/configuration on the production-equivalent 1-vCPU/2-GB budget. Establish p50/p95, response-size, timeout, and queue-depth budgets before caching or parallelization. +3. Memoize only immutable, configuration-keyed computation fragments. Use a bounded TTL/LRU keyed by a cryptographic digest of normalized input and computation settings; never cache raw profile data, user text, credentials, or final personalized prose. +4. Keep high-rigor/batch/external-heavy paths asynchronous when their measured p95 exceeds the interactive budget. Preserve existing job identity, polling, cancellation, and evidence-packet retrieval semantics. +5. Reduce model context to the route-required evidence projection. Full raw packets remain retrievable only through the authenticated/auditable path, avoiding token cost and accidental evidence loss in chat rendering. + +### Tests + +- Determinism before/after cache hit; ayanamsa/node-mode/reference-date changes must miss cache. +- Concurrent identical requests do not duplicate expensive work; cancellation never corrupts a shared result. +- Benchmark regression thresholds and response-shape snapshots. + +## Phase 4: Wire Secondary Live Flows Into The Same Truth Contract + +1. Daily guidance must carry reference date, transit source/configuration, local/external state, and a bounded claim scope; no generic model prose may replace chart-derived daily data. +2. Synastry must preserve both chart settings, Ashtakoot method/version, D9 evidence, relationship-route required layers, and non-comparability states. +3. Birth-time guidance/rectification remains evidence-collection and candidate-scoring only. It cannot present a candidate as a verified birth time until its configured evidence threshold and strict workflow state are met. +4. Use one commercial `AstrologyExecutionEnvelope` for the shared status/audit fields while retaining route-specific payloads. This is an adapter boundary, not a rewrite of engine formulas. + +### Tests + +- Daily date-boundary and fallback fixtures. +- Synastry settings mismatch/non-comparability fixtures. +- Rectification candidate confidence and no-premature-certainty fixtures. + +## Phase 5: Commercial Capability Intake + +When the owner approves a research-derived capability, add it only through a commercial intake manifest containing capability ID/version, approved interface, supplied source hash, license/attribution decision, input/output contract, privacy class, test fixture provenance, rollout flag, observability, and rollback path. The commercial adapter consumes that interface only; it does not import a research working tree. + +## Execution Order + +1. Reconcile local branch with upstream before editing runtime behavior. +2. Phase 0 deterministic invocation. +3. Phase 1 route-completeness schemas and golden contracts. +4. Phase 2 external-degradation truth handling. +5. Phase 3 measured engine performance/reliability. +6. Phase 4 secondary live flows. +7. Phase 5 only after an owner-approved capability handoff. + +Each phase requires relevant Python + frontend tests, user-invocation acceptance, adapter diagnostics, production build, and `git diff --check`. Push/deploy needs separate owner authorization. diff --git a/docs/superpowers/plans/commercial-repository-optimization-2026-07-19.md b/docs/superpowers/plans/commercial-repository-optimization-2026-07-19.md new file mode 100644 index 00000000..a862cb9f --- /dev/null +++ b/docs/superpowers/plans/commercial-repository-optimization-2026-07-19.md @@ -0,0 +1,82 @@ +# Commercial Repository Optimization Plan + +**Scope:** `jesse-ux/Jyotisha` commercial repository only. The research repository remains an external, owner-approved source of validated capability artifacts. No research source code, raw data, or internal validation chain is modified by this plan. + +## Baseline And Evidence + +- Local branch: `codex/optimize-runtime-ux`, based on `3d6d498`; upstream `main` is now `51decd5003df1a33f49e71d6469e5a0cd382e7dc`. Reconcile before implementation; do not overwrite local changes. +- Existing local change: lazy-load birth-time rectification. Largest first-page chunk measured `826,370 B -> 710,726 B` (about `115.6 KB` reduction). +- `npm test`: `264/264` pass. `npm run lint`: exit success, two existing `react-hooks/exhaustive-deps` warnings in `frontend/src/app/page.tsx` lines 1176 and 1192. +- Production smoke: `https://jyotisha.chat/` returns `200`, static cache hit, and `/api/health` returns environment/provider status plus internal API latency publicly. +- Official-registry dependency audit: 5 findings (3 low, 2 moderate), including direct `next`/transitive `postcss` and `@mastra/core`/AI SDK dependency paths. The configured `npmmirror` cannot provide npm security advisories; its audit endpoint returns `404`. +- Public evidence consulted: [Next.js lazy loading](https://nextjs.org/docs/app/guides/lazy-loading), [Next.js production checklist](https://nextjs.org/docs/app/guides/production-checklist), [Supabase SSR](https://supabase.com/docs/guides/auth/server-side/creating-a-client), and [GitHub Actions secure use](https://docs.github.com/en/actions/reference/security/secure-use). + +## Acceptance Rules + +- No research repository write, dependency, path, raw evidence, or secret enters the commercial repository without an explicit approved intake record. +- Preserve account, credits, cancellation, and existing business tests. Do not expose user identity, birth data, prompts, model keys, or Supabase service keys in logs, telemetry, responses, or build artifacts. +- A public liveness route may reveal only a coarse status. Dependency readiness and diagnostic detail must remain Docker-private or token-gated. +- Every performance claim needs before/after build evidence. Every dependency update needs audit output and full test/build evidence. + +## Phase 0: Reconcile And Freeze Baseline + +1. Run `git fetch origin main`, inspect `3d6d498..origin/main`, and rebase or manually port only the local lazy-load change after reviewing conflicts. +2. Record immutable baseline artifacts: `npm ci`, `npm test`, `npm run lint`, `npm run build`, official-registry `npm audit --omit=dev --registry=https://registry.npmjs.org`, route-size manifest, and production header/health samples. +3. Add a CI-independent script, `frontend/scripts/verify-production-baseline.mjs`, that emits sanitized JSON for test/build/audit/bundle-budget evidence. It must explicitly select `registry.npmjs.org` for audit. + +**Tests:** existing test suite; build; `git diff --check`; baseline script fixture test. + +## Phase 1: Supply Chain And Release Controls + +1. Upgrade direct vulnerable dependencies to the newest compatible patched releases, regenerate only `frontend/package-lock.json`, and re-run the official audit. Do not accept the audit tool's suggested semver-major downgrade/upgrade blindly; inspect the resolved tree first. +2. Add `dependabot.yml` for GitHub Actions, root Python, `frontend`, and `jyotish-app`; group patch/minor updates by ecosystem while retaining PR review. +3. In CI, run official-registry production audit, frontend lint/tests/build, and a lockfile integrity check. Use GitHub Actions concurrency to cancel obsolete PR runs. Pin third-party actions to immutable commit SHAs after verifying publishers and versions. +4. Keep deployment gated on the same commit that passed CI. Add a release evidence artifact containing dependency audit summary, build identifier, and sanitized production smoke result. + +**Tests:** audit reaches zero high/critical; dependency-specific regression tests; full frontend test/build; workflow syntax validation. + +## Phase 2: Public Edge And API Hardening + +1. Split health semantics: + - `GET /api/health`: public liveness only, no environment names, provider presence, topology, or internal latency. + - an internal-only diagnostic route or direct Docker healthcheck: detailed dependency checks, accessible only from the compose network or through a deployment-only token. + - Add route tests proving detail cannot reach the public response. +2. Add Caddy edge headers: `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`, clickjacking protection, and production HSTS. Design CSP in report-only mode first because Next.js/Supabase scripts and streaming require nonce/hash validation; promote only after browser and login-flow verification. +3. Map all mutating API routes to explicit authentication, schema validation, authorization, idempotency, timeout, and rate-limit behavior. Preserve the existing credit RPC as the billing authority; add a durable per-user guard only where the current credit lifecycle does not already prevent expensive model work. +4. Add request IDs and sanitized structured event fields (`route`, `status`, `latency_ms`, `model_id`, `credit_transition`, `error_class`). Explicitly prohibit prompt/profile/body logging. + +**Tests:** public health redaction, internal health success in compose, unauthenticated/malformed/over-limit cases for every mutation route, streamed consultation cancellation, browser login/account/consult smoke. + +## Phase 3: First-Use Performance And Frontend Maintainability + +1. Keep the existing lazy-loaded rectification subtree and turn its measured saving into a regression budget. Add a bundle report that identifies first-page JS separately from deferred chunks; fail CI only on a deliberate, reviewed budget breach. +2. Defer heavy onboarding-only data, beginning with `china-locations`, until the location step opens. Preserve typed loading/error states and keyboard behavior. +3. Split `frontend/src/app/page.tsx` (2,643 lines) by stable product boundaries, not generic abstractions: + - session/chat composer and streaming lifecycle; + - onboarding/profile and birth-time flow; + - chart library and synastry history; + - account/model-selection orchestration. + State ownership remains at the smallest shared parent; pure transformations move to tested `lib` modules. +4. Resolve the two exhaustive-deps warnings by proving the intended dependency model through tests, rather than silencing lint rules. Avoid adding `profile` wholesale if that would cause duplicate network calls; extract stable primitive dependencies or a memoized request key. +5. Validate desktop/mobile rendering, loading fallback, focus order, reduced-motion behavior, and long Chinese content after each split. + +**Tests:** unit tests for extracted state transitions; existing source-contract tests updated only for behavior; Playwright flows for login, onboarding, guided rectification, cancel/retry, chat session switching, account dialogs; production bundle comparison. + +## Phase 4: Commercial Capability Intake Boundary + +1. Add `docs/commercial-capability-intake.md` plus a machine-readable `frontend/src/lib/capability-manifest.ts` only when a research capability is approved for commercial use. +2. Each intake row records: capability ID/version, permitted interface, source commit/hash supplied by the owner, license/attribution decision, accepted input/output schema, user-facing fallback, privacy classification, test fixture provenance, and rollback switch. +3. Commercial adapters call only the approved stable interface. They must not import a research checkout, scrape research artifacts, or claim research-level validation beyond the supplied manifest. +4. Gate every intake behind contract tests, a staged feature flag, production observability, and an explicit rollback procedure. + +**Tests:** manifest schema validation; adapter contract fixtures; feature-flag off fallback; rollback integration test. + +## Execution Order + +1. Phase 0 reconcile/baseline. +2. Phase 1 dependencies and CI controls. +3. Phase 2 health/edge/API hardening. +4. Phase 3 performance decomposition and browser verification. +5. Phase 4 only when an owner-approved research capability arrives. + +Each phase ends with `git diff --check`, full relevant tests, production build, and an evidence note. Deployment/push remains separate owner authorization. diff --git a/frontend/src/app/api/consult/route.ts b/frontend/src/app/api/consult/route.ts index e0102815..fbb797a1 100644 --- a/frontend/src/app/api/consult/route.ts +++ b/frontend/src/app/api/consult/route.ts @@ -1,7 +1,9 @@ import { NextResponse } from "next/server"; import { consultationInputSchema, + consultationWorkflowReceipt, getJyotishAgent, + runConsultationWorkflow, } from "@/mastra"; import { languageModelConfigurationMessage, @@ -167,8 +169,10 @@ export async function POST(request: Request) { try { const { history, name } = parsed.data; const toolInput = consultationInputSchema.parse(parsed.data); + const workflowContext = await runConsultationWorkflow(toolInput); + const workflowReceipt = consultationWorkflowReceipt(workflowContext); - const result = await getJyotishAgent(selectedModel).stream([ + const result = await getJyotishAgent(selectedModel, workflowContext).stream([ ...history.map((message) => message.role === "user" ? { role: "user" as const, content: message.text } : { role: "assistant" as const, content: message.text }), @@ -191,6 +195,12 @@ export async function POST(request: Request) { return streamTextResponse(result.textStream, { mode: "mastra", requestId, + headers: { + "x-jyotish-workflow-route": workflowReceipt.route, + "x-jyotish-workflow-status": workflowReceipt.status, + "x-jyotish-precise-timing": workflowReceipt.preciseTiming, + "x-jyotish-missing-layers": workflowReceipt.missingLayers, + }, onComplete: () => settle(completeAndRecordUsage), onError: (_error, emitted) => settleInterrupted(emitted), onCancel: settleInterrupted, diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 53b2c847..c2a38565 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,12 +1,12 @@ "use client"; import Link from "next/link"; +import dynamic from "next/dynamic"; import { ArrowUp, ArrowUpRight, Sparkles, Square, X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import type { FormEvent, KeyboardEvent } from "react"; import { AppSidebar } from "@/components/app-sidebar"; import { BirthTimeIntakeFields } from "@/components/birth-time-intake"; -import { BirthTimeRectification } from "@/components/birth-time-rectification"; import { ChatMessageContent } from "@/components/chat-message-content"; import { ModelSelector } from "@/components/model-selector"; import { Button } from "@/components/ui/button"; @@ -46,6 +46,14 @@ import { } from "@/lib/public-models"; import { createBrowserSupabaseClient } from "@/lib/supabase/client"; +const BirthTimeRectification = dynamic( + () => import("@/components/birth-time-rectification").then((module) => module.BirthTimeRectification), + { + ssr: false, + loading: () =>
正在加载出生时间评估...
, + }, +); + type Theme = ReplyTheme; type Message = { role: "user" | "assistant"; text: string; suggestions?: string[] }; type Profile = BirthTimeDraft & { @@ -1165,7 +1173,7 @@ export default function Home() { return () => { cancelled = true; }; - }, [hydrated, profile.date, profile.time, profile.provinceCode, profile.cityCode, profileComplete]); + }, [hydrated, profile, profileComplete]); useEffect(() => { if (!hydrated || !profileComplete) return; @@ -1181,7 +1189,7 @@ export default function Home() { return () => { cancelled = true; }; - }, [hydrated, profile.date, profile.time, profile.provinceCode, profile.cityCode, profileComplete]); + }, [hydrated, profile, profileComplete]); useEffect(() => { const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; diff --git a/frontend/src/lib/stream-text-response.ts b/frontend/src/lib/stream-text-response.ts index df8ac39b..4f6acb83 100644 --- a/frontend/src/lib/stream-text-response.ts +++ b/frontend/src/lib/stream-text-response.ts @@ -7,6 +7,7 @@ type StreamHooks = { type StreamTextResponseOptions = StreamHooks & { readonly mode: "engine" | "mastra"; readonly requestId: string; + readonly headers?: Record