Skip to content

Commit 0bf5fd6

Browse files
authored
Merge pull request #47 from yeahhe365/refactor/pure-frontend-platform
Refactor pure frontend platform architecture
2 parents 652a6db + 99a5a85 commit 0bf5fd6

File tree

126 files changed

+2261
-465
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+2261
-465
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ Thumbs.db
3232

3333
# Coverage
3434
coverage/
35+
36+
# Local worktrees
37+
.worktrees/

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,11 @@ npm run dev
143143
除了在界面中手动配置,也可在根目录创建 `.env.local`
144144

145145
```bash
146-
GEMINI_API_KEY=your_api_key_here
146+
VITE_GEMINI_API_KEY=your_api_key_here
147147
```
148148

149+
兼容旧配置:如果你之前使用的是 `GEMINI_API_KEY`,当前版本仍会回退读取,但建议迁移到 `VITE_GEMINI_API_KEY`
150+
149151
### 构建部署
150152

151153
```bash
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Pure Frontend Platform Refactor Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4+
5+
**Goal:** Refactor the app into a safer, adapter-driven pure-frontend architecture while preserving persisted user data and fixing Gemini protocol drift.
6+
7+
**Architecture:** Start with a narrow phase that creates stable seams around Gemini integration, persistence migration, and quality gates. Use that phase to stop protocol breakage and type drift before expanding the refactor into broader feature decomposition.
8+
9+
**Tech Stack:** React 18, TypeScript, Vite, Vitest, Zustand, IndexedDB, `@google/genai`
10+
11+
---
12+
13+
## File Structure
14+
15+
- Create: `src/platform/genai/client.ts`
16+
- Create: `src/platform/genai/modelCatalog.ts`
17+
- Create: `src/platform/genai/liveApi.ts`
18+
- Create: `src/platform/persistence/schema.ts`
19+
- Create: `src/platform/persistence/migrations.ts`
20+
- Modify: `src/hooks/live-api/useLiveConnection.ts`
21+
- Modify: `src/hooks/live-api/useLiveConfig.ts`
22+
- Modify: `src/hooks/live-api/useLiveMessageProcessing.ts`
23+
- Modify: `src/services/api/baseApi.ts`
24+
- Modify: `src/utils/apiUtils.ts`
25+
- Modify: `src/constants/appConstants.ts`
26+
- Modify: `src/constants/modelConstants.ts`
27+
- Modify: `src/utils/modelHelpers.ts`
28+
- Modify: `src/hooks/useModelCapabilities.ts`
29+
- Modify: `vite.config.ts`
30+
- Modify: `package.json`
31+
- Test: `src/hooks/live-api/__tests__/useLiveMessageProcessing.test.ts`
32+
- Test: `src/platform/genai/__tests__/liveApi.test.ts`
33+
- Test: `src/platform/persistence/__tests__/migrations.test.ts`
34+
- Test: `src/utils/__tests__/apiUtils.test.ts`
35+
- Test: `src/services/api/__tests__/baseApi.test.ts`
36+
37+
### Task 1: Lock In Live API 3.1 Behavior
38+
39+
**Files:**
40+
- Create: `src/platform/genai/liveApi.ts`
41+
- Modify: `src/hooks/live-api/useLiveConnection.ts`
42+
- Modify: `src/hooks/live-api/useLiveConfig.ts`
43+
- Modify: `src/hooks/live-api/useLiveMessageProcessing.ts`
44+
- Test: `src/platform/genai/__tests__/liveApi.test.ts`
45+
- Test: `src/hooks/live-api/__tests__/useLiveMessageProcessing.test.ts`
46+
47+
- [ ] Write failing tests for Gemini 3.1 text transport selection and multipart server-event parsing.
48+
- [ ] Run the targeted tests and confirm failure against current `sendClientContent` and first-part-only logic.
49+
- [ ] Implement a `liveApi` adapter that selects request mode by model descriptor and exposes helper predicates.
50+
- [ ] Refactor live hooks to use the adapter and iterate over all response parts in each event.
51+
- [ ] Re-run targeted tests and then the full test suite.
52+
53+
### Task 2: Restore Safe Default Request Configuration
54+
55+
**Files:**
56+
- Modify: `src/services/api/baseApi.ts`
57+
- Modify: `src/constants/appConstants.ts`
58+
- Modify: `src/constants/modelConstants.ts`
59+
- Modify: `src/services/api/__tests__/baseApi.test.ts`
60+
61+
- [ ] Write failing tests for safety-setting omission when the user has not customized defaults.
62+
- [ ] Run the targeted base API tests and verify failure.
63+
- [ ] Change request-building logic so default Gemini behavior is preserved unless the user explicitly overrides safety settings.
64+
- [ ] Reconcile thinking defaults between model metadata and request configuration for the touched paths.
65+
- [ ] Re-run targeted tests and the full suite.
66+
67+
### Task 3: Introduce Model Metadata and Remove Stringly Live Decisions
68+
69+
**Files:**
70+
- Create: `src/platform/genai/modelCatalog.ts`
71+
- Modify: `src/utils/modelHelpers.ts`
72+
- Modify: `src/hooks/useModelCapabilities.ts`
73+
- Modify: `src/constants/modelConstants.ts`
74+
- Test: `src/utils/__tests__/modelHelpers.test.ts`
75+
76+
- [ ] Write failing tests for structured capability lookups replacing current `includes(...)` checks on touched model paths.
77+
- [ ] Run model helper tests and confirm failure.
78+
- [ ] Add a typed `ModelDescriptor` catalog for currently supported and deprecated models in scope.
79+
- [ ] Switch live and capability logic to use catalog helpers first, leaving legacy helpers only as compatibility wrappers where needed.
80+
- [ ] Re-run targeted tests and the full suite.
81+
82+
### Task 4: Add Persistence Schema Versioning and Compatibility Entry Point
83+
84+
**Files:**
85+
- Create: `src/platform/persistence/schema.ts`
86+
- Create: `src/platform/persistence/migrations.ts`
87+
- Modify: `src/stores/settingsStore.ts`
88+
- Modify: `src/utils/db.ts`
89+
- Test: `src/platform/persistence/__tests__/migrations.test.ts`
90+
91+
- [ ] Write failing tests for version detection, no-op migrations, and future compatibility hooks.
92+
- [ ] Run migration tests and confirm failure.
93+
- [ ] Add a minimal schema-version store and migration pipeline without rewriting existing user data yet.
94+
- [ ] Integrate startup reads through the migration entry point.
95+
- [ ] Re-run targeted tests and the full suite.
96+
97+
### Task 5: Fix Environment Contract and Quality Gates
98+
99+
**Files:**
100+
- Modify: `vite.config.ts`
101+
- Modify: `src/utils/apiUtils.ts`
102+
- Modify: `package.json`
103+
- Modify: `README.md`
104+
- Test: `src/utils/__tests__/apiUtils.test.ts`
105+
106+
- [ ] Write failing tests for environment variable priority and compatibility.
107+
- [ ] Run the API utils tests and confirm failure if the current contract is inconsistent.
108+
- [ ] Align build-time and runtime env variable handling so `VITE_GEMINI_API_KEY` behaves exactly as documented.
109+
- [ ] Make `build` depend on `typecheck` and ensure the touched code path compiles cleanly.
110+
- [ ] Re-run targeted tests, `npm run typecheck`, `npm run build`, and the full suite.
111+
112+
### Task 6: Expand Quality Gates for the Touched Surface
113+
114+
**Files:**
115+
- Modify: touched files from Tasks 1-5
116+
- Test: existing targeted suites
117+
118+
- [ ] Resolve TypeScript and lint issues introduced or exposed in the touched files.
119+
- [ ] Run `npm run typecheck` and confirm that touched-surface regressions are eliminated.
120+
- [ ] Run `npm test` and `npm run build` from the worktree.
121+
- [ ] Summarize remaining repo-wide debt that is intentionally left for later phases.
122+
123+
## Self-Review
124+
125+
- Spec coverage checked: Phase 1 covers Live protocol drift, safety defaults, model metadata foundation, migration scaffolding, env contract, and quality gates.
126+
- Placeholder scan checked: task outputs are concrete and bounded to the current phase.
127+
- Type consistency checked: `ModelDescriptor`, migration entry points, and Live adapter names are consistent across tasks.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Pure Frontend Platform Refactor Design
2+
3+
**Date:** 2026-04-08
4+
5+
## Goal
6+
7+
Refactor `All-Model-Chat` into a maintainable pure-frontend platform that preserves existing IndexedDB and localStorage user data, fixes Gemini protocol drift, and creates clear module boundaries for future work.
8+
9+
## Constraints
10+
11+
- Pure frontend remains the primary deployment model.
12+
- Existing chat history, session settings, saved model lists, shortcuts, and API configuration must migrate automatically and remain usable.
13+
- Google AI Studio / zero-build mode may be downgraded or removed if it conflicts with maintainability.
14+
- Large refactors are acceptable if they reduce long-term structural debt.
15+
16+
## Current Problems
17+
18+
- Gemini SDK usage is scattered across hooks, services, helpers, and stores.
19+
- Live API behavior is mixed across model generations and does not match current Gemini 3.1 semantics.
20+
- Safety defaults are more permissive than the documented Gemini defaults.
21+
- Model capability checks depend on string matching instead of structured metadata.
22+
- `build` can pass while `typecheck` and `lint` fail, so the repo has no trustworthy quality gate.
23+
- Persistent data uses ad hoc compatibility logic instead of schema-driven migrations.
24+
25+
## Target Architecture
26+
27+
The refactor will reorganize the app into a layered frontend monolith:
28+
29+
- `src/app`
30+
Bootstrap, app shell, providers, boundary setup.
31+
- `src/features/*`
32+
User-facing workflows such as `chat`, `live`, `files`, `settings`, `history`.
33+
- `src/application/*`
34+
Use-case orchestration such as `send message`, `resume session`, `migrate persisted data`.
35+
- `src/domain/*`
36+
Business models and rules without React or browser APIs.
37+
- `src/platform/*`
38+
Adapters for Gemini SDK, IndexedDB, browser media APIs, notifications, and storage.
39+
- `src/shared/*`
40+
Shared UI primitives and utilities with no feature ownership.
41+
42+
The first implementation phase will not move every file immediately. It will establish the seams and move the highest-risk integrations first.
43+
44+
## Data Compatibility Design
45+
46+
Persistent data will adopt explicit schema versioning.
47+
48+
- Add a persisted app schema version key.
49+
- On startup, run `detect -> migrate -> validate -> load`.
50+
- Migrations must be idempotent and non-destructive.
51+
- If migration fails, preserve original data and enter a recoverable fallback mode.
52+
53+
### Data to Preserve
54+
55+
- IndexedDB chat sessions
56+
- Per-session chat settings
57+
- App settings
58+
- Saved model preferences
59+
- Shortcuts
60+
- API config
61+
62+
### Compatibility Strategy
63+
64+
- Keep current stored shapes readable during the transition.
65+
- Introduce normalized in-memory models first.
66+
- Add background rewrite migrations only after normalized read/write paths are stable.
67+
68+
## Gemini Integration Design
69+
70+
Gemini integration will be consolidated behind platform adapters:
71+
72+
- `platform/genai/client.ts`
73+
- `platform/genai/model-catalog.ts`
74+
- `platform/genai/chat-api.ts`
75+
- `platform/genai/live-api.ts`
76+
- `platform/genai/content-mapper.ts`
77+
- `platform/genai/safety.ts`
78+
- `platform/genai/errors.ts`
79+
80+
### Model Metadata
81+
82+
Replace string-based capability checks with a `ModelDescriptor` structure that includes:
83+
84+
- `id`
85+
- `family`
86+
- `mode`
87+
- `supportsThinkingLevel`
88+
- `supportsThinkingBudget`
89+
- `supportsLive`
90+
- `supportsImageGeneration`
91+
- `supportsImageEditing`
92+
- `supportsTts`
93+
- `supportsTranscription`
94+
- `supportsGoogleSearch`
95+
- `supportsCodeExecution`
96+
- `supportsUrlContext`
97+
- `deprecatedAt`
98+
- `replacement`
99+
100+
## Live API Design
101+
102+
Live API handling must split by model-generation behavior.
103+
104+
- Gemini 3.1 Live:
105+
use `sendRealtimeInput` for conversational text updates and process all parts in each server event.
106+
- Gemini 2.5 live/native-audio:
107+
retain compatible request/response handling where still valid.
108+
109+
The UI should clearly mark direct browser Live connections using long-lived API keys as less safe than ephemeral-token-backed flows.
110+
111+
## Safety Design
112+
113+
Default app behavior should follow Gemini documented defaults unless the user explicitly overrides safety settings.
114+
115+
- Do not eagerly send permissive `BLOCK_NONE` defaults.
116+
- Only send request-level safety settings after user customization.
117+
- Keep UI state expressive, but map it to API payloads only when needed.
118+
119+
## Quality Gates
120+
121+
The repo must not rely on `vite build` as the only health check.
122+
123+
- `build` should depend on `typecheck`.
124+
- CI should run `test`, `typecheck`, `lint`, and `build`.
125+
- SDK type drift should be isolated behind adapter types instead of leaking into business code.
126+
127+
## Migration Phases
128+
129+
### Phase 1
130+
131+
- Fix Gemini Live protocol drift.
132+
- Fix Live multipart event parsing.
133+
- Align safety defaults with documented behavior.
134+
- Resolve environment variable/documentation mismatch.
135+
- Establish adapter entry points and migration scaffolding.
136+
- Make `typecheck` failures actionable in the touched surface.
137+
138+
### Phase 2
139+
140+
- Introduce structured model catalog and capability lookups.
141+
- Move chat request construction into application/platform boundaries.
142+
- Begin persistent schema migration support.
143+
144+
### Phase 3
145+
146+
- Break remaining monolithic hooks into feature/application modules.
147+
- Reduce bundle size with lazy loading for heavyweight features.
148+
- Remove obsolete zero-build assumptions if they continue to constrain architecture.
149+
150+
## Risks
151+
152+
- Existing uncommitted work in the main workspace may diverge from the refactor branch.
153+
- Migration bugs could affect stored session integrity if validation is weak.
154+
- Gemini SDK changes can still break adapter assumptions if the adapter surface is not tightly typed.
155+
- Live API behavior differs by model family, so regression tests must cover both 2.5 and 3.1 paths.
156+
157+
## Success Criteria
158+
159+
- Existing users can open the refactored app without losing sessions or settings.
160+
- Gemini 3.1 Live text and multipart responses behave according to current docs.
161+
- Safety defaults match documented Gemini defaults.
162+
- `test`, `typecheck`, `lint`, and `build` become meaningful quality gates for the touched code paths.
163+
- New Gemini integration work can be added through adapters and model metadata instead of string matching across the codebase.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8-
"build": "vite build",
8+
"build": "npm run typecheck && vite build",
99
"preview": "vite preview",
1010
"lint": "eslint . --ext .ts,.tsx",
1111
"lint:fix": "eslint . --ext .ts,.tsx --fix",

src/components/chat/MessageList.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { useMessageListScroll } from './message-list/hooks/useMessageListScroll'
1717
import { MessageListFooter } from './message-list/MessageListFooter';
1818
import { useChatStore } from '../../stores/chatStore';
1919
import { useSettingsStore } from '../../stores/settingsStore';
20+
import type { Translator } from '../../utils/translations';
2021

2122
export interface MessageListProps {
2223
messages: ChatMessage[];
@@ -63,12 +64,12 @@ export const MessageList: React.FC<MessageListProps> = ({
6364
const storeTtsMessageId = useChatStore(s => s.ttsMessageId);
6465
const storeAppSettings = useSettingsStore(s => s.appSettings);
6566
const storeThemeId = useSettingsStore(s => s.currentTheme.id);
66-
const storeScrollContainerRef = useChatStore(s => s.scrollContainerRef);
6767

6868
// Use store values with fallback to props
6969
const ttsMessageId = storeTtsMessageId ?? propsTtsMessageId;
7070
const appSettings = storeAppSettings ?? propsAppSettings;
7171
const themeId = storeThemeId ?? propsThemeId;
72+
const translate = t as Translator;
7273

7374
// UI Logic (Modals, Previews, Configuration)
7475
const {
@@ -93,7 +94,7 @@ export const MessageList: React.FC<MessageListProps> = ({
9394
// Scroll Logic
9495
const {
9596
virtuosoRef,
96-
setInternalScrollerRef,
97+
handleScrollerRef,
9798
setAtBottom,
9899
onRangeChanged,
99100
scrollToPrevTurn,
@@ -121,7 +122,7 @@ export const MessageList: React.FC<MessageListProps> = ({
121122
<Virtuoso
122123
ref={virtuosoRef}
123124
data={messages}
124-
scrollerRef={setInternalScrollerRef}
125+
scrollerRef={handleScrollerRef}
125126
atBottomStateChange={setAtBottom}
126127
followOutput={false} // Disable auto-scroll to bottom during streaming (we handle it via auto-anchor or user interaction)
127128
rangeChanged={onRangeChanged}
@@ -155,7 +156,7 @@ export const MessageList: React.FC<MessageListProps> = ({
155156
onContinueGeneration={onContinueGeneration}
156157
ttsMessageId={ttsMessageId}
157158
onSuggestionClick={onFollowUpSuggestionClick}
158-
t={t}
159+
t={translate}
159160
appSettings={appSettings}
160161
onOpenSidePanel={onOpenSidePanel}
161162
onConfigureFile={msg.role === 'user' ? handleConfigureFile : undefined}
@@ -172,7 +173,7 @@ export const MessageList: React.FC<MessageListProps> = ({
172173
onInsert={onInsert}
173174
onTTS={onQuickTTS}
174175
containerRef={scrollerRef as any}
175-
t={t}
176+
t={translate}
176177
/>
177178

178179
<ScrollNavigation
@@ -188,7 +189,7 @@ export const MessageList: React.FC<MessageListProps> = ({
188189
<FilePreviewModal
189190
file={previewFile}
190191
onClose={closeFilePreviewModal}
191-
t={t}
192+
t={translate}
192193
onPrev={handlePrevImage}
193194
onNext={handleNextImage}
194195
hasPrev={currentImageIndex > 0}
@@ -209,7 +210,7 @@ export const MessageList: React.FC<MessageListProps> = ({
209210
onClose={() => setConfiguringFile(null)}
210211
file={configuringFile?.file || null}
211212
onSave={handleSaveFileConfig}
212-
t={t}
213+
t={translate}
213214
isGemini3={isGemini3}
214215
/>
215216
</>

0 commit comments

Comments
 (0)