@chenzy-design/core 0.2.1 → 0.4.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 (283) hide show
  1. package/dist/ai-chat-dialogue.d.ts +300 -0
  2. package/dist/ai-chat-dialogue.d.ts.map +1 -0
  3. package/dist/ai-chat-dialogue.js +699 -0
  4. package/dist/ai-chat-dialogue.js.map +1 -0
  5. package/dist/ai-chat-dialogue.test.d.ts +2 -0
  6. package/dist/ai-chat-dialogue.test.d.ts.map +1 -0
  7. package/dist/ai-chat-dialogue.test.js +338 -0
  8. package/dist/ai-chat-dialogue.test.js.map +1 -0
  9. package/dist/ai-chat-input.d.ts +191 -0
  10. package/dist/ai-chat-input.d.ts.map +1 -0
  11. package/dist/ai-chat-input.js +274 -0
  12. package/dist/ai-chat-input.js.map +1 -0
  13. package/dist/ai-chat-input.test.d.ts +2 -0
  14. package/dist/ai-chat-input.test.d.ts.map +1 -0
  15. package/dist/ai-chat-input.test.js +339 -0
  16. package/dist/ai-chat-input.test.js.map +1 -0
  17. package/dist/audio-player.d.ts +154 -0
  18. package/dist/audio-player.d.ts.map +1 -0
  19. package/dist/audio-player.js +254 -0
  20. package/dist/audio-player.js.map +1 -0
  21. package/dist/audio-player.test.d.ts +2 -0
  22. package/dist/audio-player.test.d.ts.map +1 -0
  23. package/dist/audio-player.test.js +275 -0
  24. package/dist/audio-player.test.js.map +1 -0
  25. package/dist/back-top.d.ts +4 -1
  26. package/dist/back-top.d.ts.map +1 -1
  27. package/dist/back-top.js +5 -2
  28. package/dist/back-top.js.map +1 -1
  29. package/dist/back-top.test.js +3 -2
  30. package/dist/back-top.test.js.map +1 -1
  31. package/dist/calendar.d.ts +132 -44
  32. package/dist/calendar.d.ts.map +1 -1
  33. package/dist/calendar.js +413 -70
  34. package/dist/calendar.js.map +1 -1
  35. package/dist/calendar.test.js +160 -76
  36. package/dist/calendar.test.js.map +1 -1
  37. package/dist/chat.d.ts +172 -0
  38. package/dist/chat.d.ts.map +1 -0
  39. package/dist/chat.js +210 -0
  40. package/dist/chat.js.map +1 -0
  41. package/dist/chat.test.d.ts +2 -0
  42. package/dist/chat.test.d.ts.map +1 -0
  43. package/dist/chat.test.js +181 -0
  44. package/dist/chat.test.js.map +1 -0
  45. package/dist/code-highlight.d.ts +30 -0
  46. package/dist/code-highlight.d.ts.map +1 -0
  47. package/dist/code-highlight.js +37 -0
  48. package/dist/code-highlight.js.map +1 -0
  49. package/dist/code-highlight.test.d.ts +2 -0
  50. package/dist/code-highlight.test.d.ts.map +1 -0
  51. package/dist/code-highlight.test.js +36 -0
  52. package/dist/code-highlight.test.js.map +1 -0
  53. package/dist/collapsible.d.ts +41 -0
  54. package/dist/collapsible.d.ts.map +1 -0
  55. package/dist/collapsible.js +33 -0
  56. package/dist/collapsible.js.map +1 -0
  57. package/dist/collapsible.test.d.ts +2 -0
  58. package/dist/collapsible.test.d.ts.map +1 -0
  59. package/dist/collapsible.test.js +57 -0
  60. package/dist/collapsible.test.js.map +1 -0
  61. package/dist/color-value.d.ts +60 -0
  62. package/dist/color-value.d.ts.map +1 -0
  63. package/dist/color-value.js +165 -0
  64. package/dist/color-value.js.map +1 -0
  65. package/dist/color-value.test.d.ts +2 -0
  66. package/dist/color-value.test.d.ts.map +1 -0
  67. package/dist/color-value.test.js +104 -0
  68. package/dist/color-value.test.js.map +1 -0
  69. package/dist/config-provider.d.ts +76 -37
  70. package/dist/config-provider.d.ts.map +1 -1
  71. package/dist/config-provider.js +107 -32
  72. package/dist/config-provider.js.map +1 -1
  73. package/dist/config-provider.test.js +123 -60
  74. package/dist/config-provider.test.js.map +1 -1
  75. package/dist/cropper.d.ts +164 -0
  76. package/dist/cropper.d.ts.map +1 -0
  77. package/dist/cropper.js +841 -0
  78. package/dist/cropper.js.map +1 -0
  79. package/dist/cropper.test.d.ts +2 -0
  80. package/dist/cropper.test.d.ts.map +1 -0
  81. package/dist/cropper.test.js +259 -0
  82. package/dist/cropper.test.js.map +1 -0
  83. package/dist/drag-move.d.ts +119 -0
  84. package/dist/drag-move.d.ts.map +1 -0
  85. package/dist/drag-move.js +237 -0
  86. package/dist/drag-move.js.map +1 -0
  87. package/dist/drag-move.test.d.ts +2 -0
  88. package/dist/drag-move.test.d.ts.map +1 -0
  89. package/dist/drag-move.test.js +304 -0
  90. package/dist/drag-move.test.js.map +1 -0
  91. package/dist/editable.d.ts +24 -4
  92. package/dist/editable.d.ts.map +1 -1
  93. package/dist/editable.js +18 -0
  94. package/dist/editable.js.map +1 -1
  95. package/dist/editable.test.js +55 -2
  96. package/dist/editable.test.js.map +1 -1
  97. package/dist/ellipsis.d.ts +13 -0
  98. package/dist/ellipsis.d.ts.map +1 -1
  99. package/dist/ellipsis.js +36 -0
  100. package/dist/ellipsis.js.map +1 -1
  101. package/dist/ellipsis.test.js +37 -1
  102. package/dist/ellipsis.test.js.map +1 -1
  103. package/dist/form-path.d.ts +19 -0
  104. package/dist/form-path.d.ts.map +1 -0
  105. package/dist/form-path.js +97 -0
  106. package/dist/form-path.js.map +1 -0
  107. package/dist/form-path.test.d.ts +2 -0
  108. package/dist/form-path.test.d.ts.map +1 -0
  109. package/dist/form-path.test.js +57 -0
  110. package/dist/form-path.test.js.map +1 -0
  111. package/dist/form-validate.d.ts +13 -0
  112. package/dist/form-validate.d.ts.map +1 -0
  113. package/dist/form-validate.js +204 -0
  114. package/dist/form-validate.js.map +1 -0
  115. package/dist/form.d.ts +91 -18
  116. package/dist/form.d.ts.map +1 -1
  117. package/dist/form.js +170 -115
  118. package/dist/form.js.map +1 -1
  119. package/dist/form.test.js +349 -76
  120. package/dist/form.test.js.map +1 -1
  121. package/dist/highlight.d.ts +42 -32
  122. package/dist/highlight.d.ts.map +1 -1
  123. package/dist/highlight.js +67 -41
  124. package/dist/highlight.js.map +1 -1
  125. package/dist/highlight.test.js +73 -32
  126. package/dist/highlight.test.js.map +1 -1
  127. package/dist/hotkeys.d.ts +151 -0
  128. package/dist/hotkeys.d.ts.map +1 -0
  129. package/dist/hotkeys.js +188 -0
  130. package/dist/hotkeys.js.map +1 -0
  131. package/dist/hotkeys.test.d.ts +2 -0
  132. package/dist/hotkeys.test.d.ts.map +1 -0
  133. package/dist/hotkeys.test.js +170 -0
  134. package/dist/hotkeys.test.js.map +1 -0
  135. package/dist/index.d.ts +33 -17
  136. package/dist/index.d.ts.map +1 -1
  137. package/dist/index.js +32 -13
  138. package/dist/index.js.map +1 -1
  139. package/dist/input.d.ts +34 -0
  140. package/dist/input.d.ts.map +1 -0
  141. package/dist/input.js +54 -0
  142. package/dist/input.js.map +1 -0
  143. package/dist/input.test.d.ts +2 -0
  144. package/dist/input.test.d.ts.map +1 -0
  145. package/dist/input.test.js +56 -0
  146. package/dist/input.test.js.map +1 -0
  147. package/dist/markdown-render.d.ts +49 -0
  148. package/dist/markdown-render.d.ts.map +1 -0
  149. package/dist/markdown-render.js +61 -0
  150. package/dist/markdown-render.js.map +1 -0
  151. package/dist/markdown-render.test.d.ts +2 -0
  152. package/dist/markdown-render.test.d.ts.map +1 -0
  153. package/dist/markdown-render.test.js +106 -0
  154. package/dist/markdown-render.test.js.map +1 -0
  155. package/dist/notification.d.ts +40 -31
  156. package/dist/notification.d.ts.map +1 -1
  157. package/dist/notification.js +86 -70
  158. package/dist/notification.js.map +1 -1
  159. package/dist/notification.test.js +62 -39
  160. package/dist/notification.test.js.map +1 -1
  161. package/dist/numeral.d.ts +32 -0
  162. package/dist/numeral.d.ts.map +1 -0
  163. package/dist/numeral.js +67 -0
  164. package/dist/numeral.js.map +1 -0
  165. package/dist/numeral.test.d.ts +2 -0
  166. package/dist/numeral.test.d.ts.map +1 -0
  167. package/dist/numeral.test.js +59 -0
  168. package/dist/numeral.test.js.map +1 -0
  169. package/dist/overflow-list.d.ts +9 -40
  170. package/dist/overflow-list.d.ts.map +1 -1
  171. package/dist/overflow-list.js +9 -70
  172. package/dist/overflow-list.js.map +1 -1
  173. package/dist/overflow-list.test.js +1 -122
  174. package/dist/overflow-list.test.js.map +1 -1
  175. package/dist/pagination.d.ts +17 -0
  176. package/dist/pagination.d.ts.map +1 -1
  177. package/dist/pagination.js +48 -0
  178. package/dist/pagination.js.map +1 -1
  179. package/dist/pagination.test.js +40 -1
  180. package/dist/pagination.test.js.map +1 -1
  181. package/dist/pincode.d.ts +79 -0
  182. package/dist/pincode.d.ts.map +1 -0
  183. package/dist/pincode.js +119 -0
  184. package/dist/pincode.js.map +1 -0
  185. package/dist/pincode.test.d.ts +2 -0
  186. package/dist/pincode.test.d.ts.map +1 -0
  187. package/dist/pincode.test.js +151 -0
  188. package/dist/pincode.test.js.map +1 -0
  189. package/dist/progress.d.ts +32 -30
  190. package/dist/progress.d.ts.map +1 -1
  191. package/dist/progress.js +257 -64
  192. package/dist/progress.js.map +1 -1
  193. package/dist/progress.test.js +50 -47
  194. package/dist/progress.test.js.map +1 -1
  195. package/dist/resizable.d.ts +200 -0
  196. package/dist/resizable.d.ts.map +1 -0
  197. package/dist/resizable.js +329 -0
  198. package/dist/resizable.js.map +1 -0
  199. package/dist/resizable.test.d.ts +2 -0
  200. package/dist/resizable.test.d.ts.map +1 -0
  201. package/dist/resizable.test.js +302 -0
  202. package/dist/resizable.test.js.map +1 -0
  203. package/dist/scroll-list.d.ts +69 -62
  204. package/dist/scroll-list.d.ts.map +1 -1
  205. package/dist/scroll-list.js +103 -144
  206. package/dist/scroll-list.js.map +1 -1
  207. package/dist/scroll-list.test.js +100 -110
  208. package/dist/scroll-list.test.js.map +1 -1
  209. package/dist/sidebar.d.ts +46 -0
  210. package/dist/sidebar.d.ts.map +1 -0
  211. package/dist/sidebar.js +65 -0
  212. package/dist/sidebar.js.map +1 -0
  213. package/dist/sidebar.test.d.ts +2 -0
  214. package/dist/sidebar.test.d.ts.map +1 -0
  215. package/dist/sidebar.test.js +88 -0
  216. package/dist/sidebar.test.js.map +1 -0
  217. package/dist/spin.d.ts +5 -5
  218. package/dist/spin.d.ts.map +1 -1
  219. package/dist/spin.js +13 -39
  220. package/dist/spin.js.map +1 -1
  221. package/dist/spin.test.js +2 -26
  222. package/dist/spin.test.js.map +1 -1
  223. package/dist/toast.d.ts +33 -30
  224. package/dist/toast.d.ts.map +1 -1
  225. package/dist/toast.js +77 -72
  226. package/dist/toast.js.map +1 -1
  227. package/dist/toast.test.js +63 -37
  228. package/dist/toast.test.js.map +1 -1
  229. package/dist/tree.d.ts +22 -5
  230. package/dist/tree.d.ts.map +1 -1
  231. package/dist/tree.js +61 -9
  232. package/dist/tree.js.map +1 -1
  233. package/dist/tree.test.js +72 -1
  234. package/dist/tree.test.js.map +1 -1
  235. package/dist/user-guide.d.ts +73 -0
  236. package/dist/user-guide.d.ts.map +1 -0
  237. package/dist/user-guide.js +95 -0
  238. package/dist/user-guide.js.map +1 -0
  239. package/dist/user-guide.test.d.ts +2 -0
  240. package/dist/user-guide.test.d.ts.map +1 -0
  241. package/dist/user-guide.test.js +109 -0
  242. package/dist/user-guide.test.js.map +1 -0
  243. package/dist/video-player.d.ts +196 -0
  244. package/dist/video-player.d.ts.map +1 -0
  245. package/dist/video-player.js +461 -0
  246. package/dist/video-player.js.map +1 -0
  247. package/dist/video-player.test.d.ts +2 -0
  248. package/dist/video-player.test.d.ts.map +1 -0
  249. package/dist/video-player.test.js +435 -0
  250. package/dist/video-player.test.js.map +1 -0
  251. package/package.json +17 -1
  252. package/dist/banner.d.ts +0 -19
  253. package/dist/banner.d.ts.map +0 -1
  254. package/dist/banner.js +0 -20
  255. package/dist/banner.js.map +0 -1
  256. package/dist/banner.test.d.ts +0 -2
  257. package/dist/banner.test.d.ts.map +0 -1
  258. package/dist/banner.test.js +0 -29
  259. package/dist/banner.test.js.map +0 -1
  260. package/dist/breakpoints.d.ts +0 -30
  261. package/dist/breakpoints.d.ts.map +0 -1
  262. package/dist/breakpoints.js +0 -45
  263. package/dist/breakpoints.js.map +0 -1
  264. package/dist/breakpoints.test.d.ts +0 -2
  265. package/dist/breakpoints.test.d.ts.map +0 -1
  266. package/dist/breakpoints.test.js +0 -46
  267. package/dist/breakpoints.test.js.map +0 -1
  268. package/dist/lottie-icon.d.ts +0 -88
  269. package/dist/lottie-icon.d.ts.map +0 -1
  270. package/dist/lottie-icon.js +0 -84
  271. package/dist/lottie-icon.js.map +0 -1
  272. package/dist/lottie-icon.test.d.ts +0 -2
  273. package/dist/lottie-icon.test.d.ts.map +0 -1
  274. package/dist/lottie-icon.test.js +0 -88
  275. package/dist/lottie-icon.test.js.map +0 -1
  276. package/dist/sider.d.ts +0 -26
  277. package/dist/sider.d.ts.map +0 -1
  278. package/dist/sider.js +0 -55
  279. package/dist/sider.js.map +0 -1
  280. package/dist/sider.test.d.ts +0 -2
  281. package/dist/sider.test.d.ts.map +0 -1
  282. package/dist/sider.test.js +0 -29
  283. package/dist/sider.test.js.map +0 -1
