@bubblebrain-ai/bubble 0.0.24 → 0.0.26

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 (171) hide show
  1. package/README.md +5 -3
  2. package/dist/agent.js +1 -1
  3. package/dist/clipboard.d.ts +14 -0
  4. package/dist/clipboard.js +132 -0
  5. package/dist/config.d.ts +3 -0
  6. package/dist/config.js +22 -6
  7. package/dist/goal/format.js +34 -4
  8. package/dist/goal/store.d.ts +3 -0
  9. package/dist/goal/store.js +14 -1
  10. package/dist/goal/usage.d.ts +2 -0
  11. package/dist/goal/usage.js +3 -0
  12. package/dist/main.js +23 -42
  13. package/dist/model-catalog.d.ts +3 -1
  14. package/dist/model-catalog.js +17 -28
  15. package/dist/prompt/compose.js +1 -1
  16. package/dist/provider-anthropic.d.ts +4 -0
  17. package/dist/provider-anthropic.js +31 -0
  18. package/dist/provider-ark-responses.d.ts +17 -0
  19. package/dist/provider-ark-responses.js +462 -0
  20. package/dist/provider-transform.js +7 -0
  21. package/dist/provider.d.ts +7 -0
  22. package/dist/provider.js +170 -27
  23. package/dist/slash-commands/commands.js +22 -0
  24. package/dist/tools/todo.js +22 -38
  25. package/dist/tui/detect-theme.d.ts +1 -0
  26. package/dist/tui/detect-theme.js +23 -0
  27. package/dist/tui/image-display.d.ts +13 -0
  28. package/dist/tui/image-display.js +49 -0
  29. package/dist/tui/input-history.d.ts +37 -6
  30. package/dist/tui/input-history.js +194 -23
  31. package/dist/tui/model-switch.d.ts +42 -0
  32. package/dist/tui/model-switch.js +55 -0
  33. package/dist/tui-ink/app.d.ts +32 -2
  34. package/dist/tui-ink/app.js +1409 -549
  35. package/dist/tui-ink/approval/select.js +10 -0
  36. package/dist/tui-ink/detect-theme.d.ts +1 -2
  37. package/dist/tui-ink/detect-theme.js +1 -87
  38. package/dist/tui-ink/display-history.d.ts +1 -0
  39. package/dist/tui-ink/display-history.js +11 -0
  40. package/dist/tui-ink/feedback-dialog.js +10 -0
  41. package/dist/tui-ink/feishu-setup-picker.js +10 -0
  42. package/dist/tui-ink/footer.d.ts +1 -0
  43. package/dist/tui-ink/footer.js +8 -2
  44. package/dist/tui-ink/input-box.d.ts +71 -9
  45. package/dist/tui-ink/input-box.js +359 -121
  46. package/dist/tui-ink/input-history.d.ts +1 -16
  47. package/dist/tui-ink/input-history.js +1 -79
  48. package/dist/tui-ink/input-queue.d.ts +12 -0
  49. package/dist/tui-ink/input-queue.js +17 -0
  50. package/dist/tui-ink/key-events.d.ts +9 -0
  51. package/dist/tui-ink/key-events.js +8 -0
  52. package/dist/tui-ink/markdown.js +1 -1
  53. package/dist/tui-ink/message-list.d.ts +19 -1
  54. package/dist/tui-ink/message-list.js +111 -32
  55. package/dist/tui-ink/model-picker.d.ts +25 -2
  56. package/dist/tui-ink/model-picker.js +237 -20
  57. package/dist/tui-ink/plan-confirm.js +10 -0
  58. package/dist/tui-ink/question-dialog.js +46 -10
  59. package/dist/tui-ink/run.d.ts +10 -1
  60. package/dist/tui-ink/run.js +27 -42
  61. package/dist/tui-ink/session-picker.js +3 -0
  62. package/dist/tui-ink/submit-dedupe.d.ts +5 -0
  63. package/dist/tui-ink/submit-dedupe.js +25 -0
  64. package/dist/tui-ink/terminal-mouse.d.ts +24 -1
  65. package/dist/tui-ink/terminal-mouse.js +76 -21
  66. package/dist/tui-ink/theme.d.ts +6 -3
  67. package/dist/tui-ink/theme.js +10 -4
  68. package/dist/tui-ink/welcome.d.ts +1 -0
  69. package/dist/tui-ink/welcome.js +34 -27
  70. package/dist/variant/variant-resolver.js +4 -1
  71. package/package.json +1 -5
  72. package/dist/tui/clipboard.d.ts +0 -1
  73. package/dist/tui/clipboard.js +0 -53
  74. package/dist/tui/escape-confirmation.d.ts +0 -15
  75. package/dist/tui/escape-confirmation.js +0 -30
  76. package/dist/tui/global-key-router.d.ts +0 -3
  77. package/dist/tui/global-key-router.js +0 -87
  78. package/dist/tui/markdown-inline.d.ts +0 -22
  79. package/dist/tui/markdown-inline.js +0 -68
  80. package/dist/tui/markdown-theme-rules.d.ts +0 -23
  81. package/dist/tui/markdown-theme-rules.js +0 -164
  82. package/dist/tui/markdown-theme.d.ts +0 -5
  83. package/dist/tui/markdown-theme.js +0 -27
  84. package/dist/tui/opencode-spinner.d.ts +0 -22
  85. package/dist/tui/opencode-spinner.js +0 -216
  86. package/dist/tui/prompt-keybindings.d.ts +0 -42
  87. package/dist/tui/prompt-keybindings.js +0 -35
  88. package/dist/tui/render-signature.d.ts +0 -1
  89. package/dist/tui/render-signature.js +0 -7
  90. package/dist/tui/run.d.ts +0 -67
  91. package/dist/tui/run.js +0 -10166
  92. package/dist/tui/sidebar-mcp.d.ts +0 -31
  93. package/dist/tui/sidebar-mcp.js +0 -62
  94. package/dist/tui/sidebar-state.d.ts +0 -12
  95. package/dist/tui/sidebar-state.js +0 -69
  96. package/dist/tui/streaming-tool-args.d.ts +0 -15
  97. package/dist/tui/streaming-tool-args.js +0 -30
  98. package/dist/tui/tool-renderers/fallback.d.ts +0 -2
  99. package/dist/tui/tool-renderers/fallback.js +0 -75
  100. package/dist/tui/tool-renderers/registry.d.ts +0 -3
  101. package/dist/tui/tool-renderers/registry.js +0 -11
  102. package/dist/tui/tool-renderers/subagent.d.ts +0 -2
  103. package/dist/tui/tool-renderers/subagent.js +0 -135
  104. package/dist/tui/tool-renderers/types.d.ts +0 -36
  105. package/dist/tui/tool-renderers/types.js +0 -1
  106. package/dist/tui/tool-renderers/write-preview.d.ts +0 -12
  107. package/dist/tui/tool-renderers/write-preview.js +0 -32
  108. package/dist/tui/tool-renderers/write.d.ts +0 -6
  109. package/dist/tui/tool-renderers/write.js +0 -88
  110. package/dist/tui/transcript-scroll.d.ts +0 -25
  111. package/dist/tui/transcript-scroll.js +0 -20
  112. package/dist/tui-ink/transcript-viewport-math.d.ts +0 -11
  113. package/dist/tui-ink/transcript-viewport-math.js +0 -17
  114. package/dist/tui-ink/transcript-viewport.d.ts +0 -24
  115. package/dist/tui-ink/transcript-viewport.js +0 -83
  116. package/dist/tui-opentui/app.d.ts +0 -54
  117. package/dist/tui-opentui/app.js +0 -1371
  118. package/dist/tui-opentui/approval/approval-dialog.d.ts +0 -15
  119. package/dist/tui-opentui/approval/approval-dialog.js +0 -155
  120. package/dist/tui-opentui/approval/diff-view.d.ts +0 -9
  121. package/dist/tui-opentui/approval/diff-view.js +0 -43
  122. package/dist/tui-opentui/approval/select.d.ts +0 -37
  123. package/dist/tui-opentui/approval/select.js +0 -91
  124. package/dist/tui-opentui/detect-theme.d.ts +0 -2
  125. package/dist/tui-opentui/detect-theme.js +0 -87
  126. package/dist/tui-opentui/display-history.d.ts +0 -56
  127. package/dist/tui-opentui/display-history.js +0 -130
  128. package/dist/tui-opentui/edit-diff.d.ts +0 -11
  129. package/dist/tui-opentui/edit-diff.js +0 -57
  130. package/dist/tui-opentui/feedback-dialog.d.ts +0 -21
  131. package/dist/tui-opentui/feedback-dialog.js +0 -164
  132. package/dist/tui-opentui/feishu-setup-picker.d.ts +0 -7
  133. package/dist/tui-opentui/feishu-setup-picker.js +0 -272
  134. package/dist/tui-opentui/file-mentions.d.ts +0 -29
  135. package/dist/tui-opentui/file-mentions.js +0 -174
  136. package/dist/tui-opentui/footer.d.ts +0 -26
  137. package/dist/tui-opentui/footer.js +0 -40
  138. package/dist/tui-opentui/image-paste.d.ts +0 -54
  139. package/dist/tui-opentui/image-paste.js +0 -288
  140. package/dist/tui-opentui/input-box.d.ts +0 -32
  141. package/dist/tui-opentui/input-box.js +0 -462
  142. package/dist/tui-opentui/input-history.d.ts +0 -16
  143. package/dist/tui-opentui/input-history.js +0 -79
  144. package/dist/tui-opentui/markdown.d.ts +0 -66
  145. package/dist/tui-opentui/markdown.js +0 -127
  146. package/dist/tui-opentui/message-list.d.ts +0 -31
  147. package/dist/tui-opentui/message-list.js +0 -131
  148. package/dist/tui-opentui/model-picker.d.ts +0 -63
  149. package/dist/tui-opentui/model-picker.js +0 -450
  150. package/dist/tui-opentui/plan-confirm.d.ts +0 -9
  151. package/dist/tui-opentui/plan-confirm.js +0 -124
  152. package/dist/tui-opentui/question-dialog.d.ts +0 -10
  153. package/dist/tui-opentui/question-dialog.js +0 -110
  154. package/dist/tui-opentui/recent-activity.d.ts +0 -8
  155. package/dist/tui-opentui/recent-activity.js +0 -71
  156. package/dist/tui-opentui/run-session-picker.d.ts +0 -10
  157. package/dist/tui-opentui/run-session-picker.js +0 -28
  158. package/dist/tui-opentui/run.d.ts +0 -38
  159. package/dist/tui-opentui/run.js +0 -48
  160. package/dist/tui-opentui/session-picker.d.ts +0 -12
  161. package/dist/tui-opentui/session-picker.js +0 -120
  162. package/dist/tui-opentui/theme.d.ts +0 -89
  163. package/dist/tui-opentui/theme.js +0 -157
  164. package/dist/tui-opentui/todos.d.ts +0 -9
  165. package/dist/tui-opentui/todos.js +0 -45
  166. package/dist/tui-opentui/trace-groups.d.ts +0 -27
  167. package/dist/tui-opentui/trace-groups.js +0 -455
  168. package/dist/tui-opentui/use-terminal-size.d.ts +0 -4
  169. package/dist/tui-opentui/use-terminal-size.js +0 -5
  170. package/dist/tui-opentui/welcome.d.ts +0 -25
  171. package/dist/tui-opentui/welcome.js +0 -77
