tabby-ai-assistant 1.0.12 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.editorconfig +18 -0
  2. package/README.md +113 -55
  3. package/dist/index.js +1 -1
  4. package/package.json +6 -4
  5. package/src/components/chat/ai-sidebar.component.scss +220 -9
  6. package/src/components/chat/ai-sidebar.component.ts +364 -29
  7. package/src/components/chat/chat-input.component.ts +36 -4
  8. package/src/components/chat/chat-interface.component.ts +225 -5
  9. package/src/components/chat/chat-message.component.ts +6 -1
  10. package/src/components/settings/context-settings.component.ts +91 -91
  11. package/src/components/terminal/ai-toolbar-button.component.ts +4 -2
  12. package/src/components/terminal/command-suggestion.component.ts +148 -6
  13. package/src/index.ts +0 -6
  14. package/src/providers/tabby/ai-toolbar-button.provider.ts +7 -3
  15. package/src/services/chat/ai-sidebar.service.ts +414 -410
  16. package/src/services/chat/chat-session.service.ts +36 -12
  17. package/src/services/context/compaction.ts +110 -134
  18. package/src/services/context/manager.ts +27 -7
  19. package/src/services/context/memory.ts +17 -33
  20. package/src/services/context/summary.service.ts +136 -0
  21. package/src/services/core/ai-assistant.service.ts +1060 -37
  22. package/src/services/core/ai-provider-manager.service.ts +154 -25
  23. package/src/services/core/checkpoint.service.ts +218 -18
  24. package/src/services/core/config-provider.service.ts +4 -12
  25. package/src/services/core/toast.service.ts +106 -106
  26. package/src/services/providers/anthropic-provider.service.ts +126 -202
  27. package/src/services/providers/base-provider.service.ts +315 -21
  28. package/src/services/providers/glm-provider.service.ts +151 -233
  29. package/src/services/providers/minimax-provider.service.ts +55 -238
  30. package/src/services/providers/ollama-provider.service.ts +117 -188
  31. package/src/services/providers/openai-compatible.service.ts +165 -177
  32. package/src/services/providers/openai-provider.service.ts +170 -177
  33. package/src/services/providers/vllm-provider.service.ts +116 -188
  34. package/src/services/terminal/terminal-context.service.ts +265 -5
  35. package/src/services/terminal/terminal-manager.service.ts +748 -748
  36. package/src/services/terminal/terminal-tools.service.ts +612 -441
  37. package/src/types/ai.types.ts +156 -3
  38. package/src/types/provider.types.ts +206 -75
  39. package/src/utils/cost.utils.ts +249 -0
  40. package/src/utils/validation.utils.ts +306 -2
  41. package/dist/index.js.LICENSE.txt +0 -18
  42. package/src/index.ts.backup +0 -165
  43. package/src/services/chat/chat-history.service.ts.backup +0 -239
  44. package/src/services/terminal/command-analyzer.service.ts +0 -43
  45. package/src/services/terminal/context-menu.service.ts +0 -45
  46. package/src/services/terminal/hotkey.service.ts +0 -53
  47. package/webpack.config.js.backup +0 -57