@@ -0,0 +1,699 @@
1
+ /**
2
+ * AIChatDialogue headless — OpenAI Response Object 消息格式类型 + 数据 Adapter。
3
+ * 框架无关(无 DOM / 无组件依赖)。渲染层(svelte)消费这些类型与转换函数。
4
+ * 对齐 Semi `@douyinfe/semi-foundation/aiChatDialogue`(foundation + dataAdapter)。
5
+ * 见 specs/components/show/AIChatDialogue.spec.md。
6
+ *
7
+ * 本文件实现 §13 的「本次范围」:类型全谱 + 非流式 Adapter
8
+ * (responseToMessage / chatCompletionToMessage)。流式 Adapter 为 P1,见 spec 登记。
9
+ */
10
+ /**
11
+ * Response Object → Message(对齐 Semi responseToMessage)。
12
+ * 非流式:直接把 output 作为 content,assistant 角色。
13
+ */
14
+ export function responseToMessage(response) {
15
+ // exactOptionalPropertyTypes:仅在有值时写入 optional 字段,避免显式 undefined。
16
+ const msg = { id: response.id, role: 'assistant' };
17
+ if (response.output !== undefined)
18
+ msg.content = response.output;
19
+ if (response.created_at !== undefined)
20
+ msg.createdAt = response.created_at;
21
+ if (response.output_text !== undefined)
22
+ msg.output_text = response.output_text;
23
+ if (response.model !== undefined)
24
+ msg.model = response.model;
25
+ if (response.status !== undefined)
26
+ msg.status = response.status;
27
+ return msg;
28
+ }
29
+ /**
30
+ * ChatCompletion Object → Message[](对齐 Semi chatCompletionToMessage)。
31
+ * 每个 choice → 一条 Message;content/refusal → output_text/refusal 块,
32
+ * function_call / tool_calls / audio 各成块。因 `n` 可 >1,返回数组。
33
+ */
34
+ export function chatCompletionToMessage(chatCompletion) {
35
+ return chatCompletion.choices.map((choice) => {
36
+ const message = choice.message;
37
+ const role = message.role;
38
+ const id = chatCompletion.id;
39
+ const status = 'completed';
40
+ const outputResult = [];
41
+ // text + refusal
42
+ if (message.content !== '' || message.refusal !== '') {
43
+ const annotations = message.annotations?.length
44
+ ? message.annotations.map((annotation) => ({
45
+ type: annotation.type,
46
+ ...(annotation.url_citation ?? {}),
47
+ }))
48
+ : [];
49
+ const outputMessage = [
50
+ message.content !== '' &&
51
+ message.content !== undefined && {
52
+ type: 'output_text',
53
+ text: message.content,
54
+ annotations,
55
+ },
56
+ message.refusal !== '' &&
57
+ message.refusal !== undefined && { type: 'refusal', refusal: message.refusal },
58
+ ].filter(Boolean);
59
+ if (outputMessage.length > 0) {
60
+ outputResult.push({
61
+ type: 'message',
62
+ id,
63
+ role: 'assistant',
64
+ status,
65
+ content: outputMessage,
66
+ });
67
+ }
68
+ }
69
+ // function call
70
+ if (message.function_call) {
71
+ outputResult.push({
72
+ ...message.function_call,
73
+ type: 'function_call',
74
+ status: 'completed',
75
+ });
76
+ }
77
+ // tool calls
78
+ if (message.tool_calls?.length) {
79
+ for (const toolCall of message.tool_calls) {
80
+ if (toolCall.type === 'function') {
81
+ outputResult.push({
82
+ status: 'completed',
83
+ ...(toolCall.function ?? {}),
84
+ type: 'function_call',
85
+ });
86
+ }
87
+ else {
88
+ outputResult.push({
89
+ ...(toolCall.custom ?? {}),
90
+ type: 'custom_call',
91
+ });
92
+ }
93
+ }
94
+ }
95
+ // audio(ChatCompletion 特有)
96
+ if (message.audio) {
97
+ outputResult.push({ type: 'audio', ...message.audio });
98
+ }
99
+ return { id, role, content: outputResult, status };
100
+ });
101
+ }
102
+ /** 判定 ContentItem 的展示类型(供渲染层分派)。 */
103
+ export function contentItemType(item) {
104
+ return item.type ?? 'unknown';
105
+ }
106
+ /** 规范化 Message.content 为 ContentItem[](string → 单个 output_text 块)。 */
107
+ export function normalizeDialogueContent(content) {
108
+ if (content == null)
109
+ return [];
110
+ if (typeof content === 'string') {
111
+ return [{ type: 'message', content: [{ type: 'output_text', text: content }] }];
112
+ }
113
+ return content;
114
+ }
115
+ /** 深拷贝(避免修改原始 chunk 数据)。 */
116
+ function deepCloneChunk(obj) {
117
+ if (obj === null || typeof obj !== 'object')
118
+ return obj;
119
+ if (Array.isArray(obj))
120
+ return obj.map((item) => deepCloneChunk(item));
121
+ const cloned = {};
122
+ for (const key in obj) {
123
+ if (Object.prototype.hasOwnProperty.call(obj, key))
124
+ cloned[key] = deepCloneChunk(obj[key]);
125
+ }
126
+ return cloned;
127
+ }
128
+ /**
129
+ * streamingResponseToMessage —— 流式 Response 块的增量归约器(全功能,无序容错)。
130
+ * 对齐 Semi:按 sequence_number 顺序处理、缓冲无序块、MAX_GAP(10) 容错跳过丢失块、
131
+ * 逐类型累积 output_text/refusal/reasoning/function_call/custom_tool_call/mcp/code_interpreter/
132
+ * image_generation 等 delta,快速路径 response.completed 直接返回完整消息。
133
+ *
134
+ * @param chunks 本次到达的流式块数组
135
+ * @param prevState 上次调用返回的 nextState(增量处理;首次传 undefined/null)
136
+ * @returns { message, nextState } —— message 为尽力而为的累积消息(in_progress/completed);无块返回 null
137
+ */
138
+ export function streamingResponseToMessage(chunks, prevState) {
139
+ if (!chunks?.length)
140
+ return null;
141
+ // 快速路径:末块是 response.completed,直接返回完整响应。
142
+ const tail = chunks[chunks.length - 1];
143
+ if (tail?.type === 'response.completed' && tail.response) {
144
+ const { id, model, status, output, output_text, created_at } = tail.response;
145
+ const message = { id, role: 'assistant' };
146
+ if (output !== undefined)
147
+ message.content = output;
148
+ if (created_at !== undefined)
149
+ message.createdAt = created_at;
150
+ if (output_text !== undefined)
151
+ message.output_text = output_text;
152
+ if (model !== undefined)
153
+ message.model = model;
154
+ if (status !== undefined)
155
+ message.status = status;
156
+ return { message, nextState: null };
157
+ }
158
+ // 初始化 / 从上次状态恢复。
159
+ const state = prevState
160
+ ? {
161
+ processedSeq: new Set(prevState.processedSeq),
162
+ outputs: new Map(prevState.outputs),
163
+ meta: { ...prevState.meta },
164
+ error: prevState.error ?? null,
165
+ buffer: new Map(prevState.buffer),
166
+ lastProcessedSeq: prevState.lastProcessedSeq ?? -1,
167
+ }
168
+ : {
169
+ processedSeq: new Set(),
170
+ outputs: new Map(),
171
+ meta: {},
172
+ error: null,
173
+ buffer: new Map(),
174
+ lastProcessedSeq: -1,
175
+ };
176
+ // 过滤已处理块,未处理块入缓冲(无 sequence_number 的用 lastProcessedSeq+0.5 临时键)。
177
+ const unprocessed = chunks.filter((c) => {
178
+ const seq = c?.sequence_number;
179
+ return typeof seq !== 'number' || !state.processedSeq.has(seq);
180
+ });
181
+ for (const chunk of unprocessed) {
182
+ const seq = chunk?.sequence_number;
183
+ if (typeof seq === 'number')
184
+ state.buffer.set(seq, chunk);
185
+ else
186
+ state.buffer.set(state.lastProcessedSeq + 0.5, chunk);
187
+ }
188
+ // 逐块处理(累积各类型 delta)。
189
+ const processChunk = (chunk) => {
190
+ switch (chunk.type) {
191
+ case 'response.created': {
192
+ const r = chunk.response;
193
+ if (r) {
194
+ state.meta.id = r.id ?? state.meta.id;
195
+ state.meta.model = r.model ?? state.meta.model;
196
+ state.meta.status = r.status ?? state.meta.status;
197
+ state.meta.created_at = r.created_at ?? state.meta.created_at;
198
+ }
199
+ break;
200
+ }
201
+ case 'response.output_item.added': {
202
+ const outIdx = typeof chunk.output_index === 'number' ? chunk.output_index : 0;
203
+ if (!state.outputs.has(outIdx))
204
+ state.outputs.set(outIdx, deepCloneChunk(chunk.item ?? {}));
205
+ break;
206
+ }
207
+ case 'response.output_item.done':
208
+ state.outputs.set(chunk.output_index, deepCloneChunk(chunk.item));
209
+ break;
210
+ case 'response.content_part.added':
211
+ case 'response.content_part.done': {
212
+ const item = state.outputs.get(chunk.output_index);
213
+ item.content = item.content ?? [];
214
+ item.content[chunk.content_index] = deepCloneChunk(chunk.part);
215
+ break;
216
+ }
217
+ case 'response.output_text.delta': {
218
+ const item = state.outputs.get(chunk.output_index);
219
+ item.content = item.content ?? [];
220
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
221
+ type: 'output_text',
222
+ text: '',
223
+ };
224
+ item.content[chunk.content_index].text =
225
+ (item.content[chunk.content_index].text ?? '') + (chunk.delta ?? '');
226
+ break;
227
+ }
228
+ case 'response.output_text.done': {
229
+ const item = state.outputs.get(chunk.output_index);
230
+ item.content = item.content ?? [];
231
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
232
+ type: 'output_text',
233
+ text: '',
234
+ };
235
+ item.content[chunk.content_index].text = chunk.text;
236
+ break;
237
+ }
238
+ case 'response.output_text.annotation.added': {
239
+ const item = state.outputs.get(chunk.output_index);
240
+ item.content = item.content ?? [];
241
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
242
+ type: 'output_text',
243
+ text: '',
244
+ annotations: [],
245
+ };
246
+ item.content[chunk.content_index].annotations =
247
+ item.content[chunk.content_index].annotations ?? [];
248
+ item.content[chunk.content_index].annotations[chunk.annotation_index] = deepCloneChunk(chunk.annotation);
249
+ break;
250
+ }
251
+ case 'response.refusal.delta': {
252
+ const item = state.outputs.get(chunk.output_index);
253
+ item.content = item.content ?? [];
254
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
255
+ type: 'refusal',
256
+ refusal: '',
257
+ };
258
+ item.content[chunk.content_index].refusal =
259
+ (item.content[chunk.content_index].refusal ?? '') + (chunk.delta ?? '');
260
+ break;
261
+ }
262
+ case 'response.refusal.done': {
263
+ const item = state.outputs.get(chunk.output_index);
264
+ item.content = item.content ?? [];
265
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
266
+ type: 'refusal',
267
+ refusal: '',
268
+ };
269
+ item.content[chunk.content_index].refusal = chunk.refusal;
270
+ break;
271
+ }
272
+ case 'response.reasoning_summary_part.added':
273
+ case 'response.reasoning_summary_part.done': {
274
+ const item = state.outputs.get(chunk.output_index);
275
+ item.summary = item.summary ?? [];
276
+ item.summary[chunk.summary_index] = deepCloneChunk(chunk.part);
277
+ break;
278
+ }
279
+ case 'response.reasoning_summary_text.delta': {
280
+ const item = state.outputs.get(chunk.output_index);
281
+ item.summary = item.summary ?? [];
282
+ item.summary[chunk.summary_index] = item.summary[chunk.summary_index] ?? {
283
+ type: 'reasoning',
284
+ text: '',
285
+ };
286
+ item.summary[chunk.summary_index].text =
287
+ (item.summary[chunk.summary_index].text ?? '') + (chunk.delta ?? '');
288
+ break;
289
+ }
290
+ case 'response.reasoning_summary_text.done': {
291
+ const item = state.outputs.get(chunk.output_index);
292
+ item.summary = item.summary ?? [];
293
+ item.summary[chunk.summary_index] = item.summary[chunk.summary_index] ?? {
294
+ type: 'reasoning',
295
+ text: '',
296
+ };
297
+ item.summary[chunk.summary_index].text = chunk.text;
298
+ break;
299
+ }
300
+ case 'response.reasoning_text.delta': {
301
+ const item = state.outputs.get(chunk.output_index);
302
+ item.content = item.content ?? [];
303
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
304
+ type: 'reasoning',
305
+ text: '',
306
+ };
307
+ item.content[chunk.content_index].text =
308
+ (item.content[chunk.content_index].text ?? '') + (chunk.delta ?? '');
309
+ break;
310
+ }
311
+ case 'response.reasoning_text.done': {
312
+ const item = state.outputs.get(chunk.output_index);
313
+ item.content = item.content ?? [];
314
+ item.content[chunk.content_index] = item.content[chunk.content_index] ?? {
315
+ type: 'reasoning',
316
+ text: '',
317
+ };
318
+ item.content[chunk.content_index].text = chunk.text;
319
+ break;
320
+ }
321
+ case 'response.function_call_arguments.delta': {
322
+ const item = state.outputs.get(chunk.output_index);
323
+ item.arguments = (item.arguments ?? '') + (chunk.delta ?? '');
324
+ break;
325
+ }
326
+ case 'response.function_call_arguments.done': {
327
+ const item = state.outputs.get(chunk.output_index);
328
+ item.arguments = chunk.arguments;
329
+ item.name = chunk.name;
330
+ break;
331
+ }
332
+ case 'response.custom_tool_call_input.delta': {
333
+ const item = state.outputs.get(chunk.output_index);
334
+ item.input = (item.input ?? '') + (chunk.delta ?? '');
335
+ break;
336
+ }
337
+ case 'response.custom_tool_call_input.done': {
338
+ const item = state.outputs.get(chunk.output_index);
339
+ item.input = chunk.input;
340
+ break;
341
+ }
342
+ case 'response.mcp_call_arguments.delta': {
343
+ const item = state.outputs.get(chunk.output_index);
344
+ item.arguments = (item.arguments ?? '') + (chunk.delta ?? '');
345
+ break;
346
+ }
347
+ case 'response.mcp_call_arguments.done': {
348
+ const item = state.outputs.get(chunk.output_index);
349
+ item.arguments = chunk.arguments;
350
+ break;
351
+ }
352
+ case 'response.file_search_call.in_progress':
353
+ case 'response.web_search_call.in_progress':
354
+ case 'response.image_generation_call.in_progress':
355
+ case 'response.mcp_call.in_progress':
356
+ case 'response.mcp_list_tools.in_progress':
357
+ case 'response.code_interpreter_call.in_progress': {
358
+ const out = state.outputs.get(chunk.output_index);
359
+ if (out)
360
+ out.status = 'in_progress';
361
+ break;
362
+ }
363
+ case 'response.mcp_call.failed':
364
+ case 'response.mcp_list_tools.failed': {
365
+ const out = state.outputs.get(chunk.output_index);
366
+ if (out)
367
+ out.status = 'failed';
368
+ break;
369
+ }
370
+ case 'response.file_search_call.completed':
371
+ case 'response.web_search_call.completed':
372
+ case 'response.image_generation_call.completed':
373
+ case 'response.mcp_call.completed':
374
+ case 'response.mcp_list_tools.completed':
375
+ case 'response.code_interpreter_call.completed': {
376
+ const out = state.outputs.get(chunk.output_index);
377
+ if (out)
378
+ out.status = 'completed';
379
+ break;
380
+ }
381
+ case 'response.code_interpreter_call_code.delta': {
382
+ const item = state.outputs.get(chunk.output_index);
383
+ item.code = (item.code ?? '') + (chunk.delta ?? '');
384
+ break;
385
+ }
386
+ case 'response.code_interpreter_call_code.done': {
387
+ const item = state.outputs.get(chunk.output_index);
388
+ item.code = chunk.code;
389
+ break;
390
+ }
391
+ case 'response.image_generation_call.partial_image': {
392
+ const item = state.outputs.get(chunk.output_index);
393
+ if (item)
394
+ item.result = chunk.partial_image_b64;
395
+ break;
396
+ }
397
+ case 'error':
398
+ state.error = { code: chunk.code, message: chunk.message };
399
+ break;
400
+ case 'response.completed':
401
+ state.meta.status = chunk.response?.status ?? 'completed';
402
+ break;
403
+ default:
404
+ break;
405
+ }
406
+ };
407
+ // 顺序处理:从 lastProcessedSeq+1 开始,处理连续块(含无 seq 的 N.5 块)。
408
+ let nextExpected = state.lastProcessedSeq + 1;
409
+ let processed;
410
+ do {
411
+ processed = false;
412
+ const chunk = state.buffer.get(nextExpected);
413
+ if (chunk) {
414
+ processChunk(chunk);
415
+ state.processedSeq.add(nextExpected);
416
+ state.buffer.delete(nextExpected);
417
+ state.lastProcessedSeq = nextExpected;
418
+ nextExpected++;
419
+ processed = true;
420
+ }
421
+ else {
422
+ const decimalKey = state.lastProcessedSeq + 0.5;
423
+ const noSeqChunk = state.buffer.get(decimalKey);
424
+ if (noSeqChunk) {
425
+ processChunk(noSeqChunk);
426
+ state.buffer.delete(decimalKey);
427
+ state.lastProcessedSeq = nextExpected;
428
+ nextExpected++;
429
+ processed = true;
430
+ }
431
+ }
432
+ } while (processed);
433
+ // 容错:缓冲积压超过 MAX_GAP(10) 时,假设中间块永久丢失,继续处理剩余连续块。
434
+ const MAX_GAP = 10;
435
+ const bufferedSeqs = Array.from(state.buffer.keys())
436
+ .filter((k) => typeof k === 'number' && k === Math.floor(k))
437
+ .sort((a, b) => a - b);
438
+ if (bufferedSeqs.length > MAX_GAP) {
439
+ let lastSeq = state.lastProcessedSeq;
440
+ for (const seq of bufferedSeqs) {
441
+ if (seq === lastSeq + 1) {
442
+ const chunk = state.buffer.get(seq);
443
+ if (chunk) {
444
+ processChunk(chunk);
445
+ state.processedSeq.add(seq);
446
+ state.buffer.delete(seq);
447
+ state.lastProcessedSeq = seq;
448
+ lastSeq = seq;
449
+ }
450
+ }
451
+ else
452
+ break;
453
+ }
454
+ }
455
+ // 构建尽力而为消息。
456
+ const content = Array.from(state.outputs.values()).filter((item) => item !== null);
457
+ const output_text = content
458
+ .filter((p) => p?.type === 'output_text')
459
+ .map((p) => p?.text ?? '')
460
+ .join('');
461
+ let message = null;
462
+ if (content.length || state.meta.id) {
463
+ // exactOptionalPropertyTypes:仅在有值时写入 optional 字段。
464
+ message = {
465
+ id: state.meta.id ?? '',
466
+ role: 'assistant',
467
+ content,
468
+ output_text,
469
+ status: state.meta.status ?? 'in_progress',
470
+ error: state.error ?? null,
471
+ };
472
+ if (state.meta.created_at !== undefined)
473
+ message.createdAt = state.meta.created_at;
474
+ if (state.meta.model !== undefined)
475
+ message.model = state.meta.model;
476
+ }
477
+ return { message, nextState: state };
478
+ }
479
+ /** 按 choice.index 分组(每 chunk 的 choices 拆成单 choice 的独立 chunk)。 */
480
+ function groupByChoiceIndex(chunks) {
481
+ const grouped = [];
482
+ for (const chunk of chunks) {
483
+ for (const choice of chunk.choices) {
484
+ const idx = choice.index;
485
+ if (!grouped[idx])
486
+ grouped[idx] = [];
487
+ grouped[idx].push({ ...chunk, choices: [choice] });
488
+ }
489
+ }
490
+ return grouped;
491
+ }
492
+ /** 末块 finish_reason 非 null → completed,否则 in_progress。 */
493
+ function chatCompletionStatus(chunks) {
494
+ const last = chunks[chunks.length - 1];
495
+ return last?.choices?.[0]?.finish_reason != null ? 'completed' : 'in_progress';
496
+ }
497
+ /**
498
+ * streamingChatCompletionToMessage —— 流式 ChatCompletion 块的增量归约器(全功能)。
499
+ * 对齐 Semi:按 choice.index 分组、基于 state.processedCountByIndex 增量处理新到达片段、
500
+ * 累积 content/refusal/function_call/tool_calls(function/custom),产出每 index 一条 Message[]。
501
+ *
502
+ * @param chunks 本次到达的流式块数组
503
+ * @param prevState 上次调用返回的 state(增量;首次传 undefined)
504
+ * @returns { messages, state }
505
+ */
506
+ export function streamingChatCompletionToMessage(chunks, prevState) {
507
+ const grouped = groupByChoiceIndex(chunks);
508
+ let state = prevState;
509
+ const results = grouped
510
+ .map((groupChunks, groupIndex) => {
511
+ const id = groupChunks[0]?.id ?? '';
512
+ const status = chatCompletionStatus(groupChunks);
513
+ const stateKey = `${id}:${groupChunks[0]?.choices?.[0]?.index ?? groupIndex}`;
514
+ const processedCount = state?.processedCountByIndex?.[stateKey] ?? 0;
515
+ const start = processedCount > 0 ? Math.min(processedCount, groupChunks.length) : 0;
516
+ const chunksToProcess = state ? groupChunks.slice(start) : groupChunks;
517
+ // 本 index 无新增内容 → 沿用上次结果。
518
+ if (state && chunksToProcess.length === 0)
519
+ return state.previousResult?.[groupIndex];
520
+ const previousResult = state?.previousResult?.[groupIndex];
521
+ let textContent = '';
522
+ let refusal = '';
523
+ const functionCall = { name: '', arguments: '' };
524
+ const toolCalls = [];
525
+ // 从上次结果恢复已累积内容(content 为 ContentItem[] 时遍历)。
526
+ const prevContent = Array.isArray(previousResult?.content) ? previousResult.content : [];
527
+ prevContent.forEach((item) => {
528
+ item.content?.forEach?.((content) => {
529
+ if (content.type === 'output_text')
530
+ textContent += content.text;
531
+ if (content.type === 'refusal')
532
+ refusal += content.refusal;
533
+ });
534
+ if (item.type === 'function_call' && !item.id) {
535
+ functionCall.name = item.name;
536
+ functionCall.arguments = item.arguments;
537
+ }
538
+ if (item.type === 'tool_call' || (item.type === 'function_call' && item.id)) {
539
+ toolCalls.push(item);
540
+ }
541
+ });
542
+ // 累积本次新到达 delta。
543
+ for (const chunk of chunksToProcess) {
544
+ const delta = chunk.choices[0]?.delta;
545
+ if (delta?.content)
546
+ textContent += delta.content;
547
+ if (delta?.refusal)
548
+ refusal += delta.refusal;
549
+ if (delta?.function_call) {
550
+ if (delta.function_call.name)
551
+ functionCall.name += delta.function_call.name;
552
+ functionCall.arguments += delta.function_call.arguments ?? '';
553
+ }
554
+ if (delta?.tool_calls) {
555
+ for (const toolCall of delta.tool_calls) {
556
+ const cur = toolCalls.find((t) => t.id === toolCall.id);
557
+ if (cur) {
558
+ if (toolCall?.function?.name) {
559
+ cur.name += toolCall.function.name;
560
+ cur.arguments += toolCall.function.arguments ?? '';
561
+ }
562
+ else if (toolCall?.custom?.name) {
563
+ cur.name += toolCall.custom.name;
564
+ cur.input = (cur.input ?? '') + (toolCall.custom.input ?? '');
565
+ }
566
+ cur.status = status;
567
+ }
568
+ else {
569
+ toolCalls.push({
570
+ ...toolCall?.function,
571
+ ...toolCall?.custom,
572
+ type: toolCall?.function ? 'function_call' : 'custom_call',
573
+ id: toolCall.id,
574
+ });
575
+ }
576
+ }
577
+ }
578
+ }
579
+ const outputMessage = [
580
+ textContent !== '' && { type: 'output_text', text: textContent },
581
+ refusal !== '' && { type: 'refusal', refusal },
582
+ ].filter(Boolean);
583
+ const outputResult = [
584
+ outputMessage.length > 0 && {
585
+ type: 'message',
586
+ id,
587
+ role: 'assistant',
588
+ status,
589
+ content: outputMessage,
590
+ },
591
+ functionCall.name !== '' && { type: 'function_call', ...functionCall },
592
+ ...toolCalls,
593
+ ].filter(Boolean);
594
+ // 更新已处理计数。
595
+ if (state && state.processedCountByIndex) {
596
+ state.processedCountByIndex[stateKey] = groupChunks.length;
597
+ }
598
+ else {
599
+ state = { processedCountByIndex: { [stateKey]: groupChunks.length } };
600
+ }
601
+ return { id, role: 'assistant', content: outputResult, status };
602
+ })
603
+ .filter(Boolean);
604
+ if (!state)
605
+ state = { processedCountByIndex: {} };
606
+ state.previousResult = results.map((r) => deepCloneChunk(r));
607
+ return { messages: results, state };
608
+ }
609
+ // ————————————————————————————————————————————————
610
+ // 消息编辑桥(P1):dialogue 消息 → AIChatInput MessageContent(供 messageEditRender 载入编辑器)
611
+ // ————————————————————————————————————————————————
612
+ /**
613
+ * dialogueMessageToInput —— 把 AIDialogueMessage 抽取成 AIChatInputMessageContent(inputContents 文本段),
614
+ * 供 AIChatDialogue 的 messageEditRender 把消息载入 AIChatInput 编辑器(对齐 Semi messageToChatInput 方向)。
615
+ * 抽取 message.content 里 input_text/output_text 文本;attachments/references 若消息带则透传。
616
+ */
617
+ export function dialogueMessageToInput(message) {
618
+ const items = normalizeDialogueContent(message.content);
619
+ const inputContents = [];
620
+ for (const item of items) {
621
+ const inner = item.content;
622
+ if (Array.isArray(inner)) {
623
+ for (const part of inner) {
624
+ const p = part;
625
+ if ((p.type === 'input_text' || p.type === 'output_text') && p.text) {
626
+ inputContents.push({ type: 'text', text: p.text });
627
+ }
628
+ }
629
+ }
630
+ else if (typeof message.content === 'string' && message.output_text) {
631
+ inputContents.push({ type: 'text', text: message.output_text });
632
+ }
633
+ }
634
+ const payload = { inputContents };
635
+ const atts = message.attachments;
636
+ if (Array.isArray(atts) && atts.length > 0)
637
+ payload.attachments = atts;
638
+ const refs = message.references;
639
+ if (Array.isArray(refs) && refs.length > 0)
640
+ payload.references = refs;
641
+ return payload;
642
+ }
643
+ // ————————————————————————————————————————————————
644
+ // 工具调用块 helpers(P1 完整块交互)
645
+ // ————————————————————————————————————————————————
646
+ /**
647
+ * formatToolArguments —— 把工具调用的 arguments/input(JSON 字符串或对象)美化成缩进 JSON 文本。
648
+ * 解析失败(未完成的流式片段)时原样返回,保证增量流式下不抛错。
649
+ */
650
+ export function formatToolArguments(raw) {
651
+ if (raw == null)
652
+ return '';
653
+ if (typeof raw === 'object') {
654
+ try {
655
+ return JSON.stringify(raw, null, 2);
656
+ }
657
+ catch {
658
+ return String(raw);
659
+ }
660
+ }
661
+ const s = String(raw);
662
+ try {
663
+ return JSON.stringify(JSON.parse(s), null, 2);
664
+ }
665
+ catch {
666
+ return s; // 未完成的流式 JSON 片段,原样展示
667
+ }
668
+ }
669
+ export function toolCallStatus(item) {
670
+ const s = item.status;
671
+ if (s === 'in_progress' || s === 'queued')
672
+ return 'in_progress';
673
+ if (s === 'failed' || s === 'cancelled')
674
+ return 'failed';
675
+ if (s === 'incomplete')
676
+ return 'incomplete';
677
+ return 'completed';
678
+ }
679
+ export function toolCallView(item) {
680
+ const it = item;
681
+ const view = {
682
+ name: typeof it.name === 'string' ? it.name : '',
683
+ status: toolCallStatus(item),
684
+ arguments: formatToolArguments(it.arguments),
685
+ };
686
+ if (it.input != null)
687
+ view.input = formatToolArguments(it.input);
688
+ const out = it.output ?? it.result ?? it.code;
689
+ if (out != null)
690
+ view.output = formatToolArguments(out);
691
+ if (typeof it.call_id === 'string')
692
+ view.callId = it.call_id;
693
+ else if (typeof it.id === 'string')
694
+ view.callId = it.id;
695
+ if (typeof it.server_label === 'string')
696
+ view.serverLabel = it.server_label;
697
+ return view;
698
+ }
699
+ //# sourceMappingURL=ai-chat-dialogue.js.map