lookatstudy-mobile 0.31.8 → 0.33.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.
Files changed (134) hide show
  1. package/package.json +1 -1
  2. package/server.cjs +270 -130
  3. package/web/assets/{CanvasStage-CmtH-mbw.js → CanvasStage-CaFu-HaO.js} +1 -1
  4. package/web/assets/{CommandPalette-DUmqE72K.js → CommandPalette-BPSWW32h.js} +1 -1
  5. package/web/assets/{CourseSearchPanel-3-HAQF8k.js → CourseSearchPanel-CfyFDrU0.js} +1 -1
  6. package/web/assets/{ExamView-Bicz9rKK.js → ExamView-DpO-T-FU.js} +1 -1
  7. package/web/assets/{ReviewPanel-D_uuegad.js → ReviewPanel-BWsENArl.js} +1 -1
  8. package/web/assets/{SettingsView-BGcc_gyc.js → SettingsView-Dlb3-wms.js} +2 -2
  9. package/web/assets/{VoicePanel-BcJ0p1uZ.js → VoicePanel-D-9fJp6L.js} +1 -1
  10. package/web/assets/{abnfDiagram-VCTEODGH-ODA7YWAP-CgLsazU5.js → abnfDiagram-VCTEODGH-ODA7YWAP-CONl7hDv.js} +1 -1
  11. package/web/assets/{abnfDiagram-VCTEODGH-BQPjZWFz.js → abnfDiagram-VCTEODGH-zkSafbw8.js} +1 -1
  12. package/web/assets/{architectureDiagram-5GKGNRK7-DnhDmsUm.js → architectureDiagram-5GKGNRK7-BTcz7RyQ.js} +1 -1
  13. package/web/assets/{architectureDiagram-5GKGNRK7-C4PU3XN7-CisfWjkP.js → architectureDiagram-5GKGNRK7-C4PU3XN7-DMWuKYkU.js} +1 -1
  14. package/web/assets/{arrow-right-D1P_tI28.js → arrow-right-COMYZ1fA.js} +1 -1
  15. package/web/assets/{blockDiagram-I7D4REHJ-83IkxDza.js → blockDiagram-I7D4REHJ-B63IaFUV.js} +1 -1
  16. package/web/assets/{blockDiagram-NRAW4CY4-UMJ6PMQQ-CH_Oenby.js → blockDiagram-NRAW4CY4-UMJ6PMQQ-CIAE11Pm.js} +1 -1
  17. package/web/assets/{c4Diagram-7LVT6UL2-o3zPt7D8.js → c4Diagram-7LVT6UL2-BwajFuZF.js} +1 -1
  18. package/web/assets/{c4Diagram-UCG6FXSJ-75X3U2P3-BE9I4UiJ.js → c4Diagram-UCG6FXSJ-75X3U2P3-CQ2Qp_c1.js} +1 -1
  19. package/web/assets/channel-Daa-iwE6.js +1 -0
  20. package/web/assets/{chunk-2Q5K7J3B-HP7HQB9K.js → chunk-2Q5K7J3B-hrIKE0Kh.js} +1 -1
  21. package/web/assets/{chunk-5VM5RSS4-ljP2dFgU.js → chunk-5VM5RSS4-nWuT_8NP.js} +1 -1
  22. package/web/assets/{chunk-7XDTSPCN-DAnvw--2.js → chunk-7XDTSPCN-DaOQXXh6.js} +1 -1
  23. package/web/assets/{chunk-CTNIYPP6-CwyFNhT9.js → chunk-CTNIYPP6-B2__YmBS.js} +1 -1
  24. package/web/assets/{chunk-CXNFBKHE-Ca0kybi8.js → chunk-CXNFBKHE-CmQMLQWw.js} +1 -1
  25. package/web/assets/{chunk-F27PBJKO-BB-X0SRn.js → chunk-F27PBJKO-zHBM_1uo.js} +1 -1
  26. package/web/assets/{chunk-IMKFNOWR-TO2LpOwJ.js → chunk-IMKFNOWR-DTwQZApD.js} +1 -1
  27. package/web/assets/{chunk-ISA7TJRJ-KaruUw1r.js → chunk-ISA7TJRJ-C_jhI1TS.js} +1 -1
  28. package/web/assets/{chunk-JWPE2WC7-BvW1vu0A.js → chunk-JWPE2WC7-Dx6T5lv2.js} +1 -1
  29. package/web/assets/{chunk-LV3HUYFY-C4qp41yC.js → chunk-LV3HUYFY--L9ggqz-.js} +1 -1
  30. package/web/assets/{chunk-M3IUQBOH-FnRpFVPN.js → chunk-M3IUQBOH-OFj5uQc-.js} +1 -1
  31. package/web/assets/{chunk-NDIOYS4C-BBjAdP34.js → chunk-NDIOYS4C-BaCZBdfD.js} +1 -1
  32. package/web/assets/{chunk-POPQ4Y6H-BwMRZsoa.js → chunk-POPQ4Y6H-CpiIve5m.js} +1 -1
  33. package/web/assets/{chunk-RE4WF27V-eSOho_BF.js → chunk-RE4WF27V-DMiY8mvU.js} +1 -1
  34. package/web/assets/{chunk-SVP7TREG-Bkn5RRJ4.js → chunk-SVP7TREG-BgA7U0O5.js} +1 -1
  35. package/web/assets/{chunk-TICWLB2K-PSw0ashI.js → chunk-TICWLB2K-BhfM6aa6.js} +1 -1
  36. package/web/assets/{chunk-VII2H2IX-DqlE5Xbz.js → chunk-VII2H2IX-D97vmfRp.js} +1 -1
  37. package/web/assets/{chunk-X5GNSKZ3-BN7Cc4Mi.js → chunk-X5GNSKZ3-Duc5cfce.js} +1 -1
  38. package/web/assets/{chunk-XCWWM2C3-BRFBRsfc.js → chunk-XCWWM2C3-cz_1pt_w.js} +1 -1
  39. package/web/assets/{chunk-XXDRQBXY-CEKM89fL.js → chunk-XXDRQBXY-dbgIls1a.js} +1 -1
  40. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-B0cf41QA.js +1 -0
  41. package/web/assets/classDiagram-ZZMXUADV-BCEbKtzF.js +1 -0
  42. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-B0cf41QA.js +1 -0
  43. package/web/assets/classDiagram-v2-VYDZK3BY-BCEbKtzF.js +1 -0
  44. package/web/assets/{core-CZEHsvvz.js → core-B40QXYe5.js} +1 -1
  45. package/web/assets/{cose-bilkent-JH36ORCC-D579Qukk.js → cose-bilkent-JH36ORCC-Ce0oIg81.js} +1 -1
  46. package/web/assets/{cose-bilkent-JH36ORCC-OB24KH3T-CWEUO9HU.js → cose-bilkent-JH36ORCC-OB24KH3T-CN3uo8CD.js} +1 -1
  47. package/web/assets/{cynefin-OW5HDTMX-C4i_PqN4.js → cynefin-OW5HDTMX-D283bZaS.js} +1 -1
  48. package/web/assets/{cynefin-OW5HDTMX-GVF3BKWE-B4Zq08WU.js → cynefin-OW5HDTMX-GVF3BKWE-blsoPqhC.js} +1 -1
  49. package/web/assets/{cynefinDiagram-5FMLGOSQ-cNCP-cfB.js → cynefinDiagram-5FMLGOSQ-Dk3rgOe4.js} +1 -1
  50. package/web/assets/{cynefinDiagram-5FMLGOSQ-H3WIRU3N-C28pB-YN.js → cynefinDiagram-5FMLGOSQ-H3WIRU3N-DnTy2Qp1.js} +1 -1
  51. package/web/assets/{dagre-3AP2YEHR-DCERTXHT-CdouCY5m.js → dagre-3AP2YEHR-DCERTXHT-YyKk2Eje.js} +1 -1
  52. package/web/assets/{dagre-GXQ25YYZ-Ctx7xXqC.js → dagre-GXQ25YYZ-C4wVVN3x.js} +1 -1
  53. package/web/assets/{diagram-S7CK7UJ4-DWIMTLIt.js → diagram-S7CK7UJ4-Bl_tuPkt.js} +1 -1
  54. package/web/assets/{diagram-S7CK7UJ4-MULGZGEL-DF3SiCMB.js → diagram-S7CK7UJ4-MULGZGEL-RsN96cLG.js} +1 -1
  55. package/web/assets/{diagram-UQ7AKVKN-CkFzc0Wk.js → diagram-UQ7AKVKN-CDq4dP0x.js} +1 -1
  56. package/web/assets/{diagram-UQ7AKVKN-YQBY353J-B4zrXVTC.js → diagram-UQ7AKVKN-YQBY353J-CnONTOO_.js} +1 -1
  57. package/web/assets/{diagram-VSXAHHWV-QR1SVd14.js → diagram-VSXAHHWV-KXVyLIQF.js} +1 -1
  58. package/web/assets/{diagram-VSXAHHWV-WLNH2ELY-CTJy_AbP.js → diagram-VSXAHHWV-WLNH2ELY-BiT9bonG.js} +1 -1
  59. package/web/assets/{diagram-VX7I27RA-XW6YQV5G-V9WvfXDt.js → diagram-VX7I27RA-XW6YQV5G-CM2-RHcs.js} +1 -1
  60. package/web/assets/{diagram-VX7I27RA-D1gH9GfG.js → diagram-VX7I27RA-w44lGlag.js} +1 -1
  61. package/web/assets/{diagram-Z3DM3KII-CAXOio_U.js → diagram-Z3DM3KII-Dk9pGU7a.js} +1 -1
  62. package/web/assets/{diagram-Z3DM3KII-HG7RF65D-4bZaGG4C.js → diagram-Z3DM3KII-HG7RF65D-NDekrIV6.js} +1 -1
  63. package/web/assets/{ebnfDiagram-PWID7BFC-OKY4VHYD-0MAzrs3J.js → ebnfDiagram-PWID7BFC-OKY4VHYD-D3U0p9Dw.js} +1 -1
  64. package/web/assets/{ebnfDiagram-PWID7BFC-DKEIx1fH.js → ebnfDiagram-PWID7BFC-QL78PgDI.js} +1 -1
  65. package/web/assets/{erDiagram-RLTQ6QDP-PAe9jFM5.js → erDiagram-RLTQ6QDP-BsC71zHF.js} +1 -1
  66. package/web/assets/{erDiagram-SSCWMZ5O-PIPKOIK7-Q240Gd2f.js → erDiagram-SSCWMZ5O-PIPKOIK7-CEQ1fj11.js} +1 -1
  67. package/web/assets/{flowDiagram-A5DVABFB-2Z4AVO5R-BBoqYx4U.js → flowDiagram-A5DVABFB-2Z4AVO5R-CeEDePYs.js} +1 -1
  68. package/web/assets/{flowDiagram-HODETNUW-CaYb_bpF.js → flowDiagram-HODETNUW-j9xJY7Cn.js} +1 -1
  69. package/web/assets/{ganttDiagram-EL5Y4UJY-JZNG7GOG-s7gZuKXt.js → ganttDiagram-EL5Y4UJY-JZNG7GOG-BP55ilH-.js} +1 -1
  70. package/web/assets/{ganttDiagram-EL5Y4UJY-DoBHn__J.js → ganttDiagram-EL5Y4UJY-uJxSumZ8.js} +1 -1
  71. package/web/assets/{gitGraphDiagram-WWUBYQGX-DMWMLL3G-CwDSrNDV.js → gitGraphDiagram-WWUBYQGX-DMWMLL3G-CNDUB39t.js} +1 -1
  72. package/web/assets/{gitGraphDiagram-WWUBYQGX-BhhYj-JV.js → gitGraphDiagram-WWUBYQGX-DVI1ESQd.js} +1 -1
  73. package/web/assets/{index-AJUn0HO2.js → index-BCpaGgFy.js} +1 -1
  74. package/web/assets/{index-C71uzKGb.js → index-DrY2EFcb.js} +1 -1
  75. package/web/assets/{index-BqzFb37p.js → index-_UR-NqZ3.js} +3 -3
  76. package/web/assets/{infoDiagram-27XIBGKW-DKEb7t-E.js → infoDiagram-27XIBGKW-CkW-sNO8.js} +1 -1
  77. package/web/assets/{infoDiagram-RXCK75RN-HANS5KVC-CAhHD8Zx.js → infoDiagram-RXCK75RN-HANS5KVC-dTP_Odo6.js} +1 -1
  78. package/web/assets/{ishikawaDiagram-5VMMS53U-7GCIT7WU-kYI0Svj2.js → ishikawaDiagram-5VMMS53U-7GCIT7WU-CpugNdNM.js} +1 -1
  79. package/web/assets/{ishikawaDiagram-5VMMS53U-KwkM0a8C.js → ishikawaDiagram-5VMMS53U-Q4eOk7i4.js} +1 -1
  80. package/web/assets/{journeyDiagram-3NMN7TZE-CtMQfk5A.js → journeyDiagram-3NMN7TZE-Dxj1sa_P.js} +1 -1
  81. package/web/assets/{journeyDiagram-EYS64GPL-OAPELBT7-C2b8Qct7.js → journeyDiagram-EYS64GPL-OAPELBT7-DTtloFWb.js} +1 -1
  82. package/web/assets/{kanban-definition-3QL26DDD-I7RKWQQY-DQ6fffBv.js → kanban-definition-3QL26DDD-I7RKWQQY-DNUfp8js.js} +1 -1
  83. package/web/assets/{kanban-definition-UXKFOSKX-D-ZouSUt.js → kanban-definition-UXKFOSKX-lN88B3xx.js} +1 -1
  84. package/web/assets/{katex-N6JRN4PM-CvNS8psm.js → katex-N6JRN4PM-lNEBPo7H.js} +1 -1
  85. package/web/assets/{layout-5k30qfxq.js → layout-DbydpuQY.js} +1 -1
  86. package/web/assets/{main-DN7XAao0.js → main-DGGbnUfo.js} +6 -6
  87. package/web/assets/{mermaid-layout-elk.core-gJBBkIZ-.js → mermaid-layout-elk.core-DiLPr9HM.js} +2 -2
  88. package/web/assets/{mermaid.core-B0xYKBVE.js → mermaid.core-D7fD1FwK.js} +5 -5
  89. package/web/assets/{mindmap-definition-FBJOCRG2-KIYZG64Y-p1ZYgvAP.js → mindmap-definition-FBJOCRG2-KIYZG64Y-BOFqPKDa.js} +1 -1
  90. package/web/assets/{mindmap-definition-YA3MSWOX-0ofFOH6e.js → mindmap-definition-YA3MSWOX-CATiDuGI.js} +1 -1
  91. package/web/assets/{pegDiagram-XKGWAZYB-Bve3ufMO.js → pegDiagram-XKGWAZYB-Bp1tCSY-.js} +1 -1
  92. package/web/assets/{pegDiagram-XKGWAZYB-OIP57N6J-Dgul-x8l.js → pegDiagram-XKGWAZYB-OIP57N6J-DlQB65ue.js} +1 -1
  93. package/web/assets/{pieDiagram-E7YTZNPT-2UOTW327-BNXTtM-8.js → pieDiagram-E7YTZNPT-2UOTW327-C_8F2EM1.js} +1 -1
  94. package/web/assets/{pieDiagram-E7YTZNPT-B7EiiDGT.js → pieDiagram-E7YTZNPT-CrDGrlAd.js} +1 -1
  95. package/web/assets/{quadrantDiagram-AXDQQJYC-Db9803af.js → quadrantDiagram-AXDQQJYC-Dr7W78wK.js} +1 -1
  96. package/web/assets/{quadrantDiagram-AXDQQJYC-SN3ASJJK-yzspgYAb.js → quadrantDiagram-AXDQQJYC-SN3ASJJK-C39aRWD3.js} +1 -1
  97. package/web/assets/{railroadDiagram-O6MQD6OU-34742W6X-Vb3jhFnN.js → railroadDiagram-O6MQD6OU-34742W6X-CjrAplDr.js} +1 -1
  98. package/web/assets/{railroadDiagram-O6MQD6OU-CnAROgoQ.js → railroadDiagram-O6MQD6OU-CXiZMLyn.js} +1 -1
  99. package/web/assets/{render-O7CIS3YK-BPgUWeds.js → render-O7CIS3YK-CZ3IDVwW.js} +7 -7
  100. package/web/assets/{requirementDiagram-BXWQKSXE-8faD_xLf.js → requirementDiagram-BXWQKSXE-C2qycPSr.js} +1 -1
  101. package/web/assets/{requirementDiagram-EFPCY7ZU-NGAFFSMB-C_yLtE0T.js → requirementDiagram-EFPCY7ZU-NGAFFSMB-DHlqxJGG.js} +1 -1
  102. package/web/assets/{rotate-ccw-C_Y1XSKQ.js → rotate-ccw-Cca2hxMT.js} +1 -1
  103. package/web/assets/{sankeyDiagram-P5KCCOFB-3D3M4XPB-DK22ici_.js → sankeyDiagram-P5KCCOFB-3D3M4XPB-AsThg1OY.js} +1 -1
  104. package/web/assets/{sankeyDiagram-P5KCCOFB-BVvhQQLS.js → sankeyDiagram-P5KCCOFB-vMRJfraP.js} +1 -1
  105. package/web/assets/{sequenceDiagram-WJ2MYXX4-Dnnu7jW_.js → sequenceDiagram-WJ2MYXX4-DXz4qAcJ.js} +1 -1
  106. package/web/assets/{sequenceDiagram-WJ2MYXX4-Q2IOPB4R-DRoza_p9.js → sequenceDiagram-WJ2MYXX4-Q2IOPB4R-O-Lrk2oI.js} +1 -1
  107. package/web/assets/{sizeCapture-INFHLROL-C2UzO0Rg.js → sizeCapture-INFHLROL-DoMzpXxN.js} +1 -1
  108. package/web/assets/{sizeCapture-X5ZJPWSS-PSGVOMYM-MWOck30Y.js → sizeCapture-X5ZJPWSS-PSGVOMYM-CGWX8Jny.js} +1 -1
  109. package/web/assets/{stateDiagram-D77RDMKH-BVIVX5nP.js → stateDiagram-D77RDMKH-aoa5ZmSB.js} +1 -1
  110. package/web/assets/{stateDiagram-HBIQ2CUA-4M2S6MAN-J76hZP7n.js → stateDiagram-HBIQ2CUA-4M2S6MAN-BsvWo7X8.js} +1 -1
  111. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-BSX-RFNn.js +1 -0
  112. package/web/assets/stateDiagram-v2-MP3YSRHH-DiN5JuuU.js +1 -0
  113. package/web/assets/{swimlanes-42K2YHIH-Bn9vLZix.js → swimlanes-42K2YHIH-Dz4OR5iQ.js} +1 -1
  114. package/web/assets/{swimlanes-XN3QIQJK-N6N2CCQ6-Cb2pT1cn.js → swimlanes-XN3QIQJK-N6N2CCQ6-DVIJq7Pa.js} +1 -1
  115. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-fcmr0ac0.js +8 -0
  116. package/web/assets/swimlanesDiagram-VR7AAH4N-C_q81JGw.js +8 -0
  117. package/web/assets/{timeline-definition-24CTP7MA-KN7RSRVM-CR5emk9g.js → timeline-definition-24CTP7MA-KN7RSRVM-U2gzdSo-.js} +1 -1
  118. package/web/assets/{timeline-definition-24CTP7MA-CdqRB00q.js → timeline-definition-24CTP7MA-VTB2LyFw.js} +1 -1
  119. package/web/assets/{vennDiagram-4TSXK5OY-AKJ7LXAN-CniQ996Z.js → vennDiagram-4TSXK5OY-AKJ7LXAN-DtdtRly6.js} +1 -1
  120. package/web/assets/{vennDiagram-4TSXK5OY-Kfn75Zy6.js → vennDiagram-4TSXK5OY-BC1R0pU_.js} +1 -1
  121. package/web/assets/{wardleyDiagram-VM6X3IG4-3B6A3BN5-BtkV5bQm.js → wardleyDiagram-VM6X3IG4-3B6A3BN5-BgacOfmW.js} +1 -1
  122. package/web/assets/{wardleyDiagram-VM6X3IG4-C5PoKUwU.js → wardleyDiagram-VM6X3IG4-DmMxrWiy.js} +1 -1
  123. package/web/assets/{xychartDiagram-S5SC5T6Z-CpVEqSP1.js → xychartDiagram-S5SC5T6Z-B3ColLAu.js} +1 -1
  124. package/web/assets/{xychartDiagram-S5SC5T6Z-OBDNV6WG-tHDy9evm.js → xychartDiagram-S5SC5T6Z-OBDNV6WG-DEomTVra.js} +1 -1
  125. package/web/index.html +1 -1
  126. package/web/assets/channel-BhvVFhTx.js +0 -1
  127. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-CJqUE9P6.js +0 -1
  128. package/web/assets/classDiagram-ZZMXUADV-woPJRnPi.js +0 -1
  129. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-CJqUE9P6.js +0 -1
  130. package/web/assets/classDiagram-v2-VYDZK3BY-woPJRnPi.js +0 -1
  131. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-BgEDLlx3.js +0 -1
  132. package/web/assets/stateDiagram-v2-MP3YSRHH-B-9bx94R.js +0 -1
  133. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-B-AcSAO_.js +0 -8
  134. package/web/assets/swimlanesDiagram-VR7AAH4N-DUXEdjy8.js +0 -8
