@codehz/ai 0.2.3 → 0.3.0
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 +34 -38
- package/dist/index.d.mts +18 -40
- package/dist/index.mjs +88 -139
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/chat-completions.ts +4 -22
- package/src/adapters/messages.ts +10 -28
- package/src/adapters/mock.ts +9 -12
- package/src/adapters/ollama.ts +26 -53
- package/src/adapters/responses.ts +17 -35
- package/src/core/client.ts +15 -2
- package/src/core/validation.ts +19 -0
- package/src/helpers/adapter-base.ts +6 -3
- package/src/helpers/index.ts +0 -1
- package/src/helpers/mapping.ts +1 -2
- package/src/helpers/request-mapper.ts +18 -25
- package/src/index.ts +1 -1
- package/src/types/adapter.ts +3 -12
- package/src/types/index.ts +1 -9
- package/src/types/items.ts +0 -1
- package/src/types/request.ts +2 -0
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
import { AIRequestError } from "../core/errors.js";
|
|
2
2
|
import { contentBlocksToText } from "./mapping.js";
|
|
3
3
|
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
export type ProviderProfile = {
|
|
7
|
-
readonly kind: string;
|
|
8
|
-
readonly instructionsMode: "system_message" | "instructions_field" | "none";
|
|
9
|
-
readonly supportedBlockTypes: ReadonlyArray<ContentBlock["type"]>;
|
|
10
|
-
readonly reasoningBlockTypes: ReadonlyArray<ContentBlock["type"]>;
|
|
11
|
-
readonly capabilities: AdapterCapabilities;
|
|
12
|
-
};
|
|
4
|
+
import type { ContentBlock, InstructionBlock, ToolCallItem } from "../types/index.js";
|
|
13
5
|
|
|
14
6
|
export class NormalizedRequestMapper {
|
|
15
|
-
constructor(readonly
|
|
7
|
+
constructor(readonly kind: string) {}
|
|
16
8
|
|
|
17
9
|
mapInstructions(instructions: string | InstructionBlock[]): string {
|
|
18
10
|
return typeof instructions === "string"
|
|
@@ -21,27 +13,28 @@ export class NormalizedRequestMapper {
|
|
|
21
13
|
}
|
|
22
14
|
|
|
23
15
|
ensureTextBlocks(blocks: ContentBlock[], field: string): ContentBlock[] {
|
|
24
|
-
return this.ensureBlocks(blocks, field,
|
|
16
|
+
return this.ensureBlocks(blocks, field, ["text", "json"], "only text/json blocks are supported");
|
|
25
17
|
}
|
|
26
18
|
|
|
27
19
|
ensureReasoningBlocks(blocks: ContentBlock[], field: string): Array<Extract<ContentBlock, { type: "text" }>> {
|
|
28
|
-
return this.ensureBlocks(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.profile.reasoningBlockTypes,
|
|
32
|
-
"reasoning only supports text blocks",
|
|
33
|
-
) as Array<Extract<ContentBlock, { type: "text" }>>;
|
|
20
|
+
return this.ensureBlocks(blocks, field, ["text"], "reasoning only supports text blocks") as Array<
|
|
21
|
+
Extract<ContentBlock, { type: "text" }>
|
|
22
|
+
>;
|
|
34
23
|
}
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
parseToolArguments(item: ToolCallItem): Record<string, unknown> {
|
|
26
|
+
try {
|
|
27
|
+
const parsed: unknown = JSON.parse(item.argumentsText);
|
|
28
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
29
|
+
return parsed as Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// handled below
|
|
33
|
+
}
|
|
38
34
|
|
|
39
|
-
const outcomes = this.profile.capabilities.toolResultOutcomes;
|
|
40
|
-
const supported = outcomes.map((value) => `"${value}"`).join(" and ");
|
|
41
|
-
const verb = outcomes.length > 1 ? "are" : "is";
|
|
42
35
|
throw new AIRequestError(
|
|
43
|
-
`${this.
|
|
44
|
-
"
|
|
36
|
+
`${this.kind} requires tool_call argumentsText to be a valid JSON object`,
|
|
37
|
+
"TOOL_CALL_ARGUMENTS_INVALID",
|
|
45
38
|
);
|
|
46
39
|
}
|
|
47
40
|
|
|
@@ -61,7 +54,7 @@ export class NormalizedRequestMapper {
|
|
|
61
54
|
const block = blocks[i];
|
|
62
55
|
if (block && !supportedTypes.includes(block.type)) {
|
|
63
56
|
throw new AIRequestError(
|
|
64
|
-
`${this.
|
|
57
|
+
`${this.kind} does not support ${field}[${i}] of type "${block.type}"; ${description}`,
|
|
65
58
|
"UNSUPPORTED_CONTENT_BLOCK",
|
|
66
59
|
);
|
|
67
60
|
}
|
package/src/index.ts
CHANGED
package/src/types/adapter.ts
CHANGED
|
@@ -21,20 +21,9 @@ export type NormalizedRequest = AIRequest & {
|
|
|
21
21
|
|
|
22
22
|
// ── Adapter 接口 ──────────────────────────────────────────────
|
|
23
23
|
|
|
24
|
-
export type StreamingCapability = "native" | "synthetic" | "none";
|
|
25
|
-
|
|
26
|
-
export type AdapterCapabilities = {
|
|
27
|
-
readonly textStreaming: StreamingCapability;
|
|
28
|
-
readonly reasoningStreaming: StreamingCapability;
|
|
29
|
-
readonly toolCallStreaming: StreamingCapability;
|
|
30
|
-
readonly replay: "canonical" | "opaque" | "none";
|
|
31
|
-
readonly usage: "stream" | "final" | "none";
|
|
32
|
-
readonly toolResultOutcomes: ReadonlyArray<"success" | "error" | "rejected">;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
24
|
export interface BackendAdapter {
|
|
36
25
|
readonly kind: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
37
|
-
readonly
|
|
26
|
+
readonly isSyntheticStream: boolean;
|
|
38
27
|
stream(request: NormalizedRequest): AsyncIterable<AIStreamEvent>;
|
|
39
28
|
}
|
|
40
29
|
|
|
@@ -44,6 +33,8 @@ export type CreateAIClientOptions = {
|
|
|
44
33
|
adapter: BackendAdapter;
|
|
45
34
|
model: string;
|
|
46
35
|
defaults?: Partial<AIRequest>;
|
|
36
|
+
/** 全局默认 AbortSignal,当 request.signal 未设置时生效。 */
|
|
37
|
+
signal?: AbortSignal;
|
|
47
38
|
};
|
|
48
39
|
|
|
49
40
|
export interface AIClient {
|
package/src/types/index.ts
CHANGED
|
@@ -46,12 +46,4 @@ export type {
|
|
|
46
46
|
} from "./events.js";
|
|
47
47
|
|
|
48
48
|
// Adapter 协议和 client 类型
|
|
49
|
-
export type {
|
|
50
|
-
AdapterCapabilities,
|
|
51
|
-
StreamingCapability,
|
|
52
|
-
BackendAdapter,
|
|
53
|
-
FetchFn,
|
|
54
|
-
NormalizedRequest,
|
|
55
|
-
CreateAIClientOptions,
|
|
56
|
-
AIClient,
|
|
57
|
-
} from "./adapter.js";
|
|
49
|
+
export type { BackendAdapter, FetchFn, NormalizedRequest, CreateAIClientOptions, AIClient } from "./adapter.js";
|
package/src/types/items.ts
CHANGED