@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 +2 -2
- package/dist/index.d.mts +12 -9
- package/dist/index.mjs +27 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/chat-completions.ts +1 -8
- package/src/adapters/messages.ts +10 -15
- package/src/adapters/ollama.ts +2 -9
- package/src/adapters/responses.ts +2 -2
- package/src/core/validation.ts +21 -3
- package/src/helpers/mapping.ts +3 -2
- package/src/types/content.ts +5 -2
- package/src/types/index.ts +1 -1
- package/src/types/items.ts +1 -1
- package/src/types/request.ts +2 -2
- package/bun.lock +0 -231
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
|
|
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"
|
|
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 |
|
|
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"
|
|
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 |
|
|
965
|
+
* 将 instructions(string | InstructionBlock[])归一化为纯文本。
|
|
963
966
|
*/
|
|
964
|
-
declare function instructionsToText(instructions: 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))
|
|
196
|
-
else pushIssue(issues, "instructions", "INSTRUCTIONS_INVALID", "instructions must be a string or
|
|
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 |
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
2299
|
+
const role = item.role;
|
|
2293
2300
|
messages.push({
|
|
2294
2301
|
role,
|
|
2295
2302
|
content: contentBlocksToText(ensureOllamaTextBlocks(item.content, `input message (${item.role}) content`))
|