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.
Files changed (116) hide show
  1. package/dist/components/chat/ai-sidebar.component.d.ts +147 -0
  2. package/dist/components/chat/chat-interface.component.d.ts +38 -6
  3. package/dist/components/settings/general-settings.component.d.ts +6 -3
  4. package/dist/components/settings/provider-config.component.d.ts +25 -12
  5. package/dist/components/terminal/command-preview.component.d.ts +38 -0
  6. package/dist/index-full.d.ts +8 -0
  7. package/dist/index-minimal.d.ts +3 -0
  8. package/dist/index.d.ts +7 -3
  9. package/dist/index.js +1 -2
  10. package/dist/providers/tabby/ai-config.provider.d.ts +57 -5
  11. package/dist/providers/tabby/ai-hotkey.provider.d.ts +8 -14
  12. package/dist/providers/tabby/ai-toolbar-button.provider.d.ts +8 -9
  13. package/dist/services/chat/ai-sidebar.service.d.ts +89 -0
  14. package/dist/services/chat/chat-history.service.d.ts +78 -0
  15. package/dist/services/chat/chat-session.service.d.ts +57 -2
  16. package/dist/services/context/compaction.d.ts +90 -0
  17. package/dist/services/context/manager.d.ts +69 -0
  18. package/dist/services/context/memory.d.ts +116 -0
  19. package/dist/services/context/token-budget.d.ts +105 -0
  20. package/dist/services/core/ai-assistant.service.d.ts +40 -1
  21. package/dist/services/core/checkpoint.service.d.ts +130 -0
  22. package/dist/services/platform/escape-sequence.service.d.ts +132 -0
  23. package/dist/services/platform/platform-detection.service.d.ts +146 -0
  24. package/dist/services/providers/anthropic-provider.service.d.ts +5 -0
  25. package/dist/services/providers/base-provider.service.d.ts +6 -1
  26. package/dist/services/providers/glm-provider.service.d.ts +5 -0
  27. package/dist/services/providers/minimax-provider.service.d.ts +10 -1
  28. package/dist/services/providers/ollama-provider.service.d.ts +76 -0
  29. package/dist/services/providers/openai-compatible.service.d.ts +5 -0
  30. package/dist/services/providers/openai-provider.service.d.ts +5 -0
  31. package/dist/services/providers/vllm-provider.service.d.ts +82 -0
  32. package/dist/services/terminal/buffer-analyzer.service.d.ts +128 -0
  33. package/dist/services/terminal/terminal-manager.service.d.ts +185 -0
  34. package/dist/services/terminal/terminal-tools.service.d.ts +79 -0
  35. package/dist/types/ai.types.d.ts +92 -0
  36. package/dist/types/provider.types.d.ts +1 -1
  37. package/package.json +7 -10
  38. package/src/components/chat/ai-sidebar.component.ts +945 -0
  39. package/src/components/chat/chat-input.component.html +9 -24
  40. package/src/components/chat/chat-input.component.scss +3 -2
  41. package/src/components/chat/chat-interface.component.html +77 -69
  42. package/src/components/chat/chat-interface.component.scss +54 -4
  43. package/src/components/chat/chat-interface.component.ts +250 -34
  44. package/src/components/chat/chat-settings.component.scss +4 -4
  45. package/src/components/chat/chat-settings.component.ts +22 -11
  46. package/src/components/common/error-message.component.html +15 -0
  47. package/src/components/common/error-message.component.scss +77 -0
  48. package/src/components/common/error-message.component.ts +2 -96
  49. package/src/components/common/loading-spinner.component.html +4 -0
  50. package/src/components/common/loading-spinner.component.scss +57 -0
  51. package/src/components/common/loading-spinner.component.ts +2 -63
  52. package/src/components/security/consent-dialog.component.html +22 -0
  53. package/src/components/security/consent-dialog.component.scss +34 -0
  54. package/src/components/security/consent-dialog.component.ts +2 -55
  55. package/src/components/security/password-prompt.component.html +19 -0
  56. package/src/components/security/password-prompt.component.scss +30 -0
  57. package/src/components/security/password-prompt.component.ts +2 -54
  58. package/src/components/security/risk-confirm-dialog.component.html +8 -12
  59. package/src/components/security/risk-confirm-dialog.component.scss +8 -5
  60. package/src/components/security/risk-confirm-dialog.component.ts +6 -6
  61. package/src/components/settings/ai-settings-tab.component.html +16 -20
  62. package/src/components/settings/ai-settings-tab.component.scss +8 -5
  63. package/src/components/settings/ai-settings-tab.component.ts +12 -12
  64. package/src/components/settings/general-settings.component.html +8 -17
  65. package/src/components/settings/general-settings.component.scss +6 -3
  66. package/src/components/settings/general-settings.component.ts +62 -22
  67. package/src/components/settings/provider-config.component.html +19 -39
  68. package/src/components/settings/provider-config.component.scss +182 -39
  69. package/src/components/settings/provider-config.component.ts +119 -7
  70. package/src/components/settings/security-settings.component.scss +1 -1
  71. package/src/components/terminal/ai-toolbar-button.component.html +8 -0
  72. package/src/components/terminal/ai-toolbar-button.component.scss +20 -0
  73. package/src/components/terminal/ai-toolbar-button.component.ts +2 -30
  74. package/src/components/terminal/command-preview.component.html +61 -0
  75. package/src/components/terminal/command-preview.component.scss +72 -0
  76. package/src/components/terminal/command-preview.component.ts +127 -140
  77. package/src/components/terminal/command-suggestion.component.html +23 -0
  78. package/src/components/terminal/command-suggestion.component.scss +55 -0
  79. package/src/components/terminal/command-suggestion.component.ts +2 -77
  80. package/src/index-minimal.ts +32 -0
  81. package/src/index.ts +94 -11
  82. package/src/index.ts.backup +165 -0
  83. package/src/providers/tabby/ai-config.provider.ts +60 -51
  84. package/src/providers/tabby/ai-hotkey.provider.ts +23 -39
  85. package/src/providers/tabby/ai-settings-tab.provider.ts +2 -2
  86. package/src/providers/tabby/ai-toolbar-button.provider.ts +29 -24
  87. package/src/services/chat/ai-sidebar.service.ts +258 -0
  88. package/src/services/chat/chat-history.service.ts +308 -0
  89. package/src/services/chat/chat-history.service.ts.backup +239 -0
  90. package/src/services/chat/chat-session.service.ts +276 -3
  91. package/src/services/context/compaction.ts +483 -0
  92. package/src/services/context/manager.ts +442 -0
  93. package/src/services/context/memory.ts +519 -0
  94. package/src/services/context/token-budget.ts +422 -0
  95. package/src/services/core/ai-assistant.service.ts +280 -5
  96. package/src/services/core/ai-provider-manager.service.ts +2 -2
  97. package/src/services/core/checkpoint.service.ts +619 -0
  98. package/src/services/platform/escape-sequence.service.ts +499 -0
  99. package/src/services/platform/platform-detection.service.ts +494 -0
  100. package/src/services/providers/anthropic-provider.service.ts +28 -1
  101. package/src/services/providers/base-provider.service.ts +7 -1
  102. package/src/services/providers/glm-provider.service.ts +28 -1
  103. package/src/services/providers/minimax-provider.service.ts +209 -11
  104. package/src/services/providers/ollama-provider.service.ts +445 -0
  105. package/src/services/providers/openai-compatible.service.ts +9 -0
  106. package/src/services/providers/openai-provider.service.ts +9 -0
  107. package/src/services/providers/vllm-provider.service.ts +463 -0
  108. package/src/services/security/risk-assessment.service.ts +6 -2
  109. package/src/services/terminal/buffer-analyzer.service.ts +594 -0
  110. package/src/services/terminal/terminal-manager.service.ts +748 -0
  111. package/src/services/terminal/terminal-tools.service.ts +441 -0
  112. package/src/styles/ai-assistant.scss +78 -6
  113. package/src/types/ai.types.ts +144 -0
  114. package/src/types/provider.types.ts +1 -1
  115. package/tsconfig.json +9 -9
  116. package/webpack.config.js +28 -6
