-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathllm.dev.txt
More file actions
1248 lines (1024 loc) · 36.5 KB
/
llm.dev.txt
File metadata and controls
1248 lines (1024 loc) · 36.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# LiteChat Developer Guide - LLM Context
## Architecture Overview
LiteChat is a modular, event-driven React application built with TypeScript, featuring a sophisticated plugin system and 100% client-side architecture. The core principle is modularity through Control Modules with event-driven communication.
### Core Technologies
- **Frontend**: React 19, TypeScript, Tailwind CSS, shadcn/ui
- **State Management**: Zustand with Immer middleware
- **Database**: Dexie.js (IndexedDB wrapper)
- **Virtual File System**: ZenFS with IndexedDB backend
- **Git Operations**: isomorphic-git for browser-based Git
- **AI Integration**: Vercel AI SDK with multiple providers
- **Event System**: mitt event emitter for decoupled communication
- **Build System**: Vite with TypeScript
- **Forms**: TanStack Form with Zod validation
### Key Architectural Principles
1. **100% Client-Side**: No server dependencies, all data in IndexedDB
2. **Control Module System**: UI features as pluggable modules
3. **Event-Driven Communication**: Decoupled via mitt event emitter
4. **Immutable State**: Zustand + Immer for safe mutations
5. **Type Safety**: Comprehensive TypeScript coverage
6. **Controlled Extensibility**: Safe modding API for extensions
7. **Universal Block Rendering**: Extensible code block system
8. **Canvas Control Integration**: Contextual UI controls for interactions
## Project Structure
```
src/
├── components/ # React components
│ ├── LiteChat/ # Main application components
│ │ ├── canvas/ # Chat canvas and interaction display
│ │ ├── chat/ # Chat controls and UI
│ │ ├── common/ # Shared components (UniversalBlockRenderer, etc.)
│ │ ├── file-manager/ # VFS file management
│ │ └── prompt/ # Prompt input area
│ └── ui/ # shadcn/ui components
├── controls/ # Control Module system
│ ├── modules/ # Control Module implementations
│ │ ├── canvas/ # Canvas interaction modules
│ │ └── example/ # Example modules for reference
│ └── components/ # Module-specific components
├── hooks/ # React hooks
│ ├── litechat/ # LiteChat-specific hooks
│ ├── use-formedible.tsx # TanStack Form abstraction (DO NOT USE react-hook-form)
│ └── use-prompt-compilation.tsx # Template compilation hook
├── lib/ # Core libraries and utilities
│ └── litechat/ # Core LiteChat functionality
├── modding/ # Modding system implementation
├── services/ # Business logic services
│ ├── ai.service.ts # AI integration and streaming
│ ├── block-renderer.service.ts # Universal block rendering
│ ├── persistence.service.ts # Database operations
│ └── conversation.service.ts # Conversation management
├── store/ # Zustand state stores
├── types/ # TypeScript type definitions
│ └── litechat/ # LiteChat-specific types
│ ├── events/ # Event definitions
│ ├── canvas/ # Canvas and block renderer types
│ └── middleware/ # Middleware types
├── App.tsx # Module registration and app setup
└── main.tsx # Application entry point
```
## Control Module System
The Control Module System is LiteChat's core architectural pattern. Each UI feature is implemented as a `ControlModule` that manages its own state and components.
### ControlModule Interface
```typescript
interface ControlModule {
readonly id: string;
readonly dependencies?: string[];
initialize(modApi: LiteChatModApi): Promise<void>;
register(modApi: LiteChatModApi): void;
destroy(modApi: LiteChatModApi): void;
}
```
### Module Lifecycle
1. **Instantiation**: Modules instantiated from constructors in `App.tsx`
2. **Dependency Resolution**: Topological sort based on dependencies
3. **Initialization**: `initialize()` called for setup and event subscriptions
4. **Registration**: `register()` called to register UI components/tools
5. **Destruction**: `destroy()` called for cleanup
### Module Types
#### Settings Modules
Register settings tabs in the main settings interface:
```typescript
export class GeneralSettingsModule implements ControlModule {
readonly id = "core-settings-general";
register(modApi: LiteChatModApi): void {
this.unregisterCallback = modApi.registerSettingsTab({
id: "general",
title: "General",
component: SettingsGeneral,
order: 10,
});
}
}
```
#### Prompt Control Modules
Add UI elements to the prompt input area:
```typescript
export class ParameterControlModule implements ControlModule {
private turnEnabled = false;
private temperature: number | null = null;
register(modApi: LiteChatModApi): void {
this.unregisterCallback = modApi.registerPromptControl({
id: this.id,
triggerRenderer: () => React.createElement(ParameterControlTrigger, { module: this }),
getMetadata: () => this.turnEnabled ? {
temperature: this.temperature,
parametersEnabled: this.turnEnabled,
} : undefined,
clearOnSubmit: () => {
this.turnEnabled = false;
this.notifyComponentUpdate?.();
},
});
}
}
```
#### Chat Control Modules
Add UI to chat areas (sidebar, header, modals):
```typescript
export class ConversationListControlModule implements ControlModule {
register(modApi: LiteChatModApi): void {
this.unregisterCallback = modApi.registerChatControl({
id: this.id,
panel: "sidebar",
component: ConversationListComponent,
moduleInstance: this,
});
}
}
```
#### Tool Modules
Register AI tools available during conversations:
```typescript
export class VfsToolsModule implements ControlModule {
register(modApi: LiteChatModApi): void {
this.unregisterCallbacks.push(
modApi.registerTool("vfs_read_file", readFileToolDefinition, readFileImplementation),
modApi.registerTool("vfs_write_file", writeFileToolDefinition, writeFileImplementation),
modApi.registerTool("vfs_create_directory", createDirectoryToolDefinition, createDirectoryImplementation),
// ... more tools
);
}
}
```
#### Canvas Control Modules
Handle interactions within chat canvas:
```typescript
export class CopyActionControlModule implements ControlModule {
register(modApi: LiteChatModApi): void {
this.unregisterCallback = modApi.registerCanvasControl({
id: this.id,
type: "interaction",
placement: "header",
component: CopyActionComponent,
moduleInstance: this,
showCondition: (context) => {
// Only show for completed interactions
return context.interaction.status === "COMPLETED";
}
});
}
}
```
#### Block Renderer Modules
Extend code block rendering with specialized visualizations:
```typescript
export class MermaidBlockRendererModule implements ControlModule {
register(modApi: LiteChatModApi): void {
const mermaidRenderer: BlockRenderer = {
id: this.id,
supportedLanguages: ["mermaid"],
priority: 10,
renderer: (context: BlockRendererContext) => {
return React.createElement(MermaidBlockRenderer, {
code: context.code,
isStreaming: context.isStreaming,
});
},
};
this.unregisterCallback = modApi.registerBlockRenderer(mermaidRenderer);
}
}
```
### Module Registration in App.tsx
All modules must be registered in the `controlModulesToRegister` array:
```typescript
const controlModulesToRegister: ControlModuleConstructor[] = [
UrlParameterControlModule,
GeneralSettingsModule,
ThemeSettingsControlModule,
// Block renderers should be registered early for proper initialization
CodeBlockRendererModule,
MermaidBlockRendererModule,
FormedibleBlockRendererModule,
FlowBlockRendererModule,
// ... order matters for dependencies
];
```
## Universal Block Renderer System
LiteChat features an extensible Block Renderer System that allows custom rendering of code blocks based on language.
### Core Components
1. **BlockRenderer Interface**: Defines how to render specific languages
2. **BlockRendererService**: Manages renderer selection and execution
3. **UniversalBlockRenderer**: Main component that routes to appropriate renderers
4. **Control Modules**: Register language-specific renderers
### Block Renderer Interface
```typescript
interface BlockRenderer {
id: string;
supportedLanguages?: string[]; // ["mermaid"], ["js", "typescript"], etc.
priority?: number; // Higher priority wins for conflicting languages
renderer: (context: BlockRendererContext) => React.ReactNode;
onMounted?: (context: BlockRendererContext & { element: HTMLElement }) => void;
onUnmounted?: (context: BlockRendererContext) => void;
}
interface BlockRendererContext {
lang: string | undefined;
code: string;
filepath?: string;
isStreaming?: boolean;
blockId?: string;
interactionId?: string;
}
```
### Renderer Selection Logic
1. **Specific Language Match**: Renderers that explicitly support the block's language
2. **Priority**: Among matching renderers, higher priority wins
3. **Fallback**: Renderers with no `supportedLanguages` serve as fallbacks
4. **Default**: Simple pre/code fallback if no renderers match
### Built-in Renderers
- **CodeBlockRendererModule**: General code with syntax highlighting (fallback, priority 0)
- **MermaidBlockRendererModule**: Mermaid diagrams (priority 10)
- **FormedibleBlockRendererModule**: Interactive forms (priority 10)
- **FlowBlockRendererModule**: React Flow diagrams (priority 10)
### Creating Custom Block Renderers
```typescript
export class CustomRendererModule implements ControlModule {
readonly id = "my-custom-renderer";
register(modApi: LiteChatModApi): void {
const customRenderer: BlockRenderer = {
id: this.id,
supportedLanguages: ["mylang", "custom"],
priority: 8,
renderer: (context: BlockRendererContext) => {
return React.createElement(MyCustomComponent, {
code: context.code,
lang: context.lang,
isStreaming: context.isStreaming,
});
},
};
this.unregisterCallback = modApi.registerBlockRenderer(customRenderer);
}
}
```
## Event System Architecture
LiteChat uses a sophisticated event-driven architecture for component communication.
### Event Emitter
Central event bus using mitt:
```typescript
import mitt, { type Emitter, type EventType } from "mitt";
import type { ModEventPayloadMap } from "@/types/litechat/modding";
export const emitter: Emitter<ModEventPayloadMap & Record<EventType, any>> =
mitt<ModEventPayloadMap & Record<EventType, any>>();
```
### Event Patterns
#### Request/Response Pattern
1. Component emits request event
2. Store processes request and updates state
3. Store emits change notification event
```typescript
// 1. Request theme change
emitter.emit(settingsEvent.setThemeRequest, { theme: "dark" });
// 2. SettingsStore processes and updates state
// (handled automatically by EventActionCoordinatorService)
// 3. Store emits change notification
emitter.emit(settingsEvent.themeChanged, { theme: "dark" });
```
### Event Categories
#### State Change Events
Notify that state has changed:
```typescript
export const settingsEvent = {
themeChanged: "settings.theme.changed",
temperatureChanged: "settings.temperature.changed",
autoTitleEnabledChanged: "settings.auto.title.enabled.changed",
// ...
};
```
#### Action Request Events
Request that an action be performed:
```typescript
export const settingsEvent = {
setThemeRequest: "settings.set.theme.request",
setTemperatureRequest: "settings.set.temperature.request",
loadSettingsRequest: "settings.load.settings.request",
// ...
};
```
### Event Type Safety
All events are strongly typed through `ModEventPayloadMap`:
```typescript
export interface ModEventPayloadMap extends
SettingsEventPayloads,
ProviderEventPayloads,
ConversationEventPayloads,
InteractionEventPayloads,
ProjectEventPayloads,
VfsEventPayloads,
UiEventPayloads,
GitEventPayloads,
PromptEventPayloads,
BlockRendererEventPayloads,
McpEventPayloads
{}
interface SettingsEventPayloads {
[settingsEvent.themeChanged]: { theme: string };
[settingsEvent.setThemeRequest]: { theme: string };
[settingsEvent.temperatureChanged]: { temperature: number };
// ... all event payloads
}
```
## State Management with Zustand
LiteChat uses Zustand for state management with domain-specific stores.
### Store Structure Pattern
```typescript
export const useExampleStore = create(
immer<ExampleState & ExampleActions>((set, get) => ({
// State properties
data: [],
loading: false,
error: null,
// Action methods
loadData: async () => {
set((state) => {
state.loading = true;
state.error = null;
});
try {
const data = await SomeService.loadData();
set((state) => {
state.data = data;
state.loading = false;
});
// Emit change event
emitter.emit(exampleEvent.dataLoaded, { data });
} catch (error) {
set((state) => {
state.error = error.message;
state.loading = false;
});
emitter.emit(exampleEvent.loadFailed, { error: error.message });
}
},
// Event integration
getRegisteredActionHandlers: (): RegisteredActionHandler[] => {
const actions = get();
return [
{
eventName: exampleEvent.loadDataRequest,
handler: () => actions.loadData(),
storeId: "exampleStore",
},
];
},
}))
);
```
### Key Stores
#### ConversationStore (`src/store/conversation.store.ts`)
- Manages conversations, projects, selection state
- Handles Git sync repositories and conversation linking
- Coordinates with InteractionStore for message loading
- Provides `selectedItemId` and `selectedItemType` for context
#### InteractionStore (`src/store/interaction.store.ts`)
- Manages messages/interactions for current conversation
- Handles streaming state and response buffers
- Coordinates with AI services for real-time updates
- Tracks parent-child relationships for race conditions/regeneration
- Methods: `promoteChildToParent`, `appendInteractionResponseChunk`
#### ProviderStore (`src/store/provider.store.ts`)
- Manages AI provider configurations and API keys
- Handles model fetching and selection
- Provides enabled models across all providers
- Integrates with AI SDK for multiple provider support
#### SettingsStore (`src/store/settings.store.ts`)
- Global application settings (theme, AI parameters, Git config)
- Auto-title configuration (`autoTitleEnabled`, `autoTitleAlwaysOn`, `autoTitleModelId`)
- Form-related settings with TanStack Form integration
- Control rule preferences (`controlRuleAlwaysOn: Record<string, boolean>`)
- Git user configuration (`gitUserName`, `gitUserEmail`)
- Persistence through PersistenceService
#### VfsStore (`src/store/vfs.store.ts`)
- Virtual File System state for current context
- File/folder tree management with parent-child relationships
- Context switching between projects (`vfsKey`)
- Integration with ZenFS and IndexedDB backend
#### ProjectStore (`src/store/project.store.ts`)
- Project hierarchy and settings inheritance
- Effective settings calculation with cascading
- Path-based project organization
- Default rules and tags per project
#### PromptTemplateStore (`src/store/prompt-template.store.ts`)
- Manages prompt templates, agents (`type: "agent"`), and tasks (`type: "task"`)
- Handles compilation of templates with form data and variable substitution
- Integration with TanStack Form for template editing
- Auto-selection of tools, rules, and tags in templates
#### McpStore (`src/store/mcp.store.ts`)
- Manages MCP server configurations and connection status
- Bridge configuration for stdio MCP servers (`bridgeConfig`)
- Retry settings and connection timeouts
- Server status tracking and tool discovery
- Tool response size configuration (`maxResponseSize`)
#### ControlRegistryStore (`src/store/control.store.ts`)
- Central registry for all Control Module registrations
- Block renderers registry (`blockRenderers: Record<string, BlockRenderer>`)
- Prompt controls, canvas controls, chat controls
- Control rules from modules (separate from user rules)
#### RulesStore (`src/store/rules.store.ts`)
- User-defined rules and tags
- Rule-tag associations
- Always-on rule management
- Integration with prompt compilation
### Event Action Coordinator
The `EventActionCoordinatorService` automatically connects events to store actions:
```typescript
export class EventActionCoordinatorService {
public static initialize(): void {
const storesWithActionHandlers = [
useSettingsStore,
useProviderStore,
useConversationStore,
usePromptTemplateStore,
useMcpStore,
useRulesStore,
// ... all stores
];
storesWithActionHandlers.forEach((storeHook) => {
const handlers = storeHook.getState().getRegisteredActionHandlers();
handlers.forEach((handler) => {
emitter.on(handler.eventName, handler.handler);
});
});
}
}
```
## Virtual File System Architecture
LiteChat implements a browser-based Virtual File System using ZenFS with IndexedDB backend.
### VFS Context Switching
VFS operates with different contexts:
- **Project VFS**: `vfsKey = projectId` - Project-specific filesystem
- **Orphan VFS**: `vfsKey = "orphan"` - For conversations without projects
- **Sync VFS**: `vfsKey = "sync_repos"` - For Git repositories
### VFS Operations (`src/lib/litechat/vfs-operations.ts`)
Core filesystem operations:
```typescript
// Initialize VFS for specific context
export const initializeFsOp = async (vfsKey: string): Promise<typeof fs | null> => {
const vfsConf = {
backend: IndexedDB,
name: `litechat_vfs_${vfsKey}`,
};
await configureSingle(vfsConf);
return fs;
};
// File operations (all run through VFS worker for performance)
export const writeFileOp = async (path: string, content: ArrayBuffer): Promise<void>;
export const readFileOp = async (path: string): Promise<ArrayBuffer>;
export const deleteItemOp = async (path: string, recursive?: boolean): Promise<void>;
export const createDirectoryOp = async (path: string): Promise<void>;
export const listFilesOp = async (path: string): Promise<FileSystemEntry[]>;
```
### VFS Store Integration
The VfsStore manages VFS state and coordinates operations:
```typescript
interface VfsState {
nodes: Record<string, VfsNode>; // File/folder tree
childrenMap: Record<string, string[]>; // Parent-child relationships
rootId: string | null; // Root directory node ID
currentParentId: string | null;
selectedFileIds: Set<string>; // Selected files
fs: typeof fs | null; // ZenFS instance
vfsKey: string | null; // Current VFS context
configuredVfsKey: string | null; // Active VFS context
}
```
## AI Integration Architecture
LiteChat provides comprehensive AI integration through the Vercel AI SDK with support for multiple providers and advanced features.
### Provider Support
Supported AI providers:
- **OpenAI**: GPT models with function calling, vision, reasoning, structured output
- **Google Gemini**: Gemini Pro with multimodal capabilities
- **Anthropic Claude**: Via OpenAI-compatible interface with reasoning support
- **OpenRouter**: Access to 100+ models
- **Local Providers**: Ollama, LMStudio, OpenAI-compatible APIs
### AI Service Layer (`src/services/ai.service.ts`)
```typescript
export class AIService {
static async executeInteraction(
interactionId: string,
payload: StreamingInteractionPayload,
callbacks: StreamingCallbacks
): Promise<void> {
const model = await createModelFromConfig(payload.modelConfig);
const result = await streamText({
model,
messages: payload.messages,
tools: payload.tools,
maxTokens: payload.maxTokens,
temperature: payload.temperature,
experimental_providerMetadata: payload.providerMetadata,
// ... other parameters
});
// Process stream parts with proper error handling
for await (const part of result.fullStream) {
switch (part.type) {
case "text-delta":
callbacks.onChunk(part.textDelta);
break;
case "tool-call":
callbacks.onToolCall(part);
break;
case "tool-result":
callbacks.onToolResult(part);
break;
case "finish":
callbacks.onFinish({
finishReason: part.finishReason,
usage: part.usage,
});
break;
case "error":
callbacks.onError(part.error);
break;
}
}
}
}
```
### Tool System
AI tools are registered by Control Modules and support advanced features:
```typescript
// Tool definition with Zod schema
const readFileToolDefinition = {
description: "Read contents of a file from the virtual file system",
parameters: z.object({
path: z.string().describe("The path to the file to read"),
}),
};
// Tool implementation with context
const readFileImplementation = async (
{ path }: { path: string },
context: ToolExecutionContext
): Promise<ToolResult> => {
try {
const content = await readFileOp(path);
const textContent = new TextDecoder().decode(content);
return {
success: true,
content: textContent,
};
} catch (error) {
return {
success: false,
error: error.message,
};
}
};
```
### Streaming Management
Real-time response streaming with sophisticated buffer management:
```typescript
interface InteractionState {
activeStreamBuffers: Record<string, string>; // Main response content
activeReasoningBuffers: Record<string, string>; // Reasoning content (Claude, etc.)
streamingInteractionIds: string[]; // Active streams
status: "idle" | "streaming" | "completed" | "error";
}
// Stream processing with race condition handling
appendInteractionResponseChunk: (id: string, chunk: string) => {
set((state) => {
if (!state.activeStreamBuffers[id]) {
state.activeStreamBuffers[id] = "";
}
state.activeStreamBuffers[id] += chunk;
});
};
```
## MCP (Model Context Protocol) Integration
LiteChat provides comprehensive MCP integration with multiple transport protocols and flexible deployment options.
### Supported Transport Protocols
1. **Streamable HTTP (MCP 2025-03-26)** - Primary
- Latest MCP specification with enhanced features
- Session management and security improvements
- Single endpoint design with better error handling
2. **Stdio Transport** - Local/Remote Servers
- Via LiteChat MCP Bridge service
- Supports local and remote bridge deployments
- Process management and secure proxy functionality
3. **SSE Transport** - Legacy Compatibility
- Backwards compatibility with older MCP implementations
- Automatic fallback when newer protocols fail
### Bridge Configuration
The MCP Bridge supports flexible deployment scenarios:
```typescript
interface McpBridgeConfig {
url?: string; // Full URL: http://192.168.1.100:3001
host?: string; // Host only: 192.168.1.100
port?: number; // Port only: 3001
}
// Auto-detection fallback: localhost ports 3001, 8080, 3000, 8000
```
### MCP Server Configuration
```typescript
interface McpServerConfig {
id: string;
name: string;
url: string; // HTTP/HTTPS or stdio:// URLs
description?: string;
headers?: Record<string, string>;
enabled: boolean;
}
```
### Tool Integration
MCP tools are registered as individual tools in the tool selector:
```typescript
// Tools are prefixed with server name for identification
const toolName = `mcp_${serverId}_${originalToolName}`;
// Each tool can be toggled independently
this.unregisterCallback = modApi.registerTool(
toolName,
toolDefinition,
toolImplementation
);
```
## Git Integration
LiteChat provides browser-based Git operations using isomorphic-git with comprehensive sync capabilities.
### Git Operations (`src/lib/litechat/vfs-git-operations.ts`)
```typescript
// Clone repository with authentication
export const cloneRepoOp = async (
url: string,
dir: string,
auth?: GitAuth,
options?: { fsInstance?: typeof fs }
): Promise<void> => {
await git.clone({
fs: options?.fsInstance ?? fs,
http,
dir: normalizePath(dir),
url,
...getAuthConfig(auth),
});
};
// Commit with proper author configuration
export const commitOp = async (
message: string,
options?: GitOperationOptions
): Promise<string> => {
return await git.commit({
fs: options?.fsInstance ?? fs,
dir: "/",
message,
author: {
name: options?.author?.name ?? "LiteChat User",
email: options?.author?.email ?? "user@litechat.local",
},
});
};
```
### Conversation Sync
Conversations are synced as JSON files in repositories:
```
repository/
├── .litechat/
│ └── conversations/
│ ├── conv-123.json
│ ├── conv-456.json
│ └── metadata.json
```
### Git Tools for AI
Git operations available as AI tools through GitToolsModule:
```typescript
export class GitToolsModule implements ControlModule {
register(modApi: LiteChatModApi): void {
this.unregisterCallbacks.push(
modApi.registerTool("git_status", gitStatusTool, gitStatusImplementation),
modApi.registerTool("git_add", gitAddTool, gitAddImplementation),
modApi.registerTool("git_commit", gitCommitTool, gitCommitImplementation),
modApi.registerTool("git_push", gitPushTool, gitPushImplementation),
modApi.registerTool("git_pull", gitPullTool, gitPullImplementation),
);
}
}
```
## Form System Architecture
LiteChat uses TanStack Form exclusively with a strict abstraction layer.
### Form Hook Pattern
**CRITICAL**: Always use `use-formedible.tsx` abstraction, never `react-hook-form`:
```typescript
// ✅ CORRECT: Use TanStack Form via abstraction
import { useFormedible } from "@/hooks/use-formedible";
const MyComponent = () => {
const form = useFormedible({
defaultValues: { name: "", email: "" },
validators: {
onChange: z.object({
name: z.string().min(1),
email: z.string().email(),
})
},
onSubmit: async ({ value }) => {
await saveData(value);
},
});
return (
<form onSubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>
<form.Field name="name" children={(field) => (
<Input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
/>
)} />
</form>
);
};
```
### Settings Form Pattern
Settings forms follow a consistent pattern with event integration:
```typescript
// Settings form with store integration
const form = useForm({
defaultValues: {
autoTitleEnabled: settings.autoTitleEnabled ?? false,
autoTitleModelId: settings.autoTitleModelId ?? null,
},
validators: { onChange: settingsSchema },
onSubmit: async ({ value }) => {
// Use events, not direct store calls
emitter.emit(settingsEvent.setAutoTitleEnabledRequest, {
enabled: value.autoTitleEnabled
});
},
});
// Reset form when store changes
useEffect(() => {
form.reset({
autoTitleEnabled: settings.autoTitleEnabled ?? false,
autoTitleModelId: settings.autoTitleModelId ?? null,
});
}, [settings.autoTitleEnabled, settings.autoTitleModelId, form]);
```
## Modding System
LiteChat provides a secure modding system allowing external extensions while maintaining system integrity.
### LiteChatModApi Interface
Controlled API for mod interactions:
```typescript
interface LiteChatModApi {
readonly modId: string;
readonly modName: string;
// Component Registration
registerPromptControl(control: ModPromptControl): () => void;
registerChatControl(control: ModChatControl): () => void;
registerCanvasControl(control: ModCanvasControl): () => void;
registerSettingsTab(tab: CustomSettingTab): () => void;
registerBlockRenderer(renderer: BlockRenderer): () => void;
// Tool Registration
registerTool<T extends z.ZodSchema>(
name: string,
tool: Tool<T>,
implementation: ToolImplementation<T>
): () => void;
// Rule Registration (Control Rules)
registerRule(rule: ModControlRule): () => void;
// Event System
on<K extends keyof ModEventPayloadMap>(
eventName: K,
handler: (payload: ModEventPayloadMap[K]) => void
): () => void;
emit<K extends keyof ModEventPayloadMap>(
eventName: K,
payload: ModEventPayloadMap[K]
): void;
// Context and Utilities
getContext(): ModApiContext;
getContextSnapshot(): ModApiContextSnapshot;
log(level: 'info' | 'warn' | 'error', message: string, ...args: any[]): void;
toast(message: string, options?: ToastOptions): void;
}
```
### Mod Creation Pattern
```typescript
function createMyMod(modApi: LiteChatModApi) {
let internalState = { enabled: true };
// Register components with proper cleanup
const unregisterControl = modApi.registerPromptControl({
id: 'my-control',
triggerRenderer: () => React.createElement(MyControlComponent, { modApi }),
getMetadata: () => ({ customFlag: internalState.enabled }),
clearOnSubmit: () => {
internalState.enabled = false;
},
});
// Subscribe to events with proper cleanup
const unregisterEvent = modApi.on('conversation.selected.item.changed', (payload) => {
modApi.log('info', 'Conversation changed:', payload.itemId);
});
// Cleanup function - CRITICAL for proper module lifecycle
return () => {
unregisterControl();
unregisterEvent();
};
}
```
## Development Patterns
### Adding New Control Modules
1. **Create Module Class**:
```typescript
export class MyControlModule implements ControlModule {
readonly id = "my-module";
readonly dependencies = ["some-dependency"]; // Optional dependencies
private unregisterCallback: (() => void) | null = null;
private eventUnsubscribers: (() => void)[] = [];
private modApiRef: LiteChatModApi | null = null;
async initialize(modApi: LiteChatModApi): Promise<void> {
this.modApiRef = modApi;