@akemi-mio/creativity 0.2.0 → 0.3.0

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.
@@ -33,10 +33,13 @@ export declare class ConceptMixer {
33
33
  * @param strategy 策略约束:stable/explore/signal,默认为 'explore'
34
34
  * 策略决定哪些 type 配对被允许、评分权重如何调整。
35
35
  * @param feedback 可选:正向反馈有界修正 + 探索预算;缺省 = 行为不变。
36
+ * @returns 每项含 combo / score / pair。pair 是组合引用的原始来源对象对
37
+ * (R2 收敛:CLI 引擎等调用方不再从 combo.sources 字符串反查来源)。
36
38
  */
37
39
  mix(sources: CreativitySource[], maxCombos?: number, exploredPairs?: string[], strategy?: Strategy, feedback?: FeedbackMixerInput): {
38
40
  combo: ConceptCombo;
39
41
  score: number;
42
+ pair: [CreativitySource, CreativitySource];
40
43
  }[];
41
44
  /**
42
45
  * 按策略约束生成配对 — 核心改动:
@@ -27,6 +27,8 @@ class ConceptMixer {
27
27
  * @param strategy 策略约束:stable/explore/signal,默认为 'explore'
28
28
  * 策略决定哪些 type 配对被允许、评分权重如何调整。
29
29
  * @param feedback 可选:正向反馈有界修正 + 探索预算;缺省 = 行为不变。
30
+ * @returns 每项含 combo / score / pair。pair 是组合引用的原始来源对象对
31
+ * (R2 收敛:CLI 引擎等调用方不再从 combo.sources 字符串反查来源)。
30
32
  */
31
33
  mix(sources, maxCombos = 10, exploredPairs = [], strategy = 'explore', feedback) {
32
34
  if (sources.length < 2)
@@ -64,7 +66,7 @@ class ConceptMixer {
64
66
  .slice(0, exploreCount);
65
67
  return [...main, ...rest]
66
68
  .sort((a, b) => (b.adjusted - a.adjusted) || (a.feedbackKey < b.feedbackKey ? -1 : 1))
67
- .map((s) => ({ combo: s.combo, score: s.adjusted }));
69
+ .map((s) => ({ combo: s.combo, score: s.adjusted, pair: s.pair }));
68
70
  }
69
71
  /**
70
72
  * 按策略约束生成配对 — 核心改动:
@@ -147,7 +149,7 @@ class ConceptMixer {
147
149
  description,
148
150
  createdAt: Date.now(),
149
151
  };
150
- return { combo, score };
152
+ return { combo, score, pair: [a, b] };
151
153
  }
152
154
  contentRelevance(a, b) {
153
155
  const contentA = a.fullContent ?? a.content;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * FeedbackMetrics — 正向反馈闭环验证指标(spec §八,P3 收官)
3
+ *
4
+ * 把"三类验证指标"里能在本地数据上回答的部分落成纯函数:
5
+ * - Pair Precision@K:快照中反馈调整幅度最大的 K 个概念对里,
6
+ * 已有终局(validated/rejected)假设的对的通过率(无终局样本 → null,
7
+ * 无样本 ≠ 0;hypothesis_only 键不是概念对,不参与排名)。
8
+ * - Novelty@K:top-K 概念对里未被窗口内假设探索过的比例。
9
+ * - Validation Pass Rate:窗口内终局假设的通过率。
10
+ * - Event Ingestion Completeness:JSONL 原始行 vs 可解析行(损坏行=丢失)。
11
+ *
12
+ * 身份规则与快照一致(types.ts sourceConceptId/conceptPairKey):
13
+ * 概念对键 = conceptPairKey(sourceConceptId),hypothesis_only 键带
14
+ * `hypothesis:` 前缀被排除;无 provenance 的假设回退 sourceLabels 的
15
+ * `name:` 键(与 sourceConceptId 的无 origin 回退同空间)。
16
+ *
17
+ * 纯函数:不读写文件、不碰 DB、不进 checkPromotionGate/checkSubmitGate
18
+ * 输入(spec §二.2 反馈权限隔离)。
19
+ */
20
+ import { type FeedbackLearningConfig, type FeedbackSnapshot } from './FeedbackLearning';
21
+ export interface FeedbackMetricsConfig {
22
+ /** Pair Precision@K / Novelty@K 的 K */
23
+ precisionK: number;
24
+ /** 通过率与探索集的回看窗口(天) */
25
+ windowDays: number;
26
+ }
27
+ export declare const DEFAULT_FEEDBACK_METRICS_CONFIG: FeedbackMetricsConfig;
28
+ /** 解析并校验指标配置;两个字段都缺失返回 null(fail-closed,调用方回退默认)。 */
29
+ export declare function parseFeedbackMetricsConfig(raw: unknown): FeedbackMetricsConfig | null;
30
+ /** 从环境变量解析(MIO_FEEDBACK_PRECISION_K / MIO_FEEDBACK_WINDOW_DAYS,缺省全默认)。 */
31
+ export declare function resolveFeedbackMetricsConfig(env?: Record<string, string | undefined>): FeedbackMetricsConfig;
32
+ /** 结构子集:主进程 Hypothesis 与 CLI store 行都满足(只要求用到的字段)。 */
33
+ export interface FeedbackMetricsHypothesis {
34
+ id: string;
35
+ status?: string;
36
+ createdAt?: number;
37
+ sourceLabels?: readonly string[];
38
+ provenance?: {
39
+ sources?: ReadonlyArray<{
40
+ name: string;
41
+ origin?: string;
42
+ }>;
43
+ };
44
+ }
45
+ /** 证据事件 JSONL 的行统计(调用方做原始扫描;本模块纯计算)。 */
46
+ export interface FeedbackIngestionCounts {
47
+ /** 非空行总数 */
48
+ rawLines: number;
49
+ /** 可 JSON 解析的行数 */
50
+ validRows: number;
51
+ }
52
+ export interface FeedbackTopPair {
53
+ pairKey: string;
54
+ /** λ clamp 后的调整量(排名依据取绝对值) */
55
+ adjustment: number;
56
+ validated: number;
57
+ rejected: number;
58
+ /** 无终局样本 → null(无样本 ≠ 0) */
59
+ precision: number | null;
60
+ /** 是否未被窗口内假设探索过 */
61
+ novel: boolean;
62
+ }
63
+ export interface FeedbackGenerationMetrics {
64
+ precisionK: number;
65
+ windowDays: number;
66
+ snapshotVersion: string | null;
67
+ pairPrecisionAtK: number | null;
68
+ evaluatedPairs: number;
69
+ noveltyAtK: number | null;
70
+ validationPassRate: number | null;
71
+ /** 窗口内终局假设数(validationPassRate 的分母) */
72
+ terminalHypotheses: number;
73
+ ingestion: {
74
+ rawLines: number;
75
+ validRows: number;
76
+ droppedRows: number;
77
+ completeness: number | null;
78
+ };
79
+ topPairs: FeedbackTopPair[];
80
+ }
81
+ export interface ComputeFeedbackGenerationMetricsArgs {
82
+ snapshot?: FeedbackSnapshot | null;
83
+ hypotheses?: readonly FeedbackMetricsHypothesis[];
84
+ ingestion?: FeedbackIngestionCounts;
85
+ config?: FeedbackMetricsConfig;
86
+ /** 缺省 Date.now();测试可注入固定时间 */
87
+ now?: number;
88
+ learningConfig?: FeedbackLearningConfig;
89
+ }
90
+ export declare function computeFeedbackGenerationMetrics(args?: ComputeFeedbackGenerationMetricsArgs): FeedbackGenerationMetrics;
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ /**
3
+ * FeedbackMetrics — 正向反馈闭环验证指标(spec §八,P3 收官)
4
+ *
5
+ * 把"三类验证指标"里能在本地数据上回答的部分落成纯函数:
6
+ * - Pair Precision@K:快照中反馈调整幅度最大的 K 个概念对里,
7
+ * 已有终局(validated/rejected)假设的对的通过率(无终局样本 → null,
8
+ * 无样本 ≠ 0;hypothesis_only 键不是概念对,不参与排名)。
9
+ * - Novelty@K:top-K 概念对里未被窗口内假设探索过的比例。
10
+ * - Validation Pass Rate:窗口内终局假设的通过率。
11
+ * - Event Ingestion Completeness:JSONL 原始行 vs 可解析行(损坏行=丢失)。
12
+ *
13
+ * 身份规则与快照一致(types.ts sourceConceptId/conceptPairKey):
14
+ * 概念对键 = conceptPairKey(sourceConceptId),hypothesis_only 键带
15
+ * `hypothesis:` 前缀被排除;无 provenance 的假设回退 sourceLabels 的
16
+ * `name:` 键(与 sourceConceptId 的无 origin 回退同空间)。
17
+ *
18
+ * 纯函数:不读写文件、不碰 DB、不进 checkPromotionGate/checkSubmitGate
19
+ * 输入(spec §二.2 反馈权限隔离)。
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.DEFAULT_FEEDBACK_METRICS_CONFIG = void 0;
23
+ exports.parseFeedbackMetricsConfig = parseFeedbackMetricsConfig;
24
+ exports.resolveFeedbackMetricsConfig = resolveFeedbackMetricsConfig;
25
+ exports.computeFeedbackGenerationMetrics = computeFeedbackGenerationMetrics;
26
+ const FeedbackLearning_1 = require("./FeedbackLearning");
27
+ const types_1 = require("./types");
28
+ exports.DEFAULT_FEEDBACK_METRICS_CONFIG = {
29
+ precisionK: 10,
30
+ windowDays: 30,
31
+ };
32
+ function clampNumber(value, min, max, fallback) {
33
+ const num = typeof value === 'string' ? Number(value) : value;
34
+ if (typeof num !== 'number' || !Number.isFinite(num))
35
+ return fallback;
36
+ return Math.max(min, Math.min(max, num));
37
+ }
38
+ /** 解析并校验指标配置;两个字段都缺失返回 null(fail-closed,调用方回退默认)。 */
39
+ function parseFeedbackMetricsConfig(raw) {
40
+ if (raw === null || typeof raw !== 'object')
41
+ return null;
42
+ const obj = raw;
43
+ const hasAny = ['precisionK', 'windowDays'].some((k) => obj[k] !== undefined);
44
+ if (!hasAny)
45
+ return null;
46
+ return {
47
+ precisionK: Math.floor(clampNumber(obj.precisionK, 1, 1000, exports.DEFAULT_FEEDBACK_METRICS_CONFIG.precisionK)),
48
+ windowDays: Math.floor(clampNumber(obj.windowDays, 1, 3650, exports.DEFAULT_FEEDBACK_METRICS_CONFIG.windowDays)),
49
+ };
50
+ }
51
+ /** 从环境变量解析(MIO_FEEDBACK_PRECISION_K / MIO_FEEDBACK_WINDOW_DAYS,缺省全默认)。 */
52
+ function resolveFeedbackMetricsConfig(env = process.env) {
53
+ return (parseFeedbackMetricsConfig({
54
+ precisionK: env.MIO_FEEDBACK_PRECISION_K,
55
+ windowDays: env.MIO_FEEDBACK_WINDOW_DAYS,
56
+ }) ?? exports.DEFAULT_FEEDBACK_METRICS_CONFIG);
57
+ }
58
+ const TERMINAL_STATUSES = new Set(['validated', 'rejected']);
59
+ const DAY_MS = 86_400_000;
60
+ const HYPOTHESIS_ONLY_PREFIX = 'hypothesis:';
61
+ /** 由 provenance 来源推导概念对键(与 buildFeedbackSnapshot 的归因同一规则)。 */
62
+ function pairKeysFromSources(sources) {
63
+ const ids = sources.map(types_1.sourceConceptId);
64
+ const keys = [];
65
+ for (let i = 0; i < ids.length; i++) {
66
+ for (let j = i + 1; j < ids.length; j++) {
67
+ if (ids[i] === ids[j])
68
+ continue;
69
+ keys.push((0, types_1.conceptPairKey)(ids[i], ids[j]));
70
+ }
71
+ }
72
+ return keys;
73
+ }
74
+ /** 无 provenance 假设的回退:sourceLabels 是原始名,等价于无 origin 的概念身份。 */
75
+ function pairKeysFromLabels(labels) {
76
+ const ids = labels.map((l) => `name:${l}`);
77
+ const keys = [];
78
+ for (let i = 0; i < ids.length; i++) {
79
+ for (let j = i + 1; j < ids.length; j++) {
80
+ if (ids[i] === ids[j])
81
+ continue;
82
+ keys.push((0, types_1.conceptPairKey)(ids[i], ids[j]));
83
+ }
84
+ }
85
+ return keys;
86
+ }
87
+ function computeFeedbackGenerationMetrics(args = {}) {
88
+ const config = args.config ?? exports.DEFAULT_FEEDBACK_METRICS_CONFIG;
89
+ const now = args.now ?? Date.now();
90
+ const learningConfig = args.learningConfig ?? FeedbackLearning_1.DEFAULT_FEEDBACK_LEARNING_CONFIG;
91
+ const hypotheses = args.hypotheses ?? [];
92
+ const snapshot = args.snapshot ?? null;
93
+ const cutoff = now - config.windowDays * DAY_MS;
94
+ // ── Validation Pass Rate(窗口内终局假设) ──
95
+ let validatedTotal = 0;
96
+ let rejectedTotal = 0;
97
+ for (const h of hypotheses) {
98
+ if (!h.status || !TERMINAL_STATUSES.has(h.status))
99
+ continue;
100
+ if (typeof h.createdAt !== 'number' || h.createdAt < cutoff)
101
+ continue;
102
+ if (h.status === 'validated')
103
+ validatedTotal++;
104
+ else
105
+ rejectedTotal++;
106
+ }
107
+ const terminalHypotheses = validatedTotal + rejectedTotal;
108
+ const validationPassRate = terminalHypotheses > 0 ? validatedTotal / terminalHypotheses : null;
109
+ // ── 终局假设 → 概念对链接(全量:配对证据来自快照,不受窗口裁剪) ──
110
+ const pairToTerminal = new Map();
111
+ for (const h of hypotheses) {
112
+ if (!h.status || !TERMINAL_STATUSES.has(h.status))
113
+ continue;
114
+ const sources = h.provenance?.sources;
115
+ if (!sources || sources.length < 2)
116
+ continue;
117
+ for (const key of pairKeysFromSources(sources)) {
118
+ let counts = pairToTerminal.get(key);
119
+ if (!counts) {
120
+ counts = { validated: 0, rejected: 0 };
121
+ pairToTerminal.set(key, counts);
122
+ }
123
+ if (h.status === 'validated')
124
+ counts.validated++;
125
+ else
126
+ counts.rejected++;
127
+ }
128
+ }
129
+ // ── 窗口内探索集(novelty 判定) ──
130
+ const explored = new Set();
131
+ for (const h of hypotheses) {
132
+ if (typeof h.createdAt !== 'number' || h.createdAt < cutoff)
133
+ continue;
134
+ const sources = h.provenance?.sources;
135
+ if (sources && sources.length >= 2) {
136
+ for (const key of pairKeysFromSources(sources))
137
+ explored.add(key);
138
+ }
139
+ else if (h.sourceLabels && h.sourceLabels.length >= 2) {
140
+ for (const key of pairKeysFromLabels(h.sourceLabels))
141
+ explored.add(key);
142
+ }
143
+ }
144
+ // ── top-K:快照概念对按 |clampedAdjustment| 排名(tie-break pairKey,稳定) ──
145
+ const conceptPairs = (snapshot?.pairs ?? []).filter((p) => !p.pairKey.startsWith(HYPOTHESIS_ONLY_PREFIX));
146
+ const topPairs = conceptPairs
147
+ .map((p) => {
148
+ const counts = pairToTerminal.get(p.pairKey);
149
+ const validated = counts?.validated ?? 0;
150
+ const rejected = counts?.rejected ?? 0;
151
+ const total = validated + rejected;
152
+ return {
153
+ pairKey: p.pairKey,
154
+ adjustment: (0, FeedbackLearning_1.replayFeedbackAdjustment)(p, learningConfig).clampedAdjustment,
155
+ validated,
156
+ rejected,
157
+ precision: total > 0 ? validated / total : null,
158
+ novel: !explored.has(p.pairKey),
159
+ };
160
+ })
161
+ .sort((a, b) => Math.abs(b.adjustment) - Math.abs(a.adjustment) || (a.pairKey < b.pairKey ? -1 : 1))
162
+ .slice(0, config.precisionK);
163
+ let evaluatedPairs = 0;
164
+ let precisionSum = 0;
165
+ let novelCount = 0;
166
+ for (const p of topPairs) {
167
+ if (p.precision !== null) {
168
+ evaluatedPairs++;
169
+ precisionSum += p.precision;
170
+ }
171
+ if (p.novel)
172
+ novelCount++;
173
+ }
174
+ const pairPrecisionAtK = evaluatedPairs > 0 ? precisionSum / evaluatedPairs : null;
175
+ const noveltyAtK = topPairs.length > 0 ? novelCount / topPairs.length : null;
176
+ // ── 事件摄取完整度(原始行 vs 可解析行) ──
177
+ const rawLines = args.ingestion?.rawLines ?? 0;
178
+ const validRows = args.ingestion?.validRows ?? 0;
179
+ const droppedRows = Math.max(0, rawLines - validRows);
180
+ const completeness = rawLines > 0 ? Math.max(0, Math.min(1, validRows / rawLines)) : null;
181
+ return {
182
+ precisionK: config.precisionK,
183
+ windowDays: config.windowDays,
184
+ snapshotVersion: snapshot?.version ?? null,
185
+ pairPrecisionAtK,
186
+ evaluatedPairs,
187
+ noveltyAtK,
188
+ validationPassRate,
189
+ terminalHypotheses,
190
+ ingestion: { rawLines, validRows, droppedRows, completeness },
191
+ topPairs,
192
+ };
193
+ }
@@ -33,5 +33,5 @@ export declare function parseFeedbackRuntime(raw: unknown): FeedbackRuntimeConfi
33
33
  export declare function resolveFeedbackRuntime(env?: Record<string, string | undefined>): FeedbackRuntimeConfig;
34
34
  /** 该模式下是否实际应用反馈到生成(shadow 只观测)。 */
35
35
  export declare function isFeedbackApplied(mode: FeedbackMode): boolean;
36
- /** 该模式下是否观测(计算 delta 并记录)。 */
37
- export declare function isFeedbackObserved(mode: FeedbackMode): boolean;
36
+ /** 该模式下是否观测(计算 delta 并记录)。谓词形式让调用方在守卫内拿到非 `off` 收窄。 */
37
+ export declare function isFeedbackObserved(mode: FeedbackMode): mode is Exclude<FeedbackMode, 'off'>;
@@ -66,7 +66,7 @@ function resolveFeedbackRuntime(env = process.env) {
66
66
  function isFeedbackApplied(mode) {
67
67
  return mode === 'canary' || mode === 'full';
68
68
  }
69
- /** 该模式下是否观测(计算 delta 并记录)。 */
69
+ /** 该模式下是否观测(计算 delta 并记录)。谓词形式让调用方在守卫内拿到非 `off` 收窄。 */
70
70
  function isFeedbackObserved(mode) {
71
71
  return mode === 'shadow' || mode === 'canary' || mode === 'full';
72
72
  }
@@ -0,0 +1,14 @@
1
+ import type { FeedbackRuntimeRun } from './FeedbackRollout';
2
+ /**
3
+ * feedback-runtime-runs.jsonl 的唯一读写实现(append-only,供放量报告统计阶段门槛)。
4
+ *
5
+ * 双轴共用:CLI/MCP(CreativityEngine)与主进程(CreativityService)都经由本模块落盘,
6
+ * 因此两个入口写入的行格式与读取口径不可能各自漂移(同 memory-store/policy-store 模式)。
7
+ * 数据目录由调用方决定:CLI/MCP 是 `<MIO_HOME>/creativity`,主进程是
8
+ * `MIO_HOME/creativity`(未设置时回退 `WORKSPACE_ROOT/creativity`)。
9
+ */
10
+ export declare const FEEDBACK_RUNTIME_RUNS_FILE = "feedback-runtime-runs.jsonl";
11
+ /** 追加一条观测运行摘要。落盘失败由调用方 best-effort 兜底(不得阻断生成)。 */
12
+ export declare function recordFeedbackRuntimeRun(dir: string, run: FeedbackRuntimeRun): void;
13
+ /** 读取全部观测运行摘要。损坏行/非对象行/`off` 行跳过(同 JsonlFeedbackEventStore 策略)。 */
14
+ export declare function readFeedbackRuntimeRuns(dir: string): FeedbackRuntimeRun[];
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FEEDBACK_RUNTIME_RUNS_FILE = void 0;
4
+ exports.recordFeedbackRuntimeRun = recordFeedbackRuntimeRun;
5
+ exports.readFeedbackRuntimeRuns = readFeedbackRuntimeRuns;
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const FeedbackRuntime_1 = require("./FeedbackRuntime");
9
+ /**
10
+ * feedback-runtime-runs.jsonl 的唯一读写实现(append-only,供放量报告统计阶段门槛)。
11
+ *
12
+ * 双轴共用:CLI/MCP(CreativityEngine)与主进程(CreativityService)都经由本模块落盘,
13
+ * 因此两个入口写入的行格式与读取口径不可能各自漂移(同 memory-store/policy-store 模式)。
14
+ * 数据目录由调用方决定:CLI/MCP 是 `<MIO_HOME>/creativity`,主进程是
15
+ * `MIO_HOME/creativity`(未设置时回退 `WORKSPACE_ROOT/creativity`)。
16
+ */
17
+ exports.FEEDBACK_RUNTIME_RUNS_FILE = 'feedback-runtime-runs.jsonl';
18
+ /** 追加一条观测运行摘要。落盘失败由调用方 best-effort 兜底(不得阻断生成)。 */
19
+ function recordFeedbackRuntimeRun(dir, run) {
20
+ if (!(0, fs_1.existsSync)(dir))
21
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
22
+ (0, fs_1.appendFileSync)((0, path_1.join)(dir, exports.FEEDBACK_RUNTIME_RUNS_FILE), JSON.stringify(run) + '\n', 'utf8');
23
+ }
24
+ /** 读取全部观测运行摘要。损坏行/非对象行/`off` 行跳过(同 JsonlFeedbackEventStore 策略)。 */
25
+ function readFeedbackRuntimeRuns(dir) {
26
+ const file = (0, path_1.join)(dir, exports.FEEDBACK_RUNTIME_RUNS_FILE);
27
+ if (!(0, fs_1.existsSync)(file))
28
+ return [];
29
+ const out = [];
30
+ for (const line of (0, fs_1.readFileSync)(file, 'utf8').split('\n')) {
31
+ if (!line.trim())
32
+ continue;
33
+ try {
34
+ const row = JSON.parse(line);
35
+ if (row &&
36
+ typeof row === 'object' &&
37
+ typeof row.mode === 'string' &&
38
+ row.mode !== 'off' &&
39
+ FeedbackRuntime_1.FEEDBACK_MODES.includes(row.mode)) {
40
+ out.push({
41
+ at: Number(row.at) || 0,
42
+ mode: row.mode,
43
+ snapshotVersion: typeof row.snapshotVersion === 'string' ? row.snapshotVersion : null,
44
+ pairCount: Number(row.pairCount) || 0,
45
+ applied: !!row.applied,
46
+ });
47
+ }
48
+ }
49
+ catch (_) {
50
+ // 损坏行跳过
51
+ }
52
+ }
53
+ return out;
54
+ }
@@ -20,6 +20,7 @@ export declare class HypothesisGenerator {
20
20
  timeoutMs?: number;
21
21
  requestId?: string;
22
22
  maxTokens?: number;
23
+ responseFormat?: 'object' | 'array';
23
24
  }) => Promise<{
24
25
  data?: any;
25
26
  error?: string;
@@ -122,6 +122,12 @@ class HypothesisGenerator {
122
122
  timeoutMs: 60000,
123
123
  // 输出无界会顶满超时(M2):生成上限 1200 tokens
124
124
  maxTokens: 1200,
125
+ // 提示词要求顶层数组:json_object 模式下部分模型会包成
126
+ // {"ideas": [...]},Array.isArray 判空后**静默**降级到模板
127
+ // (无 provenance.sources → 反馈事件不可归因,attribution
128
+ // coverage 恒 0)。声明 array 身份让 llm-client 省略
129
+ // response_format,与 InsightGenerator 同策略。
130
+ responseFormat: 'array',
125
131
  });
126
132
  if (result.error) {
127
133
  (0, Logger_1.log)('WARN', 'hypothesis_llm_error', { error: result.error });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akemi-mio/creativity",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Creativity layer: ideas, writing, blog, image, inspiration",
5
5
  "main": "./dist/IdeaGenerator.js",
6
6
  "types": "./dist/IdeaGenerator.d.ts",
@@ -85,6 +85,16 @@
85
85
  "require": "./dist/FeedbackRollout.js",
86
86
  "default": "./dist/FeedbackRollout.js"
87
87
  },
88
+ "./FeedbackRuntimeRuns": {
89
+ "types": "./dist/FeedbackRuntimeRuns.d.ts",
90
+ "require": "./dist/FeedbackRuntimeRuns.js",
91
+ "default": "./dist/FeedbackRuntimeRuns.js"
92
+ },
93
+ "./FeedbackMetrics": {
94
+ "types": "./dist/FeedbackMetrics.d.ts",
95
+ "require": "./dist/FeedbackMetrics.js",
96
+ "default": "./dist/FeedbackMetrics.js"
97
+ },
88
98
  "./package.json": "./package.json"
89
99
  },
90
100
  "files": [