@codehz/ai 0.1.4 → 0.1.5

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;
@@ -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,5 @@ 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
+ 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, validateRequest, withMockStreaming };
1047
1050
  //# 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);
@@ -1380,6 +1388,10 @@ function parseMessagesSSE(chunk) {
1380
1388
  function rollbackTrailingAssistantMessages$2(messages) {
1381
1389
  while (messages.length > 0 && messages[messages.length - 1]?.role === "assistant") messages.pop();
1382
1390
  }
1391
+ /** 用 response 级别的命名空间合成 content block 的 item ID,避免多轮工具循环 ID 碰撞 */
1392
+ function synthesizeItemId(kind, blockIndex, responseId) {
1393
+ return `${kind}-${blockIndex}-${responseId}`;
1394
+ }
1383
1395
  function parseToolUseInput(input) {
1384
1396
  try {
1385
1397
  const parsed = JSON.parse(input);
@@ -1447,11 +1459,6 @@ var MessagesAdapter = class extends AdapterBase {
1447
1459
  if (request.instructions) systemPrompt = instructionsToMessagesText(request.instructions);
1448
1460
  for (const item of request.input) switch (item.type) {
1449
1461
  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
1462
  const role = item.role === "user" ? "user" : "assistant";
1456
1463
  const supportedContent = ensureMessagesTextBlocks(item.content, `input message (${item.role}) content`);
1457
1464
  if (supportedContent.length === 1 && supportedContent[0]?.type === "text") messages.push({
@@ -1581,7 +1588,7 @@ var MessagesAdapter = class extends AdapterBase {
1581
1588
  let argsBuffer = "";
1582
1589
  let stopReason;
1583
1590
  let stopSequence;
1584
- let rawResponseId;
1591
+ let rawResponseId = "";
1585
1592
  if (request.include?.providerMetadata !== "off") {
1586
1593
  const headerMetadata = pickProviderHeaders(response.headers);
1587
1594
  auxiliary.recordProviderMetadata("header", Object.keys(headerMetadata).length > 0 ? { headers: headerMetadata } : void 0);
@@ -1618,14 +1625,14 @@ var MessagesAdapter = class extends AdapterBase {
1618
1625
  switch (block.type) {
1619
1626
  case "text":
1620
1627
  currentItemType = "message";
1621
- currentItemId = `msg-${block.type}-${currentContentBlockIndex}`;
1628
+ currentItemId = synthesizeItemId("msg", currentContentBlockIndex, rawResponseId);
1622
1629
  textBuffer = "";
1623
1630
  yield factory.messageStarted(currentItemId);
1624
1631
  break;
1625
1632
  case "thinking":
1626
1633
  hasStreamedReasoning = true;
1627
1634
  currentItemType = "reasoning";
1628
- currentItemId = `reason-${currentContentBlockIndex}`;
1635
+ currentItemId = synthesizeItemId("reason", currentContentBlockIndex, rawResponseId);
1629
1636
  currentThinkingVisibility = "full";
1630
1637
  thinkingBuffer = "";
1631
1638
  yield factory.reasoningStarted(currentItemId, "full");
@@ -1633,7 +1640,7 @@ var MessagesAdapter = class extends AdapterBase {
1633
1640
  case "redacted_thinking": {
1634
1641
  hasStreamedReasoning = true;
1635
1642
  currentItemType = "reasoning";
1636
- currentItemId = `reason-redacted-${currentContentBlockIndex}`;
1643
+ currentItemId = synthesizeItemId("reason-redacted", currentContentBlockIndex, rawResponseId);
1637
1644
  currentThinkingVisibility = "redacted";
1638
1645
  const data = block.data;
1639
1646
  yield factory.reasoningStarted(currentItemId, "redacted");
@@ -1899,7 +1906,7 @@ var ChatCompletionsAdapter = class extends AdapterBase {
1899
1906
  }
1900
1907
  for (const item of request.input) switch (item.type) {
1901
1908
  case "message": {
1902
- const role = item.role === "developer" ? "system" : item.role === "system" ? "system" : item.role === "user" ? "user" : "assistant";
1909
+ const role = item.role;
1903
1910
  const text = contentBlocksToChatText(item.content, `input message (${item.role}) content`);
1904
1911
  messages.push({
1905
1912
  role,
@@ -2289,7 +2296,7 @@ var OllamaAdapter = class extends AdapterBase {
2289
2296
  });
2290
2297
  for (const item of request.input) switch (item.type) {
2291
2298
  case "message": {
2292
- const role = item.role === "developer" ? "system" : item.role === "system" ? "system" : item.role === "user" ? "user" : "assistant";
2299
+ const role = item.role;
2293
2300
  messages.push({
2294
2301
  role,
2295
2302
  content: contentBlocksToText(ensureOllamaTextBlocks(item.content, `input message (${item.role}) content`))