autosnippet 3.2.15 → 3.2.16

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 (50) hide show
  1. package/dist/bin/cli.js +10 -0
  2. package/dist/bin/cli.js.map +1 -1
  3. package/dist/lib/external/mcp/handlers/consolidated.d.ts.map +1 -1
  4. package/dist/lib/external/mcp/handlers/consolidated.js +4 -2
  5. package/dist/lib/external/mcp/handlers/consolidated.js.map +1 -1
  6. package/dist/lib/external/mcp/handlers/skill.d.ts +17 -0
  7. package/dist/lib/external/mcp/handlers/skill.d.ts.map +1 -1
  8. package/dist/lib/external/mcp/handlers/skill.js +166 -0
  9. package/dist/lib/external/mcp/handlers/skill.js.map +1 -1
  10. package/dist/lib/http/routes/skills.d.ts.map +1 -1
  11. package/dist/lib/http/routes/skills.js +73 -0
  12. package/dist/lib/http/routes/skills.js.map +1 -1
  13. package/dist/lib/injection/modules/AgentModule.d.ts +1 -0
  14. package/dist/lib/injection/modules/AgentModule.d.ts.map +1 -1
  15. package/dist/lib/injection/modules/AgentModule.js +28 -0
  16. package/dist/lib/injection/modules/AgentModule.js.map +1 -1
  17. package/dist/lib/platform/ios/spm/SpmHelper.d.ts +1 -1
  18. package/dist/lib/service/skills/AIRecallStrategy.d.ts +30 -0
  19. package/dist/lib/service/skills/AIRecallStrategy.d.ts.map +1 -0
  20. package/dist/lib/service/skills/AIRecallStrategy.js +51 -0
  21. package/dist/lib/service/skills/AIRecallStrategy.js.map +1 -0
  22. package/dist/lib/service/skills/FeedbackStore.d.ts +48 -0
  23. package/dist/lib/service/skills/FeedbackStore.d.ts.map +1 -0
  24. package/dist/lib/service/skills/FeedbackStore.js +255 -0
  25. package/dist/lib/service/skills/FeedbackStore.js.map +1 -0
  26. package/dist/lib/service/skills/RecommendationMetrics.d.ts +60 -0
  27. package/dist/lib/service/skills/RecommendationMetrics.d.ts.map +1 -0
  28. package/dist/lib/service/skills/RecommendationMetrics.js +120 -0
  29. package/dist/lib/service/skills/RecommendationMetrics.js.map +1 -0
  30. package/dist/lib/service/skills/RecommendationPipeline.d.ts +43 -0
  31. package/dist/lib/service/skills/RecommendationPipeline.d.ts.map +1 -0
  32. package/dist/lib/service/skills/RecommendationPipeline.js +235 -0
  33. package/dist/lib/service/skills/RecommendationPipeline.js.map +1 -0
  34. package/dist/lib/service/skills/RuleRecallStrategy.d.ts +16 -0
  35. package/dist/lib/service/skills/RuleRecallStrategy.d.ts.map +1 -0
  36. package/dist/lib/service/skills/RuleRecallStrategy.js +37 -0
  37. package/dist/lib/service/skills/RuleRecallStrategy.js.map +1 -0
  38. package/dist/lib/service/skills/SignalCollector.d.ts +3 -3
  39. package/dist/lib/service/skills/SignalCollector.d.ts.map +1 -1
  40. package/dist/lib/service/skills/SignalCollector.js +72 -2
  41. package/dist/lib/service/skills/SignalCollector.js.map +1 -1
  42. package/dist/lib/service/skills/SkillHooks.d.ts +33 -14
  43. package/dist/lib/service/skills/SkillHooks.d.ts.map +1 -1
  44. package/dist/lib/service/skills/SkillHooks.js +261 -30
  45. package/dist/lib/service/skills/SkillHooks.js.map +1 -1
  46. package/dist/lib/service/skills/types.d.ts +210 -0
  47. package/dist/lib/service/skills/types.d.ts.map +1 -0
  48. package/dist/lib/service/skills/types.js +7 -0
  49. package/dist/lib/service/skills/types.js.map +1 -0
  50. package/package.json +5 -1
