@chatluna/v1-shared-adapter 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  convertMessageToMessageChunk: () => convertMessageToMessageChunk,
28
28
  createEmbeddings: () => createEmbeddings,
29
29
  createRequestContext: () => createRequestContext,
30
+ createUsageMetadata: () => createUsageMetadata,
30
31
  expandReasoningEffortModelVariants: () => expandReasoningEffortModelVariants,
31
32
  fetchFileLikeUrl: () => fetchFileLikeUrl,
32
33
  fetchImageUrl: () => fetchImageUrl,
@@ -39,9 +40,9 @@ __export(index_exports, {
39
40
  langchainMessageToOpenAIMessage: () => langchainMessageToOpenAIMessage,
40
41
  messageTypeToOpenAIRole: () => messageTypeToOpenAIRole,
41
42
  normalizeOpenAIModelName: () => normalizeOpenAIModelName,
43
+ openAIUsageToUsageMetadata: () => openAIUsageToUsageMetadata,
42
44
  parseOpenAIModelNameWithReasoningEffort: () => parseOpenAIModelNameWithReasoningEffort,
43
- processDeepSeekThinkMessages: () => processDeepSeekThinkMessages,
44
- processReasoningContent: () => processReasoningContent,
45
+ processInterleavedThinkMessages: () => processInterleavedThinkMessages,
45
46
  processResponse: () => processResponse,
46
47
  processStreamResponse: () => processStreamResponse,
47
48
  reasoningEffortModelSuffixes: () => reasoningEffortModelSuffixes,
@@ -164,6 +165,8 @@ var imageModelMatchers = [
164
165
  "qwen*-omni",
165
166
  "qwen-omni",
166
167
  "qwen*-vl",
168
+ "qwen-3.5",
169
+ "qwen3.5",
167
170
  "qvq",
168
171
  "o1",
169
172
  "o3",
@@ -191,10 +194,40 @@ var import_messages = require("@langchain/core/messages");
191
194
  var import_zod_to_json_schema = require("zod-to-json-schema");
192
195
  var import_string = require("koishi-plugin-chatluna/utils/string");
193
196
  var import_types = require("@langchain/core/utils/types");
197
+ function createUsageMetadata(data) {
198
+ const inputTokenDetails = {
199
+ ...data.inputAudioTokens != null ? { audio: data.inputAudioTokens } : {},
200
+ ...data.cacheReadTokens != null ? { cache_read: data.cacheReadTokens } : {},
201
+ ...data.cacheCreationTokens != null ? { cache_creation: data.cacheCreationTokens } : {}
202
+ };
203
+ const outputTokenDetails = {
204
+ ...data.outputAudioTokens != null ? { audio: data.outputAudioTokens } : {},
205
+ ...data.reasoningTokens != null ? { reasoning: data.reasoningTokens } : {}
206
+ };
207
+ return {
208
+ input_tokens: data.inputTokens,
209
+ output_tokens: data.outputTokens,
210
+ total_tokens: data.totalTokens,
211
+ ...Object.keys(inputTokenDetails).length > 0 ? { input_token_details: inputTokenDetails } : {},
212
+ ...Object.keys(outputTokenDetails).length > 0 ? { output_token_details: outputTokenDetails } : {}
213
+ };
214
+ }
215
+ __name(createUsageMetadata, "createUsageMetadata");
216
+ function openAIUsageToUsageMetadata(usage) {
217
+ return createUsageMetadata({
218
+ inputTokens: usage.prompt_tokens,
219
+ outputTokens: usage.completion_tokens,
220
+ totalTokens: usage.total_tokens,
221
+ inputAudioTokens: usage.prompt_tokens_details?.audio_tokens,
222
+ outputAudioTokens: usage.completion_tokens_details?.audio_tokens,
223
+ cacheReadTokens: usage.prompt_tokens_details?.cached_tokens,
224
+ reasoningTokens: usage.completion_tokens_details?.reasoning_tokens
225
+ });
226
+ }
227
+ __name(openAIUsageToUsageMetadata, "openAIUsageToUsageMetadata");
194
228
  async function langchainMessageToOpenAIMessage(messages, plugin, model, supportImageInputType, removeSystemMessage) {
195
229
  const result = [];
196
230
  const normalizedModel = model ? normalizeOpenAIModelName(model) : model;
197
- const isDeepseekThinkModel = normalizedModel?.includes("deepseek-reasoner");
198
231
  for (const rawMessage of messages) {
199
232
  const role = messageTypeToOpenAIRole(rawMessage.getType());
200
233
  const msg = {
@@ -309,13 +342,10 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
309
342
  if (removeSystemMessage) {
310
343
  return transformSystemMessages(result);
311
344
  }
312
- if (isDeepseekThinkModel) {
313
- return processDeepSeekThinkMessages(result, messages);
314
- }
315
- return result;
345
+ return processInterleavedThinkMessages(result, messages);
316
346
  }
317
347
  __name(langchainMessageToOpenAIMessage, "langchainMessageToOpenAIMessage");
318
- function processDeepSeekThinkMessages(convertedMessages, originalMessages) {
348
+ function processInterleavedThinkMessages(convertedMessages, originalMessages) {
319
349
  if (originalMessages.length === 0) {
320
350
  return convertedMessages;
321
351
  }
@@ -344,7 +374,7 @@ function processDeepSeekThinkMessages(convertedMessages, originalMessages) {
344
374
  return message;
345
375
  });
346
376
  }
347
- __name(processDeepSeekThinkMessages, "processDeepSeekThinkMessages");
377
+ __name(processInterleavedThinkMessages, "processInterleavedThinkMessages");
348
378
  function transformSystemMessages(messages) {
349
379
  const mappedMessage = [];
350
380
  for (let i = 0; i < messages.length; i++) {
@@ -537,8 +567,12 @@ function convertMessageToMessageChunk(message) {
537
567
  const toolCallChunks = [];
538
568
  if (Array.isArray(message.tool_calls)) {
539
569
  for (const rawToolCall of message.tool_calls) {
570
+ let name = rawToolCall.function?.name;
571
+ if (name != null && name.length < 1) {
572
+ name = void 0;
573
+ }
540
574
  toolCallChunks.push({
541
- name: rawToolCall.function?.name,
575
+ name,
542
576
  args: rawToolCall.function?.arguments,
543
577
  id: rawToolCall.id
544
578
  });
@@ -577,10 +611,6 @@ function convertDeltaToMessageChunk(delta, defaultRole) {
577
611
  additionalKwargs = {
578
612
  function_call: delta.function_call
579
613
  };
580
- } else if (delta.tool_calls) {
581
- additionalKwargs = {
582
- tool_calls: delta.tool_calls
583
- };
584
614
  } else {
585
615
  additionalKwargs = {};
586
616
  }
@@ -593,12 +623,16 @@ function convertDeltaToMessageChunk(delta, defaultRole) {
593
623
  const toolCallChunks = [];
594
624
  if (Array.isArray(delta.tool_calls)) {
595
625
  for (const rawToolCall of delta.tool_calls) {
596
- toolCallChunks.push({
626
+ const toolCall = {
597
627
  name: rawToolCall.function?.name,
598
628
  args: rawToolCall.function?.arguments,
599
629
  id: rawToolCall.id,
600
630
  index: rawToolCall.index
601
- });
631
+ };
632
+ if (toolCall.name != null && toolCall.name.length < 1) {
633
+ delete toolCall.name;
634
+ }
635
+ toolCallChunks.push(toolCall);
602
636
  }
603
637
  }
604
638
  return new import_messages.AIMessageChunk({
@@ -678,25 +712,14 @@ async function buildChatCompletionParams(params, plugin, enableGoogleSearch, sup
678
712
  return (0, import_object.deepAssign)({}, base, params.overrideRequestParams ?? {});
679
713
  }
680
714
  __name(buildChatCompletionParams, "buildChatCompletionParams");
681
- function processReasoningContent(delta, reasoningState) {
682
- if (delta.reasoning_content) {
683
- reasoningState.content += delta.reasoning_content;
684
- if (reasoningState.time === 0) {
685
- reasoningState.time = Date.now();
686
- }
687
- }
688
- if ((delta.reasoning_content == null || delta.reasoning_content === "") && delta.content && delta.content.length > 0 && reasoningState.time > 0 && !reasoningState.isSet) {
689
- const reasoningTime = Date.now() - reasoningState.time;
690
- reasoningState.time = reasoningTime;
691
- reasoningState.isSet = true;
692
- return reasoningTime;
693
- }
694
- }
695
- __name(processReasoningContent, "processReasoningContent");
696
715
  async function* processStreamResponse(requestContext, iterator) {
697
716
  let defaultRole = "assistant";
698
717
  let errorCount = 0;
699
- const reasoningState = { content: "", time: 0, isSet: false };
718
+ const reasoningState = {
719
+ content: "",
720
+ startedAt: Date.now(),
721
+ endedAt: void 0
722
+ };
700
723
  for await (const event of iterator) {
701
724
  const chunk = event.data;
702
725
  if (chunk === "[DONE]") break;
@@ -711,26 +734,38 @@ async function* processStreamResponse(requestContext, iterator) {
711
734
  }
712
735
  const choice = data.choices?.[0];
713
736
  if (data.usage) {
737
+ const usageMetadata = openAIUsageToUsageMetadata(data.usage);
714
738
  yield new import_outputs.ChatGenerationChunk({
739
+ generationInfo: {
740
+ usage_metadata: usageMetadata
741
+ },
715
742
  message: new import_messages2.AIMessageChunk({
716
743
  content: "",
717
- response_metadata: {
718
- tokenUsage: {
719
- promptTokens: data.usage.prompt_tokens,
720
- completionTokens: data.usage.completion_tokens,
721
- totalTokens: data.usage.total_tokens
722
- }
723
- }
744
+ usage_metadata: usageMetadata
724
745
  }),
725
746
  text: ""
726
747
  });
727
748
  }
728
749
  if (!choice) continue;
729
750
  const { delta } = choice;
730
- const messageChunk = convertDeltaToMessageChunk(delta, defaultRole);
731
- const reasoningTime = processReasoningContent(delta, reasoningState);
732
- if (reasoningTime !== void 0) {
733
- messageChunk.additional_kwargs.reasoning_time = reasoningTime;
751
+ const hasResult = (delta.content?.length ?? 0) > 0 || (delta.tool_calls?.length ?? 0) > 0 || delta.function_call != null;
752
+ if (reasoningState.endedAt == null && hasResult) {
753
+ reasoningState.endedAt = Date.now();
754
+ }
755
+ if (reasoningState.endedAt == null && !hasResult && delta.reasoning_content) {
756
+ reasoningState.content += delta.reasoning_content;
757
+ }
758
+ const messageChunk = convertDeltaToMessageChunk(
759
+ {
760
+ ...delta,
761
+ reasoning_content: void 0
762
+ },
763
+ defaultRole
764
+ );
765
+ const hasMessageChunk = (typeof messageChunk.content === "string" ? messageChunk.content.length > 0 : Array.isArray(messageChunk.content) && messageChunk.content.length > 0) || messageChunk instanceof import_messages2.AIMessageChunk && (messageChunk.tool_call_chunks?.length ?? 0) > 0 || messageChunk.additional_kwargs.function_call != null;
766
+ if (!hasMessageChunk) {
767
+ defaultRole = (delta.role?.length ?? 0) > 0 ? delta.role : defaultRole;
768
+ continue;
734
769
  }
735
770
  defaultRole = (delta.role?.length ?? 0) > 0 ? delta.role : defaultRole;
736
771
  yield new import_outputs.ChatGenerationChunk({
@@ -738,6 +773,13 @@ async function* processStreamResponse(requestContext, iterator) {
738
773
  text: messageChunk.content
739
774
  });
740
775
  } catch (e) {
776
+ if (chunk.includes("tool_calls") || chunk.includes("function_call") || chunk.includes("tool_call_id")) {
777
+ requestContext.modelRequester.logger.error(
778
+ "error with chunk",
779
+ chunk
780
+ );
781
+ throw new import_error.ChatLunaError(import_error.ChatLunaErrorCode.API_REQUEST_FAILED, e);
782
+ }
741
783
  if (errorCount > 5) {
742
784
  requestContext.modelRequester.logger.error(
743
785
  "error with chunk",
@@ -749,8 +791,19 @@ async function* processStreamResponse(requestContext, iterator) {
749
791
  }
750
792
  }
751
793
  if (reasoningState.content.length > 0) {
794
+ const reasoningTime = (reasoningState.endedAt ?? Date.now()) - reasoningState.startedAt;
795
+ yield new import_outputs.ChatGenerationChunk({
796
+ message: new import_messages2.AIMessageChunk({
797
+ content: "",
798
+ additional_kwargs: {
799
+ reasoning_content: reasoningState.content,
800
+ ...reasoningTime != null ? { reasoning_time: reasoningTime } : {}
801
+ }
802
+ }),
803
+ text: ""
804
+ });
752
805
  requestContext.modelRequester.logger.debug(
753
- `reasoning content: ${reasoningState.content}. Use time: ${reasoningState.time / 1e3}s`
806
+ `Reasoning Content: ${reasoningState.content}. Thought for: ${(reasoningTime ?? 0) / 1e3}s`
754
807
  );
755
808
  }
756
809
  }
@@ -785,11 +838,15 @@ async function processResponse(requestContext, response) {
785
838
  );
786
839
  }
787
840
  const messageChunk = convertMessageToMessageChunk(choice.message);
841
+ const usageMetadata = data.usage ? openAIUsageToUsageMetadata(data.usage) : void 0;
842
+ if (messageChunk instanceof import_messages2.AIMessageChunk) {
843
+ messageChunk.usage_metadata = usageMetadata;
844
+ }
788
845
  return new import_outputs.ChatGenerationChunk({
789
846
  message: messageChunk,
790
847
  text: (0, import_string2.getMessageContent)(messageChunk.content),
791
- generationInfo: {
792
- tokenUsage: data.usage
848
+ generationInfo: usageMetadata == null ? void 0 : {
849
+ usage_metadata: usageMetadata
793
850
  }
794
851
  });
795
852
  } catch (e) {
@@ -957,6 +1014,7 @@ __name(createRequestContext, "createRequestContext");
957
1014
  convertMessageToMessageChunk,
958
1015
  createEmbeddings,
959
1016
  createRequestContext,
1017
+ createUsageMetadata,
960
1018
  expandReasoningEffortModelVariants,
961
1019
  fetchFileLikeUrl,
962
1020
  fetchImageUrl,
@@ -969,9 +1027,9 @@ __name(createRequestContext, "createRequestContext");
969
1027
  langchainMessageToOpenAIMessage,
970
1028
  messageTypeToOpenAIRole,
971
1029
  normalizeOpenAIModelName,
1030
+ openAIUsageToUsageMetadata,
972
1031
  parseOpenAIModelNameWithReasoningEffort,
973
- processDeepSeekThinkMessages,
974
- processReasoningContent,
1032
+ processInterleavedThinkMessages,
975
1033
  processResponse,
976
1034
  processStreamResponse,
977
1035
  reasoningEffortModelSuffixes,
package/lib/index.mjs CHANGED
@@ -114,6 +114,8 @@ var imageModelMatchers = [
114
114
  "qwen*-omni",
115
115
  "qwen-omni",
116
116
  "qwen*-vl",
117
+ "qwen-3.5",
118
+ "qwen3.5",
117
119
  "qvq",
118
120
  "o1",
119
121
  "o3",
@@ -155,10 +157,40 @@ import {
155
157
  isMessageContentImageUrl
156
158
  } from "koishi-plugin-chatluna/utils/string";
157
159
  import { isZodSchemaV3 } from "@langchain/core/utils/types";
160
+ function createUsageMetadata(data) {
161
+ const inputTokenDetails = {
162
+ ...data.inputAudioTokens != null ? { audio: data.inputAudioTokens } : {},
163
+ ...data.cacheReadTokens != null ? { cache_read: data.cacheReadTokens } : {},
164
+ ...data.cacheCreationTokens != null ? { cache_creation: data.cacheCreationTokens } : {}
165
+ };
166
+ const outputTokenDetails = {
167
+ ...data.outputAudioTokens != null ? { audio: data.outputAudioTokens } : {},
168
+ ...data.reasoningTokens != null ? { reasoning: data.reasoningTokens } : {}
169
+ };
170
+ return {
171
+ input_tokens: data.inputTokens,
172
+ output_tokens: data.outputTokens,
173
+ total_tokens: data.totalTokens,
174
+ ...Object.keys(inputTokenDetails).length > 0 ? { input_token_details: inputTokenDetails } : {},
175
+ ...Object.keys(outputTokenDetails).length > 0 ? { output_token_details: outputTokenDetails } : {}
176
+ };
177
+ }
178
+ __name(createUsageMetadata, "createUsageMetadata");
179
+ function openAIUsageToUsageMetadata(usage) {
180
+ return createUsageMetadata({
181
+ inputTokens: usage.prompt_tokens,
182
+ outputTokens: usage.completion_tokens,
183
+ totalTokens: usage.total_tokens,
184
+ inputAudioTokens: usage.prompt_tokens_details?.audio_tokens,
185
+ outputAudioTokens: usage.completion_tokens_details?.audio_tokens,
186
+ cacheReadTokens: usage.prompt_tokens_details?.cached_tokens,
187
+ reasoningTokens: usage.completion_tokens_details?.reasoning_tokens
188
+ });
189
+ }
190
+ __name(openAIUsageToUsageMetadata, "openAIUsageToUsageMetadata");
158
191
  async function langchainMessageToOpenAIMessage(messages, plugin, model, supportImageInputType, removeSystemMessage) {
159
192
  const result = [];
160
193
  const normalizedModel = model ? normalizeOpenAIModelName(model) : model;
161
- const isDeepseekThinkModel = normalizedModel?.includes("deepseek-reasoner");
162
194
  for (const rawMessage of messages) {
163
195
  const role = messageTypeToOpenAIRole(rawMessage.getType());
164
196
  const msg = {
@@ -273,13 +305,10 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
273
305
  if (removeSystemMessage) {
274
306
  return transformSystemMessages(result);
275
307
  }
276
- if (isDeepseekThinkModel) {
277
- return processDeepSeekThinkMessages(result, messages);
278
- }
279
- return result;
308
+ return processInterleavedThinkMessages(result, messages);
280
309
  }
281
310
  __name(langchainMessageToOpenAIMessage, "langchainMessageToOpenAIMessage");
282
- function processDeepSeekThinkMessages(convertedMessages, originalMessages) {
311
+ function processInterleavedThinkMessages(convertedMessages, originalMessages) {
283
312
  if (originalMessages.length === 0) {
284
313
  return convertedMessages;
285
314
  }
@@ -308,7 +337,7 @@ function processDeepSeekThinkMessages(convertedMessages, originalMessages) {
308
337
  return message;
309
338
  });
310
339
  }
311
- __name(processDeepSeekThinkMessages, "processDeepSeekThinkMessages");
340
+ __name(processInterleavedThinkMessages, "processInterleavedThinkMessages");
312
341
  function transformSystemMessages(messages) {
313
342
  const mappedMessage = [];
314
343
  for (let i = 0; i < messages.length; i++) {
@@ -501,8 +530,12 @@ function convertMessageToMessageChunk(message) {
501
530
  const toolCallChunks = [];
502
531
  if (Array.isArray(message.tool_calls)) {
503
532
  for (const rawToolCall of message.tool_calls) {
533
+ let name = rawToolCall.function?.name;
534
+ if (name != null && name.length < 1) {
535
+ name = void 0;
536
+ }
504
537
  toolCallChunks.push({
505
- name: rawToolCall.function?.name,
538
+ name,
506
539
  args: rawToolCall.function?.arguments,
507
540
  id: rawToolCall.id
508
541
  });
@@ -541,10 +574,6 @@ function convertDeltaToMessageChunk(delta, defaultRole) {
541
574
  additionalKwargs = {
542
575
  function_call: delta.function_call
543
576
  };
544
- } else if (delta.tool_calls) {
545
- additionalKwargs = {
546
- tool_calls: delta.tool_calls
547
- };
548
577
  } else {
549
578
  additionalKwargs = {};
550
579
  }
@@ -557,12 +586,16 @@ function convertDeltaToMessageChunk(delta, defaultRole) {
557
586
  const toolCallChunks = [];
558
587
  if (Array.isArray(delta.tool_calls)) {
559
588
  for (const rawToolCall of delta.tool_calls) {
560
- toolCallChunks.push({
589
+ const toolCall = {
561
590
  name: rawToolCall.function?.name,
562
591
  args: rawToolCall.function?.arguments,
563
592
  id: rawToolCall.id,
564
593
  index: rawToolCall.index
565
- });
594
+ };
595
+ if (toolCall.name != null && toolCall.name.length < 1) {
596
+ delete toolCall.name;
597
+ }
598
+ toolCallChunks.push(toolCall);
566
599
  }
567
600
  }
568
601
  return new AIMessageChunk({
@@ -642,25 +675,14 @@ async function buildChatCompletionParams(params, plugin, enableGoogleSearch, sup
642
675
  return deepAssign({}, base, params.overrideRequestParams ?? {});
643
676
  }
644
677
  __name(buildChatCompletionParams, "buildChatCompletionParams");
645
- function processReasoningContent(delta, reasoningState) {
646
- if (delta.reasoning_content) {
647
- reasoningState.content += delta.reasoning_content;
648
- if (reasoningState.time === 0) {
649
- reasoningState.time = Date.now();
650
- }
651
- }
652
- if ((delta.reasoning_content == null || delta.reasoning_content === "") && delta.content && delta.content.length > 0 && reasoningState.time > 0 && !reasoningState.isSet) {
653
- const reasoningTime = Date.now() - reasoningState.time;
654
- reasoningState.time = reasoningTime;
655
- reasoningState.isSet = true;
656
- return reasoningTime;
657
- }
658
- }
659
- __name(processReasoningContent, "processReasoningContent");
660
678
  async function* processStreamResponse(requestContext, iterator) {
661
679
  let defaultRole = "assistant";
662
680
  let errorCount = 0;
663
- const reasoningState = { content: "", time: 0, isSet: false };
681
+ const reasoningState = {
682
+ content: "",
683
+ startedAt: Date.now(),
684
+ endedAt: void 0
685
+ };
664
686
  for await (const event of iterator) {
665
687
  const chunk = event.data;
666
688
  if (chunk === "[DONE]") break;
@@ -675,26 +697,38 @@ async function* processStreamResponse(requestContext, iterator) {
675
697
  }
676
698
  const choice = data.choices?.[0];
677
699
  if (data.usage) {
700
+ const usageMetadata = openAIUsageToUsageMetadata(data.usage);
678
701
  yield new ChatGenerationChunk({
702
+ generationInfo: {
703
+ usage_metadata: usageMetadata
704
+ },
679
705
  message: new AIMessageChunk2({
680
706
  content: "",
681
- response_metadata: {
682
- tokenUsage: {
683
- promptTokens: data.usage.prompt_tokens,
684
- completionTokens: data.usage.completion_tokens,
685
- totalTokens: data.usage.total_tokens
686
- }
687
- }
707
+ usage_metadata: usageMetadata
688
708
  }),
689
709
  text: ""
690
710
  });
691
711
  }
692
712
  if (!choice) continue;
693
713
  const { delta } = choice;
694
- const messageChunk = convertDeltaToMessageChunk(delta, defaultRole);
695
- const reasoningTime = processReasoningContent(delta, reasoningState);
696
- if (reasoningTime !== void 0) {
697
- messageChunk.additional_kwargs.reasoning_time = reasoningTime;
714
+ const hasResult = (delta.content?.length ?? 0) > 0 || (delta.tool_calls?.length ?? 0) > 0 || delta.function_call != null;
715
+ if (reasoningState.endedAt == null && hasResult) {
716
+ reasoningState.endedAt = Date.now();
717
+ }
718
+ if (reasoningState.endedAt == null && !hasResult && delta.reasoning_content) {
719
+ reasoningState.content += delta.reasoning_content;
720
+ }
721
+ const messageChunk = convertDeltaToMessageChunk(
722
+ {
723
+ ...delta,
724
+ reasoning_content: void 0
725
+ },
726
+ defaultRole
727
+ );
728
+ const hasMessageChunk = (typeof messageChunk.content === "string" ? messageChunk.content.length > 0 : Array.isArray(messageChunk.content) && messageChunk.content.length > 0) || messageChunk instanceof AIMessageChunk2 && (messageChunk.tool_call_chunks?.length ?? 0) > 0 || messageChunk.additional_kwargs.function_call != null;
729
+ if (!hasMessageChunk) {
730
+ defaultRole = (delta.role?.length ?? 0) > 0 ? delta.role : defaultRole;
731
+ continue;
698
732
  }
699
733
  defaultRole = (delta.role?.length ?? 0) > 0 ? delta.role : defaultRole;
700
734
  yield new ChatGenerationChunk({
@@ -702,6 +736,13 @@ async function* processStreamResponse(requestContext, iterator) {
702
736
  text: messageChunk.content
703
737
  });
704
738
  } catch (e) {
739
+ if (chunk.includes("tool_calls") || chunk.includes("function_call") || chunk.includes("tool_call_id")) {
740
+ requestContext.modelRequester.logger.error(
741
+ "error with chunk",
742
+ chunk
743
+ );
744
+ throw new ChatLunaError(ChatLunaErrorCode.API_REQUEST_FAILED, e);
745
+ }
705
746
  if (errorCount > 5) {
706
747
  requestContext.modelRequester.logger.error(
707
748
  "error with chunk",
@@ -713,8 +754,19 @@ async function* processStreamResponse(requestContext, iterator) {
713
754
  }
714
755
  }
715
756
  if (reasoningState.content.length > 0) {
757
+ const reasoningTime = (reasoningState.endedAt ?? Date.now()) - reasoningState.startedAt;
758
+ yield new ChatGenerationChunk({
759
+ message: new AIMessageChunk2({
760
+ content: "",
761
+ additional_kwargs: {
762
+ reasoning_content: reasoningState.content,
763
+ ...reasoningTime != null ? { reasoning_time: reasoningTime } : {}
764
+ }
765
+ }),
766
+ text: ""
767
+ });
716
768
  requestContext.modelRequester.logger.debug(
717
- `reasoning content: ${reasoningState.content}. Use time: ${reasoningState.time / 1e3}s`
769
+ `Reasoning Content: ${reasoningState.content}. Thought for: ${(reasoningTime ?? 0) / 1e3}s`
718
770
  );
719
771
  }
720
772
  }
@@ -749,11 +801,15 @@ async function processResponse(requestContext, response) {
749
801
  );
750
802
  }
751
803
  const messageChunk = convertMessageToMessageChunk(choice.message);
804
+ const usageMetadata = data.usage ? openAIUsageToUsageMetadata(data.usage) : void 0;
805
+ if (messageChunk instanceof AIMessageChunk2) {
806
+ messageChunk.usage_metadata = usageMetadata;
807
+ }
752
808
  return new ChatGenerationChunk({
753
809
  message: messageChunk,
754
810
  text: getMessageContent(messageChunk.content),
755
- generationInfo: {
756
- tokenUsage: data.usage
811
+ generationInfo: usageMetadata == null ? void 0 : {
812
+ usage_metadata: usageMetadata
757
813
  }
758
814
  });
759
815
  } catch (e) {
@@ -920,6 +976,7 @@ export {
920
976
  convertMessageToMessageChunk,
921
977
  createEmbeddings,
922
978
  createRequestContext,
979
+ createUsageMetadata,
923
980
  expandReasoningEffortModelVariants,
924
981
  fetchFileLikeUrl,
925
982
  fetchImageUrl,
@@ -932,9 +989,9 @@ export {
932
989
  langchainMessageToOpenAIMessage,
933
990
  messageTypeToOpenAIRole,
934
991
  normalizeOpenAIModelName,
992
+ openAIUsageToUsageMetadata,
935
993
  parseOpenAIModelNameWithReasoningEffort,
936
- processDeepSeekThinkMessages,
937
- processReasoningContent,
994
+ processInterleavedThinkMessages,
938
995
  processResponse,
939
996
  processStreamResponse,
940
997
  reasoningEffortModelSuffixes,
@@ -37,14 +37,6 @@ export declare function buildChatCompletionParams(params: ModelRequestParams, pl
37
37
  include_usage: boolean;
38
38
  };
39
39
  } & Record<string, any>>;
40
- export declare function processReasoningContent(delta: {
41
- reasoning_content?: string;
42
- content?: string;
43
- }, reasoningState: {
44
- content: string;
45
- time: number;
46
- isSet: boolean;
47
- }): number;
48
40
  export declare function processStreamResponse<T extends ClientConfig, R extends ChatLunaPlugin.Config>(requestContext: RequestContext<T, R>, iterator: AsyncGenerator<SSEEvent, string, unknown>): AsyncGenerator<ChatGenerationChunk, void, unknown>;
49
41
  export declare function processResponse<T extends ClientConfig, R extends ChatLunaPlugin.Config>(requestContext: RequestContext<T, R>, response: Response): Promise<ChatGenerationChunk>;
50
42
  export declare function completionStream<T extends ClientConfig, R extends ChatLunaPlugin.Config>(requestContext: RequestContext<T, R>, params: ModelRequestParams, completionUrl?: string, enableGoogleSearch?: boolean, supportImageInput?: boolean): AsyncGenerator<ChatGenerationChunk>;
package/lib/types.d.ts CHANGED
@@ -7,6 +7,7 @@ export interface ChatCompletionResponse {
7
7
  role?: string;
8
8
  reasoning_content?: string;
9
9
  function_call?: ChatCompletionRequestMessageToolCall;
10
+ tool_calls?: ChatCompletionRequestMessageToolCall[];
10
11
  };
11
12
  message: ChatCompletionResponseMessage;
12
13
  }[];
@@ -14,11 +15,24 @@ export interface ChatCompletionResponse {
14
15
  object: string;
15
16
  created: number;
16
17
  model: string;
17
- usage: {
18
- prompt_tokens: number;
19
- completion_tokens: number;
20
- total_tokens: number;
21
- };
18
+ usage?: ChatCompletionUsage;
19
+ }
20
+ export interface ChatCompletionPromptTokensDetails {
21
+ audio_tokens?: number;
22
+ cached_tokens?: number;
23
+ }
24
+ export interface ChatCompletionCompletionTokensDetails {
25
+ reasoning_tokens?: number;
26
+ audio_tokens?: number;
27
+ accepted_prediction_tokens?: number;
28
+ rejected_prediction_tokens?: number;
29
+ }
30
+ export interface ChatCompletionUsage {
31
+ prompt_tokens: number;
32
+ completion_tokens: number;
33
+ total_tokens: number;
34
+ prompt_tokens_details?: ChatCompletionPromptTokensDetails;
35
+ completion_tokens_details?: ChatCompletionCompletionTokensDetails;
22
36
  }
23
37
  export interface ChatCompletionTextPart {
24
38
  type: 'text';
package/lib/utils.d.ts CHANGED
@@ -1,10 +1,21 @@
1
- import { AIMessageChunk, BaseMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, MessageContentComplex, MessageContentImageUrl, MessageType, SystemMessageChunk, ToolMessageChunk } from '@langchain/core/messages';
1
+ import { AIMessageChunk, BaseMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, MessageContentComplex, MessageContentImageUrl, MessageType, SystemMessageChunk, ToolMessageChunk, type UsageMetadata } from '@langchain/core/messages';
2
2
  import { StructuredTool } from '@langchain/core/tools';
3
3
  import { JsonSchema7Type } from 'zod-to-json-schema';
4
- import { ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatCompletionTool } from './types';
4
+ import { ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatCompletionTool, ChatCompletionUsage } from './types';
5
5
  import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
6
+ export declare function createUsageMetadata(data: {
7
+ inputTokens: number;
8
+ outputTokens: number;
9
+ totalTokens: number;
10
+ inputAudioTokens?: number;
11
+ outputAudioTokens?: number;
12
+ cacheReadTokens?: number;
13
+ cacheCreationTokens?: number;
14
+ reasoningTokens?: number;
15
+ }): UsageMetadata;
16
+ export declare function openAIUsageToUsageMetadata(usage: ChatCompletionUsage): UsageMetadata;
6
17
  export declare function langchainMessageToOpenAIMessage(messages: BaseMessage[], plugin: ChatLunaPlugin, model?: string, supportImageInputType?: boolean, removeSystemMessage?: boolean): Promise<ChatCompletionResponseMessage[]>;
7
- export declare function processDeepSeekThinkMessages(convertedMessages: ChatCompletionResponseMessage[], originalMessages: BaseMessage[]): ChatCompletionResponseMessage[];
18
+ export declare function processInterleavedThinkMessages(convertedMessages: ChatCompletionResponseMessage[], originalMessages: BaseMessage[]): ChatCompletionResponseMessage[];
8
19
  export declare function transformSystemMessages(messages: ChatCompletionResponseMessage[]): ChatCompletionResponseMessage[];
9
20
  export declare function fetchImageUrl(plugin: ChatLunaPlugin, content: MessageContentImageUrl): Promise<string>;
10
21
  type MessageContentFileLike = MessageContentComplex & ({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chatluna/v1-shared-adapter",
3
3
  "description": "chatluna shared adapter",
4
- "version": "1.0.28",
4
+ "version": "1.0.30",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",
@@ -70,6 +70,6 @@
70
70
  },
71
71
  "peerDependencies": {
72
72
  "koishi": "^4.18.9",
73
- "koishi-plugin-chatluna": "^1.3.23"
73
+ "koishi-plugin-chatluna": "^1.3.33"
74
74
  }
75
75
  }