@codehz/ai 0.1.2 → 0.1.3

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/dist/index.mjs CHANGED
@@ -1,67 +1,3 @@
1
- //#region src/types/adapter.ts
2
- const CAPABILITY_MATRIX = {
3
- responses: {
4
- nativeStreaming: true,
5
- messageStreaming: true,
6
- reasoningStreaming: true,
7
- toolCallStreaming: true,
8
- hiddenReasoningReplay: "full",
9
- replayFidelity: "high",
10
- tools: true,
11
- usage: "full",
12
- billing: "lookup",
13
- providerMetadata: true
14
- },
15
- messages: {
16
- nativeStreaming: true,
17
- messageStreaming: true,
18
- reasoningStreaming: false,
19
- toolCallStreaming: true,
20
- hiddenReasoningReplay: "partial",
21
- replayFidelity: "medium",
22
- tools: true,
23
- usage: "full",
24
- billing: "lookup",
25
- providerMetadata: true
26
- },
27
- "chat.completions": {
28
- nativeStreaming: true,
29
- messageStreaming: true,
30
- reasoningStreaming: false,
31
- toolCallStreaming: false,
32
- hiddenReasoningReplay: "none",
33
- replayFidelity: "low",
34
- tools: true,
35
- usage: "full",
36
- billing: "derived",
37
- providerMetadata: false
38
- },
39
- ollama: {
40
- nativeStreaming: true,
41
- messageStreaming: true,
42
- reasoningStreaming: false,
43
- toolCallStreaming: false,
44
- hiddenReasoningReplay: "none",
45
- replayFidelity: "low",
46
- tools: true,
47
- usage: "partial",
48
- billing: "none",
49
- providerMetadata: false
50
- },
51
- mock: {
52
- nativeStreaming: false,
53
- messageStreaming: true,
54
- reasoningStreaming: false,
55
- toolCallStreaming: true,
56
- hiddenReasoningReplay: "none",
57
- replayFidelity: "high",
58
- tools: true,
59
- usage: "none",
60
- billing: "none",
61
- providerMetadata: true
62
- }
63
- };
64
- //#endregion
65
1
  //#region src/core/errors.ts
