chainlesschain 0.161.5 → 0.161.7

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 (140) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DGVHYt7m.js → AIOps-C06IYJkC.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-B3a-9Af9.js → ActionButton-Cq4f1js5.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-Bx3Oxl0X.js → Analytics-DyJsowHu.js} +1 -1
  7. package/src/assets/web-panel/assets/{AppLayout-BzejRYN2.js → AppLayout-DSFSWtOZ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-NY4P1SWh.js → Audit-C7y4wGzh.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DZq4lKGA.js → Backup-BxkJJwr5.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CdsLMh-s.js → BaseInput-BraWNP3N.js} +1 -1
  11. package/src/assets/web-panel/assets/Chat-BhZPLetb.js +7 -0
  12. package/src/assets/web-panel/assets/{Chat-D4oAhi11.css → Chat-IlrLB9ZV.css} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-C5XnHFiF.js → Checkbox-DuDAToKQ.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BKxq1Elq.js → Codegen-DWHT3ZCT.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-9_JZdhJl.js → Col-rZ1FbPeP.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-RjNSGqVo.js → Community-BHefT_qI.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-COZAt3WB.js → Compact-D68vLPVh.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-hk2sypg0.js → Compliance-cxmKFzWJ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-9CLNBbEQ.js → Cowork-Dzt1uT50.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cron-74hvFk4_.js → Cron-oWxj9K9p.js} +1 -1
  21. package/src/assets/web-panel/assets/{Crosschain-M_9qbH-m.js → Crosschain-C9UdRkm2.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-BOx1xBNu.js → DID-D5WEHKMO.js} +1 -1
  23. package/src/assets/web-panel/assets/{Dashboard-C3KfYy9t.js → Dashboard-dP1_OGh-.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-Buk4zcYG.js → Dropdown-C55GjQPR.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-96LSDwN_.js → Federation-oJxrz7TD.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-DY7VfLgy.js → FormItemContext-CeLP5Pvz.js} +1 -1
  27. package/src/assets/web-panel/assets/{Git-KCUcIFj0.js → Git-CWs6CrRt.js} +1 -1
  28. package/src/assets/web-panel/assets/{Governance--yT5V49L.js → Governance-wo9Gz6OK.js} +1 -1
  29. package/src/assets/web-panel/assets/{Inference-D0NeQyx6.js → Inference-75Ob1OAF.js} +1 -1
  30. package/src/assets/web-panel/assets/{KnowledgeGraph-DYRq64do.js → KnowledgeGraph-DNw3Xz30.js} +1 -1
  31. package/src/assets/web-panel/assets/{Logs-DHSi_Oi1.js → Logs-Bo7_f07I.js} +1 -1
  32. package/src/assets/web-panel/assets/{Marketplace-TT0gv-wI.js → Marketplace-Dm0yQkoQ.js} +1 -1
  33. package/src/assets/web-panel/assets/{McpTools-DfCzYzeM.js → McpTools-oh6SZgBB.js} +1 -1
  34. package/src/assets/web-panel/assets/{Memory-35QBk-VQ.js → Memory-DANDCrzX.js} +1 -1
  35. package/src/assets/web-panel/assets/{Mtc-Dvc-7WJs.js → Mtc-4D52E6FP.js} +1 -1
  36. package/src/assets/web-panel/assets/{MtcAudit-CzTgYL-a.js → MtcAudit-BmlorrLr.js} +1 -1
  37. package/src/assets/web-panel/assets/{NLProgramming-CrcJekBx.js → NLProgramming-DolGSSOm.js} +1 -1
  38. package/src/assets/web-panel/assets/{Notes-0B3NXKhh.js → Notes-BTyTq1Qk.js} +1 -1
  39. package/src/assets/web-panel/assets/{NotificationSettings-KlJUb1mE.js → NotificationSettings-Db1AaWp_.js} +1 -1
  40. package/src/assets/web-panel/assets/{Organization-COS-etp0.js → Organization-DC4RfB2j.js} +1 -1
  41. package/src/assets/web-panel/assets/{Overflow-Cy4-usEJ.js → Overflow-cYKtW74T.js} +1 -1
  42. package/src/assets/web-panel/assets/{P2P-C0_fKvmV.js → P2P-CY5dBoF-.js} +1 -1
  43. package/src/assets/web-panel/assets/{Permissions-C59VtMDt.js → Permissions-B-U6t8Wf.js} +1 -1
  44. package/src/assets/web-panel/assets/{Pipeline-BjFugIMn.js → Pipeline-a2pkdq6t.js} +1 -1
  45. package/src/assets/web-panel/assets/{Privacy-tAalWiJA.js → Privacy-ClgLdkPP.js} +1 -1
  46. package/src/assets/web-panel/assets/{ProjectSettings-CLRVvTkY.js → ProjectSettings-D4Fi9bEQ.js} +1 -1
  47. package/src/assets/web-panel/assets/{Projects-ByvwUl9Z.js → Projects-BiSWtWMm.js} +1 -1
  48. package/src/assets/web-panel/assets/{Providers-CP6aUtPG.js → Providers-ydpAao66.js} +1 -1
  49. package/src/assets/web-panel/assets/{QuickAsk-5wazQ8Rv.js → QuickAsk-Bg955QRg.js} +1 -1
  50. package/src/assets/web-panel/assets/{Recommend-Z-lSAvhS.js → Recommend-BqynHnTn.js} +1 -1
  51. package/src/assets/web-panel/assets/{Reputation-DaCrszi3.js → Reputation-B8xfdWQt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Row-BFHRFhrC.js → Row-D4zoYiqD.js} +1 -1
  53. package/src/assets/web-panel/assets/{RssFeed-61djI0cm.js → RssFeed-BI0FPtP6.js} +1 -1
  54. package/src/assets/web-panel/assets/{Search-B4DqaBN0.js → Search-BG975ISr.js} +1 -1
  55. package/src/assets/web-panel/assets/{Security-8BvDlsI4.js → Security-BObRR-p6.js} +1 -1
  56. package/src/assets/web-panel/assets/{Services-BOgC-V6e.js → Services-B2TScn1O.js} +1 -1
  57. package/src/assets/web-panel/assets/{Skeleton-DxGa2EcF.js → Skeleton-PYzlv5Fw.js} +1 -1
  58. package/src/assets/web-panel/assets/{Skills-DsHzWQAl.js → Skills-DbsTF84K.js} +1 -1
  59. package/src/assets/web-panel/assets/{Sla-3KdTHpSY.js → Sla-D8q9j9bo.js} +1 -1
  60. package/src/assets/web-panel/assets/{SpeechSettings-C8xEI_J4.js → SpeechSettings-CjjNbmVH.js} +1 -1
  61. package/src/assets/web-panel/assets/{SyncSettings-BrTgn_a6.js → SyncSettings-UEp5lB2T.js} +1 -1
  62. package/src/assets/web-panel/assets/{Tasks-BsatF04-.js → Tasks-CoCW4gWI.js} +1 -1
  63. package/src/assets/web-panel/assets/{Templates-BXG2BXzE.js → Templates-hd7UB-8K.js} +1 -1
  64. package/src/assets/web-panel/assets/{Tenant-OjqSY3OD.js → Tenant-CqebAGfR.js} +1 -1
  65. package/src/assets/web-panel/assets/{Tokens-WrFIqGuF.js → Tokens-9b0DDm86.js} +1 -1
  66. package/src/assets/web-panel/assets/{Trigger-ql7VwBhY.js → Trigger-CG_ZXii2.js} +1 -1
  67. package/src/assets/web-panel/assets/{Trust-BnJxgiUu.js → Trust-CoCtornh.js} +1 -1
  68. package/src/assets/web-panel/assets/{UkeySign-DI1rcWZ-.js → UkeySign-mBEc6SBj.js} +1 -1
  69. package/src/assets/web-panel/assets/{VideoEditing-C1jgL5fG.js → VideoEditing-41j-ZZYu.js} +1 -1
  70. package/src/assets/web-panel/assets/{Wallet-CVMM1wf-.js → Wallet-DX4iBaEj.js} +1 -1
  71. package/src/assets/web-panel/assets/{WebAuthn-Bz-7j8cP.js → WebAuthn-9BlQYiNI.js} +1 -1
  72. package/src/assets/web-panel/assets/{WorkflowEditor-B_En7K3B.js → WorkflowEditor-BVm3icIg.js} +1 -1
  73. package/src/assets/web-panel/assets/chat-D98zBL7S.js +1 -0
  74. package/src/assets/web-panel/assets/{colors-C-_WCP_I.js → colors-ARL9W9UC.js} +1 -1
  75. package/src/assets/web-panel/assets/{compact-item-DRlYnN0j.js → compact-item-MYI7UP_X.js} +1 -1
  76. package/src/assets/web-panel/assets/{createContext-CQjz89ZD.js → createContext-BddTmM7g.js} +1 -1
  77. package/src/assets/web-panel/assets/{hasIn-DkvrU3Ng.js → hasIn-2OsB0OBj.js} +1 -1
  78. package/src/assets/web-panel/assets/{index-Dp-9lS6Q.js → index-B5UMIkIp.js} +1 -1
  79. package/src/assets/web-panel/assets/{index-D_UyFEni.js → index-B7XKJHg8.js} +1 -1
  80. package/src/assets/web-panel/assets/{index-nqPi_FUF.js → index-BA8yc-bG.js} +1 -1
  81. package/src/assets/web-panel/assets/{index-gyq6o1eH.js → index-BIpkHBFo.js} +1 -1
  82. package/src/assets/web-panel/assets/{index-BPtmPFwc.js → index-BKl1SKpb.js} +4 -4
  83. package/src/assets/web-panel/assets/{index-DEEKNhJo.js → index-BNXp47dX.js} +1 -1
  84. package/src/assets/web-panel/assets/{index-D8kTtVhG.js → index-BNjLDXWZ.js} +1 -1
  85. package/src/assets/web-panel/assets/{index-spVYB7ka.js → index-BO0TQWkU.js} +1 -1
  86. package/src/assets/web-panel/assets/{index-B4WoTHzD.js → index-BP5G8FRT.js} +1 -1
  87. package/src/assets/web-panel/assets/{index-Bh1pl2no.js → index-BSKiudeY.js} +1 -1
  88. package/src/assets/web-panel/assets/{index-BWrmR8z4.js → index-BYKZplcs.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-C5_IA35Q.js → index-BYbgYr7r.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-BxGG_QJu.js → index-Bc-fiOB-.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-CW6aTL_U.js → index-BhgLJAQi.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-Bm5beO8z.js → index-C5qBLUjM.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DFWu8Nod.js → index-CHfRLYw8.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DZ0FDal8.js → index-CISWdYQV.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BQJBwuxS.js → index-CXMgUcC_.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DaKiN39Q.js → index-CndUS0Yo.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-SGHpg8vZ.js → index-CtCi5cvq.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-qVl4nFNX.js → index-CuoiTv71.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CAWrRKBV.js → index-D2lcW3-z.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DWnUOEdQ.js → index-DK71wnJK.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CAXp9Lwm.js → index-DVB0ott1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-eZTZv_mW.js → index-DnL-YqLO.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DTCCIKB3.js → index-DpAOSmby.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DVvcsuh0.js → index-DqCyINtK.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrE6wIhJ.js → index-Dz5ro_F6.js} +1 -1
  106. package/src/assets/web-panel/assets/index-G5xmB5Af.js +1 -0
  107. package/src/assets/web-panel/assets/{index-CwYZLSvq.js → index-GxbpL_A7.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CreE5ozl.js → index-N8eKGGPN.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BcIcrbaL.js → index-N9X-UOF0.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DDElQABk.js → index-TepTGolv.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Banf4rVv.js → index-awm9n2jp.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DuutOf_b.js → index-hP2fDMJo.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DhAdUGyf.js → index-kNDK9K4y.js} +1 -1
  114. package/src/assets/web-panel/assets/index-qbPE-_18.js +1 -0
  115. package/src/assets/web-panel/assets/{index-Dcotn-Yi.js → index-tSE1B4ri.js} +1 -1
  116. package/src/assets/web-panel/assets/{initDefaultProps-DzCq75v2.js → initDefaultProps-CJbHV9hH.js} +1 -1
  117. package/src/assets/web-panel/assets/{motion-CwDCjQBX.js → motion-BTVrWA7N.js} +1 -1
  118. package/src/assets/web-panel/assets/{move-CiyNq_dM.js → move-CRIIhWv7.js} +1 -1
  119. package/src/assets/web-panel/assets/{omit-CV_avDvk.js → omit-CDcQHhGi.js} +1 -1
  120. package/src/assets/web-panel/assets/{pickAttrs-BVSL31rv.js → pickAttrs-Dplb8z8U.js} +1 -1
  121. package/src/assets/web-panel/assets/{placementArrow-oxkKuQCJ.js → placementArrow-CP1cLg6P.js} +1 -1
  122. package/src/assets/web-panel/assets/{responsiveObserve-Dva2arKe.js → responsiveObserve-PFMAIMDu.js} +1 -1
  123. package/src/assets/web-panel/assets/{slide-FbHwK4f8.js → slide-_CVxhTa3.js} +1 -1
  124. package/src/assets/web-panel/assets/{statusUtils-Pg-fsC5F.js → statusUtils-6j8grlgm.js} +1 -1
  125. package/src/assets/web-panel/assets/{styleChecker-CuXdVqkl.js → styleChecker-BbC7i8Sl.js} +1 -1
  126. package/src/assets/web-panel/assets/{useFlexGapSupport-z-vK8Wcv.js → useFlexGapSupport-Ctha7v2w.js} +1 -1
  127. package/src/assets/web-panel/assets/{useFs-Cr5jQ4qa.js → useFs-CeTUZIh2.js} +1 -1
  128. package/src/assets/web-panel/assets/{vnode-51kseDDa.js → vnode-kefkre4N.js} +1 -1
  129. package/src/assets/web-panel/assets/{zoom-DSlt2Q3p.js → zoom-CZjCXV_O.js} +1 -1
  130. package/src/assets/web-panel/index.html +1 -1
  131. package/src/gateways/ws/chat-intent-protocol.js +13 -19
  132. package/src/gateways/ws/llm-chat-protocol.js +166 -0
  133. package/src/gateways/ws/llm-creds.js +93 -0
  134. package/src/gateways/ws/message-dispatcher.js +1 -0
  135. package/src/gateways/ws/ws-server.js +6 -0
  136. package/src/lib/chat-core.js +60 -34
  137. package/src/assets/web-panel/assets/Chat-BhwqdoXy.js +0 -7
  138. package/src/assets/web-panel/assets/chat-HZBXEHqE.js +0 -1
  139. package/src/assets/web-panel/assets/index-BrNvQLt8.js +0 -1
  140. package/src/assets/web-panel/assets/index-DtjB2WpK.js +0 -1
