tabby-ai-assistant 1.0.13 → 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 (41) hide show
  1. package/.editorconfig +18 -0
  2. package/dist/index.js +1 -1
  3. package/package.json +6 -4
  4. package/src/components/chat/ai-sidebar.component.scss +220 -9
  5. package/src/components/chat/ai-sidebar.component.ts +364 -29
  6. package/src/components/chat/chat-input.component.ts +36 -4
  7. package/src/components/chat/chat-interface.component.ts +225 -5
  8. package/src/components/chat/chat-message.component.ts +6 -1
  9. package/src/components/settings/context-settings.component.ts +91 -91
  10. package/src/components/terminal/ai-toolbar-button.component.ts +4 -2
  11. package/src/components/terminal/command-suggestion.component.ts +148 -6
  12. package/src/index.ts +0 -6
  13. package/src/providers/tabby/ai-toolbar-button.provider.ts +7 -3
  14. package/src/services/chat/ai-sidebar.service.ts +414 -410
  15. package/src/services/chat/chat-session.service.ts +36 -12
  16. package/src/services/context/compaction.ts +110 -134
  17. package/src/services/context/manager.ts +27 -7
  18. package/src/services/context/memory.ts +17 -33
  19. package/src/services/context/summary.service.ts +136 -0
  20. package/src/services/core/ai-assistant.service.ts +1060 -37
  21. package/src/services/core/ai-provider-manager.service.ts +154 -25
  22. package/src/services/core/checkpoint.service.ts +218 -18
  23. package/src/services/core/toast.service.ts +106 -106
  24. package/src/services/providers/anthropic-provider.service.ts +126 -30
  25. package/src/services/providers/base-provider.service.ts +90 -7
  26. package/src/services/providers/glm-provider.service.ts +151 -38
  27. package/src/services/providers/minimax-provider.service.ts +55 -40
  28. package/src/services/providers/ollama-provider.service.ts +117 -28
  29. package/src/services/providers/openai-compatible.service.ts +164 -34
  30. package/src/services/providers/openai-provider.service.ts +169 -34
  31. package/src/services/providers/vllm-provider.service.ts +116 -28
  32. package/src/services/terminal/terminal-context.service.ts +265 -5
  33. package/src/services/terminal/terminal-manager.service.ts +748 -748
  34. package/src/services/terminal/terminal-tools.service.ts +612 -441
  35. package/src/types/ai.types.ts +156 -3
  36. package/src/utils/cost.utils.ts +249 -0
  37. package/src/utils/validation.utils.ts +306 -2
  38. package/dist/index.js.LICENSE.txt +0 -18
  39. package/src/services/terminal/command-analyzer.service.ts +0 -43
  40. package/src/services/terminal/context-menu.service.ts +0 -45
  41. package/src/services/terminal/hotkey.service.ts +0 -53