66
2
  var AIError = class extends Error {
67
3
  code;
@@ -901,12 +837,10 @@ function withTimeout(promise, ms) {
901
837
  //#region src/helpers/adapter-auxiliary.ts
902
838
  var AdapterAuxiliaryState = class {
903
839
  request;
904
- capabilities;
905
840
  collector = new AuxiliaryCollector();
906
841
  metadataSources = /* @__PURE__ */ new Set();
907
- constructor(request, capabilities) {
842
+ constructor(request) {
908
843
  this.request = request;
909
- this.capabilities = capabilities;
910
844
  }
911
845
  recordUsage(usage, source, raw) {
912
846
  if (this.request.include?.usage === "off" || isEmptyRecord(usage)) return;
@@ -930,8 +864,7 @@ var AdapterAuxiliaryState = class {
930
864
  request: this.request,
931
865
  usage: snapshot.usage,
932
866
  billing: snapshot.billing,
933
- auxiliary: snapshot.auxiliary,
934
- capabilities: this.capabilities
867
+ auxiliary: snapshot.auxiliary
935
868
  });
936
869
  if (derived && !isEmptyRecord(derived)) this.collector.recordBilling({
937
870
  ...derived,
@@ -996,7 +929,7 @@ var AdapterBase = class {
996
929
  responseId: request.requestId,
997
930
  backend: {
998
931
  kind: this.kind,
999
- isSynthetic: !this.capabilities.nativeStreaming
932
+ isSynthetic: !this.nativeStreaming
1000
933
  }
1001
934
  });
1002
935
  yield factory.responseStarted(request.model);
@@ -1035,7 +968,7 @@ var AdapterBase = class {
1035
968
  requestId: request.requestId,
1036
969
  rawResponseId: result.rawResponseId,
1037
970
  adapter: this.kind,
1038
- isSyntheticStream: !this.capabilities.nativeStreaming,
971
+ isSyntheticStream: !this.nativeStreaming,
1039
972
  metadataSources: result.metadataSources,
1040
973
  warnings
1041
974
  }
@@ -1046,7 +979,7 @@ var AdapterBase = class {
1046
979
  return extractText(output);
1047
980
  }
1048
981
  createAuxiliaryState(request) {
1049
- return new AdapterAuxiliaryState(request, this.capabilities);
982
+ return new AdapterAuxiliaryState(request);
1050
983
  }
1051
984
  };
1052
985
  function mergeAuxiliary(base, patch) {
@@ -1187,7 +1120,7 @@ function canonicalToResponsesBlock(b) {
1187
1120
  }
1188
1121
  var ResponsesAdapter = class extends AdapterBase {
1189
1122
  kind = "responses";
1190
- capabilities = CAPABILITY_MATRIX.responses;
1123
+ nativeStreaming = true;
1191
1124
  apiKey;
1192
1125
  baseUrl;
1193
1126
  fetchFn;
@@ -1491,7 +1424,7 @@ function buildStreamMetadata(options) {
1491
1424
  }
1492
1425
  var MessagesAdapter = class extends AdapterBase {
1493
1426
  kind = "messages";
1494
- capabilities = CAPABILITY_MATRIX.messages;
1427
+ nativeStreaming = true;
1495
1428
  apiKey;
1496
1429
  apiVersion;
1497
1430
  baseUrl;
@@ -1945,26 +1878,10 @@ function buildAssistantReplayMessage(params) {
1945
1878
  }
1946
1879
  var ChatCompletionsAdapter = class extends AdapterBase {
1947
1880
  kind = "chat-completions";
1948
- capabilities = {
1949
- nativeStreaming: true,
1950
- messageStreaming: true,
1951
- reasoningStreaming: false,
1952
- toolCallStreaming: false,
1953
- hiddenReasoningReplay: "none",
1954
- replayFidelity: "low",
1955
- tools: true,
1956
- usage: "full",
1957
- billing: "derived",
1958
- providerMetadata: false
1959
- };
1881
+ nativeStreaming = true;
1960
1882
  apiKey;
1961
1883
  baseUrl;
1962
1884
  fetchFn;
1963
- markReasoningCompatibility() {
1964
- this.capabilities.reasoningStreaming = true;
1965
- this.capabilities.hiddenReasoningReplay = "partial";
1966
- this.capabilities.replayFidelity = "medium";
1967
- }
1968
1885
  constructor(options) {
1969
1886
  super();
1970
1887
  this.apiKey = options.apiKey;
@@ -2089,7 +2006,6 @@ var ChatCompletionsAdapter = class extends AdapterBase {
2089
2006
  let currentReasoningId = "";
2090
2007
  let hasMessageStarted = false;
2091
2008
  let hasReasoningStarted = false;
2092
- let hasStreamedReasoning = false;
2093
2009
  const pendingToolCalls = /* @__PURE__ */ new Map();
2094
2010
  const reasoningByField = /* @__PURE__ */ new Map();
2095
2011
  const finalizePendingTurn = () => {
@@ -2164,7 +2080,6 @@ var ChatCompletionsAdapter = class extends AdapterBase {
2164
2080
  if (!hasReasoningStarted) {
2165
2081
  currentReasoningId = `reason-${chunk.id}`;
2166
2082
  hasReasoningStarted = true;
2167
- hasStreamedReasoning = true;
2168
2083
  accumulatedReasoning = "";
2169
2084
  yield factory.reasoningStarted(currentReasoningId, "full");
2170
2085
  }
@@ -2222,7 +2137,6 @@ var ChatCompletionsAdapter = class extends AdapterBase {
2222
2137
  if (finishReason && finishReason !== null) {
2223
2138
  const { events, assistantReplayMessage } = finalizePendingTurn();
2224
2139
  for (const event of events) yield event;
2225
- if (hasStreamedReasoning) this.markReasoningCompatibility();
2226
2140
  const stopReason = mapStopReason(finishReason);
2227
2141
  const replay = [...replayFromOutput(output)];
2228
2142
  if (assistantReplayMessage) replay.push(opaqueItem("chat.completions", "replay", {
@@ -2252,7 +2166,6 @@ var ChatCompletionsAdapter = class extends AdapterBase {
2252
2166
  if (buffer.trim().length > 0) yield factory.responseWarning("Stream ended with an incomplete Chat Completions SSE frame", "STREAM_ERROR");
2253
2167
  if (hasMessageStarted || hasReasoningStarted || pendingToolCalls.size > 0) {
2254
2168
  yield factory.responseWarning("Stream ended without a finish_reason", "INCOMPLETE_STREAM");
2255
- if (hasStreamedReasoning) this.markReasoningCompatibility();
2256
2169
  const { events, assistantReplayMessage } = finalizePendingTurn();
2257
2170
  for (const event of events) yield event;
2258
2171
  const replay = [...replayFromOutput(output)];
@@ -2357,18 +2270,7 @@ function isOllamaToolCalls(value) {
2357
2270
  }
2358
2271
  var OllamaAdapter = class extends AdapterBase {
2359
2272
  kind = "ollama";
2360
- capabilities = {
2361
- nativeStreaming: true,
2362
- messageStreaming: true,
2363
- reasoningStreaming: false,
2364
- toolCallStreaming: false,
2365
- hiddenReasoningReplay: "none",
2366
- replayFidelity: "low",
2367
- tools: true,
2368
- usage: "partial",
2369
- billing: "none",
2370
- providerMetadata: false
2371
- };
2273
+ nativeStreaming = true;
2372
2274
  baseUrl;
2373
2275
  apiKey;
2374
2276
  fetchFn;
@@ -2618,10 +2520,11 @@ var OllamaAdapter = class extends AdapterBase {
2618
2520
  */
2619
2521
  var MockAdapter = class extends AdapterBase {
2620
2522
  kind = "mock";
2621
- capabilities = CAPABILITY_MATRIX.mock;
2523
+ nativeStreaming = false;
2622
2524
  turns;
2623
2525
  onExhausted;
2624
2526
  providerMetadata;
2527
+ defaultStream;
2625
2528
  cursor = 0;
2626
2529
  previousReplay = [];
2627
2530
  pendingToolCalls = [];
@@ -2632,6 +2535,7 @@ var MockAdapter = class extends AdapterBase {
2632
2535
  this.turns = options.turns;
2633
2536
  this.onExhausted = options.onExhausted ?? "throw";
2634
2537
  this.providerMetadata = options.providerMetadata;
2538
+ this.defaultStream = resolveMockTextStreamOptions(options.stream, "adapter stream");
2635
2539
  }
2636
2540
  async buildRequest(request) {
2637
2541
  const turnIndex = this.cursor;
@@ -2669,26 +2573,26 @@ var MockAdapter = class extends AdapterBase {
2669
2573
  break;
2670
2574
  case "message": {
2671
2575
  const item = createMessageFromStep(step, request, mockRequest.turnIndex, stepIndex);
2672
- yield* emitMessage(factory, item);
2576
+ yield* emitMessage(factory, item, resolveStepStreamOptions(this.defaultStream, step.stream, "message"));
2673
2577
  output.push(item);
2674
2578
  break;
2675
2579
  }
2676
2580
  case "reasoning": {
2677
2581
  const item = createReasoningFromStep(step, request, mockRequest.turnIndex, stepIndex);
2678
- yield* emitReasoning(factory, item);
2582
+ yield* emitReasoning(factory, item, resolveStepStreamOptions(this.defaultStream, step.stream, "reasoning"));
2679
2583
  output.push(item);
2680
2584
  break;
2681
2585
  }
2682
2586
  case "tool_call": {
2683
2587
  const item = createToolCallFromStep(step);
2684
- yield* emitToolCall(factory, item, step.streamArguments ?? true);
2588
+ yield* emitToolCall(factory, item, step.streamArguments ?? true, resolveStepStreamOptions(this.defaultStream, step.stream, "tool_call"));
2685
2589
  output.push(item);
2686
2590
  break;
2687
2591
  }
2688
2592
  case "output": {
2689
2593
  assertSupportedOutputItem(step.item);
2690
2594
  const item = attachSyntheticId(step.item, request, mockRequest.turnIndex, stepIndex);
2691
- yield* emitOutputItem(factory, item);
2595
+ yield* emitOutputItem(factory, item, resolveStepStreamOptions(this.defaultStream, step.stream, "output"));
2692
2596
  output.push(item);
2693
2597
  break;
2694
2598
  }
@@ -2811,34 +2715,95 @@ function attachSyntheticId(item, request, turnIndex, stepIndex) {
2811
2715
  };
2812
2716
  return item;
2813
2717
  }
2814
- async function* emitOutputItem(factory, item) {
2718
+ async function* emitOutputItem(factory, item, stream) {
2815
2719
  if (item.type === "message") {
2816
- yield* emitMessage(factory, item);
2720
+ yield* emitMessage(factory, item, stream);
2817
2721
  return;
2818
2722
  }
2819
2723
  if (item.type === "reasoning") {
2820
- yield* emitReasoning(factory, item);
2724
+ yield* emitReasoning(factory, item, stream);
2821
2725
  return;
2822
2726
  }
2823
- yield* emitToolCall(factory, item, true);
2727
+ yield* emitToolCall(factory, item, true, stream);
2824
2728
  }
2825
- async function* emitMessage(factory, item) {
2729
+ async function* emitMessage(factory, item, stream) {
2826
2730
  if (!item.id) throw new AIRequestError("Mock message output requires an id after normalization", "MOCK_MESSAGE_ID_MISSING");
2827
2731
  yield factory.messageStarted(item.id);
2828
- for (const block of item.content) if (block.type === "text") yield factory.messageDelta(item.id, block.text);
2732
+ let chunkIndex = 0;
2733
+ for (const block of item.content) if (block.type === "text") for (const chunk of chunkText(block.text, stream)) {
2734
+ await delayForChunk(stream, chunkIndex, chunk.length);
2735
+ yield factory.messageDelta(item.id, chunk);
2736
+ chunkIndex += 1;
2737
+ }
2829
2738
  yield factory.messageCompleted(item);
2830
2739
  }
2831
- async function* emitReasoning(factory, item) {
2740
+ async function* emitReasoning(factory, item, stream) {
2832
2741
  if (!item.id) throw new AIRequestError("Mock reasoning output requires an id after normalization", "MOCK_REASONING_ID_MISSING");
2833
2742
  yield factory.reasoningStarted(item.id, item.visibility);
2834
- for (const block of item.content) yield factory.reasoningDelta(item.id, block);
2743
+ let chunkIndex = 0;
2744
+ for (const block of item.content) {
2745
+ if (block.type !== "text") {
2746
+ yield factory.reasoningDelta(item.id, block);
2747
+ continue;
2748
+ }
2749
+ for (const chunk of chunkText(block.text, stream)) {
2750
+ await delayForChunk(stream, chunkIndex, chunk.length);
2751
+ yield factory.reasoningDelta(item.id, textBlock(chunk));
2752
+ chunkIndex += 1;
2753
+ }
2754
+ }
2835
2755
  yield factory.reasoningCompleted(item);
2836
2756
  }
2837
- async function* emitToolCall(factory, item, streamArguments) {
2757
+ async function* emitToolCall(factory, item, streamArguments, stream) {
2838
2758
  yield factory.toolCallStarted(item.id, item.name);
2839
- if (streamArguments && item.argumentsText) yield factory.toolCallDelta(item.id, { argumentsText: item.argumentsText });
2759
+ if (streamArguments && item.argumentsText) {
2760
+ let chunkIndex = 0;
2761
+ for (const chunk of chunkText(item.argumentsText, stream)) {
2762
+ await delayForChunk(stream, chunkIndex, chunk.length);
2763
+ yield factory.toolCallDelta(item.id, { argumentsText: chunk });
2764
+ chunkIndex += 1;
2765
+ }
2766
+ }
2840
2767
  yield factory.toolCallCompleted(item);
2841
2768
  }
2769
+ function resolveStepStreamOptions(defaults, override, label) {
2770
+ if (override === false) return;
2771
+ return resolveMockTextStreamOptions(override, `${label} stream`, defaults);
2772
+ }
2773
+ function resolveMockTextStreamOptions(options, label, defaults) {
2774
+ if (options === void 0) return defaults;
2775
+ const chunkSize = options.chunkSize ?? defaults?.chunkSize ?? 1;
2776
+ const initialDelayMs = options.initialDelayMs ?? defaults?.initialDelayMs ?? 0;
2777
+ const charsPerSecond = options.charsPerSecond ?? defaults?.charsPerSecond;
2778
+ if (!Number.isInteger(chunkSize) || chunkSize < 1) throw new AIRequestError(`${label}: chunkSize must be a positive integer`, "MOCK_STREAM_CONFIG_INVALID");
2779
+ if (!Number.isFinite(initialDelayMs) || initialDelayMs < 0) throw new AIRequestError(`${label}: initialDelayMs must be a non-negative number`, "MOCK_STREAM_CONFIG_INVALID");
2780
+ if (charsPerSecond !== void 0 && (!Number.isFinite(charsPerSecond) || charsPerSecond <= 0)) throw new AIRequestError(`${label}: charsPerSecond must be a positive number`, "MOCK_STREAM_CONFIG_INVALID");
2781
+ return {
2782
+ chunkSize,
2783
+ initialDelayMs,
2784
+ charsPerSecond
2785
+ };
2786
+ }
2787
+ function chunkText(text, stream) {
2788
+ if (!text) return [];
2789
+ if (!stream) return [text];
2790
+ const chars = Array.from(text);
2791
+ const chunks = [];
2792
+ for (let index = 0; index < chars.length; index += stream.chunkSize) chunks.push(chars.slice(index, index + stream.chunkSize).join(""));
2793
+ return chunks;
2794
+ }
2795
+ async function delayForChunk(stream, chunkIndex, chunkLength) {
2796
+ if (!stream) return;
2797
+ if (chunkIndex === 0 && stream.initialDelayMs > 0) {
2798
+ await sleep(stream.initialDelayMs);
2799
+ return;
2800
+ }
2801
+ if (chunkIndex > 0 && stream.charsPerSecond !== void 0) await sleep(chunkLength / stream.charsPerSecond * 1e3);
2802
+ }
2803
+ async function sleep(ms) {
2804
+ if (ms <= 0) return;
2805
+ await new Promise((resolve) => setTimeout(resolve, ms));
2806
+ }
2842
2807
  function resolveStopReason(output) {
2843
2808
  return output.some((item) => item.type === "tool_call") ? "tool_call" : "end_turn";
2844
2809
  }
@@ -3028,6 +2993,6 @@ function* emitToolCallEvents(item, factory) {
3028
2993
  yield factory.toolCallCompleted(item);
3029
2994
  }
3030
2995
  //#endregion
3031
- export { AIError, AIMappingError, AIProviderError, AIRequestError, AIStreamError, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, CAPABILITY_MATRIX, ChatCompletionsAdapter, MessagesAdapter, MockAdapter, OllamaAdapter, ResponsesAdapter, WarningCode, aggregateEvents, 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 };
2996
+ export { AIError, AIMappingError, AIProviderError, AIRequestError, AIStreamError, AdapterAuxiliaryState, AdapterBase, AuxiliaryCollector, ChatCompletionsAdapter, MessagesAdapter, MockAdapter, OllamaAdapter, ResponsesAdapter, WarningCode, aggregateEvents, 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 };
3032
2997
 
3033
2998
  //# sourceMappingURL=index.mjs.map