engine7 7.1.59 → 7.1.60

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 CHANGED
@@ -12272,8 +12272,14 @@ var init_my_eyes = __esm({
12272
12272
  return { content: "Error: my_eyes \u672A\u914D\u7F6E\u3002\u8BF7\u5728 config.tools.my_eyes.model \u8BBE\u7F6E\uFF08\u683C\u5F0F\uFF1Aprovider/model\uFF09\u3002", isError: true };
12273
12273
  }
12274
12274
  const slashIdx = modelRef.indexOf("/");
12275
+ const providerId = modelRef.slice(0, slashIdx);
12275
12276
  const modelId = modelRef.slice(slashIdx + 1);
12276
- const provider = ctx.provider;
12277
+ const providerCfg = (liveConfig.get("providers") || {})[providerId];
12278
+ if (!providerCfg) {
12279
+ return { content: `Error: tools.my_eyes.model \u7684 provider "${providerId}" \u4E0D\u5B58\u5728\u4E8E providers \u914D\u7F6E\u3002\u68C0\u67E5 config \u91CC models.providers.${providerId}\u3002`, isError: true };
12280
+ }
12281
+ const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_provider_factory(), provider_factory_exports));
12282
+ const provider = createProvider2(providerCfg);
12277
12283
  if (!provider?.streamChat) {
12278
12284
  return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
12279
12285
  }
@@ -12781,6 +12787,115 @@ async function wavToOggOpus(wavPath) {
12781
12787
  fs18.unlinkSync(wavPath);
12782
12788
  return oggPath;
12783
12789
  }