@@ -0,0 +1,136 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { AiAssistantService } from '../core/ai-assistant.service';
3
+ import { LoggerService } from '../core/logger.service';
4
+ import { ChatMessage, MessageRole, ApiMessage } from '../../types/ai.types';
5
+
6
+ /**
7
+ * 摘要生成结果
8
+ */
9
+ export interface SummaryResult {
10
+ summary: string;
11
+ tokensCost: number;
12
+ originalMessageCount: number;
13
+ }
14
+
15
+ /**
16
+ * 摘要服务
17
+ * 使用 AI 生成消息摘要,用于上下文压缩和记忆管理
18
+ */
19
+ @Injectable({ providedIn: 'root' })
20
+ export class SummaryService {
21
+ constructor(
22
+ private aiService: AiAssistantService,
23
+ private logger: LoggerService
24
+ ) {}
25
+
26
+ /**
27
+ * 使用 AI 生成消息摘要
28
+ * @param messages 要摘要的消息数组(支持 ApiMessage 和 ChatMessage)
29
+ * @param maxLength 摘要最大长度(默认200字)
30
+ */
31
+ async generateSummary(messages: (ChatMessage | ApiMessage)[], maxLength: number = 200): Promise<SummaryResult> {
32
+ try {
33
+ if (!messages || messages.length === 0) {
34
+ return {
35
+ summary: '',
36
+ tokensCost: 0,
37
+ originalMessageCount: 0
38
+ };
39
+ }
40
+
41
+ // 构建摘要提示
42
+ const prompt = this.buildSummaryPrompt(messages, maxLength);
43
+
44
+ // 调用 AI 生成摘要
45
+ const response = await this.aiService.chat({
46
+ messages: [{
47
+ role: MessageRole.USER,
48
+ content: prompt,
49
+ id: 'summary-request',
50
+ timestamp: new Date()
51
+ }],
52
+ maxTokens: 500,
53
+ temperature: 0.3 // 低温度以获得更稳定的摘要
54
+ });
55
+
56
+ const summary = response.message?.content?.trim() || '';
57
+
58
+ this.logger.debug('Summary generated', {
59
+ originalCount: messages.length,
60
+ summaryLength: summary.length,
61
+ tokensCost: response.usage?.totalTokens || 0
62
+ });
63
+
64
+ return {
65
+ summary,
66
+ tokensCost: response.usage?.totalTokens || 0,
67
+ originalMessageCount: messages.length
68
+ };
69
+ } catch (error) {
70
+ this.logger.error('Failed to generate summary', error);
71
+ // 返回空摘要作为降级方案
72
+ return {
73
+ summary: `[摘要失败,共 ${messages.length} 条消息]`,
74
+ tokensCost: 0,
75
+ originalMessageCount: messages.length
76
+ };
77
+ }
78
+ }
79
+
80
+ /**
81
+ * 从消息列表生成简化的消息数组
82
+ */
83
+ private formatMessagesForSummary(messages: (ChatMessage | ApiMessage)[]): { role: string; content: string; timestamp?: Date }[] {
84
+ return messages.map(msg => {
85
+ // 处理 ChatMessage (有 timestamp: Date)
86
+ if ('timestamp' in msg && msg.timestamp instanceof Date) {
87
+ return {
88
+ role: String(msg.role),
89
+ content: typeof msg.content === 'string' ? msg.content : '[复杂内容]',
90
+ timestamp: msg.timestamp
91
+ };
92
+ }
93
+ // 处理 ApiMessage (有 ts: number)
94
+ return {
95
+ role: String(msg.role),
96
+ content: typeof msg.content === 'string' ? msg.content : '[复杂内容]'
97
+ };
98
+ });
99
+ }
100
+
101
+ /**
102
+ * 构建摘要提示词
103
+ */
104
+ private buildSummaryPrompt(messages: (ChatMessage | ApiMessage)[], maxLength: number): string {
105
+ const formattedMessages = this.formatMessagesForSummary(messages);
106
+
107
+ // 如果消息太多,截取最后N条
108
+ const maxMessages = 20;
109
+ const recentMessages = formattedMessages.slice(-maxMessages);
110
+ const truncated = formattedMessages.length > maxMessages;
111
+
112
+ const content = recentMessages.map(m =>
113
+ `[${m.role}]: ${m.content}`
114
+ ).join('\n');
115
+
116
+ return `请简洁概括以下对话的主要内容和结论,不超过${maxLength}字。\n${truncated ? `(共 ${formattedMessages.length} 条消息,显示最后 ${maxMessages} 条)\n` : ''}\n${content}\n\n请直接返回摘要,不需要其他解释。`;
117
+ }
118
+
119
+ /**
120
+ * 检查是否需要对消息进行摘要
121
+ * 基于消息数量和token数量判断
122
+ */
123
+ shouldSummarize(messageCount: number, tokenCount: number, thresholdCount: number = 30, thresholdTokens: number = 8000): boolean {
124
+ return messageCount > thresholdCount || tokenCount > thresholdTokens;
125
+ }
126
+
127
+ /**
128
+ * 计算摘要的压缩率
129
+ */
130
+ calculateCompressionRatio(originalCount: number, summaryLength: number): number {
131
+ if (originalCount === 0) return 0;
132
+ // 假设平均每条消息50个字符,计算理论压缩比
133
+ const originalLength = originalCount * 50;
134
+ return originalLength > 0 ? Math.round((1 - summaryLength / originalLength) * 100) : 0;
135
+ }
136
+ }