@codehz/ai 0.1.0 → 0.1.2
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 +109 -2
- package/dist/index.d.mts +174 -7
- package/dist/index.mjs +382 -107
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/adapters/chat-completions.ts +1 -0
- package/src/adapters/index.ts +21 -0
- package/src/adapters/messages.ts +1 -0
- package/src/adapters/mock.ts +721 -0
- package/src/adapters/ollama.ts +2 -0
- package/src/adapters/responses.ts +1 -0
- package/src/core/aggregator.ts +72 -177
- package/src/core/collect-stream.ts +4 -4
- package/src/core/event-factory.ts +1 -1
- package/src/helpers/adapter-base.ts +5 -5
- package/src/helpers/synthetic-stream.ts +1 -1
- package/src/types/adapter.ts +13 -1
- package/src/types/events.ts +1 -1
- package/src/types/response.ts +1 -1
package/src/adapters/ollama.ts
CHANGED
|
@@ -84,6 +84,7 @@ function ensureOllamaTextBlocks(
|
|
|
84
84
|
): import("../index.js").ContentBlock[] {
|
|
85
85
|
for (let i = 0; i < blocks.length; i++) {
|
|
86
86
|
const block = blocks[i];
|
|
87
|
+
if (!block) continue;
|
|
87
88
|
if (block.type !== "text" && block.type !== "json") {
|
|
88
89
|
throw new AIRequestError(
|
|
89
90
|
`ollama does not support ${field}[${i}] of type "${block.type}"; only text/json blocks are supported`,
|
|
@@ -519,6 +520,7 @@ export class OllamaAdapter extends AdapterBase {
|
|
|
519
520
|
);
|
|
520
521
|
}
|
|
521
522
|
|
|
523
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
522
524
|
const auxiliaryResult = await auxiliary.finalize(factory);
|
|
523
525
|
for (const event of auxiliaryResult.events) {
|
|
524
526
|
yield event;
|
|
@@ -77,6 +77,7 @@ function ensureResponsesTextBlocks(
|
|
|
77
77
|
): import("../index.js").ContentBlock[] {
|
|
78
78
|
for (let i = 0; i < blocks.length; i++) {
|
|
79
79
|
const block = blocks[i];
|
|
80
|
+
if (!block) continue;
|
|
80
81
|
if (block.type !== "text" && block.type !== "json") {
|
|
81
82
|
throw new AIRequestError(
|
|
82
83
|
`responses does not support ${field}[${i}] of type "${block.type}"; only text/json blocks are supported`,
|
package/src/core/aggregator.ts
CHANGED
|
@@ -17,9 +17,7 @@
|
|
|
17
17
|
import type {
|
|
18
18
|
AIStreamEvent,
|
|
19
19
|
AIResponse,
|
|
20
|
-
ContentBlock,
|
|
21
20
|
MessageItem,
|
|
22
|
-
ReasoningItem,
|
|
23
21
|
ToolCallItem,
|
|
24
22
|
OutputItem,
|
|
25
23
|
Usage,
|
|
@@ -29,26 +27,9 @@ import type {
|
|
|
29
27
|
StopReason,
|
|
30
28
|
} from "../types/index.js";
|
|
31
29
|
|
|
32
|
-
// ── 内部 pending item 状态 ────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
interface PendingMessage {
|
|
35
|
-
role: "assistant";
|
|
36
|
-
texts: string[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface PendingReasoning {
|
|
40
|
-
visibility: ReasoningItem["visibility"];
|
|
41
|
-
blocks: ContentBlock[];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface PendingToolCall {
|
|
45
|
-
name: string;
|
|
46
|
-
argsParts: string[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
30
|
// ── 聚合器状态 ────────────────────────────────────────────────
|
|
50
31
|
|
|
51
|
-
interface AggregatorState {
|
|
32
|
+
export interface AggregatorState {
|
|
52
33
|
responseId?: string;
|
|
53
34
|
model?: string;
|
|
54
35
|
backendInfo?: { kind: BackendTrace["adapter"]; isSynthetic: boolean };
|
|
@@ -57,16 +38,11 @@ interface AggregatorState {
|
|
|
57
38
|
billing?: BillingInfo;
|
|
58
39
|
auxiliary: AuxiliaryInfo;
|
|
59
40
|
warnings: string[];
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/** 已完成 item 的 id 列表,保持输出顺序 */
|
|
66
|
-
outputOrder: string[];
|
|
67
|
-
completedMessages: Map<string, MessageItem>;
|
|
68
|
-
completedReasonings: Map<string, ReasoningItem>;
|
|
69
|
-
completedToolCalls: Map<string, ToolCallItem>;
|
|
41
|
+
warningSet: Set<string>;
|
|
42
|
+
output: OutputItem[];
|
|
43
|
+
textParts: string[];
|
|
44
|
+
toolCalls: ToolCallItem[];
|
|
45
|
+
lastEventType?: AIStreamEvent["type"];
|
|
70
46
|
|
|
71
47
|
/** adapter 在 response.completed 中提供的 replay */
|
|
72
48
|
replayFromAdapter?: import("../types/index.js").ReplayItem[];
|
|
@@ -75,17 +51,14 @@ interface AggregatorState {
|
|
|
75
51
|
backendFromAdapter?: BackendTrace;
|
|
76
52
|
}
|
|
77
53
|
|
|
78
|
-
function
|
|
54
|
+
export function createAggregatorState(): AggregatorState {
|
|
79
55
|
return {
|
|
80
|
-
pendingMessages: new Map(),
|
|
81
|
-
pendingReasonings: new Map(),
|
|
82
|
-
pendingToolCalls: new Map(),
|
|
83
|
-
outputOrder: [],
|
|
84
|
-
completedMessages: new Map(),
|
|
85
|
-
completedReasonings: new Map(),
|
|
86
|
-
completedToolCalls: new Map(),
|
|
87
56
|
auxiliary: {},
|
|
88
57
|
warnings: [],
|
|
58
|
+
warningSet: new Set(),
|
|
59
|
+
output: [],
|
|
60
|
+
textParts: [],
|
|
61
|
+
toolCalls: [],
|
|
89
62
|
};
|
|
90
63
|
}
|
|
91
64
|
|
|
@@ -113,72 +86,21 @@ function handleResponseAuxiliary(state: AggregatorState, event: AIStreamEvent &
|
|
|
113
86
|
}
|
|
114
87
|
}
|
|
115
88
|
|
|
116
|
-
function handleMessageStarted(state: AggregatorState, event: AIStreamEvent & { type: "message.started" }): void {
|
|
117
|
-
state.pendingMessages.set(event.item.id, {
|
|
118
|
-
role: event.item.role,
|
|
119
|
-
texts: [],
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function handleMessageDelta(state: AggregatorState, event: AIStreamEvent & { type: "message.delta" }): void {
|
|
124
|
-
const pending = state.pendingMessages.get(event.itemId);
|
|
125
|
-
if (pending) {
|
|
126
|
-
pending.texts.push(event.delta.text);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
89
|
function handleMessageCompleted(state: AggregatorState, event: AIStreamEvent & { type: "message.completed" }): void {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
state.completedMessages.set(itemId, item);
|
|
134
|
-
state.outputOrder.push(itemId);
|
|
135
|
-
state.pendingMessages.delete(itemId);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function handleReasoningStarted(state: AggregatorState, event: AIStreamEvent & { type: "reasoning.started" }): void {
|
|
139
|
-
state.pendingReasonings.set(event.item.id, {
|
|
140
|
-
visibility: event.item.visibility,
|
|
141
|
-
blocks: [],
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function handleReasoningDelta(state: AggregatorState, event: AIStreamEvent & { type: "reasoning.delta" }): void {
|
|
146
|
-
const pending = state.pendingReasonings.get(event.itemId);
|
|
147
|
-
if (pending) {
|
|
148
|
-
pending.blocks.push(event.delta);
|
|
149
|
-
}
|
|
90
|
+
state.output.push(event.item);
|
|
91
|
+
pushMessageText(state, event.item);
|
|
150
92
|
}
|
|
151
93
|
|
|
152
94
|
function handleReasoningCompleted(
|
|
153
95
|
state: AggregatorState,
|
|
154
96
|
event: AIStreamEvent & { type: "reasoning.completed" },
|
|
155
97
|
): void {
|
|
156
|
-
|
|
157
|
-
const stableId = item.id ?? `reason-${state.outputOrder.length}-${Date.now()}`;
|
|
158
|
-
state.completedReasonings.set(stableId, item);
|
|
159
|
-
state.outputOrder.push(stableId);
|
|
160
|
-
state.pendingReasonings.delete(item.id ?? "");
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function handleToolCallStarted(state: AggregatorState, event: AIStreamEvent & { type: "tool_call.started" }): void {
|
|
164
|
-
state.pendingToolCalls.set(event.item.id, {
|
|
165
|
-
name: event.item.name,
|
|
166
|
-
argsParts: [],
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function handleToolCallDelta(state: AggregatorState, event: AIStreamEvent & { type: "tool_call.delta" }): void {
|
|
171
|
-
const pending = state.pendingToolCalls.get(event.itemId);
|
|
172
|
-
if (pending && event.delta.argumentsText) {
|
|
173
|
-
pending.argsParts.push(event.delta.argumentsText);
|
|
174
|
-
}
|
|
98
|
+
state.output.push(event.item);
|
|
175
99
|
}
|
|
176
100
|
|
|
177
101
|
function handleToolCallCompleted(state: AggregatorState, event: AIStreamEvent & { type: "tool_call.completed" }): void {
|
|
178
|
-
|
|
179
|
-
state.
|
|
180
|
-
state.outputOrder.push(item.id);
|
|
181
|
-
state.pendingToolCalls.delete(item.id);
|
|
102
|
+
state.output.push(event.item);
|
|
103
|
+
state.toolCalls.push(event.item);
|
|
182
104
|
}
|
|
183
105
|
|
|
184
106
|
function handleResponseCompleted(state: AggregatorState, event: AIStreamEvent & { type: "response.completed" }): void {
|
|
@@ -205,37 +127,6 @@ function handleResponseCompleted(state: AggregatorState, event: AIStreamEvent &
|
|
|
205
127
|
// ── 从聚合状态构建最终 AIResponse ─────────────────────────────
|
|
206
128
|
|
|
207
129
|
function buildResponse(state: AggregatorState): AIResponse {
|
|
208
|
-
// 按 outputOrder 组装 output
|
|
209
|
-
const output: OutputItem[] = [];
|
|
210
|
-
for (const id of state.outputOrder) {
|
|
211
|
-
const msg = state.completedMessages.get(id);
|
|
212
|
-
if (msg) {
|
|
213
|
-
output.push(msg);
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
const reason = state.completedReasonings.get(id);
|
|
217
|
-
if (reason) {
|
|
218
|
-
output.push(reason);
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
const tc = state.completedToolCalls.get(id);
|
|
222
|
-
if (tc) {
|
|
223
|
-
output.push(tc);
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// 汇总 text
|
|
229
|
-
const text = output
|
|
230
|
-
.filter((item): item is MessageItem => item.type === "message")
|
|
231
|
-
.flatMap((m) => m.content)
|
|
232
|
-
.filter((b): b is ContentBlock & { type: "text" } => b.type === "text")
|
|
233
|
-
.map((b) => b.text)
|
|
234
|
-
.join("");
|
|
235
|
-
|
|
236
|
-
// toolCalls
|
|
237
|
-
const toolCalls = output.filter((item): item is ToolCallItem => item.type === "tool_call");
|
|
238
|
-
|
|
239
130
|
// 合并 backend trace
|
|
240
131
|
const backendFromResponse = state.backendFromAdapter;
|
|
241
132
|
const backend: BackendTrace = {
|
|
@@ -249,10 +140,10 @@ function buildResponse(state: AggregatorState): AIResponse {
|
|
|
249
140
|
|
|
250
141
|
return {
|
|
251
142
|
id: state.responseIdFromAdapter ?? state.responseId,
|
|
252
|
-
output,
|
|
143
|
+
output: state.output,
|
|
253
144
|
replay: state.replayFromAdapter ?? [],
|
|
254
|
-
text,
|
|
255
|
-
toolCalls,
|
|
145
|
+
text: state.textParts.join(""),
|
|
146
|
+
toolCalls: state.toolCalls,
|
|
256
147
|
stopReason: state.stopReasonFromAdapter,
|
|
257
148
|
usage: state.usage,
|
|
258
149
|
billing: state.billing,
|
|
@@ -269,55 +160,50 @@ function buildResponse(state: AggregatorState): AIResponse {
|
|
|
269
160
|
* 适用于测试和离线处理场景。
|
|
270
161
|
*/
|
|
271
162
|
export function aggregateEvents(events: AIStreamEvent[]): AIResponse {
|
|
272
|
-
const state =
|
|
273
|
-
|
|
163
|
+
const state = createAggregatorState();
|
|
274
164
|
for (const event of events) {
|
|
275
|
-
|
|
276
|
-
case "response.started":
|
|
277
|
-
handleResponseStarted(state, event);
|
|
278
|
-
break;
|
|
279
|
-
case "response.warning":
|
|
280
|
-
handleResponseWarning(state, event);
|
|
281
|
-
break;
|
|
282
|
-
case "response.auxiliary":
|
|
283
|
-
handleResponseAuxiliary(state, event);
|
|
284
|
-
break;
|
|
285
|
-
case "message.started":
|
|
286
|
-
handleMessageStarted(state, event);
|
|
287
|
-
break;
|
|
288
|
-
case "message.delta":
|
|
289
|
-
handleMessageDelta(state, event);
|
|
290
|
-
break;
|
|
291
|
-
case "message.completed":
|
|
292
|
-
handleMessageCompleted(state, event);
|
|
293
|
-
break;
|
|
294
|
-
case "reasoning.started":
|
|
295
|
-
handleReasoningStarted(state, event);
|
|
296
|
-
break;
|
|
297
|
-
case "reasoning.delta":
|
|
298
|
-
handleReasoningDelta(state, event);
|
|
299
|
-
break;
|
|
300
|
-
case "reasoning.completed":
|
|
301
|
-
handleReasoningCompleted(state, event);
|
|
302
|
-
break;
|
|
303
|
-
case "tool_call.started":
|
|
304
|
-
handleToolCallStarted(state, event);
|
|
305
|
-
break;
|
|
306
|
-
case "tool_call.delta":
|
|
307
|
-
handleToolCallDelta(state, event);
|
|
308
|
-
break;
|
|
309
|
-
case "tool_call.completed":
|
|
310
|
-
handleToolCallCompleted(state, event);
|
|
311
|
-
break;
|
|
312
|
-
case "response.completed":
|
|
313
|
-
handleResponseCompleted(state, event);
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
165
|
+
aggregateEvent(state, event);
|
|
316
166
|
}
|
|
167
|
+
return finalizeAggregation(state);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function aggregateEvent(state: AggregatorState, event: AIStreamEvent): void {
|
|
171
|
+
state.lastEventType = event.type;
|
|
172
|
+
|
|
173
|
+
switch (event.type) {
|
|
174
|
+
case "response.started":
|
|
175
|
+
handleResponseStarted(state, event);
|
|
176
|
+
break;
|
|
177
|
+
case "response.warning":
|
|
178
|
+
handleResponseWarning(state, event);
|
|
179
|
+
break;
|
|
180
|
+
case "response.auxiliary":
|
|
181
|
+
handleResponseAuxiliary(state, event);
|
|
182
|
+
break;
|
|
183
|
+
case "message.started":
|
|
184
|
+
case "message.delta":
|
|
185
|
+
case "reasoning.started":
|
|
186
|
+
case "reasoning.delta":
|
|
187
|
+
case "tool_call.started":
|
|
188
|
+
case "tool_call.delta":
|
|
189
|
+
break;
|
|
190
|
+
case "message.completed":
|
|
191
|
+
handleMessageCompleted(state, event);
|
|
192
|
+
break;
|
|
193
|
+
case "reasoning.completed":
|
|
194
|
+
handleReasoningCompleted(state, event);
|
|
195
|
+
break;
|
|
196
|
+
case "tool_call.completed":
|
|
197
|
+
handleToolCallCompleted(state, event);
|
|
198
|
+
break;
|
|
199
|
+
case "response.completed":
|
|
200
|
+
handleResponseCompleted(state, event);
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
317
204
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (!lastEvent || lastEvent.type !== "response.completed") {
|
|
205
|
+
export function finalizeAggregation(state: AggregatorState): AIResponse {
|
|
206
|
+
if (state.lastEventType !== "response.completed") {
|
|
321
207
|
throw new Error("Stream must end with response.completed event to produce a valid AIResponse");
|
|
322
208
|
}
|
|
323
209
|
|
|
@@ -332,8 +218,8 @@ function mergeAuxiliary(base: AuxiliaryInfo, patch: Partial<AuxiliaryInfo>): Aux
|
|
|
332
218
|
|
|
333
219
|
if (base.providerMetadata || patch.providerMetadata) {
|
|
334
220
|
merged.providerMetadata = {
|
|
335
|
-
...
|
|
336
|
-
...
|
|
221
|
+
...base.providerMetadata,
|
|
222
|
+
...patch.providerMetadata,
|
|
337
223
|
};
|
|
338
224
|
}
|
|
339
225
|
|
|
@@ -342,8 +228,17 @@ function mergeAuxiliary(base: AuxiliaryInfo, patch: Partial<AuxiliaryInfo>): Aux
|
|
|
342
228
|
|
|
343
229
|
function pushWarnings(state: AggregatorState, warnings: readonly string[]): void {
|
|
344
230
|
for (const warning of warnings) {
|
|
345
|
-
if (!state.
|
|
231
|
+
if (!state.warningSet.has(warning)) {
|
|
232
|
+
state.warningSet.add(warning);
|
|
346
233
|
state.warnings.push(warning);
|
|
347
234
|
}
|
|
348
235
|
}
|
|
349
236
|
}
|
|
237
|
+
|
|
238
|
+
function pushMessageText(state: AggregatorState, item: MessageItem): void {
|
|
239
|
+
for (const block of item.content) {
|
|
240
|
+
if (block.type === "text") {
|
|
241
|
+
state.textParts.push(block.text);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { AIStreamEvent, AIResponse } from "../types/index.js";
|
|
9
|
-
import {
|
|
9
|
+
import { aggregateEvent, createAggregatorState, finalizeAggregation } from "./aggregator.js";
|
|
10
10
|
|
|
11
11
|
export async function collectStream(stream: AsyncIterable<AIStreamEvent>): Promise<AIResponse> {
|
|
12
|
-
const
|
|
12
|
+
const state = createAggregatorState();
|
|
13
13
|
|
|
14
14
|
for await (const event of stream) {
|
|
15
|
-
|
|
15
|
+
aggregateEvent(state, event);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return
|
|
18
|
+
return finalizeAggregation(state);
|
|
19
19
|
}
|
|
@@ -30,7 +30,7 @@ import type {
|
|
|
30
30
|
} from "../types/index.js";
|
|
31
31
|
|
|
32
32
|
export type EventFactoryBackend = {
|
|
33
|
-
kind: "chat-completions" | "messages" | "responses" | "ollama";
|
|
33
|
+
kind: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
34
34
|
isSynthetic: boolean;
|
|
35
35
|
};
|
|
36
36
|
|
|
@@ -55,7 +55,7 @@ export type StreamResult = {
|
|
|
55
55
|
// ── 抽象基类 ──────────────────────────────────────────────────
|
|
56
56
|
|
|
57
57
|
export abstract class AdapterBase implements BackendAdapter {
|
|
58
|
-
abstract readonly kind: "chat-completions" | "messages" | "responses" | "ollama";
|
|
58
|
+
abstract readonly kind: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
59
59
|
abstract readonly capabilities: AdapterCapabilities;
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -154,14 +154,14 @@ function mergeAuxiliary(
|
|
|
154
154
|
if (!base && !patch) return undefined;
|
|
155
155
|
|
|
156
156
|
const merged: AuxiliaryInfo = {
|
|
157
|
-
...
|
|
158
|
-
...
|
|
157
|
+
...base,
|
|
158
|
+
...patch,
|
|
159
159
|
};
|
|
160
160
|
|
|
161
161
|
if (base?.providerMetadata || patch?.providerMetadata) {
|
|
162
162
|
merged.providerMetadata = {
|
|
163
|
-
...
|
|
164
|
-
...
|
|
163
|
+
...base?.providerMetadata,
|
|
164
|
+
...patch?.providerMetadata,
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
|
|
@@ -35,7 +35,7 @@ export type SyntheticStreamOptions = {
|
|
|
35
35
|
model: string;
|
|
36
36
|
responseId: string;
|
|
37
37
|
backend: {
|
|
38
|
-
kind: "chat-completions" | "messages" | "responses";
|
|
38
|
+
kind: "chat-completions" | "messages" | "responses" | "mock";
|
|
39
39
|
/** syntheticStream 强制设为 true */
|
|
40
40
|
};
|
|
41
41
|
output: OutputItem[];
|
package/src/types/adapter.ts
CHANGED
|
@@ -86,12 +86,24 @@ export const CAPABILITY_MATRIX = {
|
|
|
86
86
|
billing: "none" as const,
|
|
87
87
|
providerMetadata: false,
|
|
88
88
|
},
|
|
89
|
+
mock: {
|
|
90
|
+
nativeStreaming: false,
|
|
91
|
+
messageStreaming: true,
|
|
92
|
+
reasoningStreaming: false,
|
|
93
|
+
toolCallStreaming: true,
|
|
94
|
+
hiddenReasoningReplay: "none" as const,
|
|
95
|
+
replayFidelity: "high" as const,
|
|
96
|
+
tools: true,
|
|
97
|
+
usage: "none" as const,
|
|
98
|
+
billing: "none" as const,
|
|
99
|
+
providerMetadata: true,
|
|
100
|
+
},
|
|
89
101
|
} as const satisfies Record<string, AdapterCapabilities>;
|
|
90
102
|
|
|
91
103
|
// ── Adapter 接口 ──────────────────────────────────────────────
|
|
92
104
|
|
|
93
105
|
export interface BackendAdapter {
|
|
94
|
-
readonly kind: "chat-completions" | "messages" | "responses" | "ollama";
|
|
106
|
+
readonly kind: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
95
107
|
readonly capabilities: AdapterCapabilities;
|
|
96
108
|
stream(request: NormalizedRequest): AsyncIterable<AIStreamEvent>;
|
|
97
109
|
}
|
package/src/types/events.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type StreamEventBase = {
|
|
|
18
18
|
sequence: number;
|
|
19
19
|
timestamp: string;
|
|
20
20
|
backend: {
|
|
21
|
-
kind: "chat-completions" | "messages" | "responses" | "ollama";
|
|
21
|
+
kind: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
22
22
|
isSynthetic: boolean;
|
|
23
23
|
};
|
|
24
24
|
};
|
package/src/types/response.ts
CHANGED
|
@@ -42,7 +42,7 @@ export type AuxiliaryInfo = {
|
|
|
42
42
|
export type BackendTrace = {
|
|
43
43
|
requestId?: string;
|
|
44
44
|
rawResponseId?: string;
|
|
45
|
-
adapter: "chat-completions" | "messages" | "responses" | "ollama";
|
|
45
|
+
adapter: "chat-completions" | "messages" | "responses" | "ollama" | "mock";
|
|
46
46
|
isSyntheticStream: boolean;
|
|
47
47
|
metadataSources?: string[];
|
|
48
48
|
warnings?: string[];
|