12790
+ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12791
+ const vc = liveConfig.get("tools.my_voice");
12792
+ let audioPath = "";
12793
+ let actualEngine = opts.engine || vc?.provider || "edge";
12794
+ try {
12795
+ if (actualEngine === "qwen3-3060" && vc?.url) {
12796
+ try {
12797
+ const { oggPath } = await ttsQwen3Opus(text, { url: vc.url, voice: vc.voice, lang: vc.lang });
12798
+ audioPath = oggPath;
12799
+ } catch (e) {
12800
+ console.warn(`[my-voice:multaca] qwen3 opus failed (${e.message}), trying PCM`);
12801
+ const pcmChunks = [];
12802
+ await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
12803
+ const pcm = Buffer.concat(pcmChunks);
12804
+ fs18.mkdirSync(VOICE_DIR, { recursive: true });
12805
+ const wavPath = path19.join(VOICE_DIR, `tts_mc_${Date.now()}.wav`);
12806
+ const header = Buffer.alloc(44);
12807
+ header.write("RIFF", 0);
12808
+ header.writeUInt32LE(36 + pcm.length, 4);
12809
+ header.write("WAVE", 8);
12810
+ header.write("fmt ", 12);
12811
+ header.writeUInt32LE(16, 16);
12812
+ header.writeUInt16LE(1, 20);
12813
+ header.writeUInt16LE(1, 22);
12814
+ header.writeUInt32LE(24e3, 24);
12815
+ header.writeUInt32LE(48e3, 28);
12816
+ header.writeUInt16LE(2, 32);
12817
+ header.writeUInt16LE(16, 34);
12818
+ header.write("data", 36);
12819
+ header.writeUInt32LE(pcm.length, 40);
12820
+ fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
12821
+ audioPath = wavPath;
12822
+ }
12823
+ } else if (actualEngine === "cosyvoice" && vc?.apiKey) {
12824
+ audioPath = await ttsCosyvoice(text, vc.apiKey, vc.model || "cosyvoice-v1", vc.voice, vc.workspaceId, vc.instruction);
12825
+ } else if (actualEngine === "gptsovits") {
12826
+ audioPath = await ttsGptsovits(text);
12827
+ } else {
12828
+ audioPath = await ttsEdge(text);
12829
+ actualEngine = "edge";
12830
+ }
12831
+ } catch (e) {
12832
+ return { content: `\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
12833
+ }
12834
+ if (!audioPath || !fs18.existsSync(audioPath)) {
12835
+ return { content: "\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1ATTS \u672A\u4EA7\u51FA\u6587\u4EF6\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002", isError: true };
12836
+ }
12837
+ if (audioPath.endsWith(".wav")) {
12838
+ try {
12839
+ audioPath = await wavToOggOpus(audioPath);
12840
+ } catch (e) {
12841
+ console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
12842
+ }
12843
+ }
12844
+ const ext = path19.extname(audioPath).toLowerCase();
12845
+ const sizeKB = fs18.statSync(audioPath).size / 1024;
12846
+ const voiceFile = `voice_${Date.now()}${ext}`;
12847
+ const cwdCopy = path19.join(process.cwd(), voiceFile);
12848
+ try {
12849
+ fs18.copyFileSync(audioPath, cwdCopy);
12850
+ } catch (e) {
12851
+ try {
12852
+ fs18.unlinkSync(audioPath);
12853
+ } catch {
12854
+ }
12855
+ return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
12856
+ }
12857
+ try {
12858
+ fs18.unlinkSync(audioPath);
12859
+ } catch {
12860
+ }
12861
+ const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
12862
+ try {
12863
+ const { execFile: execFile3 } = await import("node:child_process");
12864
+ const { promisify: promisify3 } = await import("node:util");
12865
+ const execFileA = promisify3(execFile3);
12866
+ const { stdout } = await execFileA("multica", [
12867
+ "issue",
12868
+ "comment",
12869
+ "add",
12870
+ issueId,
12871
+ "--content",
12872
+ content,
12873
+ "--attachment",
12874
+ voiceFile,
12875
+ "--output",
12876
+ "json"
12877
+ ], { timeout: 6e4 });
12878
+ let ok = false;
12879
+ try {
12880
+ const parsed = JSON.parse(stdout);
12881
+ ok = !!(parsed?.comment_id || parsed?.id || parsed?.attachments && parsed.attachments.length > 0);
12882
+ } catch {
12883
+ ok = stdout.includes("Comment added");
12884
+ }
12885
+ if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
12886
+ try {
12887
+ fs18.unlinkSync(cwdCopy);
12888
+ } catch {
12889
+ }
12890
+ return { content: `Voice sent to multaca issue ${issueId}! (${actualEngine}, ${sizeKB.toFixed(0)}KB, \u9644\u4EF6\u5DF2\u6302\u5230\u8BC4\u8BBA\u2014\u2014\u5728 multaca \u5BA2\u6237\u7AEF\u64AD\u653E)` };
12891
+ } catch (e) {
12892
+ try {
12893
+ fs18.unlinkSync(cwdCopy);
12894
+ } catch {
12895
+ }
12896
+ return { content: `\u8BED\u97F3\u6302\u5230 multaca issue \u5931\u8D25\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
12897
+ }
12898
+ }
12784
12899
  var execFileAsync, VOICE_DIR, _pyCache, GPTSOVITS_API, GPTSOVITS_REF_WAV, GPTSOVITS_REF_TEXT, GPTSOVITS_REF_LANG, EDGE_VOICE;
