engine7 7.1.119 → 7.1.120
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/cli.mjs +48 -19
- package/dist/engine-startup.mjs +302 -235
- package/dist/main.mjs +302 -235
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -395,6 +395,17 @@ var init_live = __esm({
|
|
|
395
395
|
Object.assign(this.current, newConfig);
|
|
396
396
|
}
|
|
397
397
|
/** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
|
|
398
|
+
/**
|
|
399
|
+
* 改活树 + 落盘。
|
|
400
|
+
*
|
|
401
|
+
* 返回值 = **落盘**是否成功(活树无论成败都已同步——它是先改的)。绝大多数调用点照旧
|
|
402
|
+
* `void liveConfig.set(...)` 不理它;但**要打成功日志的调用点必须 await 这个布尔值**。
|
|
403
|
+
*
|
|
404
|
+
* 为什么把这个信号交出去(1001 审查捞回):本方法本来是 fire-and-forget,落盘失败只在
|
|
405
|
+
* `persistToFile` 里 warn 一行;而启动早段的调用点(两个免费档 fixup)紧接着打了句
|
|
406
|
+
* "免费档补齐 xxx" 的成功日志 ⇒ 配置**没写进文件**却被读成"写好了":进程内生效、托盘
|
|
407
|
+
* 读文件还是旧值、下次启动重放同一句——正是本仓最恨的假信号。
|
|
408
|
+
*/
|
|
398
409
|
async set(dotPath, val) {
|
|
399
410
|
if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
400
411
|
const keys = dotPath.split(".");
|
|
@@ -404,15 +415,15 @@ var init_live = __esm({
|
|
|
404
415
|
obj = obj[keys[i]];
|
|
405
416
|
}
|
|
406
417
|
obj[keys[keys.length - 1]] = val;
|
|
407
|
-
|
|
418
|
+
return this.persistToFile(dotPath, val);
|
|
408
419
|
}
|
|
409
|
-
/** 把改动写回 config
|
|
420
|
+
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效)。返回是否真的落盘。 */
|
|
410
421
|
async persistToFile(dotPath, val) {
|
|
411
422
|
const fs44 = await import("node:fs");
|
|
412
423
|
const cfgPath = this.current?._configFilePath;
|
|
413
424
|
if (!cfgPath || !fs44.existsSync(cfgPath)) {
|
|
414
425
|
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
415
|
-
return;
|
|
426
|
+
return false;
|
|
416
427
|
}
|
|
417
428
|
try {
|
|
418
429
|
const raw = JSON.parse(fs44.readFileSync(cfgPath, "utf-8"));
|
|
@@ -426,8 +437,10 @@ var init_live = __esm({
|
|
|
426
437
|
fs44.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
427
438
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
428
439
|
markSelfWrite();
|
|
440
|
+
return true;
|
|
429
441
|
} catch (e) {
|
|
430
442
|
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
443
|
+
return false;
|
|
431
444
|
}
|
|
432
445
|
}
|
|
433
446
|
/** 是否已初始化 */
|
|
@@ -1549,6 +1562,16 @@ function secretRef(envKey, value) {
|
|
|
1549
1562
|
function isFreeTier(v) {
|
|
1550
1563
|
return v.freeTier === true || v.primaryProvider === "7yi";
|
|
1551
1564
|
}
|
|
1565
|
+
function freeTierVoiceConfig(existing) {
|
|
1566
|
+
const mv = existing && typeof existing === "object" ? existing : {};
|
|
1567
|
+
return {
|
|
1568
|
+
...mv,
|
|
1569
|
+
provider: "relay",
|
|
1570
|
+
relayProviderId: FREE_TIER_PROVIDER_ID,
|
|
1571
|
+
relayModel: "engine7-tts",
|
|
1572
|
+
voice: mv.voice || DEFAULT_FREE_VOICE
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1552
1575
|
function resolveRelayUrl(relayArg, env = process.env) {
|
|
1553
1576
|
return (relayArg || "").trim() || (env.E7_RELAY_URL || "").trim() || FREE_TIER_RELAY_URL;
|
|
1554
1577
|
}
|
|
@@ -1612,9 +1635,21 @@ function generateConfig(v) {
|
|
|
1612
1635
|
},
|
|
1613
1636
|
// 0917:my_eyes(看图工具)读的是 tools.my_eyes.model,不是 tools.vision——
|
|
1614
1637
|
// 后者是模板里遗留的死键(全仓零读者),已删。visionModel 解析不出就不写这个块。
|
|
1638
|
+
//
|
|
1639
|
+
// 1001 发语音条(§7.4):免费档必须把这块写全。此前唯一会写 `tools.my_voice` 的是
|
|
1640
|
+
// `applyFreeTier`,而它只从「切换到免费档」那张卡触发——配置已经是免费档时卡片不显示
|
|
1641
|
+
// ⇒ **新装机永远没有这块**:托盘「合成引擎」显示 edge-tts(面板在 provider 缺失时
|
|
1642
|
+
// 默认选它),引擎 `pickProvider` 也落 edge,而 edge 要本机 Python + `edge_tts`
|
|
1643
|
+
// (安装包一个都不带)⇒ 用户第一次说"发条语音"就报错。郭叔 1001 装机实测撞到。
|
|
1644
|
+
// 形状走 `freeTierVoiceConfig()`(唯一源,与 applyFreeTier / 启动补齐同一份)。
|
|
1615
1645
|
tools: {
|
|
1616
1646
|
...v.tavilyKey ? { tavily: { apiKey: v.tavilyKey } } : {},
|
|
1617
1647
|
...v.visionModel ? { my_eyes: { model: v.visionModel } } : {},
|
|
1648
|
+
// ⚠️ 判据是 **provider 真的是 7yi**,不是 `isFreeTier(v)`:后者会因 `freeTier:true`
|
|
1649
|
+
// 单独为真(answers 手写坏组合时),而那种 config 里**根本没有 7yi provider 块**,
|
|
1650
|
+
// 写进去就是个悬空引用(第一次发语音报"免费池未配置",把用户指向错误的排查方向)。
|
|
1651
|
+
// 与下面 vision/video 的收口闸同一条纪律:**引用必须落在本次真实写出的 provider 里**。
|
|
1652
|
+
...v.primaryProvider === FREE_TIER_PROVIDER_ID ? { my_voice: freeTierVoiceConfig() } : {},
|
|
1618
1653
|
// 自拍(§4.3):免费档必须显式写 provider:'relay'。不写的话 getProvider()
|
|
1619
1654
|
// 会落回默认值 'fal',而免费装机没有 fal key——第一次自拍就失败。
|
|
1620
1655
|
// 非免费档只在用户真给了形象时才写这个块,且不替他决定 provider。
|
|
@@ -1837,13 +1872,15 @@ function generateConfig(v) {
|
|
|
1837
1872
|
}
|
|
1838
1873
|
return config;
|
|
1839
1874
|
}
|
|
1840
|
-
var SCHEMA_VERSION, FREE_TIER_RELAY_URL, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
|
|
1875
|
+
var SCHEMA_VERSION, FREE_TIER_RELAY_URL, FREE_TIER_PROVIDER_ID, DEFAULT_FREE_VOICE, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
|
|
1841
1876
|
var init_cli_init_config = __esm({
|
|
1842
1877
|
"src/cli-init-config.ts"() {
|
|
1843
1878
|
"use strict";
|
|
1844
1879
|
init_registry();
|
|
1845
1880
|
SCHEMA_VERSION = 1;
|
|
1846
1881
|
FREE_TIER_RELAY_URL = "https://www.twinsun.top:8866";
|
|
1882
|
+
FREE_TIER_PROVIDER_ID = "7yi";
|
|
1883
|
+
DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
|
|
1847
1884
|
DEFAULT_PRIMARY_MODEL = {
|
|
1848
1885
|
dashscope: "dashscope/qwen3.8-max",
|
|
1849
1886
|
minimax: "minimax/MiniMax-M3",
|
|
@@ -15575,7 +15612,7 @@ var init_providers = __esm({
|
|
|
15575
15612
|
if (r.warning) console.warn(`[my-voice] ${r.warning}`);
|
|
15576
15613
|
if (!r.voice) {
|
|
15577
15614
|
throw new TtsConfigError(
|
|
15578
|
-
"relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\
|
|
15615
|
+
"relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\u81EA\u52A8\u586B\u597D\u9ED8\u8BA4\u97F3\u8272\uFF08\u65B0\u88C5\u673A generateConfig / \u8001\u88C5\u673A\u542F\u52A8\u8865\u9F50 / \u5207\u6362\u514D\u8D39\u6863 applyFreeTier \u4E09\u6761\u8DEF\uFF0C\u89C1 cli-init-config.ts \u7684 freeTierVoiceConfig\uFF09\u3002"
|
|
15579
15616
|
);
|
|
15580
15617
|
}
|
|
15581
15618
|
try {
|
|
@@ -15824,7 +15861,7 @@ var init_my_voice = __esm({
|
|
|
15824
15861
|
description: "TTS engine. relay = 7yi \u4E2D\u8F6C\u7AD9\uFF08\u514D\u8D39\u6863\u9ED8\u8BA4\uFF09\uFF0Ccosyvoice = \u767E\u70BC API\uFF0Cgptsovits = \u672C\u5730\u514B\u9686\uFF0Cqwen3-3060 = \u672C\u5730 GGML\uFF0Cedge = \u515C\u5E95\u3002"
|
|
15825
15862
|
},
|
|
15826
15863
|
channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
|
|
15827
|
-
to: { type: "string", description:
|
|
15864
|
+
to: { type: "string", description: 'Recipient ID, ONLY when sending to someone else. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\uFF1B\u53D1\u7ED9\u522B\u4EBA\u524D read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002**\u53D1\u7ED9\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA\uFF08"\u53D1\u7ED9\u6211/\u53D1\u6761\u8BED\u97F3"\uFF09\u4E0D\u8981\u586B to**\u2014\u2014\u7559\u7A7A\u5373\u53D1\u5F53\u524D\u4F1A\u8BDD\uFF0C\u8FD9\u662F\u9ED8\u8BA4\u4E5F\u662F\u66F4\u7A33\u7684\u8DEF\uFF08\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF0C\u89C1 1001 \u6848\u4F8B\uFF09\u3002multaca \u4EFB\u52A1\u91CC\u4E0D\u9700\u8981\u586B to\u2014\u2014\u8BED\u97F3\u4F1A\u6302\u5230\u5F53\u524D issue \u8BC4\u8BBA\uFF0C\u586B issueId \u6307\u5B9A\u76EE\u6807 issue\u3002' },
|
|
15828
15865
|
issueId: { type: "string", description: 'multaca headless \u4E13\u7528\uFF1A\u76EE\u6807 issue ID\uFF08\u4EFB\u52A1 prompt \u91CC\u7684 "Your assigned issue ID"\uFF09\u3002\u666E\u901A\u98DE\u4E66/\u5FAE\u4FE1\u573A\u666F\u4E0D\u8981\u586B\u3002' },
|
|
15829
15866
|
caption: { type: "string", description: "Optional text to accompany the voice message." }
|
|
15830
15867
|
},
|
|
@@ -15936,7 +15973,8 @@ var init_my_voice = __esm({
|
|
|
15936
15973
|
}
|
|
15937
15974
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
15938
15975
|
} catch (err) {
|
|
15939
|
-
|
|
15976
|
+
const toHint = args.to ? '\u3002\u26A0\uFE0F \u8FD9\u6B21\u5E26\u7684\u662F to=\u6536\u4EF6\u4EBA ID\uFF1A\u82E5\u6536\u4EF6\u4EBA\u5C31\u662F**\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA**\uFF0C\u53BB\u6389 to \u91CD\u8BD5\u2014\u2014\u5F15\u64CE\u4F1A\u53D1\u7ED9\u5F53\u524D\u4F1A\u8BDD\uFF0C\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF08\u98DE\u4E66 230101\uFF09' : "";
|
|
15977
|
+
return { content: `Voice send failed: ${err.message}${toHint}`, isError: true };
|
|
15940
15978
|
}
|
|
15941
15979
|
},
|
|
15942
15980
|
isConcurrencySafe: () => false,
|
|
@@ -29835,15 +29873,7 @@ function applyFreeTier(cfg, opts = {}) {
|
|
|
29835
29873
|
const mv = cfg.tools.my_voice || null;
|
|
29836
29874
|
const existingProvider = typeof mv?.provider === "string" ? mv.provider : "";
|
|
29837
29875
|
if (!mv || existingProvider === "relay") {
|
|
29838
|
-
cfg.tools.my_voice =
|
|
29839
|
-
...mv || {},
|
|
29840
|
-
provider: "relay",
|
|
29841
|
-
relayProviderId: FREE_TIER_PROVIDER_ID,
|
|
29842
|
-
// '7yi'
|
|
29843
|
-
relayModel: "engine7-tts",
|
|
29844
|
-
// 有块就不夺 ⇒ 走到这里时 mv 要么不存在、要么 voice 就是 relay 的;非 relay 的块已跳过
|
|
29845
|
-
voice: mv?.voice || DEFAULT_FREE_VOICE
|
|
29846
|
-
};
|
|
29876
|
+
cfg.tools.my_voice = freeTierVoiceConfig(mv);
|
|
29847
29877
|
}
|
|
29848
29878
|
return cfg;
|
|
29849
29879
|
}
|
|
@@ -29889,15 +29919,14 @@ function applyFreeTierToConfig(configPath, opts = {}) {
|
|
|
29889
29919
|
video: cfg.agents.defaults.model.video ?? null
|
|
29890
29920
|
};
|
|
29891
29921
|
}
|
|
29892
|
-
var
|
|
29922
|
+
var FREE_TIER_PRIMARY;
|
|
29893
29923
|
var init_free_tier_apply = __esm({
|
|
29894
29924
|
"src/free-tier-apply.ts"() {
|
|
29895
29925
|
"use strict";
|
|
29896
29926
|
init_cli_init_config();
|
|
29897
29927
|
init_provision_free();
|
|
29898
|
-
|
|
29928
|
+
init_cli_init_config();
|
|
29899
29929
|
FREE_TIER_PRIMARY = "7yi/engine7-free";
|
|
29900
|
-
DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
|
|
29901
29930
|
}
|
|
29902
29931
|
});
|
|
29903
29932
|
|