@@ -0,0 +1,255 @@
1
+ /**
2
+ * FeedbackStore — 推荐反馈持久化与用户偏好推导
3
+ *
4
+ * 存储位置: {projectRoot}/.autosnippet/feedback.jsonl
5
+ * 格式: 每行一个 JSON 对象 (append-only log)
6
+ *
7
+ * 职责:
8
+ * - 记录用户对推荐的反馈 (adopted / dismissed / expired / viewed / modified)
9
+ * - 计算采纳率、查看率、按来源分组的采纳率
10
+ * - 推导用户偏好向量 (喜欢/回避的类别和来源)
11
+ * - 检测被频繁忽略的推荐类别
12
+ */
13
+ import fs from 'node:fs';
14
+ import path from 'node:path';
15
+ import { RUNTIME_DIR } from '#shared/ProjectMarkers.js';
16
+ import Logger from '../../infrastructure/logging/Logger.js';
17
+ const FEEDBACK_FILE = 'feedback.jsonl';
18
+ /** 频繁忽略阈值: 该类别至少 5 次且忽略率 >= 70% */
19
+ const DISMISS_MIN_COUNT = 5;
20
+ const DISMISS_THRESHOLD = 0.7;
21
+ /** 内存缓存条数上限 (JSONL 可无限追加,但内存只保留最近 N 条) */
22
+ const MAX_MEMORY_ENTRIES = 2000;
23
+ export class FeedbackStore {
24
+ #filePath;
25
+ #logger;
26
+ #entries = [];
27
+ #loaded = false;
28
+ constructor(projectRoot) {
29
+ this.#filePath = path.join(projectRoot, RUNTIME_DIR, FEEDBACK_FILE);
30
+ this.#logger = Logger.getInstance();
31
+ }
32
+ // ─── 公共 API ──────────────────────────────────────────
33
+ /**
34
+ * 记录一条反馈
35
+ */
36
+ async record(feedback) {
37
+ this.#ensureLoaded();
38
+ const entry = {
39
+ ...feedback,
40
+ timestamp: feedback.timestamp || new Date().toISOString(),
41
+ _ts: new Date().toISOString(),
42
+ };
43
+ this.#entries.push(entry);
44
+ // 内存溢出保护
45
+ if (this.#entries.length > MAX_MEMORY_ENTRIES) {
46
+ this.#entries = this.#entries.slice(-MAX_MEMORY_ENTRIES);
47
+ }
48
+ // 追加写入 JSONL
49
+ try {
50
+ const dir = path.dirname(this.#filePath);
51
+ if (!fs.existsSync(dir)) {
52
+ fs.mkdirSync(dir, { recursive: true });
53
+ }
54
+ fs.appendFileSync(this.#filePath, `${JSON.stringify(entry)}\n`, 'utf-8');
55
+ }
56
+ catch (err) {
57
+ this.#logger.warn('FeedbackStore: failed to persist feedback', {
58
+ error: err instanceof Error ? err.message : String(err),
59
+ });
60
+ }
61
+ }
62
+ /**
63
+ * 获取采纳率
64
+ * @param source 可选 — 按推荐来源过滤
65
+ */
66
+ getAdoptionRate(source) {
67
+ this.#ensureLoaded();
68
+ const filtered = source ? this.#entries.filter((e) => e.source === source) : this.#entries;
69
+ const adopted = filtered.filter((e) => e.action === 'adopted' || e.action === 'modified').length;
70
+ const dismissed = filtered.filter((e) => e.action === 'dismissed').length;
71
+ const total = adopted + dismissed;
72
+ if (total === 0) {
73
+ return 0;
74
+ }
75
+ return adopted / total;
76
+ }
77
+ /**
78
+ * 获取用户偏好向量 (基于历史反馈推导)
79
+ */
80
+ getUserPreference() {
81
+ this.#ensureLoaded();
82
+ const categoryStats = new Map();
83
+ const sourceStats = new Map();
84
+ for (const entry of this.#entries) {
85
+ const cat = entry.category ?? 'unknown';
86
+ const src = entry.source ?? 'unknown';
87
+ // 按类别
88
+ if (!categoryStats.has(cat)) {
89
+ categoryStats.set(cat, { adopted: 0, dismissed: 0 });
90
+ }
91
+ const cs = categoryStats.get(cat);
92
+ if (entry.action === 'adopted' || entry.action === 'modified') {
93
+ cs.adopted++;
94
+ }
95
+ if (entry.action === 'dismissed') {
96
+ cs.dismissed++;
97
+ }
98
+ // 按来源
99
+ if (!sourceStats.has(src)) {
100
+ sourceStats.set(src, { adopted: 0, dismissed: 0 });
101
+ }
102
+ const ss = sourceStats.get(src);
103
+ if (entry.action === 'adopted' || entry.action === 'modified') {
104
+ ss.adopted++;
105
+ }
106
+ if (entry.action === 'dismissed') {
107
+ ss.dismissed++;
108
+ }
109
+ }
110
+ const preferredCategories = [];
111
+ const avoidedCategories = [];
112
+ for (const [cat, stats] of categoryStats) {
113
+ const total = stats.adopted + stats.dismissed;
114
+ if (total < 3) {
115
+ continue;
116
+ }
117
+ const rate = stats.adopted / total;
118
+ if (rate >= 0.6) {
119
+ preferredCategories.push(cat);
120
+ }
121
+ if (rate <= 0.3) {
122
+ avoidedCategories.push(cat);
123
+ }
124
+ }
125
+ const preferredSources = [];
126
+ for (const [src, stats] of sourceStats) {
127
+ const total = stats.adopted + stats.dismissed;
128
+ if (total >= 3 && stats.adopted / total >= 0.5) {
129
+ preferredSources.push(src);
130
+ }
131
+ }
132
+ return {
133
+ preferredCategories,
134
+ avoidedCategories,
135
+ preferredSources,
136
+ adoptionRate: this.getAdoptionRate(),
137
+ };
138
+ }
139
+ /**
140
+ * 特定类别的推荐是否被用户频繁忽略
141
+ */
142
+ isFrequentlyDismissed(category) {
143
+ this.#ensureLoaded();
144
+ const entries = this.#entries.filter((e) => e.category === category);
145
+ const dismissed = entries.filter((e) => e.action === 'dismissed').length;
146
+ const adopted = entries.filter((e) => e.action === 'adopted' || e.action === 'modified').length;
147
+ const total = dismissed + adopted;
148
+ if (total < DISMISS_MIN_COUNT) {
149
+ return false;
150
+ }
151
+ return dismissed / total >= DISMISS_THRESHOLD;
152
+ }
153
+ /**
154
+ * 获取推荐效果指标快照
155
+ */
156
+ getMetricsSnapshot(since) {
157
+ this.#ensureLoaded();
158
+ const sinceTs = since?.toISOString() ?? '1970-01-01T00:00:00.000Z';
159
+ const filtered = this.#entries.filter((e) => e.timestamp >= sinceTs);
160
+ const totalRecommendations = filtered.length;
161
+ const totalViewed = filtered.filter((e) => e.action === 'viewed').length;
162
+ const totalAdopted = filtered.filter((e) => e.action === 'adopted' || e.action === 'modified').length;
163
+ const totalDismissed = filtered.filter((e) => e.action === 'dismissed').length;
164
+ const totalExpired = filtered.filter((e) => e.action === 'expired').length;
165
+ // 按来源分组采纳率
166
+ const sourceMap = new Map();
167
+ for (const entry of filtered) {
168
+ const src = entry.source ?? 'unknown';
169
+ if (!sourceMap.has(src)) {
170
+ sourceMap.set(src, { adopted: 0, total: 0 });
171
+ }
172
+ const s = sourceMap.get(src);
173
+ if (entry.action === 'adopted' ||
174
+ entry.action === 'modified' ||
175
+ entry.action === 'dismissed') {
176
+ s.total++;
177
+ }
178
+ if (entry.action === 'adopted' || entry.action === 'modified') {
179
+ s.adopted++;
180
+ }
181
+ }
182
+ const adoptionRateBySource = {};
183
+ for (const [src, stats] of sourceMap) {
184
+ adoptionRateBySource[src] = stats.total > 0 ? stats.adopted / stats.total : 0;
185
+ }
186
+ const decisionTotal = totalAdopted + totalDismissed;
187
+ return {
188
+ totalRecommendations,
189
+ totalViewed,
190
+ totalAdopted,
191
+ totalDismissed,
192
+ totalExpired,
193
+ adoptionRate: decisionTotal > 0 ? totalAdopted / decisionTotal : 0,
194
+ viewRate: totalRecommendations > 0 ? totalViewed / totalRecommendations : 0,
195
+ adoptionRateBySource,
196
+ since: sinceTs,
197
+ };
198
+ }
199
+ /**
200
+ * 获取指定推荐 ID 的反馈历史
201
+ */
202
+ getFeedbackFor(recommendationId) {
203
+ this.#ensureLoaded();
204
+ return this.#entries.filter((e) => e.recommendationId === recommendationId);
205
+ }
206
+ /**
207
+ * 全部反馈条数
208
+ */
209
+ get size() {
210
+ this.#ensureLoaded();
211
+ return this.#entries.length;
212
+ }
213
+ // ─── 内部方法 ──────────────────────────────────────────
214
+ /**
215
+ * 惰性加载: 首次访问时从 JSONL 文件读取历史
216
+ */
217
+ #ensureLoaded() {
218
+ if (this.#loaded) {
219
+ return;
220
+ }
221
+ this.#loaded = true;
222
+ this.#loadFromDisk();
223
+ }
224
+ #loadFromDisk() {
225
+ try {
226
+ if (!fs.existsSync(this.#filePath)) {
227
+ return;
228
+ }
229
+ const content = fs.readFileSync(this.#filePath, 'utf-8');
230
+ const lines = content.trim().split('\n').filter(Boolean);
231
+ const entries = [];
232
+ for (const line of lines) {
233
+ try {
234
+ entries.push(JSON.parse(line));
235
+ }
236
+ catch {
237
+ // 跳过损坏行
238
+ }
239
+ }
240
+ // 只保留最近 N 条
241
+ this.#entries =
242
+ entries.length > MAX_MEMORY_ENTRIES ? entries.slice(-MAX_MEMORY_ENTRIES) : entries;
243
+ if (this.#entries.length > 0) {
244
+ this.#logger.debug(`FeedbackStore: loaded ${this.#entries.length} entries from disk`);
245
+ }
246
+ }
247
+ catch (err) {
248
+ this.#logger.warn('FeedbackStore: failed to load from disk', {
249
+ error: err instanceof Error ? err.message : String(err),
250
+ });
251
+ }
252
+ }
253
+ }
254
+ export default FeedbackStore;
255
+ //# sourceMappingURL=FeedbackStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedbackStore.js","sourceRoot":"","sources":["../../../../lib/service/skills/FeedbackStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * RecommendationMetrics — 推荐效果度量追踪
3
+ *
4
+ * 追踪推荐系统的关键指标:
5
+ * - 展示次数 (display)
6
+ * - 查看次数 (view)
7
+ * - 采纳次数 (adopt)
8
+ * - 忽略次数 (dismiss)
9
+ * - 采纳率 = adopt / (adopt + dismiss)
10
+ * - CTR = view / display
11
+ *
12
+ * 所有数据委托给 FeedbackStore 持久化。
13
+ * 本类只负责实时聚合 + 对外暴露接口。
14
+ */
15
+ import type { FeedbackStore } from './FeedbackStore.js';
16
+ import type { RecommendationMetricsSnapshot, ScoredRecommendation } from './types.js';
17
+ interface MetricsCounters {
18
+ displayed: number;
19
+ viewed: number;
20
+ adopted: number;
21
+ dismissed: number;
22
+ expired: number;
23
+ }
24
+ export declare class RecommendationMetrics {
25
+ #private;
26
+ constructor(feedbackStore: FeedbackStore);
27
+ /**
28
+ * 记录推荐已展示 (dashboard/MCP 返回推荐列表时调用)
29
+ */
30
+ trackDisplayed(recommendations: ScoredRecommendation[]): void;
31
+ /**
32
+ * 记录推荐被采纳
33
+ */
34
+ trackAdopted(recommendationId: string, source?: string, category?: string): Promise<void>;
35
+ /**
36
+ * 记录推荐被忽略
37
+ */
38
+ trackDismissed(recommendationId: string, reason?: string, source?: string, category?: string): Promise<void>;
39
+ /**
40
+ * 记录推荐过期
41
+ */
42
+ trackExpired(recommendationId: string, source?: string): Promise<void>;
43
+ /**
44
+ * 获取当前会话的指标
45
+ */
46
+ getSessionMetrics(): MetricsCounters & {
47
+ adoptionRate: number;
48
+ ctr: number;
49
+ };
50
+ /**
51
+ * 获取全局指标快照 (含持久化历史)
52
+ */
53
+ getGlobalSnapshot(since?: Date): RecommendationMetricsSnapshot;
54
+ /**
55
+ * 获取指定来源的采纳率
56
+ */
57
+ getAdoptionRateBySource(source: string): number;
58
+ }
59
+ export default RecommendationMetrics;
60
+ //# sourceMappingURL=RecommendationMetrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecommendationMetrics.d.ts","sourceRoot":"","sources":["../../../../lib/service/skills/RecommendationMetrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEtF,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;;gBAapB,aAAa,EAAE,aAAa;IAOxC;;OAEG;IACH,cAAc,CAAC,eAAe,EAAE,oBAAoB,EAAE,GAAG,IAAI;IAqB7D;;OAEG;IACG,YAAY,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/F;;OAEG;IACG,cAAc,CAClB,gBAAgB,EAAE,MAAM,EACxB,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,YAAY,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5E;;OAEG;IACH,iBAAiB,IAAI,eAAe,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;IAU5E;;OAEG;IACH,iBAAiB,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,6BAA6B;IAI9D;;OAEG;IACH,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAGhD;AAED,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * RecommendationMetrics — 推荐效果度量追踪
3
+ *
4
+ * 追踪推荐系统的关键指标:
5
+ * - 展示次数 (display)
6
+ * - 查看次数 (view)
7
+ * - 采纳次数 (adopt)
8
+ * - 忽略次数 (dismiss)
9
+ * - 采纳率 = adopt / (adopt + dismiss)
10
+ * - CTR = view / display
11
+ *
12
+ * 所有数据委托给 FeedbackStore 持久化。
13
+ * 本类只负责实时聚合 + 对外暴露接口。
14
+ */
15
+ import Logger from '../../infrastructure/logging/Logger.js';
16
+ export class RecommendationMetrics {
17
+ #feedbackStore;
18
+ #logger;
19
+ /** 内存计数器 — 只追踪本次进程的增量 */
20
+ #session = {
21
+ displayed: 0,
22
+ viewed: 0,
23
+ adopted: 0,
24
+ dismissed: 0,
25
+ expired: 0,
26
+ };
27
+ constructor(feedbackStore) {
28
+ this.#feedbackStore = feedbackStore;
29
+ this.#logger = Logger.getInstance();
30
+ }
31
+ // ─── 事件记录 ──────────────────────────────────────────
32
+ /**
33
+ * 记录推荐已展示 (dashboard/MCP 返回推荐列表时调用)
34
+ */
35
+ trackDisplayed(recommendations) {
36
+ this.#session.displayed += recommendations.length;
37
+ // 记录 viewed 事件到 FeedbackStore (展示即视为曝光)
38
+ for (const rec of recommendations) {
39
+ this.#feedbackStore
40
+ .record({
41
+ recommendationId: rec.recommendationId,
42
+ action: 'viewed',
43
+ timestamp: new Date().toISOString(),
44
+ source: rec.source,
45
+ category: rec.signals.category,
46
+ })
47
+ .catch((err) => {
48
+ this.#logger.warn('RecommendationMetrics: failed to record viewed', {
49
+ error: err instanceof Error ? err.message : String(err),
50
+ });
51
+ });
52
+ }
53
+ }
54
+ /**
55
+ * 记录推荐被采纳
56
+ */
57
+ async trackAdopted(recommendationId, source, category) {
58
+ this.#session.adopted++;
59
+ await this.#feedbackStore.record({
60
+ recommendationId,
61
+ action: 'adopted',
62
+ timestamp: new Date().toISOString(),
63
+ source,
64
+ category,
65
+ });
66
+ }
67
+ /**
68
+ * 记录推荐被忽略
69
+ */
70
+ async trackDismissed(recommendationId, reason, source, category) {
71
+ this.#session.dismissed++;
72
+ await this.#feedbackStore.record({
73
+ recommendationId,
74
+ action: 'dismissed',
75
+ timestamp: new Date().toISOString(),
76
+ source,
77
+ category,
78
+ reason,
79
+ });
80
+ }
81
+ /**
82
+ * 记录推荐过期
83
+ */
84
+ async trackExpired(recommendationId, source) {
85
+ this.#session.expired++;
86
+ await this.#feedbackStore.record({
87
+ recommendationId,
88
+ action: 'expired',
89
+ timestamp: new Date().toISOString(),
90
+ source,
91
+ });
92
+ }
93
+ // ─── 查询 ──────────────────────────────────────────────
94
+ /**
95
+ * 获取当前会话的指标
96
+ */
97
+ getSessionMetrics() {
98
+ const s = this.#session;
99
+ const decisionTotal = s.adopted + s.dismissed;
100
+ return {
101
+ ...s,
102
+ adoptionRate: decisionTotal > 0 ? s.adopted / decisionTotal : 0,
103
+ ctr: s.displayed > 0 ? s.viewed / s.displayed : 0,
104
+ };
105
+ }
106
+ /**
107
+ * 获取全局指标快照 (含持久化历史)
108
+ */
109
+ getGlobalSnapshot(since) {
110
+ return this.#feedbackStore.getMetricsSnapshot(since);
111
+ }
112
+ /**
113
+ * 获取指定来源的采纳率
114
+ */
115
+ getAdoptionRateBySource(source) {
116
+ return this.#feedbackStore.getAdoptionRate(source);
117
+ }
118
+ }
119
+ export default RecommendationMetrics;
120
+ //# sourceMappingURL=RecommendationMetrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecommendationMetrics.js","sourceRoot":"","sources":["../../../../lib/service/skills/RecommendationMetrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * RecommendationPipeline — 统一推荐管线
3
+ *
4
+ * 多阶段处理:
5
+ * 1. Recall — 多策略并行召回候选 (Rule / AI / Vector / Popularity)
6
+ * 2. Score — 综合评分 (信号强度 × 用户偏好 × 新鲜度)
7
+ * 3. Rank — 排序 + 截断
8
+ * 4. Filter — 去重、过滤已有 Skill、过滤频繁忽略的类别
9
+ * 5. Deliver — 输出最终推荐列表 + 触发 Hook
10
+ *
11
+ * 设计原则:
12
+ * - 静默降级: 任何策略失败不影响其他策略
13
+ * - 离线优先: 无 AI 时降级到规则召回
14
+ * - 反馈闪环: 利用 FeedbackStore 调整排序权重
15
+ */
16
+ import type { FeedbackStore } from './FeedbackStore.js';
17
+ import type { SkillHooks } from './SkillHooks.js';
18
+ import type { RecallStrategy, RecommendationContext, ScoredRecommendation } from './types.js';
19
+ export declare class RecommendationPipeline {
20
+ #private;
21
+ constructor(opts?: {
22
+ feedbackStore?: FeedbackStore | null;
23
+ skillHooks?: SkillHooks | null;
24
+ });
25
+ /**
26
+ * 注册召回策略
27
+ */
28
+ addStrategy(strategy: RecallStrategy): void;
29
+ /**
30
+ * 获取已注册策略列表
31
+ */
32
+ getStrategies(): ReadonlyArray<RecallStrategy>;
33
+ /**
34
+ * 执行推荐管线
35
+ *
36
+ * @param context 推荐上下文
37
+ * @param topK 最多返回数量
38
+ * @returns 排序后的推荐结果列表
39
+ */
40
+ recommend(context: RecommendationContext, topK?: number): Promise<ScoredRecommendation[]>;
41
+ }
42
+ export default RecommendationPipeline;
43
+ //# sourceMappingURL=RecommendationPipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecommendationPipeline.d.ts","sourceRoot":"","sources":["../../../../lib/service/skills/RecommendationPipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EACV,cAAc,EAEd,qBAAqB,EACrB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAmBpB,qBAAa,sBAAsB;;gBAO/B,IAAI,GAAE;QACJ,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;QACrC,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;KAC3B;IASR;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAK3C;;OAEG;IACH,aAAa,IAAI,aAAa,CAAC,cAAc,CAAC;IAM9C;;;;;;OAMG;IACG,SAAS,CACb,OAAO,EAAE,qBAAqB,EAC9B,IAAI,GAAE,MAAsB,GAC3B,OAAO,CAAC,oBAAoB,EAAE,CAAC;CA0NnC;AAED,eAAe,sBAAsB,CAAC"}