@cicctencent/agent-core 0.1.17 → 0.1.19
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/README.md +70 -1
- package/dist/cjs/agent/engine.d.ts +23 -0
- package/dist/cjs/agent/engine.d.ts.map +1 -1
- package/dist/cjs/agent/engine.js +78 -5
- package/dist/cjs/agent/engine.js.map +1 -1
- package/dist/cjs/agent/history-manager.d.ts +66 -1
- package/dist/cjs/agent/history-manager.d.ts.map +1 -1
- package/dist/cjs/agent/history-manager.js +232 -0
- package/dist/cjs/agent/history-manager.js.map +1 -1
- package/dist/cjs/agent/llm-caller.d.ts.map +1 -1
- package/dist/cjs/agent/llm-caller.js +10 -4
- package/dist/cjs/agent/llm-caller.js.map +1 -1
- package/dist/cjs/agent/profile-loader.d.ts +56 -0
- package/dist/cjs/agent/profile-loader.d.ts.map +1 -0
- package/dist/cjs/agent/profile-loader.js +145 -0
- package/dist/cjs/agent/profile-loader.js.map +1 -0
- package/dist/cjs/agent/types.d.ts +32 -3
- package/dist/cjs/agent/types.d.ts.map +1 -1
- package/dist/cjs/agent/types.js.map +1 -1
- package/dist/cjs/context/types.d.ts +3 -3
- package/dist/cjs/context/types.d.ts.map +1 -1
- package/dist/cjs/index.d.ts +26 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +42 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/kb/in-memory-kb.d.ts +29 -0
- package/dist/cjs/kb/in-memory-kb.d.ts.map +1 -0
- package/dist/cjs/kb/in-memory-kb.js +210 -0
- package/dist/cjs/kb/in-memory-kb.js.map +1 -0
- package/dist/cjs/kb/rag-middleware.d.ts +31 -0
- package/dist/cjs/kb/rag-middleware.d.ts.map +1 -0
- package/dist/cjs/kb/rag-middleware.js +94 -0
- package/dist/cjs/kb/rag-middleware.js.map +1 -0
- package/dist/cjs/kb/types.d.ts +80 -0
- package/dist/cjs/kb/types.d.ts.map +1 -0
- package/dist/cjs/kb/types.js +6 -0
- package/dist/cjs/kb/types.js.map +1 -0
- package/dist/cjs/llm/anthropic-provider.d.ts +7 -0
- package/dist/cjs/llm/anthropic-provider.d.ts.map +1 -1
- package/dist/cjs/llm/anthropic-provider.js +84 -9
- package/dist/cjs/llm/anthropic-provider.js.map +1 -1
- package/dist/cjs/llm/openai-provider.d.ts +9 -0
- package/dist/cjs/llm/openai-provider.d.ts.map +1 -1
- package/dist/cjs/llm/openai-provider.js +41 -1
- package/dist/cjs/llm/openai-provider.js.map +1 -1
- package/dist/cjs/llm/pricing.d.ts +26 -0
- package/dist/cjs/llm/pricing.d.ts.map +1 -0
- package/dist/cjs/llm/pricing.js +86 -0
- package/dist/cjs/llm/pricing.js.map +1 -0
- package/dist/cjs/llm/usage-tracker.d.ts +119 -0
- package/dist/cjs/llm/usage-tracker.d.ts.map +1 -0
- package/dist/cjs/llm/usage-tracker.js +105 -0
- package/dist/cjs/llm/usage-tracker.js.map +1 -0
- package/dist/cjs/memory/extractor.js +1 -1
- package/dist/cjs/memory/extractor.js.map +1 -1
- package/dist/cjs/memory/persona.js +1 -1
- package/dist/cjs/memory/persona.js.map +1 -1
- package/dist/cjs/memory/scene.js +1 -1
- package/dist/cjs/memory/scene.js.map +1 -1
- package/dist/cjs/middleware/types.d.ts +2 -4
- package/dist/cjs/middleware/types.d.ts.map +1 -1
- package/dist/cjs/middleware/workspace-notes.d.ts +36 -0
- package/dist/cjs/middleware/workspace-notes.d.ts.map +1 -0
- package/dist/cjs/middleware/workspace-notes.js +53 -0
- package/dist/cjs/middleware/workspace-notes.js.map +1 -0
- package/dist/cjs/observability/logger.d.ts +1 -0
- package/dist/cjs/observability/logger.d.ts.map +1 -1
- package/dist/cjs/observability/logger.js.map +1 -1
- package/dist/cjs/observability/trace.d.ts +45 -0
- package/dist/cjs/observability/trace.d.ts.map +1 -0
- package/dist/cjs/observability/trace.js +59 -0
- package/dist/cjs/observability/trace.js.map +1 -0
- package/dist/cjs/runtime/run-registry-interface.d.ts +42 -0
- package/dist/cjs/runtime/run-registry-interface.d.ts.map +1 -0
- package/dist/cjs/runtime/run-registry-interface.js +7 -0
- package/dist/cjs/runtime/run-registry-interface.js.map +1 -0
- package/dist/cjs/runtime/run-registry.d.ts +15 -2
- package/dist/cjs/runtime/run-registry.d.ts.map +1 -1
- package/dist/cjs/runtime/run-registry.js +43 -1
- package/dist/cjs/runtime/run-registry.js.map +1 -1
- package/dist/cjs/sandbox/code-sandbox.d.ts +42 -0
- package/dist/cjs/sandbox/code-sandbox.d.ts.map +1 -0
- package/dist/cjs/sandbox/code-sandbox.js +59 -0
- package/dist/cjs/sandbox/code-sandbox.js.map +1 -0
- package/dist/cjs/skill/router.d.ts +20 -1
- package/dist/cjs/skill/router.d.ts.map +1 -1
- package/dist/cjs/skill/router.js +39 -1
- package/dist/cjs/skill/router.js.map +1 -1
- package/dist/cjs/skill/types.d.ts +1 -1
- package/dist/cjs/skill/types.d.ts.map +1 -1
- package/dist/cjs/skill/vector-index.d.ts +42 -0
- package/dist/cjs/skill/vector-index.d.ts.map +1 -0
- package/dist/cjs/skill/vector-index.js +70 -0
- package/dist/cjs/skill/vector-index.js.map +1 -0
- package/dist/cjs/store/history-persistence.d.ts +36 -0
- package/dist/cjs/store/history-persistence.d.ts.map +1 -0
- package/dist/cjs/store/history-persistence.js +142 -0
- package/dist/cjs/store/history-persistence.js.map +1 -0
- package/dist/cjs/types.d.ts +40 -1
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/types.js +34 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/token-counter.d.ts.map +1 -1
- package/dist/cjs/utils/token-counter.js +33 -1
- package/dist/cjs/utils/token-counter.js.map +1 -1
- package/dist/esm/agent/engine.d.ts +23 -0
- package/dist/esm/agent/engine.d.ts.map +1 -1
- package/dist/esm/agent/engine.js +78 -5
- package/dist/esm/agent/engine.js.map +1 -1
- package/dist/esm/agent/history-manager.d.ts +66 -1
- package/dist/esm/agent/history-manager.d.ts.map +1 -1
- package/dist/esm/agent/history-manager.js +232 -0
- package/dist/esm/agent/history-manager.js.map +1 -1
- package/dist/esm/agent/llm-caller.d.ts.map +1 -1
- package/dist/esm/agent/llm-caller.js +10 -4
- package/dist/esm/agent/llm-caller.js.map +1 -1
- package/dist/esm/agent/profile-loader.d.ts +56 -0
- package/dist/esm/agent/profile-loader.d.ts.map +1 -0
- package/dist/esm/agent/profile-loader.js +108 -0
- package/dist/esm/agent/profile-loader.js.map +1 -0
- package/dist/esm/agent/types.d.ts +32 -3
- package/dist/esm/agent/types.d.ts.map +1 -1
- package/dist/esm/agent/types.js.map +1 -1
- package/dist/esm/context/types.d.ts +3 -3
- package/dist/esm/context/types.d.ts.map +1 -1
- package/dist/esm/index.d.ts +26 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/kb/in-memory-kb.d.ts +29 -0
- package/dist/esm/kb/in-memory-kb.d.ts.map +1 -0
- package/dist/esm/kb/in-memory-kb.js +206 -0
- package/dist/esm/kb/in-memory-kb.js.map +1 -0
- package/dist/esm/kb/rag-middleware.d.ts +31 -0
- package/dist/esm/kb/rag-middleware.d.ts.map +1 -0
- package/dist/esm/kb/rag-middleware.js +91 -0
- package/dist/esm/kb/rag-middleware.js.map +1 -0
- package/dist/esm/kb/types.d.ts +80 -0
- package/dist/esm/kb/types.d.ts.map +1 -0
- package/dist/esm/kb/types.js +5 -0
- package/dist/esm/kb/types.js.map +1 -0
- package/dist/esm/llm/anthropic-provider.d.ts +7 -0
- package/dist/esm/llm/anthropic-provider.d.ts.map +1 -1
- package/dist/esm/llm/anthropic-provider.js +84 -9
- package/dist/esm/llm/anthropic-provider.js.map +1 -1
- package/dist/esm/llm/openai-provider.d.ts +9 -0
- package/dist/esm/llm/openai-provider.d.ts.map +1 -1
- package/dist/esm/llm/openai-provider.js +41 -1
- package/dist/esm/llm/openai-provider.js.map +1 -1
- package/dist/esm/llm/pricing.d.ts +26 -0
- package/dist/esm/llm/pricing.d.ts.map +1 -0
- package/dist/esm/llm/pricing.js +81 -0
- package/dist/esm/llm/pricing.js.map +1 -0
- package/dist/esm/llm/usage-tracker.d.ts +119 -0
- package/dist/esm/llm/usage-tracker.d.ts.map +1 -0
- package/dist/esm/llm/usage-tracker.js +101 -0
- package/dist/esm/llm/usage-tracker.js.map +1 -0
- package/dist/esm/memory/extractor.js +1 -1
- package/dist/esm/memory/extractor.js.map +1 -1
- package/dist/esm/memory/persona.js +1 -1
- package/dist/esm/memory/persona.js.map +1 -1
- package/dist/esm/memory/scene.js +1 -1
- package/dist/esm/memory/scene.js.map +1 -1
- package/dist/esm/middleware/types.d.ts +2 -4
- package/dist/esm/middleware/types.d.ts.map +1 -1
- package/dist/esm/middleware/workspace-notes.d.ts +36 -0
- package/dist/esm/middleware/workspace-notes.d.ts.map +1 -0
- package/dist/esm/middleware/workspace-notes.js +49 -0
- package/dist/esm/middleware/workspace-notes.js.map +1 -0
- package/dist/esm/observability/logger.d.ts +1 -0
- package/dist/esm/observability/logger.d.ts.map +1 -1
- package/dist/esm/observability/logger.js.map +1 -1
- package/dist/esm/observability/trace.d.ts +45 -0
- package/dist/esm/observability/trace.d.ts.map +1 -0
- package/dist/esm/observability/trace.js +55 -0
- package/dist/esm/observability/trace.js.map +1 -0
- package/dist/esm/runtime/run-registry-interface.d.ts +42 -0
- package/dist/esm/runtime/run-registry-interface.d.ts.map +1 -0
- package/dist/esm/runtime/run-registry-interface.js +6 -0
- package/dist/esm/runtime/run-registry-interface.js.map +1 -0
- package/dist/esm/runtime/run-registry.d.ts +15 -2
- package/dist/esm/runtime/run-registry.d.ts.map +1 -1
- package/dist/esm/runtime/run-registry.js +43 -1
- package/dist/esm/runtime/run-registry.js.map +1 -1
- package/dist/esm/sandbox/code-sandbox.d.ts +42 -0
- package/dist/esm/sandbox/code-sandbox.d.ts.map +1 -0
- package/dist/esm/sandbox/code-sandbox.js +56 -0
- package/dist/esm/sandbox/code-sandbox.js.map +1 -0
- package/dist/esm/skill/router.d.ts +20 -1
- package/dist/esm/skill/router.d.ts.map +1 -1
- package/dist/esm/skill/router.js +37 -0
- package/dist/esm/skill/router.js.map +1 -1
- package/dist/esm/skill/types.d.ts +1 -1
- package/dist/esm/skill/types.d.ts.map +1 -1
- package/dist/esm/skill/vector-index.d.ts +42 -0
- package/dist/esm/skill/vector-index.d.ts.map +1 -0
- package/dist/esm/skill/vector-index.js +66 -0
- package/dist/esm/skill/vector-index.js.map +1 -0
- package/dist/esm/store/history-persistence.d.ts +36 -0
- package/dist/esm/store/history-persistence.d.ts.map +1 -0
- package/dist/esm/store/history-persistence.js +105 -0
- package/dist/esm/store/history-persistence.js.map +1 -0
- package/dist/esm/types.d.ts +40 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/types.js +32 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/token-counter.d.ts.map +1 -1
- package/dist/esm/utils/token-counter.js +33 -1
- package/dist/esm/utils/token-counter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// InMemoryKnowledgeBase — 内存知识库实现(TF-IDF 关键词匹配)
|
|
3
|
+
// ============================================================
|
|
4
|
+
// ---- 文本分词 ----
|
|
5
|
+
/**
|
|
6
|
+
* 将文本分词为小写词项数组
|
|
7
|
+
* 按非字母数字字符分割,过滤空串和过短词
|
|
8
|
+
*/
|
|
9
|
+
function tokenize(text) {
|
|
10
|
+
return text
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.split(/[^a-z0-9\u4e00-\u9fff]+/)
|
|
13
|
+
.filter(t => t.length > 0);
|
|
14
|
+
}
|
|
15
|
+
/** 计算词项频率(TF) */
|
|
16
|
+
function computeTF(tokens) {
|
|
17
|
+
const tf = new Map();
|
|
18
|
+
for (const t of tokens) {
|
|
19
|
+
tf.set(t, (tf.get(t) || 0) + 1);
|
|
20
|
+
}
|
|
21
|
+
// 归一化:除以总词数
|
|
22
|
+
const total = tokens.length;
|
|
23
|
+
if (total > 0) {
|
|
24
|
+
for (const [k, v] of tf) {
|
|
25
|
+
tf.set(k, v / total);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return tf;
|
|
29
|
+
}
|
|
30
|
+
// ---- InMemoryKnowledgeBase ----
|
|
31
|
+
/**
|
|
32
|
+
* 内存知识库实现
|
|
33
|
+
*
|
|
34
|
+
* 当注入 EmbeddingProvider 时使用语义向量检索(余弦相似度);
|
|
35
|
+
* 未注入时回退到 TF-IDF 关键词匹配(余弦相似度)。
|
|
36
|
+
*
|
|
37
|
+
* 零外部依赖,适合开发/测试及小规模知识库场景。
|
|
38
|
+
*/
|
|
39
|
+
export class InMemoryKnowledgeBase {
|
|
40
|
+
/** 文档存储:docId -> StoredDoc */
|
|
41
|
+
docs = new Map();
|
|
42
|
+
/** 嵌入向量提供者(可选) */
|
|
43
|
+
embeddingProvider;
|
|
44
|
+
/** 全局文档频率:term -> 包含该词的文档数 */
|
|
45
|
+
df = new Map();
|
|
46
|
+
/** 总文档数(用于 IDF 计算) */
|
|
47
|
+
totalDocs = 0;
|
|
48
|
+
/** 缓存的 chunk TF-IDF 向量:chunkId -> TFIDFVector */
|
|
49
|
+
chunkVectors = new Map();
|
|
50
|
+
constructor(embeddingProvider) {
|
|
51
|
+
this.embeddingProvider = embeddingProvider;
|
|
52
|
+
}
|
|
53
|
+
async ingest(docId, chunks) {
|
|
54
|
+
if (!chunks.length)
|
|
55
|
+
return;
|
|
56
|
+
// 如果已有同 ID 文档,先移除
|
|
57
|
+
if (this.docs.has(docId)) {
|
|
58
|
+
await this.remove(docId);
|
|
59
|
+
}
|
|
60
|
+
// 生成嵌入向量(如果提供了 EmbeddingProvider)
|
|
61
|
+
if (this.embeddingProvider) {
|
|
62
|
+
const texts = chunks.map(c => c.content);
|
|
63
|
+
const embeddings = await this.embeddingProvider.embed(texts);
|
|
64
|
+
chunks = chunks.map((c, i) => ({ ...c, embedding: embeddings[i] }));
|
|
65
|
+
}
|
|
66
|
+
const now = new Date().toISOString();
|
|
67
|
+
const title = chunks[0]?.metadata?.title || docId;
|
|
68
|
+
const doc = {
|
|
69
|
+
meta: {
|
|
70
|
+
id: docId,
|
|
71
|
+
title,
|
|
72
|
+
chunkCount: chunks.length,
|
|
73
|
+
createdAt: now,
|
|
74
|
+
metadata: chunks[0]?.metadata,
|
|
75
|
+
},
|
|
76
|
+
chunks,
|
|
77
|
+
};
|
|
78
|
+
this.docs.set(docId, doc);
|
|
79
|
+
this.totalDocs++;
|
|
80
|
+
// 更新 DF(文档频率)
|
|
81
|
+
const docTerms = new Set();
|
|
82
|
+
for (const chunk of chunks) {
|
|
83
|
+
const tokens = tokenize(chunk.content);
|
|
84
|
+
for (const t of tokens)
|
|
85
|
+
docTerms.add(t);
|
|
86
|
+
}
|
|
87
|
+
for (const t of docTerms) {
|
|
88
|
+
this.df.set(t, (this.df.get(t) || 0) + 1);
|
|
89
|
+
}
|
|
90
|
+
// 计算并缓存每个 chunk 的 TF-IDF 向量
|
|
91
|
+
for (const chunk of chunks) {
|
|
92
|
+
this.chunkVectors.set(chunk.id, this.computeTFIDF(chunk.content));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async search(query, topK = 5) {
|
|
96
|
+
if (this.docs.size === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const results = [];
|
|
99
|
+
// 如果有 EmbeddingProvider,使用语义检索
|
|
100
|
+
if (this.embeddingProvider) {
|
|
101
|
+
const [queryEmbedding] = await this.embeddingProvider.embed([query]);
|
|
102
|
+
for (const doc of this.docs.values()) {
|
|
103
|
+
for (const chunk of doc.chunks) {
|
|
104
|
+
if (!chunk.embedding)
|
|
105
|
+
continue;
|
|
106
|
+
const score = cosineSimilarity(queryEmbedding, chunk.embedding);
|
|
107
|
+
results.push({ chunk, score });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// 回退到 TF-IDF 关键词匹配
|
|
113
|
+
const queryVector = this.computeTFIDF(query);
|
|
114
|
+
for (const doc of this.docs.values()) {
|
|
115
|
+
for (const chunk of doc.chunks) {
|
|
116
|
+
const chunkVector = this.chunkVectors.get(chunk.id);
|
|
117
|
+
if (!chunkVector)
|
|
118
|
+
continue;
|
|
119
|
+
const score = cosineSimilaritySparse(queryVector, chunkVector);
|
|
120
|
+
results.push({ chunk, score });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// 按得分降序排列,取 topK
|
|
125
|
+
results.sort((a, b) => b.score - a.score);
|
|
126
|
+
return results.slice(0, topK);
|
|
127
|
+
}
|
|
128
|
+
async remove(docId) {
|
|
129
|
+
const doc = this.docs.get(docId);
|
|
130
|
+
if (!doc)
|
|
131
|
+
return;
|
|
132
|
+
// 移除 chunk 向量缓存
|
|
133
|
+
for (const chunk of doc.chunks) {
|
|
134
|
+
this.chunkVectors.delete(chunk.id);
|
|
135
|
+
}
|
|
136
|
+
// 更新 DF
|
|
137
|
+
const docTerms = new Set();
|
|
138
|
+
for (const chunk of doc.chunks) {
|
|
139
|
+
const tokens = tokenize(chunk.content);
|
|
140
|
+
for (const t of tokens)
|
|
141
|
+
docTerms.add(t);
|
|
142
|
+
}
|
|
143
|
+
for (const t of docTerms) {
|
|
144
|
+
const count = this.df.get(t);
|
|
145
|
+
if (count != null) {
|
|
146
|
+
if (count <= 1)
|
|
147
|
+
this.df.delete(t);
|
|
148
|
+
else
|
|
149
|
+
this.df.set(t, count - 1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
this.docs.delete(docId);
|
|
153
|
+
this.totalDocs--;
|
|
154
|
+
}
|
|
155
|
+
async list() {
|
|
156
|
+
return Array.from(this.docs.values()).map(d => d.meta);
|
|
157
|
+
}
|
|
158
|
+
// ---- TF-IDF 计算 ----
|
|
159
|
+
/** 计算文本的 TF-IDF 稀疏向量 */
|
|
160
|
+
computeTFIDF(text) {
|
|
161
|
+
const tokens = tokenize(text);
|
|
162
|
+
const tf = computeTF(tokens);
|
|
163
|
+
const vector = new Map();
|
|
164
|
+
for (const [term, tfVal] of tf) {
|
|
165
|
+
const dfVal = this.df.get(term) || 0;
|
|
166
|
+
// IDF = log((1 + N) / (1 + DF)) + 1 (平滑处理)
|
|
167
|
+
const idf = Math.log((1 + this.totalDocs) / (1 + dfVal)) + 1;
|
|
168
|
+
vector.set(term, tfVal * idf);
|
|
169
|
+
}
|
|
170
|
+
return vector;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// ---- 向量相似度计算 ----
|
|
174
|
+
/** 计算两个稠密向量的余弦相似度 */
|
|
175
|
+
function cosineSimilarity(a, b) {
|
|
176
|
+
if (a.length !== b.length || a.length === 0)
|
|
177
|
+
return 0;
|
|
178
|
+
let dot = 0;
|
|
179
|
+
let magA = 0;
|
|
180
|
+
let magB = 0;
|
|
181
|
+
for (let i = 0; i < a.length; i++) {
|
|
182
|
+
dot += a[i] * b[i];
|
|
183
|
+
magA += a[i] * a[i];
|
|
184
|
+
magB += b[i] * b[i];
|
|
185
|
+
}
|
|
186
|
+
const denom = Math.sqrt(magA) * Math.sqrt(magB);
|
|
187
|
+
return denom === 0 ? 0 : dot / denom;
|
|
188
|
+
}
|
|
189
|
+
/** 计算两个稀疏向量(Map)的余弦相似度 */
|
|
190
|
+
function cosineSimilaritySparse(a, b) {
|
|
191
|
+
let dot = 0;
|
|
192
|
+
let magA = 0;
|
|
193
|
+
let magB = 0;
|
|
194
|
+
for (const [k, v] of a) {
|
|
195
|
+
magA += v * v;
|
|
196
|
+
const bv = b.get(k);
|
|
197
|
+
if (bv != null)
|
|
198
|
+
dot += v * bv;
|
|
199
|
+
}
|
|
200
|
+
for (const [, v] of b) {
|
|
201
|
+
magB += v * v;
|
|
202
|
+
}
|
|
203
|
+
const denom = Math.sqrt(magA) * Math.sqrt(magB);
|
|
204
|
+
return denom === 0 ? 0 : dot / denom;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=in-memory-kb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-kb.js","sourceRoot":"","sources":["../../../src/kb/in-memory-kb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Middleware } from '../middleware/types.js';
|
|
2
|
+
import type { KnowledgeBase } from './types.js';
|
|
3
|
+
/** RAG 中间件配置 */
|
|
4
|
+
export interface RAGMiddlewareOptions {
|
|
5
|
+
/** 检索结果数量(默认 3) */
|
|
6
|
+
topK?: number;
|
|
7
|
+
/** 注入的上下文笔记标题(默认 "Retrieved Knowledge") */
|
|
8
|
+
noteTitle?: string;
|
|
9
|
+
/** 每个分块最大字符数(默认 500,超出截断) */
|
|
10
|
+
maxChunkLength?: number;
|
|
11
|
+
/** 最低相似度阈值(低于此值的结果不注入,默认 0.01) */
|
|
12
|
+
minScore?: number;
|
|
13
|
+
/** 是否仅在首轮迭代注入(默认 false,每轮都检索) */
|
|
14
|
+
firstIterationOnly?: boolean;
|
|
15
|
+
/** 日志输出函数 */
|
|
16
|
+
logger?: (msg: string) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 创建 RAG(检索增强生成)中间件
|
|
20
|
+
*
|
|
21
|
+
* 在每轮迭代开始前:
|
|
22
|
+
* 1. 提取用户最新消息文本
|
|
23
|
+
* 2. 检索知识库中相关分块
|
|
24
|
+
* 3. 将检索结果格式化为系统级上下文笔记,注入到消息列表末尾
|
|
25
|
+
*
|
|
26
|
+
* @param kb 知识库实例
|
|
27
|
+
* @param options 配置选项
|
|
28
|
+
* @returns Middleware 实例
|
|
29
|
+
*/
|
|
30
|
+
export declare function createRAGMiddleware(kb: KnowledgeBase, options?: RAGMiddlewareOptions): Middleware;
|
|
31
|
+
//# sourceMappingURL=rag-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rag-middleware.d.ts","sourceRoot":"","sources":["../../../src/kb/rag-middleware.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,wBAAwB,CAAC;AAG5E,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAC;AAI9D,gBAAgB;AAChB,MAAM,WAAW,oBAAoB;IACnC,mBAAmB;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa;IACb,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,aAAa,EACjB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,UAAU,CAkFZ"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// RAGMiddleware — 检索增强生成中间件
|
|
3
|
+
// ============================================================
|
|
4
|
+
import { extractTextFromContent } from "../types.js";
|
|
5
|
+
// ---- createRAGMiddleware ----
|
|
6
|
+
/**
|
|
7
|
+
* 创建 RAG(检索增强生成)中间件
|
|
8
|
+
*
|
|
9
|
+
* 在每轮迭代开始前:
|
|
10
|
+
* 1. 提取用户最新消息文本
|
|
11
|
+
* 2. 检索知识库中相关分块
|
|
12
|
+
* 3. 将检索结果格式化为系统级上下文笔记,注入到消息列表末尾
|
|
13
|
+
*
|
|
14
|
+
* @param kb 知识库实例
|
|
15
|
+
* @param options 配置选项
|
|
16
|
+
* @returns Middleware 实例
|
|
17
|
+
*/
|
|
18
|
+
export function createRAGMiddleware(kb, options) {
|
|
19
|
+
const topK = options?.topK ?? 3;
|
|
20
|
+
const noteTitle = options?.noteTitle ?? 'Retrieved Knowledge';
|
|
21
|
+
const maxChunkLength = options?.maxChunkLength ?? 500;
|
|
22
|
+
const minScore = options?.minScore ?? 0.01;
|
|
23
|
+
const firstIterationOnly = options?.firstIterationOnly ?? false;
|
|
24
|
+
const logger = options?.logger ?? (() => { });
|
|
25
|
+
/** 已注入过的会话集合(用于 firstIterationOnly 模式) */
|
|
26
|
+
const injectedSessions = new Set();
|
|
27
|
+
/** 格式化检索结果为上下文笔记 */
|
|
28
|
+
function formatContextNote(results) {
|
|
29
|
+
const lines = [`--- ${noteTitle} ---`];
|
|
30
|
+
for (let i = 0; i < results.length; i++) {
|
|
31
|
+
const { chunk, score } = results[i];
|
|
32
|
+
let content = chunk.content;
|
|
33
|
+
if (content.length > maxChunkLength) {
|
|
34
|
+
content = content.slice(0, maxChunkLength) + '...';
|
|
35
|
+
}
|
|
36
|
+
const source = chunk.metadata?.title
|
|
37
|
+
? `[${chunk.metadata.title}]`
|
|
38
|
+
: `[doc: ${chunk.docId}]`;
|
|
39
|
+
lines.push(`[${i + 1}] ${source} (score: ${score.toFixed(3)})`);
|
|
40
|
+
lines.push(content);
|
|
41
|
+
lines.push('');
|
|
42
|
+
}
|
|
43
|
+
return lines.join('\n');
|
|
44
|
+
}
|
|
45
|
+
/** 从消息列表中提取最新的用户消息文本 */
|
|
46
|
+
function getLatestUserMessage(messages) {
|
|
47
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
48
|
+
const msg = messages[i];
|
|
49
|
+
if (msg.role === 'user') {
|
|
50
|
+
return extractTextFromContent(msg.content);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
name: 'rag',
|
|
57
|
+
async before(ctx) {
|
|
58
|
+
// firstIterationOnly 模式:仅首轮注入
|
|
59
|
+
if (firstIterationOnly && injectedSessions.has(ctx.sessionId)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// 提取最新用户消息
|
|
63
|
+
const query = getLatestUserMessage(ctx.messages);
|
|
64
|
+
if (!query.trim())
|
|
65
|
+
return;
|
|
66
|
+
try {
|
|
67
|
+
const results = await kb.search(query, topK);
|
|
68
|
+
// 过滤低分结果
|
|
69
|
+
const filtered = results.filter(r => r.score >= minScore);
|
|
70
|
+
if (filtered.length === 0)
|
|
71
|
+
return;
|
|
72
|
+
// 格式化上下文笔记
|
|
73
|
+
const note = formatContextNote(filtered);
|
|
74
|
+
// 注入系统级上下文消息
|
|
75
|
+
const contextMessage = {
|
|
76
|
+
role: 'system',
|
|
77
|
+
content: note,
|
|
78
|
+
};
|
|
79
|
+
// ctx.messages 是 ReadonlyArray,但底层是可变数组
|
|
80
|
+
// 与引擎内部注入消息的模式一致(如 progress nudge、iteration guard 等)
|
|
81
|
+
ctx.messages.push(contextMessage);
|
|
82
|
+
injectedSessions.add(ctx.sessionId);
|
|
83
|
+
logger(`[RAG] Injected ${filtered.length} chunks for session ${ctx.sessionId} (iter ${ctx.iteration})`);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
logger(`[RAG] Search failed: ${e?.message || e}`);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=rag-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rag-middleware.js","sourceRoot":"","sources":["../../../src/kb/rag-middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** 文本分块(知识库最小检索单元) */
|
|
2
|
+
export interface TextChunk {
|
|
3
|
+
/** 分块唯一 ID */
|
|
4
|
+
id: string;
|
|
5
|
+
/** 所属文档 ID */
|
|
6
|
+
docId: string;
|
|
7
|
+
/** 分块文本内容 */
|
|
8
|
+
content: string;
|
|
9
|
+
/** 预计算的嵌入向量(可选,由 EmbeddingProvider 生成) */
|
|
10
|
+
embedding?: number[];
|
|
11
|
+
/** 附加元数据(如页码、标题、来源等) */
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** 知识库检索结果 */
|
|
15
|
+
export interface SearchResult {
|
|
16
|
+
/** 匹配到的文本分块 */
|
|
17
|
+
chunk: TextChunk;
|
|
18
|
+
/** 相似度得分(0~1,越高越相关) */
|
|
19
|
+
score: number;
|
|
20
|
+
}
|
|
21
|
+
/** 文档元数据 */
|
|
22
|
+
export interface DocMeta {
|
|
23
|
+
/** 文档 ID */
|
|
24
|
+
id: string;
|
|
25
|
+
/** 文档标题 */
|
|
26
|
+
title: string;
|
|
27
|
+
/** 分块数量 */
|
|
28
|
+
chunkCount: number;
|
|
29
|
+
/** 创建时间(ISO 8601) */
|
|
30
|
+
createdAt: string;
|
|
31
|
+
/** 附加元数据 */
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 嵌入向量提供者接口
|
|
36
|
+
*
|
|
37
|
+
* 将文本转换为高维向量,用于语义检索。
|
|
38
|
+
* Core 仅定义接口,具体实现由上层注入(如调用 OpenAI Embeddings API)。
|
|
39
|
+
*/
|
|
40
|
+
export interface EmbeddingProvider {
|
|
41
|
+
/**
|
|
42
|
+
* 批量生成文本的嵌入向量
|
|
43
|
+
* @param texts 文本数组
|
|
44
|
+
* @returns 嵌入向量数组(与输入一一对应)
|
|
45
|
+
*/
|
|
46
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 知识库接口
|
|
50
|
+
*
|
|
51
|
+
* 提供文档摄入、语义/关键词检索、文档管理和列表功能。
|
|
52
|
+
* Core 定义接口,具体实现可以是内存型(InMemoryKnowledgeBase)
|
|
53
|
+
* 或外部向量数据库(由上层注入)。
|
|
54
|
+
*/
|
|
55
|
+
export interface KnowledgeBase {
|
|
56
|
+
/**
|
|
57
|
+
* 摄入文档分块
|
|
58
|
+
* @param docId 文档 ID
|
|
59
|
+
* @param chunks 文本分块数组
|
|
60
|
+
*/
|
|
61
|
+
ingest(docId: string, chunks: TextChunk[]): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* 检索与查询最相关的分块
|
|
64
|
+
* @param query 查询文本
|
|
65
|
+
* @param topK 返回结果数量(默认 5)
|
|
66
|
+
* @returns 按相关度降序排列的检索结果
|
|
67
|
+
*/
|
|
68
|
+
search(query: string, topK?: number): Promise<SearchResult[]>;
|
|
69
|
+
/**
|
|
70
|
+
* 删除指定文档及其所有分块
|
|
71
|
+
* @param docId 文档 ID
|
|
72
|
+
*/
|
|
73
|
+
remove(docId: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* 列出知识库中的所有文档元数据
|
|
76
|
+
* @returns 文档元数据数组
|
|
77
|
+
*/
|
|
78
|
+
list(): Promise<DocMeta[]>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/kb/types.ts"],"names":[],"mappings":"AAMA,sBAAsB;AACtB,MAAM,WAAW,SAAS;IACxB,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAID,cAAc;AACd,MAAM,WAAW,YAAY;IAC3B,eAAe;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,YAAY;AACZ,MAAM,WAAW,OAAO;IACtB,YAAY;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAID;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CAC7C;AAID;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAE9D;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/kb/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,0BAA0B;AAC1B,+DAA+D"}
|
|
@@ -20,6 +20,13 @@ export declare class AnthropicProvider implements LLMProvider {
|
|
|
20
20
|
* - assistant 的 tool_calls 转换为 tool_use 块
|
|
21
21
|
*/
|
|
22
22
|
private convertMessages;
|
|
23
|
+
/**
|
|
24
|
+
* 将 ContentPart[] 转换为 Anthropic content blocks
|
|
25
|
+
* - TextPart → {type: 'text', text}
|
|
26
|
+
* - ImagePart → {type: 'image', source: {type: 'base64'|'url', ...}}
|
|
27
|
+
* - FilePart → {type: 'text', text: '[file]\n${content}'}
|
|
28
|
+
*/
|
|
29
|
+
private convertContentPartsForAnthropic;
|
|
23
30
|
private convertTools;
|
|
24
31
|
private buildRequestBody;
|
|
25
32
|
private parseResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../../src/llm/anthropic-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../../src/llm/anthropic-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAgD3G,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAkE;gBAEpE,MAAM,EAAE,WAAW;IAY/B,QAAQ,IAAI,SAAS;IAUf,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAexB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAa9C,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC;IAkIhE,WAAW;IACX,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAMjD;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IA0EvB;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IA2CvC,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,aAAa;YAwCP,SAAS;CA2BxB"}
|
|
@@ -204,17 +204,27 @@ export class AnthropicProvider {
|
|
|
204
204
|
for (const msg of messages) {
|
|
205
205
|
switch (msg.role) {
|
|
206
206
|
case 'system':
|
|
207
|
-
system = (system ? system + '\n\n' : '') + (msg.content
|
|
207
|
+
system = (system ? system + '\n\n' : '') + (typeof msg.content === 'string' ? msg.content : '');
|
|
208
208
|
break;
|
|
209
|
-
case 'user':
|
|
210
|
-
|
|
209
|
+
case 'user': {
|
|
210
|
+
// 多模态内容:ContentPart[] → Anthropic content blocks
|
|
211
|
+
if (Array.isArray(msg.content)) {
|
|
212
|
+
const blocks = this.convertContentPartsForAnthropic(msg.content);
|
|
213
|
+
result.push({ role: 'user', content: blocks });
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
result.push({ role: 'user', content: msg.content || '' });
|
|
217
|
+
}
|
|
211
218
|
break;
|
|
219
|
+
}
|
|
212
220
|
case 'assistant': {
|
|
213
221
|
if (msg.tool_calls?.length) {
|
|
214
222
|
// assistant 带 tool_calls → text + tool_use blocks
|
|
215
223
|
const blocks = [];
|
|
216
224
|
if (msg.content) {
|
|
217
|
-
|
|
225
|
+
const textContent = typeof msg.content === 'string' ? msg.content : msg.content.map(p => p.type === 'text' ? p.text : '').join('');
|
|
226
|
+
if (textContent)
|
|
227
|
+
blocks.push({ type: 'text', text: textContent });
|
|
218
228
|
}
|
|
219
229
|
for (const tc of msg.tool_calls) {
|
|
220
230
|
let input;
|
|
@@ -236,7 +246,8 @@ export class AnthropicProvider {
|
|
|
236
246
|
result.push({ role: 'assistant', content: blocks });
|
|
237
247
|
}
|
|
238
248
|
else {
|
|
239
|
-
|
|
249
|
+
const textContent = typeof msg.content === 'string' ? msg.content : (msg.content || []).map(p => p.type === 'text' ? p.text : '').join('');
|
|
250
|
+
result.push({ role: 'assistant', content: textContent || '' });
|
|
240
251
|
}
|
|
241
252
|
break;
|
|
242
253
|
}
|
|
@@ -247,7 +258,7 @@ export class AnthropicProvider {
|
|
|
247
258
|
content: [{
|
|
248
259
|
type: 'tool_result',
|
|
249
260
|
tool_use_id: msg.tool_call_id,
|
|
250
|
-
content: msg.content
|
|
261
|
+
content: typeof msg.content === 'string' ? msg.content : '',
|
|
251
262
|
}],
|
|
252
263
|
});
|
|
253
264
|
break;
|
|
@@ -256,6 +267,55 @@ export class AnthropicProvider {
|
|
|
256
267
|
}
|
|
257
268
|
return { system, messages: result };
|
|
258
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* 将 ContentPart[] 转换为 Anthropic content blocks
|
|
272
|
+
* - TextPart → {type: 'text', text}
|
|
273
|
+
* - ImagePart → {type: 'image', source: {type: 'base64'|'url', ...}}
|
|
274
|
+
* - FilePart → {type: 'text', text: '[file]\n${content}'}
|
|
275
|
+
*/
|
|
276
|
+
convertContentPartsForAnthropic(parts) {
|
|
277
|
+
const blocks = [];
|
|
278
|
+
for (const part of parts) {
|
|
279
|
+
switch (part.type) {
|
|
280
|
+
case 'text':
|
|
281
|
+
blocks.push({ type: 'text', text: part.text });
|
|
282
|
+
break;
|
|
283
|
+
case 'image': {
|
|
284
|
+
const source = part.source;
|
|
285
|
+
// base64 data URI → Anthropic base64 source
|
|
286
|
+
const dataUriMatch = source.match(/^data:(image\/[a-zA-Z+]+);base64,(.+)$/);
|
|
287
|
+
if (dataUriMatch) {
|
|
288
|
+
blocks.push({
|
|
289
|
+
type: 'image',
|
|
290
|
+
source: {
|
|
291
|
+
type: 'base64',
|
|
292
|
+
media_type: dataUriMatch[1],
|
|
293
|
+
data: dataUriMatch[2],
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// URL → Anthropic url source
|
|
299
|
+
blocks.push({
|
|
300
|
+
type: 'image',
|
|
301
|
+
source: {
|
|
302
|
+
type: 'url',
|
|
303
|
+
url: source,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case 'file':
|
|
310
|
+
blocks.push({
|
|
311
|
+
type: 'text',
|
|
312
|
+
text: `[File: ${part.filename}]\n\n${part.content}`,
|
|
313
|
+
});
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return blocks;
|
|
318
|
+
}
|
|
259
319
|
convertTools(params) {
|
|
260
320
|
if (!params.tools?.length)
|
|
261
321
|
return undefined;
|
|
@@ -278,10 +338,25 @@ export class AnthropicProvider {
|
|
|
278
338
|
messages,
|
|
279
339
|
temperature: params.temperature ?? this.config.temperature,
|
|
280
340
|
};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
341
|
+
// Prompt 缓存:对 system prompt 和 tools 插入 cache_control 断点
|
|
342
|
+
// Anthropic 会缓存这些稳定内容,减少重复 API 调用成本
|
|
343
|
+
const enableCache = this.config.extra?.enableCache !== false; // 默认启用
|
|
344
|
+
if (system) {
|
|
345
|
+
if (enableCache) {
|
|
346
|
+
// system 使用 content block 格式以支持 cache_control
|
|
347
|
+
body.system = [{ type: 'text', text: system, cache_control: { type: 'ephemeral' } }];
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
body.system = system;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (tools?.length) {
|
|
354
|
+
if (enableCache) {
|
|
355
|
+
// 在最后一个 tool 上添加 cache_control 断点
|
|
356
|
+
tools[tools.length - 1] = { ...tools[tools.length - 1], cache_control: { type: 'ephemeral' } };
|
|
357
|
+
}
|
|
284
358
|
body.tools = tools;
|
|
359
|
+
}
|
|
285
360
|
return body;
|
|
286
361
|
}
|
|
287
362
|
parseResponse(data) {
|