@akemi-mio/creativity 0.0.0-stage → 0.1.1
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/dist/ConceptMixer.d.ts +41 -0
- package/dist/ConceptMixer.js +207 -0
- package/dist/CreativityPrompt.d.ts +24 -0
- package/dist/CreativityPrompt.js +206 -0
- package/dist/ExperimentPlanner.d.ts +14 -0
- package/dist/ExperimentPlanner.js +60 -0
- package/dist/ExperimentRunStore.d.ts +97 -0
- package/dist/ExperimentRunStore.js +160 -0
- package/dist/HypothesisGenerator.d.ts +60 -0
- package/dist/HypothesisGenerator.js +246 -0
- package/dist/IdeaGenerator.d.ts +51 -0
- package/dist/IdeaGenerator.js +145 -0
- package/dist/InsightSamplingExperiment.d.ts +82 -0
- package/dist/InsightSamplingExperiment.js +308 -0
- package/dist/LocalModelService.d.ts +38 -0
- package/dist/LocalModelService.js +162 -0
- package/dist/MechanismGraph.d.ts +46 -0
- package/dist/MechanismGraph.js +76 -0
- package/dist/MechanismRegistry.d.ts +118 -0
- package/dist/MechanismRegistry.js +233 -0
- package/dist/NoveltyScorer.d.ts +40 -0
- package/dist/NoveltyScorer.js +93 -0
- package/dist/SourceAggregator.d.ts +21 -0
- package/dist/SourceAggregator.js +59 -0
- package/dist/TemplateLibrary.d.ts +29 -0
- package/dist/TemplateLibrary.js +484 -0
- package/dist/WhenThenRunner.d.ts +135 -0
- package/dist/WhenThenRunner.js +358 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.js +9 -0
- package/package.json +67 -4
- package/README.md +0 -3
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WhenThenRunner — 声明式 WHEN/THEN 受限 DSL 运行器(机制涌现 P2a,定案 D5/R5/A2)
|
|
4
|
+
*
|
|
5
|
+
* 候选执行不写任意代码:DSL 查表求值(阈值比较 + 字段存在性 + 枚举匹配,禁 JS eval)。
|
|
6
|
+
* 步骤依赖执行 + 显式 named outputs(无隐式上下文注入)。
|
|
7
|
+
* resourceBudget 编译为 CapabilityToken.constraints。
|
|
8
|
+
* 求值器输入输出全白名单序列化(JSON number/boolean/string)。
|
|
9
|
+
* 条件字符串长度上限,解析失败 = fail-closed(步骤跳过 + 记 guardrail 事件,不中断实验、不泄漏沙箱内部)。
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MAX_CONDITION_LIST_LEN = exports.MAX_CONDITION_STRING_VALUE_LEN = exports.MAX_CONDITION_FIELD_LEN = void 0;
|
|
13
|
+
exports.lookupField = lookupField;
|
|
14
|
+
exports.evaluateCondition = evaluateCondition;
|
|
15
|
+
exports.evaluateWhen = evaluateWhen;
|
|
16
|
+
exports.compileBudgetToConstraints = compileBudgetToConstraints;
|
|
17
|
+
exports.topologicalOrder = topologicalOrder;
|
|
18
|
+
exports.runWhenThenRule = runWhenThenRule;
|
|
19
|
+
// ══════════════════════════════════════════
|
|
20
|
+
// 求值器(白名单查表,禁 eval)
|
|
21
|
+
// ══════════════════════════════════════════
|
|
22
|
+
/** 条件字符串长度上限(防超长注入) */
|
|
23
|
+
exports.MAX_CONDITION_FIELD_LEN = 128;
|
|
24
|
+
exports.MAX_CONDITION_STRING_VALUE_LEN = 512;
|
|
25
|
+
exports.MAX_CONDITION_LIST_LEN = 32;
|
|
26
|
+
function isScalar(v) {
|
|
27
|
+
return typeof v === 'number' || typeof v === 'boolean' || typeof v === 'string';
|
|
28
|
+
}
|
|
29
|
+
/** 按点分路径从 context 取值;中间路径不存在返回 undefined。不深入数组索引(防原型链)。 */
|
|
30
|
+
function lookupField(context, field) {
|
|
31
|
+
if (typeof field !== 'string' || field.length === 0 || field.length > exports.MAX_CONDITION_FIELD_LEN)
|
|
32
|
+
return undefined;
|
|
33
|
+
// 禁原型链:字段不得含 `__proto__` / `constructor` / `prototype`
|
|
34
|
+
if (field.includes('__proto__') || field.includes('constructor') || field.includes('prototype'))
|
|
35
|
+
return undefined;
|
|
36
|
+
const parts = field.split('.');
|
|
37
|
+
let cur = context;
|
|
38
|
+
for (const p of parts) {
|
|
39
|
+
if (cur === null || typeof cur !== 'object' || Array.isArray(cur))
|
|
40
|
+
return undefined;
|
|
41
|
+
const obj = cur;
|
|
42
|
+
if (!Object.prototype.hasOwnProperty.call(obj, p))
|
|
43
|
+
return undefined;
|
|
44
|
+
cur = obj[p];
|
|
45
|
+
}
|
|
46
|
+
return cur;
|
|
47
|
+
}
|
|
48
|
+
/** 求值单个 WHEN 条件;解析失败(非法字段/值/操作符)返回 null(调用方 fail-closed)。 */
|
|
49
|
+
function evaluateCondition(context, cond) {
|
|
50
|
+
if (!cond || typeof cond !== 'object')
|
|
51
|
+
return null;
|
|
52
|
+
const { field, op, value } = cond;
|
|
53
|
+
if (typeof field !== 'string' || field.length === 0 || field.length > exports.MAX_CONDITION_FIELD_LEN)
|
|
54
|
+
return null;
|
|
55
|
+
if (field.includes('__proto__') || field.includes('constructor') || field.includes('prototype'))
|
|
56
|
+
return null;
|
|
57
|
+
const actual = lookupField(context, field);
|
|
58
|
+
switch (op) {
|
|
59
|
+
case 'exists':
|
|
60
|
+
return actual !== undefined && actual !== null;
|
|
61
|
+
case 'notExists':
|
|
62
|
+
return actual === undefined || actual === null;
|
|
63
|
+
case 'eq':
|
|
64
|
+
case 'neq':
|
|
65
|
+
case 'gt':
|
|
66
|
+
case 'gte':
|
|
67
|
+
case 'lt':
|
|
68
|
+
case 'lte': {
|
|
69
|
+
if (!isScalar(value))
|
|
70
|
+
return null;
|
|
71
|
+
if (!isScalar(actual))
|
|
72
|
+
return false;
|
|
73
|
+
switch (op) {
|
|
74
|
+
case 'eq':
|
|
75
|
+
return actual === value;
|
|
76
|
+
case 'neq':
|
|
77
|
+
return actual !== value;
|
|
78
|
+
case 'gt':
|
|
79
|
+
return typeof actual === 'number' && typeof value === 'number' && actual > value;
|
|
80
|
+
case 'gte':
|
|
81
|
+
return typeof actual === 'number' && typeof value === 'number' && actual >= value;
|
|
82
|
+
case 'lt':
|
|
83
|
+
return typeof actual === 'number' && typeof value === 'number' && actual < value;
|
|
84
|
+
case 'lte':
|
|
85
|
+
return typeof actual === 'number' && typeof value === 'number' && actual <= value;
|
|
86
|
+
default:
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
case 'in':
|
|
91
|
+
case 'nin': {
|
|
92
|
+
if (!Array.isArray(value) || value.length > exports.MAX_CONDITION_LIST_LEN)
|
|
93
|
+
return null;
|
|
94
|
+
if (!value.every((v) => typeof v === 'string' && v.length <= exports.MAX_CONDITION_STRING_VALUE_LEN))
|
|
95
|
+
return null;
|
|
96
|
+
if (!isScalar(actual))
|
|
97
|
+
return false;
|
|
98
|
+
const hit = value.includes(actual);
|
|
99
|
+
return op === 'in' ? hit : !hit;
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
// 未知操作符 = 解析失败
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** 求值全部 WHEN 条件(AND);任一解析失败返回 null(fail-closed)。 */
|
|
107
|
+
function evaluateWhen(context, when) {
|
|
108
|
+
if (!when || when.length === 0)
|
|
109
|
+
return true;
|
|
110
|
+
for (const c of when) {
|
|
111
|
+
const r = evaluateCondition(context, c);
|
|
112
|
+
if (r === null)
|
|
113
|
+
return null;
|
|
114
|
+
if (r === false)
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// ══════════════════════════════════════════
|
|
120
|
+
// resourceBudget → CapabilityToken.constraints
|
|
121
|
+
// ══════════════════════════════════════════
|
|
122
|
+
/** 把 ResourceBudgetSpec 编译为 CapabilityToken.constraints(白名单字段)。 */
|
|
123
|
+
function compileBudgetToConstraints(budget, ruleBudget) {
|
|
124
|
+
// 步骤级覆盖规则级
|
|
125
|
+
const b = budget ?? ruleBudget;
|
|
126
|
+
if (!b)
|
|
127
|
+
return undefined;
|
|
128
|
+
const constraints = {};
|
|
129
|
+
if (typeof b.maxCalls === 'number' && Number.isFinite(b.maxCalls) && b.maxCalls >= 0) {
|
|
130
|
+
constraints.maxCalls = Math.floor(b.maxCalls);
|
|
131
|
+
}
|
|
132
|
+
if (typeof b.maxTokens === 'number' && Number.isFinite(b.maxTokens) && b.maxTokens >= 0) {
|
|
133
|
+
constraints.maxTokens = Math.floor(b.maxTokens);
|
|
134
|
+
}
|
|
135
|
+
if (typeof b.expiryMs === 'number' && Number.isFinite(b.expiryMs) && b.expiryMs >= 0) {
|
|
136
|
+
constraints.expiryMs = Math.floor(b.expiryMs);
|
|
137
|
+
}
|
|
138
|
+
if (b.allowedValues && typeof b.allowedValues === 'object' && !Array.isArray(b.allowedValues)) {
|
|
139
|
+
const allowed = {};
|
|
140
|
+
for (const [k, arr] of Object.entries(b.allowedValues)) {
|
|
141
|
+
if (Array.isArray(arr) && arr.every((v) => typeof v === 'string' && v.length <= exports.MAX_CONDITION_STRING_VALUE_LEN)) {
|
|
142
|
+
if (arr.length <= exports.MAX_CONDITION_LIST_LEN)
|
|
143
|
+
allowed[k] = arr;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (Object.keys(allowed).length > 0)
|
|
147
|
+
constraints.allowedValues = allowed;
|
|
148
|
+
}
|
|
149
|
+
return Object.keys(constraints).length > 0 ? constraints : undefined;
|
|
150
|
+
}
|
|
151
|
+
// ══════════════════════════════════════════
|
|
152
|
+
// 依赖调度(DAG 拓扑 + named outputs)
|
|
153
|
+
// ══════════════════════════════════════════
|
|
154
|
+
/** 拓扑排序步骤;环路/未知依赖返回 null(fail-closed)。 */
|
|
155
|
+
function topologicalOrder(steps) {
|
|
156
|
+
const byId = new Map();
|
|
157
|
+
for (const s of steps) {
|
|
158
|
+
if (!s || typeof s.id !== 'string' || s.id.length === 0)
|
|
159
|
+
return null;
|
|
160
|
+
if (byId.has(s.id))
|
|
161
|
+
return null;
|
|
162
|
+
byId.set(s.id, s);
|
|
163
|
+
}
|
|
164
|
+
const indegree = new Map();
|
|
165
|
+
const children = new Map();
|
|
166
|
+
for (const s of steps) {
|
|
167
|
+
indegree.set(s.id, 0);
|
|
168
|
+
}
|
|
169
|
+
for (const s of steps) {
|
|
170
|
+
const deps = s.dependsOn ?? [];
|
|
171
|
+
for (const d of deps) {
|
|
172
|
+
if (!byId.has(d))
|
|
173
|
+
return null; // 未知依赖
|
|
174
|
+
indegree.set(s.id, (indegree.get(s.id) ?? 0) + 1);
|
|
175
|
+
const list = children.get(d) ?? [];
|
|
176
|
+
list.push(s.id);
|
|
177
|
+
children.set(d, list);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const queue = [];
|
|
181
|
+
for (const [id, deg] of indegree) {
|
|
182
|
+
if (deg === 0)
|
|
183
|
+
queue.push(id);
|
|
184
|
+
}
|
|
185
|
+
queue.sort();
|
|
186
|
+
const order = [];
|
|
187
|
+
while (queue.length > 0) {
|
|
188
|
+
const id = queue.shift();
|
|
189
|
+
order.push(byId.get(id));
|
|
190
|
+
for (const child of children.get(id) ?? []) {
|
|
191
|
+
const nd = (indegree.get(child) ?? 1) - 1;
|
|
192
|
+
indegree.set(child, nd);
|
|
193
|
+
if (nd === 0)
|
|
194
|
+
queue.push(child);
|
|
195
|
+
}
|
|
196
|
+
queue.sort();
|
|
197
|
+
}
|
|
198
|
+
if (order.length !== steps.length)
|
|
199
|
+
return null; // 环
|
|
200
|
+
return order;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 执行一条 WHEN/THEN 规则。
|
|
204
|
+
*
|
|
205
|
+
* - 按 DAG 拓扑顺序调度
|
|
206
|
+
* - 每步先求值 WHEN(解析失败 → fail-closed skip + guardrail 事件)
|
|
207
|
+
* - 输入从初始 context + 上游 named outputs 显式解析(无隐式注入)
|
|
208
|
+
* - 预算编译为 CapabilityToken.constraints 传给 executor
|
|
209
|
+
* - 任一步失败不中断实验:后续依赖步骤 blocked,独立步骤继续
|
|
210
|
+
*/
|
|
211
|
+
async function runWhenThenRule(rule, context, executeStep, options) {
|
|
212
|
+
const events = [];
|
|
213
|
+
const namedOutputs = { ...(options?.initialOutputs ?? {}) };
|
|
214
|
+
const stepStatus = new Map();
|
|
215
|
+
const stepReason = new Map();
|
|
216
|
+
const stepOutputs = new Map();
|
|
217
|
+
const sink = (ev) => {
|
|
218
|
+
events.push(ev);
|
|
219
|
+
options?.onEvent?.(ev);
|
|
220
|
+
};
|
|
221
|
+
// 1. 拓扑排序(环/未知依赖 → 整规则 fail-closed)
|
|
222
|
+
const order = topologicalOrder(rule.steps ?? []);
|
|
223
|
+
if (!order) {
|
|
224
|
+
sink({
|
|
225
|
+
event_type: 'whenthen.rule.failed',
|
|
226
|
+
rule_id: rule.id,
|
|
227
|
+
reason: 'invalid_graph',
|
|
228
|
+
outcome: 'failed',
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
});
|
|
231
|
+
return { success: false, namedOutputs, steps: [], events };
|
|
232
|
+
}
|
|
233
|
+
// 2. 逐步骤
|
|
234
|
+
for (const step of order) {
|
|
235
|
+
const deps = step.dependsOn ?? [];
|
|
236
|
+
const depBlocked = deps.some((d) => {
|
|
237
|
+
const st = stepStatus.get(d);
|
|
238
|
+
return st === 'failed' || st === 'blocked' || st === 'skipped';
|
|
239
|
+
});
|
|
240
|
+
if (depBlocked) {
|
|
241
|
+
stepStatus.set(step.id, 'blocked');
|
|
242
|
+
stepReason.set(step.id, 'upstream_blocked');
|
|
243
|
+
sink({
|
|
244
|
+
event_type: 'whenthen.step.skipped',
|
|
245
|
+
rule_id: rule.id,
|
|
246
|
+
step_id: step.id,
|
|
247
|
+
reason: 'upstream_blocked',
|
|
248
|
+
outcome: 'skipped',
|
|
249
|
+
timestamp: Date.now(),
|
|
250
|
+
});
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
// 3. WHEN 求值(fail-closed)
|
|
254
|
+
const whenOk = evaluateWhen(context, step.when);
|
|
255
|
+
if (whenOk === null) {
|
|
256
|
+
stepStatus.set(step.id, 'skipped');
|
|
257
|
+
stepReason.set(step.id, 'when_parse_failed');
|
|
258
|
+
sink({
|
|
259
|
+
event_type: 'whenthen.step.skipped',
|
|
260
|
+
rule_id: rule.id,
|
|
261
|
+
step_id: step.id,
|
|
262
|
+
reason: 'when_parse_failed',
|
|
263
|
+
outcome: 'skipped',
|
|
264
|
+
timestamp: Date.now(),
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (whenOk === false) {
|
|
269
|
+
stepStatus.set(step.id, 'skipped');
|
|
270
|
+
stepReason.set(step.id, 'when_not_satisfied');
|
|
271
|
+
sink({
|
|
272
|
+
event_type: 'whenthen.step.skipped',
|
|
273
|
+
rule_id: rule.id,
|
|
274
|
+
step_id: step.id,
|
|
275
|
+
reason: 'when_not_satisfied',
|
|
276
|
+
outcome: 'skipped',
|
|
277
|
+
timestamp: Date.now(),
|
|
278
|
+
});
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
// 4. 显式 named inputs 解析(路径 = 初始 context 或 namedOutputs)
|
|
282
|
+
const inputs = {};
|
|
283
|
+
if (step.inputs) {
|
|
284
|
+
for (const [name, path] of Object.entries(step.inputs)) {
|
|
285
|
+
if (typeof path !== 'string' || path.length === 0 || path.length > exports.MAX_CONDITION_FIELD_LEN)
|
|
286
|
+
continue;
|
|
287
|
+
if (path.includes('__proto__') || path.includes('constructor') || path.includes('prototype'))
|
|
288
|
+
continue;
|
|
289
|
+
const v = lookupField(namedOutputs, path) ?? lookupField(context, path);
|
|
290
|
+
if (v !== undefined)
|
|
291
|
+
inputs[name] = v;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// 5. 预算编译
|
|
295
|
+
const constraints = compileBudgetToConstraints(step.resourceBudget, rule.resourceBudget);
|
|
296
|
+
// 6. 执行
|
|
297
|
+
try {
|
|
298
|
+
const result = await executeStep({
|
|
299
|
+
stepId: step.id,
|
|
300
|
+
capabilityId: step.capabilityId,
|
|
301
|
+
inputs,
|
|
302
|
+
constraints,
|
|
303
|
+
});
|
|
304
|
+
if (result.success) {
|
|
305
|
+
stepStatus.set(step.id, 'ok');
|
|
306
|
+
const outs = result.outputs ?? {};
|
|
307
|
+
stepOutputs.set(step.id, outs);
|
|
308
|
+
for (const [k, v] of Object.entries(outs)) {
|
|
309
|
+
namedOutputs[k] = v;
|
|
310
|
+
namedOutputs[`${step.id}.${k}`] = v;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
stepStatus.set(step.id, 'failed');
|
|
315
|
+
stepReason.set(step.id, result.error ?? 'step_failed');
|
|
316
|
+
sink({
|
|
317
|
+
event_type: 'whenthen.step.failed',
|
|
318
|
+
rule_id: rule.id,
|
|
319
|
+
step_id: step.id,
|
|
320
|
+
reason: result.error ?? 'step_failed',
|
|
321
|
+
outcome: 'failed',
|
|
322
|
+
timestamp: Date.now(),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
stepStatus.set(step.id, 'failed');
|
|
328
|
+
stepReason.set(step.id, 'step_exception');
|
|
329
|
+
sink({
|
|
330
|
+
event_type: 'whenthen.step.failed',
|
|
331
|
+
rule_id: rule.id,
|
|
332
|
+
step_id: step.id,
|
|
333
|
+
reason: 'step_exception',
|
|
334
|
+
outcome: 'failed',
|
|
335
|
+
timestamp: Date.now(),
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const allOk = order.every((s) => stepStatus.get(s.id) === 'ok' || stepStatus.get(s.id) === 'skipped');
|
|
340
|
+
sink({
|
|
341
|
+
event_type: allOk ? 'whenthen.rule.complete' : 'whenthen.rule.failed',
|
|
342
|
+
rule_id: rule.id,
|
|
343
|
+
reason: allOk ? 'complete' : 'partial_failure',
|
|
344
|
+
outcome: allOk ? 'success' : 'partial',
|
|
345
|
+
timestamp: Date.now(),
|
|
346
|
+
});
|
|
347
|
+
return {
|
|
348
|
+
success: allOk,
|
|
349
|
+
namedOutputs,
|
|
350
|
+
steps: order.map((s) => ({
|
|
351
|
+
id: s.id,
|
|
352
|
+
status: stepStatus.get(s.id) ?? 'blocked',
|
|
353
|
+
reason: stepReason.get(s.id),
|
|
354
|
+
outputs: stepOutputs.get(s.id),
|
|
355
|
+
})),
|
|
356
|
+
events,
|
|
357
|
+
};
|
|
358
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成策略 �?�?ConceptMixer 之前选择,约束配对空�?
|
|
3
|
+
* - stable: 同类型组合,禁止 novelty bonus 主导,输出收�?
|
|
4
|
+
* - explore: 跨类型组合,提高 diversity weight,允许结构差�?
|
|
5
|
+
* - signal: 强制注入 trend/ provocation/insight 来源,限�?randomness
|
|
6
|
+
*/
|
|
7
|
+
export type Strategy = 'stable' | 'explore' | 'signal';
|
|
8
|
+
export interface CreativitySource {
|
|
9
|
+
name: string;
|
|
10
|
+
content: string;
|
|
11
|
+
fullContent?: string;
|
|
12
|
+
sourceDepth?: 'shallow' | 'medium' | 'full';
|
|
13
|
+
type: 'knowledge' | 'behavior' | 'insight' | 'failure' | 'random' | 'provocation' | 'feedback';
|
|
14
|
+
weight: number;
|
|
15
|
+
/** Provider + record id, e.g. `memory:mem_1791…`. Required on auto-aggregated sources (spec Capability 2). */
|
|
16
|
+
origin?: string;
|
|
17
|
+
/** Original record id for back-referencing. */
|
|
18
|
+
originId?: string;
|
|
19
|
+
/** 0-1 credibility hint; omit when unknowable. */
|
|
20
|
+
confidence?: number;
|
|
21
|
+
/** Source record time, ISO 8601. */
|
|
22
|
+
timestamp?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Where and how an idea.generate result was produced (spec Capability 1). */
|
|
25
|
+
export interface HypothesisProvenance {
|
|
26
|
+
/** Pairing strategy used to build source combos: explore | stable | signal. */
|
|
27
|
+
strategy?: string;
|
|
28
|
+
/** Rotation technique used for the prompt (mirrors `Hypothesis.technique`). */
|
|
29
|
+
technique?: string;
|
|
30
|
+
/** Memory record ids that grounded the goal (0-3, newest first). */
|
|
31
|
+
relatedMemoryIds?: string[];
|
|
32
|
+
/** Assembled sources that fed generation, filtered to the labels actually used. */
|
|
33
|
+
sources?: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
origin?: string;
|
|
37
|
+
timestamp?: string;
|
|
38
|
+
}>;
|
|
39
|
+
/** When the idea was generated, ISO 8601. */
|
|
40
|
+
generatedAt?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ConceptCombo {
|
|
43
|
+
id: string;
|
|
44
|
+
sources: [string, string];
|
|
45
|
+
description: string;
|
|
46
|
+
createdAt: number;
|
|
47
|
+
}
|
|
48
|
+
export type FermentVerdict = 'promote' | 'keep' | 'reject' | 'merge';
|
|
49
|
+
export interface FermentLogEntry {
|
|
50
|
+
at: number;
|
|
51
|
+
verdict: FermentVerdict;
|
|
52
|
+
reason: string;
|
|
53
|
+
score?: {
|
|
54
|
+
novelty: number;
|
|
55
|
+
feasibility: number;
|
|
56
|
+
impact: number;
|
|
57
|
+
logic?: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export interface HypothesisFermentationPatch {
|
|
61
|
+
status?: Hypothesis['status'];
|
|
62
|
+
fermentCount?: number;
|
|
63
|
+
lastFermentedAt?: number;
|
|
64
|
+
fermentLog?: FermentLogEntry[];
|
|
65
|
+
idea?: string;
|
|
66
|
+
novelty?: number;
|
|
67
|
+
feasibility?: number;
|
|
68
|
+
impact?: number;
|
|
69
|
+
logic?: number;
|
|
70
|
+
mergedInto?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface Hypothesis {
|
|
73
|
+
id: string;
|
|
74
|
+
title: string;
|
|
75
|
+
idea: string;
|
|
76
|
+
expectedBenefit: string;
|
|
77
|
+
risk: string;
|
|
78
|
+
sourceLabels: string[];
|
|
79
|
+
sourceDetails?: Array<{
|
|
80
|
+
name: string;
|
|
81
|
+
depth: 'shallow' | 'medium' | 'full';
|
|
82
|
+
}>;
|
|
83
|
+
novelty: number;
|
|
84
|
+
feasibility: number;
|
|
85
|
+
impact: number;
|
|
86
|
+
/** 逻辑一致性评分 0-100(第四维,评审/生成时打分,可缺省视为 50) */
|
|
87
|
+
logic?: number;
|
|
88
|
+
status: 'draft' | 'active' | 'testing' | 'validated' | 'rejected';
|
|
89
|
+
createdAt: number;
|
|
90
|
+
/** The rotation technique this hypothesis was generated with (idea.generate provenance.technique). */
|
|
91
|
+
technique?: string;
|
|
92
|
+
/** Idea-generation provenance; `mio.idea.generate` persists this with the record. */
|
|
93
|
+
provenance?: HypothesisProvenance;
|
|
94
|
+
/** 实现难度 1-5(LLM 生成�?*/
|
|
95
|
+
implementationDifficulty?: number;
|
|
96
|
+
/** 预计开发时间(LLM 生成,如 "1-2�?�?*/
|
|
97
|
+
estimatedDevTime?: string;
|
|
98
|
+
/** 多视角评估(LLM 生成�?*/
|
|
99
|
+
perspectives?: {
|
|
100
|
+
self: string;
|
|
101
|
+
user: string;
|
|
102
|
+
maintainer: string;
|
|
103
|
+
};
|
|
104
|
+
/** 已发酵轮�?*/
|
|
105
|
+
fermentCount?: number;
|
|
106
|
+
/** 最近发酵时间戳 */
|
|
107
|
+
lastFermentedAt?: number;
|
|
108
|
+
/** 发酵历史记录 */
|
|
109
|
+
fermentLog?: FermentLogEntry[];
|
|
110
|
+
/** merge 后指向的�?hypothesis id */
|
|
111
|
+
mergedInto?: string;
|
|
112
|
+
implementedCommitSha?: string;
|
|
113
|
+
implementedAt?: number;
|
|
114
|
+
implementationNote?: string;
|
|
115
|
+
/** 机制假设:提出的关系边(带 proposedRelations 即机制假设,否则普通创意) */
|
|
116
|
+
proposedRelations?: ProposedRelation[];
|
|
117
|
+
/** 证伪条件:命中任一条件则机制假设可被拒绝 */
|
|
118
|
+
falsificationConditions?: string[];
|
|
119
|
+
/** 触发本假设的 observation/trace id 溯源 */
|
|
120
|
+
sourceObservationIds?: string[];
|
|
121
|
+
}
|
|
122
|
+
/** 机制图的一条候选边:A --[effect]--> B */
|
|
123
|
+
export interface ProposedRelation {
|
|
124
|
+
from: string;
|
|
125
|
+
to: string;
|
|
126
|
+
effect: string;
|
|
127
|
+
/** 推断来源:identity=verified | inferred(A6 confidence 映射) */
|
|
128
|
+
inference?: 'identity' | 'inferred';
|
|
129
|
+
}
|
|
130
|
+
export interface ExperimentPlan {
|
|
131
|
+
hypothesisId: string;
|
|
132
|
+
title: string;
|
|
133
|
+
steps: string[];
|
|
134
|
+
successCriteria: string[];
|
|
135
|
+
estimatedDuration: string;
|
|
136
|
+
createdAt: number;
|
|
137
|
+
}
|
|
138
|
+
export interface CreativeIdea {
|
|
139
|
+
hypothesis: Hypothesis;
|
|
140
|
+
experiment: ExperimentPlan | null;
|
|
141
|
+
}
|
|
142
|
+
export interface DreamCycleLog {
|
|
143
|
+
timestamp: number;
|
|
144
|
+
sourcesExamined: number;
|
|
145
|
+
combosGenerated: number;
|
|
146
|
+
hypothesesGenerated: number;
|
|
147
|
+
topIdea: string | null;
|
|
148
|
+
}
|
|
149
|
+
export interface IdeaStoreLike {
|
|
150
|
+
addCombo: (combo: ConceptCombo) => void;
|
|
151
|
+
addHypothesis: (h: Hypothesis) => void;
|
|
152
|
+
addManyHypotheses: (hs: Hypothesis[]) => void;
|
|
153
|
+
addExperiment: (exp: ExperimentPlan) => void;
|
|
154
|
+
logDreamCycle: (entry: DreamCycleLog) => void;
|
|
155
|
+
getHypotheses: (options?: {
|
|
156
|
+
status?: string;
|
|
157
|
+
limit?: number;
|
|
158
|
+
}) => Hypothesis[];
|
|
159
|
+
getNovelHypotheses: (threshold?: number, limit?: number) => Hypothesis[];
|
|
160
|
+
getActiveExperiments: () => ExperimentPlan[];
|
|
161
|
+
getRecentCombos: (limit?: number) => ConceptCombo[];
|
|
162
|
+
getRecentDreamCycles: (limit?: number) => DreamCycleLog[];
|
|
163
|
+
updateHypothesisStatus: (id: string, status: Hypothesis['status']) => boolean;
|
|
164
|
+
addExploredPair: (nameA: string, nameB: string) => void;
|
|
165
|
+
getExploredPairs: () => string[];
|
|
166
|
+
resetExploredPairs: () => void;
|
|
167
|
+
count: () => {
|
|
168
|
+
combos: number;
|
|
169
|
+
hypotheses: number;
|
|
170
|
+
experiments: number;
|
|
171
|
+
dreamCycles: number;
|
|
172
|
+
};
|
|
173
|
+
templateAdoptionStats: () => Record<string, {
|
|
174
|
+
total: number;
|
|
175
|
+
active: number;
|
|
176
|
+
rejected: number;
|
|
177
|
+
adopted: number;
|
|
178
|
+
}>;
|
|
179
|
+
adoptionReport: (limit?: number) => string;
|
|
180
|
+
getFermentableHypotheses: (limit?: number) => Hypothesis[];
|
|
181
|
+
updateHypothesisFermentation: (id: string, patch: HypothesisFermentationPatch) => boolean;
|
|
182
|
+
}
|
|
183
|
+
export interface CreativityStoreData {
|
|
184
|
+
version: number;
|
|
185
|
+
combos: ConceptCombo[];
|
|
186
|
+
hypotheses: Hypothesis[];
|
|
187
|
+
experiments: ExperimentPlan[];
|
|
188
|
+
dreamCycles: DreamCycleLog[];
|
|
189
|
+
exploredPairs: string[];
|
|
190
|
+
}
|
|
191
|
+
export declare const CREATIVITY_STORE_VERSION = 2;
|
|
192
|
+
export declare const DREAM_CYCLE_INTERVAL_MS: number;
|
|
193
|
+
export declare const NORMAL_CYCLE_INTERVAL_MS: number;
|
|
194
|
+
export declare const FERMENT_INTERVAL_MS: number;
|
|
195
|
+
/** 发酵与创意周期错峰偏移:避免同一时刻并发占用 code 模型上游 */
|
|
196
|
+
export declare const FERMENT_PHASE_OFFSET_MS: number;
|
|
197
|
+
/**
|
|
198
|
+
* 外部信号 �?不进入配对空�?
|
|
199
|
+
*
|
|
200
|
+
* Observer 的外部数据在此层保持�?不可配对"的原始语义,
|
|
201
|
+
* 直接注入 LLM 作为约束/挑战,而非组合概念�?
|
|
202
|
+
*
|
|
203
|
+
* �?CreativitySource 的关键区别:
|
|
204
|
+
* - 不能进入 ConceptMixer
|
|
205
|
+
* - 不参�?combinatorial pairing
|
|
206
|
+
* - 不参�?scoring/ranking
|
|
207
|
+
* - 只作�?prompt 中的"外部审视"�?
|
|
208
|
+
*/
|
|
209
|
+
export interface ExternalSignal {
|
|
210
|
+
source: string;
|
|
211
|
+
raw: string;
|
|
212
|
+
type: 'trend' | 'event' | 'anomaly' | 'insight';
|
|
213
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FERMENT_PHASE_OFFSET_MS = exports.FERMENT_INTERVAL_MS = exports.NORMAL_CYCLE_INTERVAL_MS = exports.DREAM_CYCLE_INTERVAL_MS = exports.CREATIVITY_STORE_VERSION = void 0;
|
|
4
|
+
exports.CREATIVITY_STORE_VERSION = 2;
|
|
5
|
+
exports.DREAM_CYCLE_INTERVAL_MS = 30 * 60 * 1000; // 30min
|
|
6
|
+
exports.NORMAL_CYCLE_INTERVAL_MS = 5 * 60 * 1000; // 5min
|
|
7
|
+
exports.FERMENT_INTERVAL_MS = 10 * 60 * 1000; // 10min
|
|
8
|
+
/** 发酵与创意周期错峰偏移:避免同一时刻并发占用 code 模型上游 */
|
|
9
|
+
exports.FERMENT_PHASE_OFFSET_MS = 2 * 60 * 1000; // 2min
|
package/package.json
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akemi-mio/creativity",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Creativity layer: ideas, writing, blog, image, inspiration",
|
|
5
|
+
"main": "./dist/IdeaGenerator.js",
|
|
6
|
+
"types": "./dist/IdeaGenerator.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./IdeaGenerator": {
|
|
9
|
+
"types": "./dist/IdeaGenerator.d.ts",
|
|
10
|
+
"require": "./dist/IdeaGenerator.js",
|
|
11
|
+
"default": "./dist/IdeaGenerator.js"
|
|
12
|
+
},
|
|
13
|
+
"./SourceAggregator": {
|
|
14
|
+
"types": "./dist/SourceAggregator.d.ts",
|
|
15
|
+
"require": "./dist/SourceAggregator.js",
|
|
16
|
+
"default": "./dist/SourceAggregator.js"
|
|
17
|
+
},
|
|
18
|
+
"./NoveltyScorer": {
|
|
19
|
+
"types": "./dist/NoveltyScorer.d.ts",
|
|
20
|
+
"require": "./dist/NoveltyScorer.js",
|
|
21
|
+
"default": "./dist/NoveltyScorer.js"
|
|
22
|
+
},
|
|
23
|
+
"./types": {
|
|
24
|
+
"types": "./dist/types.d.ts",
|
|
25
|
+
"require": "./dist/types.js",
|
|
26
|
+
"default": "./dist/types.js"
|
|
27
|
+
},
|
|
28
|
+
"./MechanismRegistry": {
|
|
29
|
+
"types": "./dist/MechanismRegistry.d.ts",
|
|
30
|
+
"require": "./dist/MechanismRegistry.js",
|
|
31
|
+
"default": "./dist/MechanismRegistry.js"
|
|
32
|
+
},
|
|
33
|
+
"./ExperimentRunStore": {
|
|
34
|
+
"types": "./dist/ExperimentRunStore.d.ts",
|
|
35
|
+
"require": "./dist/ExperimentRunStore.js",
|
|
36
|
+
"default": "./dist/ExperimentRunStore.js"
|
|
37
|
+
},
|
|
38
|
+
"./WhenThenRunner": {
|
|
39
|
+
"types": "./dist/WhenThenRunner.d.ts",
|
|
40
|
+
"require": "./dist/WhenThenRunner.js",
|
|
41
|
+
"default": "./dist/WhenThenRunner.js"
|
|
42
|
+
},
|
|
43
|
+
"./MechanismGraph": {
|
|
44
|
+
"types": "./dist/MechanismGraph.d.ts",
|
|
45
|
+
"require": "./dist/MechanismGraph.js",
|
|
46
|
+
"default": "./dist/MechanismGraph.js"
|
|
47
|
+
},
|
|
48
|
+
"./InsightSamplingExperiment": {
|
|
49
|
+
"types": "./dist/InsightSamplingExperiment.d.ts",
|
|
50
|
+
"require": "./dist/InsightSamplingExperiment.js",
|
|
51
|
+
"default": "./dist/InsightSamplingExperiment.js"
|
|
52
|
+
},
|
|
53
|
+
"./package.json": "./package.json"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsc -p tsconfig.build.json",
|
|
60
|
+
"prepublishOnly": "npm run build"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=18"
|
|
64
|
+
},
|
|
65
|
+
"license": "MIT",
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@akemi-mio/core": "^0.1.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/README.md
DELETED