@@ -17,6 +17,25 @@ const MINIMAX_PROMPT_CACHE_MODELS = new Set([
17
17
  "minimax-m2",
18
18
  "m2-her",
19
19
  ]);
20
+ function anthropicEffortForLevel(level) {
21
+ switch (level) {
22
+ case "off":
23
+ return undefined;
24
+ case "minimal":
25
+ case "low":
26
+ return "low";
27
+ case "medium":
28
+ return "medium";
29
+ case "high":
30
+ return "high";
31
+ case "xhigh":
32
+ return "xhigh";
33
+ case "max":
34
+ return "max";
35
+ default:
36
+ return undefined;
37
+ }
38
+ }
20
39
  export function createAnthropicMessagesProvider(options) {
21
40
  async function* streamChat(messages, chatOptions) {
22
41
  const body = buildAnthropicRequest(options, messages, {
@@ -87,6 +106,18 @@ export function buildAnthropicRequest(options, messages, chatOptions) {
87
106
  }
88
107
  if (effectiveThinkingLevel !== "off") {
89
108
  body.thinking = { type: "adaptive" };
109
+ // Apply the selected reasoning depth via output_config.effort. Without this
110
+ // every thinking request silently ran at Anthropic's default (high),
111
+ // ignoring the chosen level. effort is an official-API feature, so only
112
+ // send it to the official endpoint — anthropic-compatible third parties
113
+ // (e.g. MiniMax) reject it. Levels are already clamped to the model's
114
+ // supported set, so the value is always a valid effort for this model.
115
+ if (isOfficialAnthropicBaseUrl(options.baseURL)) {
116
+ const effort = anthropicEffortForLevel(effectiveThinkingLevel);
117
+ if (effort) {
118
+ body.output_config = { effort };
119
+ }
120
+ }
90
121
  }
91
122
  return body;
92
123
  }
@@ -0,0 +1,17 @@
1
+ import type { Provider, ProviderMessage, StreamChunk, ThinkingLevel, TokenUsage, ToolChoiceMode, ToolDefinition } from "./types.js";
2
+ export interface ArkResponsesProviderOptions {
3
+ providerId?: string;
4
+ apiKey: string;
5
+ baseURL: string;
6
+ thinkingLevel?: ThinkingLevel;
7
+ }
8
+ export declare function createArkResponsesProvider(options: ArkResponsesProviderOptions): Provider;
9
+ export declare function buildArkResponsesBody(messages: ProviderMessage[], options: {
10
+ model: string;
11
+ tools?: ToolDefinition[];
12
+ toolChoice?: ToolChoiceMode;
13
+ thinkingLevel?: ThinkingLevel;
14
+ stream: boolean;
15
+ }): Record<string, unknown>;
16
+ export declare function translateArkResponsesStream(response: Response): AsyncIterable<StreamChunk>;
17
+ export declare function normalizeArkResponsesUsage(usage: any): TokenUsage;
@@ -0,0 +1,462 @@
1
+ import { createProviderProtocolArtifactFilter } from "./provider-artifacts.js";
2
+ import { RateLimitError } from "./network/errors.js";
3
+ import { computeRetryDelayMs, getProviderMaxRetries, isRetryableHttpStatus, retryAfterMsFromResponse, sleepBeforeRetry, } from "./network/retry.js";
4
+ const DEFAULT_ARK_MODEL = "doubao-seed-2-1-pro-260628";
5
+ export function createArkResponsesProvider(options) {
6
+ async function* streamChat(messages, chatOptions) {
7
+ const body = buildArkResponsesBody(messages, {
8
+ model: chatOptions.model,
9
+ tools: chatOptions.tools,
10
+ toolChoice: chatOptions.toolChoice,
11
+ thinkingLevel: chatOptions.thinkingLevel ?? options.thinkingLevel ?? "high",
12
+ stream: true,
13
+ });
14
+ for (let attempt = 0;; attempt += 1) {
15
+ const response = await sendArkResponsesRequest(options, body, {
16
+ signal: chatOptions.abortSignal,
17
+ rateLimitPolicy: chatOptions.rateLimitPolicy,
18
+ attempt,
19
+ });
20
+ yield* translateArkResponsesStream(response);
21
+ yield { type: "done" };
22
+ return;
23
+ }
24
+ }
25
+ async function complete(messages, chatOptions) {
26
+ const body = buildArkResponsesBody(messages, {
27
+ model: chatOptions?.model ?? DEFAULT_ARK_MODEL,
28
+ thinkingLevel: chatOptions?.thinkingLevel ?? options.thinkingLevel ?? "high",
29
+ stream: false,
30
+ });
31
+ const response = await sendArkResponsesRequest(options, body, {
32
+ signal: chatOptions?.abortSignal,
33
+ attempt: 0,
34
+ });
35
+ const payload = await response.json().catch(() => undefined);
36
+ return extractArkResponsesText(payload);
37
+ }
38
+ return { streamChat, complete };
39
+ }
40
+ export function buildArkResponsesBody(messages, options) {
41
+ const body = {
42
+ model: options.model,
43
+ input: messages.flatMap((message) => convertMessageToArkResponsesInput(message)),
44
+ store: false,
45
+ stream: options.stream,
46
+ thinking: {
47
+ type: shouldDisableArkThinking(options.thinkingLevel) ? "disabled" : "enabled",
48
+ },
49
+ };
50
+ if (options.tools && options.tools.length > 0) {
51
+ body.tools = options.tools.map((tool) => ({
52
+ type: "function",
53
+ name: tool.name,
54
+ description: tool.description,
55
+ parameters: tool.parameters,
56
+ }));
57
+ if (options.toolChoice === "none") {
58
+ body.tool_choice = "none";
59
+ }
60
+ }
61
+ return body;
62
+ }
63
+ function shouldDisableArkThinking(level) {
64
+ return level === "off" || level === "minimal";
65
+ }
66
+ function convertMessageToArkResponsesInput(message) {
67
+ if (message.role === "user") {
68
+ if (typeof message.content === "string") {
69
+ return [{
70
+ type: "message",
71
+ role: "user",
72
+ content: message.content,
73
+ }];
74
+ }
75
+ return [{
76
+ type: "message",
77
+ role: "user",
78
+ content: message.content.map((part) => {
79
+ if (part.type === "text") {
80
+ return { type: "input_text", text: part.text };
81
+ }
82
+ return { type: "input_image", image_url: part.image_url.url };
83
+ }),
84
+ }];
85
+ }
86
+ if (message.role === "system") {
87
+ return [{
88
+ type: "message",
89
+ role: "system",
90
+ content: message.content,
91
+ }];
92
+ }
93
+ if (message.role === "assistant") {
94
+ const items = [];
95
+ if (message.content) {
96
+ items.push({
97
+ type: "message",
98
+ role: "assistant",
99
+ status: "completed",
100
+ content: [{ type: "output_text", text: message.content, annotations: [] }],
101
+ });
102
+ }
103
+ for (const toolCall of message.toolCalls ?? []) {
104
+ items.push({
105
+ type: "function_call",
106
+ call_id: toolCall.id,
107
+ name: toolCall.name,
108
+ arguments: toolCall.arguments || "{}",
109
+ status: "completed",
110
+ });
111
+ }
112
+ return items;
113
+ }
114
+ return [{
115
+ type: "function_call_output",
116
+ call_id: message.toolCallId,
117
+ output: message.content,
118
+ }];
119
+ }
120
+ async function sendArkResponsesRequest(options, body, requestOptions) {
121
+ const response = await fetch(resolveArkResponsesUrl(options.baseURL), {
122
+ method: "POST",
123
+ headers: {
124
+ "Authorization": `Bearer ${options.apiKey}`,
125
+ "Content-Type": "application/json",
126
+ "Accept": body.stream ? "text/event-stream" : "application/json",
127
+ },
128
+ body: JSON.stringify(body),
129
+ signal: requestOptions.signal,
130
+ });
131
+ if (response.ok)
132
+ return response;
133
+ const errorText = await response.text().catch(() => "");
134
+ if (response.status === 429) {
135
+ const retryAfterMs = retryAfterMsFromResponse(response);
136
+ if (requestOptions.rateLimitPolicy !== "defer"
137
+ && requestOptions.attempt < getProviderMaxRetries()) {
138
+ await sleepBeforeRetry(computeRetryDelayMs(requestOptions.attempt + 1, { retryAfterMs }), requestOptions.signal);
139
+ return sendArkResponsesRequest(options, body, {
140
+ ...requestOptions,
141
+ attempt: requestOptions.attempt + 1,
142
+ });
143
+ }
144
+ throw new RateLimitError(errorText || "Rate limited (429)", {
145
+ status: 429,
146
+ retryAfterMs,
147
+ });
148
+ }
149
+ if (isRetryableHttpStatus(response.status) && requestOptions.attempt < getProviderMaxRetries()) {
150
+ await sleepBeforeRetry(computeRetryDelayMs(requestOptions.attempt + 1), requestOptions.signal);
151
+ return sendArkResponsesRequest(options, body, {
152
+ ...requestOptions,
153
+ attempt: requestOptions.attempt + 1,
154
+ });
155
+ }
156
+ throw new Error(`${response.status} status code${errorText ? `: ${errorText}` : " (no body)"}`);
157
+ }
158
+ function resolveArkResponsesUrl(baseURL) {
159
+ return `${baseURL.trim().replace(/\/+$/, "")}/responses`;
160
+ }
161
+ export async function* translateArkResponsesStream(response) {
162
+ const toolCalls = new Map();
163
+ const textFilter = createProviderProtocolArtifactFilter();
164
+ for await (const event of parseArkResponsesSse(response)) {
165
+ const type = typeof event.type === "string" ? event.type : undefined;
166
+ if (!type)
167
+ continue;
168
+ if (type === "error") {
169
+ const message = typeof event.message === "string" ? event.message : JSON.stringify(event);
170
+ throw new Error(message);
171
+ }
172
+ if (type === "response.failed") {
173
+ const message = typeof event.response?.error?.message === "string"
174
+ ? event.response.error.message
175
+ : "Ark Responses request failed";
176
+ throw new Error(message);
177
+ }
178
+ if (type === "response.output_item.added") {
179
+ const item = event.item;
180
+ if (item?.type === "function_call" && typeof item.call_id === "string" && typeof item.name === "string") {
181
+ const key = toolCallEventKey(event, item);
182
+ const entry = {
183
+ id: item.call_id,
184
+ name: item.name,
185
+ args: typeof item.arguments === "string" ? item.arguments : "",
186
+ started: true,
187
+ };
188
+ toolCalls.set(key, entry);
189
+ yield {
190
+ type: "tool_call",
191
+ id: entry.id,
192
+ name: entry.name,
193
+ arguments: "",
194
+ isStart: true,
195
+ isEnd: false,
196
+ };
197
+ }
198
+ continue;
199
+ }
200
+ if (type === "response.output_text.delta" || type === "response.refusal.delta") {
201
+ const delta = typeof event.delta === "string" ? event.delta : "";
202
+ if (delta) {
203
+ const cleaned = textFilter.push(delta);
204
+ if (cleaned)
205
+ yield { type: "text", content: cleaned };
206
+ }
207
+ continue;
208
+ }
209
+ if (type === "response.reasoning_summary_text.delta") {
210
+ const delta = typeof event.delta === "string" ? event.delta : "";
211
+ if (delta) {
212
+ yield { type: "reasoning_delta", content: delta };
213
+ }
214
+ continue;
215
+ }
216
+ if (type === "response.function_call_arguments.delta") {
217
+ const entry = toolCalls.get(toolCallEventKey(event));
218
+ const delta = typeof event.delta === "string" ? event.delta : "";
219
+ if (entry && delta) {
220
+ entry.args += delta;
221
+ yield {
222
+ type: "tool_call",
223
+ id: entry.id,
224
+ name: entry.name,
225
+ arguments: delta,
226
+ isStart: false,
227
+ isEnd: false,
228
+ };
229
+ }
230
+ continue;
231
+ }
232
+ if (type === "response.function_call_arguments.done") {
233
+ const entry = toolCalls.get(toolCallEventKey(event));
234
+ if (entry) {
235
+ const finalArgs = typeof event.arguments === "string" ? event.arguments : entry.args;
236
+ if (finalArgs.startsWith(entry.args)) {
237
+ const tail = finalArgs.slice(entry.args.length);
238
+ if (tail) {
239
+ yield {
240
+ type: "tool_call",
241
+ id: entry.id,
242
+ name: entry.name,
243
+ arguments: tail,
244
+ isStart: false,
245
+ isEnd: false,
246
+ };
247
+ }
248
+ }
249
+ entry.args = finalArgs;
250
+ }
251
+ continue;
252
+ }
253
+ if (type === "response.output_item.done") {
254
+ const item = event.item;
255
+ if (item?.type === "function_call") {
256
+ const key = toolCallEventKey(event, item);
257
+ const entry = toolCalls.get(key);
258
+ if (entry) {
259
+ const finalArgs = typeof item.arguments === "string" ? item.arguments : entry.args;
260
+ const normalized = normalizeToolArgsDetailed(finalArgs);
261
+ yield {
262
+ type: "tool_call",
263
+ id: entry.id,
264
+ name: entry.name,
265
+ arguments: "",
266
+ argumentsFull: normalized.args,
267
+ argumentsCorrupt: normalized.corrupt || undefined,
268
+ isStart: false,
269
+ isEnd: true,
270
+ };
271
+ toolCalls.delete(key);
272
+ }
273
+ }
274
+ continue;
275
+ }
276
+ if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
277
+ const remainingText = textFilter.flush();
278
+ if (remainingText) {
279
+ yield { type: "text", content: remainingText };
280
+ }
281
+ for (const [key, entry] of toolCalls) {
282
+ const normalized = normalizeToolArgsDetailed(entry.args);
283
+ yield {
284
+ type: "tool_call",
285
+ id: entry.id,
286
+ name: entry.name,
287
+ arguments: "",
288
+ argumentsFull: normalized.args,
289
+ argumentsCorrupt: normalized.corrupt || type === "response.incomplete" || undefined,
290
+ isStart: false,
291
+ isEnd: true,
292
+ };
293
+ toolCalls.delete(key);
294
+ }
295
+ const usage = event.response?.usage;
296
+ if (usage) {
297
+ yield {
298
+ type: "usage",
299
+ usage: normalizeArkResponsesUsage(usage),
300
+ };
301
+ }
302
+ continue;
303
+ }
304
+ }
305
+ const remainingText = textFilter.flush();
306
+ if (remainingText) {
307
+ yield { type: "text", content: remainingText };
308
+ }
309
+ for (const [, entry] of toolCalls) {
310
+ const normalized = normalizeToolArgsDetailed(entry.args);
311
+ yield {
312
+ type: "tool_call",
313
+ id: entry.id,
314
+ name: entry.name,
315
+ arguments: "",
316
+ argumentsFull: normalized.args,
317
+ argumentsCorrupt: normalized.corrupt || undefined,
318
+ isStart: false,
319
+ isEnd: true,
320
+ };
321
+ }
322
+ }
323
+ function toolCallEventKey(event, item) {
324
+ if (typeof event.output_index === "number")
325
+ return `output:${event.output_index}`;
326
+ const itemId = typeof event.item_id === "string"
327
+ ? event.item_id
328
+ : typeof item?.id === "string"
329
+ ? item.id
330
+ : undefined;
331
+ if (itemId)
332
+ return itemId;
333
+ return "output:0";
334
+ }
335
+ async function* parseArkResponsesSse(response) {
336
+ if (!response.body)
337
+ return;
338
+ const reader = response.body.getReader();
339
+ const decoder = new TextDecoder();
340
+ let buffer = "";
341
+ try {
342
+ while (true) {
343
+ const { done, value } = await reader.read();
344
+ if (done)
345
+ break;
346
+ buffer += decoder.decode(value, { stream: true });
347
+ let boundary = buffer.indexOf("\n\n");
348
+ while (boundary >= 0) {
349
+ const chunk = buffer.slice(0, boundary);
350
+ buffer = buffer.slice(boundary + 2);
351
+ const data = chunk
352
+ .split("\n")
353
+ .filter((line) => line.startsWith("data:"))
354
+ .map((line) => line.slice(5).trim())
355
+ .join("\n")
356
+ .trim();
357
+ if (data && data !== "[DONE]") {
358
+ try {
359
+ yield JSON.parse(data);
360
+ }
361
+ catch {
362
+ // Ignore malformed event frames; the provider will surface failure
363
+ // through response.failed when the request itself failed.
364
+ }
365
+ }
366
+ boundary = buffer.indexOf("\n\n");
367
+ }
368
+ }
369
+ }
370
+ finally {
371
+ try {
372
+ await reader.cancel();
373
+ }
374
+ catch {
375
+ // Ignore cleanup errors.
376
+ }
377
+ }
378
+ }
379
+ export function normalizeArkResponsesUsage(usage) {
380
+ const promptTokens = typeof usage?.input_tokens === "number" ? usage.input_tokens : 0;
381
+ const cachedTokens = typeof usage?.input_tokens_details?.cached_tokens === "number"
382
+ ? usage.input_tokens_details.cached_tokens
383
+ : undefined;
384
+ return {
385
+ promptTokens,
386
+ completionTokens: typeof usage?.output_tokens === "number" ? usage.output_tokens : 0,
387
+ promptCacheHitTokens: cachedTokens,
388
+ promptCacheMissTokens: cachedTokens !== undefined ? Math.max(0, promptTokens - cachedTokens) : undefined,
389
+ reasoningTokens: typeof usage?.output_tokens_details?.reasoning_tokens === "number"
390
+ ? usage.output_tokens_details.reasoning_tokens
391
+ : undefined,
392
+ totalTokens: typeof usage?.total_tokens === "number" ? usage.total_tokens : undefined,
393
+ };
394
+ }
395
+ function extractArkResponsesText(payload) {
396
+ const output = Array.isArray(payload?.output) ? payload.output : [];
397
+ const text = [];
398
+ for (const item of output) {
399
+ if (item?.type !== "message" || !Array.isArray(item.content))
400
+ continue;
401
+ for (const part of item.content) {
402
+ if ((part?.type === "output_text" || part?.type === "text") && typeof part.text === "string") {
403
+ text.push(part.text);
404
+ }
405
+ }
406
+ }
407
+ return text.join("");
408
+ }
409
+ function normalizeToolArgsDetailed(raw) {
410
+ const s = (raw ?? "").trim();
411
+ if (!s)
412
+ return { args: "{}", corrupt: false };
413
+ try {
414
+ JSON.parse(s);
415
+ return { args: s, corrupt: false };
416
+ }
417
+ catch {
418
+ const balanced = extractBalancedJson(s, 0);
419
+ if (!balanced)
420
+ return { args: "{}", corrupt: true };
421
+ try {
422
+ JSON.parse(balanced);
423
+ return { args: balanced, corrupt: false };
424
+ }
425
+ catch {
426
+ return { args: "{}", corrupt: true };
427
+ }
428
+ }
429
+ }
430
+ function extractBalancedJson(s, start) {
431
+ if (s[start] !== "{")
432
+ return null;
433
+ let depth = 0;
434
+ let inStr = false;
435
+ let escape = false;
436
+ for (let i = start; i < s.length; i += 1) {
437
+ const c = s[i];
438
+ if (escape) {
439
+ escape = false;
440
+ continue;
441
+ }
442
+ if (c === "\\" && inStr) {
443
+ escape = true;
444
+ continue;
445
+ }
446
+ if (c === "\"") {
447
+ inStr = !inStr;
448
+ continue;
449
+ }
450
+ if (inStr)
451
+ continue;
452
+ if (c === "{") {
453
+ depth += 1;
454
+ }
455
+ else if (c === "}") {
456
+ depth -= 1;
457
+ if (depth === 0)
458
+ return s.slice(start, i + 1);
459
+ }
460
+ }
461
+ return null;
462
+ }
@@ -47,6 +47,13 @@ export function resolveProviderRequestConfig(providerId, modelId, requestedLevel
47
47
  : { reasoning_effort: effectiveThinkingLevel },
48
48
  };
49
49
  }
50
+ if (providerId === "doubao") {
51
+ return {
52
+ effectiveThinkingLevel,
53
+ parallelToolCalls: false,
54
+ extraBody: { reasoning_effort: effectiveThinkingLevel },
55
+ };
56
+ }
50
57
  if (providerId === "minimax" || providerId === "minimax-openai") {
51
58
  const extraBody = { reasoning_split: true };
52
59
  if (MINIMAX_M3_FAMILY.has(modelId)) {
@@ -38,6 +38,13 @@ export interface NormalizedToolArgs {
38
38
  }
39
39
  export declare function normalizeToolArgsDetailed(raw: string): NormalizedToolArgs;
40
40
  export declare function normalizeToolArgs(raw: string): string;
41
+ /**
42
+ * Convert a non-streaming OpenAI-compatible chat-completions response into the
43
+ * same chunk protocol used by the streaming adapter. This is used for provider
44
+ * tool-call paths where streamed function arguments are not reliable enough to
45
+ * execute safely.
46
+ */
47
+ export declare function translateOpenAIFullResponse(response: any): AsyncIterable<StreamChunk>;
41
48
  /**
42
49
  * Convert an OpenAI-compatible chat-completions stream into our internal StreamChunk events.
43
50
  *