@@ -0,0 +1,166 @@
1
+ /**
2
+ * llm.chat WS protocol — single-shot streaming chat for cc ui's QuickAsk page.
3
+ *
4
+ * The desktop web-shell has had this topic since `4eaf90137` (Phase 2). cc ui
5
+ * never registered it, so QuickAsk would hit ws.sendStream's 60s idle timer
6
+ * and surface "Stream idle timeout" forever. Filed as a regression report
7
+ * comparing v5.0.3.43 desktop (works) with v5.0.3.44 cc ui (hung) — root
8
+ * cause is the missing handler, not a code regression.
9
+ *
10
+ * Frame shape mirrors the desktop's llm-handlers.js so the SPA's
11
+ * `useLlmChat()` consumer is environment-agnostic:
12
+ *
13
+ * client → server: { id, type:"llm.chat", messages:[{role, content}],
14
+ * sessionId?, options?:{ provider?, model?, baseUrl?,
15
+ * apiKey?, temperature? } }
16
+ *
17
+ * server → client (streaming):
18
+ * { id, type:"llm.chat.chunk", chunk:{ delta, content } }
19
+ * ... per-token ...
20
+ * { id, type:"llm.chat.result", ok:true,
21
+ * result:{ message:{role:"assistant", content}, model, tokens? } }
22
+ *
23
+ * On error before / mid-stream:
24
+ * { id, type:"llm.chat.result", ok:false, error:"<msg>" }
25
+ *
26
+ * Provider resolution (first non-null wins):
27
+ * 1. message.options — explicit provider/model/apiKey from the client
28
+ * 2. server.sessionManager.getSession(sessionId) — set via `cc auth llm`
29
+ * 3. process.env[BUILT_IN_PROVIDERS[provider].apiKeyEnv]
30
+ *
31
+ * Without any source of credentials we send a clean ok:false frame instantly
32
+ * — the user sees an actionable error rather than a 60s hang.
33
+ */
34
+
35
+ import {
36
+ streamOllama,
37
+ streamOpenAI,
38
+ streamAnthropic,
39
+ } from "../../lib/chat-core.js";
40
+ import { BUILT_IN_PROVIDERS } from "../../lib/llm-providers.js";
41
+ import { resolveLlmCreds } from "./llm-creds.js";
42
+
43
+ function validateMessages(messages) {
44
+ if (!Array.isArray(messages) || messages.length === 0)
45
+ return "messages_required";
46
+ for (const m of messages) {
47
+ if (
48
+ !m ||
49
+ typeof m !== "object" ||
50
+ typeof m.role !== "string" ||
51
+ typeof m.content !== "string"
52
+ ) {
53
+ return "invalid_message_shape";
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+
59
+ /**
60
+ * Streaming handler for `llm.chat`. The dispatcher invokes it; we own the
61
+ * full frame protocol (chunks + terminal result) so the consumer-side
62
+ * useLlmChat() works unchanged whether the WS gateway is desktop's
63
+ * web-shell or cc ui.
64
+ */
65
+ export async function handleLlmChat(server, id, ws, message) {
66
+ const topic = "llm.chat";
67
+ const send = (frame) => server._send(ws, { id, ...frame });
68
+
69
+ const validationError = validateMessages(message?.messages);
70
+ if (validationError) {
71
+ send({ type: `${topic}.result`, ok: false, error: validationError });
72
+ return;
73
+ }
74
+
75
+ const creds = resolveLlmCreds(server, message);
76
+ if (!creds || !creds.provider) {
77
+ send({
78
+ type: `${topic}.result`,
79
+ ok: false,
80
+ error:
81
+ "no_llm_provider_configured: pass options.provider + apiKey, sessionId with creds, or set <PROVIDER>_API_KEY env",
82
+ });
83
+ return;
84
+ }
85
+
86
+ if (creds.provider !== "ollama" && !creds.apiKey) {
87
+ const envHint = BUILT_IN_PROVIDERS[creds.provider]?.apiKeyEnv;
88
+ send({
89
+ type: `${topic}.result`,
90
+ ok: false,
91
+ error: `missing_api_key for ${creds.provider}${envHint ? ` (set ${envHint})` : ""}`,
92
+ });
93
+ return;
94
+ }
95
+
96
+ let accumulator = "";
97
+ const onToken = (token) => {
98
+ if (typeof token !== "string" || token.length === 0) return;
99
+ accumulator += token;
100
+ send({
101
+ type: `${topic}.chunk`,
102
+ chunk: { delta: token, content: accumulator },
103
+ });
104
+ };
105
+
106
+ let usage = null;
107
+ const onUsage = (u) => {
108
+ usage = u;
109
+ };
110
+
111
+ try {
112
+ const baseUrl = creds.baseUrl || "http://localhost:11434";
113
+ if (creds.provider === "ollama") {
114
+ await streamOllama(
115
+ message.messages,
116
+ creds.model,
117
+ baseUrl,
118
+ onToken,
119
+ onUsage,
120
+ );
121
+ } else if (creds.provider === "anthropic") {
122
+ const def = BUILT_IN_PROVIDERS.anthropic;
123
+ const url = baseUrl !== "http://localhost:11434" ? baseUrl : def.baseUrl;
124
+ await streamAnthropic(
125
+ message.messages,
126
+ creds.model,
127
+ url,
128
+ creds.apiKey,
129
+ onToken,
130
+ onUsage,
131
+ );
132
+ } else {
133
+ // OpenAI-compatible — covers openai / volcengine / deepseek / dashscope /
134
+ // kimi / minimax / mistral / custom. baseUrl from creds; default-from
135
+ // BUILT_IN_PROVIDERS already applied above.
136
+ const def = BUILT_IN_PROVIDERS[creds.provider];
137
+ const url = baseUrl !== "http://localhost:11434" ? baseUrl : def?.baseUrl;
138
+ await streamOpenAI(
139
+ message.messages,
140
+ creds.model,
141
+ url,
142
+ creds.apiKey,
143
+ onToken,
144
+ onUsage,
145
+ );
146
+ }
147
+
148
+ send({
149
+ type: `${topic}.result`,
150
+ ok: true,
151
+ result: {
152
+ message: { role: "assistant", content: accumulator },
153
+ model: creds.model,
154
+ provider: creds.provider,
155
+ tokens: usage?.outputTokens ?? null,
156
+ promptTokens: usage?.inputTokens ?? null,
157
+ },
158
+ });
159
+ } catch (err) {
160
+ send({
161
+ type: `${topic}.result`,
162
+ ok: false,
163
+ error: err?.message || String(err),
164
+ });
165
+ }
166
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Shared LLM credential resolver for WS handlers.
3
+ *
4
+ * Used by both `llm.chat` (single-shot streaming) and `chat.intent.*`
5
+ * (intent-understanding flow). Encapsulates the precedence rules so adding
6
+ * a third consumer doesn't fork them again.
7
+ *
8
+ * Resolution order (first non-null wins):
9
+ * 1. Explicit `message.options.{provider,model,baseUrl,apiKey}` from client.
10
+ * 2. WS session creds via `server.sessionManager.getSession(sessionId)`.
11
+ * 3. Process env — first BUILT_IN_PROVIDERS entry whose apiKeyEnv is set.
12
+ *
13
+ * Fall-throughs:
14
+ * - Provider with `free: true` (ollama) doesn't need apiKey; a session
15
+ * entry with provider=ollama and no apiKey is valid.
16
+ * - For non-ollama providers, missing apiKey is a fatal — the caller
17
+ * should send a clean error frame instead of hanging on a 401.
18
+ * - When no source has any creds, returns null. Caller decides whether
19
+ * to fail-fast (llm.chat) or yield "LLM not configured" (chat-intent).
20
+ *
21
+ * @returns {{provider, model, baseUrl, apiKey} | null}
22
+ */
23
+
24
+ import { BUILT_IN_PROVIDERS } from "../../lib/llm-providers.js";
25
+
26
+ const ENV_PREFERRED_ORDER = [
27
+ "volcengine",
28
+ "openai",
29
+ "anthropic",
30
+ "deepseek",
31
+ "dashscope",
32
+ "gemini",
33
+ "kimi",
34
+ "minimax",
35
+ "mistral",
36
+ ];
37
+
38
+ export function resolveLlmCreds(server, message) {
39
+ const opts = message?.options || {};
40
+ const optProvider = opts.provider;
41
+ const optModel = opts.model;
42
+ const optBaseUrl = opts.baseUrl;
43
+ const optApiKey = opts.apiKey;
44
+
45
+ if (optProvider) {
46
+ const def = BUILT_IN_PROVIDERS[optProvider];
47
+ return {
48
+ provider: optProvider,
49
+ model: optModel || def?.models?.[0] || null,
50
+ baseUrl: optBaseUrl || def?.baseUrl || null,
51
+ apiKey: optApiKey || (def?.apiKeyEnv ? process.env[def.apiKeyEnv] : null),
52
+ };
53
+ }
54
+
55
+ const sessionId = message?.sessionId;
56
+ if (sessionId && server?.sessionManager?.getSession) {
57
+ let session;
58
+ try {
59
+ session = server.sessionManager.getSession(sessionId);
60
+ } catch {
61
+ session = null;
62
+ }
63
+ if (session?.provider) {
64
+ const def = BUILT_IN_PROVIDERS[session.provider];
65
+ // Don't default baseUrl to ollama — that breaks every cloud provider
66
+ // when the session was created without an explicit baseUrl. Fall back
67
+ // to the provider's own default endpoint instead.
68
+ const fallbackBase =
69
+ def?.baseUrl ||
70
+ (session.provider === "ollama" ? "http://localhost:11434" : null);
71
+ return {
72
+ provider: session.provider,
73
+ model: optModel || session.model,
74
+ baseUrl: session.baseUrl || fallbackBase,
75
+ apiKey: session.apiKey,
76
+ };
77
+ }
78
+ }
79
+
80
+ for (const name of ENV_PREFERRED_ORDER) {
81
+ const def = BUILT_IN_PROVIDERS[name];
82
+ if (def?.apiKeyEnv && process.env[def.apiKeyEnv]) {
83
+ return {
84
+ provider: name,
85
+ model: optModel || def.models?.[0] || null,
86
+ baseUrl: def.baseUrl,
87
+ apiKey: process.env[def.apiKeyEnv],
88
+ };
89
+ }
90
+ }
91
+
92
+ return null;
93
+ }
@@ -96,6 +96,7 @@ export function createWsMessageDispatcher(server) {
96
96
  server._handleChatIntentUnderstandStream(id, ws, message),
97
97
  "chat.intent.classify-followup": () =>
98
98
  server._handleChatIntentClassifyFollowup(id, ws, message),
99
+ "llm.chat": () => server._handleLlmChat(id, ws, message),
99
100
  };
100
101
 
101
102
  // Phase I — Hosted Session API streaming routes (stream.run).
@@ -79,6 +79,7 @@ import {
79
79
  handleChatIntentUnderstandStream,
80
80
  handleChatIntentClassifyFollowup,
81
81
  } from "./chat-intent-protocol.js";
82
+ import { handleLlmChat } from "./llm-chat-protocol.js";
82
83
 
83
84
  const __filename = fileURLToPath(import.meta.url);
84
85
  const __dirname = dirname(__filename);
@@ -519,6 +520,11 @@ export class ChainlessChainWSServer extends EventEmitter {
519
520
  return handleChatIntentClassifyFollowup(this, id, ws, message);
520
521
  }
521
522
 
523
+ /** @private — single-shot streaming chat for QuickAsk (`llm.chat` topic) */
524
+ async _handleLlmChat(id, ws, message) {
525
+ return handleLlmChat(this, id, ws, message);
526
+ }
527
+
522
528
  /** @private */
523
529
  _handleAuth(clientId, ws, message) {
524
530
  const { id, token } = message;
@@ -242,26 +242,39 @@ export async function streamAnthropic(
242
242
  export async function* chatStream(messages, options) {
243
243
  const { provider, model, baseUrl, apiKey, sessionId } = options;
244
244
 
245
- const tokens = [];
245
+ // Token queue + waiter promise. onToken (called synchronously by each
246
+ // streamX impl per delta) pushes onto the queue and wakes the generator
247
+ // loop, which yields immediately. Pre-v5.0.3.46 this was a buffering
248
+ // tokens[] array drained only after `await streamX(...)` resolved — so
249
+ // the "stream" surfaced no progress until the LLM call finished, which
250
+ // showed up as the chat.intent placeholder card spinning at "意图: 未识别"
251
+ // for the full LLM duration.
252
+ const queue = [];
253
+ let waiter = null;
254
+ let done = false;
255
+ let capturedUsage = null;
256
+
257
+ const wake = () => {
258
+ if (!waiter) return;
259
+ const w = waiter;
260
+ waiter = null;
261
+ w();
262
+ };
246
263
  const onToken = (token) => {
247
- tokens.push(token);
264
+ queue.push(token);
265
+ wake();
248
266
  };
249
-
250
- let capturedUsage = null;
251
267
  const onUsage = (u) => {
252
268
  capturedUsage = u;
253
269
  };
254
270
 
255
- let fullResponse;
256
-
271
+ // Validate creds + assemble URL synchronously so missing-key errors
272
+ // surface immediately to the consumer instead of being deferred until
273
+ // the first queue drain tick.
274
+ let providerCall;
257
275
  if (provider === "ollama") {
258
- fullResponse = await streamOllama(
259
- messages,
260
- model,
261
- baseUrl,
262
- onToken,
263
- onUsage,
264
- );
276
+ providerCall = () =>
277
+ streamOllama(messages, model, baseUrl, onToken, onUsage);
265
278
  } else if (provider === "anthropic") {
266
279
  const providerDef = BUILT_IN_PROVIDERS.anthropic;
267
280
  const url =
@@ -276,14 +289,8 @@ export async function* chatStream(messages, options) {
276
289
  `API key required for anthropic (set ${providerDef?.apiKeyEnv || "ANTHROPIC_API_KEY"})`,
277
290
  );
278
291
  }
279
- fullResponse = await streamAnthropic(
280
- messages,
281
- model,
282
- url,
283
- key,
284
- onToken,
285
- onUsage,
286
- );
292
+ providerCall = () =>
293
+ streamAnthropic(messages, model, url, key, onToken, onUsage);
287
294
  } else {
288
295
  const providerDef = BUILT_IN_PROVIDERS[provider];
289
296
  const url =
@@ -298,16 +305,40 @@ export async function* chatStream(messages, options) {
298
305
  `API key required for ${provider} (set ${providerDef?.apiKeyEnv || "API key"})`,
299
306
  );
300
307
  }
301
- fullResponse = await streamOpenAI(
302
- messages,
303
- model,
304
- url,
305
- key,
306
- onToken,
307
- onUsage,
308
- );
308
+ providerCall = () =>
309
+ streamOpenAI(messages, model, url, key, onToken, onUsage);
309
310
  }
310
311
 
312
+ // Run the provider stream concurrently with the queue-drain loop. finally
313
+ // flips `done` and wakes the waiter so a stream that ends without emitting
314
+ // any token still terminates the generator cleanly.
315
+ const streamPromise = (async () => {
316
+ try {
317
+ return await providerCall();
318
+ } finally {
319
+ done = true;
320
+ wake();
321
+ }
322
+ })();
323
+ // Swallow-only handler so an early rejection isn't logged as unhandled
324
+ // before the consumer reaches `await streamPromise` below. The eventual
325
+ // await still rethrows.
326
+ streamPromise.catch(() => {});
327
+
328
+ while (true) {
329
+ if (queue.length > 0) {
330
+ yield { type: "response-token", token: queue.shift() };
331
+ continue;
332
+ }
333
+ if (done) break;
334
+ await new Promise((resolve) => {
335
+ waiter = resolve;
336
+ });
337
+ }
338
+
339
+ // Rethrows if providerCall rejected.
340
+ const fullResponse = await streamPromise;
341
+
311
342
  // Phase J — auto-record token usage to JSONL session store so
312
343
  // `cc session usage` and the `usage.*` WS routes see real data.
313
344
  if (sessionId && capturedUsage) {
@@ -325,11 +356,6 @@ export async function* chatStream(messages, options) {
325
356
  }
326
357
  }
327
358
 
328
- // Yield all collected tokens
329
- for (const token of tokens) {
330
- yield { type: "response-token", token };
331
- }
332
-
333
359
  yield { type: "response-complete", content: fullResponse };
334
360
  }
335
361
 
@@ -1,7 +0,0 @@
1
- import{L as l,M as m,R as f,Q as z,u as _,P as u,S as O,Z as Y,f as k,w as Z,o as ge,n as W,x as Me,$ as ae,F as G,Y as J,U as de,r as L,K as D,c as y,N as w,O as A,a0 as Oe,a1 as ze,H as Ee,I as Ae,a as Te}from"./vendor-Ci2pTZ_t.js";import{_ as ee,b as Fe}from"./index-BPtmPFwc.js";import{u as Re,M as Pe}from"./chat-HZBXEHqE.js";import{a as qe,L as ye,w as je,ad as De,ae as Le,f as Ne,c as We,p as Be,af as he,ag as Ve,b as He,F as fe,G as me,M as Ue,aa as pe,k as Qe,ah as Ke,ai as Ge}from"./icons-B2G69bhT.js";import{r as Je}from"./markdown-vYH_ziAO.js";import"./markdown-xjUYbPSW.js";const Xe=["data-testid"],Ye={class:"cb-action__icon"},Ze={class:"cb-action__label"},et={key:0,class:"cb-action__detail"},tt={key:1,class:"cb-action__caret"},st={__name:"ToolInvocationCard",props:{item:{type:Object,required:!0},expandable:{type:Boolean,default:!1},expanded:{type:Boolean,default:!1}},emits:["toggle"],setup(c,{emit:g}){const e=c,t=g;function s(){e.expandable&&t("toggle")}return(n,i)=>(l(),m("div",{class:Y(["cb-action",[`cb-action--${c.item.status}`,{"cb-action--expandable":c.expandable,"cb-action--open":c.expanded}]]),"data-testid":`tool-card-${c.item.id}`,onClick:s},[f("span",Ye,[c.item.status==="done"?(l(),z(_(qe),{key:0})):c.item.status==="running"?(l(),z(_(ye),{key:1})):(l(),z(_(je),{key:2}))]),f("span",Ze,u(c.item.label),1),c.item.detail?(l(),m("span",et,u(c.item.detail),1)):O("",!0),c.expandable?(l(),m("span",tt,[c.expanded?(l(),z(_(De),{key:0})):(l(),z(_(Le),{key:1}))])):O("",!0)],10,Xe))}},nt=ee(st,[["__scopeId","data-v-cf5a0925"]]),it=["innerHTML"],ot={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(c){const g=c,e=k(()=>Je(g.content||""));return(t,s)=>(l(),m("div",{class:"markdown-content",innerHTML:e.value},null,8,it))}},at=ee(ot,[["__scopeId","data-v-693ca57e"]]);function K(c,g,e){let t=e.initialDeps??[],s,n=!0;function i(){var a,r,I;let S;e.key&&((a=e.debug)!=null&&a.call(e))&&(S=Date.now());const b=c();if(!(b.length!==t.length||b.some((v,x)=>t[x]!==v)))return s;t=b;let d;if(e.key&&((r=e.debug)!=null&&r.call(e))&&(d=Date.now()),s=g(...b),e.key&&((I=e.debug)!=null&&I.call(e))){const v=Math.round((Date.now()-S)*100)/100,x=Math.round((Date.now()-d)*100)/100,M=x/16,T=(E,P)=>{for(E=String(E);E.length<P;)E=" "+E;return E};console.info(`%c⏱ ${T(x,5)} /${T(v,5)} ms`,`
2
- font-size: .6rem;
3
- font-weight: bold;
4
- color: hsl(${Math.max(0,Math.min(120-120*M,120))}deg 100% 31%);`,e?.key)}return e?.onChange&&!(n&&e.skipInitialOnChange)&&e.onChange(s),n=!1,s}return i.updateDeps=a=>{t=a},i}function ve(c,g){if(c===void 0)throw new Error("Unexpected undefined");return c}const lt=(c,g)=>Math.abs(c-g)<1.01,rt=c=>c,ct=c=>{const g=Math.max(c.startIndex-c.overscan,0),e=Math.min(c.endIndex+c.overscan,c.count-1),t=[];for(let s=g;s<=e;s++)t.push(s);return t},ut=(c,g,e)=>{if(g?.borderBoxSize){const t=g.borderBoxSize[0];if(t)return Math.round(t[e.options.horizontal?"inlineSize":"blockSize"])}return c[e.options.horizontal?"offsetWidth":"offsetHeight"]};class dt{constructor(g){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollState=null,this.measurementsCache=[],this.itemSizeCache=new Map,this.laneAssignments=new Map,this.pendingMeasuredCacheIndexes=[],this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this.elementsCache=new Map,this.now=()=>{var e,t,s;return((s=(t=(e=this.targetWindow)==null?void 0:e.performance)==null?void 0:t.now)==null?void 0:s.call(t))??Date.now()},this.observer=(()=>{let e=null;const t=()=>e||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:e=new this.targetWindow.ResizeObserver(s=>{s.forEach(n=>{const i=()=>{const a=n.target,r=this.indexFromElement(a);if(!a.isConnected){this.observer.unobserve(a);return}this.shouldMeasureDuringScroll(r)&&this.resizeItem(r,this.options.measureElement(a,n,this))};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(i):i()})}));return{disconnect:()=>{var s;(s=t())==null||s.disconnect(),e=null},observe:s=>{var n;return(n=t())==null?void 0:n.observe(s,{box:"border-box"})},unobserve:s=>{var n;return(n=t())==null?void 0:n.unobserve(s)}}})(),this.range=null,this.setOptions=e=>{Object.entries(e).forEach(([t,s])=>{typeof s>"u"&&delete e[t]}),this.options={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:rt,rangeExtractor:ct,onChange:()=>{},measureElement:ut,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,laneAssignmentMode:"estimate",...e}},this.notify=e=>{var t,s;(s=(t=this.options).onChange)==null||s.call(t,this,e)},this.maybeNotify=K(()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]),e=>{this.notify(e)},{key:!1,debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(e=>e()),this.unsubs=[],this.observer.disconnect(),this.rafId!=null&&this.targetWindow&&(this.targetWindow.cancelAnimationFrame(this.rafId),this.rafId=null),this.scrollState=null,this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var e;const t=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==t){if(this.cleanup(),!t){this.maybeNotify();return}this.scrollElement=t,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((e=this.scrollElement)==null?void 0:e.window)??null,this.elementsCache.forEach(s=>{this.observer.observe(s)}),this.unsubs.push(this.options.observeElementRect(this,s=>{this.scrollRect=s,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(s,n)=>{this.scrollAdjustments=0,this.scrollDirection=n?this.getScrollOffset()<s?"forward":"backward":null,this.scrollOffset=s,this.isScrolling=n,this.scrollState&&this.scheduleScrollReconcile(),this.maybeNotify()})),this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}},this.rafId=null,this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getFurthestMeasurement=(e,t)=>{const s=new Map,n=new Map;for(let i=t-1;i>=0;i--){const a=e[i];if(s.has(a.lane))continue;const r=n.get(a.lane);if(r==null||a.end>r.end?n.set(a.lane,a):a.end<r.end&&s.set(a.lane,!0),s.size===this.options.lanes)break}return n.size===this.options.lanes?Array.from(n.values()).sort((i,a)=>i.end===a.end?i.index-a.index:i.end-a.end)[0]:void 0},this.getMeasurementOptions=K(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes,this.options.laneAssignmentMode],(e,t,s,n,i,a,r)=>(this.prevLanes!==void 0&&this.prevLanes!==a&&(this.lanesChangedFlag=!0),this.prevLanes=a,this.pendingMeasuredCacheIndexes=[],{count:e,paddingStart:t,scrollMargin:s,getItemKey:n,enabled:i,lanes:a,laneAssignmentMode:r}),{key:!1}),this.getMeasurements=K(()=>[this.getMeasurementOptions(),this.itemSizeCache],({count:e,paddingStart:t,scrollMargin:s,getItemKey:n,enabled:i,lanes:a,laneAssignmentMode:r},I)=>{if(!i)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>e)for(const d of this.laneAssignments.keys())d>=e&&this.laneAssignments.delete(d);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMeasuredCacheIndexes=[]),this.measurementsCache.length===0&&!this.lanesSettling&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(d=>{this.itemSizeCache.set(d.key,d.size)}));const S=this.lanesSettling?0:this.pendingMeasuredCacheIndexes.length>0?Math.min(...this.pendingMeasuredCacheIndexes):0;this.pendingMeasuredCacheIndexes=[],this.lanesSettling&&this.measurementsCache.length===e&&(this.lanesSettling=!1);const b=this.measurementsCache.slice(0,S),R=new Array(a).fill(void 0);for(let d=0;d<S;d++){const v=b[d];v&&(R[v.lane]=d)}for(let d=S;d<e;d++){const v=n(d),x=this.laneAssignments.get(d);let M,T;const E=r==="estimate"||I.has(v);if(x!==void 0&&this.options.lanes>1){M=x;const C=R[M],B=C!==void 0?b[C]:void 0;T=B?B.end+this.options.gap:t+s}else{const C=this.options.lanes===1?b[d-1]:this.getFurthestMeasurement(b,d);T=C?C.end+this.options.gap:t+s,M=C?C.lane:d%this.options.lanes,this.options.lanes>1&&E&&this.laneAssignments.set(d,M)}const P=I.get(v),H=typeof P=="number"?P:this.options.estimateSize(d),q=T+H;b[d]={index:d,start:T,size:H,end:q,key:v,lane:M},R[M]=d}return this.measurementsCache=b,b},{key:!1,debug:()=>this.options.debug}),this.calculateRange=K(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(e,t,s,n)=>this.range=e.length>0&&t>0?ht({measurements:e,outerSize:t,scrollOffset:s,lanes:n}):null,{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=K(()=>{let e=null,t=null;const s=this.calculateRange();return s&&(e=s.startIndex,t=s.endIndex),this.maybeNotify.updateDeps([this.isScrolling,e,t]),[this.options.rangeExtractor,this.options.overscan,this.options.count,e,t]},(e,t,s,n,i)=>n===null||i===null?[]:e({startIndex:n,endIndex:i,overscan:t,count:s}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=e=>{const t=this.options.indexAttribute,s=e.getAttribute(t);return s?parseInt(s,10):(console.warn(`Missing attribute name '${t}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=e=>{var t;if(!this.scrollState||this.scrollState.behavior!=="smooth")return!0;const s=this.scrollState.index??((t=this.getVirtualItemForOffset(this.scrollState.lastTargetOffset))==null?void 0:t.index);if(s!==void 0&&this.range){const n=Math.max(this.options.overscan,Math.ceil((this.range.endIndex-this.range.startIndex)/2)),i=Math.max(0,s-n),a=Math.min(this.options.count-1,s+n);return e>=i&&e<=a}return!0},this.measureElement=e=>{if(!e){this.elementsCache.forEach((i,a)=>{i.isConnected||(this.observer.unobserve(i),this.elementsCache.delete(a))});return}const t=this.indexFromElement(e),s=this.options.getItemKey(t),n=this.elementsCache.get(s);n!==e&&(n&&this.observer.unobserve(n),this.observer.observe(e),this.elementsCache.set(s,e)),(!this.isScrolling||this.scrollState)&&this.shouldMeasureDuringScroll(t)&&this.resizeItem(t,this.options.measureElement(e,void 0,this))},this.resizeItem=(e,t)=>{var s;const n=this.measurementsCache[e];if(!n)return;const i=this.itemSizeCache.get(n.key)??n.size,a=t-i;a!==0&&(((s=this.scrollState)==null?void 0:s.behavior)!=="smooth"&&(this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(n,a,this):n.start<this.getScrollOffset()+this.scrollAdjustments)&&this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=a,behavior:void 0}),this.pendingMeasuredCacheIndexes.push(n.index),this.itemSizeCache=new Map(this.itemSizeCache.set(n.key,t)),this.notify(!1))},this.getVirtualItems=K(()=>[this.getVirtualIndexes(),this.getMeasurements()],(e,t)=>{const s=[];for(let n=0,i=e.length;n<i;n++){const a=e[n],r=t[a];s.push(r)}return s},{key:!1,debug:()=>this.options.debug}),this.getVirtualItemForOffset=e=>{const t=this.getMeasurements();if(t.length!==0)return ve(t[_e(0,t.length-1,s=>ve(t[s]).start,e)])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if("scrollHeight"in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{const e=this.scrollElement.document.documentElement;return this.options.horizontal?e.scrollWidth-this.scrollElement.innerWidth:e.scrollHeight-this.scrollElement.innerHeight}},this.getOffsetForAlignment=(e,t,s=0)=>{if(!this.scrollElement)return 0;const n=this.getSize(),i=this.getScrollOffset();t==="auto"&&(t=e>=i+n?"end":"start"),t==="center"?e+=(s-n)/2:t==="end"&&(e-=n);const a=this.getMaxScrollOffset();return Math.max(Math.min(a,e),0)},this.getOffsetForIndex=(e,t="auto")=>{e=Math.max(0,Math.min(e,this.options.count-1));const s=this.getSize(),n=this.getScrollOffset(),i=this.measurementsCache[e];if(!i)return;if(t==="auto")if(i.end>=n+s-this.options.scrollPaddingEnd)t="end";else if(i.start<=n+this.options.scrollPaddingStart)t="start";else return[n,t];if(t==="end"&&e===this.options.count-1)return[this.getMaxScrollOffset(),t];const a=t==="end"?i.end+this.options.scrollPaddingEnd:i.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(a,t,i.size),t]},this.scrollToOffset=(e,{align:t="start",behavior:s="auto"}={})=>{const n=this.getOffsetForAlignment(e,t),i=this.now();this.scrollState={index:null,align:t,behavior:s,startedAt:i,lastTargetOffset:n,stableFrames:0},this._scrollToOffset(n,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollToIndex=(e,{align:t="auto",behavior:s="auto"}={})=>{e=Math.max(0,Math.min(e,this.options.count-1));const n=this.getOffsetForIndex(e,t);if(!n)return;const[i,a]=n,r=this.now();this.scrollState={index:e,align:a,behavior:s,startedAt:r,lastTargetOffset:i,stableFrames:0},this._scrollToOffset(i,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollBy=(e,{behavior:t="auto"}={})=>{const s=this.getScrollOffset()+e,n=this.now();this.scrollState={index:null,align:"start",behavior:t,startedAt:n,lastTargetOffset:s,stableFrames:0},this._scrollToOffset(s,{adjustments:void 0,behavior:t}),this.scheduleScrollReconcile()},this.getTotalSize=()=>{var e;const t=this.getMeasurements();let s;if(t.length===0)s=this.options.paddingStart;else if(this.options.lanes===1)s=((e=t[t.length-1])==null?void 0:e.end)??0;else{const n=Array(this.options.lanes).fill(null);let i=t.length-1;for(;i>=0&&n.some(a=>a===null);){const a=t[i];n[a.lane]===null&&(n[a.lane]=a.end),i--}s=Math.max(...n.filter(a=>a!==null))}return Math.max(s-this.options.scrollMargin+this.options.paddingEnd,0)},this._scrollToOffset=(e,{adjustments:t,behavior:s})=>{this.options.scrollToFn(e,{behavior:s,adjustments:t},this)},this.measure=()=>{this.itemSizeCache=new Map,this.laneAssignments=new Map,this.notify(!1)},this.setOptions(g)}scheduleScrollReconcile(){if(!this.targetWindow){this.scrollState=null;return}this.rafId==null&&(this.rafId=this.targetWindow.requestAnimationFrame(()=>{this.rafId=null,this.reconcileScroll()}))}reconcileScroll(){if(!this.scrollState||!this.scrollElement)return;if(this.now()-this.scrollState.startedAt>5e3){this.scrollState=null;return}const t=this.scrollState.index!=null?this.getOffsetForIndex(this.scrollState.index,this.scrollState.align):void 0,s=t?t[0]:this.scrollState.lastTargetOffset,n=1,i=s!==this.scrollState.lastTargetOffset;if(!i&&lt(s,this.getScrollOffset())){if(this.scrollState.stableFrames++,this.scrollState.stableFrames>=n){this.scrollState=null;return}}else this.scrollState.stableFrames=0,i&&(this.scrollState.lastTargetOffset=s,this.scrollState.behavior="auto",this._scrollToOffset(s,{adjustments:void 0,behavior:"auto"}));this.scheduleScrollReconcile()}}const _e=(c,g,e,t)=>{for(;c<=g;){const s=(c+g)/2|0,n=e(s);if(n<t)c=s+1;else if(n>t)g=s-1;else return s}return c>0?c-1:0};function ht({measurements:c,outerSize:g,scrollOffset:e,lanes:t}){const s=c.length-1,n=r=>c[r].start;if(c.length<=t)return{startIndex:0,endIndex:s};let i=_e(0,s,n,e),a=i;if(t===1)for(;a<s&&c[a].end<e+g;)a++;else if(t>1){const r=Array(t).fill(0);for(;a<s&&r.some(S=>S<e+g);){const S=c[a];r[S.lane]=S.end,a++}const I=Array(t).fill(e+g);for(;i>=0&&I.some(S=>S>=e);){const S=c[i];I[S.lane]=S.start,i--}i=Math.max(0,i-i%t),a=Math.min(s,a+(t-1-a%t))}return{startIndex:i,endIndex:a}}const ft={key:1,class:"fallback-list"},mt={__name:"VirtualMessageList",props:{messages:{type:Array,required:!0,default:()=>[]},estimateSize:{type:Number,default:120}},emits:["scroll-to-bottom","load-more"],setup(c,{expose:g,emit:e}){const t=c,s=e,n=L(null),i=L(null),a=L(0),r=k(()=>i.value?(a.value,i.value.getVirtualItems()):[]),I=()=>{if(n.value)try{i.value=new dt({count:t.messages.length,getScrollElement:()=>n.value,estimateSize:()=>t.estimateSize,overscan:5,scrollMargin:0,onChange:()=>{a.value++}}),W(()=>{i.value&&n.value&&(i.value.measure(),a.value++,n.value.scrollTop=1,setTimeout(()=>{n.value&&(n.value.scrollTop=0)},50))})}catch(d){console.error("[VirtualMessageList] init failed:",d)}},S=()=>{if(!n.value)return;i.value&&i.value.measure();const{scrollTop:d,scrollHeight:v,clientHeight:x}=n.value;d<100&&s("load-more"),d+x>=v-50&&s("scroll-to-bottom")},b=()=>{n.value&&requestAnimationFrame(()=>{n.value&&(n.value.scrollTop=n.value.scrollHeight)})},R=d=>{const v=t.messages.findIndex(x=>x.id===d);v!==-1&&i.value&&i.value.scrollToIndex(v,{align:"center"})};return Z(()=>t.messages.length,(d,v)=>{i.value?(i.value.setOptions({count:d,estimateSize:()=>t.estimateSize}),a.value++,d>v&&W(()=>b())):W(()=>{I(),i.value&&a.value++})}),Z(()=>t.messages,d=>{!i.value&&d.length>0?W(()=>I()):i.value&&(i.value.setOptions({count:d.length,estimateSize:()=>t.estimateSize,getScrollElement:()=>n.value,overscan:5,scrollMargin:0,onChange:()=>{a.value++}}),a.value++,W(()=>{i.value&&i.value.measure()}))},{deep:!0}),g({scrollToBottom:b,scrollToMessage:R}),ge(()=>{W(()=>{I(),t.messages.length>0&&b()})}),Me(()=>{i.value&&(i.value=null)}),(d,v)=>(l(),m("div",{ref_key:"scrollContainer",ref:n,class:"virtual-message-list",onScroll:S},[i.value&&r.value.length>0?(l(),m("div",{key:0,style:ae({height:`${i.value.getTotalSize()}px`,width:"100%",position:"relative"})},[(l(!0),m(G,null,J(r.value,x=>(l(),m("div",{key:x.key,style:ae({position:"absolute",top:0,left:0,width:"100%",transform:`translateY(${x.start}px)`})},[de(d.$slots,"default",{message:c.messages[x.index],index:x.index},void 0)],4))),128))],4)):(l(),m("div",ft,[(l(!0),m(G,null,J(c.messages,(x,M)=>(l(),m("div",{key:x.id||M},[de(d.$slots,"default",{message:x,index:M},void 0)]))),128))]))],544))}},pt=ee(mt,[["__scopeId","data-v-3c34170a"]]),vt={class:"intent-confirmation-message"},gt={class:"confirmation-header"},yt={class:"header-icon"},_t={class:"header-text"},bt={key:0},St={key:1},xt={key:2},kt={class:"understanding-content"},Ct={key:0,class:"original-input"},wt={class:"label"},$t={class:"value original-text"},It={key:1,class:"corrected-input"},Mt={class:"label"},Ot={class:"value corrected-text"},zt={class:"intent-section"},Et={class:"label"},At={class:"value"},Tt={key:2,class:"key-points-section"},Ft={class:"label"},Rt={class:"key-points-list"},Pt={key:3,class:"correction-section"},qt={class:"label"},jt={class:"value correction-text"},Dt={key:0,class:"streaming-indicator"},Lt={key:0,class:"streaming-tokens"},Nt={key:1,class:"action-buttons"},Wt={key:2,class:"correction-input-section"},Bt={class:"correction-actions"},Vt={__name:"IntentConfirmationMessage",props:{message:{type:Object,required:!0}},emits:["confirm","correct"],setup(c,{emit:g}){const e=c,t=g,s=L(!1),n=L(""),i=k(()=>e.message.metadata?.originalInput||""),a=k(()=>e.message.metadata?.understanding||{}),r=k(()=>a.value.correctedInput||i.value),I=k(()=>a.value.intent||"未识别"),S=k(()=>a.value.keyPoints||[]),b=k(()=>r.value!==i.value&&i.value.trim()!==""),R=k(()=>e.message.metadata?.status||"pending"),d=k(()=>R.value==="confirmed"),v=k(()=>R.value==="corrected"),x=k(()=>!!e.message.metadata?.streaming),M=k(()=>e.message.metadata?.streamingTokens||0),T=k(()=>e.message.metadata?.correction||null);function E(){t("confirm",{messageId:e.message.id,originalInput:i.value,understanding:a.value})}function P(){s.value=!0,n.value=r.value}function H(){n.value.trim()&&(t("correct",{messageId:e.message.id,originalInput:i.value,correction:n.value}),s.value=!1)}function q(){s.value=!1,n.value=""}return(C,B)=>{const U=D("a-button"),Q=D("a-textarea");return l(),m("div",vt,[f("div",gt,[f("div",yt,[d.value?(l(),z(_(Ne),{key:0,style:{color:"#52c41a"}})):v.value?(l(),z(_(We),{key:1,style:{color:"#faad14"}})):(l(),z(_(Be),{key:2,style:{color:"#1890ff"}}))]),f("div",_t,[d.value?(l(),m("span",bt,u(C.$t("chat.intent.confirmed")),1)):v.value?(l(),m("span",St,u(C.$t("chat.intent.corrected")),1)):(l(),m("span",xt,u(c.message.content),1))])]),f("div",kt,[b.value?(l(),m("div",Ct,[f("div",wt,u(C.$t("chat.intent.label.original")),1),f("div",$t,u(i.value),1)])):O("",!0),b.value?(l(),m("div",It,[f("div",Mt,u(C.$t("chat.intent.label.understood")),1),f("div",Ot,u(r.value),1)])):O("",!0),f("div",zt,[f("div",Et,"🎯 "+u(C.$t("chat.intent.label.intent")),1),f("div",At,u(I.value),1)]),S.value&&S.value.length>0?(l(),m("div",Tt,[f("div",Ft,"📝 "+u(C.$t("chat.intent.label.keyPoints")),1),f("ul",Rt,[(l(!0),m(G,null,J(S.value,(N,ne)=>(l(),m("li",{key:ne},u(N),1))),128))])])):O("",!0),T.value?(l(),m("div",Pt,[f("div",qt,"📝 "+u(C.$t("chat.intent.label.correction")),1),f("div",jt,u(T.value),1)])):O("",!0)]),x.value?(l(),m("div",Dt,[y(_(ye),{spin:""}),f("span",null,u(C.$t("chat.intent.status.understanding")),1),M.value>0?(l(),m("span",Lt,"· "+u(M.value)+" tokens",1)):O("",!0)])):!d.value&&!v.value?(l(),m("div",Nt,[y(U,{type:"primary",onClick:E},{default:w(()=>[y(_(he)),A(" "+u(C.$t("chat.intent.action.confirm")),1)]),_:1}),y(U,{onClick:P},{default:w(()=>[y(_(Ve)),A(" "+u(C.$t("chat.intent.action.correct")),1)]),_:1})])):O("",!0),s.value?(l(),m("div",Wt,[y(Q,{value:n.value,"onUpdate:value":B[0]||(B[0]=N=>n.value=N),placeholder:C.$t("chat.intent.action.correctPlaceholder"),"auto-size":{minRows:2,maxRows:6}},null,8,["value","placeholder"]),f("div",Bt,[y(U,{type:"primary",size:"small",onClick:H},{default:w(()=>[y(_(he)),A(" "+u(C.$t("chat.intent.action.submitCorrection")),1)]),_:1}),y(U,{size:"small",onClick:q},{default:w(()=>[y(_(He)),A(" "+u(C.$t("chat.intent.action.cancelCorrection")),1)]),_:1})])])):O("",!0)])}}},Ht=ee(Vt,[["__scopeId","data-v-ded139e5"]]),Ut={style:{display:"flex",height:"calc(100vh - 56px - 48px)",gap:"16px"}},Qt={style:{width:"240px","flex-shrink":"0",background:"var(--bg-card)","border-radius":"8px",border:"1px solid var(--border-color)",display:"flex","flex-direction":"column",overflow:"hidden"}},Kt={key:0,style:{padding:"6px 12px 4px","font-size":"11px",color:"#1677ff",background:"rgba(22,119,255,.07)","border-bottom":"1px solid rgba(22,119,255,.15)",display:"flex","align-items":"center",gap:"4px"}},Gt=["title"],Jt={key:1,style:{padding:"6px 12px 4px","font-size":"11px",color:"#722ed1",background:"rgba(114,46,209,.07)","border-bottom":"1px solid rgba(114,46,209,.15)",display:"flex","align-items":"center",gap:"4px"}},Xt={style:{padding:"10px 12px","border-bottom":"1px solid var(--border-color)",display:"flex",gap:"8px"}},Yt={style:{flex:"1","overflow-y":"auto",padding:"8px"}},Zt=["onClick"],es={class:"session-icon"},ts={class:"session-info"},ss={class:"session-title"},ns={class:"session-meta"},is={key:0,style:{"text-align":"center",color:"var(--text-muted)",padding:"24px 0","font-size":"13px"}},os={style:{flex:"1",background:"var(--bg-card)","border-radius":"8px",border:"1px solid var(--border-color)",display:"flex","flex-direction":"column",overflow:"hidden"}},as={key:0,style:{flex:"1",display:"flex","flex-direction":"column","align-items":"center","justify-content":"center",color:"var(--text-muted)"}},ls={style:{"font-size":"16px","margin-bottom":"8px",color:"#777"}},rs={style:{"font-size":"13px",color:"var(--text-muted)"}},cs={style:{"margin-top":"24px",display:"flex",gap:"12px"}},us={key:1,class:"chat-header"},ds={key:2,class:"chat-area-body"},hs={key:0,class:"chat-empty-prompts"},fs={class:"empty-title"},ms={class:"empty-hint"},ps={class:"quick-prompts"},vs={key:1,class:"system-banner"},gs={key:2,class:"tool-msg"},ys={key:0,class:"tool-detail"},_s={class:"tool-detail__pre tool-detail__pre--input"},bs={key:0,class:"tool-detail__result"},Ss={class:"tool-detail__pre tool-detail__pre--result"},xs={class:"msg-body"},ks={class:"msg-meta-row"},Cs={class:"msg-role"},ws={class:"msg-time"},$s={key:0,class:"msg-tokens"},Is={key:0,class:"bubble user"},Ms={key:2,class:"question-card"},Os={class:"question-text"},zs={key:0,style:{display:"flex","flex-wrap":"wrap",gap:"8px","margin-top":"10px"}},Es={key:3,style:{padding:"16px","border-top":"1px solid var(--border-color)"}},As={style:{display:"flex",gap:"8px","align-items":"flex-end"}},Ts={style:{"margin-bottom":"8px","font-size":"12px",color:"var(--text-muted)"}},Fs={style:{"margin-top":"8px"}},Rs={__name:"Chat",setup(c){const{t:g,tm:e,rt:t}=Fe(),s=Ee()||null,n=Ae()||null,i=window.__CC_CONFIG__||{},a=k(()=>i.mode==="project"),r=Re(),I=new Set,S=L(null),b=L(""),R=k(()=>r.contextMode);function d(o){r.setContextMode(o)}const v=k(()=>r.currentSessionId),x=k(()=>v.value?r.getMessages(v.value):[]),M=k(()=>{const o=r.streaming[v.value];return o?.active?o.content:null}),T=k(()=>{const o=x.value;return M.value?[...o,{role:"assistant",content:M.value,_streaming:!0,timestamp:Date.now()}]:o}),E=k(()=>r.pendingQuestion[v.value]),P=k(()=>r.getIsLoading(v.value));function H(o){if(!o)return"";const p=new Date(o);return`${String(p.getHours()).padStart(2,"0")}:${String(p.getMinutes()).padStart(2,"0")}`}const q=Te(new Set);function C(o){q.has(o)?q.delete(o):q.add(o)}function B(o,p){return{id:`tool-${p}`,label:o.tool||g("chat.tool.unknownTool"),detail:U(o),status:o.status==="done"?"done":"running"}}function U(o){if(o.status==="running"){const F=o.input&&typeof o.input=="object"?Object.keys(o.input):[];return F.length?g("chat.tool.argsPreview",{n:F.length,key:F[0]}):g("chat.tool.running")}if(o.result==null)return g("chat.tool.done");const $=(typeof o.result=="string"?o.result:JSON.stringify(o.result)).split(`
5
- `)[0]||"";return $.length>48?`${$.slice(0,48)}…`:$||g("chat.tool.done")}async function Q(o){await r.createSession(o)}async function N(){if(!b.value.trim()||P.value||!v.value)return;const o=b.value;b.value="",await r.submitUserInput(v.value,o)}function ne(o){r.confirmIntent(v.value,o.messageId)}function be(o){r.correctIntent(v.value,o.messageId,o.correction)}const le=k(()=>{const o=r.customQuickPrompts;if(Array.isArray(o)&&o.length>0)return o;const p=e("chat.quickPrompts");return p?Object.values(p).map($=>t($)):[]}),X=L(!1),te=L("");function Se(){te.value=le.value.join(`
6
- `),X.value=!0}function xe(){const o=te.value.split(`
7
- `).map(p=>p.trim()).filter(p=>p.length>0);r.setCustomQuickPrompts(o.length>0?o:null),X.value=!1}function ke(){r.setCustomQuickPrompts(null),X.value=!1}const Ce=k(()=>g(`chat.empty.hint.${R.value}`));async function we(o){v.value||await r.createSession("chat"),b.value=o,await N()}function re(o){r.answerQuestion(v.value,o)}Z([x,M],()=>{W(()=>{S.value?.scrollToBottom()})},{deep:!0});async function ce({prompt:o,autoSend:p,session:$,token:F}){if(!o||I.has(F))return;I.add(F);let j=$||v.value;j?j!==v.value&&await r.switchSession(j):j=await r.createSession("chat"),b.value=o,p!==!1&&(await W(),await N())}function $e(){const o=s?.query||{};if(!o.prompt)return null;const p=Array.isArray(o.prompt)?o.prompt[0]:String(o.prompt);if(!p.trim())return null;const F=(Array.isArray(o.autoSend)?o.autoSend[0]:o.autoSend)!=="false",j=Array.isArray(o.session)?o.session[0]:o.session,se=j?String(j):null,oe=`query::${p}::${se||""}::${F}`;return{prompt:p,autoSend:F,session:se,token:oe}}async function ie(){const o=$e();if(o){await ce(o),n&&s&&n.replace({path:s.path,query:{}}).catch(()=>{});return}const p=r.pendingAutoSend;if(p?.prompt){const $=p.token||`staged::${p.prompt}::${Date.now()}`;await ce({...p,token:$}),r.clearAutoSend?.()}}return s&&Z(()=>[s.query.prompt,s.query.autoSend,s.query.session],()=>{ie()},{immediate:!1}),Z(()=>r.pendingAutoSend,()=>{ie()},{deep:!0}),ge(async()=>{await r.loadSessions(),await ie()}),(o,p)=>{const $=D("a-button"),F=D("a-radio-button"),j=D("a-radio-group"),se=D("a-avatar"),oe=D("a-input-search"),ue=D("a-textarea"),Ie=D("a-modal");return l(),m("div",Ut,[f("div",Qt,[a.value?(l(),m("div",Kt,[y(_(fe)),f("span",{style:{overflow:"hidden","text-overflow":"ellipsis","white-space":"nowrap"},title:_(i).projectRoot},u(_(i).projectName||o.$t("chat.scope.fallbackProjectName")),9,Gt)])):(l(),m("div",Jt,[y(_(me)),f("span",null,u(o.$t("chat.scope.globalSessions")),1)])),f("div",Xt,[y($,{type:"primary",size:"small",style:{flex:"1"},onClick:p[0]||(p[0]=h=>Q("chat"))},{icon:w(()=>[y(_(Ue))]),default:w(()=>[A(" "+u(o.$t("chat.newChat")),1)]),_:1}),y($,{size:"small",style:{flex:"1"},onClick:p[1]||(p[1]=h=>Q("agent"))},{icon:w(()=>[y(_(pe))]),default:w(()=>[A(" "+u(o.$t("chat.newAgent")),1)]),_:1})]),f("div",Yt,[(l(!0),m(G,null,J(_(r).sessions,h=>(l(),m("div",{key:h.id,class:Y(["session-item",{active:h.id===_(r).currentSessionId}]),onClick:V=>_(r).switchSession(h.id)},[f("span",es,u(h.type==="agent"?"🤖":"💬"),1),f("div",ts,[f("div",ss,u(h.title||o.$t("chat.session.untitled")),1),f("div",ns,u(o.$t("chat.session.messageCountSuffix",{n:h.messageCount||0})),1)])],10,Zt))),128)),_(r).sessions.length?O("",!0):(l(),m("div",is,u(o.$t("chat.sidebarEmpty")),1))])]),f("div",os,[v.value?O("",!0):(l(),m("div",as,[p[7]||(p[7]=f("div",{style:{"font-size":"48px","margin-bottom":"16px"}},"💬",-1)),f("div",ls,u(o.$t("chat.empty.title")),1),f("div",rs,u(o.$t("chat.empty.subtitle")),1),f("div",cs,[y($,{type:"primary",onClick:p[2]||(p[2]=h=>Q("chat"))},{default:w(()=>[A(u(o.$t("chat.empty.newChat")),1)]),_:1}),y($,{style:{},onClick:p[3]||(p[3]=h=>Q("agent"))},{default:w(()=>[A(u(o.$t("chat.empty.newAgent")),1)]),_:1})])])),v.value?(l(),m("div",us,[y(j,{value:R.value,size:"small","button-style":"solid","onUpdate:value":d},{default:w(()=>[y(F,{value:"project",disabled:!a.value},{default:w(()=>[y(_(fe)),A(" "+u(o.$t("chat.contextMode.project")),1)]),_:1},8,["disabled"]),y(F,{value:"file",disabled:""},{default:w(()=>[y(_(Qe)),A(" "+u(o.$t("chat.contextMode.file")),1)]),_:1}),y(F,{value:"global"},{default:w(()=>[y(_(me)),A(" "+u(o.$t("chat.contextMode.global")),1)]),_:1})]),_:1},8,["value"])])):O("",!0),v.value?(l(),m("div",ds,[T.value.length===0?(l(),m("div",hs,[p[8]||(p[8]=f("div",{class:"empty-icon"},"💬",-1)),f("div",fs,u(o.$t("chat.empty.startTitle")),1),f("div",ms,u(Ce.value),1),f("div",ps,[(l(!0),m(G,null,J(le.value,h=>(l(),z($,{key:h,size:"small",class:"quick-prompt-btn",onClick:V=>we(h)},{default:w(()=>[A(u(h),1)]),_:2},1032,["onClick"]))),128)),y($,{size:"small",type:"dashed",class:"quick-prompt-btn quick-prompt-edit",onClick:Se},{default:w(()=>[A(u(o.$t("chat.quickPromptsEditor.openButton")),1)]),_:1})])])):(l(),z(pt,{key:1,ref_key:"virtualListRef",ref:S,messages:T.value,"estimate-size":120,class:"chat-virtual-list"},{default:w(({message:h,index:V})=>[f("div",{class:Y(["message-row",h.role])},[h.type===_(Pe).INTENT_CONFIRMATION?(l(),z(Ht,{key:0,message:h,onConfirm:ne,onCorrect:be},null,8,["message"])):h.role==="system"?(l(),m("div",vs,u(h.content),1)):h.role==="tool"?(l(),m("div",gs,[y(nt,{item:B(h,V),expandable:"",expanded:q.has(V),onToggle:Ps=>C(V)},null,8,["item","expanded","onToggle"]),q.has(V)?(l(),m("div",ys,[f("pre",_s,u(JSON.stringify(h.input,null,2)),1),h.result?(l(),m("div",bs,[f("pre",Ss,u(typeof h.result=="string"?h.result:JSON.stringify(h.result,null,2)),1)])):O("",!0)])):O("",!0)])):(l(),m("div",{key:3,class:Y(["msg-with-avatar",h.role])},[y(se,{size:32,style:ae({backgroundColor:h.role==="user"?"#1890ff":"#52c41a",flexShrink:0})},{icon:w(()=>[h.role==="user"?(l(),z(_(Ke),{key:0})):(l(),z(_(pe),{key:1}))]),_:2},1032,["style"]),f("div",xs,[f("div",ks,[f("span",Cs,u(h.role==="user"?o.$t("chat.role.me"):"AI"),1),f("span",ws,u(H(h.timestamp)),1),h.tokens?(l(),m("span",$s,"· "+u(h.tokens)+" tokens",1)):O("",!0)]),h.role==="user"?(l(),m("div",Is,u(h.content),1)):(l(),z(at,{key:1,class:Y(["bubble assistant",{streaming:h._streaming}]),content:h.content},null,8,["class","content"]))])],2))],2)]),_:1},8,["messages"])),E.value?(l(),m("div",Ms,[f("div",Os,u(E.value.question),1),E.value.choices?.length?(l(),m("div",zs,[(l(!0),m(G,null,J(E.value.choices,h=>(l(),z($,{key:h,size:"small",onClick:V=>re(h)},{default:w(()=>[A(u(h),1)]),_:2},1032,["onClick"]))),128))])):(l(),z(oe,{key:1,placeholder:o.$t("chat.input.answerPlaceholder"),"enter-button":o.$t("chat.input.send"),style:{"margin-top":"10px"},onSearch:re},null,8,["placeholder","enter-button"]))])):O("",!0)])):O("",!0),v.value?(l(),m("div",Es,[f("div",As,[y(ue,{value:b.value,"onUpdate:value":p[4]||(p[4]=h=>b.value=h),placeholder:P.value?o.$t("chat.input.loading"):o.$t("chat.input.placeholder"),"auto-size":{minRows:1,maxRows:6},disabled:P.value,style:{background:"var(--bg-card-hover)","border-color":"var(--border-color)",color:"var(--text-primary)",resize:"none",flex:"1"},onKeydown:Oe(ze(N,["exact","prevent"]),["enter"])},null,8,["value","placeholder","disabled","onKeydown"]),y($,{type:"primary",loading:P.value,onClick:N,style:{height:"40px"}},{icon:w(()=>[y(_(Ge))]),_:1},8,["loading"])])])):O("",!0)]),y(Ie,{open:X.value,"onUpdate:open":p[6]||(p[6]=h=>X.value=h),title:o.$t("chat.quickPromptsEditor.title"),"ok-text":o.$t("chat.quickPromptsEditor.save"),"cancel-text":o.$t("chat.quickPromptsEditor.cancel"),onOk:xe},{default:w(()=>[f("div",Ts,u(o.$t("chat.quickPromptsEditor.hint")),1),y(ue,{value:te.value,"onUpdate:value":p[5]||(p[5]=h=>te.value=h),rows:8,placeholder:o.$t("chat.quickPromptsEditor.placeholder")},null,8,["value","placeholder"]),f("div",Fs,[y($,{size:"small",onClick:ke},{default:w(()=>[A(u(o.$t("chat.quickPromptsEditor.reset")),1)]),_:1})])]),_:1},8,["open","title","ok-text","cancel-text"])])}}},Bs=ee(Rs,[["__scopeId","data-v-937db6c5"]]);export{Bs as default};
@@ -1 +0,0 @@
1
- import{E as dt,r as h,a as A,f as pt}from"./vendor-Ci2pTZ_t.js";import{u as g}from"./index-BPtmPFwc.js";let L=0;function Y(s){return L+=1,`msg_${Date.now()}_${L}_${s}`}const v=Object.freeze({USER:"user",ASSISTANT:"assistant",SYSTEM:"system",INTENT_RECOGNITION:"intent-recognition",INTENT_CONFIRMATION:"intent-confirmation",TASK_ANALYSIS:"task-analysis",INTERVIEW:"interview",TASK_PLAN:"task-plan",PROGRESS:"progress",ERROR:"error"}),Q=Object.freeze({USER:"user",ASSISTANT:"assistant",SYSTEM:"system"});function mt(s,i){return{id:Y("intent_confirmation"),role:Q.ASSISTANT,type:v.INTENT_CONFIRMATION,content:"我理解您的需求如下,请确认:",timestamp:Date.now(),metadata:{originalInput:s,understanding:i||{},status:"pending",correction:null}}}function gt(s,i,u={}){const{reason:c,extractedInfo:p}=u,m={CONTINUE_EXECUTION:"✅ 收到,继续执行任务...",MODIFY_REQUIREMENT:`⚠️ 检测到需求变更:${p||i}`,CLARIFICATION:`📝 已记录补充信息:${p||i}`,CANCEL_TASK:"❌ 任务已取消"};return{id:Y("intent_system"),role:Q.SYSTEM,type:v.SYSTEM,content:m[s]||"⚠️ 未识别意图",timestamp:Date.now(),metadata:{intent:s,reason:c,userInput:i,extractedInfo:p}}}const I="新对话",b="新 Agent",K="cc.web-panel.chat.contextMode",G=["project","file","global"],B="cc.web-panel.chat.intentDecisions",$=200;function St(){try{const s=typeof localStorage<"u"?localStorage.getItem(K):null;return G.includes(s)?s:null}catch{return null}}function J(){try{if(typeof localStorage>"u")return{};const s=localStorage.getItem(B);if(!s)return{};const i=JSON.parse(s);return i&&typeof i=="object"?i:{}}catch{return{}}}function yt(s){try{if(typeof localStorage>"u")return;const i=Object.entries(s);if(i.length>$){i.sort((c,p)=>(c[1]?.ts||0)-(p[1]?.ts||0));const u=i.slice(-$);s=Object.fromEntries(u)}localStorage.setItem(B,JSON.stringify(s))}catch{}}function F(s,i,u){if(!s||!i)return;const c=J();c[`${s}::${i}`]={...u,ts:Date.now()},yt(c)}function Tt(s,i){return!s||!i?null:J()[`${s}::${i}`]||null}const ht={"assistant.delta":"response-token","assistant.final":"response-complete","assistant.message":"response-complete","tool.call.started":"tool-executing","tool.call.completed":"tool-result","tool.call.failed":"tool-result","slot.filling":"question","approval.requested":"question",error:"error"},vt=dt("chat",()=>{const s=h([]),i=h(null),u=A({}),c=A({}),p=A({}),m=A({}),P=(typeof window<"u"&&window.__CC_CONFIG__||{}).mode==="project",X=P?"project":"global",C=St(),O=h(C==="file"||C==="project"&&!P?"global":C||X);function z(t){if(G.includes(t)){O.value=t;try{typeof localStorage<"u"&&localStorage.setItem(K,t)}catch{}}}const w="cc.web-panel.chat.customQuickPrompts";function V(){try{if(typeof localStorage>"u")return null;const t=localStorage.getItem(w);if(!t)return null;const e=JSON.parse(t);if(!Array.isArray(e))return null;const n=e.map(o=>typeof o=="string"?o.trim():"").filter(o=>o.length>0&&o.length<=120).slice(0,12);return n.length>0?n:null}catch{return null}}const M=h(V());function W(t){if(t==null){M.value=null;try{typeof localStorage<"u"&&localStorage.removeItem(w)}catch{}return}if(!Array.isArray(t))return;const e=t.map(n=>typeof n=="string"?n.trim():"").filter(n=>n.length>0&&n.length<=120).slice(0,12);M.value=e.length>0?e:null;try{typeof localStorage<"u"&&(e.length>0?localStorage.setItem(w,JSON.stringify(e)):localStorage.removeItem(w))}catch{}}const D=h(null);let j=0;function H({prompt:t,autoSend:e=!0,session:n=null}={}){!t||!String(t).trim()||(j+=1,D.value={prompt:String(t),autoSend:e!==!1,session:n||null,token:`staged::${j}::${Date.now()}`})}function Z(){D.value=null}let U=null;const q=new Set;function S(t){return u[t]||(u[t]=[]),u[t]}function x(t){return!!(t&&m[t])}function y(t,e){t&&(m[t]=!!e)}function R(t){if(!t?.id)return;const e=s.value.find(n=>n.id===t.id);if(e){Object.assign(e,t);return}s.value.unshift(t)}function k(t,e=g()){u[t]||(u[t]=[]),c[t]||(c[t]={content:"",active:!1}),m[t]==null&&(m[t]=!1),!q.has(t)&&(q.add(t),e.onSession(t,n=>nt(t,n)))}function _(t=g()){U||(U=t.onRuntimeEvent(e=>{const n=e.payload||{},o=n.record||{};if(e.type==="session:start"){const a=n.sessionType||o.type||"chat";y(n.sessionId,!1),R({id:n.sessionId,type:a,provider:o.provider||null,model:o.model||null,projectRoot:o.projectRoot||null,status:o.status||"created",title:a==="chat"?I:b,createdAt:Date.now(),messageCount:o.messageCount??0})}else if(e.type==="session:resume"){const a=n.sessionId;if(!a)return;Array.isArray(n.history)&&(u[a]=n.history.map(r=>({role:r.role,content:r.content,timestamp:r.timestamp||Date.now()}))),c[a]||(c[a]={content:"",active:!1}),m[a]==null&&(m[a]=!1),R({id:a,type:o.type||null,provider:o.provider||null,model:o.model||null,projectRoot:o.projectRoot||null,status:o.status||"resumed",messageCount:o.messageCount??(Array.isArray(n.history)?n.history.length:0)})}else if(e.type==="session:end"){const a=n.sessionId;s.value=s.value.filter(r=>r.id!==a),delete m[a],i.value===a&&(i.value=s.value[0]?.id||null)}}))}async function tt(){const t=g();_(t),s.value=await t.listSessions(),s.value.forEach(e=>{k(e.id,t)})}async function et(t="chat",e={}){const n=g();_(n);const o=await n.createSession(t,null,e);return R({id:o,type:t,title:t==="chat"?I:b,createdAt:Date.now(),messageCount:0}),y(o,!1),k(o,n),i.value=o,o}function nt(t,e){const n=S(t),o=ht[e.type]||e.type,a=e.payload||{};if(o==="response-token"){c[t]||(c[t]={content:"",active:!0});const r=e.token||a.token||a.delta||a.content||"";c[t].content+=r,c[t].active=!0,y(t,!0)}else if(o==="response-complete"){const r=e.content||a.content||c[t]?.content||"";n.push({role:"assistant",content:r,timestamp:Date.now()}),c[t]&&(c[t].content="",c[t].active=!1);const f=s.value.find(l=>l.id===t);if(f&&(f.title===I||f.title===b)){const l=n.find(E=>E.role==="user");l&&(f.title=l.content.slice(0,30))}f&&(f.messageCount=n.filter(l=>l.role!=="tool").length),y(t,!1)}else if(o==="tool-executing")n.push({role:"tool",tool:e.tool||a.tool||a.toolName||"unknown",input:e.input||a.input||a.args||null,status:"running",timestamp:Date.now()}),y(t,!0);else if(o==="tool-result"){const r=e.tool||a.tool||a.toolName||"unknown",f=[...n].reverse().find(l=>l.role==="tool"&&l.tool===r);f&&(f.result=e.result||a.result||a.output||null,f.status="done")}else if(o==="question")p[t]={requestId:e.requestId||a.requestId||e.id,question:e.question||a.question||a.message||"",choices:e.choices||a.choices||a.options||[]},y(t,!1);else if(o==="error"){const r=e.message||a.message||"Unknown error";n.push({role:"assistant",content:`Error: ${r}`,timestamp:Date.now()}),y(t,!1),c[t]&&(c[t].active=!1)}}async function T(t,e){const n=g();_(n),S(t).push({role:"user",content:e,timestamp:Date.now()}),c[t]||(c[t]={content:"",active:!1}),c[t].active=!0,y(t,!0),n.sendSessionMessage(t,e)}async function ot(t,e){if(!t||!e?.trim())return;const n=O.value;if(n==="global"){await T(t,e);return}const o=g(),a=S(t).filter(d=>d.role==="user"||d.role==="assistant").slice(-5).map(d=>({role:d.role,content:String(d.content||"").slice(0,500)})),r=mt(e,{});r.metadata&&(r.metadata.streaming=!0,r.metadata.streamingTokens=0),r.content="理解中…";const f=S(t);f.push(r);let l=null;const E=new AbortController,ft=setTimeout(()=>E.abort(new Error("Intent understand wall-clock timeout")),9e4);try{const d=await o.sendStream({type:"chat.intent.understand-stream",sessionId:t,userInput:e,contextMode:n,history:a},{onChunk:()=>{r.metadata&&(r.metadata.streamingTokens=(r.metadata.streamingTokens||0)+1)},idleMs:6e4,signal:E.signal});d?.success&&(l=d)}catch{}finally{clearTimeout(ft)}if(!(l&&(l.correctedInput&&l.correctedInput!==e||Array.isArray(l.keyPoints)&&l.keyPoints.length>0))){const d=f.indexOf(r);d>=0&&f.splice(d,1),await T(t,e);return}r.content="我理解您的需求如下,请确认:",r.metadata&&(r.metadata.streaming=!1,r.metadata.understanding={correctedInput:l.correctedInput,intent:l.intent,keyPoints:l.keyPoints});const N=Tt(t,r.id);N?.status&&r.metadata&&(r.metadata.status=N.status,N.correction&&(r.metadata.correction=N.correction))}async function at(t,e){const o=S(t).find(r=>r.id===e);if(!o||o.type!==v.INTENT_CONFIRMATION)return;o.metadata&&(o.metadata.status="confirmed"),F(t,e,{status:"confirmed",correction:null});const a=o.metadata?.originalInput||"";a.trim()&&await T(t,a)}async function rt(t,e,n){const a=S(t).find(f=>f.id===e);if(!a||a.type!==v.INTENT_CONFIRMATION)return;a.metadata&&(a.metadata.status="corrected",a.metadata.correction=n),F(t,e,{status:"corrected",correction:n});const r=(n||"").trim();r&&await T(t,r)}async function st(t,e,n={}){const o=g();try{return await o.sendRaw({type:"chat.intent.classify-followup",sessionId:t,input:e,context:n},2e4)}catch{return null}}function it(t,e,n,o={}){S(t).push(gt(e,n,o))}function ct(t,e){const n=g(),o=p[t];o&&(n.answerQuestion(t,o.requestId,e),delete p[t])}async function lt(t){const e=g();if(_(e),i.value=t,k(t,e),!u[t]||u[t].length===0)try{await e.resumeSession(t)}catch{}}const ut=pt(()=>x(i.value));return{sessions:s,currentSessionId:i,messages:u,streaming:c,pendingQuestion:p,loadingBySession:m,isLoading:ut,contextMode:O,setContextMode:z,customQuickPrompts:M,setCustomQuickPrompts:W,pendingAutoSend:D,scheduleAutoSend:H,clearAutoSend:Z,getIsLoading:x,loadSessions:tt,createSession:et,sendMessage:T,submitUserInput:ot,confirmIntent:at,correctIntent:rt,classifyFollowupIntent:st,pushFollowupIntentBanner:it,answerQuestion:ct,switchSession:lt,getMessages:S}});export{v as M,vt as u};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-9_JZdhJl.js";import{R as t}from"./index-BPtmPFwc.js";import"./index-DVvcsuh0.js";import"./vendor-Ci2pTZ_t.js";import"./icons-B2G69bhT.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-BFHRFhrC.js";import{R as t}from"./index-BPtmPFwc.js";import"./responsiveObserve-Dva2arKe.js";import"./vendor-Ci2pTZ_t.js";import"./useFlexGapSupport-z-vK8Wcv.js";import"./styleChecker-CuXdVqkl.js";import"./index-DVvcsuh0.js";import"./icons-B2G69bhT.js";const l=t(o);export{l as default};