@@ -1,165 +0,0 @@
1
- import { NgModule } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
5
-
6
- // Tabby modules
7
- import TabbyCoreModule, { ToolbarButtonProvider, ConfigProvider, HotkeyProvider } from 'tabby-core';
8
- import TabbyTerminalModule from 'tabby-terminal';
9
- import { SettingsTabProvider } from 'tabby-settings';
10
-
11
- // Core Services
12
- import { AiAssistantService } from './services/core/ai-assistant.service';
13
- import { AiProviderManagerService } from './services/core/ai-provider-manager.service';
14
- import { ConfigProviderService } from './services/core/config-provider.service';
15
- import { LoggerService } from './services/core/logger.service';
16
-
17
- // Providers
18
- import { BaseAiProvider } from './services/providers/base-provider.service';
19
- import { OpenAiProviderService } from './services/providers/openai-provider.service';
20
- import { AnthropicProviderService } from './services/providers/anthropic-provider.service';
21
- import { MinimaxProviderService } from './services/providers/minimax-provider.service';
22
- import { GlmProviderService } from './services/providers/glm-provider.service';
23
- import { OpenAiCompatibleProviderService } from './services/providers/openai-compatible.service';
24
-
25
- // Security Services
26
- import { SecurityValidatorService } from './services/security/security-validator.service';
27
- import { RiskAssessmentService } from './services/security/risk-assessment.service';
28
- import { PasswordManagerService } from './services/security/password-manager.service';
29
- import { ConsentManagerService } from './services/security/consent-manager.service';
30
-
31
- // Chat Services
32
- import { ChatSessionService } from './services/chat/chat-session.service';
33
- import { ChatHistoryService } from './services/chat/chat-history.service';
34
- import { CommandGeneratorService } from './services/chat/command-generator.service';
35
-
36
- // Terminal Services
37
- import { CommandAnalyzerService } from './services/terminal/command-analyzer.service';
38
- import { ContextMenuService } from './services/terminal/context-menu.service';
39
- import { HotkeyService } from './services/terminal/hotkey.service';
40
-
41
- // Tabby Providers (enabled for proper integration)
42
-
43
- // Components
44
- import { ChatInterfaceComponent } from './components/chat/chat-interface.component';
45
- import { ChatMessageComponent } from './components/chat/chat-message.component';
46
- import { ChatInputComponent } from './components/chat/chat-input.component';
47
- import { ChatSettingsComponent } from './components/chat/chat-settings.component';
48
-
49
- import { AiSettingsTabComponent } from './components/settings/ai-settings-tab.component';
50
- import { ProviderConfigComponent } from './components/settings/provider-config.component';
51
- import { SecuritySettingsComponent } from './components/settings/security-settings.component';
52
- import { GeneralSettingsComponent } from './components/settings/general-settings.component';
53
-
54
- import { RiskConfirmDialogComponent } from './components/security/risk-confirm-dialog.component';
55
- import { PasswordPromptComponent } from './components/security/password-prompt.component';
56
- import { ConsentDialogComponent } from './components/security/consent-dialog.component';
57
-
58
- import { CommandSuggestionComponent } from './components/terminal/command-suggestion.component';
59
- import { CommandPreviewComponent } from './components/terminal/command-preview.component';
60
- import { AiToolbarButtonComponent } from './components/terminal/ai-toolbar-button.component';
61
-
62
- import { LoadingSpinnerComponent } from './components/common/loading-spinner.component';
63
- import { ErrorMessageComponent } from './components/common/error-message.component';
64
-
65
- // Tabby Integration Providers (enabled for proper integration)
66
- import { AiToolbarButtonProvider } from './providers/tabby/ai-toolbar-button.provider';
67
- import { AiSettingsTabProvider } from './providers/tabby/ai-settings-tab.provider';
68
- import { AiConfigProvider } from './providers/tabby/ai-config.provider';
69
- import { AiHotkeyProvider } from './providers/tabby/ai-hotkey.provider';
70
-
71
- @NgModule({
72
- imports: [
73
- CommonModule,
74
- FormsModule,
75
- TabbyCoreModule, // Enabled for Tabby integration
76
- TabbyTerminalModule, // Required for terminal integration
77
- NgbModule
78
- ],
79
- providers: [
80
- // Core Services
81
- AiAssistantService,
82
- AiProviderManagerService,
83
- ConfigProviderService,
84
- LoggerService,
85
-
86
- // AI Providers
87
- OpenAiProviderService,
88
- AnthropicProviderService,
89
- MinimaxProviderService,
90
- GlmProviderService,
91
- OpenAiCompatibleProviderService,
92
-
93
- // Security Services
94
- SecurityValidatorService,
95
- RiskAssessmentService,
96
- PasswordManagerService,
97
- ConsentManagerService,
98
-
99
- // Chat Services
100
- ChatSessionService,
101
- ChatHistoryService,
102
- CommandGeneratorService,
103
-
104
- // Terminal Services
105
- CommandAnalyzerService,
106
- ContextMenuService,
107
- HotkeyService,
108
-
109
- // Tabby Integration Providers (enabled for proper integration)
110
- { provide: ToolbarButtonProvider, useClass: AiToolbarButtonProvider, multi: true },
111
- { provide: SettingsTabProvider, useClass: AiSettingsTabProvider, multi: true },
112
- { provide: ConfigProvider, useClass: AiConfigProvider, multi: true },
113
- { provide: HotkeyProvider, useClass: AiHotkeyProvider, multi: true },
114
- // { provide: TabContextMenuItemProvider, useClass: AiContextMenuProvider, multi: true }
115
- ],
116
- declarations: [
117
- // Chat Components
118
- ChatInterfaceComponent,
119
- ChatMessageComponent,
120
- ChatInputComponent,
121
- ChatSettingsComponent,
122
-
123
- // Settings Components
124
- AiSettingsTabComponent,
125
- ProviderConfigComponent,
126
- SecuritySettingsComponent,
127
- GeneralSettingsComponent,
128
-
129
- // Security Components
130
- RiskConfirmDialogComponent,
131
- PasswordPromptComponent,
132
- ConsentDialogComponent,
133
-
134
- // Terminal Components
135
- CommandSuggestionComponent,
136
- CommandPreviewComponent,
137
- AiToolbarButtonComponent,
138
-
139
- // Common Components
140
- LoadingSpinnerComponent,
141
- ErrorMessageComponent
142
- ],
143
- entryComponents: [
144
- ChatInterfaceComponent,
145
- RiskConfirmDialogComponent,
146
- PasswordPromptComponent,
147
- ConsentDialogComponent,
148
- CommandSuggestionComponent,
149
- CommandPreviewComponent
150
- ]
151
- })
152
- export default class AiAssistantModule {
153
- constructor(
154
- private app: any,
155
- private aiService: AiAssistantService,
156
- private config: ConfigProviderService
157
- ) {
158
- // Wait for Tabby to be ready
159
- if (this.app && this.app.ready$) {
160
- this.app.ready$.subscribe(() => {
161
- this.aiService.initialize();
162
- });
163
- }
164
- }
165
- }
@@ -1,239 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { BehaviorSubject, Observable } from 'rxjs';
3
- import { ChatMessage } from '../../types/ai.types';
4
- import { LoggerService } from '../core/logger.service';
5
-
6
- export interface SavedSession {
7
- sessionId: string;
8
- title: string;
9
- messages: ChatMessage[];
10
- createdAt: Date;
11
- updatedAt: Date;
12
- messageCount: number;
13
- }
14
-
15
- const STORAGE_KEY = 'tabby-ai-assistant-chat-history';
16
- const MAX_SESSIONS = 50;
17
- const MAX_MESSAGES_PER_SESSION = 1000;
18
-
19
- /**
20
- * 聊天历史服务
21
- * 持久化存储和管理聊天会话历史
22
- */
23
- @Injectable({
24
- providedIn: 'root'
25
- })
26
- export class ChatHistoryService {
27
- private sessionsSubject = new BehaviorSubject<SavedSession[]>([]);
28
- public sessions$ = this.sessionsSubject.asObservable();
29
-
30
- constructor(private logger: LoggerService) {
31
- this.loadSessions();
32
- }
33
-
34
- /**
35
- * 保存会话
36
- */
37
- saveSession(sessionId: string, messages: ChatMessage[], title?: string): void {
38
- try {
39
- const sessions = this.sessionsSubject.value;
40
- const existingIndex = sessions.findIndex(s => s.sessionId === sessionId);
41
-
42
- const sessionTitle = title || this.generateSessionTitle(messages);
43
- const now = new Date();
44
-
45
- const session: SavedSession = {
46
- sessionId,
47
- title: sessionTitle,
48
- messages: this.trimMessages(messages),
49
- createdAt: existingIndex >= 0 ? sessions[existingIndex].createdAt : now,
50
- updatedAt: now,
51
- messageCount: messages.length
52
- };
53
-
54
- if (existingIndex >= 0) {
55
- sessions[existingIndex] = session;
56
- } else {
57
- sessions.unshift(session);
58
- }
59
-
60
- // 限制会话数量
61
- const trimmedSessions = sessions.slice(0, MAX_SESSIONS);
62
- this.sessionsSubject.next(trimmedSessions);
63
- this.saveToStorage(trimmedSessions);
64
-
65
- this.logger.info('Session saved', { sessionId, title: sessionTitle });
66
-
67
- } catch (error) {
68
- this.logger.error('Failed to save session', { error, sessionId });
69
- throw error;
70
- }
71
- }
72
-
73
- /**
74
- * 加载会话
75
- */
76
- loadSession(sessionId: string): SavedSession | undefined {
77
- const sessions = this.sessionsSubject.value;
78
- return sessions.find(s => s.sessionId === sessionId);
79
- }
80
-
81
- /**
82
- * 删除会话
83
- */
84
- deleteSession(sessionId: string): void {
85
- const sessions = this.sessionsSubject.value;
86
- const filteredSessions = sessions.filter(s => s.sessionId !== sessionId);
87
- this.sessionsSubject.next(filteredSessions);
88
- this.saveToStorage(filteredSessions);
89
- this.logger.info('Session deleted', { sessionId });
90
- }
91
-
92
- /**
93
- * 清空所有历史
94
- */
95
- clearAllHistory(): void {
96
- this.sessionsSubject.next([]);
97
- this.saveToStorage([]);
98
- this.logger.info('All chat history cleared');
99
- }
100
-
101
- /**
102
- * 搜索会话
103
- */
104
- searchSessions(query: string): SavedSession[] {
105
- const sessions = this.sessionsSubject.value;
106
- const lowercaseQuery = query.toLowerCase();
107
-
108
- return sessions.filter(session =>
109
- session.title.toLowerCase().includes(lowercaseQuery) ||
110
- session.messages.some(msg =>
111
- msg.content.toLowerCase().includes(lowercaseQuery)
112
- )
113
- );
114
- }
115
-
116
- /**
117
- * 获取最近的会话
118
- */
119
- getRecentSessions(count: number = 10): SavedSession[] {
120
- const sessions = this.sessionsSubject.value;
121
- return sessions.slice(0, count);
122
- }
123
-
124
- /**
125
- * 获取会话统计
126
- */
127
- getStatistics(): {
128
- totalSessions: number;
129
- totalMessages: number;
130
- averageMessagesPerSession: number;
131
- oldestSession?: Date;
132
- newestSession?: Date;
133
- } {
134
- const sessions = this.sessionsSubject.value;
135
- const totalSessions = sessions.length;
136
- const totalMessages = sessions.reduce((sum, s) => sum + s.messageCount, 0);
137
- const averageMessagesPerSession = totalSessions > 0 ? totalMessages / totalSessions : 0;
138
-
139
- const dates = sessions.map(s => s.createdAt.getTime());
140
- const oldestSession = dates.length > 0 ? new Date(Math.min(...dates)) : undefined;
141
- const newestSession = dates.length > 0 ? new Date(Math.max(...dates)) : undefined;
142
-
143
- return {
144
- totalSessions,
145
- totalMessages,
146
- averageMessagesPerSession: Math.round(averageMessagesPerSession * 100) / 100,
147
- oldestSession,
148
- newestSession
149
- };
150
- }
151
-
152
- /**
153
- * 导出所有历史
154
- */
155
- exportAllHistory(): string {
156
- const sessions = this.sessionsSubject.value;
157
- const exportData = {
158
- exportDate: new Date().toISOString(),
159
- version: '1.0',
160
- sessions
161
- };
162
- return JSON.stringify(exportData, null, 2);
163
- }
164
-
165
- /**
166
- * 导入历史
167
- */
168
- importHistory(data: string): void {
169
- try {
170
- const importData = JSON.parse(data);
171
-
172
- if (!importData.sessions || !Array.isArray(importData.sessions)) {
173
- throw new Error('Invalid history format');
174
- }
175
-
176
- const sessions = importData.sessions.map((s: any) => ({
177
- ...s,
178
- createdAt: new Date(s.createdAt),
179
- updatedAt: new Date(s.updatedAt)
180
- }));
181
-
182
- this.sessionsSubject.next(sessions);
183
- this.saveToStorage(sessions);
184
-
185
- this.logger.info('History imported', {
186
- sessionCount: sessions.length
187
- });
188
-
189
- } catch (error) {
190
- this.logger.error('Failed to import history', error);
191
- throw new Error('Invalid history file format');
192
- }
193
- }
194
-
195
- private loadSessions(): void {
196
- try {
197
- const stored = localStorage.getItem(STORAGE_KEY);
198
- if (stored) {
199
- const sessions = JSON.parse(stored).map((s: any) => ({
200
- ...s,
201
- createdAt: new Date(s.createdAt),
202
- updatedAt: new Date(s.updatedAt)
203
- }));
204
- this.sessionsSubject.next(sessions);
205
- this.logger.info('Loaded sessions from storage', { count: sessions.length });
206
- }
207
- } catch (error) {
208
- this.logger.error('Failed to load sessions from storage', error);
209
- this.sessionsSubject.next([]);
210
- }
211
- }
212
-
213
- private saveToStorage(sessions: SavedSession[]): void {
214
- try {
215
- localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
216
- } catch (error) {
217
- this.logger.error('Failed to save sessions to storage', error);
218
- }
219
- }
220
-
221
- private generateSessionTitle(messages: ChatMessage[]): string {
222
- const firstUserMessage = messages.find(m => m.role === 'user');
223
- if (!firstUserMessage) {
224
- return `会话 ${new Date().toLocaleString()}`;
225
- }
226
-
227
- const content = firstUserMessage.content;
228
- return content.length > 50 ? content.substring(0, 50) + '...' : content;
229
- }
230
-
231
- private trimMessages(messages: ChatMessage[]): ChatMessage[] {
232
- if (messages.length <= MAX_MESSAGES_PER_SESSION) {
233
- return messages;
234
- }
235
-
236
- // 保留最近的messages
237
- return messages.slice(-MAX_MESSAGES_PER_SESSION);
238
- }
239
- }
@@ -1,43 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { Observable, of } from 'rxjs';
3
-
4
- /**
5
- * 命令分析服务
6
- * 分析终端命令并提供智能建议
7
- */
8
- @Injectable({
9
- providedIn: 'root'
10
- })
11
- export class CommandAnalyzerService {
12
- constructor() {}
13
-
14
- /**
15
- * 分析命令
16
- */
17
- analyzeCommand(command: string): Observable<any> {
18
- // TODO: 实现命令分析逻辑
19
- return of({
20
- type: 'unknown',
21
- suggestions: [],
22
- explanation: ''
23
- });
24
- }
25
-
26
- /**
27
- * 获取命令历史
28
- */
29
- getCommandHistory(): string[] {
30
- return [];
31
- }
32
-
33
- /**
34
- * 解析命令参数
35
- */
36
- parseCommand(command: string): any {
37
- const parts = command.trim().split(/\s+/);
38
- return {
39
- command: parts[0],
40
- args: parts.slice(1)
41
- };
42
- }
43
- }
@@ -1,45 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { Subject } from 'rxjs';
3
-
4
- /**
5
- * 上下文菜单服务
6
- * 管理终端上下文菜单
7
- */
8
- @Injectable({
9
- providedIn: 'root'
10
- })
11
- export class ContextMenuService {
12
- private menuItemSelected$ = new Subject<any>();
13
-
14
- constructor() {}
15
-
16
- /**
17
- * 显示上下文菜单
18
- */
19
- showMenu(x: number, y: number, items: any[]): void {
20
- // TODO: 实现上下文菜单显示
21
- console.log('Show context menu at', x, y, items);
22
- }
23
-
24
- /**
25
- * 隐藏上下文菜单
26
- */
27
- hideMenu(): void {
28
- // TODO: 实现上下文菜单隐藏
29
- console.log('Hide context menu');
30
- }
31
-
32
- /**
33
- * 订阅菜单项选择事件
34
- */
35
- onMenuItemSelected(): any {
36
- return this.menuItemSelected$.asObservable();
37
- }
38
-
39
- /**
40
- * 触发菜单项选择
41
- */
42
- selectMenuItem(item: any): void {
43
- this.menuItemSelected$.next(item);
44
- }
45
- }
@@ -1,53 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { Subject } from 'rxjs';
3
-
4
- /**
5
- * 热键服务
6
- * 管理全局热键注册和处理
7
- */
8
- @Injectable({
9
- providedIn: 'root'
10
- })
11
- export class HotkeyService {
12
- private hotkeyPressed$ = new Subject<string>();
13
-
14
- constructor() {}
15
-
16
- /**
17
- * 注册热键
18
- */
19
- registerHotkey(key: string, callback: () => void): void {
20
- // TODO: 实现热键注册
21
- console.log('Register hotkey', key);
22
- }
23
-
24
- /**
25
- * 取消注册热键
26
- */
27
- unregisterHotkey(key: string): void {
28
- // TODO: 实现热键取消注册
29
- console.log('Unregister hotkey', key);
30
- }
31
-
32
- /**
33
- * 订阅热键按下事件
34
- */
35
- onHotkeyPressed(): any {
36
- return this.hotkeyPressed$.asObservable();
37
- }
38
-
39
- /**
40
- * 触发热键事件
41
- */
42
- triggerHotkey(key: string): void {
43
- this.hotkeyPressed$.next(key);
44
- }
45
-
46
- /**
47
- * 检查热键是否已注册
48
- */
49
- isHotkeyRegistered(key: string): boolean {
50
- // TODO: 实现热键检查
51
- return false;
52
- }
53
- }
@@ -1,57 +0,0 @@
1
- const path = require('path');
2
- const webpack = require('webpack');
3
-
4
- module.exports = {
5
- mode: 'production',
6
- entry: './src/index.ts',
7
- output: {
8
- path: path.resolve(__dirname, 'dist'),
9
- filename: 'index.js',
10
- libraryTarget: 'umd',
11
- devtoolModuleFilenameTemplate: 'webpack-tabby-ai-assistant:///[resource-path]',
12
- },
13
- resolve: {
14
- extensions: ['.ts', '.js'],
15
- alias: {
16
- '@': path.resolve(__dirname, 'src')
17
- },
18
- fallback: {
19
- 'os': false,
20
- 'path': false,
21
- 'crypto': false,
22
- 'stream': false,
23
- 'util': false
24
- }
25
- },
26
- module: {
27
- rules: [
28
- {
29
- test: /\.ts$/,
30
- use: [
31
- { loader: 'ts-loader' },
32
- { loader: 'angular2-template-loader' }
33
- ],
34
- exclude: /node_modules/
35
- },
36
- {
37
- test: /\.(html|css|scss)$/,
38
- use: ['raw-loader']
39
- }
40
- ]
41
- },
42
- externals: [
43
- 'tabby-core',
44
- 'tabby-terminal',
45
- 'tabby-settings',
46
- '@angular/core',
47
- '@angular/common',
48
- '@angular/forms',
49
- '@ng-bootstrap/ng-bootstrap',
50
- 'rxjs'
51
- ],
52
- plugins: [
53
- new webpack.DefinePlugin({
54
- 'process.env.NODE_ENV': JSON.stringify('production')
55
- })
56
- ]
57
- };