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
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Observable, Observer } 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';
|
|
5
|
-
import { ChatRequest, ChatResponse, CommandRequest, CommandResponse, ExplainRequest, ExplainResponse, AnalysisRequest, AnalysisResponse, MessageRole } from '../../types/ai.types';
|
|
6
|
+
import { ChatRequest, ChatResponse, CommandRequest, CommandResponse, ExplainRequest, ExplainResponse, AnalysisRequest, AnalysisResponse, MessageRole, StreamEvent } from '../../types/ai.types';
|
|
6
7
|
import { LoggerService } from '../core/logger.service';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -79,14 +80,23 @@ export class MinimaxProviderService extends BaseAiProvider {
|
|
|
79
80
|
|
|
80
81
|
try {
|
|
81
82
|
const response = await this.withRetry(async () => {
|
|
82
|
-
|
|
83
|
+
// 构建请求参数
|
|
84
|
+
const createParams: any = {
|
|
83
85
|
model: this.config?.model || 'MiniMax-M2',
|
|
84
86
|
max_tokens: request.maxTokens || 1000,
|
|
85
87
|
system: request.systemPrompt || this.getDefaultSystemPrompt(),
|
|
86
88
|
messages: this.transformMessages(request.messages),
|
|
87
89
|
temperature: request.temperature || 1.0,
|
|
88
90
|
stream: request.stream || false
|
|
89
|
-
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// 如果有工具定义,添加到请求中
|
|
94
|
+
if (request.tools && request.tools.length > 0) {
|
|
95
|
+
createParams.tools = request.tools;
|
|
96
|
+
this.logger.info('Adding tools to request', { toolCount: request.tools.length });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = await this.client!.messages.create(createParams);
|
|
90
100
|
|
|
91
101
|
this.logResponse(result);
|
|
92
102
|
return result;
|
|
@@ -100,6 +110,109 @@ export class MinimaxProviderService extends BaseAiProvider {
|
|
|
100
110
|
}
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
/**
|
|
114
|
+
* 流式聊天功能
|
|
115
|
+
*/
|
|
116
|
+
chatStream(request: ChatRequest): Observable<StreamEvent> {
|
|
117
|
+
return new Observable<StreamEvent>((subscriber: Observer<StreamEvent>) => {
|
|
118
|
+
if (!this.client) {
|
|
119
|
+
subscriber.error(new Error('Minimax client not initialized'));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.logRequest(request);
|
|
124
|
+
|
|
125
|
+
const runStream = async () => {
|
|
126
|
+
try {
|
|
127
|
+
// 注意:SDK 类型定义可能不包含 tools,但 API 实际支持
|
|
128
|
+
// 使用 as any 绕过类型检查
|
|
129
|
+
const stream = (this.client!.messages.stream as any)({
|
|
130
|
+
model: this.config?.model || 'MiniMax-M2',
|
|
131
|
+
max_tokens: request.maxTokens || 1000,
|
|
132
|
+
system: request.systemPrompt || this.getDefaultSystemPrompt(),
|
|
133
|
+
messages: this.transformMessages(request.messages),
|
|
134
|
+
temperature: request.temperature || 1.0,
|
|
135
|
+
tools: request.tools // 流式 API 支持工具调用
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// 累积工具调用数据
|
|
139
|
+
let currentToolId = '';
|
|
140
|
+
let currentToolName = '';
|
|
141
|
+
let currentToolInput = '';
|
|
142
|
+
|
|
143
|
+
for await (const event of stream) {
|
|
144
|
+
if (event.type === 'content_block_delta') {
|
|
145
|
+
const delta = event.delta as any;
|
|
146
|
+
// 文本增量
|
|
147
|
+
if (delta.type === 'text_delta') {
|
|
148
|
+
subscriber.next({
|
|
149
|
+
type: 'text_delta',
|
|
150
|
+
textDelta: delta.text
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// 工具输入增量
|
|
154
|
+
else if (delta.type === 'input_json_delta') {
|
|
155
|
+
currentToolInput += delta.partial_json || '';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// 工具调用开始
|
|
159
|
+
else if (event.type === 'content_block_start') {
|
|
160
|
+
const block = event.content_block as any;
|
|
161
|
+
if (block.type === 'tool_use') {
|
|
162
|
+
currentToolId = block.id;
|
|
163
|
+
currentToolName = block.name;
|
|
164
|
+
currentToolInput = '';
|
|
165
|
+
subscriber.next({ type: 'tool_use_start' });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 内容块结束
|
|
169
|
+
else if (event.type === 'content_block_stop') {
|
|
170
|
+
// 如果有工具调用,发送完整的工具调用
|
|
171
|
+
if (currentToolId && currentToolName) {
|
|
172
|
+
let parsedInput = {};
|
|
173
|
+
try {
|
|
174
|
+
parsedInput = JSON.parse(currentToolInput || '{}');
|
|
175
|
+
} catch (e) {
|
|
176
|
+
this.logger.warn('Failed to parse tool input', { input: currentToolInput });
|
|
177
|
+
}
|
|
178
|
+
subscriber.next({
|
|
179
|
+
type: 'tool_use_end',
|
|
180
|
+
toolCall: {
|
|
181
|
+
id: currentToolId,
|
|
182
|
+
name: currentToolName,
|
|
183
|
+
input: parsedInput
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
// 重置
|
|
187
|
+
currentToolId = '';
|
|
188
|
+
currentToolName = '';
|
|
189
|
+
currentToolInput = '';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 获取最终消息
|
|
195
|
+
const finalMessage = await stream.finalMessage();
|
|
196
|
+
subscriber.next({
|
|
197
|
+
type: 'message_end',
|
|
198
|
+
message: this.transformChatResponse(finalMessage).message
|
|
199
|
+
});
|
|
200
|
+
subscriber.complete();
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.logError(error, { request });
|
|
203
|
+
subscriber.error(new Error(`Minimax stream failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
runStream();
|
|
208
|
+
|
|
209
|
+
// 返回取消订阅的处理函数
|
|
210
|
+
return () => {
|
|
211
|
+
this.logger.debug('Stream subscription cancelled');
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
103
216
|
/**
|
|
104
217
|
* 生成命令
|
|
105
218
|
*/
|
|
@@ -231,11 +344,26 @@ export class MinimaxProviderService extends BaseAiProvider {
|
|
|
231
344
|
|
|
232
345
|
/**
|
|
233
346
|
* 转换消息格式
|
|
347
|
+
* Anthropic API 支持两种格式:
|
|
348
|
+
* 1. 简单字符串: { role: 'user', content: 'Hello' }
|
|
349
|
+
* 2. 内容块数组: { role: 'user', content: [{ type: 'text', text: 'Hello' }] }
|
|
350
|
+
* 使用简单字符串格式以确保兼容性
|
|
234
351
|
*/
|
|
235
352
|
protected transformMessages(messages: any[]): any[] {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
353
|
+
// 过滤掉系统消息(system role 不应该在 messages 数组中)
|
|
354
|
+
const filteredMessages = messages.filter(msg =>
|
|
355
|
+
msg.role === 'user' || msg.role === 'assistant'
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
this.logger.info('Transforming messages', {
|
|
359
|
+
originalCount: messages.length,
|
|
360
|
+
filteredCount: filteredMessages.length,
|
|
361
|
+
roles: messages.map(m => m.role)
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
return filteredMessages.map(msg => ({
|
|
365
|
+
role: msg.role === 'user' ? 'user' : 'assistant',
|
|
366
|
+
content: String(msg.content || '')
|
|
239
367
|
}));
|
|
240
368
|
}
|
|
241
369
|
|
|
@@ -243,22 +371,74 @@ export class MinimaxProviderService extends BaseAiProvider {
|
|
|
243
371
|
* 转换聊天响应
|
|
244
372
|
*/
|
|
245
373
|
private transformChatResponse(response: any): ChatResponse {
|
|
246
|
-
|
|
247
|
-
|
|
374
|
+
this.logger.info('Transforming chat response', {
|
|
375
|
+
hasContent: !!response?.content,
|
|
376
|
+
contentLength: response?.content?.length,
|
|
377
|
+
responseKeys: Object.keys(response || {})
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
let text = '';
|
|
381
|
+
let toolCalls: any[] = [];
|
|
382
|
+
|
|
383
|
+
// 尝试多种方式提取响应文本和工具调用
|
|
384
|
+
if (response?.content) {
|
|
385
|
+
if (Array.isArray(response.content)) {
|
|
386
|
+
// Anthropic 格式: content 是数组
|
|
387
|
+
for (const block of response.content) {
|
|
388
|
+
if (block.type === 'text') {
|
|
389
|
+
text += block.text || '';
|
|
390
|
+
} else if (block.type === 'tool_use') {
|
|
391
|
+
// 提取工具调用
|
|
392
|
+
toolCalls.push({
|
|
393
|
+
id: block.id,
|
|
394
|
+
name: block.name,
|
|
395
|
+
input: block.input
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} else if (typeof response.content === 'string') {
|
|
400
|
+
// 直接是字符串
|
|
401
|
+
text = response.content;
|
|
402
|
+
}
|
|
403
|
+
} else if (response?.message?.content) {
|
|
404
|
+
// 某些 API 可能使用 message.content
|
|
405
|
+
text = response.message.content;
|
|
406
|
+
} else if (response?.choices?.[0]?.message?.content) {
|
|
407
|
+
// OpenAI 兼容格式
|
|
408
|
+
text = response.choices[0].message.content;
|
|
409
|
+
}
|
|
248
410
|
|
|
249
|
-
|
|
411
|
+
this.logger.info('Extracted response', {
|
|
412
|
+
textLength: text.length,
|
|
413
|
+
textPreview: text.substring(0, 100),
|
|
414
|
+
toolCallCount: toolCalls.length
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
if (!text && toolCalls.length === 0) {
|
|
418
|
+
this.logger.warn('Empty response text and no tool calls, full response:', response);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const result: any = {
|
|
250
422
|
message: {
|
|
251
423
|
id: this.generateId(),
|
|
252
424
|
role: MessageRole.ASSISTANT,
|
|
253
425
|
content: text,
|
|
254
426
|
timestamp: new Date()
|
|
255
427
|
},
|
|
256
|
-
usage: response
|
|
428
|
+
usage: response?.usage ? {
|
|
257
429
|
promptTokens: response.usage.input_tokens || 0,
|
|
258
430
|
completionTokens: response.usage.output_tokens || 0,
|
|
259
431
|
totalTokens: (response.usage.input_tokens || 0) + (response.usage.output_tokens || 0)
|
|
260
432
|
} : undefined
|
|
261
433
|
};
|
|
434
|
+
|
|
435
|
+
// 如果有工具调用,添加到响应中
|
|
436
|
+
if (toolCalls.length > 0) {
|
|
437
|
+
result.toolCalls = toolCalls;
|
|
438
|
+
this.logger.info('Tool calls extracted', { toolCalls });
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return result;
|
|
262
442
|
}
|
|
263
443
|
|
|
264
444
|
/**
|
|
@@ -422,6 +602,24 @@ export class MinimaxProviderService extends BaseAiProvider {
|
|
|
422
602
|
* 获取默认系统提示
|
|
423
603
|
*/
|
|
424
604
|
private getDefaultSystemPrompt(): string {
|
|
425
|
-
return
|
|
605
|
+
return `你是一个专业的终端命令助手,运行在 Tabby 终端中。
|
|
606
|
+
|
|
607
|
+
## 核心能力
|
|
608
|
+
你可以通过以下工具直接操作终端:
|
|
609
|
+
- write_to_terminal: 向终端写入并执行命令
|
|
610
|
+
- read_terminal_output: 读取终端输出
|
|
611
|
+
- get_terminal_list: 获取所有终端列表
|
|
612
|
+
- get_terminal_cwd: 获取当前工作目录
|
|
613
|
+
|
|
614
|
+
## 重要规则
|
|
615
|
+
1. 当用户请求执行命令(如"查看当前目录"、"列出文件"等),你必须使用 write_to_terminal 工具来执行
|
|
616
|
+
2. 不要只是描述你"将要做什么",而是直接调用工具执行
|
|
617
|
+
3. 执行命令后,使用 read_terminal_output 读取结果并报告给用户
|
|
618
|
+
4. 如果不确定当前目录或终端状态,先使用 get_terminal_cwd 或 get_terminal_list 获取信息
|
|
619
|
+
|
|
620
|
+
## 示例
|
|
621
|
+
用户:"查看当前目录的文件"
|
|
622
|
+
正确做法:调用 write_to_terminal 工具,参数 { "command": "dir", "execute": true }
|
|
623
|
+
错误做法:仅回复文字"我将执行 dir 命令"`;
|
|
426
624
|
}
|
|
427
625
|
}
|