@codehz/ai 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -39,7 +39,7 @@ for await (const event of stream) {
39
39
 
40
40
  ```ts
41
41
  type AIRequest = {
42
- instructions?: string; // 系统指令
42
+ instructions?: string | InstructionBlock[]; // 系统级指令
43
43
  input: InputItem[]; // 输入 items
44
44
  tools?: ToolDefinition[]; // 工具声明
45
45
  toolChoice?: ToolChoice; // 工具选择策略
@@ -53,7 +53,7 @@ type AIRequest = {
53
53
 
54
54
  | Item 类型 | 用途 |
55
55
  | ------------- | ----------------------------------- |
56
- | `message` | 用户 / 助手 / 系统消息 |
56
+ | `message` | 用户 / 助手消息 |
57
57
  | `reasoning` | 思维链(输入侧 replay) |
58
58
  | `tool_call` | 模型发起的工具调用(输入侧 replay) |
59
59
  | `tool_result` | 工具执行结果 |
package/dist/index.d.mts CHANGED
@@ -4,13 +4,16 @@
4
4
  *
5
5
  * 覆盖文本、JSON、图片、二进制引用和后端私有内容。
6
6
  */
7
- type ContentBlock = {
7
+ type TextContentBlock = {
8
8
  type: "text";
9
9
  text: string;
10
- } | {
10
+ };
11
+ type JsonContentBlock = {
11
12
  type: "json";
12
13
  json: unknown;
13
- } | {
14
+ };
15
+ type InstructionBlock = TextContentBlock | JsonContentBlock;
16
+ type ContentBlock = InstructionBlock | {
14
17
  type: "image";
15
18
  imageUrl: string;
16
19
  } | {
@@ -25,7 +28,7 @@ type ContentBlock = {
25
28
  type MessageItem = {
26
29
  type: "message";
27
30
  id?: string;
28
- role: "user" | "assistant" | "system" | "developer";
31
+ role: "user" | "assistant";
29
32
  content: ContentBlock[];
30
33
  };
31
34
  type ReasoningItem = {
@@ -78,7 +81,7 @@ type IncludeSettings = {
78
81
  providerMetadata?: "off" | "best_effort";
79
82
  };
80
83
  type AIRequest = {
81
- instructions?: string | ContentBlock[];
84
+ instructions?: string | InstructionBlock[];
82
85
  input: InputItem[];
83
86
  tools?: ToolDefinition[];
84
87
  toolChoice?: ToolChoice;
@@ -91,13 +94,13 @@ type AIRequest = {
91
94
  //#region src/types/response.d.ts
92
95
  type StopReason = "end_turn" | "tool_call" | "max_output_tokens" | "content_filter" | "error" | "unknown";
93
96
  type Usage = {
94
- inputTokens?: number;
95
- outputTokens?: number;
97
+ /** Provider prompt / input token count */inputTokens?: number; /** Provider completion / output token count */
98
+ outputTokens?: number; /** Reasoning tokens when provider exposes output breakdown (e.g. OpenAI Responses) */
96
99
  reasoningTokens?: number;
97
- totalTokens?: number;
98
- cachedInputTokens?: number;
99
- cacheWriteInputTokens?: number;
100
- billableInputTokens?: number;
100
+ totalTokens?: number; /** Tokens read from prompt cache (OpenAI cached_tokens, Anthropic cache_read_input_tokens) */
101
+ cachedInputTokens?: number; /** Tokens written to prompt cache (Anthropic cache_creation_input_tokens) */
102
+ cacheWriteInputTokens?: number; /** Best-effort billable input (full-rate input; excludes discounted cache reads where known) */
103
+ billableInputTokens?: number; /** Best-effort billable output (non-reasoning slice when provider gives reasoning breakdown) */
101
104
  billableOutputTokens?: number;
102
105
  };
103
106
  type BillingInfo = {
@@ -542,7 +545,7 @@ type ResponsesAPIRequest = {
542
545
  };
543
546
  type ResponsesInputItem = {
544
547
  type: "message";
545
- role: "user" | "assistant" | "system" | "developer";
548
+ role: "user" | "assistant";
546
549
  content: string;
547
550
  } | {
548
551
  type: "message";
@@ -959,9 +962,9 @@ declare function blockToText(b: ContentBlock): string;
959
962
  */
960
963
  declare function contentBlocksToText(blocks: ContentBlock[]): string;
961
964
  /**
962
- * 将 instructions(string | ContentBlock[])归一化为纯文本。
965
+ * 将 instructions(string | InstructionBlock[])归一化为纯文本。
963
966
  */
964
- declare function instructionsToText(instructions: string | ContentBlock[]): string;
967
+ declare function instructionsToText(instructions: string | InstructionBlock[]): string;
965
968
  /**
966
969
  * 从 OutputItem 数组中提取所有 message 类型 item 的文本内容。
967
970
  */
@@ -1043,5 +1046,49 @@ type SyntheticStreamOptions = {
1043
1046
  */
1044
1047
  declare function syntheticStream(options: SyntheticStreamOptions): AsyncIterable<AIStreamEvent>;
1045
1048
  //#endregion
1046
- export { type AIClient, AIError, AIMappingError, AIProviderError, type AIRequest, AIRequestError, type AIResponse, AIStreamError, type AIStreamEvent, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, type AuxiliaryFinalizeOptions, type AuxiliaryFinalizeResult, type AuxiliaryInfo, type BackendAdapter, type BackendTrace, type BillingInfo, type BillingPostprocessHook, type BillingSource, ChatCompletionsAdapter, type ChatCompletionsAdapterOptions, type ContentBlock, type CreateAIClientOptions, type EventFactory, type EventFactoryBackend, type EventFactoryState, type FetchFn, type IncludeSettings, type InputItem, type LookupResult, type MessageCompletedEvent, type MessageDeltaEvent, type MessageItem, type MessageStartedEvent, MessagesAdapter, type MessagesAdapterOptions, MockAdapter, type MockAdapterOptions, type MockAuxiliaryStep, type MockCompleteStep, type MockErrorStep, type MockHandler, type MockHandlerContext, type MockHistoryRecord, type MockInputExpectation, type MockInterruptStep, type MockMessageStep, type MockOutputStep, type MockReasoningStep, type MockRequestExpectation, type MockStaticHandler, type MockStep, type MockTextStreamOptions, type MockThrowStep, type MockToolCallStep, type MockWarningStep, type NormalizeOptions, type NormalizedRequest, OllamaAdapter, type OllamaAdapterOptions, type OpaqueItem, type OutputItem, type ReasoningCompletedEvent, type ReasoningDeltaEvent, type ReasoningItem, type ReasoningStartedEvent, type ReplayItem, type ResponseAuxiliaryEvent, type ResponseCompletedEvent, type ResponseStartedEvent, type ResponseWarningEvent, ResponsesAdapter, type ResponsesAdapterOptions, type SSEEvent, type StopReason, type StreamEventBase, type StreamResult, type SyntheticStreamOptions, type ToolCallCompletedEvent, type ToolCallDeltaEvent, type ToolCallItem, type ToolCallStartedEvent, type ToolChoice, type ToolDefinition, type ToolResultItem, type Usage, type UsageSource, type ValidationIssue, WarningCode, aggregateEvents, assertMockRequest, assertValidRequest, blockToText, collectStream, contentBlocksToText, createAIClient, createEventFactory, emitMalformedStreamWarning, extractText, imageBlock, instructionsToText, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, metadataSourceList, normalizeRequest, opaqueBlock, opaqueItem, parseSSEEvents, reasoningItem, replayFromOutput, syntheticStream, textBlock, toolCallItem, toolResultItem, validateRequest, withMockStreaming };
1049
+ //#region src/helpers/usage-mapping.d.ts
1050
+ /** OpenAI Chat Completions `usage` */
1051
+ declare function usageFromChatCompletions(raw: {
1052
+ prompt_tokens?: number;
1053
+ completion_tokens?: number;
1054
+ total_tokens?: number;
1055
+ prompt_tokens_details?: {
1056
+ cached_tokens?: number;
1057
+ [key: string]: unknown;
1058
+ };
1059
+ completion_tokens_details?: {
1060
+ reasoning_tokens?: number;
1061
+ [key: string]: unknown;
1062
+ };
1063
+ }): Partial<Usage>;
1064
+ /** OpenAI Responses API `usage` */
1065
+ declare function usageFromOpenAIResponses(raw: {
1066
+ input_tokens?: number;
1067
+ output_tokens?: number;
1068
+ total_tokens?: number;
1069
+ input_tokens_details?: {
1070
+ cached_tokens?: number;
1071
+ [key: string]: unknown;
1072
+ };
1073
+ output_tokens_details?: {
1074
+ reasoning_tokens?: number;
1075
+ [key: string]: unknown;
1076
+ };
1077
+ [key: string]: unknown;
1078
+ }): Partial<Usage>;
1079
+ /** Anthropic Messages `usage`(message_start / message_delta) */
1080
+ declare function usageFromAnthropicMessages(raw: {
1081
+ input_tokens?: number;
1082
+ output_tokens?: number;
1083
+ cache_creation_input_tokens?: number;
1084
+ cache_read_input_tokens?: number;
1085
+ [key: string]: unknown;
1086
+ }): Partial<Usage>;
1087
+ /** Ollama 流式 chunk(无 cache / reasoning 细分时仅填基础与 billable 镜像) */
1088
+ declare function usageFromOllama(raw: {
1089
+ prompt_eval_count?: number;
1090
+ eval_count?: number;
1091
+ }): Partial<Usage>;
1092
+ //#endregion
1093
+ export { type AIClient, AIError, AIMappingError, AIProviderError, type AIRequest, AIRequestError, type AIResponse, AIStreamError, type AIStreamEvent, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, type AuxiliaryFinalizeOptions, type AuxiliaryFinalizeResult, type AuxiliaryInfo, type BackendAdapter, type BackendTrace, type BillingInfo, type BillingPostprocessHook, type BillingSource, ChatCompletionsAdapter, type ChatCompletionsAdapterOptions, type ContentBlock, type CreateAIClientOptions, type EventFactory, type EventFactoryBackend, type EventFactoryState, type FetchFn, type IncludeSettings, type InputItem, type InstructionBlock, type JsonContentBlock, type LookupResult, type MessageCompletedEvent, type MessageDeltaEvent, type MessageItem, type MessageStartedEvent, MessagesAdapter, type MessagesAdapterOptions, MockAdapter, type MockAdapterOptions, type MockAuxiliaryStep, type MockCompleteStep, type MockErrorStep, type MockHandler, type MockHandlerContext, type MockHistoryRecord, type MockInputExpectation, type MockInterruptStep, type MockMessageStep, type MockOutputStep, type MockReasoningStep, type MockRequestExpectation, type MockStaticHandler, type MockStep, type MockTextStreamOptions, type MockThrowStep, type MockToolCallStep, type MockWarningStep, type NormalizeOptions, type NormalizedRequest, OllamaAdapter, type OllamaAdapterOptions, type OpaqueItem, type OutputItem, type ReasoningCompletedEvent, type ReasoningDeltaEvent, type ReasoningItem, type ReasoningStartedEvent, type ReplayItem, type ResponseAuxiliaryEvent, type ResponseCompletedEvent, type ResponseStartedEvent, type ResponseWarningEvent, ResponsesAdapter, type ResponsesAdapterOptions, type SSEEvent, type StopReason, type StreamEventBase, type StreamResult, type SyntheticStreamOptions, type TextContentBlock, type ToolCallCompletedEvent, type ToolCallDeltaEvent, type ToolCallItem, type ToolCallStartedEvent, type ToolChoice, type ToolDefinition, type ToolResultItem, type Usage, type UsageSource, type ValidationIssue, WarningCode, aggregateEvents, assertMockRequest, assertValidRequest, blockToText, collectStream, contentBlocksToText, createAIClient, createEventFactory, emitMalformedStreamWarning, extractText, imageBlock, instructionsToText, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, metadataSourceList, normalizeRequest, opaqueBlock, opaqueItem, parseSSEEvents, reasoningItem, replayFromOutput, syntheticStream, textBlock, toolCallItem, toolResultItem, usageFromAnthropicMessages, usageFromChatCompletions, usageFromOllama, usageFromOpenAIResponses, validateRequest, withMockStreaming };
1047
1094
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -63,12 +63,7 @@ const WarningCode = {
63
63
  };
64
64
  //#endregion
65
65
  //#region src/core/validation.ts
66
- const MESSAGE_ROLES = /* @__PURE__ */ new Set([
67
- "user",
68
- "assistant",
69
- "system",
70
- "developer"
71
- ]);
66
+ const MESSAGE_ROLES = /* @__PURE__ */ new Set(["user", "assistant"]);
72
67
  const REASONING_VISIBILITIES = /* @__PURE__ */ new Set([
73
68
  "full",
74
69
  "summary",
@@ -122,6 +117,19 @@ function validateContentArray(content, field, issues, code) {
122
117
  }
123
118
  for (let i = 0; i < content.length; i++) validateContentBlock(content[i], `${field}[${i}]`, issues);
124
119
  }
120
+ function validateInstructionArray(content, field, issues) {
121
+ if (!Array.isArray(content)) {
122
+ pushIssue(issues, field, "INSTRUCTIONS_INVALID", `${field} must be an InstructionBlock[]`);
123
+ return;
124
+ }
125
+ for (let i = 0; i < content.length; i++) {
126
+ const block = content[i];
127
+ const blockField = `${field}[${i}]`;
128
+ validateContentBlock(block, blockField, issues);
129
+ if (!isRecord(block) || typeof block.type !== "string") continue;
130
+ if (block.type !== "text" && block.type !== "json") pushIssue(issues, blockField, "INSTRUCTIONS_INVALID", `${blockField} only supports text/json blocks`);
131
+ }
132
+ }
125
133
  function validateInputItem(item, field, issues) {
126
134
  if (!isRecord(item)) {
127
135
  pushIssue(issues, field, "INPUT_INVALID_ITEM", `${field} must be a valid InputItem`);
@@ -192,8 +200,8 @@ function validateToolChoice(toolChoice, issues) {
192
200
  */
193
201
  function validateRequest(request) {
194
202
  const issues = [];
195
- if (request.instructions !== void 0) if (typeof request.instructions === "string") {} else if (Array.isArray(request.instructions)) validateContentArray(request.instructions, "instructions", issues, "INSTRUCTIONS_INVALID");
196
- else pushIssue(issues, "instructions", "INSTRUCTIONS_INVALID", "instructions must be a string or ContentBlock[]");
203
+ if (request.instructions !== void 0) if (typeof request.instructions === "string") {} else if (Array.isArray(request.instructions)) validateInstructionArray(request.instructions, "instructions", issues);
204
+ else pushIssue(issues, "instructions", "INSTRUCTIONS_INVALID", "instructions must be a string or InstructionBlock[]");
197
205
  if (!Array.isArray(request.input) || request.input.length === 0) pushIssue(issues, "input", "INPUT_EMPTY", "input must be a non-empty array");
198
206
  if (Array.isArray(request.input)) for (let i = 0; i < request.input.length; i++) validateInputItem(request.input[i], `input[${i}]`, issues);
199
207
  if (request.temperature !== void 0) {
@@ -713,7 +721,7 @@ function contentBlocksToText(blocks) {
713
721
  return blocks.map(blockToText).join("\n");
714
722
  }
715
723
  /**
716
- * 将 instructions(string | ContentBlock[])归一化为纯文本。
724
+ * 将 instructions(string | InstructionBlock[])归一化为纯文本。
717
725
  */
718
726
  function instructionsToText(instructions) {
719
727
  return typeof instructions === "string" ? instructions : contentBlocksToText(instructions);
@@ -1003,6 +1011,93 @@ function mergeWarnings(...groups) {
1003
1011
  return merged.length > 0 ? merged : void 0;
1004
1012
  }
1005
1013
  //#endregion
1014
+ //#region src/helpers/usage-mapping.ts
1015
+ function num(value) {
1016
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1017
+ }
1018
+ function record(obj) {
1019
+ const out = {};
1020
+ for (const [key, value] of Object.entries(obj)) if (value !== void 0) out[key] = value;
1021
+ return out;
1022
+ }
1023
+ function billableFromOpenAIStyle(inputTokens, outputTokens, cachedInputTokens, reasoningTokens) {
1024
+ let billableInputTokens;
1025
+ if (inputTokens !== void 0) billableInputTokens = cachedInputTokens !== void 0 ? Math.max(0, inputTokens - cachedInputTokens) : inputTokens;
1026
+ let billableOutputTokens;
1027
+ if (outputTokens !== void 0) billableOutputTokens = reasoningTokens !== void 0 ? Math.max(0, outputTokens - reasoningTokens) : outputTokens;
1028
+ return record({
1029
+ billableInputTokens,
1030
+ billableOutputTokens
1031
+ });
1032
+ }
1033
+ /** OpenAI Chat Completions `usage` */
1034
+ function usageFromChatCompletions(raw) {
1035
+ const inputTokens = num(raw.prompt_tokens);
1036
+ const outputTokens = num(raw.completion_tokens);
1037
+ const cachedInputTokens = num(raw.prompt_tokens_details?.cached_tokens);
1038
+ const reasoningTokens = num(raw.completion_tokens_details?.reasoning_tokens);
1039
+ return record({
1040
+ inputTokens,
1041
+ outputTokens,
1042
+ totalTokens: num(raw.total_tokens) ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0),
1043
+ cachedInputTokens,
1044
+ reasoningTokens,
1045
+ ...billableFromOpenAIStyle(inputTokens, outputTokens, cachedInputTokens, reasoningTokens)
1046
+ });
1047
+ }
1048
+ /** OpenAI Responses API `usage` */
1049
+ function usageFromOpenAIResponses(raw) {
1050
+ const inputTokens = num(raw.input_tokens);
1051
+ const outputTokens = num(raw.output_tokens);
1052
+ const cachedInputTokens = num(raw.input_tokens_details?.cached_tokens);
1053
+ const reasoningTokens = num(raw.output_tokens_details?.reasoning_tokens);
1054
+ return record({
1055
+ inputTokens,
1056
+ outputTokens,
1057
+ totalTokens: num(raw.total_tokens) ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0),
1058
+ cachedInputTokens,
1059
+ reasoningTokens,
1060
+ ...billableFromOpenAIStyle(inputTokens, outputTokens, cachedInputTokens, reasoningTokens)
1061
+ });
1062
+ }
1063
+ /** Anthropic Messages `usage`(message_start / message_delta) */
1064
+ function usageFromAnthropicMessages(raw) {
1065
+ const inputTokens = num(raw.input_tokens);
1066
+ const outputTokens = num(raw.output_tokens);
1067
+ const cacheWriteInputTokens = num(raw.cache_creation_input_tokens);
1068
+ const cachedInputTokens = num(raw.cache_read_input_tokens);
1069
+ const inputParts = [
1070
+ inputTokens,
1071
+ cacheWriteInputTokens,
1072
+ cachedInputTokens
1073
+ ].filter((n) => n !== void 0);
1074
+ const summedInput = inputParts.length > 0 ? inputParts.reduce((sum, n) => sum + n, 0) : void 0;
1075
+ const totalTokens = summedInput !== void 0 && outputTokens !== void 0 ? summedInput + outputTokens : void 0;
1076
+ let billableInputTokens;
1077
+ if (inputTokens !== void 0 || cacheWriteInputTokens !== void 0) billableInputTokens = (inputTokens ?? 0) + (cacheWriteInputTokens ?? 0);
1078
+ return record({
1079
+ inputTokens,
1080
+ outputTokens,
1081
+ totalTokens,
1082
+ cachedInputTokens,
1083
+ cacheWriteInputTokens,
1084
+ billableInputTokens,
1085
+ billableOutputTokens: outputTokens
1086
+ });
1087
+ }
1088
+ /** Ollama 流式 chunk(无 cache / reasoning 细分时仅填基础与 billable 镜像) */
1089
+ function usageFromOllama(raw) {
1090
+ const inputTokens = num(raw.prompt_eval_count);
1091
+ const outputTokens = num(raw.eval_count);
1092
+ return record({
1093
+ inputTokens,
1094
+ outputTokens,
1095
+ totalTokens: inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0,
1096
+ billableInputTokens: inputTokens,
1097
+ billableOutputTokens: outputTokens
1098
+ });
1099
+ }
1100
+ //#endregion
1006
1101
  //#region src/helpers/sse-parser.ts
1007
1102
  /**
1008
1103
  * 将 SSE 文本块解析为事件数组。
@@ -1305,11 +1400,7 @@ var ResponsesAdapter = class extends AdapterBase {
1305
1400
  let rawResponseId;
1306
1401
  if (completedResponse) {
1307
1402
  rawResponseId = completedResponse.id;
1308
- if (completedResponse.usage) auxiliary.recordUsage({
1309
- inputTokens: completedResponse.usage.input_tokens,
1310
- outputTokens: completedResponse.usage.output_tokens,
1311
- totalTokens: completedResponse.usage.total_tokens
1312
- }, "final", completedResponse.usage);
1403
+ if (completedResponse.usage) auxiliary.recordUsage(usageFromOpenAIResponses(completedResponse.usage), "final", completedResponse.usage);
1313
1404
  }
1314
1405
  const replay = [...replayFromOutput(output)];
1315
1406
  if (completedResponse?.id) replay.push(opaqueItem("responses", "replay", { id: completedResponse.id }));
@@ -1380,6 +1471,10 @@ function parseMessagesSSE(chunk) {
1380
1471
  function rollbackTrailingAssistantMessages$2(messages) {
1381
1472
  while (messages.length > 0 && messages[messages.length - 1]?.role === "assistant") messages.pop();
1382
1473
  }
1474
+ /** 用 response 级别的命名空间合成 content block 的 item ID,避免多轮工具循环 ID 碰撞 */
1475
+ function synthesizeItemId(kind, blockIndex, responseId) {
1476
+ return `${kind}-${blockIndex}-${responseId}`;
1477
+ }
1383
1478
  function parseToolUseInput(input) {
1384
1479
  try {
1385
1480
  const parsed = JSON.parse(input);
@@ -1447,11 +1542,6 @@ var MessagesAdapter = class extends AdapterBase {
1447
1542
  if (request.instructions) systemPrompt = instructionsToMessagesText(request.instructions);
1448
1543
  for (const item of request.input) switch (item.type) {
1449
1544
  case "message": {
1450
- if (item.role === "system" || item.role === "developer") {
1451
- const text = contentBlocksToText(ensureMessagesTextBlocks(item.content, `input message (${item.role}) content`));
1452
- systemPrompt = systemPrompt ? `${systemPrompt}\n${text}` : text;
1453
- break;
1454
- }
1455
1545
  const role = item.role === "user" ? "user" : "assistant";
1456
1546
  const supportedContent = ensureMessagesTextBlocks(item.content, `input message (${item.role}) content`);
1457
1547
  if (supportedContent.length === 1 && supportedContent[0]?.type === "text") messages.push({
@@ -1581,7 +1671,7 @@ var MessagesAdapter = class extends AdapterBase {
1581
1671
  let argsBuffer = "";
1582
1672
  let stopReason;
1583
1673
  let stopSequence;
1584
- let rawResponseId;
1674
+ let rawResponseId = "";
1585
1675
  if (request.include?.providerMetadata !== "off") {
1586
1676
  const headerMetadata = pickProviderHeaders(response.headers);
1587
1677
  auxiliary.recordProviderMetadata("header", Object.keys(headerMetadata).length > 0 ? { headers: headerMetadata } : void 0);
@@ -1618,14 +1708,14 @@ var MessagesAdapter = class extends AdapterBase {
1618
1708
  switch (block.type) {
1619
1709
  case "text":
1620
1710
  currentItemType = "message";
1621
- currentItemId = `msg-${block.type}-${currentContentBlockIndex}`;
1711
+ currentItemId = synthesizeItemId("msg", currentContentBlockIndex, rawResponseId);
1622
1712
  textBuffer = "";
1623
1713
  yield factory.messageStarted(currentItemId);
1624
1714
  break;
1625
1715
  case "thinking":
1626
1716
  hasStreamedReasoning = true;
1627
1717
  currentItemType = "reasoning";
1628
- currentItemId = `reason-${currentContentBlockIndex}`;
1718
+ currentItemId = synthesizeItemId("reason", currentContentBlockIndex, rawResponseId);
1629
1719
  currentThinkingVisibility = "full";
1630
1720
  thinkingBuffer = "";
1631
1721
  yield factory.reasoningStarted(currentItemId, "full");
@@ -1633,7 +1723,7 @@ var MessagesAdapter = class extends AdapterBase {
1633
1723
  case "redacted_thinking": {
1634
1724
  hasStreamedReasoning = true;
1635
1725
  currentItemType = "reasoning";
1636
- currentItemId = `reason-redacted-${currentContentBlockIndex}`;
1726
+ currentItemId = synthesizeItemId("reason-redacted", currentContentBlockIndex, rawResponseId);
1637
1727
  currentThinkingVisibility = "redacted";
1638
1728
  const data = block.data;
1639
1729
  yield factory.reasoningStarted(currentItemId, "redacted");
@@ -1721,11 +1811,7 @@ var MessagesAdapter = class extends AdapterBase {
1721
1811
  stopReason = sseEvent.data.delta.stop_reason;
1722
1812
  stopSequence = sseEvent.data.delta.stop_sequence;
1723
1813
  const u = sseEvent.data.usage;
1724
- if (u) auxiliary.recordUsage({
1725
- inputTokens: u.input_tokens,
1726
- outputTokens: u.output_tokens,
1727
- totalTokens: u.input_tokens + u.output_tokens
1728
- }, "stream", u);
1814
+ if (u) auxiliary.recordUsage(usageFromAnthropicMessages(u), "stream", u);
1729
1815
  continue;
1730
1816
  }
1731
1817
  case "message_stop": break;
@@ -1899,7 +1985,7 @@ var ChatCompletionsAdapter = class extends AdapterBase {
1899
1985
  }
1900
1986
  for (const item of request.input) switch (item.type) {
1901
1987
  case "message": {
1902
- const role = item.role === "developer" ? "system" : item.role === "system" ? "system" : item.role === "user" ? "user" : "assistant";
1988
+ const role = item.role;
1903
1989
  const text = contentBlocksToChatText(item.content, `input message (${item.role}) content`);
1904
1990
  messages.push({
1905
1991
  role,
@@ -2060,11 +2146,7 @@ var ChatCompletionsAdapter = class extends AdapterBase {
2060
2146
  if (malformedWarning) yield malformedWarning;
2061
2147
  for (const chunk of chunks) {
2062
2148
  responseId = chunk.id;
2063
- if (chunk.usage) auxiliary.recordUsage({
2064
- inputTokens: chunk.usage.prompt_tokens,
2065
- outputTokens: chunk.usage.completion_tokens,
2066
- totalTokens: chunk.usage.total_tokens
2067
- }, "final", chunk.usage);
2149
+ if (chunk.usage) auxiliary.recordUsage(usageFromChatCompletions(chunk.usage), "final", chunk.usage);
2068
2150
  for (const choice of chunk.choices) {
2069
2151
  if (choice.index !== 0) continue;
2070
2152
  const delta = choice.delta;
@@ -2289,7 +2371,7 @@ var OllamaAdapter = class extends AdapterBase {
2289
2371
  });
2290
2372
  for (const item of request.input) switch (item.type) {
2291
2373
  case "message": {
2292
- const role = item.role === "developer" ? "system" : item.role === "system" ? "system" : item.role === "user" ? "user" : "assistant";
2374
+ const role = item.role;
2293
2375
  messages.push({
2294
2376
  role,
2295
2377
  content: contentBlocksToText(ensureOllamaTextBlocks(item.content, `input message (${item.role}) content`))
@@ -2434,11 +2516,10 @@ var OllamaAdapter = class extends AdapterBase {
2434
2516
  yield factory.toolCallCompleted(toolCall);
2435
2517
  output.push(toolCall);
2436
2518
  }
2437
- if (request.include?.usage !== "off" && (chunk.prompt_eval_count !== void 0 || chunk.eval_count !== void 0)) auxiliary.recordUsage({
2438
- inputTokens: chunk.prompt_eval_count,
2439
- outputTokens: chunk.eval_count,
2440
- totalTokens: chunk.prompt_eval_count !== void 0 && chunk.eval_count !== void 0 ? chunk.prompt_eval_count + chunk.eval_count : void 0
2441
- }, "final", {
2519
+ if (request.include?.usage !== "off" && (chunk.prompt_eval_count !== void 0 || chunk.eval_count !== void 0)) auxiliary.recordUsage(usageFromOllama({
2520
+ prompt_eval_count: chunk.prompt_eval_count,
2521
+ eval_count: chunk.eval_count
2522
+ }), "final", {
2442
2523
  prompt_eval_count: chunk.prompt_eval_count,
2443
2524
  eval_count: chunk.eval_count
2444
2525
  });
@@ -3003,6 +3084,6 @@ function* emitToolCallEvents(item, factory) {
3003
3084
  yield factory.toolCallCompleted(item);
3004
3085
  }
3005
3086
  //#endregion
3006
- export { AIError, AIMappingError, AIProviderError, AIRequestError, AIStreamError, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, ChatCompletionsAdapter, MessagesAdapter, MockAdapter, OllamaAdapter, ResponsesAdapter, WarningCode, aggregateEvents, assertMockRequest, assertValidRequest, blockToText, collectStream, contentBlocksToText, createAIClient, createEventFactory, emitMalformedStreamWarning, extractText, imageBlock, instructionsToText, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, metadataSourceList, normalizeRequest, opaqueBlock, opaqueItem, parseSSEEvents, reasoningItem, replayFromOutput, syntheticStream, textBlock, toolCallItem, toolResultItem, validateRequest, withMockStreaming };
3087
+ export { AIError, AIMappingError, AIProviderError, AIRequestError, AIStreamError, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, ChatCompletionsAdapter, MessagesAdapter, MockAdapter, OllamaAdapter, ResponsesAdapter, WarningCode, aggregateEvents, assertMockRequest, assertValidRequest, blockToText, collectStream, contentBlocksToText, createAIClient, createEventFactory, emitMalformedStreamWarning, extractText, imageBlock, instructionsToText, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, metadataSourceList, normalizeRequest, opaqueBlock, opaqueItem, parseSSEEvents, reasoningItem, replayFromOutput, syntheticStream, textBlock, toolCallItem, toolResultItem, usageFromAnthropicMessages, usageFromChatCompletions, usageFromOllama, usageFromOpenAIResponses, validateRequest, withMockStreaming };
3007
3088
 
3008
3089
  //# sourceMappingURL=index.mjs.map