autosnippet 3.3.6 → 3.3.7
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/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
- package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
- package/dashboard/dist/assets/index-DzoB7kxK.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +1 -0
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
- package/dist/lib/agent/forced-summary.js +7 -2
- package/dist/lib/cli/AiScanService.js +4 -4
- package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
- package/dist/lib/external/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +16 -8
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +2 -1
- package/dist/lib/external/mcp/handlers/evolve-external.js +5 -2
- package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
- package/dist/lib/http/routes/ai.js +111 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/modules.js +27 -0
- package/dist/lib/http/routes/recipes.js +7 -0
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- package/dist/lib/injection/ServiceContainer.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +11 -27
- package/dist/lib/injection/ServiceMap.d.ts +2 -0
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- package/dist/lib/injection/modules/PanoramaModule.js +1 -1
- package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
- package/dist/lib/service/cleanup/CleanupService.js +284 -37
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +6 -0
- package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +23 -10
- package/dist/lib/service/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
- package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +1 -1
- package/dist/lib/service/panorama/DimensionAnalyzer.js +31 -17
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
- package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
- package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
- package/dist/lib/service/panorama/PanoramaService.js +10 -5
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
- package/dist/lib/service/panorama/RoleRefiner.js +41 -0
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +1 -0
- package/dist/lib/service/skills/SignalCollector.js +6 -5
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- package/dist/lib/shared/LanguageService.js +3 -0
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
- package/dist/lib/shared/schemas/http-requests.js +9 -6
- package/dist/lib/types/knowledge-wire.d.ts +1 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
- package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
- package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
|
@@ -1,47 +1,323 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MockProvider
|
|
3
|
-
*
|
|
2
|
+
* MockProvider — Smart Mock AI 提供商
|
|
3
|
+
*
|
|
4
|
+
* 不发网络请求,但根据 prompt 内容智能匹配场景,返回符合格式的仿真响应。
|
|
5
|
+
* 用于让用户在没有 API Key 的情况下体验 AutoSnippet 完整工作流。
|
|
6
|
+
*
|
|
7
|
+
* 智能匹配场景:
|
|
8
|
+
* 1. probe / ping → "pong"
|
|
9
|
+
* 2. 重复度检测 (DUPLICATE/SIMILAR/UNIQUE) → "UNIQUE"
|
|
10
|
+
* 3. 对话压缩总结 → 从消息中提取关键词
|
|
11
|
+
* 4. 代码上下文化 (<chunk>) → 从代码提取函数/类名
|
|
12
|
+
* 5. 候选润色 (JSON 9字段) → 原样回传输入字段
|
|
13
|
+
* 6. 维度摘要 (dimensionDigest) → 模板化 JSON
|
|
14
|
+
* 7. 风格检查建议 → 空数组
|
|
15
|
+
* 8. Agent 路由分类 → functionCall classify_intent
|
|
16
|
+
* 9. 通用 fallback → 语义化占位文本
|
|
17
|
+
*
|
|
18
|
+
* 模拟延迟: 50-200ms 随机延迟,营造 "AI 思考" 体验
|
|
4
19
|
*/
|
|
5
|
-
import { AiProvider } from '../AiProvider.js';
|
|
20
|
+
import { AiProvider, } from '../AiProvider.js';
|
|
21
|
+
// ── 工具函数 ──────────────────────────────────────────────
|
|
22
|
+
/** 模拟延迟 (50-200ms) */
|
|
23
|
+
function mockDelay() {
|
|
24
|
+
const ms = 50 + Math.floor(Math.random() * 150);
|
|
25
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
26
|
+
}
|
|
27
|
+
/** 模拟 token 用量 */
|
|
28
|
+
function mockUsage(prompt, response) {
|
|
29
|
+
return {
|
|
30
|
+
inputTokens: Math.ceil(prompt.length / 4),
|
|
31
|
+
outputTokens: Math.ceil(response.length / 4),
|
|
32
|
+
totalTokens: Math.ceil(prompt.length / 4) + Math.ceil(response.length / 4),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** 从代码片段中提取函数/类/结构名称 */
|
|
36
|
+
function extractCodeSymbols(code) {
|
|
37
|
+
const symbols = [];
|
|
38
|
+
// Swift/TS class/struct/protocol/enum
|
|
39
|
+
for (const m of code.matchAll(/(?:class|struct|protocol|enum|interface|type)\s+(\w+)/g)) {
|
|
40
|
+
symbols.push(m[1]);
|
|
41
|
+
}
|
|
42
|
+
// func/function
|
|
43
|
+
for (const m of code.matchAll(/(?:func|function)\s+(\w+)/g)) {
|
|
44
|
+
symbols.push(m[1]);
|
|
45
|
+
}
|
|
46
|
+
// property patterns
|
|
47
|
+
for (const m of code.matchAll(/(?:let|var|const)\s+(\w+)/g)) {
|
|
48
|
+
if (m[1].length > 3) {
|
|
49
|
+
symbols.push(m[1]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return [...new Set(symbols)].slice(0, 8);
|
|
53
|
+
}
|
|
54
|
+
/** 从 prompt 中尝试提取 JSON 输入(用于润色回传) */
|
|
55
|
+
function extractJsonFromPrompt(prompt) {
|
|
56
|
+
try {
|
|
57
|
+
const match = prompt.match(/\{[\s\S]*?"description"[\s\S]*?\}/);
|
|
58
|
+
if (match) {
|
|
59
|
+
return JSON.parse(match[0]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* parse failed */
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
// ── MockProvider ─────────────────────────────────────────
|
|
6
68
|
export class MockProvider extends AiProvider {
|
|
7
69
|
callLog;
|
|
8
70
|
responses;
|
|
9
71
|
constructor(config = {}) {
|
|
10
72
|
super(config);
|
|
11
73
|
this.name = 'mock';
|
|
12
|
-
this.model = 'mock-
|
|
74
|
+
this.model = 'mock-smart';
|
|
13
75
|
this.responses = config.responses || {};
|
|
14
76
|
this.callLog = [];
|
|
15
77
|
}
|
|
78
|
+
// ── 核心: chat() 智能路由 ──────────────────────────────
|
|
16
79
|
async chat(prompt, context = {}) {
|
|
17
|
-
this.callLog.push({ method: 'chat', prompt, context });
|
|
80
|
+
this.callLog.push({ method: 'chat', prompt: prompt.slice(0, 200), context });
|
|
81
|
+
await mockDelay();
|
|
82
|
+
// 0. 用户注入的固定响应(单元测试用)
|
|
18
83
|
if (this.responses.chat) {
|
|
19
84
|
return this.responses.chat;
|
|
20
85
|
}
|
|
21
|
-
|
|
86
|
+
const p = prompt.toLowerCase();
|
|
87
|
+
// 1. Probe / ping
|
|
88
|
+
if (p === 'ping' || p.includes('ping')) {
|
|
89
|
+
return 'pong';
|
|
90
|
+
}
|
|
91
|
+
// 2. 重复度检测 — "请回答: DUPLICATE / SIMILAR / UNIQUE"
|
|
92
|
+
if (p.includes('duplicate') && p.includes('similar') && p.includes('unique')) {
|
|
93
|
+
return 'UNIQUE';
|
|
94
|
+
}
|
|
95
|
+
// 3. 对话压缩总结 — "请用 2-3 句话总结"
|
|
96
|
+
if (p.includes('总结以下对话') || p.includes('summarize the following')) {
|
|
97
|
+
const lines = prompt
|
|
98
|
+
.split('\n')
|
|
99
|
+
.filter((l) => l.startsWith('[user]') || l.startsWith('[assistant]'));
|
|
100
|
+
const topics = lines
|
|
101
|
+
.slice(0, 3)
|
|
102
|
+
.map((l) => l.slice(0, 60))
|
|
103
|
+
.join(';');
|
|
104
|
+
return `[Mock 摘要] 对话涉及: ${topics || '项目开发相关讨论'}。用户和助手讨论了代码实现和架构设计。`;
|
|
105
|
+
}
|
|
106
|
+
// 4. 代码上下文化 — <chunk>...</chunk>
|
|
107
|
+
if (p.includes('<chunk>')) {
|
|
108
|
+
const chunkMatch = prompt.match(/<chunk>([\s\S]*?)<\/chunk>/);
|
|
109
|
+
if (chunkMatch) {
|
|
110
|
+
const symbols = extractCodeSymbols(chunkMatch[1]);
|
|
111
|
+
if (symbols.length > 0) {
|
|
112
|
+
return `This chunk defines ${symbols.slice(0, 3).join(', ')} which handles ${symbols.length > 3 ? symbols.slice(3, 5).join(' and ') : 'core logic'} in the module.`;
|
|
113
|
+
}
|
|
114
|
+
return 'This chunk contains utility code for the module.';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// 5. 候选润色 — "知识库条目润色助手" + JSON 输出
|
|
118
|
+
if (p.includes('知识库条目润色') || p.includes('润色助手')) {
|
|
119
|
+
const existing = extractJsonFromPrompt(prompt);
|
|
120
|
+
if (existing) {
|
|
121
|
+
return JSON.stringify(existing);
|
|
122
|
+
}
|
|
123
|
+
return JSON.stringify({
|
|
124
|
+
description: '[Mock] 保持原内容不变',
|
|
125
|
+
pattern: '',
|
|
126
|
+
markdown: '',
|
|
127
|
+
rationale: '',
|
|
128
|
+
tags: [],
|
|
129
|
+
confidence: 0.8,
|
|
130
|
+
aiInsight: null,
|
|
131
|
+
agentNotes: null,
|
|
132
|
+
relations: {},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// 6. 维度摘要 — "dimensionDigest"
|
|
136
|
+
if (p.includes('dimensiondigest') || p.includes('dimension digest')) {
|
|
137
|
+
const dimMatch = prompt.match(/维度[::]\s*["']?(\w[\w-]+)/i) ||
|
|
138
|
+
prompt.match(/dimension[::]\s*["']?(\w[\w-]+)/i);
|
|
139
|
+
const dimId = dimMatch?.[1] || 'unknown';
|
|
140
|
+
const countMatch = prompt.match(/提交了\s*(\d+)\s*个候选/);
|
|
141
|
+
const count = countMatch ? parseInt(countMatch[1], 10) : 3;
|
|
142
|
+
return `\`\`\`json
|
|
143
|
+
${JSON.stringify({
|
|
144
|
+
dimensionDigest: {
|
|
145
|
+
summary: `[Mock] ${dimId} 维度分析完成,基于项目代码结构生成了 ${count} 个候选知识。`,
|
|
146
|
+
candidateCount: count,
|
|
147
|
+
keyFindings: ['项目采用模块化架构设计', '发现多个核心设计模式', '代码风格整体一致'],
|
|
148
|
+
crossRefs: {},
|
|
149
|
+
gaps: ['部分模块缺少充分的文档注释'],
|
|
150
|
+
remainingTasks: [],
|
|
151
|
+
},
|
|
152
|
+
}, null, 2)}
|
|
153
|
+
\`\`\``;
|
|
154
|
+
}
|
|
155
|
+
// 7. 风格检查建议 — "violation" + "suggestion"
|
|
156
|
+
if (p.includes('violation') && p.includes('suggestion')) {
|
|
157
|
+
return '[]';
|
|
158
|
+
}
|
|
159
|
+
// 8. 分析报告 — "Markdown 格式" + "代码分析报告"
|
|
160
|
+
if (p.includes('代码分析报告') || p.includes('分析报告')) {
|
|
161
|
+
const symbols = extractCodeSymbols(prompt);
|
|
162
|
+
return `## Mock 代码分析报告
|
|
163
|
+
|
|
164
|
+
### 核心发现
|
|
165
|
+
|
|
166
|
+
1. **模块结构**: 项目采用分层架构,${symbols.length > 0 ? `核心类型包括 ${symbols.slice(0, 3).join('、')}` : '各模块职责清晰'}
|
|
167
|
+
2. **设计模式**: 广泛使用协议/接口抽象和依赖注入
|
|
168
|
+
3. **代码质量**: 类型安全处理规范,错误处理完善
|
|
169
|
+
|
|
170
|
+
### 文件分析
|
|
171
|
+
|
|
172
|
+
分析的文件展现了良好的代码组织,模块间通过明确的接口通信。
|
|
173
|
+
|
|
174
|
+
> ⚠️ 此报告由 Mock AI 生成,仅包含模板化分析结果。`;
|
|
175
|
+
}
|
|
176
|
+
// 9. 通用 fallback — 语义化占位
|
|
177
|
+
const symbols = extractCodeSymbols(prompt);
|
|
178
|
+
const topic = symbols.length > 0
|
|
179
|
+
? `关于 ${symbols.slice(0, 3).join('、')} 的分析`
|
|
180
|
+
: `对 ${prompt.slice(0, 40).replace(/\n/g, ' ')} 的回复`;
|
|
181
|
+
return `[Mock AI] ${topic}。此响应由 Mock 模式生成,非真实 AI 分析结果。`;
|
|
182
|
+
}
|
|
183
|
+
// ── chatWithTools() — 智能函数调用模拟 ─────────────────
|
|
184
|
+
async chatWithTools(prompt, opts = {}) {
|
|
185
|
+
this.callLog.push({
|
|
186
|
+
method: 'chatWithTools',
|
|
187
|
+
prompt: prompt.slice(0, 200),
|
|
188
|
+
toolChoice: opts.toolChoice,
|
|
189
|
+
});
|
|
190
|
+
await mockDelay();
|
|
191
|
+
const schemas = (opts.toolSchemas || []);
|
|
192
|
+
const schemaNames = schemas.map((s) => s.name);
|
|
193
|
+
// toolChoice='none' → 纯文本回复(维度摘要、最终总结等)
|
|
194
|
+
if (opts.toolChoice === 'none') {
|
|
195
|
+
const text = await this.chat(prompt, {
|
|
196
|
+
systemPrompt: opts.systemPrompt,
|
|
197
|
+
temperature: opts.temperature,
|
|
198
|
+
maxTokens: opts.maxTokens,
|
|
199
|
+
});
|
|
200
|
+
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
|
|
201
|
+
}
|
|
202
|
+
// Agent 路由分类 — classify_intent tool
|
|
203
|
+
if (schemaNames.includes('classify_intent')) {
|
|
204
|
+
const response = JSON.stringify({ type: 'general', confidence: 0.9 });
|
|
205
|
+
return {
|
|
206
|
+
text: null,
|
|
207
|
+
functionCalls: [
|
|
208
|
+
{
|
|
209
|
+
id: `mock-fc-${Date.now()}`,
|
|
210
|
+
name: 'classify_intent',
|
|
211
|
+
args: { type: 'general', confidence: 0.9 },
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
usage: mockUsage(prompt, response),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// 有 tool schemas → 返回文本(让 AgentRuntime 的文本解析处理)
|
|
218
|
+
// Mock 不模拟复杂的多步工具调用链 — bootstrap 走 lightweight pipeline
|
|
219
|
+
if (schemas.length > 0) {
|
|
220
|
+
const text = `[Mock] 我已完成对项目代码的分析。基于代码结构,发现了几个关键的设计模式和架构约定。
|
|
221
|
+
|
|
222
|
+
以下是主要发现:
|
|
223
|
+
1. 项目采用模块化分层架构
|
|
224
|
+
2. 核心模块使用依赖注入模式
|
|
225
|
+
3. 错误处理遵循统一的类型安全约定
|
|
226
|
+
|
|
227
|
+
> 此分析由 Mock AI 生成,结果基于模板。切换到真实 AI Provider 可获得深度项目分析。`;
|
|
228
|
+
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
|
|
229
|
+
}
|
|
230
|
+
// 无 tools → 纯文本
|
|
231
|
+
const text = await this.chat(prompt, {
|
|
232
|
+
systemPrompt: opts.systemPrompt,
|
|
233
|
+
temperature: opts.temperature,
|
|
234
|
+
maxTokens: opts.maxTokens,
|
|
235
|
+
});
|
|
236
|
+
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
|
|
22
237
|
}
|
|
238
|
+
// ── chatWithStructuredOutput() — 结构化 JSON 模拟 ──────
|
|
239
|
+
async chatWithStructuredOutput(prompt, opts = {}) {
|
|
240
|
+
this.callLog.push({ method: 'chatWithStructuredOutput', prompt: prompt.slice(0, 200) });
|
|
241
|
+
await mockDelay();
|
|
242
|
+
const p = prompt.toLowerCase();
|
|
243
|
+
// 候选润色 → 尝试回传 prompt 中的 JSON
|
|
244
|
+
if (p.includes('润色') || p.includes('refine')) {
|
|
245
|
+
const existing = extractJsonFromPrompt(prompt);
|
|
246
|
+
if (existing) {
|
|
247
|
+
return existing;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
description: '[Mock] 保持原内容',
|
|
251
|
+
pattern: '',
|
|
252
|
+
markdown: '',
|
|
253
|
+
rationale: '',
|
|
254
|
+
tags: [],
|
|
255
|
+
confidence: 0.8,
|
|
256
|
+
aiInsight: null,
|
|
257
|
+
agentNotes: null,
|
|
258
|
+
relations: {},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// 风格检查 → 空数组
|
|
262
|
+
if (opts.openChar === '[' || p.includes('violation')) {
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
265
|
+
// 通用 → 尝试从 prompt 中提取已有 JSON,否则返回空对象
|
|
266
|
+
const existing = extractJsonFromPrompt(prompt);
|
|
267
|
+
return existing || {};
|
|
268
|
+
}
|
|
269
|
+
// ── summarize() — 代码摘要 ─────────────────────────────
|
|
23
270
|
async summarize(code) {
|
|
24
271
|
this.callLog.push({ method: 'summarize', code: code?.slice(0, 80) });
|
|
272
|
+
await mockDelay();
|
|
25
273
|
if (this.responses.summarize) {
|
|
26
274
|
return this.responses.summarize;
|
|
27
275
|
}
|
|
276
|
+
const symbols = extractCodeSymbols(code || '');
|
|
277
|
+
const lang = code?.includes('func ')
|
|
278
|
+
? 'swift'
|
|
279
|
+
: code?.includes('function ')
|
|
280
|
+
? 'typescript'
|
|
281
|
+
: code?.includes('def ')
|
|
282
|
+
? 'python'
|
|
283
|
+
: 'unknown';
|
|
28
284
|
return {
|
|
29
|
-
title: 'Mock Summary',
|
|
30
|
-
description:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
285
|
+
title: symbols.length > 0 ? `${symbols[0]} 模块` : 'Mock Summary',
|
|
286
|
+
description: symbols.length > 0
|
|
287
|
+
? `定义了 ${symbols.slice(0, 3).join('、')} 等 ${symbols.length} 个核心类型`
|
|
288
|
+
: `Summary of ${code?.length || 0} chars`,
|
|
289
|
+
language: lang,
|
|
290
|
+
patterns: symbols.slice(0, 3).map((s) => `${s} pattern`),
|
|
291
|
+
keyAPIs: symbols.slice(0, 4),
|
|
34
292
|
};
|
|
35
293
|
}
|
|
294
|
+
// ── embed() — 确定性伪向量 ─────────────────────────────
|
|
36
295
|
async embed(text) {
|
|
37
296
|
this.callLog.push({ method: 'embed', text: Array.isArray(text) ? text.length : 1 });
|
|
297
|
+
// 使用基于内容的确定性哈希生成向量(相似文本产生相似向量)
|
|
38
298
|
const dim = 768;
|
|
39
|
-
const makeVector = () =>
|
|
299
|
+
const makeVector = (input) => {
|
|
300
|
+
let hash = 0;
|
|
301
|
+
for (let i = 0; i < input.length; i++) {
|
|
302
|
+
hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;
|
|
303
|
+
}
|
|
304
|
+
return Array.from({ length: dim }, (_, i) => {
|
|
305
|
+
// 基于 hash + 位置的伪随机,范围 [-1, 1]
|
|
306
|
+
const x = Math.sin(hash * 0.001 + i * 0.7127) * 43758.5453;
|
|
307
|
+
return (x - Math.floor(x)) * 2 - 1;
|
|
308
|
+
});
|
|
309
|
+
};
|
|
40
310
|
if (Array.isArray(text)) {
|
|
41
|
-
return text.map(() => makeVector());
|
|
311
|
+
return text.map((t) => makeVector(t));
|
|
42
312
|
}
|
|
43
|
-
return makeVector();
|
|
313
|
+
return makeVector(text);
|
|
314
|
+
}
|
|
315
|
+
// ── probe() — 连接检测 ────────────────────────────────
|
|
316
|
+
async probe() {
|
|
317
|
+
this.callLog.push({ method: 'probe' });
|
|
318
|
+
return true;
|
|
44
319
|
}
|
|
320
|
+
// ── 辅助方法 ──────────────────────────────────────────
|
|
45
321
|
/** 获取调用日志(测试断言用) */
|
|
46
322
|
getCalls() {
|
|
47
323
|
return this.callLog;
|
|
@@ -42,6 +42,14 @@ export class OpenAiProvider extends AiProvider {
|
|
|
42
42
|
max_tokens: maxTokens,
|
|
43
43
|
};
|
|
44
44
|
const data = await this._post(`${this.baseUrl}/chat/completions`, body);
|
|
45
|
+
// 提取 token 用量
|
|
46
|
+
if (data?.usage) {
|
|
47
|
+
this._emitTokenUsage({
|
|
48
|
+
inputTokens: data.usage.prompt_tokens || 0,
|
|
49
|
+
outputTokens: data.usage.completion_tokens || 0,
|
|
50
|
+
totalTokens: data.usage.total_tokens || 0,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
45
53
|
return data?.choices?.[0]?.message?.content || '';
|
|
46
54
|
});
|
|
47
55
|
}
|
|
@@ -197,6 +205,14 @@ export class OpenAiProvider extends AiProvider {
|
|
|
197
205
|
response_format: { type: 'json_object' },
|
|
198
206
|
};
|
|
199
207
|
const data = await this._post(`${this.baseUrl}/chat/completions`, body);
|
|
208
|
+
// 提取 token 用量
|
|
209
|
+
if (data?.usage) {
|
|
210
|
+
this._emitTokenUsage({
|
|
211
|
+
inputTokens: data.usage.prompt_tokens || 0,
|
|
212
|
+
outputTokens: data.usage.completion_tokens || 0,
|
|
213
|
+
totalTokens: data.usage.total_tokens || 0,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
200
216
|
const text = data?.choices?.[0]?.message?.content || '';
|
|
201
217
|
if (!text) {
|
|
202
218
|
return null;
|
|
@@ -21,6 +21,10 @@ import type { AgentRuntime } from '#agent/AgentRuntime.js';
|
|
|
21
21
|
interface AgentFactory {
|
|
22
22
|
createLark(opts: RuntimeOverrides): AgentRuntime;
|
|
23
23
|
createRemoteExec(opts: RuntimeOverrides): AgentRuntime;
|
|
24
|
+
getAiProviderInfo(): {
|
|
25
|
+
name: string;
|
|
26
|
+
model?: string;
|
|
27
|
+
};
|
|
24
28
|
}
|
|
25
29
|
interface RuntimeOverrides {
|
|
26
30
|
lang?: string;
|
|
@@ -34,7 +38,7 @@ interface ProgressEvent {
|
|
|
34
38
|
interface LarkTransportConfig {
|
|
35
39
|
agentFactory: AgentFactory;
|
|
36
40
|
replyFn: (messageId: string, text: string) => Promise<void>;
|
|
37
|
-
sendFn: (text: string) => Promise<
|
|
41
|
+
sendFn: (text: string) => Promise<undefined | boolean>;
|
|
38
42
|
sendImageFn?: (caption: string) => Promise<{
|
|
39
43
|
success: boolean;
|
|
40
44
|
message: string;
|
|
@@ -276,6 +276,10 @@ export class LarkTransport {
|
|
|
276
276
|
}
|
|
277
277
|
/** 远程命令执行 — 使用 remote-exec preset(含 SafetyPolicy 命令白名单) */
|
|
278
278
|
async #handleRemoteExec(command, messageId, chatId, senderId, senderName) {
|
|
279
|
+
if (this.#agentFactory.getAiProviderInfo().name === 'mock') {
|
|
280
|
+
await this.#reply(messageId, '⚠️ AI 服务未配置,当前为 Mock 模式。请先配置 API Key。');
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
279
283
|
await this.#reply(messageId, `⚡ 正在执行: \`${command.slice(0, 60)}\`...`);
|
|
280
284
|
try {
|
|
281
285
|
const history = this.#getHistory(chatId);
|
|
@@ -316,6 +320,10 @@ export class LarkTransport {
|
|
|
316
320
|
}
|
|
317
321
|
/** Bot Agent 知识任务 — 服务端 AgentRuntime 直接处理 */
|
|
318
322
|
async #handleBotAgent(text, messageId, chatId, senderId, senderName) {
|
|
323
|
+
if (this.#agentFactory.getAiProviderInfo().name === 'mock') {
|
|
324
|
+
await this.#reply(messageId, '⚠️ AI 服务未配置,当前为 Mock 模式。请先配置 API Key。');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
319
327
|
// 进度提示
|
|
320
328
|
await this.#reply(messageId, '🤔 正在思考...');
|
|
321
329
|
try {
|
|
@@ -453,8 +461,8 @@ export class LarkTransport {
|
|
|
453
461
|
const history = this.#conversationHistory.get(chatId);
|
|
454
462
|
history.push({ role, content });
|
|
455
463
|
// 限制内存历史长度
|
|
456
|
-
if (history
|
|
457
|
-
history
|
|
464
|
+
if (history?.length > _a.MAX_HISTORY * 2) {
|
|
465
|
+
history?.splice(0, history?.length - _a.MAX_HISTORY * 2);
|
|
458
466
|
}
|
|
459
467
|
}
|
|
460
468
|
// ═══════════════════════════════════════════════════
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mock-pipeline.ts — Mock AI Bootstrap 轻量管线
|
|
3
|
+
*
|
|
4
|
+
* 当 AI Provider 为 mock 时,利用 Phase 1-4 已收集的真实数据
|
|
5
|
+
* (AST、依赖图、文件列表、Panorama) 为每个维度生成模板化候选知识。
|
|
6
|
+
*
|
|
7
|
+
* 不调用 AI,但走完完整的 submit → dimension_complete 流程,
|
|
8
|
+
* 使 Dashboard 能正常展示知识库、健康雷达等 UI。
|
|
9
|
+
*
|
|
10
|
+
* @module pipeline/mock-pipeline
|
|
11
|
+
*/
|
|
12
|
+
import type { DimensionDef } from '#types/project-snapshot.js';
|
|
13
|
+
import type { PipelineFillView } from '#types/snapshot-views.js';
|
|
14
|
+
/**
|
|
15
|
+
* fillDimensionsMock — Mock AI 轻量管线
|
|
16
|
+
*
|
|
17
|
+
* 利用 Phase 1-4 的真实数据(AST、文件列表、Panorama)自动生成候选知识,
|
|
18
|
+
* 不调用任何 AI API,但走完 submit → dimension_complete 的完整流程。
|
|
19
|
+
*/
|
|
20
|
+
export declare function fillDimensionsMock(view: PipelineFillView, dimensions: DimensionDef[]): Promise<void>;
|