@@ -12,6 +12,9 @@ export class ProviderConfigComponent implements OnInit {
12
12
  @Output() refreshStatus = new EventEmitter<void>();
13
13
  @Output() switchProvider = new EventEmitter<string>();
14
14
 
15
+ // 暴露 Object 给模板使用
16
+ Object = Object;
17
+
15
18
  selectedProvider = '';
16
19
  configs: { [key: string]: any } = {};
17
20
 
@@ -23,7 +26,7 @@ export class ProviderConfigComponent implements OnInit {
23
26
  fields: [
24
27
  { key: 'apiKey', label: 'API Key', type: 'password', required: true },
25
28
  { key: 'baseURL', label: 'Base URL', type: 'text', default: 'https://api.openai.com/v1', required: false },
26
- { key: 'model', label: 'Model', type: 'select', options: ['gpt-4', 'gpt-3.5-turbo'], default: 'gpt-4', required: false }
29
+ { key: 'model', label: 'Model', type: 'text', default: 'gpt-4', required: false, placeholder: '例如: gpt-4, gpt-4-turbo, gpt-3.5-turbo' }
27
30
  ]
28
31
  },
29
32
  'anthropic': {
@@ -32,7 +35,7 @@ export class ProviderConfigComponent implements OnInit {
32
35
  fields: [
33
36
  { key: 'apiKey', label: 'API Key', type: 'password', required: true },
34
37
  { key: 'baseURL', label: 'Base URL', type: 'text', default: 'https://api.anthropic.com', required: false },
35
- { key: 'model', label: 'Model', type: 'select', options: ['claude-3-opus', 'claude-3-sonnet'], default: 'claude-3-sonnet', required: false }
38
+ { key: 'model', label: 'Model', type: 'text', default: 'claude-3-sonnet-20240229', required: false, placeholder: '例如: claude-3-opus, claude-3-sonnet' }
36
39
  ]
37
40
  },
38
41
  'minimax': {
@@ -41,7 +44,7 @@ export class ProviderConfigComponent implements OnInit {
41
44
  fields: [
42
45
  { key: 'apiKey', label: 'API Key', type: 'password', required: true },
43
46
  { key: 'baseURL', label: 'Base URL', type: 'text', default: 'https://api.minimaxi.com/anthropic', required: false },
44
- { key: 'model', label: 'Model', type: 'select', options: ['MiniMax-M2', 'MiniMax-M2-Stable'], default: 'MiniMax-M2', required: false }
47
+ { key: 'model', label: 'Model', type: 'text', default: 'MiniMax-M2', required: false, placeholder: '例如: MiniMax-M2, MiniMax-M2.1' }
45
48
  ]
46
49
  },
47
50
  'glm': {
@@ -50,7 +53,7 @@ export class ProviderConfigComponent implements OnInit {
50
53
  fields: [
51
54
  { key: 'apiKey', label: 'API Key', type: 'password', required: true },
52
55
  { key: 'baseURL', label: 'Base URL', type: 'text', default: 'https://open.bigmodel.cn/api/paas/v4', required: false },
53
- { key: 'model', label: 'Model', type: 'select', options: ['glm-4', 'glm-4-air', 'chatglm4'], default: 'glm-4', required: false }
56
+ { key: 'model', label: 'Model', type: 'text', default: 'glm-4', required: false, placeholder: '例如: glm-4, glm-4-air, glm-4-flash' }
54
57
  ]
55
58
  }
56
59
  };
@@ -58,7 +61,7 @@ export class ProviderConfigComponent implements OnInit {
58
61
  constructor(
59
62
  private config: ConfigProviderService,
60
63
  private logger: LoggerService
61
- ) {}
64
+ ) { }
62
65
 
63
66
  ngOnInit(): void {
64
67
  this.loadConfigs();
@@ -128,8 +131,117 @@ export class ProviderConfigComponent implements OnInit {
128
131
  * 测试连接
129
132
  */
130
133
  async testConnection(providerName: string): Promise<void> {
131
- // TODO: 实现连接测试
132
- alert(`正在测试 ${this.providerTemplates[providerName]?.name} 的连接...`);
134
+ const providerConfig = this.configs[providerName];
135
+ if (!providerConfig) {
136
+ alert('请先配置该提供商');
137
+ return;
138
+ }
139
+
140
+ const apiKey = providerConfig.apiKey;
141
+ const baseURL = providerConfig.baseURL;
142
+
143
+ if (!apiKey) {
144
+ alert('请先填写 API Key');
145
+ return;
146
+ }
147
+
148
+ const template = (this.providerTemplates as any)[providerName];
149
+ const providerDisplayName = template?.name || providerName;
150
+
151
+ // 显示测试中状态
152
+ const testingMessage = `正在测试 ${providerDisplayName} 的连接...`;
153
+ this.logger.info(testingMessage);
154
+
155
+ try {
156
+ // 构造测试请求
157
+ const testEndpoint = this.getTestEndpoint(providerName, baseURL);
158
+ const headers = this.getTestHeaders(providerName, apiKey, baseURL);
159
+
160
+ const response = await fetch(testEndpoint, {
161
+ method: 'POST',
162
+ headers: headers,
163
+ body: JSON.stringify(this.getTestBody(providerName, baseURL))
164
+ });
165
+
166
+ if (response.ok) {
167
+ alert(`✅ ${providerDisplayName} 连接测试成功!`);
168
+ this.logger.info('Connection test successful', { provider: providerName });
169
+ } else {
170
+ const errorData = await response.text();
171
+ alert(`❌ ${providerDisplayName} 连接测试失败\n\n状态码: ${response.status}\n错误信息: ${errorData.substring(0, 200)}`);
172
+ this.logger.error('Connection test failed', { provider: providerName, status: response.status });
173
+ }
174
+ } catch (error) {
175
+ const errorMessage = error instanceof Error ? error.message : '未知错误';
176
+ alert(`❌ ${providerDisplayName} 连接测试失败\n\n错误: ${errorMessage}`);
177
+ this.logger.error('Connection test error', { provider: providerName, error: errorMessage });
178
+ }
179
+ }
180
+
181
+ /**
182
+ * 获取测试端点
183
+ */
184
+ private getTestEndpoint(providerName: string, baseURL: string): string {
185
+ // 检查 baseURL 是否包含 anthropic 路径(如 Minimax 的 Anthropic 兼容接口)
186
+ const isAnthropicCompatible = baseURL.includes('/anthropic');
187
+
188
+ if (isAnthropicCompatible) {
189
+ return `${baseURL}/v1/messages`;
190
+ }
191
+
192
+ switch (providerName) {
193
+ case 'openai':
194
+ return `${baseURL}/chat/completions`;
195
+ case 'anthropic':
196
+ return `${baseURL}/v1/messages`;
197
+ case 'glm':
198
+ return `${baseURL}/chat/completions`;
199
+ default:
200
+ return `${baseURL}/v1/chat/completions`;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * 获取测试请求头
206
+ */
207
+ private getTestHeaders(providerName: string, apiKey: string, baseURL: string): Record<string, string> {
208
+ const headers: Record<string, string> = {
209
+ 'Content-Type': 'application/json'
210
+ };
211
+
212
+ // 检查是否使用 Anthropic 兼容接口
213
+ const isAnthropicCompatible = baseURL.includes('/anthropic') || providerName === 'anthropic';
214
+
215
+ if (isAnthropicCompatible) {
216
+ headers['x-api-key'] = apiKey;
217
+ headers['anthropic-version'] = '2023-06-01';
218
+ } else {
219
+ headers['Authorization'] = `Bearer ${apiKey}`;
220
+ }
221
+
222
+ return headers;
223
+ }
224
+
225
+ /**
226
+ * 获取测试请求体
227
+ */
228
+ private getTestBody(providerName: string, baseURL: string): any {
229
+ // 检查是否使用 Anthropic 兼容接口
230
+ const isAnthropicCompatible = baseURL.includes('/anthropic') || providerName === 'anthropic';
231
+
232
+ if (isAnthropicCompatible) {
233
+ return {
234
+ model: this.configs[providerName]?.model || 'claude-3-sonnet-20240229',
235
+ max_tokens: 10,
236
+ messages: [{ role: 'user', content: 'Hi' }]
237
+ };
238
+ }
239
+
240
+ return {
241
+ model: this.configs[providerName]?.model || 'gpt-3.5-turbo',
242
+ max_tokens: 10,
243
+ messages: [{ role: 'user', content: 'Hi' }]
244
+ };
133
245
  }
134
246
 
135
247
  /**
@@ -55,7 +55,7 @@
55
55
 
56
56
  &:hover {
57
57
  background-color: #0056b3;
58
- Y(-1px transform: translate);
58
+ transform: translateY(-1px);
59
59
  }
60
60
 
61
61
  &:active {
@@ -0,0 +1,8 @@
1
+ <button
2
+ class="btn btn-sm btn-primary"
3
+ [title]="tooltip"
4
+ (click)="onClick()"
5
+ >
6
+ <i class="fas fa-robot"></i>
7
+ <span class="ms-1" *ngIf="showLabel">{{ label }}</span>
8
+ </button>
@@ -0,0 +1,20 @@
1
+ :host {
2
+ display: inline-block;
3
+ }
4
+
5
+ button {
6
+ padding: 4px 8px;
7
+ border-radius: 4px;
8
+ border: none;
9
+ background: #007bff;
10
+ color: white;
11
+ cursor: pointer;
12
+ display: flex;
13
+ align-items: center;
14
+ gap: 4px;
15
+ transition: background-color 0.2s;
16
+ }
17
+
18
+ button:hover {
19
+ background: #0056b3;
20
+ }
@@ -6,36 +6,8 @@ import { Component, Input } from '@angular/core';
6
6
  */
7
7
  @Component({
8
8
  selector: 'ai-toolbar-button',
9
- template: `
10
- <button
11
- class="btn btn-sm btn-primary"
12
- [title]="tooltip"
13
- (click)="onClick()"
14
- >
15
- <i class="fas fa-robot"></i>
16
- <span class="ms-1" *ngIf="showLabel">{{ label }}</span>
17
- </button>
18
- `,
19
- styles: [`
20
- :host {
21
- display: inline-block;
22
- }
23
- button {
24
- padding: 4px 8px;
25
- border-radius: 4px;
26
- border: none;
27
- background: #007bff;
28
- color: white;
29
- cursor: pointer;
30
- display: flex;
31
- align-items: center;
32
- gap: 4px;
33
- transition: background-color 0.2s;
34
- }
35
- button:hover {
36
- background: #0056b3;
37
- }
38
- `]
9
+ templateUrl: './ai-toolbar-button.component.html',
10
+ styleUrls: ['./ai-toolbar-button.component.scss']
39
11
  })
40
12
  export class AiToolbarButtonComponent {
41
13
  @Input() label: string = 'AI Assistant';
@@ -0,0 +1,61 @@
1
+ <div class="command-preview" *ngIf="command">
2
+ <div class="preview-header">
3
+ <h4>
4
+ <i class="fa fa-terminal"></i>
5
+ 命令预览
6
+ </h4>
7
+ <button class="btn-close" (click)="close()">
8
+ <i class="fa fa-times"></i>
9
+ </button>
10
+ </div>
11
+
12
+ <div class="preview-content">
13
+ <!-- 风险级别 -->
14
+ <div class="risk-indicator" [ngClass]="'risk-' + riskLevel.toLowerCase()">
15
+ <i [class]="getRiskIcon()"></i>
16
+ <span>{{ getRiskText() }}</span>
17
+ </div>
18
+
19
+ <!-- 命令 -->
20
+ <div class="command-section">
21
+ <label>将要执行的命令:</label>
22
+ <div class="command-display">
23
+ <code>{{ command.command }}</code>
24
+ <button class="btn-copy" (click)="copyCommand()" title="复制">
25
+ <i class="fa fa-copy"></i>
26
+ </button>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- 解释 -->
31
+ <div class="explanation-section">
32
+ <label>命令解释:</label>
33
+ <p>{{ command.explanation }}</p>
34
+ </div>
35
+
36
+ <!-- 置信度 -->
37
+ <div class="confidence-section" *ngIf="command.confidence">
38
+ <label>AI置信度:</label>
39
+ <div class="confidence-meter">
40
+ <div class="confidence-bar" [style.width.%]="command.confidence * 100"></div>
41
+ <span class="confidence-text">{{ (command.confidence * 100).toFixed(0) }}%</span>
42
+ </div>
43
+ </div>
44
+
45
+ <!-- 替代方案 -->
46
+ <div class="alternatives-section" *ngIf="command.alternatives && command.alternatives.length > 0">
47
+ <label>替代方案:</label>
48
+ <div class="alternatives-list">
49
+ <div *ngFor="let alt of command.alternatives" class="alternative-item" (click)="selectAlternative(alt)">
50
+ <code>{{ alt.command }}</code>
51
+ <span class="alt-confidence">{{ (alt.confidence * 100).toFixed(0) }}%</span>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="preview-footer">
58
+ <button class="btn btn-secondary" (click)="close()">取消</button>
59
+ <button class="btn btn-primary" (click)="execute()">执行命令</button>
60
+ </div>
61
+ </div>
@@ -0,0 +1,72 @@
1
+ .command-preview {
2
+ background: var(--ai-bg-primary);
3
+ border: 1px solid var(--ai-border);
4
+ border-radius: 0.5rem;
5
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
6
+ max-width: 600px;
7
+ }
8
+
9
+ .preview-header {
10
+ display: flex;
11
+ justify-content: space-between;
12
+ align-items: center;
13
+ padding: 1rem;
14
+ background: var(--ai-bg-secondary);
15
+ border-bottom: 1px solid var(--ai-border);
16
+ }
17
+
18
+ .preview-content {
19
+ padding: 1rem;
20
+ max-height: 50vh;
21
+ overflow-y: auto;
22
+ }
23
+
24
+ .risk-indicator {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 0.5rem;
28
+ padding: 0.5rem;
29
+ margin-bottom: 1rem;
30
+ border-radius: 0.375rem;
31
+ }
32
+
33
+ .command-section, .explanation-section, .confidence-section, .alternatives-section {
34
+ margin-bottom: 1rem;
35
+ }
36
+
37
+ .command-display {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 0.5rem;
41
+ background: var(--ai-bg-secondary);
42
+ padding: 0.75rem;
43
+ border-radius: 0.375rem;
44
+ }
45
+
46
+ .alternatives-list {
47
+ background: var(--ai-bg-secondary);
48
+ border-radius: 0.375rem;
49
+ overflow: hidden;
50
+ }
51
+
52
+ .alternative-item {
53
+ padding: 0.75rem;
54
+ border-bottom: 1px solid var(--ai-border);
55
+ cursor: pointer;
56
+ transition: background-color 0.2s;
57
+ display: flex;
58
+ justify-content: space-between;
59
+ align-items: center;
60
+ }
61
+
62
+ .alternative-item:hover {
63
+ background-color: var(--ai-border);
64
+ }
65
+
66
+ .preview-footer {
67
+ padding: 1rem;
68
+ display: flex;
69
+ justify-content: flex-end;
70
+ gap: 0.5rem;
71
+ border-top: 1px solid var(--ai-border);
72
+ }