package/server.cjs CHANGED
@@ -12719,6 +12719,8 @@ var init_schema = __esm({
12719
12719
  labType: text("lab_type", { enum: ["doc", "code", "notebook"] }).notNull().default("doc"),
12720
12720
  /** 仓库原文语言 (en / zh-CN / zh-TW / ...), LLM Step 2 判断; null=未知按 en 处理 */
12721
12721
  sourceLang: text("source_lang"),
12722
+ /** v0.33 语言学习课程的目标语言;null = 非语言课程 */
12723
+ languageTarget: text("language_target"),
12722
12724
  createdAt: text("created_at").notNull().default(sql`(CURRENT_TIMESTAMP)`)
12723
12725
  });
12724
12726
  contentNodes = sqliteTable("content_nodes", {
@@ -13021,6 +13023,9 @@ CREATE TABLE IF NOT EXISTS courses (
13021
13023
  lab_type TEXT NOT NULL DEFAULT 'doc' CHECK (lab_type IN ('doc', 'code', 'notebook')),
13022
13024
  -- \u4ED3\u5E93\u539F\u6587\u8BED\u8A00 (BCP-47 \u5B50\u96C6: en / zh-CN / zh-TW / ja / ...), LLM \u5728 Step 2 \u5224\u65AD
13023
13025
  source_lang TEXT,
13026
+ -- v0.33 \u8BED\u8A00\u5B66\u4E60\u8BFE\u7A0B\u7684\u76EE\u6807\u8BED\u8A00(\u88AB\u6559\u7684\u8BED\u8A00,BCP-47);NULL = \u975E\u8BED\u8A00\u8BFE\u7A0B\u3002
13027
+ -- \u4E0E source_lang \u8BED\u4E49\u4E0D\u540C:\u4E2D\u6587\u5199\u7684\u82F1\u8BED\u6559\u6750 source_lang=zh-CN\u3001language_target=en
13028
+ language_target TEXT,
13024
13029
  created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP)
13025
13030
  );
13026
13031
 
@@ -13422,6 +13427,7 @@ function runMigrations(db) {
13422
13427
  addColumnIfMissing("content_nodes", "knowledge_points", "TEXT");
13423
13428
  addColumnIfMissing("exercises", "kc_title", "TEXT");
13424
13429
  addColumnIfMissing("courses", "source_lang", "TEXT");
13430
+ addColumnIfMissing("courses", "language_target", "TEXT");
13425
13431
  addColumnIfMissing("custom_providers", "kind", "TEXT NOT NULL DEFAULT 'llm'");
13426
13432
  addColumnIfMissing("custom_providers", "vision", "INTEGER NOT NULL DEFAULT 0");
13427
13433
  addColumnIfMissing("memory", "course_id", "TEXT");
@@ -13918,7 +13924,8 @@ async function executeImport(db, structure, opts, onProgress) {
13918
13924
  description: `\u4ECE ${opts.repoName} \u5BFC\u5165`,
13919
13925
  version: 1,
13920
13926
  labType: "doc",
13921
- sourceLang: opts.sourceLang
13927
+ sourceLang: opts.sourceLang,
13928
+ languageTarget: opts.languageTarget ?? null
13922
13929
  }).run();
13923
13930
  for (const sec of structure.sections) {
13924
13931
  const sectionId = (0, import_node_crypto3.randomUUID)();
@@ -60668,22 +60675,23 @@ var init_llm_presets = __esm({
60668
60675
  "use strict";
60669
60676
  PROVIDER_PRESETS = [
60670
60677
  // ================================================================
60671
- // 智谱 GLM — 标准按量计费端点
60678
+ // 智谱 GLM — 标准按量计费端点(模型清单 = z.ai /models 实测 + 常驻免费档)
60672
60679
  // ================================================================
60673
60680
  {
60674
60681
  id: "glm",
60675
60682
  label: "\u667A\u8C31 GLM\uFF08\u6807\u51C6 API\uFF09",
60676
60683
  protocol: "openai-compatible",
60677
60684
  baseUrl: "https://open.bigmodel.cn/api/paas/v4",
60678
- defaultModel: "glm-4-flash",
60685
+ defaultModel: "glm-5.3-flash",
60679
60686
  models: [
60680
- { id: "glm-4-flash", label: "GLM-4-Flash\uFF08\u514D\u8D39\uFF09", contextWindow: 128e3, free: true, capabilities: ["chat"], pricing: { input: 0, output: 0 } },
60681
- { id: "glm-5.2", label: "GLM-5.2\uFF08\u65D7\u8230 \xB7 1M\u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, capabilities: ["chat", "reasoning", "tools"], pricing: { input: 0.5, output: 1.5 } },
60682
- { id: "glm-5.3-flash", label: "GLM-5.3-Flash\uFF08\u5FEB\u901F \xB7 \u652F\u6301\u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "tools", "vision"] },
60687
+ { id: "glm-5.3", label: "GLM-5.3\uFF08\u65D7\u8230 \xB7 1.3M\u4E0A\u4E0B\u6587\uFF09", contextWindow: 1310720, capabilities: ["chat", "reasoning", "tools"], pricing: { input: 1.4, output: 4.4 } },
60688
+ { id: "glm-5.3-flash", label: "GLM-5.3-Flash\uFF08\u5FEB\u901F \xB7 \u652F\u6301\u770B\u56FE\uFF09", contextWindow: 1310720, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.15, output: 0.5 } },
60689
+ { id: "glm-5.2", label: "GLM-5.2\uFF08\u4E0A\u4EE3\u65D7\u8230 \xB7 1M\u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, capabilities: ["chat", "reasoning", "tools"], pricing: { input: 0.5, output: 1.5 } },
60690
+ { id: "glm-5", label: "GLM-5\uFF08\u901A\u7528\uFF09", contextWindow: null, capabilities: ["chat", "reasoning", "tools"] },
60691
+ { id: "glm-5-turbo", label: "GLM-5-Turbo\uFF08\u6781\u901F\uFF09", contextWindow: null, capabilities: ["chat", "tools"] },
60683
60692
  { id: "glm-4.7", label: "GLM-4.7\uFF08\u5747\u8861\uFF09", contextWindow: 2e5, capabilities: ["chat", "tools"], pricing: { input: 0.14, output: 0.28 } },
60684
- { id: "glm-4.7-flash", label: "GLM-4.7-Flash\uFF08\u514D\u8D39\uFF09", contextWindow: 2e5, free: true, capabilities: ["chat"], pricing: { input: 0, output: 0 } },
60685
- { id: "glm-4.6", label: "GLM-4.6\uFF08\u7F16\u7801/\u63A8\u7406\u5F3A\uFF09", contextWindow: 2e5, capabilities: ["chat", "reasoning", "tools"], pricing: { input: 0.28, output: 0.84 } },
60686
- { id: "glm-4-long", label: "GLM-4-Long\uFF081M\u8D85\u957F\u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, capabilities: ["chat"], pricing: { input: 0.07, output: 0.14 } }
60693
+ { id: "glm-4.5-air", label: "GLM-4.5-Air\uFF08\u8F7B\u91CF\u4FBF\u5B9C\uFF09", contextWindow: null, capabilities: ["chat", "tools"] },
60694
+ { id: "glm-4-flash", label: "GLM-4-Flash\uFF08\u514D\u8D39\uFF09", contextWindow: 128e3, free: true, capabilities: ["chat"], pricing: { input: 0, output: 0 } }
60687
60695
  ],
60688
60696
  apiKeySetting: "glm_api_key",
60689
60697
  keyUrl: "https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys",
@@ -60691,18 +60699,23 @@ var init_llm_presets = __esm({
60691
60699
  note: "\u56FD\u5185\u63A8\u8350 \xB7 \u6309\u91CF\u8BA1\u8D39 \xB7 \u6709\u514D\u8D39\u989D\u5EA6"
60692
60700
  },
60693
60701
  // ================================================================
60694
- // 智谱 GLM — CodingPlan 订阅端点(性价比最高,限制 CodingPlan key)
60702
+ // 智谱 GLM — CodingPlan 订阅端点(性价比最高;清单 = coding /models 实测)
60695
60703
  // ================================================================
60696
60704
  {
60697
60705
  id: "glm-codingplan",
60698
60706
  label: "\u667A\u8C31 GLM\uFF08CodingPlan \u8BA2\u9605\uFF09",
60699
60707
  protocol: "openai-compatible",
60700
60708
  baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
60701
- defaultModel: "glm-5.2",
60709
+ defaultModel: "glm-5.3",
60702
60710
  models: [
60703
- { id: "glm-5.2", label: "GLM-5.2\uFF08\u65D7\u8230\uFF09", contextWindow: 1e6, capabilities: ["chat", "reasoning", "tools"] },
60704
- { id: "glm-5.3-flash", label: "GLM-5.3-Flash\uFF08\u5FEB\u901F \xB7 \u652F\u6301\u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "tools", "vision"] },
60705
- { id: "glm-4.6", label: "GLM-4.6\uFF08\u7F16\u7801\u5F3A\uFF09", contextWindow: 2e5, capabilities: ["chat", "reasoning", "tools"] }
60711
+ { id: "glm-5.3", label: "GLM-5.3\uFF08\u65D7\u8230\uFF09", contextWindow: 1310720, capabilities: ["chat", "reasoning", "tools"] },
60712
+ { id: "glm-5.3-flash", label: "GLM-5.3-Flash\uFF08\u5FEB\u901F \xB7 \u652F\u6301\u770B\u56FE\uFF09", contextWindow: 1310720, capabilities: ["chat", "tools", "vision"] },
60713
+ { id: "glm-5.2", label: "GLM-5.2\uFF08\u4E0A\u4EE3\u65D7\u8230\uFF09", contextWindow: 1e6, capabilities: ["chat", "reasoning", "tools"] },
60714
+ { id: "glm-5", label: "GLM-5\uFF08\u901A\u7528\uFF09", contextWindow: null, capabilities: ["chat", "reasoning", "tools"] },
60715
+ { id: "glm-5-turbo", label: "GLM-5-Turbo\uFF08\u6781\u901F\uFF09", contextWindow: null, capabilities: ["chat", "tools"] },
60716
+ { id: "glm-4.7", label: "GLM-4.7\uFF08\u5747\u8861\uFF09", contextWindow: 2e5, capabilities: ["chat", "tools"] },
60717
+ { id: "glm-4.6", label: "GLM-4.6\uFF08\u7F16\u7801\u5F3A\uFF09", contextWindow: 2e5, capabilities: ["chat", "reasoning", "tools"] },
60718
+ { id: "glm-4.5-air", label: "GLM-4.5-Air\uFF08\u8F7B\u91CF\u4FBF\u5B9C\uFF09", contextWindow: null, capabilities: ["chat", "tools"] }
60706
60719
  ],
60707
60720
  apiKeySetting: "glm_codingplan_key",
60708
60721
  keyUrl: "https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys",
@@ -60710,26 +60723,27 @@ var init_llm_presets = __esm({
60710
60723
  note: "\u{1F680} CodingPlan \u8BA2\u9605 \xB7 \u6027\u4EF7\u6BD4\u6700\u9AD8 \xB7 \u9700 CodingPlan key"
60711
60724
  },
60712
60725
  // ================================================================
60713
- // DeepSeek — 当前模型 v4,旧模型 deepseek-chat 即将退役
60726
+ // DeepSeek — V4 世代;thinking 参数(none/low/high/max,默认开=high);
60727
+ // 旧 deepseek-chat/deepseek-reasoner 模型名 2026-07 已退役(官方迁移公告)
60714
60728
  // ================================================================
60715
60729
  {
60716
60730
  id: "deepseek",
60717
60731
  label: "DeepSeek",
60718
60732
  protocol: "openai-compatible",
60719
60733
  baseUrl: "https://api.deepseek.com",
60720
- defaultModel: "deepseek-v4-flash",
60734
+ defaultModel: "deepseek-v4.1-flash",
60721
60735
  models: [
60722
- { id: "deepseek-v4-flash", label: "DeepSeek V4 Flash\uFF08\u5F53\u524D\u63A8\u8350\uFF09", contextWindow: 64e3, capabilities: ["chat", "tools"], pricing: { input: 0.14, output: 0.28 } },
60723
- { id: "deepseek-v4-pro", label: "DeepSeek V4 Pro\uFF08\u65D7\u8230\uFF09", contextWindow: 64e3, capabilities: ["chat", "reasoning", "tools"] },
60724
- { id: "deepseek-reasoner", label: "DeepSeek Reasoner\uFF08R1 \u63A8\u7406 \xB7 \u5373\u5C06\u9000\u5F79\uFF09", contextWindow: 64e3, capabilities: ["chat", "reasoning"] }
60736
+ { id: "deepseek-v4.1-flash", label: "DeepSeek V4.1 Flash\uFF08\u63A8\u8350 \xB7 1M\u4E0A\u4E0B\u6587 \xB7 \u652F\u6301\u770B\u56FE\uFF09", contextWindow: 1048576, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.15, output: 0.6 } },
60737
+ { id: "deepseek-v4-pro", label: "DeepSeek V4 Pro\uFF08\u65D7\u8230 \xB7 1M\u4E0A\u4E0B\u6587\uFF09", contextWindow: 1048576, capabilities: ["chat", "reasoning", "tools"], pricing: { input: 0.84, output: 1.68 } },
60738
+ { id: "deepseek-v4-flash", label: "DeepSeek V4 Flash\uFF08\u4E0A\u4EE3\u5FEB\u6863\uFF09", contextWindow: 64e3, capabilities: ["chat", "tools"], pricing: { input: 0.14, output: 0.28 } }
60725
60739
  ],
60726
60740
  apiKeySetting: "deepseek_api_key",
60727
60741
  keyUrl: "https://platform.deepseek.com/api_keys",
60728
60742
  docsUrl: "https://api-docs.deepseek.com/",
60729
- note: "\u56FD\u5185 \xB7 \u63A8\u7406\u80FD\u529B\u5F3A"
60743
+ note: "\u56FD\u5185 \xB7 \u63A8\u7406\u5F3A \xB7 V4.1 Flash \u652F\u6301\u770B\u56FE"
60730
60744
  },
60731
60745
  // ================================================================
60732
- // Moonshot Kimi — 超长上下文
60746
+ // Moonshot Kimi — k3 旗舰(1M·看图),k2.5/k2.6 混合思考(默认开)
60733
60747
  // ================================================================
60734
60748
  {
60735
60749
  id: "kimi",
@@ -60738,7 +60752,9 @@ var init_llm_presets = __esm({
60738
60752
  baseUrl: "https://api.moonshot.cn/v1",
60739
60753
  defaultModel: "kimi-k3",
60740
60754
  models: [
60741
- { id: "kimi-k3", label: "Kimi K3\uFF081M \u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools"] }
60755
+ { id: "kimi-k3", label: "Kimi K3\uFF08\u65D7\u8230 \xB7 1M\u4E0A\u4E0B\u6587 \xB7 \u770B\u56FE\uFF09", contextWindow: 1048576, capabilities: ["chat", "tools", "vision"], pricing: { input: 2.3, output: 11.55 } },
60756
+ { id: "kimi-k2.6", label: "Kimi K2.6\uFF08\u6DF7\u5408\u601D\u8003 \xB7 \u770B\u56FE\uFF09", contextWindow: 262144, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.95, output: 4 } },
60757
+ { id: "kimi-k2.7-code", label: "Kimi K2.7 Code\uFF08\u4EE3\u7801\uFF09", contextWindow: 262144, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.71, output: 3.5 } }
60742
60758
  ],
60743
60759
  apiKeySetting: "kimi_api_key",
60744
60760
  keyUrl: "https://platform.kimi.com/console/api-keys",
@@ -60746,18 +60762,18 @@ var init_llm_presets = __esm({
60746
60762
  note: "\u56FD\u5185 \xB7 \u8D85\u957F\u4E0A\u4E0B\u6587"
60747
60763
  },
60748
60764
  // ================================================================
60749
- // 通义千问 Qwen(阿里云百炼)
60765
+ // 通义千问 Qwen(阿里云百炼)— qwen3.5 世代(全系多模态)
60750
60766
  // ================================================================
60751
60767
  {
60752
60768
  id: "qwen",
60753
60769
  label: "\u901A\u4E49\u5343\u95EE Qwen",
60754
60770
  protocol: "openai-compatible",
60755
60771
  baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
60756
- defaultModel: "qwen-plus",
60772
+ defaultModel: "qwen3.5-plus",
60757
60773
  models: [
60758
- { id: "qwen-max", label: "Qwen Max\uFF08\u65D7\u8230\uFF09", contextWindow: 32e3, capabilities: ["chat", "tools"] },
60759
- { id: "qwen-plus", label: "Qwen Plus\uFF08\u5747\u8861\uFF09", contextWindow: 131072, capabilities: ["chat", "tools"] },
60760
- { id: "qwen-turbo", label: "Qwen Turbo\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 1e6, capabilities: ["chat"] }
60774
+ { id: "qwen3.5-plus", label: "Qwen3.5 Plus\uFF08\u5747\u8861 \xB7 1M\u4E0A\u4E0B\u6587 \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.3, output: 1.8 } },
60775
+ { id: "qwen3.5-flash", label: "Qwen3.5 Flash\uFF08\u5FEB/\u4FBF\u5B9C \xB7 1M\u4E0A\u4E0B\u6587 \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.07, output: 0.26 } },
60776
+ { id: "qwen3.5-122b-a10b", label: "Qwen3.5 122B-A10B\uFF08\u5F00\u6E90\u65D7\u8230\u6258\u7BA1\uFF09", contextWindow: 262144, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.26, output: 2.08 } }
60761
60777
  ],
60762
60778
  apiKeySetting: "qwen_api_key",
60763
60779
  keyUrl: "https://dashscope.console.aliyun.com/apiKey",
@@ -60765,56 +60781,57 @@ var init_llm_presets = __esm({
60765
60781
  note: "\u56FD\u5185 \xB7 \u963F\u91CC\u4E91\u767E\u70BC"
60766
60782
  },
60767
60783
  // ================================================================
60768
- // SiliconCloud 硅基流动(聚合平台,一个 key 访问多个开源模型)
60784
+ // SiliconCloud 硅基流动(聚合平台;模型名随上游滚动,以控制台列表为准)
60769
60785
  // ================================================================
60770
60786
  {
60771
60787
  id: "siliconcloud",
60772
60788
  label: "SiliconCloud \u7845\u57FA\u6D41\u52A8",
60773
60789
  protocol: "openai-compatible",
60774
60790
  baseUrl: "https://api.siliconflow.cn/v1",
60775
- defaultModel: "deepseek-ai/DeepSeek-V3",
60791
+ defaultModel: "deepseek-ai/DeepSeek-V4.1",
60776
60792
  models: [
60777
- { id: "deepseek-ai/DeepSeek-V3", label: "DeepSeek-V3", contextWindow: 64e3 },
60778
- { id: "Qwen/Qwen2.5-72B-Instruct", label: "Qwen2.5-72B", contextWindow: 131072 }
60793
+ { id: "deepseek-ai/DeepSeek-V4.1", label: "DeepSeek V4.1", contextWindow: 1048576, capabilities: ["chat", "tools"] },
60794
+ { id: "Qwen/Qwen3.5-122B-A10B", label: "Qwen3.5 122B-A10B", contextWindow: 262144, capabilities: ["chat", "tools"] }
60779
60795
  ],
60780
60796
  apiKeySetting: "siliconcloud_api_key",
60781
60797
  keyUrl: "https://cloud.siliconflow.cn/account/ak",
60782
60798
  docsUrl: "https://docs.siliconflow.cn/",
60783
- note: "\u805A\u5408\u5E73\u53F0 \xB7 \u4E00\u4E2A key \u8BBF\u95EE\u591A\u4E2A\u5F00\u6E90\u6A21\u578B"
60799
+ note: "\u805A\u5408\u5E73\u53F0 \xB7 \u6A21\u578B\u968F\u4E0A\u6E38\u6EDA\u52A8,\u4EE5\u63A7\u5236\u53F0\u5217\u8868\u4E3A\u51C6"
60784
60800
  },
60785
60801
  // ================================================================
60786
- // OpenRouter(国际聚合,自动发现模型)
60802
+ // OpenRouter(国际聚合,应用内另有全量自动发现;此为常驻精选)
60787
60803
  // ================================================================
60788
60804
  {
60789
60805
  id: "openrouter",
60790
60806
  label: "OpenRouter\uFF08\u56FD\u9645\u805A\u5408\uFF09",
60791
60807
  protocol: "openai-compatible",
60792
60808
  baseUrl: "https://openrouter.ai/api/v1",
60793
- defaultModel: "z-ai/glm-5.2",
60809
+ defaultModel: "z-ai/glm-5.3-flash",
60794
60810
  models: [
60795
- { id: "z-ai/glm-5.2", label: "GLM-5.2", contextWindow: 1e6, capabilities: ["chat", "reasoning"] },
60796
- { id: "anthropic/claude-3.5-sonnet", label: "Claude 3.5 Sonnet", contextWindow: 2e5, capabilities: ["chat", "tools", "vision"] },
60797
- { id: "openai/gpt-4o-mini", label: "GPT-4o mini", contextWindow: 128e3, capabilities: ["chat", "tools", "vision"] },
60798
- { id: "google/gemini-flash-1.5", label: "Gemini Flash 1.5", contextWindow: 1e6, capabilities: ["chat", "vision"] }
60811
+ { id: "z-ai/glm-5.3-flash", label: "GLM-5.3-Flash\uFF08\u4FBF\u5B9C \xB7 \u770B\u56FE\uFF09", contextWindow: 1310720, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.15, output: 0.5 } },
60812
+ { id: "openai/gpt-5.6-luna", label: "GPT-5.6 Luna\uFF08\u4FBF\u5B9C \xB7 \u770B\u56FE\uFF09", contextWindow: 105e4, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.2, output: 1.2 } },
60813
+ { id: "anthropic/claude-sonnet-5", label: "Claude Sonnet 5\uFF08\u5747\u8861 \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 2, output: 10 } },
60814
+ { id: "google/gemini-3.8-flash", label: "Gemini 3.8 Flash\uFF08\u5FEB \xB7 \u770B\u56FE\uFF09", contextWindow: 1048576, capabilities: ["chat", "vision"], pricing: { input: 0.75, output: 3.75 } },
60815
+ { id: "deepseek/deepseek-v4.1-flash", label: "DeepSeek V4.1 Flash\uFF08\u4FBF\u5B9C \xB7 \u770B\u56FE\uFF09", contextWindow: 1048576, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.15, output: 0.6 } }
60799
60816
  ],
60800
60817
  apiKeySetting: "openrouter_api_key",
60801
60818
  keyUrl: "https://openrouter.ai/keys",
60802
60819
  docsUrl: "https://openrouter.ai/docs",
60803
- note: "\u56FD\u9645\u805A\u5408 \xB7 \u8986\u76D6\u6240\u6709\u4E3B\u6D41\u6A21\u578B \xB7 \u9700\u6D77\u5916\u7F51\u7EDC"
60820
+ note: "\u56FD\u9645\u805A\u5408 \xB7 \u5E94\u7528\u5185\u53EF\u53D1\u73B0\u5168\u90E8 400+ \u6A21\u578B \xB7 \u9700\u6D77\u5916\u7F51\u7EDC"
60804
60821
  },
60805
60822
  // ================================================================
60806
- // OpenAI
60823
+ // OpenAI — GPT-5.6 世代(id/价格/模态取自 OpenRouter 实时返回)
60807
60824
  // ================================================================
60808
60825
  {
60809
60826
  id: "openai",
60810
60827
  label: "OpenAI",
60811
60828
  protocol: "openai-compatible",
60812
60829
  baseUrl: "https://api.openai.com/v1",
60813
- defaultModel: "gpt-4o-mini",
60830
+ defaultModel: "gpt-5.6-luna",
60814
60831
  models: [
60815
- { id: "gpt-4o-mini", label: "GPT-4o mini\uFF08\u4FBF\u5B9C\uFF09", contextWindow: 128e3, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.15, output: 0.6 } },
60816
- { id: "gpt-4o", label: "GPT-4o\uFF08\u65D7\u8230\uFF09", contextWindow: 128e3, capabilities: ["chat", "tools", "vision"], pricing: { input: 2.5, output: 10 } },
60817
- { id: "o4-mini", label: "o4-mini\uFF08\u63A8\u7406\uFF09", contextWindow: 2e5, capabilities: ["chat", "reasoning"] }
60832
+ { id: "gpt-5.6-luna", label: "GPT-5.6 Luna\uFF08\u4FBF\u5B9C \xB7 \u770B\u56FE\uFF09", contextWindow: 105e4, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.2, output: 1.2 } },
60833
+ { id: "gpt-5.6-sol", label: "GPT-5.6 Sol\uFF08\u5747\u8861\uFF09", contextWindow: 105e4, capabilities: ["chat", "tools", "vision"], pricing: { input: 2, output: 10 } },
60834
+ { id: "gpt-5.6-terra-pro", label: "GPT-5.6 Terra Pro\uFF08\u65D7\u8230\uFF09", contextWindow: 105e4, capabilities: ["chat", "reasoning", "tools", "vision"], pricing: { input: 2, output: 12 } }
60818
60835
  ],
60819
60836
  apiKeySetting: "openai_api_key",
60820
60837
  keyUrl: "https://platform.openai.com/api-keys",
@@ -60822,33 +60839,34 @@ var init_llm_presets = __esm({
60822
60839
  note: "\u9700\u6D77\u5916\u7F51\u7EDC"
60823
60840
  },
60824
60841
  // ================================================================
60825
- // Anthropic Claude
60842
+ // Anthropic Claude — 5 世代(fable 5.1 旗舰/opus 5/sonnet 5;1M 上下文)
60826
60843
  // ================================================================
60827
60844
  {
60828
60845
  id: "anthropic",
60829
60846
  label: "Anthropic Claude",
60830
60847
  protocol: "anthropic",
60831
- defaultModel: "claude-3-5-haiku-latest",
60848
+ defaultModel: "claude-sonnet-5",
60832
60849
  models: [
60833
- { id: "claude-3-5-haiku-latest", label: "Claude 3.5 Haiku\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 2e5, capabilities: ["chat", "tools"], pricing: { input: 0.8, output: 4 } },
60834
- { id: "claude-3-5-sonnet-latest", label: "Claude 3.5 Sonnet\uFF08\u5747\u8861\uFF09", contextWindow: 2e5, capabilities: ["chat", "tools", "vision"], pricing: { input: 3, output: 15 } }
60850
+ { id: "claude-sonnet-5", label: "Claude Sonnet 5\uFF08\u5747\u8861 \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 2, output: 10 } },
60851
+ { id: "claude-opus-5", label: "Claude Opus 5\uFF08\u5F3A \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 5, output: 25 } },
60852
+ { id: "claude-fable-5.1", label: "Claude Fable 5.1\uFF08\u65D7\u8230 \xB7 \u770B\u56FE\uFF09", contextWindow: 1e6, capabilities: ["chat", "tools", "vision"], pricing: { input: 10, output: 50 } }
60835
60853
  ],
60836
60854
  apiKeySetting: "anthropic_api_key",
60837
60855
  keyUrl: "https://console.anthropic.com/settings/keys",
60838
60856
  docsUrl: "https://docs.anthropic.com/",
60839
- note: "\u9700\u6D77\u5916\u7F51\u7EDC \xB7 \u957F\u4E0A\u4E0B\u6587"
60857
+ note: "\u9700\u6D77\u5916\u7F51\u7EDC \xB7 1M \u957F\u4E0A\u4E0B\u6587"
60840
60858
  },
60841
60859
  // ================================================================
60842
- // Google Gemini
60860
+ // Google Gemini — 3.8/3.7 Flash(1M 上下文全模态;Pro 未见于 /models 返回)
60843
60861
  // ================================================================
60844
60862
  {
60845
60863
  id: "google",
60846
60864
  label: "Google Gemini",
60847
60865
  protocol: "google",
60848
- defaultModel: "gemini-1.5-flash",
60866
+ defaultModel: "gemini-3.8-flash",
60849
60867
  models: [
60850
- { id: "gemini-1.5-flash", label: "Gemini 1.5 Flash\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 1e6, capabilities: ["chat", "vision"], pricing: { input: 0.075, output: 0.3 } },
60851
- { id: "gemini-1.5-pro", label: "Gemini 1.5 Pro\uFF08\u5F3A\uFF09", contextWindow: 2e6, capabilities: ["chat", "vision"], pricing: { input: 1.25, output: 5 } }
60868
+ { id: "gemini-3.8-flash", label: "Gemini 3.8 Flash\uFF08\u5FEB \xB7 \u770B\u56FE\uFF09", contextWindow: 1048576, capabilities: ["chat", "vision"], pricing: { input: 0.75, output: 3.75 } },
60869
+ { id: "gemini-3.7-flash", label: "Gemini 3.7 Flash\uFF08\u4E0A\u4EE3\uFF09", contextWindow: 1048576, capabilities: ["chat", "vision"], pricing: { input: 0.75, output: 3.75 } }
60852
60870
  ],
60853
60871
  apiKeySetting: "google_api_key",
60854
60872
  keyUrl: "https://aistudio.google.com/app/apikey",
@@ -60856,74 +60874,73 @@ var init_llm_presets = __esm({
60856
60874
  note: "\u9700\u6D77\u5916\u7F51\u7EDC \xB7 \u8D85\u957F\u4E0A\u4E0B\u6587"
60857
60875
  },
60858
60876
  // ================================================================
60859
- // Groq — 超快推理(LPU),免费额度
60877
+ // Groq — Llama 4 世代(LPU 极速;官方模型列表)
60860
60878
  // ================================================================
60861
60879
  {
60862
60880
  id: "groq",
60863
60881
  label: "Groq",
60864
60882
  protocol: "openai-compatible",
60865
60883
  baseUrl: "https://api.groq.com/openai/v1",
60866
- defaultModel: "llama-3.3-70b-versatile",
60884
+ defaultModel: "meta-llama/llama-4-maverick-17b-128e-instruct",
60867
60885
  models: [
60868
- { id: "llama-3.3-70b-versatile", label: "Llama 3.3 70B\uFF08\u5747\u8861\uFF09", contextWindow: 128e3, capabilities: ["chat", "tools"] },
60869
- { id: "llama-3.1-8b-instant", label: "Llama 3.1 8B Instant\uFF08\u6781\u901F\uFF09", contextWindow: 128e3, capabilities: ["chat"], free: true },
60870
- { id: "deepseek-r1-distill-llama-70b", label: "DeepSeek R1 Distill 70B\uFF08\u63A8\u7406\uFF09", contextWindow: 128e3, capabilities: ["chat", "reasoning"] }
60886
+ { id: "meta-llama/llama-4-maverick-17b-128e-instruct", label: "Llama 4 Maverick\uFF08\u5747\u8861 \xB7 \u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "tools", "vision"] },
60887
+ { id: "meta-llama/llama-4-scout-17b-16e-instruct", label: "Llama 4 Scout\uFF08\u5FEB \xB7 \u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "vision"] }
60871
60888
  ],
60872
60889
  apiKeySetting: "groq_api_key",
60873
60890
  keyUrl: "https://console.groq.com/keys",
60874
- docsUrl: "https://docs.groq.com/",
60891
+ docsUrl: "https://console.groq.com/docs/models",
60875
60892
  note: "\u8D85\u5FEB\u63A8\u7406 \xB7 \u514D\u8D39\u989D\u5EA6"
60876
60893
  },
60877
60894
  // ================================================================
60878
- // Together AI — 开源模型托管
60895
+ // Together AI — 开源模型托管(Llama 4 官方命名;低置信,以控制台为准)
60879
60896
  // ================================================================
60880
60897
  {
60881
60898
  id: "together",
60882
60899
  label: "Together AI",
60883
60900
  protocol: "openai-compatible",
60884
60901
  baseUrl: "https://api.together.xyz/v1",
60885
- defaultModel: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
60902
+ defaultModel: "meta-llama/Llama-4-Scout-17B-16E-Instruct",
60886
60903
  models: [
60887
- { id: "meta-llama/Llama-3.3-70B-Instruct-Turbo", label: "Llama 3.3 70B Turbo", contextWindow: 128e3, capabilities: ["chat", "tools"] },
60888
- { id: "Qwen/Qwen2.5-72B-Instruct-Turbo", label: "Qwen2.5 72B Turbo", contextWindow: 32768, capabilities: ["chat"] },
60889
- { id: "deepseek-ai/DeepSeek-R1", label: "DeepSeek R1", contextWindow: 128e3, capabilities: ["chat", "reasoning"] }
60904
+ { id: "meta-llama/Llama-4-Scout-17B-16E-Instruct", label: "Llama 4 Scout", contextWindow: null, capabilities: ["chat", "vision"] },
60905
+ { id: "meta-llama/Llama-4-Maverick-17B-128E-Instruct", label: "Llama 4 Maverick", contextWindow: null, capabilities: ["chat", "vision"] }
60890
60906
  ],
60891
60907
  apiKeySetting: "together_api_key",
60892
60908
  keyUrl: "https://api.together.ai/settings/api-keys",
60893
60909
  docsUrl: "https://docs.together.ai/",
60894
- note: "\u5F00\u6E90\u6A21\u578B \xB7 \u6D77\u5916"
60910
+ note: "\u5F00\u6E90\u6A21\u578B \xB7 \u6D77\u5916 \xB7 \u547D\u540D\u4EE5\u63A7\u5236\u53F0\u4E3A\u51C6"
60895
60911
  },
60896
60912
  // ================================================================
60897
- // Mistral AI — 欧洲开源模型
60913
+ // Mistral AI — 2512/2603 世代(id/价格/模态取自 OpenRouter 返回)
60898
60914
  // ================================================================
60899
60915
  {
60900
60916
  id: "mistral",
60901
60917
  label: "Mistral AI",
60902
60918
  protocol: "openai-compatible",
60903
60919
  baseUrl: "https://api.mistral.ai/v1",
60904
- defaultModel: "mistral-large-latest",
60920
+ defaultModel: "mistral-medium-3-5",
60905
60921
  models: [
60906
- { id: "mistral-large-latest", label: "Mistral Large\uFF08\u65D7\u8230\uFF09", contextWindow: 128e3, capabilities: ["chat", "tools", "vision"] },
60907
- { id: "mistral-small-latest", label: "Mistral Small\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 32e3, capabilities: ["chat", "tools"] },
60908
- { id: "codestral-latest", label: "Codestral\uFF08\u4EE3\u7801\u4E13\u7528\uFF09", contextWindow: 256e3, capabilities: ["chat"] }
60922
+ { id: "mistral-medium-3-5", label: "Mistral Medium 3.5\uFF08\u5747\u8861 \xB7 \u770B\u56FE\uFF09", contextWindow: 262144, capabilities: ["chat", "tools", "vision"], pricing: { input: 1.5, output: 7.5 } },
60923
+ { id: "mistral-large-2512", label: "Mistral Large 2512\uFF08\u5927\u676F\u4FBF\u5B9C\uFF09", contextWindow: 262144, capabilities: ["chat", "tools", "vision"], pricing: { input: 0.5, output: 1.5 } },
60924
+ { id: "mistral-small-2603", label: "Mistral Small 2603\uFF08\u5FEB/\u4FBF\u5B9C \xB7 \u770B\u56FE\uFF09", contextWindow: 262144, capabilities: ["chat", "vision"], pricing: { input: 0.15, output: 0.6 } }
60909
60925
  ],
60910
60926
  apiKeySetting: "mistral_api_key",
60911
60927
  keyUrl: "https://console.mistral.ai/api-keys",
60912
60928
  docsUrl: "https://docs.mistral.ai/",
60913
- note: "\u6B27\u6D32 \xB7 \u5F00\u6E90 \xB7 \u6D77\u5916"
60929
+ note: "\u6B27\u6D32 \xB7 \u6D77\u5916"
60914
60930
  },
60915
60931
  // ================================================================
60916
- // xAI Grok — Elon Musk 的 AI
60932
+ // xAI Grok — 4.x 世代(4.3/4.5/4.6 认 reasoning_effort;裸 grok-4 传参报错已避开)
60917
60933
  // ================================================================
60918
60934
  {
60919
60935
  id: "xai",
60920
60936
  label: "xAI Grok",
60921
60937
  protocol: "openai-compatible",
60922
60938
  baseUrl: "https://api.x.ai/v1",
60923
- defaultModel: "grok-3-mini",
60939
+ defaultModel: "grok-4.3",
60924
60940
  models: [
60925
- { id: "grok-3", label: "Grok 3\uFF08\u65D7\u8230\uFF09", contextWindow: 131072, capabilities: ["chat", "reasoning", "tools", "vision"] },
60926
- { id: "grok-3-mini", label: "Grok 3 Mini\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 131072, capabilities: ["chat", "reasoning"] }
60941
+ { id: "grok-4.6", label: "Grok 4.6\uFF08\u65D7\u8230 \xB7 \u770B\u56FE\uFF09", contextWindow: 5e5, capabilities: ["chat", "reasoning", "tools", "vision"], pricing: { input: 2, output: 6 } },
60942
+ { id: "grok-4.3", label: "Grok 4.3\uFF081M\u4E0A\u4E0B\u6587 \xB7 \u6027\u4EF7\u6BD4\uFF09", contextWindow: 1e6, capabilities: ["chat", "reasoning", "tools", "vision"], pricing: { input: 1.25, output: 2.5 } },
60943
+ { id: "grok-4.20", label: "Grok 4.20\uFF082M\u8D85\u957F\u4E0A\u4E0B\u6587\uFF09", contextWindow: 2e6, capabilities: ["chat", "reasoning", "tools", "vision"], pricing: { input: 1.25, output: 2.5 } }
60927
60944
  ],
60928
60945
  apiKeySetting: "xai_api_key",
60929
60946
  keyUrl: "https://console.x.ai/",
@@ -60931,63 +60948,58 @@ var init_llm_presets = __esm({
60931
60948
  note: "\u6D77\u5916 \xB7 \u5B9E\u65F6\u4FE1\u606F"
60932
60949
  },
60933
60950
  // ================================================================
60934
- // 火山引擎豆包(字节跳动)
60951
+ // 火山引擎豆包 — Seed 世代(深度思考默认开;thinking.type+reasoning_effort 方言)
60935
60952
  // ================================================================
60936
60953
  {
60937
60954
  id: "volcano",
60938
60955
  label: "\u706B\u5C71\u5F15\u64CE\u8C46\u5305",
60939
60956
  protocol: "openai-compatible",
60940
60957
  baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
60941
- defaultModel: "doubao-1.5-pro-32k",
60958
+ defaultModel: "doubao-seed-2-0-pro-260215",
60942
60959
  models: [
60943
- { id: "doubao-1.5-pro-32k", label: "Doubao 1.5 Pro\uFF08\u65D7\u8230\uFF09", contextWindow: 32e3, capabilities: ["chat", "tools"] },
60944
- { id: "doubao-1.5-lite-32k", label: "Doubao 1.5 Lite\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 32e3, capabilities: ["chat"] },
60945
- { id: "deepseek-r1-250120", label: "DeepSeek R1\uFF08\u706B\u5C71\u7248\uFF09", contextWindow: 64e3, capabilities: ["chat", "reasoning"] }
60960
+ { id: "doubao-seed-2-0-pro-260215", label: "Doubao Seed 2.0 Pro\uFF08\u65D7\u8230 \xB7 \u6DF1\u5EA6\u601D\u8003\uFF09", contextWindow: null, capabilities: ["chat", "reasoning", "tools"] }
60946
60961
  ],
60947
60962
  apiKeySetting: "volcano_api_key",
60948
60963
  keyUrl: "https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey",
60949
- docsUrl: "https://www.volcengine.com/docs/82379/",
60950
- note: "\u56FD\u5185 \xB7 \u5B57\u8282\u8DF3\u52A8"
60964
+ docsUrl: "https://www.volcengine.com/docs/82379/1330310",
60965
+ note: "\u56FD\u5185 \xB7 \u5B57\u8282 \xB7 \u5B8C\u6574\u6A21\u578B id \u89C1\u65B9\u821F\u63A7\u5236\u53F0"
60951
60966
  },
60952
60967
  // ================================================================
60953
- // 百度文心一言(千帆 v2 OpenAI 兼容)
60968
+ // 百度文心(千帆 v2 OpenAI 兼容)— ERNIE 5.0 全模态世代
60954
60969
  // ================================================================
60955
60970
  {
60956
60971
  id: "baidu",
60957
60972
  label: "\u767E\u5EA6\u6587\u5FC3",
60958
60973
  protocol: "openai-compatible",
60959
60974
  baseUrl: "https://qianfan.baidubce.com/v2",
60960
- defaultModel: "ernie-4.0-8k-latest",
60975
+ defaultModel: "ernie-5.0",
60961
60976
  models: [
60962
- { id: "ernie-4.0-8k-latest", label: "ERNIE 4.0\uFF08\u65D7\u8230\uFF09", contextWindow: 8e3, capabilities: ["chat", "tools"] },
60963
- { id: "ernie-3.5-8k-latest", label: "ERNIE 3.5\uFF08\u5747\u8861\uFF09", contextWindow: 8e3, capabilities: ["chat"] },
60964
- { id: "ernie-speed-128k", label: "ERNIE Speed 128K\uFF08\u957F\u4E0A\u4E0B\u6587\uFF09", contextWindow: 128e3, capabilities: ["chat"] }
60977
+ { id: "ernie-5.0", label: "ERNIE 5.0\uFF08\u65D7\u8230 \xB7 \u5168\u6A21\u6001\u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "tools", "vision"] }
60965
60978
  ],
60966
60979
  apiKeySetting: "baidu_api_key",
60967
60980
  keyUrl: "https://console.bce.baidu.com/iam/#/iam/apikey/list",
60968
- docsUrl: "https://cloud.baidu.com/doc/WENXINWORKSHOP/index",
60969
- note: "\u56FD\u5185 \xB7 \u767E\u5EA6"
60981
+ docsUrl: "https://cloud.baidu.com/doc/qianfan/s/rmh4stp0j",
60982
+ note: "\u56FD\u5185 \xB7 \u767E\u5EA6 \xB7 \u66F4\u591A\u6A21\u578B\u89C1\u5343\u5E06\u6A21\u578B\u5217\u8868"
60970
60983
  },
60971
60984
  // ================================================================
60972
- // MiniMax
60985
+ // MiniMax — M2 世代(交错思考常开,官方 API 无禁用开关)
60973
60986
  // ================================================================
60974
60987
  {
60975
60988
  id: "minimax",
60976
60989
  label: "MiniMax",
60977
60990
  protocol: "openai-compatible",
60978
60991
  baseUrl: "https://api.minimax.chat/v1",
60979
- defaultModel: "abab6.5s-chat",
60992
+ defaultModel: "MiniMax-M2.7",
60980
60993
  models: [
60981
- { id: "abab6.5s-chat", label: "abab6.5s\uFF08\u5FEB/\u4FBF\u5B9C\uFF09", contextWindow: 245760, capabilities: ["chat"] },
60982
- { id: "abab6.5-chat", label: "abab6.5\uFF08\u65D7\u8230\uFF09", contextWindow: 8192, capabilities: ["chat", "tools"] }
60994
+ { id: "MiniMax-M2.7", label: "MiniMax M2.7\uFF08\u5F53\u524D\u4E16\u4EE3 \xB7 \u601D\u8003\u5E38\u5F00\uFF09", contextWindow: 204800, capabilities: ["chat", "tools"], pricing: { input: 0.3, output: 1.2 } }
60983
60995
  ],
60984
60996
  apiKeySetting: "minimax_api_key",
60985
60997
  keyUrl: "https://platform.minimaxi.com/user-center/basic-information/interface-key",
60986
- docsUrl: "https://platform.minimaxi.com/document/",
60987
- note: "\u56FD\u5185 \xB7 \u957F\u4E0A\u4E0B\u6587"
60998
+ docsUrl: "https://platform.minimax.io/docs/",
60999
+ note: "\u56FD\u5185 \xB7 \u601D\u8003\u5E38\u5F00(\u5B98\u65B9\u65E0\u601D\u8003\u5F00\u5173)"
60988
61000
  },
60989
61001
  // ================================================================
60990
- // 百川 Baichuan
61002
+ // 百川 Baichuan(无 2026-09 新资料,维持旧条目;以控制台为准)
60991
61003
  // ================================================================
60992
61004
  {
60993
61005
  id: "baichuan",
@@ -61002,20 +61014,20 @@ var init_llm_presets = __esm({
61002
61014
  apiKeySetting: "baichuan_api_key",
61003
61015
  keyUrl: "https://platform.baichuan-ai.com/console/apikey",
61004
61016
  docsUrl: "https://platform.baichuan-ai.com/docs/api",
61005
- note: "\u56FD\u5185 \xB7 \u767E\u5DDD\u667A\u80FD"
61017
+ note: "\u56FD\u5185 \xB7 \u767E\u5DDD\u667A\u80FD \xB7 \u5F85\u6838(\u4EE5\u63A7\u5236\u53F0\u4E3A\u51C6)"
61006
61018
  },
61007
61019
  // ================================================================
61008
- // 阶跃星辰 StepFun
61020
+ // 阶跃星辰 StepFun — Step 3.7 世代(多模态推理,默认关思考,enable_thinking 方言)
61009
61021
  // ================================================================
61010
61022
  {
61011
61023
  id: "stepfun",
61012
61024
  label: "\u9636\u8DC3\u661F\u8FB0 StepFun",
61013
61025
  protocol: "openai-compatible",
61014
61026
  baseUrl: "https://api.stepfun.com/v1",
61015
- defaultModel: "step-2-16k",
61027
+ defaultModel: "step-3.7-flash",
61016
61028
  models: [
61017
- { id: "step-2-16k", label: "Step 2 16K\uFF08\u65D7\u8230\uFF09", contextWindow: 16384, capabilities: ["chat", "tools"] },
61018
- { id: "step-1flash", label: "Step 1 Flash\uFF08\u5FEB/\u514D\u8D39\uFF09", contextWindow: 8192, capabilities: ["chat"], free: true }
61029
+ { id: "step-3.7-flash", label: "Step 3.7 Flash\uFF08\u65D7\u8230 \xB7 \u591A\u6A21\u6001\u63A8\u7406 \xB7 \u770B\u56FE\uFF09", contextWindow: null, capabilities: ["chat", "reasoning", "tools", "vision"] },
61030
+ { id: "step-3.5-flash", label: "Step 3.5 Flash\uFF08\u4E0A\u4EE3\uFF09", contextWindow: null, capabilities: ["chat", "reasoning", "tools", "vision"] }
61019
61031
  ],
61020
61032
  apiKeySetting: "stepfun_api_key",
61021
61033
  keyUrl: "https://platform.stepfun.com/interface-key",
@@ -61471,6 +61483,19 @@ function llmFamilyOf(providerId, baseUrl, model) {
61471
61483
  return "qwen";
61472
61484
  if (url2.includes("siliconflow"))
61473
61485
  return "siliconcloud";
61486
+ if (url2.includes("deepseek") || m.startsWith("deepseek-"))
61487
+ return "deepseek";
61488
+ if (url2.includes("moonshot") || m.startsWith("kimi-"))
61489
+ return "kimi";
61490
+ if (url2.includes("volces.com") || m.startsWith("doubao-"))
61491
+ return "volcano";
61492
+ if (url2.includes("stepfun") || m.startsWith("step-"))
61493
+ return "stepfun";
61494
+ if (url2.includes("x.ai") || m.startsWith("grok-")) {
61495
+ if (/^(grok-3-mini|grok-4\.(?:[3-9]|\d{2,}))/.test(m))
61496
+ return "grok-effort";
61497
+ return providerId;
61498
+ }
61474
61499
  return providerId;
61475
61500
  }
61476
61501
  function reasoningPlanFor(providerId, protocol, effort, hints) {
@@ -61546,6 +61571,54 @@ var init_reasoning_effort = __esm({
61546
61571
  deep: (b) => {
61547
61572
  b.enable_thinking = true;
61548
61573
  }
61574
+ },
61575
+ // 以下五家 2026-09-12 进表(官方文档核对;除 GLM 外无 key 未实测端点,行为以文档为准):
61576
+ // DeepSeek V4 世代:thinking 字符串参数 none/low/high/max,默认开且默认 high。
61577
+ deepseek: {
61578
+ fast: (b) => {
61579
+ b.thinking = "none";
61580
+ },
61581
+ deep: (b) => {
61582
+ b.thinking = "max";
61583
+ }
61584
+ },
61585
+ // Moonshot Kimi:k2.5/k2.6 混合思考默认开,thinking 对象参数可关(平台文档)。
61586
+ kimi: {
61587
+ fast: (b) => {
61588
+ b.thinking = { type: "disabled" };
61589
+ },
61590
+ deep: (b) => {
61591
+ b.thinking = { type: "enabled" };
61592
+ }
61593
+ },
61594
+ // 火山方舟豆包 Seed:与 GLM 同款方言(thinking.type + reasoning_effort,官方深度思考文档)。
61595
+ volcano: {
61596
+ fast: (b) => {
61597
+ b.thinking = { type: "disabled" };
61598
+ b.reasoning_effort = "low";
61599
+ },
61600
+ deep: (b) => {
61601
+ b.thinking = { type: "enabled" };
61602
+ }
61603
+ },
61604
+ // 阶跃 Step 3.x:enable_thinking 布尔(与 Qwen 同款;Step 3.7 默认关,deep 档才有感)。
61605
+ stepfun: {
61606
+ fast: (b) => {
61607
+ b.enable_thinking = false;
61608
+ },
61609
+ deep: (b) => {
61610
+ b.enable_thinking = true;
61611
+ }
61612
+ },
61613
+ // xAI Grok:reasoning_effort(grok-4.3 none/low/medium/high 默认 high,4.5/4.6 支持;
61614
+ // 裸 grok-4 传参报错 → 家族判定按模型门控,进不了表就落 none)。
61615
+ "grok-effort": {
61616
+ fast: (b) => {
61617
+ b.reasoning_effort = "low";
61618
+ },
61619
+ deep: (b) => {
61620
+ b.reasoning_effort = "high";
61621
+ }
61549
61622
  }
61550
61623
  };
61551
61624
  OPENAI_EFFORT = { fast: "low", deep: "high" };
@@ -63496,7 +63569,8 @@ async function classifyFileRoles(db, readmeMd, fileList, fullTree, onProgress, o
63496
63569
  skip,
63497
63570
  languages: validLangs,
63498
63571
  sourceLang: detectSourceLangByRule(readmeMd),
63499
- translationLayout: layoutResult.layout
63572
+ translationLayout: layoutResult.layout,
63573
+ languageTarget: null
63500
63574
  };
63501
63575
  }
63502
63576
  send(`AI \u5224\u65AD ${remaining.length} \u4E2A\u6587\u4EF6\u89D2\u8272 + \u539F\u6587\u8BED\u8A00\uFF08\u770B README + \u76EE\u5F55\u6811\uFF09`);
@@ -63508,6 +63582,7 @@ async function classifyFileRoles(db, readmeMd, fileList, fullTree, onProgress, o
63508
63582
  const allPathSet = new Set(allPaths);
63509
63583
  const llmLangs = /* @__PURE__ */ new Set();
63510
63584
  let sourceLang = "";
63585
+ let languageTarget = null;
63511
63586
  for (let i = 0; i < remaining.length; i += CHUNK_SIZE) {
63512
63587
  const chunk = remaining.slice(i, i + CHUNK_SIZE);
63513
63588
  const chunkNum = Math.floor(i / CHUNK_SIZE) + 1;
@@ -63528,6 +63603,8 @@ async function classifyFileRoles(db, readmeMd, fileList, fullTree, onProgress, o
63528
63603
  });
63529
63604
  if (!sourceLang && parsed.sourceLang)
63530
63605
  sourceLang = parsed.sourceLang;
63606
+ if (languageTarget === null && parsed.languageTarget)
63607
+ languageTarget = parsed.languageTarget;
63531
63608
  for (const { path: path6, role, lang, translates } of parsed.files) {
63532
63609
  if (role === "translation") {
63533
63610
  if (lang && translates && allPathSet.has(translates)) {
@@ -63554,7 +63631,7 @@ async function classifyFileRoles(db, readmeMd, fileList, fullTree, onProgress, o
63554
63631
  validLangs.push({ code, name: LANG_NAMES2[code] ?? code });
63555
63632
  }
63556
63633
  }
63557
- return { original, translations, translationPairs, practice, skip, languages: validLangs, sourceLang, translationLayout: layoutResult.layout };
63634
+ return { original, translations, translationPairs, practice, skip, languages: validLangs, sourceLang, translationLayout: layoutResult.layout, languageTarget };
63558
63635
  }
63559
63636
  function detectSourceLangByRule(readmeMd) {
63560
63637
  const total = Math.max(readmeMd.length, 1);
@@ -63632,7 +63709,7 @@ ${readmeExcerpt}
63632
63709
  ---` : "\uFF08\u65E0 README \u6587\u4EF6\uFF0C\u8BF7\u6839\u636E\u6587\u4EF6\u540D\u3001\u76EE\u5F55\u7ED3\u6784\u3001\u6587\u4EF6\u7C7B\u578B\u5224\u65AD\u539F\u6587\u8BED\u8A00\u548C\u6587\u4EF6\u89D2\u8272\uFF09";
63633
63710
  return `\u4F60\u662F\u8BFE\u7A0B\u4ED3\u5E93\u5206\u6790\u4E13\u5BB6\u3002\u4E0B\u9762\u662F\u4E00\u4E2A\u5B66\u4E60\u4ED3\u5E93\u7684 README\uFF08\u524D3000\u5B57\uFF09\u3001\u5B8C\u6574\u76EE\u5F55\u6811\u548C\u5F85\u5206\u7C7B\u7684\u6587\u4EF6\u5217\u8868\u3002
63634
63711
 
63635
- \u8BF7\u5B8C\u6210\u4E24\u4E2A\u4EFB\u52A1:
63712
+ \u8BF7\u5B8C\u6210\u4E09\u4E2A\u4EFB\u52A1:
63636
63713
 
63637
63714
  1. \u5224\u65AD README \u7684**\u539F\u6587\u8BED\u8A00**\uFF08\u4E0D\u662F\u7FFB\u8BD1\u8BED\u8A00\uFF09\u3002\u770B README \u6B63\u6587\u662F\u4EC0\u4E48\u8BED\u8A00\u5199\u7684:
63638
63715
  - \u82F1\u6587 \u2192 "en"
@@ -63649,6 +63726,15 @@ ${readmeExcerpt}
63649
63726
  \u548C "translates"(\u5B83\u7FFB\u8BD1\u7684\u539F\u6587\u6587\u4EF6\u8DEF\u5F84\uFF0C\u5FC5\u987B\u662F\u6587\u4EF6\u5217\u8868\u6216\u76EE\u5F55\u6811\u91CC\u771F\u5B9E\u5B58\u5728\u7684\u6587\u4EF6)
63650
63727
  - **skip**: \u566A\u58F0\uFF08\u7EAF\u914D\u7F6E\u3001\u7A7A\u6587\u4EF6\u3001\u975E\u5B66\u4E60\u5185\u5BB9\uFF09
63651
63728
 
63729
+ 3. \u5224\u65AD\u8FD9\u4E2A\u4ED3\u5E93**\u662F\u4E0D\u662F\u8BED\u8A00\u5B66\u4E60\u8BFE\u7A0B**\u2014\u2014\u5373\u8BFE\u7A0B\u6559\u7684\u79D1\u76EE\u5C31\u662F\u4E00\u95E8\u8BED\u8A00\u672C\u8EAB\uFF08\u6559\u82F1\u8BED/\u65E5\u8BED/\u97E9\u8BED/\u4E2D\u6587\u2026\u7684
63730
+ \u8BCD\u6C47\u3001\u8BED\u6CD5\u3001\u542C\u8BF4\u8BFB\u5199\uFF09\uFF0C\u800C\u4E0D\u662F"\u7528\u67D0\u79CD\u8BED\u8A00\u5199\u7684\u77E5\u8BC6/\u6280\u672F\u6559\u7A0B"\u3002\u4F9D\u636E README \u4E0E\u76EE\u5F55\u6811\u7684\u660E\u663E\u7279\u5F81:
63731
+ - \u662F\u8BED\u8A00\u8BFE \u2192 "languageTarget" \u586B**\u88AB\u6559\u7684\u90A3\u95E8\u8BED\u8A00**\u7684 BCP-47 \u7801\uFF08\u6559\u82F1\u8BED \u2192 "en"\uFF0C\u6559\u65E5\u8BED \u2192 "ja"\u2026\uFF09\u3002
63732
+ \u6CE8\u610F:\u6559\u6750\u7684\u4E66\u5199\u8BED\u8A00\u4E0D\u7B49\u4E8E\u88AB\u6559\u7684\u8BED\u8A00\u2014\u2014\u4E2D\u6587\u5199\u7684\u82F1\u8BED\u6559\u6750\u4ED3\u5E93\uFF0ClanguageTarget \u662F "en"
63733
+ - \u8BED\u8A00\u8BFE\u7684\u5178\u578B\u7279\u5F81: \u8BCD\u6C47\u8868/\u8BCD\u6839\u8BCD\u7F00\u3001\u8BED\u6CD5\u70B9\u8BB2\u89E3\u3001\u5BF9\u8BDD/\u8BFE\u6587\u3001\u53E5\u5B50-\u7FFB\u8BD1\u5BF9\u3001
63734
+ \u6C34\u5E73\u5206\u7EA7\u6807\u8BB0\uFF08N5/N1\u3001TOEFL/IELTS\u3001HSK\u3001JLPT\u2026\uFF09\u3001\u53D1\u97F3/\u97F3\u6807\u5185\u5BB9
63735
+ - \u4E0D\u662F\u8BED\u8A00\u8BFE\uFF08\u7F16\u7A0B/\u6570\u5B66/\u79D1\u5B66\u6559\u7A0B\u3001\u7528\u82F1\u6587\u5199\u7684\u6280\u8853\u6587\u6863\u7B49\uFF09\u2192 "languageTarget": null
63736
+ - \u5224\u65AD\u4E0D\u51C6\u65F6\u503E\u5411 null\uFF08\u5B81\u53EF\u6309\u666E\u901A\u8BFE\u7A0B\u5904\u7406\uFF0C\u4E0D\u53EF\u628A\u666E\u901A\u8BFE\u7A0B\u5F53\u8BED\u8A00\u8BFE\uFF09
63737
+
63652
63738
  ${readmeSection}
63653
63739
 
63654
63740
  \u4ED3\u5E93\u5B8C\u6574\u76EE\u5F55\u6811\uFF08\u6811\u72B6\u7ED3\u6784\uFF0C\u6700\u591A\u5C55\u5F00 3 \u5C42\uFF0C\u6BCF\u76EE\u5F55\u6700\u591A 10 \u9879\uFF0C\u8D85\u51FA\u6298\u53E0\uFF09:
@@ -63675,6 +63761,7 @@ ${fileList}
63675
63761
  \u4E25\u683C\u8FD4\u56DE\u5982\u4E0B\u5F62\u72B6\u7684 JSON \u5BF9\u8C61:
63676
63762
  {
63677
63763
  "sourceLang": "en",
63764
+ "languageTarget": null,
63678
63765
  "files": [
63679
63766
  { "path": "lessons/1-Intro/README.md", "role": "original" },
63680
63767
  { "path": "lessons/2-Symbolic/Animals.ipynb", "role": "practice" },
@@ -63691,11 +63778,13 @@ function parseRoleResult(raw, validPaths) {
63691
63778
  } catch {
63692
63779
  return {
63693
63780
  sourceLang: "",
63781
+ languageTarget: null,
63694
63782
  files: validPaths.map((p) => ({ path: p, role: "original" })),
63695
63783
  degraded: true
63696
63784
  };
63697
63785
  }
63698
63786
  let sourceLang = "";
63787
+ let languageTarget = null;
63699
63788
  let filesRaw;
63700
63789
  if (Array.isArray(obj)) {
63701
63790
  filesRaw = obj;
@@ -63703,9 +63792,11 @@ function parseRoleResult(raw, validPaths) {
63703
63792
  const o = obj;
63704
63793
  if (typeof o.sourceLang === "string")
63705
63794
  sourceLang = o.sourceLang;
63795
+ if (typeof o.languageTarget === "string" && o.languageTarget.trim())
63796
+ languageTarget = o.languageTarget.trim();
63706
63797
  filesRaw = o.files;
63707
63798
  } else {
63708
- return { sourceLang: "", files: validPaths.map((p) => ({ path: p, role: "original" })), degraded: true };
63799
+ return { sourceLang: "", languageTarget: null, files: validPaths.map((p) => ({ path: p, role: "original" })), degraded: true };
63709
63800
  }
63710
63801
  const validSet = new Set(validPaths);
63711
63802
  const files = filesRaw.filter((item) => typeof item.path === "string" && validSet.has(item.path)).map((item) => ({
@@ -63715,7 +63806,7 @@ function parseRoleResult(raw, validPaths) {
63715
63806
  lang: typeof item.lang === "string" ? item.lang : void 0,
63716
63807
  translates: typeof item.translates === "string" ? item.translates : void 0
63717
63808
  }));
63718
- return { sourceLang, files, degraded: false };
63809
+ return { sourceLang, languageTarget, files, degraded: false };
63719
63810
  }
63720
63811
  async function classifyFilesResilient(files, deps) {
63721
63812
  const attempt = async (chunk) => {
@@ -63738,6 +63829,7 @@ async function classifyFilesResilient(files, deps) {
63738
63829
  const right = await recurse(chunk.slice(mid));
63739
63830
  return {
63740
63831
  sourceLang: left.sourceLang || right.sourceLang,
63832
+ languageTarget: left.languageTarget ?? right.languageTarget,
63741
63833
  files: [...left.files, ...right.files],
63742
63834
  degraded: false
63743
63835
  };
@@ -532974,7 +533066,8 @@ function rolesToPlan(r) {
532974
533066
  translationPairs: Object.fromEntries(r.translationPairs),
532975
533067
  languages: r.languages,
532976
533068
  sourceLang: r.sourceLang,
532977
- translationLayout: r.translationLayout
533069
+ translationLayout: r.translationLayout,
533070
+ languageTarget: r.languageTarget
532978
533071
  };
532979
533072
  }
532980
533073
  function planToRoles(p) {
@@ -532986,7 +533079,9 @@ function planToRoles(p) {
532986
533079
  translationPairs: new Map(Object.entries(p.translationPairs)),
532987
533080
  languages: p.languages,
532988
533081
  sourceLang: p.sourceLang,
532989
- translationLayout: p.translationLayout
533082
+ translationLayout: p.translationLayout,
533083
+ // 旧版快照无此字段 → undefined,统一压成 null(非语言课,现状行为)
533084
+ languageTarget: p.languageTarget ?? null
532990
533085
  };
532991
533086
  }
532992
533087
  function filterClassificationToTree(p, tree) {
@@ -533348,10 +533443,10 @@ ${(entries3[0]?.[1] ?? "").slice(0, 2e3)}`;
533348
533443
  let roles;
533349
533444
  if (plan.classification) {
533350
533445
  roles = planToRoles(plan.classification);
533351
- send(`\u2713 \u6587\u4EF6\u5206\u7C7B:\u590D\u7528\u5FEB\u7167(${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang})`);
533446
+ send(`\u2713 \u6587\u4EF6\u5206\u7C7B:\u590D\u7528\u5FEB\u7167(${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang}${roles.languageTarget ? ` \xB7 \u8BED\u8A00\u8BFE ${roles.languageTarget}` : ""})`);
533352
533447
  } else {
533353
533448
  roles = await (deps.classify ?? classifyFileRoles)(db, readmeMd, fileList, fullTree, send, { signal: cancelCtl.signal });
533354
- send(`\u2713 \u6587\u4EF6\u5206\u7C7B:${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 ${roles.skip.length} \u8DF3\u8FC7 \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang}`);
533449
+ send(`\u2713 \u6587\u4EF6\u5206\u7C7B:${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 ${roles.skip.length} \u8DF3\u8FC7 \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang}${roles.languageTarget ? ` \xB7 \u8BED\u8A00\u8BFE ${roles.languageTarget}` : ""}`);
533355
533450
  plan.classification = rolesToPlan(roles);
533356
533451
  plan.reachedStep = 2;
533357
533452
  savePlan();
@@ -533423,6 +533518,7 @@ ${(entries3[0]?.[1] ?? "").slice(0, 2e3)}`;
533423
533518
  translationPairs: roles.translationPairs,
533424
533519
  sourceLang: roles.sourceLang,
533425
533520
  translationLayout: roles.translationLayout,
533521
+ languageTarget: roles.languageTarget,
533426
533522
  shouldAbort,
533427
533523
  markDirty: markDirty2
533428
533524
  },
@@ -561229,33 +561325,67 @@ function localeToLanguageName(locale) {
561229
561325
  function isZhLocale(locale) {
561230
561326
  return locale.toLowerCase().startsWith("zh");
561231
561327
  }
561232
- function buildLanguageDirective(locale) {
561328
+ function buildLanguageDirective(locale, targetLang) {
561233
561329
  const name19 = localeToLanguageName(locale);
561234
561330
  if (isZhLocale(locale)) {
561235
- return "\u7528\u6E05\u6670\u3001\u9F13\u52B1\u7684\u4E2D\u6587\u56DE\u7B54\u3002\u5F53\u5B66\u4E60\u8005\u7B54\u9519\u65F6\uFF0C\u5148\u80AF\u5B9A\u5C1D\u8BD5\u518D\u7EA0\u6B63\u3002";
561236
- }
561237
- return `Always respond in ${name19}. This applies to every word you output, tool-call parameters included (quiz prompts, options, explanations, guess questions). Be clear and encouraging; when the learner gets something wrong, acknowledge the attempt first, then correct it.`;
561331
+ const base2 = "\u7528\u6E05\u6670\u3001\u9F13\u52B1\u7684\u4E2D\u6587\u56DE\u7B54\u3002\u5F53\u5B66\u4E60\u8005\u7B54\u9519\u65F6\uFF0C\u5148\u80AF\u5B9A\u5C1D\u8BD5\u518D\u7EA0\u6B63\u3002";
561332
+ if (!targetLang)
561333
+ return base2;
561334
+ const t2 = localeToLanguageName(targetLang);
561335
+ return base2 + `\u8FD9\u662F\u4E00\u95E8${t2}\u5B66\u4E60\u8BFE\u7A0B:\u8BB2\u89E3\u3001\u6307\u4EE4\u3001\u53CD\u9988\u7528\u4E2D\u6587,\u4F46\u8BFE\u6587\u5F15\u7528\u3001\u4F8B\u53E5\u3001\u9898\u76EE\u4E2D\u7684\u8BED\u8A00\u7D20\u6750\u5FC5\u987B\u4FDD\u6301${t2}\u539F\u6587\u2014\u2014\u4E0D\u8981\u628A\u76EE\u6807\u8BED\u8A00\u6750\u6599\u7FFB\u8BD1\u6210\u4E2D\u6587\u6765\u8BB2\u89E3\u6216\u51FA\u9898(\u751F\u8BCD\u53EF\u9644\u4E2D\u6587\u6CE8\u91CA)\u3002`;
561336
+ }
561337
+ const base = `Always respond in ${name19}. This applies to every word you output, tool-call parameters included (quiz prompts, options, explanations, guess questions). Be clear and encouraging; when the learner gets something wrong, acknowledge the attempt first, then correct it.`;
561338
+ if (!targetLang)
561339
+ return base;
561340
+ const t = localeToLanguageName(targetLang);
561341
+ return base + ` This course teaches ${t}: your explanations and instructions stay in ${name19}, but reading passages, example sentences, and quiz language material must remain in original ${t} \u2014 never translate target-language material into ${name19} to teach or quiz (gloss unfamiliar words sparingly).`;
561238
561342
  }
561239
561343
  function resolveOutputLang(explicit) {
561240
561344
  if (explicit && explicit.trim())
561241
561345
  return explicit;
561242
561346
  return "zh-CN";
561243
561347
  }
561244
- function questionLanguageLine(locale) {
561348
+ function questionLanguageLine(locale, targetLang) {
561245
561349
  const name19 = localeToLanguageName(locale);
561246
- if (isZhLocale(locale))
561247
- return "- \u9898\u5E72\u548C\u9009\u9879\u7528\u4E2D\u6587,\u6E05\u6670\u65E0\u6B67\u4E49";
561248
- return `- Write the question stem and options in ${name19}, clear and unambiguous`;
561350
+ if (isZhLocale(locale)) {
561351
+ if (!targetLang)
561352
+ return "- \u9898\u5E72\u548C\u9009\u9879\u7528\u4E2D\u6587,\u6E05\u6670\u65E0\u6B67\u4E49";
561353
+ const t2 = localeToLanguageName(targetLang);
561354
+ return `- \u8FD9\u662F${t2}\u8BED\u8A00\u5B66\u4E60\u6D4B\u9A8C:\u9898\u5E72\u548C\u9009\u9879\u4E2D\u7684\u8BED\u8A00\u7D20\u6750(\u53E5\u5B50/\u5355\u8BCD/\u77ED\u8BED/\u8BED\u6CD5\u70B9)\u7528${t2}\u539F\u6587\u51FA\u9898,\u6307\u4EE4\u6027\u6587\u5B57\u548C\u89E3\u6790\u7528\u4E2D\u6587`;
561355
+ }
561356
+ if (!targetLang)
561357
+ return `- Write the question stem and options in ${name19}, clear and unambiguous`;
561358
+ const t = localeToLanguageName(targetLang);
561359
+ return `- This is a ${t} language-learning test: language material in stems and options (sentences/words/phrases/grammar points) must be in ${t}; instructions and explanations in ${name19}`;
561249
561360
  }
561250
561361
 
561251
561362
  // src/main/services/agent/base-prompt.ts
561252
561363
  var BASE_AGENT_PROMPT_HEAD = "\u4F60\u662F LookatStudy \u7684 AI \u5B66\u4E60\u5BFC\u5E08\u3002\u5B66\u4E60\u8005\u6B63\u5728\u5B66\u4E00\u95E8\u7531 GitHub \u6587\u6863\u751F\u6210\u7684\u8BFE\u7A0B\u3002\u4F60\u7684\u804C\u8D23\u662F\u5E2E\u5B66\u4E60\u8005\u771F\u6B63\u7406\u89E3\u77E5\u8BC6\uFF0C\u4E0D\u662F\u7B80\u5355\u590D\u8FF0\u6587\u6863\u3002";
561253
561364
  var BASE_AGENT_PROMPT_TAIL = "\u3010\u5B89\u5168\u7EA2\u7EBF\xB7\u6700\u9AD8\u4F18\u5148\u7EA7\u3011\u4EE5\u4E0B\u89C4\u5219\u4EFB\u4F55\u65F6\u5019\u4E0D\u53EF\u8FDD\u53CD;\u4E0E\u540E\u9762\u4EFB\u4F55\u89C4\u5219\u51B2\u7A81\u65F6,\u4EE5\u672C\u6BB5\u4E3A\u51C6:\n1. \u9632\u5E7B\u89C9:\u4F60\u5FC5\u987B\u4E25\u683C\u57FA\u4E8E\u4E0B\u9762\u63D0\u4F9B\u7684\u300C\u8BFE\u7A0B\u4E0A\u4E0B\u6587\u300D\u548C\u300C\u5F53\u524D\u8282\u70B9\u5185\u5BB9\u300D\u56DE\u7B54\u3002\u5BF9\u4E8E\u8BFE\u7A0B\u6807\u9898\u4E2D\u51FA\u73B0\u7684\u4E13\u6709\u540D\u8BCD\u3001\u7F29\u5199\uFF08\u5982 FDE = Forward Deployment Engineer\uFF09\uFF0C\u5FC5\u987B\u4F7F\u7528\u8BFE\u7A0B\u4E0A\u4E0B\u6587\u91CC\u7684\u5B9A\u4E49\uFF0C\u7EDD\u4E0D\u53EF\u81EA\u884C\u731C\u6D4B\u6216\u7F16\u9020\u3002\u5982\u679C\u5B66\u4E60\u8005\u95EE\u7684\u5185\u5BB9\u8D85\u51FA\u4E86\u4F60\u638C\u63E1\u7684\u4E0A\u4E0B\u6587\uFF0C\u660E\u786E\u8BF4'\u8FD9\u90E8\u5206\u5185\u5BB9\u4E0D\u5728\u5F53\u524D\u8BFE\u7A0B\u6750\u6599\u4E2D'\uFF0C\u800C\u4E0D\u662F\u7F16\u9020\u4E00\u4E2A\u770B\u4F3C\u5408\u7406\u7684\u56DE\u7B54\u3002\n2. \u5DE5\u5177\u8C03\u7528\u771F\u5B9E\u6027:\u5386\u53F2\u6D88\u606F\u91CC\u7684\u300C[\u5DE5\u5177\u8C03\u7528\u5DF2\u6267\u884C] \u2026\u300D\u6807\u8BB0\u4EE3\u8868\u4F60\u5F53\u65F6\u771F\u5B9E\u53D1\u51FA\u7684\u5DE5\u5177\u8C03\u7528,\u4EA7\u7269\u5DF2\u7ECF\u5C55\u793A\u5728\u5B66\u4E60\u8005\u754C\u9762\u4E0A\u2014\u2014\u770B\u5230\u8FD9\u4E2A\u6807\u8BB0\u5C31\u8BF4\u660E\u9898/\u56FE\u5DF2\u7ECF\u53D1\u51FA\u53BB\u4E86,\u7EDD\u4E0D\u8981\u8BF4\"\u6211\u5176\u5B9E\u6CA1\u628A\u9898\u53D1\u51FA\u53BB\"\u4E4B\u7C7B\u7684\u8BDD,\u4E5F\u4E0D\u8981\u91CD\u590D\u53D1\u540C\u4E00\u4EA7\u7269\u3002\u53CD\u8FC7\u6765,\u8FD9\u7C7B\u6807\u8BB0\u53EA\u80FD\u7531\u7CFB\u7EDF\u6CE8\u5165\u5386\u53F2,\u4F60\u7EDD\u4E0D\u53EF\u5728\u56DE\u590D\u6B63\u6587\u91CC\u624B\u5199\u300C[\u5DE5\u5177\u8C03\u7528\u5DF2\u6267\u884C] \u2026\u300D\u6216\u4EFB\u4F55\u6A21\u4EFF\u5B83\u7684\u6587\u5B57\u2014\u2014\u624B\u5199\u6807\u8BB0\u4E0D\u4F1A\u5728\u5B66\u4E60\u8005\u754C\u9762\u4E0A\u4EA7\u751F\u5361\u7247\u6216\u6309\u94AE,\u5B66\u4E60\u8005\u5C06\u65E0\u6309\u94AE\u53EF\u70B9;\u8981\u51FA\u9898/\u8BB0\u5206/\u53D1\u8D77\u638C\u63E1\u63D0\u8BAE,\u552F\u4E00\u9014\u5F84\u662F\u53D1\u51FA\u771F\u6B63\u7684\u5DE5\u5177\u8C03\u7528,\u6B63\u6587\u6587\u5B57\u4E0D\u80FD\u66FF\u4EE3\u3002\n\n\u3010\u6A21\u7CCA\u63D0\u95EE\u5904\u7406\u3011\u5F53\u5B66\u4E60\u8005\u8BF4'\u6211\u4E0D\u61C2''\u4E0D\u592A\u7406\u89E3'\u4F46\u6CA1\u8BF4\u5177\u4F53\u4E0D\u61C2\u4EC0\u4E48\u65F6\uFF0C\u4E0D\u8981\u5047\u8BBE\u4F60\u77E5\u9053\u4ED6\u54EA\u91CC\u4E0D\u61C2\u7136\u540E\u957F\u7BC7\u5927\u8BBA\u3002\u5148\u53CD\u95EE'\u4F60\u5177\u4F53\u662F\u54EA\u4E2A\u6982\u5FF5\u4E0D\u592A\u6E05\u695A\uFF1F'\uFF0C\u6216\u8005\u5217\u51FA\u8FD9\u8BFE\u6D89\u53CA\u7684 2-3 \u4E2A\u6838\u5FC3\u6982\u5FF5\u8BA9\u4ED6\u9009\u3002\u53EA\u8BB2\u89E3\u5B66\u4E60\u8005\u660E\u786E\u95EE\u5230\u7684\u90E8\u5206\uFF0C\u4E0D\u8981\u4E3B\u52A8\u6269\u5C55\u5230\u8BFE\u7A0B\u5185\u5BB9\u4E4B\u5916\u7684\u9886\u57DF\u77E5\u8BC6\u3002\n\n\u3010\u6559\u5B66\u5DE5\u5177\u4F7F\u7528\u3011\u4F60\u6709\u51E0\u4E2A\u80FD\u751F\u6210\u53EF\u89C6\u5316\u5B66\u4E60\u4EA7\u7269\u3001\u8BB0\u5F55\u5B66\u4E60\u72B6\u6001\u7684\u5DE5\u5177\uFF0C\u9002\u65F6\u4F7F\u7528\u80FD\u5927\u5E45\u63D0\u5347\u7406\u89E3\uFF1A- show_concept_map:\u7406\u6E05\u6982\u5FF5\u95F4\u5173\u7CFB(\u67B6\u6784/\u4F9D\u8D56/\u5206\u7C7B),\u5B66\u4E60\u8005\u8BF4'\u7406\u4E0D\u6E05''\u6709\u4EC0\u4E48\u5173\u7CFB'\u65F6\u7528;- generate_quiz:\u51FA\u9898\u68C0\u9A8C,\u5B66\u4E60\u8005\u8BF4'\u8003\u8003\u6211''\u51FA\u9898'\u65F6,\u6216\u8BB2\u5B8C\u4E00\u8282\u4E3B\u52A8\u51FA 2-3 \u9898\u5DE9\u56FA;- compare_table:\u5BF9\u6BD4 A vs B,\u5B66\u4E60\u8005\u95EE'\u533A\u522B''\u5BF9\u6BD4'\u65F6\u7528;- draw_diagram:\u753B\u6D41\u7A0B/\u65F6\u5E8F/\u72B6\u6001\u56FE,\u8BB2\u6D41\u7A0B\u7C7B\u5185\u5BB9\u65F6\u7528;- show_code_walkthrough:\u9010\u6BB5\u8BB2\u89E3\u4EE3\u7801,\u5B66\u4E60\u8005\u95EE'\u8FD9\u6BB5\u4EE3\u7801'\u65F6\u7528\u3002- pose_guess:\u629B\u4E00\u4E2A\u4E8C\u9009\u4E00\u731C\u6D4B(\u662F'\u731C'/\u73A9,\u4E0D\u8BA1\u5206\u3001\u4E0D\u662F\u8003),\u5B66\u4E60\u8005\u6CA1\u52B2/\u9700\u8981\u88AB\u52FE\u4F4F\u65F6\u7528\u2014\u2014\u914D\u5408\u4E00\u4E24\u53E5\u94A9\u5B50\u628A\u4EBA\u5E26\u8FDB\u6765,\u4ED6\u731C\u5B8C\u4F60\u4E0B\u4E00\u56DE\u5408\u518D\u63ED\u6653\u3002\u8D77\u624B\u5F0F\u4E13\u7528,\u522B\u5F53\u6D4B\u9A8C\u7528\u3002- record_answer:\u628A\u5B66\u4E60\u8005\u7684\u7B54\u9898\u7ED3\u679C\u8BB0\u5165\u638C\u63E1\u5EA6\u8FFD\u8E2A(\u5BF9/\u9519+\u7406\u7531),\u5B66\u4E60\u8005\u7B54\u5B8C\u9898\u4F60\u5224\u5206\u65F6\u7528\u3002- mark_mastered:\u63D0\u8BAE\u628A\u5F53\u524D\u8282\u70B9\u6807\u8BB0\u4E3A\u5DF2\u638C\u63E1\u2014\u2014\u591A\u7EF4\u5EA6\u9A8C\u8BC1\u9F50\u4E86\u3001\u4F60\u5224\u5B9A\u53EF\u4EE5\u6536\u5C3E\u65F6\u8C03\u7528,\u5B66\u4E60\u8005\u754C\u9762\u4F1A\u51FA\u73B0\u786E\u8BA4\u5361\u7247,\u4ED6\u53EF\u4EE5\u62D2\u7EDD;\u5148\u5728\u6B63\u6587\u8BF4\u6E05\u5224\u5B9A\u4F9D\u636E,\u7136\u540E\u8C03\u7528\u5DE5\u5177\u3002\u5DE5\u5177\u662F\u624B\u6BB5\u4E0D\u662F\u76EE\u7684:\u80FD\u7528\u5DE5\u5177\u8BA9\u77E5\u8BC6\u66F4\u6E05\u6670\u5C31\u7528,\u5426\u5219\u6B63\u5E38\u6587\u5B57\u8BB2\u89E3\u5373\u53EF\u3002\u4E00\u6B21\u56DE\u590D\u6700\u591A\u7528 1 \u4E2A\u5DE5\u5177,\u907F\u514D\u8FC7\u8F7D\u3002\n\n\u3010\u56DE\u7B54\u6392\u7248\xB7\u504F\u597D\u7EA7\u3011\u4F60\u7684\u56DE\u7B54\u652F\u6301\u5B8C\u6574 Markdown \u6E32\u67D3(\u6807\u9898/\u5217\u8868/\u8868\u683C/\u4EE3\u7801\u5757/\u5F15\u7528/\u7C97\u659C\u4F53),\u5728\u4E0D\u8FDD\u53CD\u4E0A\u9762\u7EA2\u7EBF\u4E0E\u884C\u4E3A\u89C4\u5219\u7684\u524D\u63D0\u4E0B,\u5145\u5206\u5229\u7528\u7ED3\u6784\u5316\u6392\u7248\u8BA9\u5185\u5BB9\u66F4\u6613\u8BFB:- \u7528 ##/### \u5212\u5206\u6BB5\u843D,\u4E0D\u8981\u4E00\u6574\u5757\u6587\u5B57;- \u5E76\u5217\u8981\u70B9\u7528\u65E0\u5E8F\u5217\u8868(- ),\u6709\u987A\u5E8F\u7684\u6B65\u9AA4\u7528\u6709\u5E8F\u5217\u8868(1. );- \u5BF9\u6BD4\u3001\u5C5E\u6027\u3001\u89C4\u683C\u7528 GFM \u8868\u683C(| \u52171 | \u52172 |),\u4E0D\u8981\u5806\u6587\u5B57;- \u91CD\u8981\u7ED3\u8BBA\u7528 **\u7C97\u4F53**,\u672F\u8BED\u9996\u6B21\u51FA\u73B0\u7528 *\u659C\u4F53*;- \u547D\u4EE4/\u4EE3\u7801/\u6587\u4EF6\u540D\u7528 `\u884C\u5185\u4EE3\u7801`,\u591A\u884C\u4EE3\u7801\u7528 ```language \u4EE3\u7801\u5757;- \u63D0\u793A\u3001\u8B66\u544A\u3001\u8865\u5145\u8BF4\u660E\u7528 > \u5F15\u7528\u5757;- \u907F\u514D\u957F\u6BB5\u843D(\u8D85\u8FC7 4 \u884C\u5C31\u8003\u8651\u62C6\u5206\u6216\u8F6C\u5217\u8868)\u3002\u597D\u7684\u6392\u7248 = \u5B66\u4E60\u8005\u66F4\u5BB9\u6613\u6293\u4F4F\u91CD\u70B9,\u8FD9\u662F\u6559\u5B66\u6548\u679C\u7684\u4E00\u90E8\u5206\u3002";
561254
- function buildBaseAgentPrompt(locale) {
561365
+ function buildBaseAgentPrompt(locale, targetLang) {
561366
+ const targetBlock = buildLanguageTeachingBlock(locale, targetLang);
561367
+ if (isZhLocale(locale)) {
561368
+ return BASE_AGENT_PROMPT_HEAD + buildLanguageDirective(locale, targetLang) + (targetBlock ? "\n\n" + targetBlock : "") + "\n\n" + BASE_AGENT_PROMPT_TAIL;
561369
+ }
561370
+ return BASE_AGENT_PROMPT_HEAD_EN + buildLanguageDirective(locale, targetLang) + (targetBlock ? "\n\n" + targetBlock : "") + "\n\n" + BASE_AGENT_PROMPT_TAIL_EN;
561371
+ }
561372
+ function buildLanguageTeachingBlock(locale, targetLang) {
561373
+ if (!targetLang)
561374
+ return null;
561375
+ const t = localeToLanguageName(targetLang);
561255
561376
  if (isZhLocale(locale)) {
561256
- return BASE_AGENT_PROMPT_HEAD + buildLanguageDirective(locale) + "\n\n" + BASE_AGENT_PROMPT_TAIL;
561377
+ return `\u3010\u8BED\u8A00\u6559\u5B66\u59FF\u6001\u3011\u8FD9\u95E8\u8BFE\u7A0B\u6559\u7684\u662F${t}\u2014\u2014\u4E2D\u6587\u662F\u6559\u5B66\u8BED\u8A00,${t}\u662F\u5B66\u4E60\u5BF9\u8C61:
561378
+ - \u8BB2\u89E3\u3001\u6307\u4EE4\u3001\u53CD\u9988\u4E00\u5F8B\u7528\u4E2D\u6587;\u8BFE\u6587\u5F15\u7528\u3001\u4F8B\u53E5\u3001\u9898\u76EE\u7D20\u6750\u4FDD\u6301${t}\u539F\u6587,\u8003\u5BDF\u76EE\u6807\u8BED\u8A00\u672C\u8EAB;
561379
+ - \u5B66\u4E60\u8005\u7528${t}\u9020\u53E5\u6216\u8868\u8FBE\u65F6,\u5148\u80AF\u5B9A\u518D\u7EA0\u6B63\u5176\u4E2D\u7684\u8BED\u8A00\u9519\u8BEF(\u8BED\u6CD5/\u7528\u8BCD/\u62FC\u5199),\u7528\u4E2D\u6587\u8BB2\u6E05\u9519\u5728\u54EA;
561380
+ - \u65B0\u8BCD\u9996\u6B21\u51FA\u73B0\u53EF\u9644\u4E2D\u6587\u6CE8\u91CA,\u6CE8\u91CA\u662F\u8F85\u52A9\u4E0D\u662F\u66FF\u4EE3\u2014\u2014\u4E0D\u8981\u6574\u6BB5\u7ED9\u51FA\u4E2D\u6587\u7FFB\u8BD1;
561381
+ - \u968F\u638C\u63E1\u5EA6\u4E0A\u5347,\u6E10\u8FDB\u63D0\u9AD8${t}\u7D20\u6750\u7684\u5360\u6BD4,\u628A\u5B66\u4E60\u8005\u5F80"\u76F4\u63A5\u7528${t}\u8BFB"\u5E26\u3002`;
561257
561382
  }
561258
- return BASE_AGENT_PROMPT_HEAD_EN + buildLanguageDirective(locale) + "\n\n" + BASE_AGENT_PROMPT_TAIL_EN;
561383
+ const name19 = localeToLanguageName(locale);
561384
+ return `[Language-teaching posture] This course teaches ${t} \u2014 ${name19} is the medium of instruction, ${t} is the subject:
561385
+ - Explanations, instructions, and feedback in ${name19}; quoted passages, example sentences, and quiz material stay in ${t}, testing the target language itself;
561386
+ - When the learner writes in ${t}, acknowledge the attempt first, then correct language errors (grammar/word choice/spelling), explaining the reason in ${name19};
561387
+ - Gloss new words on first appearance \u2014 a gloss is an aid, not a substitute; never hand out full translations of passages;
561388
+ - Raise the share of ${t} material as mastery grows, guiding the learner toward reading ${t} directly.`;
561259
561389
  }
561260
561390
  var BASE_AGENT_PROMPT_HEAD_EN = "You are LookatStudy's AI learning tutor. The learner is studying a course generated from a GitHub repository. Your job is to help them genuinely understand the material, not to paraphrase the docs.";
561261
561391
  var BASE_AGENT_PROMPT_TAIL_EN = `SAFETY RED LINES \u2014 TOP PRIORITY. The following rules must never be violated; whenever they conflict with any later rule, this section prevails:
@@ -561927,12 +562057,16 @@ function extractInlineDataImages(content) {
561927
562057
  return out;
561928
562058
  }
561929
562059
  function assembleContextBlocks(db, nodeId, locale) {
561930
- const outLang = resolveOutputLang(locale);
561931
- const system = buildSystemPrompt(db, buildBaseAgentPrompt(outLang), buildSoulLangReminder(outLang));
561932
562060
  const node = db.select().from(contentNodes).where(eq(contentNodes.id, nodeId)).get();
561933
562061
  const nodeProgress = db.select().from(progress).where(eq(progress.nodeId, nodeId)).get();
561934
562062
  const courseId = node?.courseId;
561935
562063
  const course = courseId ? db.select().from(courses).where(eq(courses.id, courseId)).get() : null;
562064
+ const outLang = resolveOutputLang(locale);
562065
+ const system = buildSystemPrompt(
562066
+ db,
562067
+ buildBaseAgentPrompt(outLang, course?.languageTarget ?? null),
562068
+ buildSoulLangReminder(outLang)
562069
+ );
561936
562070
  const courseSections = courseId ? db.select().from(contentNodes).where(eq(contentNodes.courseId, courseId)).all().filter((n) => n.type === "section").sort((a, b) => a.orderIdx - b.orderIdx) : [];
561937
562071
  const courseOutline = courseSections.map((s) => ` - ${s.title}`).join("\n");
561938
562072
  const courseContext = course ? `\u8BFE\u7A0B\u6807\u9898\uFF1A${course.title}
@@ -563312,7 +563446,9 @@ async function generateExercise(db, nodeId, type, locale) {
563312
563446
  const exerciseType = !type || type === "fill_blank" ? "mcq" : type;
563313
563447
  const llm = resolveLlm(db);
563314
563448
  const outLang = resolveOutputLang(locale);
563315
- const prompt = buildGenerationPrompt(node.title, node.content ?? "(\u65E0\u5185\u5BB9\uFF0C\u57FA\u4E8E\u6807\u9898\u51FA\u9898)", exerciseType, outLang);
563449
+ const courseRow = node.courseId ? db.select().from(courses).where(eq(courses.id, node.courseId)).get() : void 0;
563450
+ const languageTarget = courseRow?.languageTarget ?? null;
563451
+ const prompt = buildGenerationPrompt(node.title, node.content ?? "(\u65E0\u5185\u5BB9\uFF0C\u57FA\u4E8E\u6807\u9898\u51FA\u9898)", exerciseType, outLang, languageTarget);
563316
563452
  const result = await generateText({
563317
563453
  model: llm.languageModel,
563318
563454
  prompt
@@ -563386,7 +563522,7 @@ function rowToExercise(row) {
563386
563522
  createdAt: row.createdAt
563387
563523
  };
563388
563524
  }
563389
- function buildGenerationPrompt(title, content, type, outLang) {
563525
+ function buildGenerationPrompt(title, content, type, outLang, languageTarget) {
563390
563526
  const typeSpec = {
563391
563527
  mcq: `\u51FA\u4E00\u9053\u56DB\u9009\u4E00\u9009\u62E9\u9898\u3002options \u662F 4 \u4E2A\u9009\u9879\u7684\u6570\u7EC4\uFF0Canswer \u662F\u6B63\u786E\u9009\u9879\u7684\u4E0B\u6807\uFF08"0"/"1"/"2"/"3"\uFF09\u3002
563392
563528
  \u5E72\u6270\u9879\u8BBE\u8BA1\u8981\u6C42\uFF1A\u57FA\u4E8E\u5B66\u4E60\u8005\u5E38\u72AF\u7684\u771F\u5B9E\u8BEF\u89E3\uFF08\u4E0D\u662F\u660E\u663E\u9519\u8BEF\u7684\u51D1\u6570\u9009\u9879\uFF09\uFF0C\u8BA9\u8BA4\u771F\u5B66\u8FC7\u7684\u4EBA\u80FD\u6392\u9664\uFF0C\u6CA1\u5B66\u61C2\u7684\u4EBA\u4F1A\u9009\u9519\u3002
@@ -563407,7 +563543,7 @@ function buildGenerationPrompt(title, content, type, outLang) {
563407
563543
  `\u51FA\u9898\u7EA2\u7EBF:`,
563408
563544
  `- \u7B54\u6848\u5FC5\u987B\u5728\u63D0\u4F9B\u7684\u5B66\u4E60\u5185\u5BB9\u4E2D\u6709\u4F9D\u636E\uFF0C\u4E0D\u53EF\u7F16\u9020\u5185\u5BB9\u91CC\u6CA1\u6709\u7684\u77E5\u8BC6`,
563409
563545
  `- \u6570\u5B66\u8868\u8FBE\u5F0F\u7528\u884C\u5185 $..$ \u6216\u884C\u95F4 $$..$$ \u7684 LaTeX \u8BB0\u6CD5\u4E66\u5199\uFF0C\u4E0D\u8981\u7528\u7EAF\u6587\u672C\u8FD1\u4F3C\uFF08\u754C\u9762\u4F1A\u6E32\u67D3\u6210\u516C\u5F0F\uFF09`,
563410
- questionLanguageLine(outLang),
563546
+ questionLanguageLine(outLang, languageTarget),
563411
563547
  `- \u5E72\u6270\u9879 plausible \u4F46 definitely wrong\uFF08\u4E0D\u80FD\u6709\u4E89\u8BAE\uFF09`,
563412
563548
  ``,
563413
563549
  `\u4E25\u683C\u6309\u4EE5\u4E0B JSON \u683C\u5F0F\u8FD4\u56DE\uFF0C\u4E0D\u8981\u52A0\u4EFB\u4F55 markdown \u4EE3\u7801\u5757\u6807\u8BB0\u3001\u4E0D\u8981\u89E3\u91CA\uFF1A`,
@@ -563688,6 +563824,8 @@ async function generateExamBank(db, examNodeId, locale) {
563688
563824
  setGenerating(examNodeId, kcs.length);
563689
563825
  const llm = resolveLlm(db);
563690
563826
  const outLang = resolveOutputLang(locale);
563827
+ const courseRow = node.courseId ? db.select().from(courses).where(eq(courses.id, node.courseId)).get() : void 0;
563828
+ const languageTarget = courseRow?.languageTarget ?? null;
563691
563829
  const collected = [];
563692
563830
  let lastError = null;
563693
563831
  let done = 0;
@@ -563697,7 +563835,7 @@ async function generateExamBank(db, examNodeId, locale) {
563697
563835
  const lessonContents = lessonIds.map((id) => db.select().from(contentNodes).where(eq(contentNodes.id, id)).get()).filter((l) => !!l).map((l) => ({ title: l.title, content: (l.content ?? "").slice(0, 800) }));
563698
563836
  for (let attempt = 0; attempt <= BATCH_RETRY; attempt++) {
563699
563837
  try {
563700
- const prompt = buildKcBatchPrompt(node.title, batch, lessonContents, outLang);
563838
+ const prompt = buildKcBatchPrompt(node.title, batch, lessonContents, outLang, languageTarget);
563701
563839
  const result = await generateText({ model: llm.languageModel, prompt });
563702
563840
  const parsed = parseExamJson(result.text.trim(), batch.quota, allowedKcs);
563703
563841
  if (!parsed.ok)
@@ -563902,7 +564040,7 @@ function accuracyToStars(accuracy) {
563902
564040
  return 1;
563903
564041
  return 0;
563904
564042
  }
563905
- function buildKcBatchPrompt(examTitle, batch, lessonContents, outLang) {
564043
+ function buildKcBatchPrompt(examTitle, batch, lessonContents, outLang, languageTarget) {
563906
564044
  const kcList = batch.kcs.map((k) => `- ${k.title}:${k.description || "(\u89C1\u4E0B\u65B9\u8BFE\u65F6\u5185\u5BB9)"}(\u6765\u81EA\u8BFE\u65F6\u300A${k.lessonTitle}\u300B)`).join("\n");
563907
564045
  const contentParts = lessonContents.map(
563908
564046
  (l, i) => `### ${i + 1}. ${l.title}
@@ -563925,7 +564063,7 @@ ${l.content || "(\u8BFE\u65F6\u65E0\u6B63\u6587)"}`
563925
564063
  `- \u5E72\u6270\u9879 plausible \u4F46 definitely wrong(\u57FA\u4E8E\u5B66\u4E60\u8005\u5E38\u72AF\u7684\u771F\u5B9E\u8BEF\u89E3)`,
563926
564064
  `- \u7B54\u6848\u5FC5\u987B\u5728\u63D0\u4F9B\u7684\u8BFE\u7A0B\u5185\u5BB9\u4E2D\u6709\u4F9D\u636E`,
563927
564065
  `- \u6570\u5B66\u8868\u8FBE\u5F0F\u7528\u884C\u5185 $..$ \u6216\u884C\u95F4 $$..$$ \u7684 LaTeX \u8BB0\u6CD5\u4E66\u5199,\u4E0D\u8981\u7528\u7EAF\u6587\u672C\u8FD1\u4F3C(\u754C\u9762\u4F1A\u6E32\u67D3\u6210\u516C\u5F0F)`,
563928
- questionLanguageLine(outLang),
564066
+ questionLanguageLine(outLang, languageTarget),
563929
564067
  ``,
563930
564068
  `\u4E25\u683C\u6309\u4EE5\u4E0B JSON \u683C\u5F0F\u8FD4\u56DE,\u4E0D\u8981\u52A0 markdown \u4EE3\u7801\u5757\u6807\u8BB0\u3001\u4E0D\u8981\u89E3\u91CA:`,
563931
564069
  `{`,
@@ -564162,7 +564300,7 @@ function registerCourseHandlers(deps) {
564162
564300
  const { classifyFileRoles: classifyFileRoles2 } = await Promise.resolve().then(() => (init_import_llm_service(), import_llm_service_exports));
564163
564301
  console.error("[import] Step 2: LLM \u6587\u4EF6\u89D2\u8272\u5206\u7C7B + \u539F\u6587\u8BED\u8A00\u5224\u65AD\u2026");
564164
564302
  const roles = await classifyFileRoles2(getDb(), inventory.readmeMd, inventory.fileList, inventory.fullTree, send);
564165
- send(`\u2713 \u6587\u4EF6\u5206\u7C7B: ${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 ${roles.skip.length} \u8DF3\u8FC7 \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang}`);
564303
+ send(`\u2713 \u6587\u4EF6\u5206\u7C7B: ${roles.original.length} \u539F\u6587 \xB7 ${roles.practice.length} \u5B9E\u64CD \xB7 ${roles.skip.length} \u8DF3\u8FC7 \xB7 \u539F\u6587\u8BED\u8A00 ${roles.sourceLang}${roles.languageTarget ? ` \xB7 \u8BED\u8A00\u8BFE ${roles.languageTarget}` : ""}`);
564166
564304
  console.error(`[import] Step 2 \u5B8C\u6210: ${roles.original.length} original, ${roles.practice.length} practice, ${roles.skip.length} skip, sourceLang=${roles.sourceLang}, ${roles.languages.length} \u7FFB\u8BD1\u8BED\u8A00`);
564167
564305
  const { getPrefLang: getPrefLang2, resolveImportLang: resolveImportLang2 } = await Promise.resolve().then(() => (init_lang_pref(), lang_pref_exports));
564168
564306
  const pref = getPrefLang2(getDb()) ?? "en";
@@ -564182,6 +564320,7 @@ function registerCourseHandlers(deps) {
564182
564320
  readmeMd: inventory.readmeMd,
564183
564321
  branch: inventory.branch,
564184
564322
  sourceLang: roles.sourceLang,
564323
+ languageTarget: roles.languageTarget,
564185
564324
  languages: roles.languages,
564186
564325
  selectedLang,
564187
564326
  importReason: reason,
@@ -564242,6 +564381,7 @@ function registerCourseHandlers(deps) {
564242
564381
  translationPairs: translationPairsMap,
564243
564382
  sourceLang: analysis.sourceLang,
564244
564383
  translationLayout: analysis.translationLayout,
564384
+ languageTarget: analysis.languageTarget,
564245
564385
  markDirty
564246
564386
  },
564247
564387
  send