mio-agent-runtime 0.14.0 → 0.14.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/README.md
CHANGED
|
@@ -423,6 +423,13 @@ mio creativity ferment --limit 3
|
|
|
423
423
|
`@akemi-mio/insight` 已安装且至少存有一条洞察时有意义,否则明确报错而不是
|
|
424
424
|
静默当作「没有来源」。因为来源可由它提供,`mio.creativity.generate` 的
|
|
425
425
|
`sources` 不再是 schema 必填项。
|
|
426
|
+
- **判重粒度是(素材对 × `--strategy`)。** 同一对素材在 `explore` / `signal` /
|
|
427
|
+
`stable` 下各算一次实验——「409 就换 strategy 重试」是有效的降级而不是空转;
|
|
428
|
+
三种 strategy 都试过、且没有新素材时才真正耗尽,此时返回的 `reason` 会带上
|
|
429
|
+
strategy、来源数与候选对数(外加 `strategy` 与 `pairsAvailable: 0` 字段),
|
|
430
|
+
调用方可以据此区分「换个 strategy 有用」与「该补新素材了」。素材身份取名称
|
|
431
|
+
去空白后的**前 120 个字符**(`--source` 省略 `|` 时 name 会退化成整段描述,
|
|
432
|
+
描述尾部微调不得绕过判重);没有 `strategy` 字段的旧记录仍挡住所有 strategy。
|
|
426
433
|
- `ferment` 会复核 `active` / `draft` 假设并更新分数;`verdict=promote` 且总分 > 200 时
|
|
427
434
|
升为 `validated`,`verdict=reject` 则标记为 `rejected`。
|
|
428
435
|
- **失败的 LLM 调用会出现在结果里,不再被吞掉。** 返回值带 `errors`
|
package/package.json
CHANGED
|
@@ -162,14 +162,34 @@ function mulberry32(seed) {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
// One concept-pair identity. `--source "name|content"` allows omitting the
|
|
166
|
+
// pipe, so `name` can degrade into the entire description (often >1k chars):
|
|
167
|
+
// with the raw name as identity, a tail edit mints a brand-new pair and
|
|
168
|
+
// silently bypasses dedup. Trim + first 120 chars is short enough to read in
|
|
169
|
+
// a key and long enough that genuine sources do not collide.
|
|
170
|
+
function pairSourceKey(name) {
|
|
171
|
+
return String(name == null ? '' : name).trim().slice(0, 120)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function mixConcepts(sources, exploredPairs, rng, strategy) {
|
|
166
175
|
if (sources.length < 2) return []
|
|
176
|
+
// Dedup identity is (pair, strategy): `strategy` picks the prompt and the
|
|
177
|
+
// temperature, so the documented fallback "hit 409, retry with another
|
|
178
|
+
// strategy" is a genuinely different experiment. Without the suffix every
|
|
179
|
+
// retry recomputed the same key and returned the same deterministic
|
|
180
|
+
// `all pairs already explored` — three LLM-less no-ops in a row.
|
|
181
|
+
const strat = String(strategy || '')
|
|
167
182
|
const pairs = []
|
|
168
183
|
for (let i = 0; i < sources.length; i++) {
|
|
169
184
|
for (let j = i + 1; j < sources.length; j++) {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
185
|
+
const a = pairSourceKey(sources[i].name)
|
|
186
|
+
const b = pairSourceKey(sources[j].name)
|
|
187
|
+
const key = strat ? `${a}||${b}||${strat}` : `${a}||${b}`
|
|
188
|
+
const reverseKey = strat ? `${b}||${a}||${strat}` : `${b}||${a}`
|
|
172
189
|
if (exploredPairs.has(key) || exploredPairs.has(reverseKey)) continue
|
|
190
|
+
// Records written without a strategy field carry the unsuffixed key;
|
|
191
|
+
// they must keep blocking every strategy (the old semantics).
|
|
192
|
+
if (strat && (exploredPairs.has(`${a}||${b}`) || exploredPairs.has(`${b}||${a}`))) continue
|
|
173
193
|
pairs.push([sources[i], sources[j]])
|
|
174
194
|
}
|
|
175
195
|
}
|
|
@@ -266,14 +286,35 @@ class CreativityEngine {
|
|
|
266
286
|
const strat = strategy || STRATEGY_CYCLE[this.strategyIndex % STRATEGY_CYCLE.length]
|
|
267
287
|
this.strategyIndex++
|
|
268
288
|
|
|
269
|
-
// Mix concepts
|
|
289
|
+
// Mix concepts. Keys carry the strategy each record was written with, so
|
|
290
|
+
// explore -> signal -> stable retries each get their own attempt while a
|
|
291
|
+
// record without a strategy stays unsuffixed and blocks every strategy.
|
|
270
292
|
const recent = this.store.getHypotheses({ limit: 30 })
|
|
271
293
|
const rejected = this.store.getHypotheses({ status: 'rejected', limit: 50 })
|
|
272
|
-
const exploredPairs = new Set(
|
|
273
|
-
|
|
294
|
+
const exploredPairs = new Set(
|
|
295
|
+
recent.flatMap((h) =>
|
|
296
|
+
(h.sourceLabels || []).flatMap((l, i, a) => {
|
|
297
|
+
if (i === 0) return []
|
|
298
|
+
const x = pairSourceKey(a[i - 1])
|
|
299
|
+
const y = pairSourceKey(l)
|
|
300
|
+
return h.strategy ? [`${x}||${y}||${h.strategy}`] : [`${x}||${y}`]
|
|
301
|
+
})
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
const pairs = mixConcepts(sources, exploredPairs, this.rng.bind(this), strat)
|
|
274
305
|
|
|
275
306
|
if (pairs.length === 0) {
|
|
276
|
-
|
|
307
|
+
// The bare string made a deterministic failure look like "this strategy
|
|
308
|
+
// did not work, maybe the next one will" — callers that degrade by
|
|
309
|
+
// switching strategy burned two LLM-less retries before learning the
|
|
310
|
+
// material pool itself was exhausted.
|
|
311
|
+
const candidatePairs = (sources.length * (sources.length - 1)) / 2
|
|
312
|
+
return {
|
|
313
|
+
ideas: [],
|
|
314
|
+
reason: `all pairs already explored for strategy "${strat}" (${sources.length} sources, ${candidatePairs} candidate pairs)`,
|
|
315
|
+
strategy: strat,
|
|
316
|
+
pairsAvailable: 0,
|
|
317
|
+
}
|
|
277
318
|
}
|
|
278
319
|
|
|
279
320
|
// Generate hypotheses via LLM
|
|
@@ -735,7 +735,7 @@ const TOOLS = [
|
|
|
735
735
|
type: 'boolean',
|
|
736
736
|
description: 'Seed concept sources from stored insights (highest score first), merged with any explicit sources. Needs @akemi-mio/insight and at least one stored insight.',
|
|
737
737
|
},
|
|
738
|
-
strategy: { type: 'string', description: 'Generation strategy: explore (cross-domain), signal (provocative), stable (conservative). Auto-selected if omitted.' },
|
|
738
|
+
strategy: { type: 'string', description: 'Generation strategy: explore (cross-domain), signal (provocative), stable (conservative). Auto-selected if omitted. Pair dedup is per strategy: the same source pair may be tried once under each strategy.' },
|
|
739
739
|
},
|
|
740
740
|
},
|
|
741
741
|
},
|