@codehz/ai 0.1.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.
@@ -0,0 +1,109 @@
1
+ /**
2
+ * BackendAdapter — adapter 内部协议和 client 公开类型
3
+ *
4
+ * adapter 对前台只暴露一个统一适配点。
5
+ * 能力矩阵在此落成代码而非仅存在于文档。
6
+ */
7
+
8
+ import type { AIRequest } from "./request.js";
9
+ import type { AIStreamEvent } from "./events.js";
10
+
11
+ // ── 公共工具类型 ──────────────────────────────────────────────
12
+
13
+ /** HTTP fetch 函数签名,用于注入自定义请求实现(测试/代理) */
14
+ export type FetchFn = (url: string, init: RequestInit) => Promise<Response>;
15
+
16
+ // ── 归一化请求 ────────────────────────────────────────────────
17
+
18
+ export type NormalizedRequest = AIRequest & {
19
+ model: string;
20
+ requestId: string;
21
+ };
22
+
23
+ // ── 能力矩阵 ──────────────────────────────────────────────────
24
+
25
+ export type AdapterCapabilities = {
26
+ nativeStreaming: boolean;
27
+ messageStreaming: boolean;
28
+ reasoningStreaming: boolean;
29
+ toolCallStreaming: boolean;
30
+ hiddenReasoningReplay: "full" | "partial" | "none";
31
+ replayFidelity: "high" | "medium" | "low";
32
+ tools: boolean;
33
+ usage: "full" | "partial" | "none";
34
+ billing: "direct" | "lookup" | "derived" | "none";
35
+ providerMetadata: boolean;
36
+ };
37
+
38
+ // ── 能力矩阵常量(文档中的能力表在此落代码) ────────────────
39
+
40
+ export const CAPABILITY_MATRIX = {
41
+ responses: {
42
+ nativeStreaming: true,
43
+ messageStreaming: true,
44
+ reasoningStreaming: true,
45
+ toolCallStreaming: true,
46
+ hiddenReasoningReplay: "full" as const,
47
+ replayFidelity: "high" as const,
48
+ tools: true,
49
+ usage: "full" as const,
50
+ billing: "lookup" as const,
51
+ providerMetadata: true,
52
+ },
53
+ messages: {
54
+ nativeStreaming: true,
55
+ messageStreaming: true,
56
+ reasoningStreaming: false, // 条件支持,默认 false
57
+ toolCallStreaming: true,
58
+ hiddenReasoningReplay: "partial" as const,
59
+ replayFidelity: "medium" as const,
60
+ tools: true,
61
+ usage: "full" as const,
62
+ billing: "lookup" as const,
63
+ providerMetadata: true,
64
+ },
65
+ "chat.completions": {
66
+ nativeStreaming: true,
67
+ messageStreaming: true,
68
+ reasoningStreaming: false,
69
+ toolCallStreaming: false, // 中,默认 false
70
+ hiddenReasoningReplay: "none" as const,
71
+ replayFidelity: "low" as const,
72
+ tools: true,
73
+ usage: "full" as const,
74
+ billing: "derived" as const,
75
+ providerMetadata: false,
76
+ },
77
+ ollama: {
78
+ nativeStreaming: true,
79
+ messageStreaming: true,
80
+ reasoningStreaming: false,
81
+ toolCallStreaming: false,
82
+ hiddenReasoningReplay: "none" as const,
83
+ replayFidelity: "low" as const,
84
+ tools: true,
85
+ usage: "partial" as const,
86
+ billing: "none" as const,
87
+ providerMetadata: false,
88
+ },
89
+ } as const satisfies Record<string, AdapterCapabilities>;
90
+
91
+ // ── Adapter 接口 ──────────────────────────────────────────────
92
+
93
+ export interface BackendAdapter {
94
+ readonly kind: "chat-completions" | "messages" | "responses" | "ollama";
95
+ readonly capabilities: AdapterCapabilities;
96
+ stream(request: NormalizedRequest): AsyncIterable<AIStreamEvent>;
97
+ }
98
+
99
+ // ── Client 公开类型 ───────────────────────────────────────────
100
+
101
+ export type CreateAIClientOptions = {
102
+ adapter: BackendAdapter;
103
+ model: string;
104
+ defaults?: Partial<AIRequest>;
105
+ };
106
+
107
+ export interface AIClient {
108
+ stream(request: AIRequest): AsyncIterable<AIStreamEvent>;
109
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * ContentBlock — 统一内容块类型
3
+ *
4
+ * 覆盖文本、JSON、图片、二进制引用和后端私有内容。
5
+ */
6
+
7
+ export type ContentBlock =
8
+ | { type: "text"; text: string }
9
+ | { type: "json"; json: unknown }
10
+ | { type: "image"; imageUrl: string }
11
+ | { type: "binary_ref"; ref: string }
12
+ | { type: "opaque"; payload: unknown };
@@ -0,0 +1,134 @@
1
+ /**
2
+ * AIStreamEvent — 统一流事件模型
3
+ *
4
+ * 所有 adapter 都必须产出 AsyncIterable<AIStreamEvent>。
5
+ * 无论后端是否支持原生流式,调用方看到的事件语义都一致:
6
+ * 响应级开始 → item 级开始/增量/完成 → 响应级完成
7
+ */
8
+
9
+ import type { ContentBlock } from "./content.js";
10
+ import type { MessageItem, ReasoningItem, ToolCallItem } from "./items.js";
11
+ import type { AIResponse, Usage, BillingInfo, AuxiliaryInfo } from "./response.js";
12
+
13
+ // ── 事件基类 ──────────────────────────────────────────────────
14
+
15
+ export type StreamEventBase = {
16
+ type: string;
17
+ responseId?: string;
18
+ sequence: number;
19
+ timestamp: string;
20
+ backend: {
21
+ kind: "chat-completions" | "messages" | "responses" | "ollama";
22
+ isSynthetic: boolean;
23
+ };
24
+ };
25
+
26
+ // ── 响应级事件 ────────────────────────────────────────────────
27
+
28
+ export type ResponseStartedEvent = StreamEventBase & {
29
+ type: "response.started";
30
+ model: string;
31
+ };
32
+
33
+ export type ResponseWarningEvent = StreamEventBase & {
34
+ type: "response.warning";
35
+ message: string;
36
+ code?: string;
37
+ };
38
+
39
+ export type ResponseAuxiliaryEvent = StreamEventBase & {
40
+ type: "response.auxiliary";
41
+ usage?: Usage;
42
+ billing?: BillingInfo;
43
+ auxiliary?: Partial<AuxiliaryInfo>;
44
+ };
45
+
46
+ export type ResponseCompletedEvent = StreamEventBase & {
47
+ type: "response.completed";
48
+ response: AIResponse;
49
+ };
50
+
51
+ // ── 消息流事件 ────────────────────────────────────────────────
52
+
53
+ export type MessageStartedEvent = StreamEventBase & {
54
+ type: "message.started";
55
+ item: {
56
+ id: string;
57
+ role: "assistant";
58
+ };
59
+ };
60
+
61
+ export type MessageDeltaEvent = StreamEventBase & {
62
+ type: "message.delta";
63
+ itemId: string;
64
+ delta: {
65
+ type: "text";
66
+ text: string;
67
+ };
68
+ };
69
+
70
+ export type MessageCompletedEvent = StreamEventBase & {
71
+ type: "message.completed";
72
+ item: MessageItem;
73
+ };
74
+
75
+ // ── 思维链流事件 ──────────────────────────────────────────────
76
+
77
+ export type ReasoningStartedEvent = StreamEventBase & {
78
+ type: "reasoning.started";
79
+ item: {
80
+ id: string;
81
+ visibility: "full" | "summary" | "redacted" | "opaque";
82
+ };
83
+ };
84
+
85
+ export type ReasoningDeltaEvent = StreamEventBase & {
86
+ type: "reasoning.delta";
87
+ itemId: string;
88
+ delta: ContentBlock;
89
+ };
90
+
91
+ export type ReasoningCompletedEvent = StreamEventBase & {
92
+ type: "reasoning.completed";
93
+ item: ReasoningItem;
94
+ };
95
+
96
+ // ── 工具调用流事件 ────────────────────────────────────────────
97
+
98
+ export type ToolCallStartedEvent = StreamEventBase & {
99
+ type: "tool_call.started";
100
+ item: {
101
+ id: string;
102
+ name: string;
103
+ };
104
+ };
105
+
106
+ export type ToolCallDeltaEvent = StreamEventBase & {
107
+ type: "tool_call.delta";
108
+ itemId: string;
109
+ delta: {
110
+ argumentsText?: string;
111
+ };
112
+ };
113
+
114
+ export type ToolCallCompletedEvent = StreamEventBase & {
115
+ type: "tool_call.completed";
116
+ item: ToolCallItem;
117
+ };
118
+
119
+ // ── 统一事件联合 ──────────────────────────────────────────────
120
+
121
+ export type AIStreamEvent =
122
+ | ResponseStartedEvent
123
+ | ResponseWarningEvent
124
+ | ResponseAuxiliaryEvent
125
+ | MessageStartedEvent
126
+ | MessageDeltaEvent
127
+ | MessageCompletedEvent
128
+ | ReasoningStartedEvent
129
+ | ReasoningDeltaEvent
130
+ | ReasoningCompletedEvent
131
+ | ToolCallStartedEvent
132
+ | ToolCallDeltaEvent
133
+ | ToolCallCompletedEvent
134
+ | ResponseCompletedEvent;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Canonical 类型系统
3
+ *
4
+ * 模块边界:统一请求、事件、响应模型的核心类型定义。
5
+ * 所有公开类型最终从这里导出。
6
+ */
7
+
8
+ // 基础内容块
9
+ export type { ContentBlock } from "./content.js";
10
+
11
+ // Item 类型体系
12
+ export type {
13
+ MessageItem,
14
+ ReasoningItem,
15
+ ToolCallItem,
16
+ ToolResultItem,
17
+ OpaqueItem,
18
+ InputItem,
19
+ OutputItem,
20
+ ReplayItem,
21
+ } from "./items.js";
22
+
23
+ // 请求模型
24
+ export type { AIRequest, ToolDefinition, ToolChoice, IncludeSettings } from "./request.js";
25
+
26
+ // 响应模型
27
+ export type { AIResponse, StopReason, Usage, BillingInfo, AuxiliaryInfo, BackendTrace } from "./response.js";
28
+
29
+ // 流事件模型
30
+ export type {
31
+ AIStreamEvent,
32
+ StreamEventBase,
33
+ ResponseStartedEvent,
34
+ ResponseWarningEvent,
35
+ ResponseAuxiliaryEvent,
36
+ ResponseCompletedEvent,
37
+ MessageStartedEvent,
38
+ MessageDeltaEvent,
39
+ MessageCompletedEvent,
40
+ ReasoningStartedEvent,
41
+ ReasoningDeltaEvent,
42
+ ReasoningCompletedEvent,
43
+ ToolCallStartedEvent,
44
+ ToolCallDeltaEvent,
45
+ ToolCallCompletedEvent,
46
+ } from "./events.js";
47
+
48
+ // Adapter 协议和 client 类型
49
+ export type {
50
+ BackendAdapter,
51
+ AdapterCapabilities,
52
+ FetchFn,
53
+ NormalizedRequest,
54
+ CreateAIClientOptions,
55
+ AIClient,
56
+ } from "./adapter.js";
57
+
58
+ // 能力矩阵常量
59
+ export { CAPABILITY_MATRIX } from "./adapter.js";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Canonical Item 类型体系
3
+ *
4
+ * 覆盖统一请求/响应中的所有 item 类型。
5
+ */
6
+
7
+ import type { ContentBlock } from "./content.js";
8
+
9
+ // ── Input item types ──────────────────────────────────────────
10
+
11
+ export type MessageItem = {
12
+ type: "message";
13
+ id?: string;
14
+ role: "user" | "assistant" | "system" | "developer";
15
+ content: ContentBlock[];
16
+ };
17
+
18
+ export type ReasoningItem = {
19
+ type: "reasoning";
20
+ id?: string;
21
+ visibility: "full" | "summary" | "redacted" | "opaque";
22
+ content: ContentBlock[];
23
+ };
24
+
25
+ export type ToolCallItem = {
26
+ type: "tool_call";
27
+ id: string;
28
+ name: string;
29
+ argumentsText: string;
30
+ argumentsJson?: unknown;
31
+ };
32
+
33
+ export type ToolResultItem = {
34
+ type: "tool_result";
35
+ callId: string;
36
+ toolName: string;
37
+ outcome: "success" | "error" | "rejected";
38
+ content: ContentBlock[];
39
+ };
40
+
41
+ export type OpaqueItem = {
42
+ type: "opaque";
43
+ id?: string;
44
+ source: "responses" | "messages" | "chat.completions" | string;
45
+ purpose: "replay" | "provider_state" | "unknown";
46
+ payload: unknown;
47
+ };
48
+
49
+ // ── Aliases ───────────────────────────────────────────────────
50
+
51
+ /** 可出现在请求 input 中的 item 类型 */
52
+ export type InputItem = MessageItem | ReasoningItem | ToolCallItem | ToolResultItem | OpaqueItem;
53
+
54
+ /** 可出现在响应 output 中的 item 类型(不含 ToolResultItem) */
55
+ export type OutputItem = MessageItem | ReasoningItem | ToolCallItem | OpaqueItem;
56
+
57
+ /** replay 材料的类型等价于 InputItem */
58
+ export type ReplayItem = InputItem;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AIRequest — 统一请求模型
3
+ *
4
+ * 所有 adapter 都接受同一形状的 canonical request。
5
+ */
6
+
7
+ import type { ContentBlock } from "./content.js";
8
+ import type { InputItem } from "./items.js";
9
+
10
+ // ── 工具定义 ──────────────────────────────────────────────────
11
+
12
+ export type ToolDefinition = {
13
+ name: string;
14
+ description?: string;
15
+ inputSchema: Record<string, unknown>;
16
+ };
17
+
18
+ export type ToolChoice = "auto" | "none" | { type: "tool"; name: string };
19
+
20
+ // ── include 控制 ──────────────────────────────────────────────
21
+
22
+ export type IncludeSettings = {
23
+ usage?: "off" | "best_effort";
24
+ billing?: "off" | "best_effort";
25
+ providerMetadata?: "off" | "best_effort";
26
+ };
27
+
28
+ // ── 统一请求 ──────────────────────────────────────────────────
29
+
30
+ export type AIRequest = {
31
+ instructions?: string | ContentBlock[];
32
+ input: InputItem[];
33
+ tools?: ToolDefinition[];
34
+ toolChoice?: ToolChoice;
35
+ include?: IncludeSettings;
36
+ metadata?: Record<string, string>;
37
+ temperature?: number;
38
+ maxOutputTokens?: number;
39
+ };
@@ -0,0 +1,65 @@
1
+ /**
2
+ * AIResponse — 统一终结结果模型
3
+ *
4
+ * 流结束后由聚合器产出,用于承载当前轮的规范化输出、replay 材料及辅助信息。
5
+ */
6
+
7
+ import type { OutputItem, ReplayItem, ToolCallItem } from "./items.js";
8
+
9
+ // ── StopReason ────────────────────────────────────────────────
10
+
11
+ export type StopReason = "end_turn" | "tool_call" | "max_output_tokens" | "content_filter" | "error" | "unknown";
12
+
13
+ // ── 辅助信息类型 ──────────────────────────────────────────────
14
+
15
+ export type Usage = {
16
+ inputTokens?: number;
17
+ outputTokens?: number;
18
+ reasoningTokens?: number;
19
+ totalTokens?: number;
20
+ cachedInputTokens?: number;
21
+ cacheWriteInputTokens?: number;
22
+ billableInputTokens?: number;
23
+ billableOutputTokens?: number;
24
+ };
25
+
26
+ export type BillingInfo = {
27
+ amount?: number;
28
+ currency?: string;
29
+ isEstimated: boolean;
30
+ source: "provider" | "lookup" | "derived" | "unknown";
31
+ raw?: unknown;
32
+ };
33
+
34
+ export type AuxiliaryInfo = {
35
+ usageSource?: "stream" | "final" | "header" | "lookup" | "derived";
36
+ billingSource?: "stream" | "final" | "header" | "lookup" | "derived";
37
+ providerUsage?: unknown;
38
+ providerBilling?: unknown;
39
+ providerMetadata?: Record<string, unknown>;
40
+ };
41
+
42
+ export type BackendTrace = {
43
+ requestId?: string;
44
+ rawResponseId?: string;
45
+ adapter: "chat-completions" | "messages" | "responses" | "ollama";
46
+ isSyntheticStream: boolean;
47
+ metadataSources?: string[];
48
+ warnings?: string[];
49
+ };
50
+
51
+ // ── 统一响应 ──────────────────────────────────────────────────
52
+
53
+ export type AIResponse = {
54
+ id?: string;
55
+ output: OutputItem[];
56
+ replay: ReplayItem[];
57
+ text: string;
58
+ toolCalls: ToolCallItem[];
59
+ stopReason?: StopReason;
60
+ usage?: Usage;
61
+ billing?: BillingInfo;
62
+ auxiliary?: AuxiliaryInfo;
63
+ warnings?: string[];
64
+ backend: BackendTrace;
65
+ };
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "tsdown";
2
+
3
+ export default defineConfig({
4
+ entry: ["./src/index.ts"],
5
+ format: ["esm"],
6
+ dts: true,
7
+ platform: "node",
8
+ clean: true,
9
+ sourcemap: true,
10
+ });