12785
12900
  var init_my_voice = __esm({
12786
12901
  "src/tools/my-voice.ts"() {
@@ -12806,7 +12921,8 @@ var init_my_voice = __esm({
12806
12921
  text: { type: "string", description: "What to say (Chinese text)." },
12807
12922
  engine: { type: "string", enum: ["cosyvoice", "gptsovits", "qwen3-3060", "edge"], description: "TTS engine. cosyvoice = \u767E\u70BCAPI (default if configured), gptsovits = local voice clone, qwen3-3060 = \u672C\u5730 GGML Q8_0 (3060), edge = backup." },
12808
12923
  channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
12809
- to: { type: "string", description: "Recipient ID. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\u3002\u4E0D\u786E\u5B9A\u5C31\u5148 read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002" },
12924
+ to: { type: "string", description: "Recipient ID. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\u3002\u4E0D\u786E\u5B9A\u5C31\u5148 read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\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" },
12925
+ 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' },
12810
12926
  caption: { type: "string", description: "Optional text to accompany the voice message." }
12811
12927
  },
12812
12928
  required: ["text"]
@@ -12817,7 +12933,17 @@ var init_my_voice = __esm({
12817
12933
  const requestedEngine = args.engine || "";
12818
12934
  const caption = args.caption || "";
12819
12935
  const mgr = ctx.channelManager;
12820
- if (!mgr) return { content: "\u53D1\u9001\u5931\u8D25: \u6CA1\u6709 ChannelManager", isError: true };
12936
+ if (!mgr) {
12937
+ const multicaTaskId = process.env.MULTICA_TASK_ID || "";
12938
+ const issueId = args.issueId || multicaTaskId;
12939
+ if (multicaTaskId && issueId) {
12940
+ return await sendVoiceToMulticaIssue(text, issueId, { engine: requestedEngine, caption });
12941
+ }
12942
+ return {
12943
+ content: "\u8BED\u97F3\u672A\u53D1\u9001\uFF1A\u5F53\u524D\u662F\u65E0\u6E20\u9053\u73AF\u5883\uFF08headless/CLI\uFF09\uFF0C\u4E14\u6CA1\u6709 multaca \u4EFB\u52A1\u4E0A\u4E0B\u6587\uFF08MULTICA_TASK_ID\uFF09\u6216 issueId\u3002\u6CA1\u6709\u53EF\u7528\u7684\u53D1\u9001\u51FA\u53E3\uFF0C\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002",
12944
+ isError: true
12945
+ };
12946
+ }
12821
12947
  const resolvedChannelRaw = args.channel || (ctx.channel === "deskBuddy" ? "feishu" : ctx.channel) || "feishu";
12822
12948
  const resolvedChannel = resolvedChannelRaw === "weixin" ? "wechat" : resolvedChannelRaw;
12823
12949
  let target = args.to || ctx.channelTarget || ctx.from;
@@ -19566,6 +19692,7 @@ function parseCcRunArgs(argv) {
19566
19692
  verbose: false,
19567
19693
  sessionId: "",
19568
19694
  maxTurns: void 0,
19695
+ noRecall: false,
19569
19696
  stateDir: "",
19570
19697
  configName: "",
19571
19698
  agentName: ""
@@ -19600,6 +19727,8 @@ function parseCcRunArgs(argv) {
19600
19727
  args.sessionId = takeValue();
19601
19728
  } else if (a === "--max-turns") {
19602
19729
  args.maxTurns = parseInt(takeValue(), 10) || void 0;
19730
+ } else if (a === "--no-recall") {
19731
+ args.noRecall = true;
19603
19732
  } else if (a === "--state-dir") {
19604
19733
  args.stateDir = takeValue().trim();
19605
19734
  } else if (a === "--config") {
@@ -19739,6 +19868,8 @@ async function runQuery(args) {
19739
19868
  await Promise.resolve().then(() => (init_tools_bundle(), tools_bundle_exports));
19740
19869
  const { registry: registry2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
19741
19870
  registry2.config = config;
19871
+ const { liveConfig: liveConfig2 } = await Promise.resolve().then(() => (init_live(), live_exports));
19872
+ liveConfig2.init(config);
19742
19873
  const { handleQuery: handleQuery2 } = await Promise.resolve().then(() => (init_handle_query(), handle_query_exports));
19743
19874
  const deps = {
19744
19875
  engine,
@@ -19777,8 +19908,8 @@ async function runQuery(args) {
19777
19908
  // channelTarget
19778
19909
  void 0,
19779
19910
  // inboundMeta
19780
- void 0,
19781
- // skipRecall
19911
+ args.noRecall || /quick-create assistant/i.test(args.prompt),
19912
+ // skipRecall(--no-recall 或建单任务自动跳过:daemon 拼的 quick-create prompt 是机械转述,recall sideQuery 在子进程里拖 30-65s)
19782
19913
  "cc-run"
19783
19914
  // source
19784
19915
  );