@codehz/ai 0.1.2 → 0.1.4

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/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ai",
3
+ "version": "0.1.4",
3
4
  "type": "module",
4
5
  "module": "dist/index.mjs",
5
6
  "exports": {
@@ -26,6 +27,5 @@
26
27
  "oxlint": "^1.73.0",
27
28
  "tsdown": "^0.22.3",
28
29
  "typescript": "^6"
29
- },
30
- "version": "0.1.2"
30
+ }
31
31
  }
@@ -22,7 +22,7 @@ import {
22
22
  } from "../helpers/mapping.js";
23
23
  import { emitMalformedStreamWarning } from "../helpers/adapter-auxiliary.js";
24
24
 
25
- import type { AdapterCapabilities, NormalizedRequest, AIStreamEvent, EventFactory, OutputItem, FetchFn } from "../index.js";
25
+ import type { NormalizedRequest, AIStreamEvent, EventFactory, OutputItem, FetchFn } from "../index.js";
26
26
 
27
27
  // ── 类型 ──────────────────────────────────────────────────────
28
28
 
@@ -249,29 +249,12 @@ function buildAssistantReplayMessage(params: {
249
249
 
250
250
  export class ChatCompletionsAdapter extends AdapterBase {
251
251
  readonly kind = "chat-completions" as const;
252
- readonly capabilities: AdapterCapabilities = {
253
- nativeStreaming: true,
254
- messageStreaming: true,
255
- reasoningStreaming: false,
256
- toolCallStreaming: false,
257
- hiddenReasoningReplay: "none" as const,
258
- replayFidelity: "low" as const,
259
- tools: true,
260
- usage: "full" as const,
261
- billing: "derived" as const,
262
- providerMetadata: false,
263
- };
252
+ readonly nativeStreaming = true;
264
253
 
265
254
  private apiKey: string;
266
255
  private baseUrl: string;
267
256
  private fetchFn: FetchFn;
268
257
 
269
- private markReasoningCompatibility(): void {
270
- this.capabilities.reasoningStreaming = true;
271
- this.capabilities.hiddenReasoningReplay = "partial";
272
- this.capabilities.replayFidelity = "medium";
273
- }
274
-
275
258
  constructor(options: ChatCompletionsAdapterOptions) {
276
259
  super();
277
260
  this.apiKey = options.apiKey;
@@ -300,7 +283,7 @@ export class ChatCompletionsAdapter extends AdapterBase {
300
283
  item.role === "developer"
301
284
  ? "system"
302
285
  : item.role === "system"
303
- ? "system"
286
+ ? "system"
304
287
  : item.role === "user"
305
288
  ? "user"
306
289
  : "assistant";
@@ -310,9 +293,10 @@ export class ChatCompletionsAdapter extends AdapterBase {
310
293
  }
311
294
  case "tool_call": {
312
295
  // 只允许附着到尾部 assistant turn,否则新建一个
313
- const lastAssistant = messages.length > 0 && messages[messages.length - 1]?.role === "assistant"
314
- ? messages[messages.length - 1]
315
- : null;
296
+ const lastAssistant =
297
+ messages.length > 0 && messages[messages.length - 1]?.role === "assistant"
298
+ ? messages[messages.length - 1]
299
+ : null;
316
300
  const tc: ChatToolCall = {
317
301
  id: item.id,
318
302
  type: "function",
@@ -439,7 +423,6 @@ export class ChatCompletionsAdapter extends AdapterBase {
439
423
  let currentReasoningId = "";
440
424
  let hasMessageStarted = false;
441
425
  let hasReasoningStarted = false;
442
- let hasStreamedReasoning = false;
443
426
 
444
427
  // tool_calls 累积: tool call index → { id, name, args }
445
428
  const pendingToolCalls = new Map<number, PendingToolCall>();
@@ -540,7 +523,6 @@ export class ChatCompletionsAdapter extends AdapterBase {
540
523
  if (!hasReasoningStarted) {
541
524
  currentReasoningId = `reason-${chunk.id}`;
542
525
  hasReasoningStarted = true;
543
- hasStreamedReasoning = true;
544
526
  accumulatedReasoning = "";
545
527
  yield factory.reasoningStarted(currentReasoningId, "full");
546
528
  }
@@ -609,8 +591,6 @@ export class ChatCompletionsAdapter extends AdapterBase {
609
591
  yield event;
610
592
  }
611
593
 
612
- if (hasStreamedReasoning) this.markReasoningCompatibility();
613
-
614
594
  // 构建 stop reason
615
595
  const stopReason = mapStopReason(finishReason);
616
596
 
@@ -665,8 +645,6 @@ export class ChatCompletionsAdapter extends AdapterBase {
665
645
  if (hasMessageStarted || hasReasoningStarted || pendingToolCalls.size > 0) {
666
646
  yield factory.responseWarning("Stream ended without a finish_reason", "INCOMPLETE_STREAM");
667
647
 
668
- if (hasStreamedReasoning) this.markReasoningCompatibility();
669
-
670
648
  const { events, assistantReplayMessage } = finalizePendingTurn();
671
649
  for (const event of events) {
672
650
  yield event;
@@ -22,10 +22,13 @@ export type { OllamaAdapterOptions } from "./ollama.js";
22
22
  export { MockAdapter } from "./mock.js";
23
23
  export type {
24
24
  MockAdapterOptions,
25
+ MockHistoryRecord,
26
+ MockTextStreamOptions,
25
27
  MockInputExpectation,
26
28
  MockRequestExpectation,
27
- MockTurnContext,
28
- MockTurnValidator,
29
+ MockHandlerContext,
30
+ MockHandler,
31
+ MockStaticHandler,
29
32
  MockWarningStep,
30
33
  MockAuxiliaryStep,
31
34
  MockMessageStep,
@@ -37,5 +40,5 @@ export type {
37
40
  MockInterruptStep,
38
41
  MockThrowStep,
39
42
  MockStep,
40
- MockTurn,
41
43
  } from "./mock.js";
44
+ export { assertMockRequest, withMockStreaming } from "./mock.js";
@@ -27,7 +27,6 @@ import { emitMalformedStreamWarning } from "../helpers/adapter-auxiliary.js";
27
27
 
28
28
  import { parseSSEEvents } from "../helpers/sse-parser.js";
29
29
 
30
- import { CAPABILITY_MATRIX } from "../index.js";
31
30
  import type { NormalizedRequest, AIStreamEvent, EventFactory, OutputItem, FetchFn } from "../index.js";
32
31
 
33
32
  // ── 类型 ──────────────────────────────────────────────────────
@@ -237,7 +236,7 @@ function buildStreamMetadata(options: {
237
236
 
238
237
  export class MessagesAdapter extends AdapterBase {
239
238
  readonly kind = "messages" as const;
240
- readonly capabilities = CAPABILITY_MATRIX.messages;
239
+ readonly nativeStreaming = true;
241
240
 
242
241
  private apiKey: string;
243
242
  private apiVersion: string;
@@ -276,7 +275,9 @@ export class MessagesAdapter extends AdapterBase {
276
275
  if (item.role === "system" || item.role === "developer") {
277
276
  // Anthropic 不支持 system/developer role 在 messages 中
278
277
  // 合并到 system prompt
279
- const text = contentBlocksToText(ensureMessagesTextBlocks(item.content, `input message (${item.role}) content`));
278
+ const text = contentBlocksToText(
279
+ ensureMessagesTextBlocks(item.content, `input message (${item.role}) content`),
280
+ );
280
281
  systemPrompt = systemPrompt ? `${systemPrompt}\n${text}` : text;
281
282
  break;
282
283
  }
@@ -297,9 +298,7 @@ export class MessagesAdapter extends AdapterBase {
297
298
  type: "tool_use",
298
299
  id: item.id,
299
300
  name: item.name,
300
- input:
301
- (item.argumentsJson as Record<string, unknown> | undefined) ??
302
- parseToolUseInput(item.argumentsText),
301
+ input: (item.argumentsJson as Record<string, unknown> | undefined) ?? parseToolUseInput(item.argumentsText),
303
302
  };
304
303
 
305
304
  if (lastMsg && lastMsg.role === "assistant" && typeof lastMsg.content !== "string") {
@@ -346,7 +345,11 @@ export class MessagesAdapter extends AdapterBase {
346
345
  typeof b === "object" &&
347
346
  b !== null &&
348
347
  "type" in b &&
349
- (b.type === "text" || b.type === "thinking" || b.type === "redacted_thinking" || b.type === "tool_use" || b.type === "tool_result"),
348
+ (b.type === "text" ||
349
+ b.type === "thinking" ||
350
+ b.type === "redacted_thinking" ||
351
+ b.type === "tool_use" ||
352
+ b.type === "tool_result"),
350
353
  );
351
354
  if (isValidContent) {
352
355
  rollbackTrailingAssistantMessages(messages);
@@ -405,7 +408,10 @@ export class MessagesAdapter extends AdapterBase {
405
408
  const auxiliary = this.createAuxiliaryState(request);
406
409
 
407
410
  if (request.metadata) {
408
- yield factory.responseWarning("Request metadata is not supported by the Messages adapter", "UNSUPPORTED_METADATA");
411
+ yield factory.responseWarning(
412
+ "Request metadata is not supported by the Messages adapter",
413
+ "UNSUPPORTED_METADATA",
414
+ );
409
415
  }
410
416
 
411
417
  const response = await this.fetchFn(`${this.baseUrl}/messages`, {
@@ -454,7 +460,10 @@ export class MessagesAdapter extends AdapterBase {
454
460
 
455
461
  if (request.include?.providerMetadata !== "off") {
456
462
  const headerMetadata = pickProviderHeaders(response.headers);
457
- auxiliary.recordProviderMetadata("header", Object.keys(headerMetadata).length > 0 ? { headers: headerMetadata } : undefined);
463
+ auxiliary.recordProviderMetadata(
464
+ "header",
465
+ Object.keys(headerMetadata).length > 0 ? { headers: headerMetadata } : undefined,
466
+ );
458
467
  }
459
468
 
460
469
  try {
@@ -614,9 +623,9 @@ export class MessagesAdapter extends AdapterBase {
614
623
  if (u) {
615
624
  auxiliary.recordUsage(
616
625
  {
617
- inputTokens: u.input_tokens,
618
- outputTokens: u.output_tokens,
619
- totalTokens: u.input_tokens + u.output_tokens,
626
+ inputTokens: u.input_tokens,
627
+ outputTokens: u.output_tokens,
628
+ totalTokens: u.input_tokens + u.output_tokens,
620
629
  },
621
630
  "stream",
622
631
  u,