tabby-ai-assistant 1.0.5 → 1.0.6
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.
- package/dist/components/chat/ai-sidebar.component.d.ts +147 -0
- package/dist/components/chat/chat-interface.component.d.ts +38 -6
- package/dist/components/settings/general-settings.component.d.ts +6 -3
- package/dist/components/settings/provider-config.component.d.ts +25 -12
- package/dist/components/terminal/command-preview.component.d.ts +38 -0
- package/dist/index-full.d.ts +8 -0
- package/dist/index-minimal.d.ts +3 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +1 -2
- package/dist/providers/tabby/ai-config.provider.d.ts +57 -5
- package/dist/providers/tabby/ai-hotkey.provider.d.ts +8 -14
- package/dist/providers/tabby/ai-toolbar-button.provider.d.ts +8 -9
- package/dist/services/chat/ai-sidebar.service.d.ts +89 -0
- package/dist/services/chat/chat-history.service.d.ts +78 -0
- package/dist/services/chat/chat-session.service.d.ts +57 -2
- package/dist/services/context/compaction.d.ts +90 -0
- package/dist/services/context/manager.d.ts +69 -0
- package/dist/services/context/memory.d.ts +116 -0
- package/dist/services/context/token-budget.d.ts +105 -0
- package/dist/services/core/ai-assistant.service.d.ts +40 -1
- package/dist/services/core/checkpoint.service.d.ts +130 -0
- package/dist/services/platform/escape-sequence.service.d.ts +132 -0
- package/dist/services/platform/platform-detection.service.d.ts +146 -0
- package/dist/services/providers/anthropic-provider.service.d.ts +5 -0
- package/dist/services/providers/base-provider.service.d.ts +6 -1
- package/dist/services/providers/glm-provider.service.d.ts +5 -0
- package/dist/services/providers/minimax-provider.service.d.ts +10 -1
- package/dist/services/providers/ollama-provider.service.d.ts +76 -0
- package/dist/services/providers/openai-compatible.service.d.ts +5 -0
- package/dist/services/providers/openai-provider.service.d.ts +5 -0
- package/dist/services/providers/vllm-provider.service.d.ts +82 -0
- package/dist/services/terminal/buffer-analyzer.service.d.ts +128 -0
- package/dist/services/terminal/terminal-manager.service.d.ts +185 -0
- package/dist/services/terminal/terminal-tools.service.d.ts +79 -0
- package/dist/types/ai.types.d.ts +92 -0
- package/dist/types/provider.types.d.ts +1 -1
- package/package.json +7 -10
- package/src/components/chat/ai-sidebar.component.ts +945 -0
- package/src/components/chat/chat-input.component.html +9 -24
- package/src/components/chat/chat-input.component.scss +3 -2
- package/src/components/chat/chat-interface.component.html +77 -69
- package/src/components/chat/chat-interface.component.scss +54 -4
- package/src/components/chat/chat-interface.component.ts +250 -34
- package/src/components/chat/chat-settings.component.scss +4 -4
- package/src/components/chat/chat-settings.component.ts +22 -11
- package/src/components/common/error-message.component.html +15 -0
- package/src/components/common/error-message.component.scss +77 -0
- package/src/components/common/error-message.component.ts +2 -96
- package/src/components/common/loading-spinner.component.html +4 -0
- package/src/components/common/loading-spinner.component.scss +57 -0
- package/src/components/common/loading-spinner.component.ts +2 -63
- package/src/components/security/consent-dialog.component.html +22 -0
- package/src/components/security/consent-dialog.component.scss +34 -0
- package/src/components/security/consent-dialog.component.ts +2 -55
- package/src/components/security/password-prompt.component.html +19 -0
- package/src/components/security/password-prompt.component.scss +30 -0
- package/src/components/security/password-prompt.component.ts +2 -54
- package/src/components/security/risk-confirm-dialog.component.html +8 -12
- package/src/components/security/risk-confirm-dialog.component.scss +8 -5
- package/src/components/security/risk-confirm-dialog.component.ts +6 -6
- package/src/components/settings/ai-settings-tab.component.html +16 -20
- package/src/components/settings/ai-settings-tab.component.scss +8 -5
- package/src/components/settings/ai-settings-tab.component.ts +12 -12
- package/src/components/settings/general-settings.component.html +8 -17
- package/src/components/settings/general-settings.component.scss +6 -3
- package/src/components/settings/general-settings.component.ts +62 -22
- package/src/components/settings/provider-config.component.html +19 -39
- package/src/components/settings/provider-config.component.scss +182 -39
- package/src/components/settings/provider-config.component.ts +119 -7
- package/src/components/settings/security-settings.component.scss +1 -1
- package/src/components/terminal/ai-toolbar-button.component.html +8 -0
- package/src/components/terminal/ai-toolbar-button.component.scss +20 -0
- package/src/components/terminal/ai-toolbar-button.component.ts +2 -30
- package/src/components/terminal/command-preview.component.html +61 -0
- package/src/components/terminal/command-preview.component.scss +72 -0
- package/src/components/terminal/command-preview.component.ts +127 -140
- package/src/components/terminal/command-suggestion.component.html +23 -0
- package/src/components/terminal/command-suggestion.component.scss +55 -0
- package/src/components/terminal/command-suggestion.component.ts +2 -77
- package/src/index-minimal.ts +32 -0
- package/src/index.ts +94 -11
- package/src/index.ts.backup +165 -0
- package/src/providers/tabby/ai-config.provider.ts +60 -51
- package/src/providers/tabby/ai-hotkey.provider.ts +23 -39
- package/src/providers/tabby/ai-settings-tab.provider.ts +2 -2
- package/src/providers/tabby/ai-toolbar-button.provider.ts +29 -24
- package/src/services/chat/ai-sidebar.service.ts +258 -0
- package/src/services/chat/chat-history.service.ts +308 -0
- package/src/services/chat/chat-history.service.ts.backup +239 -0
- package/src/services/chat/chat-session.service.ts +276 -3
- package/src/services/context/compaction.ts +483 -0
- package/src/services/context/manager.ts +442 -0
- package/src/services/context/memory.ts +519 -0
- package/src/services/context/token-budget.ts +422 -0
- package/src/services/core/ai-assistant.service.ts +280 -5
- package/src/services/core/ai-provider-manager.service.ts +2 -2
- package/src/services/core/checkpoint.service.ts +619 -0
- package/src/services/platform/escape-sequence.service.ts +499 -0
- package/src/services/platform/platform-detection.service.ts +494 -0
- package/src/services/providers/anthropic-provider.service.ts +28 -1
- package/src/services/providers/base-provider.service.ts +7 -1
- package/src/services/providers/glm-provider.service.ts +28 -1
- package/src/services/providers/minimax-provider.service.ts +209 -11
- package/src/services/providers/ollama-provider.service.ts +445 -0
- package/src/services/providers/openai-compatible.service.ts +9 -0
- package/src/services/providers/openai-provider.service.ts +9 -0
- package/src/services/providers/vllm-provider.service.ts +463 -0
- package/src/services/security/risk-assessment.service.ts +6 -2
- package/src/services/terminal/buffer-analyzer.service.ts +594 -0
- package/src/services/terminal/terminal-manager.service.ts +748 -0
- package/src/services/terminal/terminal-tools.service.ts +441 -0
- package/src/styles/ai-assistant.scss +78 -6
- package/src/types/ai.types.ts +144 -0
- package/src/types/provider.types.ts +1 -1
- package/tsconfig.json +9 -9
- package/webpack.config.js +28 -6
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { LoggerService } from '../core/logger.service';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 操作系统类型
|
|
6
|
+
*/
|
|
7
|
+
export enum OSType {
|
|
8
|
+
LINUX = 'linux',
|
|
9
|
+
WINDOWS = 'windows',
|
|
10
|
+
MACOS = 'macos',
|
|
11
|
+
UNKNOWN = 'unknown'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 终端类型
|
|
16
|
+
*/
|
|
17
|
+
export enum TerminalType {
|
|
18
|
+
XTERM = 'xterm',
|
|
19
|
+
XTERM_256_COLOR = 'xterm-256color',
|
|
20
|
+
LINUX_CONSOLE = 'linux',
|
|
21
|
+
WINDOWS_CMD = 'windows-cmd',
|
|
22
|
+
WINDOWS_POWERSHELL = 'windows-powershell',
|
|
23
|
+
WINDOWS_WSL = 'windows-wsl',
|
|
24
|
+
MACOS_TERMINAL = 'macos-terminal',
|
|
25
|
+
ITerm2 = 'iterm2',
|
|
26
|
+
UNKNOWN = 'unknown'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 终端能力
|
|
31
|
+
*/
|
|
32
|
+
export interface TerminalCapabilities {
|
|
33
|
+
colors: number; // 颜色数(8, 16, 256, 16777216)
|
|
34
|
+
trueColor: boolean; // 是否支持TrueColor
|
|
35
|
+
unicode: boolean; // 是否支持Unicode
|
|
36
|
+
mouse: boolean; // 是否支持鼠标
|
|
37
|
+
bracketedPaste: boolean; // 是否支持括号粘贴
|
|
38
|
+
imageSupport: boolean; // 是否支持图片
|
|
39
|
+
titleSupport: boolean; // 是否支持标题设置
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 平台信息
|
|
44
|
+
*/
|
|
45
|
+
export interface PlatformInfo {
|
|
46
|
+
os: OSType;
|
|
47
|
+
osVersion: string;
|
|
48
|
+
terminal: TerminalType;
|
|
49
|
+
terminalVersion?: string;
|
|
50
|
+
shell: string;
|
|
51
|
+
shellVersion?: string;
|
|
52
|
+
capabilities: TerminalCapabilities;
|
|
53
|
+
environment: Record<string, string>;
|
|
54
|
+
arch: string; // 架构(x64, x86, arm64等)
|
|
55
|
+
isVirtualTerminal: boolean; // 是否为虚拟终端(如WSL、SSH等)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 环境分析结果
|
|
60
|
+
*/
|
|
61
|
+
export interface EnvironmentAnalysis {
|
|
62
|
+
platformInfo: PlatformInfo;
|
|
63
|
+
features: {
|
|
64
|
+
supportsAnsiColors: boolean;
|
|
65
|
+
supportsUnicode: boolean;
|
|
66
|
+
supportsTrueColor: boolean;
|
|
67
|
+
supportsMouseEvents: boolean;
|
|
68
|
+
supportsImages: boolean;
|
|
69
|
+
};
|
|
70
|
+
recommendations: string[];
|
|
71
|
+
compatibility: {
|
|
72
|
+
score: number; // 0-100的兼容性分数
|
|
73
|
+
issues: string[];
|
|
74
|
+
workarounds: string[];
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 平台检测服务
|
|
80
|
+
* 提供跨平台终端环境检测、兼容性分析和能力检测功能
|
|
81
|
+
*/
|
|
82
|
+
@Injectable({
|
|
83
|
+
providedIn: 'root'
|
|
84
|
+
})
|
|
85
|
+
export class PlatformDetectionService {
|
|
86
|
+
private platformInfo: PlatformInfo | null = null;
|
|
87
|
+
private analysisCache: EnvironmentAnalysis | null = null;
|
|
88
|
+
|
|
89
|
+
constructor(private logger: LoggerService) {
|
|
90
|
+
this.logger.info('PlatformDetectionService initialized');
|
|
91
|
+
this.detectPlatform();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 检测操作系统
|
|
96
|
+
*/
|
|
97
|
+
detectOS(): OSType {
|
|
98
|
+
const platform = process.platform;
|
|
99
|
+
|
|
100
|
+
switch (platform) {
|
|
101
|
+
case 'linux':
|
|
102
|
+
return OSType.LINUX;
|
|
103
|
+
case 'win32':
|
|
104
|
+
return OSType.WINDOWS;
|
|
105
|
+
case 'darwin':
|
|
106
|
+
return OSType.MACOS;
|
|
107
|
+
default:
|
|
108
|
+
return OSType.UNKNOWN;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 检测终端类型
|
|
114
|
+
*/
|
|
115
|
+
detectTerminal(): TerminalType {
|
|
116
|
+
const term = process.env.TERM || '';
|
|
117
|
+
const termProgram = process.env.TERM_PROGRAM || '';
|
|
118
|
+
const sessionName = process.env.SESSION_NAME || '';
|
|
119
|
+
|
|
120
|
+
// Windows终端检测
|
|
121
|
+
if (termProgram === 'Windows Terminal' || sessionName === 'Windows Terminal') {
|
|
122
|
+
return TerminalType.WINDOWS_WSL;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (process.env.PROMPT || process.env.COMSPEC) {
|
|
126
|
+
return TerminalType.WINDOWS_CMD;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (termProgram === 'PowerShell' || process.env.POWERSHELL_VERSION) {
|
|
130
|
+
return TerminalType.WINDOWS_POWERSHELL;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// macOS终端检测
|
|
134
|
+
if (termProgram === 'iTerm.app') {
|
|
135
|
+
return TerminalType.ITerm2;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (termProgram === 'Apple_Terminal') {
|
|
139
|
+
return TerminalType.MACOS_TERMINAL;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Linux终端检测
|
|
143
|
+
if (term === 'linux') {
|
|
144
|
+
return TerminalType.LINUX_CONSOLE;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (term === 'xterm-256color') {
|
|
148
|
+
return TerminalType.XTERM_256_COLOR;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (term === 'xterm') {
|
|
152
|
+
return TerminalType.XTERM;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return TerminalType.UNKNOWN;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 检查终端能力
|
|
160
|
+
*/
|
|
161
|
+
checkCapabilities(): TerminalCapabilities {
|
|
162
|
+
const term = process.env.TERM || '';
|
|
163
|
+
const colorTerm = process.env.COLORTERM || '';
|
|
164
|
+
|
|
165
|
+
const capabilities: TerminalCapabilities = {
|
|
166
|
+
colors: this.getColorCount(term, colorTerm),
|
|
167
|
+
trueColor: this.supportsTrueColor(term, colorTerm),
|
|
168
|
+
unicode: this.supportsUnicode(),
|
|
169
|
+
mouse: this.supportsMouse(term),
|
|
170
|
+
bracketedPaste: this.supportsBracketedPaste(term),
|
|
171
|
+
imageSupport: this.supportsImages(term),
|
|
172
|
+
titleSupport: this.supportsTitle(term)
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return capabilities;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 分析环境
|
|
180
|
+
*/
|
|
181
|
+
analyzeEnvironment(): EnvironmentAnalysis {
|
|
182
|
+
if (this.analysisCache) {
|
|
183
|
+
return this.analysisCache;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const platformInfo = this.getPlatformInfo();
|
|
187
|
+
const features = this.analyzeFeatures(platformInfo);
|
|
188
|
+
const recommendations = this.generateRecommendations(platformInfo);
|
|
189
|
+
const compatibility = this.analyzeCompatibility(platformInfo);
|
|
190
|
+
|
|
191
|
+
const analysis: EnvironmentAnalysis = {
|
|
192
|
+
platformInfo,
|
|
193
|
+
features,
|
|
194
|
+
recommendations,
|
|
195
|
+
compatibility
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
this.analysisCache = analysis;
|
|
199
|
+
return analysis;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 获取版本信息
|
|
204
|
+
*/
|
|
205
|
+
getVersionInfo(): {
|
|
206
|
+
osVersion: string;
|
|
207
|
+
terminalVersion?: string;
|
|
208
|
+
shellVersion?: string;
|
|
209
|
+
nodeVersion: string;
|
|
210
|
+
} {
|
|
211
|
+
return {
|
|
212
|
+
osVersion: this.getOSVersion(),
|
|
213
|
+
terminalVersion: this.getTerminalVersion(),
|
|
214
|
+
shellVersion: this.getShellVersion(),
|
|
215
|
+
nodeVersion: process.version
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 获取完整的平台信息
|
|
221
|
+
*/
|
|
222
|
+
getPlatformInfo(): PlatformInfo {
|
|
223
|
+
if (this.platformInfo) {
|
|
224
|
+
return this.platformInfo;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const os = this.detectOS();
|
|
228
|
+
const terminal = this.detectTerminal();
|
|
229
|
+
const capabilities = this.checkCapabilities();
|
|
230
|
+
const shell = this.getActiveShell();
|
|
231
|
+
const arch = process.arch;
|
|
232
|
+
|
|
233
|
+
this.platformInfo = {
|
|
234
|
+
os,
|
|
235
|
+
osVersion: this.getOSVersion(),
|
|
236
|
+
terminal,
|
|
237
|
+
terminalVersion: this.getTerminalVersion(),
|
|
238
|
+
shell,
|
|
239
|
+
shellVersion: this.getShellVersion(),
|
|
240
|
+
capabilities,
|
|
241
|
+
environment: this.filterEnvVariables(process.env),
|
|
242
|
+
arch,
|
|
243
|
+
isVirtualTerminal: this.isVirtualTerminal()
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
return this.platformInfo;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 检查是否支持特定功能
|
|
251
|
+
*/
|
|
252
|
+
supportsFeature(feature: 'ansiColors' | 'unicode' | 'trueColor' | 'mouse' | 'images'): boolean {
|
|
253
|
+
const capabilities = this.checkCapabilities();
|
|
254
|
+
|
|
255
|
+
switch (feature) {
|
|
256
|
+
case 'ansiColors':
|
|
257
|
+
return capabilities.colors >= 8;
|
|
258
|
+
case 'unicode':
|
|
259
|
+
return capabilities.unicode;
|
|
260
|
+
case 'trueColor':
|
|
261
|
+
return capabilities.trueColor;
|
|
262
|
+
case 'mouse':
|
|
263
|
+
return capabilities.mouse;
|
|
264
|
+
case 'images':
|
|
265
|
+
return capabilities.imageSupport;
|
|
266
|
+
default:
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 获取终端颜色数(公共方法)
|
|
273
|
+
*/
|
|
274
|
+
getTerminalColorCount(): number {
|
|
275
|
+
return this.checkCapabilities().colors;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 检查是否为Windows WSL环境
|
|
280
|
+
*/
|
|
281
|
+
isWSL(): boolean {
|
|
282
|
+
return process.platform === 'linux' &&
|
|
283
|
+
!!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 检查是否通过SSH连接
|
|
288
|
+
*/
|
|
289
|
+
isSSH(): boolean {
|
|
290
|
+
return !!process.env.SSH_CLIENT || !!process.env.SSH_TTY || !!process.env.SSH_CONNECTION;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 清理缓存并重新检测
|
|
295
|
+
*/
|
|
296
|
+
refresh(): void {
|
|
297
|
+
this.platformInfo = null;
|
|
298
|
+
this.analysisCache = null;
|
|
299
|
+
this.detectPlatform();
|
|
300
|
+
this.logger.info('Platform detection refreshed');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ==================== 私有方法 ====================
|
|
304
|
+
|
|
305
|
+
private detectPlatform(): void {
|
|
306
|
+
try {
|
|
307
|
+
const platformInfo = this.getPlatformInfo();
|
|
308
|
+
this.logger.info('Platform detected', {
|
|
309
|
+
os: platformInfo.os,
|
|
310
|
+
terminal: platformInfo.terminal,
|
|
311
|
+
shell: platformInfo.shell,
|
|
312
|
+
arch: platformInfo.arch
|
|
313
|
+
});
|
|
314
|
+
} catch (error) {
|
|
315
|
+
this.logger.error('Failed to detect platform', error);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private getColorCount(term: string, colorTerm: string): number {
|
|
320
|
+
if (colorTerm === 'truecolor' || colorTerm === '24bit') {
|
|
321
|
+
return 16777216;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (term.includes('256color')) {
|
|
325
|
+
return 256;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (term.includes('color')) {
|
|
329
|
+
return 16;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return 8;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private supportsTrueColor(term: string, colorTerm: string): boolean {
|
|
336
|
+
return colorTerm === 'truecolor' ||
|
|
337
|
+
colorTerm === '24bit' ||
|
|
338
|
+
term.includes('truecolor') ||
|
|
339
|
+
term.includes('24bit');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private supportsUnicode(): boolean {
|
|
343
|
+
return !!process.env.LC_ALL || !!process.env.LC_CTYPE || !!process.env.LANG;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private supportsMouse(term: string): boolean {
|
|
347
|
+
return term.includes('mouse') || term.includes('xterm');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private supportsBracketedPaste(term: string): boolean {
|
|
351
|
+
return term.includes('xterm') || term.includes('screen');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private supportsImages(term: string): boolean {
|
|
355
|
+
return term.includes('kitty') || term.includes('iterm');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private supportsTitle(term: string): boolean {
|
|
359
|
+
return term.includes('xterm') || term.includes('screen') || term.includes('tmux');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
private analyzeFeatures(platformInfo: PlatformInfo) {
|
|
363
|
+
return {
|
|
364
|
+
supportsAnsiColors: platformInfo.capabilities.colors >= 8,
|
|
365
|
+
supportsUnicode: platformInfo.capabilities.unicode,
|
|
366
|
+
supportsTrueColor: platformInfo.capabilities.trueColor,
|
|
367
|
+
supportsMouseEvents: platformInfo.capabilities.mouse,
|
|
368
|
+
supportsImages: platformInfo.capabilities.imageSupport
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private generateRecommendations(platformInfo: PlatformInfo): string[] {
|
|
373
|
+
const recommendations: string[] = [];
|
|
374
|
+
|
|
375
|
+
// 基于OS的推荐
|
|
376
|
+
if (platformInfo.os === OSType.WINDOWS) {
|
|
377
|
+
recommendations.push('建议使用Windows Terminal或WSL以获得更好的终端体验');
|
|
378
|
+
if (platformInfo.terminal === TerminalType.WINDOWS_CMD) {
|
|
379
|
+
recommendations.push('CMD终端功能有限,建议升级到PowerShell或Windows Terminal');
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (platformInfo.os === OSType.MACOS) {
|
|
384
|
+
if (platformInfo.terminal === TerminalType.MACOS_TERMINAL) {
|
|
385
|
+
recommendations.push('建议使用iTerm2以获得更多功能和更好的性能');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// 基于终端能力的推荐
|
|
390
|
+
if (!platformInfo.capabilities.trueColor) {
|
|
391
|
+
recommendations.push('当前终端不支持TrueColor,颜色显示可能受限');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!platformInfo.capabilities.unicode) {
|
|
395
|
+
recommendations.push('当前终端不支持Unicode,非ASCII字符可能显示异常');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!platformInfo.capabilities.mouse) {
|
|
399
|
+
recommendations.push('当前终端不支持鼠标事件,交互功能可能受限');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return recommendations;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private analyzeCompatibility(platformInfo: PlatformInfo): {
|
|
406
|
+
score: number;
|
|
407
|
+
issues: string[];
|
|
408
|
+
workarounds: string[];
|
|
409
|
+
} {
|
|
410
|
+
let score = 100;
|
|
411
|
+
const issues: string[] = [];
|
|
412
|
+
const workarounds: string[] = [];
|
|
413
|
+
|
|
414
|
+
// 操作系统兼容性
|
|
415
|
+
if (platformInfo.os === OSType.UNKNOWN) {
|
|
416
|
+
score -= 20;
|
|
417
|
+
issues.push('未识别的操作系统');
|
|
418
|
+
workarounds.push('使用默认兼容性设置');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// 终端兼容性
|
|
422
|
+
if (platformInfo.terminal === TerminalType.UNKNOWN) {
|
|
423
|
+
score -= 15;
|
|
424
|
+
issues.push('未识别的终端类型');
|
|
425
|
+
workarounds.push('使用基础终端功能');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 颜色支持
|
|
429
|
+
if (platformInfo.capabilities.colors < 16) {
|
|
430
|
+
score -= 10;
|
|
431
|
+
issues.push('终端颜色支持有限(少于16色)');
|
|
432
|
+
workarounds.push('使用ANSI基本颜色');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// TrueColor支持
|
|
436
|
+
if (!platformInfo.capabilities.trueColor) {
|
|
437
|
+
score -= 5;
|
|
438
|
+
issues.push('不支持TrueColor');
|
|
439
|
+
workarounds.push('使用256色或基本颜色替代');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Unicode支持
|
|
443
|
+
if (!platformInfo.capabilities.unicode) {
|
|
444
|
+
score -= 10;
|
|
445
|
+
issues.push('不支持Unicode字符');
|
|
446
|
+
workarounds.push('使用ASCII字符集');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
score: Math.max(0, score),
|
|
451
|
+
issues,
|
|
452
|
+
workarounds
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private getOSVersion(): string {
|
|
457
|
+
if (typeof process.release !== 'undefined') {
|
|
458
|
+
return process.release.name + ' ' + (process.version || '');
|
|
459
|
+
}
|
|
460
|
+
return process.platform;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private getTerminalVersion(): string | undefined {
|
|
464
|
+
return process.env.TERM_VERSION;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private getActiveShell(): string {
|
|
468
|
+
return process.env.SHELL || process.env.COMSPEC || 'unknown';
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private getShellVersion(): string | undefined {
|
|
472
|
+
// 简化实现:实际应通过执行命令获取
|
|
473
|
+
if (process.env.SHELL) {
|
|
474
|
+
const shellName = process.env.SHELL.split('/').pop();
|
|
475
|
+
return shellName;
|
|
476
|
+
}
|
|
477
|
+
return undefined;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
private isVirtualTerminal(): boolean {
|
|
481
|
+
return this.isWSL() || this.isSSH();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private filterEnvVariables(env: NodeJS.ProcessEnv): Record<string, string> {
|
|
485
|
+
const result: Record<string, string> = {};
|
|
486
|
+
for (const key of Object.keys(env)) {
|
|
487
|
+
const value = env[key];
|
|
488
|
+
if (value !== undefined) {
|
|
489
|
+
result[key] = value;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Observable, from } from 'rxjs';
|
|
2
3
|
import { Anthropic } from '@anthropic-ai/sdk';
|
|
3
4
|
import { BaseAiProvider } from './base-provider.service';
|
|
4
5
|
import { ProviderCapability, HealthStatus, ValidationResult } from '../../types/provider.types';
|
|
@@ -91,6 +92,14 @@ export class AnthropicProviderService extends BaseAiProvider {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
/**
|
|
96
|
+
* 流式聊天功能 - 暂未实现,回退到非流式
|
|
97
|
+
*/
|
|
98
|
+
chatStream(request: ChatRequest): Observable<any> {
|
|
99
|
+
// 回退到非流式
|
|
100
|
+
return from(this.chat(request));
|
|
101
|
+
}
|
|
102
|
+
|
|
94
103
|
async generateCommand(request: CommandRequest): Promise<CommandResponse> {
|
|
95
104
|
const prompt = this.buildCommandPrompt(request);
|
|
96
105
|
|
|
@@ -368,6 +377,24 @@ export class AnthropicProviderService extends BaseAiProvider {
|
|
|
368
377
|
}
|
|
369
378
|
|
|
370
379
|
private getDefaultSystemPrompt(): string {
|
|
371
|
-
return
|
|
380
|
+
return `你是一个专业的终端命令助手,运行在 Tabby 终端中。
|
|
381
|
+
|
|
382
|
+
## 核心能力
|
|
383
|
+
你可以通过以下工具直接操作终端:
|
|
384
|
+
- write_to_terminal: 向终端写入并执行命令
|
|
385
|
+
- read_terminal_output: 读取终端输出
|
|
386
|
+
- get_terminal_list: 获取所有终端列表
|
|
387
|
+
- get_terminal_cwd: 获取当前工作目录
|
|
388
|
+
|
|
389
|
+
## 重要规则
|
|
390
|
+
1. 当用户请求执行命令(如"查看当前目录"、"列出文件"等),你必须使用 write_to_terminal 工具来执行
|
|
391
|
+
2. 不要只是描述你"将要做什么",而是直接调用工具执行
|
|
392
|
+
3. 执行命令后,使用 read_terminal_output 读取结果并报告给用户
|
|
393
|
+
4. 如果不确定当前目录或终端状态,先使用 get_terminal_cwd 或 get_terminal_list 获取信息
|
|
394
|
+
|
|
395
|
+
## 示例
|
|
396
|
+
用户:"查看当前目录的文件"
|
|
397
|
+
正确做法:调用 write_to_terminal 工具,参数 { "command": "dir", "execute": true }
|
|
398
|
+
错误做法:仅回复文字"我将执行 dir 命令"`;
|
|
372
399
|
}
|
|
373
400
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
2
3
|
import { BaseAiProvider as IBaseAiProvider, ProviderConfig, AuthConfig, ProviderCapability, HealthStatus, ValidationResult } from '../../types/provider.types';
|
|
3
|
-
import { ChatRequest, ChatResponse, CommandRequest, CommandResponse, ExplainRequest, ExplainResponse, AnalysisRequest, AnalysisResponse } from '../../types/ai.types';
|
|
4
|
+
import { ChatRequest, ChatResponse, CommandRequest, CommandResponse, ExplainRequest, ExplainResponse, AnalysisRequest, AnalysisResponse, StreamEvent } from '../../types/ai.types';
|
|
4
5
|
import { LoggerService } from '../core/logger.service';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -36,6 +37,11 @@ export abstract class BaseAiProvider extends IBaseAiProvider {
|
|
|
36
37
|
*/
|
|
37
38
|
abstract chat(request: ChatRequest): Promise<ChatResponse>;
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 流式聊天功能 - 必须由子类实现
|
|
42
|
+
*/
|
|
43
|
+
abstract chatStream(request: ChatRequest): Observable<StreamEvent>;
|
|
44
|
+
|
|
39
45
|
/**
|
|
40
46
|
* 生成命令 - 必须由子类实现
|
|
41
47
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Observable, from } from 'rxjs';
|
|
2
3
|
import axios, { AxiosInstance } from 'axios';
|
|
3
4
|
import { BaseAiProvider } from './base-provider.service';
|
|
4
5
|
import { ProviderCapability, HealthStatus, ValidationResult } from '../../types/provider.types';
|
|
@@ -135,6 +136,14 @@ export class GlmProviderService extends BaseAiProvider {
|
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
/**
|
|
140
|
+
* 流式聊天功能 - 暂未实现,回退到非流式
|
|
141
|
+
*/
|
|
142
|
+
chatStream(request: ChatRequest): Observable<any> {
|
|
143
|
+
// 回退到非流式
|
|
144
|
+
return from(this.chat(request));
|
|
145
|
+
}
|
|
146
|
+
|
|
138
147
|
/**
|
|
139
148
|
* 生成命令
|
|
140
149
|
*/
|
|
@@ -462,6 +471,24 @@ export class GlmProviderService extends BaseAiProvider {
|
|
|
462
471
|
}
|
|
463
472
|
|
|
464
473
|
private getDefaultSystemPrompt(): string {
|
|
465
|
-
return
|
|
474
|
+
return `你是一个专业的终端命令助手,运行在 Tabby 终端中。
|
|
475
|
+
|
|
476
|
+
## 核心能力
|
|
477
|
+
你可以通过以下工具直接操作终端:
|
|
478
|
+
- write_to_terminal: 向终端写入并执行命令
|
|
479
|
+
- read_terminal_output: 读取终端输出
|
|
480
|
+
- get_terminal_list: 获取所有终端列表
|
|
481
|
+
- get_terminal_cwd: 获取当前工作目录
|
|
482
|
+
|
|
483
|
+
## 重要规则
|
|
484
|
+
1. 当用户请求执行命令(如"查看当前目录"、"列出文件"等),你必须使用 write_to_terminal 工具来执行
|
|
485
|
+
2. 不要只是描述你"将要做什么",而是直接调用工具执行
|
|
486
|
+
3. 执行命令后,使用 read_terminal_output 读取结果并报告给用户
|
|
487
|
+
4. 如果不确定当前目录或终端状态,先使用 get_terminal_cwd 或 get_terminal_list 获取信息
|
|
488
|
+
|
|
489
|
+
## 示例
|
|
490
|
+
用户:"查看当前目录的文件"
|
|
491
|
+
正确做法:调用 write_to_terminal 工具,参数 { "command": "dir", "execute": true }
|
|
492
|
+
错误做法:仅回复文字"我将执行 dir 命令"`;
|
|
466
493
|
}
|
|
467
494
|
}
|