autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
331 lines (323 loc) • 14.4 kB
JavaScript
/**
* MockProvider — Smart Mock AI 提供商
*
* 不发网络请求,但根据 prompt 内容智能匹配场景,返回符合格式的仿真响应。
* 用于让用户在没有 API Key 的情况下体验 AutoSnippet 完整工作流。
*
* 智能匹配场景:
* 1. probe / ping → "pong"
* 2. 重复度检测 (DUPLICATE/SIMILAR/UNIQUE) → "UNIQUE"
* 3. 对话压缩总结 → 从消息中提取关键词
* 4. 代码上下文化 (<chunk>) → 从代码提取函数/类名
* 5. 候选润色 (JSON 9字段) → 原样回传输入字段
* 6. 维度摘要 (dimensionDigest) → 模板化 JSON
* 7. 风格检查建议 → 空数组
* 8. Agent 路由分类 → functionCall classify_intent
* 9. 通用 fallback → 语义化占位文本
*
* 模拟延迟: 50-200ms 随机延迟,营造 "AI 思考" 体验
*/
import { AiProvider, } from '../AiProvider.js';
// ── 工具函数 ──────────────────────────────────────────────
/** 模拟延迟 (50-200ms) */
function mockDelay() {
const ms = 50 + Math.floor(Math.random() * 150);
return new Promise((resolve) => setTimeout(resolve, ms));
}
/** 模拟 token 用量 */
function mockUsage(prompt, response) {
return {
inputTokens: Math.ceil(prompt.length / 4),
outputTokens: Math.ceil(response.length / 4),
totalTokens: Math.ceil(prompt.length / 4) + Math.ceil(response.length / 4),
};
}
/** 从代码片段中提取函数/类/结构名称 */
function extractCodeSymbols(code) {
const symbols = [];
// Swift/TS class/struct/protocol/enum
for (const m of code.matchAll(/(?:class|struct|protocol|enum|interface|type)\s+(\w+)/g)) {
symbols.push(m[1]);
}
// func/function
for (const m of code.matchAll(/(?:func|function)\s+(\w+)/g)) {
symbols.push(m[1]);
}
// property patterns
for (const m of code.matchAll(/(?:let|var|const)\s+(\w+)/g)) {
if (m[1].length > 3) {
symbols.push(m[1]);
}
}
return [...new Set(symbols)].slice(0, 8);
}
/** 从 prompt 中尝试提取 JSON 输入(用于润色回传) */
function extractJsonFromPrompt(prompt) {
try {
const match = prompt.match(/\{[\s\S]*?"description"[\s\S]*?\}/);
if (match) {
return JSON.parse(match[0]);
}
}
catch {
/* parse failed */
}
return null;
}
// ── MockProvider ─────────────────────────────────────────
export class MockProvider extends AiProvider {
callLog;
responses;
constructor(config = {}) {
super(config);
this.name = 'mock';
this.model = 'mock-smart';
this.responses = config.responses || {};
this.callLog = [];
}
// ── 核心: chat() 智能路由 ──────────────────────────────
async chat(prompt, context = {}) {
this.callLog.push({ method: 'chat', prompt: prompt.slice(0, 200), context });
await mockDelay();
// 0. 用户注入的固定响应(单元测试用)
if (this.responses.chat) {
return this.responses.chat;
}
const p = prompt.toLowerCase();
// 1. Probe / ping
if (p === 'ping' || p.includes('ping')) {
return 'pong';
}
// 2. 重复度检测 — "请回答: DUPLICATE / SIMILAR / UNIQUE"
if (p.includes('duplicate') && p.includes('similar') && p.includes('unique')) {
return 'UNIQUE';
}
// 3. 对话压缩总结 — "请用 2-3 句话总结"
if (p.includes('总结以下对话') || p.includes('summarize the following')) {
const lines = prompt
.split('\n')
.filter((l) => l.startsWith('[user]') || l.startsWith('[assistant]'));
const topics = lines
.slice(0, 3)
.map((l) => l.slice(0, 60))
.join(';');
return `[Mock 摘要] 对话涉及: ${topics || '项目开发相关讨论'}。用户和助手讨论了代码实现和架构设计。`;
}
// 4. 代码上下文化 — <chunk>...</chunk>
if (p.includes('<chunk>')) {
const chunkMatch = prompt.match(/<chunk>([\s\S]*?)<\/chunk>/);
if (chunkMatch) {
const symbols = extractCodeSymbols(chunkMatch[1]);
if (symbols.length > 0) {
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.`;
}
return 'This chunk contains utility code for the module.';
}
}
// 5. 候选润色 — "知识库条目润色助手" + JSON 输出
if (p.includes('知识库条目润色') || p.includes('润色助手')) {
const existing = extractJsonFromPrompt(prompt);
if (existing) {
return JSON.stringify(existing);
}
return JSON.stringify({
description: '[Mock] 保持原内容不变',
pattern: '',
markdown: '',
rationale: '',
tags: [],
confidence: 0.8,
aiInsight: null,
agentNotes: null,
relations: {},
});
}
// 6. 维度摘要 — "dimensionDigest"
if (p.includes('dimensiondigest') || p.includes('dimension digest')) {
const dimMatch = prompt.match(/维度[::]\s*["']?(\w[\w-]+)/i) ||
prompt.match(/dimension[::]\s*["']?(\w[\w-]+)/i);
const dimId = dimMatch?.[1] || 'unknown';
const countMatch = prompt.match(/提交了\s*(\d+)\s*个候选/);
const count = countMatch ? parseInt(countMatch[1], 10) : 3;
return `\`\`\`json
${JSON.stringify({
dimensionDigest: {
summary: `[Mock] ${dimId} 维度分析完成,基于项目代码结构生成了 ${count} 个候选知识。`,
candidateCount: count,
keyFindings: ['项目采用模块化架构设计', '发现多个核心设计模式', '代码风格整体一致'],
crossRefs: {},
gaps: ['部分模块缺少充分的文档注释'],
remainingTasks: [],
},
}, null, 2)}
\`\`\``;
}
// 7. 风格检查建议 — "violation" + "suggestion"
if (p.includes('violation') && p.includes('suggestion')) {
return '[]';
}
// 8. 分析报告 — "Markdown 格式" + "代码分析报告"
if (p.includes('代码分析报告') || p.includes('分析报告')) {
const symbols = extractCodeSymbols(prompt);
return `## Mock 代码分析报告
### 核心发现
1. **模块结构**: 项目采用分层架构,${symbols.length > 0 ? `核心类型包括 ${symbols.slice(0, 3).join('、')}` : '各模块职责清晰'}
2. **设计模式**: 广泛使用协议/接口抽象和依赖注入
3. **代码质量**: 类型安全处理规范,错误处理完善
### 文件分析
分析的文件展现了良好的代码组织,模块间通过明确的接口通信。
> ⚠️ 此报告由 Mock AI 生成,仅包含模板化分析结果。`;
}
// 9. 通用 fallback — 语义化占位
const symbols = extractCodeSymbols(prompt);
const topic = symbols.length > 0
? `关于 ${symbols.slice(0, 3).join('、')} 的分析`
: `对 ${prompt.slice(0, 40).replace(/\n/g, ' ')} 的回复`;
return `[Mock AI] ${topic}。此响应由 Mock 模式生成,非真实 AI 分析结果。`;
}
// ── chatWithTools() — 智能函数调用模拟 ─────────────────
async chatWithTools(prompt, opts = {}) {
this.callLog.push({
method: 'chatWithTools',
prompt: prompt.slice(0, 200),
toolChoice: opts.toolChoice,
});
await mockDelay();
const schemas = (opts.toolSchemas || []);
const schemaNames = schemas.map((s) => s.name);
// toolChoice='none' → 纯文本回复(维度摘要、最终总结等)
if (opts.toolChoice === 'none') {
const text = await this.chat(prompt, {
systemPrompt: opts.systemPrompt,
temperature: opts.temperature,
maxTokens: opts.maxTokens,
});
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
}
// Agent 路由分类 — classify_intent tool
if (schemaNames.includes('classify_intent')) {
const response = JSON.stringify({ type: 'general', confidence: 0.9 });
return {
text: null,
functionCalls: [
{
id: `mock-fc-${Date.now()}`,
name: 'classify_intent',
args: { type: 'general', confidence: 0.9 },
},
],
usage: mockUsage(prompt, response),
};
}
// 有 tool schemas → 返回文本(让 AgentRuntime 的文本解析处理)
// Mock 不模拟复杂的多步工具调用链 — bootstrap 走 lightweight pipeline
if (schemas.length > 0) {
const text = `[Mock] 我已完成对项目代码的分析。基于代码结构,发现了几个关键的设计模式和架构约定。
以下是主要发现:
1. 项目采用模块化分层架构
2. 核心模块使用依赖注入模式
3. 错误处理遵循统一的类型安全约定
> 此分析由 Mock AI 生成,结果基于模板。切换到真实 AI Provider 可获得深度项目分析。`;
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
}
// 无 tools → 纯文本
const text = await this.chat(prompt, {
systemPrompt: opts.systemPrompt,
temperature: opts.temperature,
maxTokens: opts.maxTokens,
});
return { text, functionCalls: null, usage: mockUsage(prompt, text) };
}
// ── chatWithStructuredOutput() — 结构化 JSON 模拟 ──────
async chatWithStructuredOutput(prompt, opts = {}) {
this.callLog.push({ method: 'chatWithStructuredOutput', prompt: prompt.slice(0, 200) });
await mockDelay();
const p = prompt.toLowerCase();
// 候选润色 → 尝试回传 prompt 中的 JSON
if (p.includes('润色') || p.includes('refine')) {
const existing = extractJsonFromPrompt(prompt);
if (existing) {
return existing;
}
return {
description: '[Mock] 保持原内容',
pattern: '',
markdown: '',
rationale: '',
tags: [],
confidence: 0.8,
aiInsight: null,
agentNotes: null,
relations: {},
};
}
// 风格检查 → 空数组
if (opts.openChar === '[' || p.includes('violation')) {
return [];
}
// 通用 → 尝试从 prompt 中提取已有 JSON,否则返回空对象
const existing = extractJsonFromPrompt(prompt);
return existing || {};
}
// ── summarize() — 代码摘要 ─────────────────────────────
async summarize(code) {
this.callLog.push({ method: 'summarize', code: code?.slice(0, 80) });
await mockDelay();
if (this.responses.summarize) {
return this.responses.summarize;
}
const symbols = extractCodeSymbols(code || '');
const lang = code?.includes('func ')
? 'swift'
: code?.includes('function ')
? 'typescript'
: code?.includes('def ')
? 'python'
: 'unknown';
return {
title: symbols.length > 0 ? `${symbols[0]} 模块` : 'Mock Summary',
description: symbols.length > 0
? `定义了 ${symbols.slice(0, 3).join('、')} 等 ${symbols.length} 个核心类型`
: `Summary of ${code?.length || 0} chars`,
language: lang,
patterns: symbols.slice(0, 3).map((s) => `${s} pattern`),
keyAPIs: symbols.slice(0, 4),
};
}
// ── embed() — 确定性伪向量 ─────────────────────────────
async embed(text) {
this.callLog.push({ method: 'embed', text: Array.isArray(text) ? text.length : 1 });
// 使用基于内容的确定性哈希生成向量(相似文本产生相似向量)
const dim = 768;
const makeVector = (input) => {
let hash = 0;
for (let i = 0; i < input.length; i++) {
hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;
}
return Array.from({ length: dim }, (_, i) => {
// 基于 hash + 位置的伪随机,范围 [-1, 1]
const x = Math.sin(hash * 0.001 + i * 0.7127) * 43758.5453;
return (x - Math.floor(x)) * 2 - 1;
});
};
if (Array.isArray(text)) {
return text.map((t) => makeVector(t));
}
return makeVector(text);
}
// ── probe() — 连接检测 ────────────────────────────────
async probe() {
this.callLog.push({ method: 'probe' });
return true;
}
// ── 辅助方法 ──────────────────────────────────────────
/** 获取调用日志(测试断言用) */
getCalls() {
return this.callLog;
}
/** 重置调用记录 */
reset() {
this.callLog = [];
}
}
export default MockProvider;