ai-protocol-adapters 1.0.0-alpha.2 → 1.0.0-alpha.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # @ai-protocol/adapters
1
+ # ai-protocol-adapters
2
2
 
3
- [![npm version](https://badge.fury.io/js/@ai-protocol%2Fadapters.svg)](https://badge.fury.io/js/@ai-protocol%2Fadapters)
3
+ [![npm version](https://badge.fury.io/js/ai-protocol-adapters.svg)](https://badge.fury.io/js/ai-protocol-adapters)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
6
 
@@ -19,15 +19,15 @@
19
19
  ## 📦 安装
20
20
 
21
21
  ```bash
22
- npm install @ai-protocol/adapters
22
+ npm install ai-protocol-adapters
23
23
  ```
24
24
 
25
25
  ```bash
26
- yarn add @ai-protocol/adapters
26
+ yarn add ai-protocol-adapters
27
27
  ```
28
28
 
29
29
  ```bash
30
- pnpm add @ai-protocol/adapters
30
+ pnpm add ai-protocol-adapters
31
31
  ```
32
32
 
33
33
  ## 🚀 快速开始
@@ -35,7 +35,7 @@ pnpm add @ai-protocol/adapters
35
35
  ### 基础使用
36
36
 
37
37
  ```typescript
38
- import { StreamingProtocolAdapter } from '@ai-protocol/adapters'
38
+ import { StreamingProtocolAdapter } from 'ai-protocol-adapters'
39
39
 
40
40
  // 创建适配器实例
41
41
  const adapter = new StreamingProtocolAdapter({
@@ -103,7 +103,7 @@ const { openaiRequest } = adapter.convertAnthropicToOpenAI(glmRequest)
103
103
  ### 自定义日志器
104
104
 
105
105
  ```typescript
106
- import { setGlobalLogger, StreamingProtocolAdapter } from '@ai-protocol/adapters'
106
+ import { setGlobalLogger, StreamingProtocolAdapter } from 'ai-protocol-adapters'
107
107
 
108
108
  // 使用自定义日志器
109
109
  setGlobalLogger({
package/dist/index.d.mts CHANGED
@@ -6029,6 +6029,89 @@ declare class FormatValidator {
6029
6029
  };
6030
6030
  }
6031
6031
 
6032
+ /**
6033
+ * 流式处理相关类型定义
6034
+ */
6035
+
6036
+ /**
6037
+ * 流式转换配置选项
6038
+ */
6039
+ interface StreamConversionOptions {
6040
+ /** 模型名称 */
6041
+ modelName?: string;
6042
+ /** 消息ID */
6043
+ messageId?: string;
6044
+ /** 缓冲区超时时间(毫秒) */
6045
+ bufferTimeout?: number;
6046
+ /** 是否启用错误恢复 */
6047
+ errorRecovery?: boolean;
6048
+ /** 最大重试次数 */
6049
+ maxRetries?: number;
6050
+ /** 块处理回调 */
6051
+ onChunkProcessed?: (chunk: string, events: string[]) => void;
6052
+ /** 错误回调 */
6053
+ onError?: (error: Error, context: StreamErrorContext) => void;
6054
+ /** 调试模式 */
6055
+ debug?: boolean;
6056
+ }
6057
+ /**
6058
+ * 流式错误上下文
6059
+ */
6060
+ interface StreamErrorContext {
6061
+ chunk: string;
6062
+ state: IncrementalConversionState;
6063
+ attempt?: number;
6064
+ totalRetries?: number;
6065
+ }
6066
+ /**
6067
+ * 流式转换器接口
6068
+ */
6069
+ interface IStreamConverter {
6070
+ /**
6071
+ * 获取初始事件
6072
+ */
6073
+ getInitialEvents(): string[];
6074
+ /**
6075
+ * 处理单个数据块
6076
+ */
6077
+ processChunk(chunk: string): string[];
6078
+ /**
6079
+ * 结束流处理
6080
+ */
6081
+ finalize(): string[];
6082
+ /**
6083
+ * 获取当前状态
6084
+ */
6085
+ getState(): IncrementalConversionState;
6086
+ /**
6087
+ * 重置状态
6088
+ */
6089
+ reset(): void;
6090
+ /**
6091
+ * 获取统计信息
6092
+ */
6093
+ getStats(): StreamStats;
6094
+ }
6095
+ /**
6096
+ * 流式处理统计信息
6097
+ */
6098
+ interface StreamStats {
6099
+ /** 处理的块数量 */
6100
+ chunksProcessed: number;
6101
+ /** 生成的事件数量 */
6102
+ eventsGenerated: number;
6103
+ /** 错误数量 */
6104
+ errors: number;
6105
+ /** 重试次数 */
6106
+ retries: number;
6107
+ /** 处理开始时间 */
6108
+ startTime: number;
6109
+ /** 最后更新时间 */
6110
+ lastUpdateTime: number;
6111
+ /** 缓冲区大小 */
6112
+ bufferSize: number;
6113
+ }
6114
+
6032
6115
  /**
6033
6116
  * O2A SSE适配器配置
6034
6117
  */
@@ -6103,6 +6186,20 @@ declare class O2ASSEAdapter {
6103
6186
  errors: string[];
6104
6187
  warnings: string[];
6105
6188
  };
6189
+ /**
6190
+ * 将 OpenAI Response 流直接转换为 Anthropic SSE 流
6191
+ * 这是新增的核心流式处理方法,支持实时转换
6192
+ */
6193
+ convertResponseStream(openaiResponse: Response, options?: StreamConversionOptions): ReadableStream<string>;
6194
+ /**
6195
+ * 将 ReadableStream 转换为 Anthropic SSE 流
6196
+ */
6197
+ convertReadableStream(openaiStream: ReadableStream<Uint8Array>, options?: StreamConversionOptions): ReadableStream<string>;
6198
+ /**
6199
+ * 创建流式转换器实例
6200
+ * 提供更精细的流处理控制
6201
+ */
6202
+ createStreamConverter(options?: StreamConversionOptions): IStreamConverter;
6106
6203
  /**
6107
6204
  * 应用增强功能到SSE转换
6108
6205
  * 包括输入验证、输出修复等
@@ -6135,6 +6232,21 @@ declare const O2ASSEAdapterStatic: {
6135
6232
  errors: string[];
6136
6233
  warnings: string[];
6137
6234
  };
6235
+ /**
6236
+ * 转换 Response 流为 Anthropic SSE(静态方法)
6237
+ * 新增:直接处理 Response 对象的流式转换
6238
+ */
6239
+ convertResponseStream: (openaiResponse: Response, options?: StreamConversionOptions) => ReadableStream<string>;
6240
+ /**
6241
+ * 转换 ReadableStream 为 Anthropic SSE(静态方法)
6242
+ * 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
6243
+ */
6244
+ convertReadableStream: (openaiStream: ReadableStream<Uint8Array>, options?: StreamConversionOptions) => ReadableStream<string>;
6245
+ /**
6246
+ * 创建流式转换器(静态方法)
6247
+ * 新增:提供更精细的流处理控制
6248
+ */
6249
+ createStreamConverter: (options?: StreamConversionOptions) => IStreamConverter;
6138
6250
  };
6139
6251
 
6140
6252
  /**
@@ -7155,7 +7267,7 @@ interface Logger {
7155
7267
  declare function getGlobalLogger(): Logger;
7156
7268
 
7157
7269
  /**
7158
- * @ai-protocol/adapters - Universal AI Protocol Converter
7270
+ * ai-protocol-adapters - Universal AI Protocol Converter
7159
7271
  * OpenAI ⇄ Anthropic with full TypeScript support
7160
7272
  */
7161
7273
 
package/dist/index.d.ts CHANGED
@@ -6029,6 +6029,89 @@ declare class FormatValidator {
6029
6029
  };
6030
6030
  }
6031
6031
 
6032
+ /**
6033
+ * 流式处理相关类型定义
6034
+ */
6035
+
6036
+ /**
6037
+ * 流式转换配置选项
6038
+ */
6039
+ interface StreamConversionOptions {
6040
+ /** 模型名称 */
6041
+ modelName?: string;
6042
+ /** 消息ID */
6043
+ messageId?: string;
6044
+ /** 缓冲区超时时间(毫秒) */
6045
+ bufferTimeout?: number;
6046
+ /** 是否启用错误恢复 */
6047
+ errorRecovery?: boolean;
6048
+ /** 最大重试次数 */
6049
+ maxRetries?: number;
6050
+ /** 块处理回调 */
6051
+ onChunkProcessed?: (chunk: string, events: string[]) => void;
6052
+ /** 错误回调 */
6053
+ onError?: (error: Error, context: StreamErrorContext) => void;
6054
+ /** 调试模式 */
6055
+ debug?: boolean;
6056
+ }
6057
+ /**
6058
+ * 流式错误上下文
6059
+ */
6060
+ interface StreamErrorContext {
6061
+ chunk: string;
6062
+ state: IncrementalConversionState;
6063
+ attempt?: number;
6064
+ totalRetries?: number;
6065
+ }
6066
+ /**
6067
+ * 流式转换器接口
6068
+ */
6069
+ interface IStreamConverter {
6070
+ /**
6071
+ * 获取初始事件
6072
+ */
6073
+ getInitialEvents(): string[];
6074
+ /**
6075
+ * 处理单个数据块
6076
+ */
6077
+ processChunk(chunk: string): string[];
6078
+ /**
6079
+ * 结束流处理
6080
+ */
6081
+ finalize(): string[];
6082
+ /**
6083
+ * 获取当前状态
6084
+ */
6085
+ getState(): IncrementalConversionState;
6086
+ /**
6087
+ * 重置状态
6088
+ */
6089
+ reset(): void;
6090
+ /**
6091
+ * 获取统计信息
6092
+ */
6093
+ getStats(): StreamStats;
6094
+ }
6095
+ /**
6096
+ * 流式处理统计信息
6097
+ */
6098
+ interface StreamStats {
6099
+ /** 处理的块数量 */
6100
+ chunksProcessed: number;
6101
+ /** 生成的事件数量 */
6102
+ eventsGenerated: number;
6103
+ /** 错误数量 */
6104
+ errors: number;
6105
+ /** 重试次数 */
6106
+ retries: number;
6107
+ /** 处理开始时间 */
6108
+ startTime: number;
6109
+ /** 最后更新时间 */
6110
+ lastUpdateTime: number;
6111
+ /** 缓冲区大小 */
6112
+ bufferSize: number;
6113
+ }
6114
+
6032
6115
  /**
6033
6116
  * O2A SSE适配器配置
6034
6117
  */
@@ -6103,6 +6186,20 @@ declare class O2ASSEAdapter {
6103
6186
  errors: string[];
6104
6187
  warnings: string[];
6105
6188
  };
6189
+ /**
6190
+ * 将 OpenAI Response 流直接转换为 Anthropic SSE 流
6191
+ * 这是新增的核心流式处理方法,支持实时转换
6192
+ */
6193
+ convertResponseStream(openaiResponse: Response, options?: StreamConversionOptions): ReadableStream<string>;
6194
+ /**
6195
+ * 将 ReadableStream 转换为 Anthropic SSE 流
6196
+ */
6197
+ convertReadableStream(openaiStream: ReadableStream<Uint8Array>, options?: StreamConversionOptions): ReadableStream<string>;
6198
+ /**
6199
+ * 创建流式转换器实例
6200
+ * 提供更精细的流处理控制
6201
+ */
6202
+ createStreamConverter(options?: StreamConversionOptions): IStreamConverter;
6106
6203
  /**
6107
6204
  * 应用增强功能到SSE转换
6108
6205
  * 包括输入验证、输出修复等
@@ -6135,6 +6232,21 @@ declare const O2ASSEAdapterStatic: {
6135
6232
  errors: string[];
6136
6233
  warnings: string[];
6137
6234
  };
6235
+ /**
6236
+ * 转换 Response 流为 Anthropic SSE(静态方法)
6237
+ * 新增:直接处理 Response 对象的流式转换
6238
+ */
6239
+ convertResponseStream: (openaiResponse: Response, options?: StreamConversionOptions) => ReadableStream<string>;
6240
+ /**
6241
+ * 转换 ReadableStream 为 Anthropic SSE(静态方法)
6242
+ * 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
6243
+ */
6244
+ convertReadableStream: (openaiStream: ReadableStream<Uint8Array>, options?: StreamConversionOptions) => ReadableStream<string>;
6245
+ /**
6246
+ * 创建流式转换器(静态方法)
6247
+ * 新增:提供更精细的流处理控制
6248
+ */
6249
+ createStreamConverter: (options?: StreamConversionOptions) => IStreamConverter;
6138
6250
  };
6139
6251
 
6140
6252
  /**
@@ -7155,7 +7267,7 @@ interface Logger {
7155
7267
  declare function getGlobalLogger(): Logger;
7156
7268
 
7157
7269
  /**
7158
- * @ai-protocol/adapters - Universal AI Protocol Converter
7270
+ * ai-protocol-adapters - Universal AI Protocol Converter
7159
7271
  * OpenAI ⇄ Anthropic with full TypeScript support
7160
7272
  */
7161
7273
 
package/dist/index.js CHANGED
@@ -4480,6 +4480,247 @@ function generateMessageId() {
4480
4480
  return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
4481
4481
  }
4482
4482
 
4483
+ // src/core/o2a-sse-adapter/stream-converter.ts
4484
+ var StreamConverter = class {
4485
+ constructor(adapter, options = {}) {
4486
+ this.buffer = "";
4487
+ this.adapter = adapter;
4488
+ this.options = {
4489
+ bufferTimeout: 5e3,
4490
+ errorRecovery: true,
4491
+ maxRetries: 3,
4492
+ debug: false,
4493
+ ...options
4494
+ };
4495
+ this.state = this.adapter.createIncrementalState();
4496
+ this.stats = {
4497
+ chunksProcessed: 0,
4498
+ eventsGenerated: 0,
4499
+ errors: 0,
4500
+ retries: 0,
4501
+ startTime: Date.now(),
4502
+ lastUpdateTime: Date.now(),
4503
+ bufferSize: 0
4504
+ };
4505
+ if (this.options.debug) {
4506
+ console.log("[StreamConverter] \u5DF2\u521D\u59CB\u5316\uFF0C\u914D\u7F6E:", this.options);
4507
+ }
4508
+ }
4509
+ /**
4510
+ * 获取初始事件
4511
+ */
4512
+ getInitialEvents() {
4513
+ const events = this.adapter.getInitialSSEEvents(
4514
+ this.options.modelName,
4515
+ this.options.messageId
4516
+ );
4517
+ this.stats.eventsGenerated += events.length;
4518
+ this.stats.lastUpdateTime = Date.now();
4519
+ if (this.options.debug) {
4520
+ console.log("[StreamConverter] \u751F\u6210\u521D\u59CB\u4E8B\u4EF6:", events.length, "\u4E2A");
4521
+ }
4522
+ return events;
4523
+ }
4524
+ /**
4525
+ * 处理单个数据块
4526
+ */
4527
+ processChunk(chunk) {
4528
+ this.stats.chunksProcessed++;
4529
+ this.stats.lastUpdateTime = Date.now();
4530
+ if (this.options.debug) {
4531
+ console.log("[StreamConverter] \u5904\u7406\u6570\u636E\u5757:", chunk.substring(0, 100) + "...");
4532
+ }
4533
+ try {
4534
+ const events = this.processBufferedData(chunk);
4535
+ this.stats.eventsGenerated += events.length;
4536
+ if (this.options.onChunkProcessed) {
4537
+ this.options.onChunkProcessed(chunk, events);
4538
+ }
4539
+ return events;
4540
+ } catch (error) {
4541
+ return this.handleChunkError(error, chunk);
4542
+ }
4543
+ }
4544
+ /**
4545
+ * 结束流处理
4546
+ */
4547
+ finalize() {
4548
+ if (this.options.debug) {
4549
+ console.log("[StreamConverter] \u7ED3\u675F\u6D41\u5904\u7406\uFF0C\u7F13\u51B2\u533A\u5927\u5C0F:", this.buffer.length);
4550
+ }
4551
+ let events = [];
4552
+ if (this.buffer.trim()) {
4553
+ console.warn("[StreamConverter] \u7F13\u51B2\u533A\u4E2D\u6709\u672A\u5904\u7406\u6570\u636E\uFF0C\u5F3A\u5236\u5904\u7406:", this.buffer);
4554
+ events = this.processIncompleteBuffer();
4555
+ }
4556
+ try {
4557
+ const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
4558
+ events.push(...finalEvents);
4559
+ this.stats.eventsGenerated += finalEvents.length;
4560
+ } catch (error) {
4561
+ console.error("[StreamConverter] \u5904\u7406\u7ED3\u675F\u4E8B\u4EF6\u5931\u8D25:", error);
4562
+ }
4563
+ this.clearBufferTimeout();
4564
+ this.stats.lastUpdateTime = Date.now();
4565
+ if (this.options.debug) {
4566
+ console.log("[StreamConverter] \u6D41\u5904\u7406\u5B8C\u6210\uFF0C\u7EDF\u8BA1\u4FE1\u606F:", this.stats);
4567
+ }
4568
+ return events;
4569
+ }
4570
+ /**
4571
+ * 获取当前状态
4572
+ */
4573
+ getState() {
4574
+ return { ...this.state };
4575
+ }
4576
+ /**
4577
+ * 重置状态
4578
+ */
4579
+ reset() {
4580
+ this.state = this.adapter.createIncrementalState();
4581
+ this.buffer = "";
4582
+ this.clearBufferTimeout();
4583
+ this.stats = {
4584
+ chunksProcessed: 0,
4585
+ eventsGenerated: 0,
4586
+ errors: 0,
4587
+ retries: 0,
4588
+ startTime: Date.now(),
4589
+ lastUpdateTime: Date.now(),
4590
+ bufferSize: 0
4591
+ };
4592
+ if (this.options.debug) {
4593
+ console.log("[StreamConverter] \u72B6\u6001\u5DF2\u91CD\u7F6E");
4594
+ }
4595
+ }
4596
+ /**
4597
+ * 获取统计信息
4598
+ */
4599
+ getStats() {
4600
+ return {
4601
+ ...this.stats,
4602
+ bufferSize: this.buffer.length
4603
+ };
4604
+ }
4605
+ /**
4606
+ * 处理缓冲的数据
4607
+ */
4608
+ processBufferedData(newChunk) {
4609
+ this.buffer += newChunk;
4610
+ this.stats.bufferSize = this.buffer.length;
4611
+ const lines = this.buffer.split("\n");
4612
+ this.buffer = lines.pop() || "";
4613
+ const events = [];
4614
+ for (const line of lines) {
4615
+ if (line.startsWith("data:")) {
4616
+ const jsonStr = line.slice(5).trim();
4617
+ if (jsonStr && jsonStr !== "[DONE]") {
4618
+ const lineEvents = this.processDataLine(jsonStr);
4619
+ events.push(...lineEvents);
4620
+ } else if (jsonStr === "[DONE]") {
4621
+ const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
4622
+ events.push(...finalEvents);
4623
+ }
4624
+ }
4625
+ }
4626
+ this.resetBufferTimeout();
4627
+ return events;
4628
+ }
4629
+ /**
4630
+ * 处理单行数据
4631
+ */
4632
+ processDataLine(jsonStr, attempt = 0) {
4633
+ try {
4634
+ const chunkEvents = this.adapter.convertIncrementalChunk(jsonStr, this.state);
4635
+ if (this.options.debug && chunkEvents.length > 0) {
4636
+ console.log("[StreamConverter] \u751F\u6210\u4E8B\u4EF6:", chunkEvents.length, "\u4E2A");
4637
+ }
4638
+ return chunkEvents;
4639
+ } catch (error) {
4640
+ if (this.options.errorRecovery && attempt < (this.options.maxRetries || 3)) {
4641
+ console.warn(`[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u5931\u8D25\uFF0C\u91CD\u8BD5 ${attempt + 1}/${this.options.maxRetries}:`, error);
4642
+ this.stats.retries++;
4643
+ return this.processDataLine(jsonStr, attempt + 1);
4644
+ }
4645
+ this.stats.errors++;
4646
+ console.error("[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u6700\u7EC8\u5931\u8D25:", error, "Data:", jsonStr);
4647
+ if (this.options.onError) {
4648
+ this.options.onError(error, {
4649
+ chunk: jsonStr,
4650
+ state: this.state,
4651
+ attempt,
4652
+ totalRetries: this.stats.retries
4653
+ });
4654
+ }
4655
+ return [];
4656
+ }
4657
+ }
4658
+ /**
4659
+ * 处理块错误
4660
+ */
4661
+ handleChunkError(error, chunk) {
4662
+ this.stats.errors++;
4663
+ if (this.options.debug) {
4664
+ console.error("[StreamConverter] \u5757\u5904\u7406\u9519\u8BEF:", error.message);
4665
+ }
4666
+ if (!this.options.errorRecovery) {
4667
+ throw error;
4668
+ }
4669
+ this.state.errors.push(`Chunk processing error: ${error.message}`);
4670
+ if (this.options.onError) {
4671
+ this.options.onError(error, {
4672
+ chunk,
4673
+ state: this.state,
4674
+ totalRetries: this.stats.retries
4675
+ });
4676
+ }
4677
+ return [];
4678
+ }
4679
+ /**
4680
+ * 处理不完整的缓冲区数据
4681
+ */
4682
+ processIncompleteBuffer() {
4683
+ if (!this.buffer.trim()) {
4684
+ return [];
4685
+ }
4686
+ console.warn("[StreamConverter] \u5904\u7406\u4E0D\u5B8C\u6574\u7F13\u51B2\u533A\u6570\u636E:", this.buffer);
4687
+ if (this.buffer.startsWith("data:")) {
4688
+ const jsonStr = this.buffer.slice(5).trim();
4689
+ if (jsonStr) {
4690
+ return this.processDataLine(jsonStr);
4691
+ }
4692
+ }
4693
+ return [];
4694
+ }
4695
+ /**
4696
+ * 重置缓冲区超时
4697
+ */
4698
+ resetBufferTimeout() {
4699
+ this.clearBufferTimeout();
4700
+ if (this.options.bufferTimeout && this.options.bufferTimeout > 0) {
4701
+ this.bufferTimeout = setTimeout(() => {
4702
+ if (this.buffer.trim()) {
4703
+ console.warn("[StreamConverter] \u7F13\u51B2\u533A\u8D85\u65F6\uFF0C\u5F3A\u5236\u5904\u7406\u6570\u636E:", this.buffer);
4704
+ const events = this.processIncompleteBuffer();
4705
+ this.buffer = "";
4706
+ if (events.length > 0 && this.options.onChunkProcessed) {
4707
+ this.options.onChunkProcessed("TIMEOUT_FLUSH", events);
4708
+ }
4709
+ }
4710
+ }, this.options.bufferTimeout);
4711
+ }
4712
+ }
4713
+ /**
4714
+ * 清理缓冲区超时
4715
+ */
4716
+ clearBufferTimeout() {
4717
+ if (this.bufferTimeout) {
4718
+ clearTimeout(this.bufferTimeout);
4719
+ this.bufferTimeout = void 0;
4720
+ }
4721
+ }
4722
+ };
4723
+
4483
4724
  // src/core/o2a-sse-adapter/adapter.ts
4484
4725
  var O2ASSEAdapter = class {
4485
4726
  constructor(debugMode = false, config = {}) {
@@ -4734,6 +4975,101 @@ var O2ASSEAdapter = class {
4734
4975
  validateClaudeSSE(sseContent) {
4735
4976
  return FormatValidator2.validateClaudeSSE(sseContent);
4736
4977
  }
4978
+ /**
4979
+ * 将 OpenAI Response 流直接转换为 Anthropic SSE 流
4980
+ * 这是新增的核心流式处理方法,支持实时转换
4981
+ */
4982
+ convertResponseStream(openaiResponse, options = {}) {
4983
+ if (!openaiResponse.body) {
4984
+ throw new Error("Response body is null or undefined");
4985
+ }
4986
+ return this.convertReadableStream(openaiResponse.body, options);
4987
+ }
4988
+ /**
4989
+ * 将 ReadableStream 转换为 Anthropic SSE 流
4990
+ */
4991
+ convertReadableStream(openaiStream, options = {}) {
4992
+ const converter = this.createStreamConverter(options);
4993
+ const decoder = new TextDecoder();
4994
+ return new ReadableStream({
4995
+ async start(controller) {
4996
+ if (options.debug) {
4997
+ console.log("[O2ASSEAdapter] \u5F00\u59CB\u6D41\u5F0F\u8F6C\u6362\uFF0C\u914D\u7F6E:", options);
4998
+ }
4999
+ try {
5000
+ const initialEvents = converter.getInitialEvents();
5001
+ for (const event of initialEvents) {
5002
+ controller.enqueue(event);
5003
+ }
5004
+ } catch (error) {
5005
+ console.error("[O2ASSEAdapter] \u521D\u59CB\u5316\u5931\u8D25:", error);
5006
+ controller.error(error);
5007
+ return;
5008
+ }
5009
+ const reader = openaiStream.getReader();
5010
+ try {
5011
+ while (true) {
5012
+ const { done, value } = await reader.read();
5013
+ if (done) {
5014
+ try {
5015
+ const finalEvents = converter.finalize();
5016
+ for (const event of finalEvents) {
5017
+ controller.enqueue(event);
5018
+ }
5019
+ if (options.debug) {
5020
+ console.log("[O2ASSEAdapter] \u6D41\u5F0F\u8F6C\u6362\u5B8C\u6210\uFF0C\u7EDF\u8BA1:", converter.getStats());
5021
+ }
5022
+ } catch (error) {
5023
+ console.error("[O2ASSEAdapter] \u7ED3\u675F\u5904\u7406\u5931\u8D25:", error);
5024
+ }
5025
+ break;
5026
+ }
5027
+ const chunk = decoder.decode(value, { stream: true });
5028
+ try {
5029
+ const events = converter.processChunk(chunk);
5030
+ for (const event of events) {
5031
+ controller.enqueue(event);
5032
+ }
5033
+ } catch (error) {
5034
+ console.error("[O2ASSEAdapter] \u5757\u5904\u7406\u5931\u8D25:", error);
5035
+ if (options.errorRecovery === false) {
5036
+ controller.error(error);
5037
+ return;
5038
+ }
5039
+ if (options.onError) {
5040
+ options.onError(error, {
5041
+ chunk,
5042
+ state: converter.getState()
5043
+ });
5044
+ }
5045
+ }
5046
+ }
5047
+ } catch (error) {
5048
+ console.error("[O2ASSEAdapter] \u6D41\u5904\u7406\u5931\u8D25:", error);
5049
+ if (options.onError) {
5050
+ options.onError(error, {
5051
+ chunk: "",
5052
+ state: converter.getState()
5053
+ });
5054
+ }
5055
+ controller.error(error);
5056
+ } finally {
5057
+ controller.close();
5058
+ }
5059
+ }
5060
+ });
5061
+ }
5062
+ /**
5063
+ * 创建流式转换器实例
5064
+ * 提供更精细的流处理控制
5065
+ */
5066
+ createStreamConverter(options = {}) {
5067
+ return new StreamConverter(this, {
5068
+ modelName: options.modelName || this.config.defaultModel,
5069
+ debug: options.debug || this.debugMode,
5070
+ ...options
5071
+ });
5072
+ }
4737
5073
  /**
4738
5074
  * 应用增强功能到SSE转换
4739
5075
  * 包括输入验证、输出修复等
@@ -4805,13 +5141,49 @@ var O2ASSEAdapterStatic = {
4805
5141
  validateClaudeSSE: (sseContent) => {
4806
5142
  const adapter = new O2ASSEAdapter(false);
4807
5143
  return adapter.validateClaudeSSE(sseContent);
5144
+ },
5145
+ /**
5146
+ * 转换 Response 流为 Anthropic SSE(静态方法)
5147
+ * 新增:直接处理 Response 对象的流式转换
5148
+ */
5149
+ convertResponseStream: (openaiResponse, options = {}) => {
5150
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5151
+ defaultModel: options.modelName || "claude-sonnet-4",
5152
+ generateUniqueMessageId: !options.messageId,
5153
+ errorDataMaxLength: 500
5154
+ });
5155
+ return adapter.convertResponseStream(openaiResponse, options);
5156
+ },
5157
+ /**
5158
+ * 转换 ReadableStream 为 Anthropic SSE(静态方法)
5159
+ * 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
5160
+ */
5161
+ convertReadableStream: (openaiStream, options = {}) => {
5162
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5163
+ defaultModel: options.modelName || "claude-sonnet-4",
5164
+ generateUniqueMessageId: !options.messageId,
5165
+ errorDataMaxLength: 500
5166
+ });
5167
+ return adapter.convertReadableStream(openaiStream, options);
5168
+ },
5169
+ /**
5170
+ * 创建流式转换器(静态方法)
5171
+ * 新增:提供更精细的流处理控制
5172
+ */
5173
+ createStreamConverter: (options = {}) => {
5174
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5175
+ defaultModel: options.modelName || "claude-sonnet-4",
5176
+ generateUniqueMessageId: !options.messageId,
5177
+ errorDataMaxLength: 500
5178
+ });
5179
+ return adapter.createStreamConverter(options);
4808
5180
  }
4809
5181
  };
4810
5182
 
4811
5183
  // src/core/standard/standard-protocol-adapter.ts
4812
5184
  var StandardProtocolAdapter = class {
4813
5185
  constructor(options = {}) {
4814
- this.debugMode = options.debugMode || false;
5186
+ this.debugMode = options.debugMode !== void 0 ? options.debugMode : true;
4815
5187
  this.sseAdapter = new O2ASSEAdapter(this.debugMode);
4816
5188
  }
4817
5189
  /**
@@ -4888,6 +5260,8 @@ var StandardProtocolAdapter = class {
4888
5260
  };
4889
5261
  let currentTextContent = "";
4890
5262
  const toolCalls = /* @__PURE__ */ new Map();
5263
+ const toolInputBuffers = /* @__PURE__ */ new Map();
5264
+ const indexToToolId = /* @__PURE__ */ new Map();
4891
5265
  let processedDataLines = 0;
4892
5266
  for (const line of lines) {
4893
5267
  if (line.startsWith("data: ")) {
@@ -4900,15 +5274,22 @@ var StandardProtocolAdapter = class {
4900
5274
  if (data.type === "content_block_start") {
4901
5275
  const contentBlock = data.content_block;
4902
5276
  if (contentBlock.type === "tool_use") {
5277
+ const toolIndex = data.index;
4903
5278
  toolCalls.set(contentBlock.id, {
4904
5279
  type: "tool_use",
4905
5280
  id: contentBlock.id,
4906
5281
  name: contentBlock.name,
4907
5282
  input: contentBlock.input || {}
5283
+ // 初始为空对象,稍后会被更新
5284
+ });
5285
+ toolInputBuffers.set(toolIndex, "");
5286
+ indexToToolId.set(toolIndex, contentBlock.id);
5287
+ console.log("\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", {
5288
+ index: toolIndex,
5289
+ toolId: contentBlock.id,
5290
+ name: contentBlock.name,
5291
+ indexToToolIdSize: indexToToolId.size
4908
5292
  });
4909
- if (this.debugMode) {
4910
- console.log("\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", contentBlock);
4911
- }
4912
5293
  }
4913
5294
  }
4914
5295
  if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
@@ -4918,6 +5299,46 @@ var StandardProtocolAdapter = class {
4918
5299
  }
4919
5300
  }
4920
5301
  if (data.type === "content_block_delta" && data.delta?.type === "input_json_delta") {
5302
+ const toolIndex = data.index;
5303
+ const toolId = indexToToolId.get(toolIndex);
5304
+ console.log(`\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u68C0\u6D4B\u5230input_json_delta\u4E8B\u4EF6\uFF01`, {
5305
+ toolIndex,
5306
+ toolId: toolId || "NOT_FOUND",
5307
+ delta: data.delta.partial_json
5308
+ });
5309
+ if (toolId) {
5310
+ const currentBuffer = toolInputBuffers.get(toolIndex) || "";
5311
+ const newBuffer = currentBuffer + data.delta.partial_json;
5312
+ toolInputBuffers.set(toolIndex, newBuffer);
5313
+ console.log(`\u{1F527} [StandardProtocolAdapter] \u7D2F\u79EF\u5DE5\u5177\u53C2\u6570 (index=${toolIndex}, id=${toolId}):`, {
5314
+ delta: data.delta.partial_json,
5315
+ bufferLength: newBuffer.length
5316
+ });
5317
+ } else {
5318
+ console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u627E\u4E0D\u5230toolId for index=${toolIndex}`);
5319
+ }
5320
+ }
5321
+ if (data.type === "content_block_stop") {
5322
+ const toolIndex = data.index;
5323
+ const toolId = indexToToolId.get(toolIndex);
5324
+ if (toolId) {
5325
+ const jsonBuffer = toolInputBuffers.get(toolIndex);
5326
+ const tool = toolCalls.get(toolId);
5327
+ if (jsonBuffer && tool) {
5328
+ try {
5329
+ const parsedInput = JSON.parse(jsonBuffer);
5330
+ tool.input = parsedInput;
5331
+ if (this.debugMode) {
5332
+ console.log(`\u2705 [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570\u89E3\u6790\u5B8C\u6210 (index=${toolIndex}, id=${toolId}):`, parsedInput);
5333
+ }
5334
+ } catch (parseError) {
5335
+ console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570JSON\u89E3\u6790\u5931\u8D25 (index=${toolIndex}, id=${toolId}):`, {
5336
+ buffer: jsonBuffer,
5337
+ error: parseError
5338
+ });
5339
+ }
5340
+ }
5341
+ }
4921
5342
  }
4922
5343
  if (data.type === "message_delta") {
4923
5344
  if (data.delta?.stop_reason) {
package/dist/index.mjs CHANGED
@@ -4373,6 +4373,247 @@ function generateMessageId() {
4373
4373
  return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
4374
4374
  }
4375
4375
 
4376
+ // src/core/o2a-sse-adapter/stream-converter.ts
4377
+ var StreamConverter = class {
4378
+ constructor(adapter, options = {}) {
4379
+ this.buffer = "";
4380
+ this.adapter = adapter;
4381
+ this.options = {
4382
+ bufferTimeout: 5e3,
4383
+ errorRecovery: true,
4384
+ maxRetries: 3,
4385
+ debug: false,
4386
+ ...options
4387
+ };
4388
+ this.state = this.adapter.createIncrementalState();
4389
+ this.stats = {
4390
+ chunksProcessed: 0,
4391
+ eventsGenerated: 0,
4392
+ errors: 0,
4393
+ retries: 0,
4394
+ startTime: Date.now(),
4395
+ lastUpdateTime: Date.now(),
4396
+ bufferSize: 0
4397
+ };
4398
+ if (this.options.debug) {
4399
+ console.log("[StreamConverter] \u5DF2\u521D\u59CB\u5316\uFF0C\u914D\u7F6E:", this.options);
4400
+ }
4401
+ }
4402
+ /**
4403
+ * 获取初始事件
4404
+ */
4405
+ getInitialEvents() {
4406
+ const events = this.adapter.getInitialSSEEvents(
4407
+ this.options.modelName,
4408
+ this.options.messageId
4409
+ );
4410
+ this.stats.eventsGenerated += events.length;
4411
+ this.stats.lastUpdateTime = Date.now();
4412
+ if (this.options.debug) {
4413
+ console.log("[StreamConverter] \u751F\u6210\u521D\u59CB\u4E8B\u4EF6:", events.length, "\u4E2A");
4414
+ }
4415
+ return events;
4416
+ }
4417
+ /**
4418
+ * 处理单个数据块
4419
+ */
4420
+ processChunk(chunk) {
4421
+ this.stats.chunksProcessed++;
4422
+ this.stats.lastUpdateTime = Date.now();
4423
+ if (this.options.debug) {
4424
+ console.log("[StreamConverter] \u5904\u7406\u6570\u636E\u5757:", chunk.substring(0, 100) + "...");
4425
+ }
4426
+ try {
4427
+ const events = this.processBufferedData(chunk);
4428
+ this.stats.eventsGenerated += events.length;
4429
+ if (this.options.onChunkProcessed) {
4430
+ this.options.onChunkProcessed(chunk, events);
4431
+ }
4432
+ return events;
4433
+ } catch (error) {
4434
+ return this.handleChunkError(error, chunk);
4435
+ }
4436
+ }
4437
+ /**
4438
+ * 结束流处理
4439
+ */
4440
+ finalize() {
4441
+ if (this.options.debug) {
4442
+ console.log("[StreamConverter] \u7ED3\u675F\u6D41\u5904\u7406\uFF0C\u7F13\u51B2\u533A\u5927\u5C0F:", this.buffer.length);
4443
+ }
4444
+ let events = [];
4445
+ if (this.buffer.trim()) {
4446
+ console.warn("[StreamConverter] \u7F13\u51B2\u533A\u4E2D\u6709\u672A\u5904\u7406\u6570\u636E\uFF0C\u5F3A\u5236\u5904\u7406:", this.buffer);
4447
+ events = this.processIncompleteBuffer();
4448
+ }
4449
+ try {
4450
+ const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
4451
+ events.push(...finalEvents);
4452
+ this.stats.eventsGenerated += finalEvents.length;
4453
+ } catch (error) {
4454
+ console.error("[StreamConverter] \u5904\u7406\u7ED3\u675F\u4E8B\u4EF6\u5931\u8D25:", error);
4455
+ }
4456
+ this.clearBufferTimeout();
4457
+ this.stats.lastUpdateTime = Date.now();
4458
+ if (this.options.debug) {
4459
+ console.log("[StreamConverter] \u6D41\u5904\u7406\u5B8C\u6210\uFF0C\u7EDF\u8BA1\u4FE1\u606F:", this.stats);
4460
+ }
4461
+ return events;
4462
+ }
4463
+ /**
4464
+ * 获取当前状态
4465
+ */
4466
+ getState() {
4467
+ return { ...this.state };
4468
+ }
4469
+ /**
4470
+ * 重置状态
4471
+ */
4472
+ reset() {
4473
+ this.state = this.adapter.createIncrementalState();
4474
+ this.buffer = "";
4475
+ this.clearBufferTimeout();
4476
+ this.stats = {
4477
+ chunksProcessed: 0,
4478
+ eventsGenerated: 0,
4479
+ errors: 0,
4480
+ retries: 0,
4481
+ startTime: Date.now(),
4482
+ lastUpdateTime: Date.now(),
4483
+ bufferSize: 0
4484
+ };
4485
+ if (this.options.debug) {
4486
+ console.log("[StreamConverter] \u72B6\u6001\u5DF2\u91CD\u7F6E");
4487
+ }
4488
+ }
4489
+ /**
4490
+ * 获取统计信息
4491
+ */
4492
+ getStats() {
4493
+ return {
4494
+ ...this.stats,
4495
+ bufferSize: this.buffer.length
4496
+ };
4497
+ }
4498
+ /**
4499
+ * 处理缓冲的数据
4500
+ */
4501
+ processBufferedData(newChunk) {
4502
+ this.buffer += newChunk;
4503
+ this.stats.bufferSize = this.buffer.length;
4504
+ const lines = this.buffer.split("\n");
4505
+ this.buffer = lines.pop() || "";
4506
+ const events = [];
4507
+ for (const line of lines) {
4508
+ if (line.startsWith("data:")) {
4509
+ const jsonStr = line.slice(5).trim();
4510
+ if (jsonStr && jsonStr !== "[DONE]") {
4511
+ const lineEvents = this.processDataLine(jsonStr);
4512
+ events.push(...lineEvents);
4513
+ } else if (jsonStr === "[DONE]") {
4514
+ const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
4515
+ events.push(...finalEvents);
4516
+ }
4517
+ }
4518
+ }
4519
+ this.resetBufferTimeout();
4520
+ return events;
4521
+ }
4522
+ /**
4523
+ * 处理单行数据
4524
+ */
4525
+ processDataLine(jsonStr, attempt = 0) {
4526
+ try {
4527
+ const chunkEvents = this.adapter.convertIncrementalChunk(jsonStr, this.state);
4528
+ if (this.options.debug && chunkEvents.length > 0) {
4529
+ console.log("[StreamConverter] \u751F\u6210\u4E8B\u4EF6:", chunkEvents.length, "\u4E2A");
4530
+ }
4531
+ return chunkEvents;
4532
+ } catch (error) {
4533
+ if (this.options.errorRecovery && attempt < (this.options.maxRetries || 3)) {
4534
+ console.warn(`[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u5931\u8D25\uFF0C\u91CD\u8BD5 ${attempt + 1}/${this.options.maxRetries}:`, error);
4535
+ this.stats.retries++;
4536
+ return this.processDataLine(jsonStr, attempt + 1);
4537
+ }
4538
+ this.stats.errors++;
4539
+ console.error("[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u6700\u7EC8\u5931\u8D25:", error, "Data:", jsonStr);
4540
+ if (this.options.onError) {
4541
+ this.options.onError(error, {
4542
+ chunk: jsonStr,
4543
+ state: this.state,
4544
+ attempt,
4545
+ totalRetries: this.stats.retries
4546
+ });
4547
+ }
4548
+ return [];
4549
+ }
4550
+ }
4551
+ /**
4552
+ * 处理块错误
4553
+ */
4554
+ handleChunkError(error, chunk) {
4555
+ this.stats.errors++;
4556
+ if (this.options.debug) {
4557
+ console.error("[StreamConverter] \u5757\u5904\u7406\u9519\u8BEF:", error.message);
4558
+ }
4559
+ if (!this.options.errorRecovery) {
4560
+ throw error;
4561
+ }
4562
+ this.state.errors.push(`Chunk processing error: ${error.message}`);
4563
+ if (this.options.onError) {
4564
+ this.options.onError(error, {
4565
+ chunk,
4566
+ state: this.state,
4567
+ totalRetries: this.stats.retries
4568
+ });
4569
+ }
4570
+ return [];
4571
+ }
4572
+ /**
4573
+ * 处理不完整的缓冲区数据
4574
+ */
4575
+ processIncompleteBuffer() {
4576
+ if (!this.buffer.trim()) {
4577
+ return [];
4578
+ }
4579
+ console.warn("[StreamConverter] \u5904\u7406\u4E0D\u5B8C\u6574\u7F13\u51B2\u533A\u6570\u636E:", this.buffer);
4580
+ if (this.buffer.startsWith("data:")) {
4581
+ const jsonStr = this.buffer.slice(5).trim();
4582
+ if (jsonStr) {
4583
+ return this.processDataLine(jsonStr);
4584
+ }
4585
+ }
4586
+ return [];
4587
+ }
4588
+ /**
4589
+ * 重置缓冲区超时
4590
+ */
4591
+ resetBufferTimeout() {
4592
+ this.clearBufferTimeout();
4593
+ if (this.options.bufferTimeout && this.options.bufferTimeout > 0) {
4594
+ this.bufferTimeout = setTimeout(() => {
4595
+ if (this.buffer.trim()) {
4596
+ console.warn("[StreamConverter] \u7F13\u51B2\u533A\u8D85\u65F6\uFF0C\u5F3A\u5236\u5904\u7406\u6570\u636E:", this.buffer);
4597
+ const events = this.processIncompleteBuffer();
4598
+ this.buffer = "";
4599
+ if (events.length > 0 && this.options.onChunkProcessed) {
4600
+ this.options.onChunkProcessed("TIMEOUT_FLUSH", events);
4601
+ }
4602
+ }
4603
+ }, this.options.bufferTimeout);
4604
+ }
4605
+ }
4606
+ /**
4607
+ * 清理缓冲区超时
4608
+ */
4609
+ clearBufferTimeout() {
4610
+ if (this.bufferTimeout) {
4611
+ clearTimeout(this.bufferTimeout);
4612
+ this.bufferTimeout = void 0;
4613
+ }
4614
+ }
4615
+ };
4616
+
4376
4617
  // src/core/o2a-sse-adapter/adapter.ts
4377
4618
  var O2ASSEAdapter = class {
4378
4619
  constructor(debugMode = false, config = {}) {
@@ -4627,6 +4868,101 @@ var O2ASSEAdapter = class {
4627
4868
  validateClaudeSSE(sseContent) {
4628
4869
  return FormatValidator2.validateClaudeSSE(sseContent);
4629
4870
  }
4871
+ /**
4872
+ * 将 OpenAI Response 流直接转换为 Anthropic SSE 流
4873
+ * 这是新增的核心流式处理方法,支持实时转换
4874
+ */
4875
+ convertResponseStream(openaiResponse, options = {}) {
4876
+ if (!openaiResponse.body) {
4877
+ throw new Error("Response body is null or undefined");
4878
+ }
4879
+ return this.convertReadableStream(openaiResponse.body, options);
4880
+ }
4881
+ /**
4882
+ * 将 ReadableStream 转换为 Anthropic SSE 流
4883
+ */
4884
+ convertReadableStream(openaiStream, options = {}) {
4885
+ const converter = this.createStreamConverter(options);
4886
+ const decoder = new TextDecoder();
4887
+ return new ReadableStream({
4888
+ async start(controller) {
4889
+ if (options.debug) {
4890
+ console.log("[O2ASSEAdapter] \u5F00\u59CB\u6D41\u5F0F\u8F6C\u6362\uFF0C\u914D\u7F6E:", options);
4891
+ }
4892
+ try {
4893
+ const initialEvents = converter.getInitialEvents();
4894
+ for (const event of initialEvents) {
4895
+ controller.enqueue(event);
4896
+ }
4897
+ } catch (error) {
4898
+ console.error("[O2ASSEAdapter] \u521D\u59CB\u5316\u5931\u8D25:", error);
4899
+ controller.error(error);
4900
+ return;
4901
+ }
4902
+ const reader = openaiStream.getReader();
4903
+ try {
4904
+ while (true) {
4905
+ const { done, value } = await reader.read();
4906
+ if (done) {
4907
+ try {
4908
+ const finalEvents = converter.finalize();
4909
+ for (const event of finalEvents) {
4910
+ controller.enqueue(event);
4911
+ }
4912
+ if (options.debug) {
4913
+ console.log("[O2ASSEAdapter] \u6D41\u5F0F\u8F6C\u6362\u5B8C\u6210\uFF0C\u7EDF\u8BA1:", converter.getStats());
4914
+ }
4915
+ } catch (error) {
4916
+ console.error("[O2ASSEAdapter] \u7ED3\u675F\u5904\u7406\u5931\u8D25:", error);
4917
+ }
4918
+ break;
4919
+ }
4920
+ const chunk = decoder.decode(value, { stream: true });
4921
+ try {
4922
+ const events = converter.processChunk(chunk);
4923
+ for (const event of events) {
4924
+ controller.enqueue(event);
4925
+ }
4926
+ } catch (error) {
4927
+ console.error("[O2ASSEAdapter] \u5757\u5904\u7406\u5931\u8D25:", error);
4928
+ if (options.errorRecovery === false) {
4929
+ controller.error(error);
4930
+ return;
4931
+ }
4932
+ if (options.onError) {
4933
+ options.onError(error, {
4934
+ chunk,
4935
+ state: converter.getState()
4936
+ });
4937
+ }
4938
+ }
4939
+ }
4940
+ } catch (error) {
4941
+ console.error("[O2ASSEAdapter] \u6D41\u5904\u7406\u5931\u8D25:", error);
4942
+ if (options.onError) {
4943
+ options.onError(error, {
4944
+ chunk: "",
4945
+ state: converter.getState()
4946
+ });
4947
+ }
4948
+ controller.error(error);
4949
+ } finally {
4950
+ controller.close();
4951
+ }
4952
+ }
4953
+ });
4954
+ }
4955
+ /**
4956
+ * 创建流式转换器实例
4957
+ * 提供更精细的流处理控制
4958
+ */
4959
+ createStreamConverter(options = {}) {
4960
+ return new StreamConverter(this, {
4961
+ modelName: options.modelName || this.config.defaultModel,
4962
+ debug: options.debug || this.debugMode,
4963
+ ...options
4964
+ });
4965
+ }
4630
4966
  /**
4631
4967
  * 应用增强功能到SSE转换
4632
4968
  * 包括输入验证、输出修复等
@@ -4698,13 +5034,49 @@ var O2ASSEAdapterStatic = {
4698
5034
  validateClaudeSSE: (sseContent) => {
4699
5035
  const adapter = new O2ASSEAdapter(false);
4700
5036
  return adapter.validateClaudeSSE(sseContent);
5037
+ },
5038
+ /**
5039
+ * 转换 Response 流为 Anthropic SSE(静态方法)
5040
+ * 新增:直接处理 Response 对象的流式转换
5041
+ */
5042
+ convertResponseStream: (openaiResponse, options = {}) => {
5043
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5044
+ defaultModel: options.modelName || "claude-sonnet-4",
5045
+ generateUniqueMessageId: !options.messageId,
5046
+ errorDataMaxLength: 500
5047
+ });
5048
+ return adapter.convertResponseStream(openaiResponse, options);
5049
+ },
5050
+ /**
5051
+ * 转换 ReadableStream 为 Anthropic SSE(静态方法)
5052
+ * 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
5053
+ */
5054
+ convertReadableStream: (openaiStream, options = {}) => {
5055
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5056
+ defaultModel: options.modelName || "claude-sonnet-4",
5057
+ generateUniqueMessageId: !options.messageId,
5058
+ errorDataMaxLength: 500
5059
+ });
5060
+ return adapter.convertReadableStream(openaiStream, options);
5061
+ },
5062
+ /**
5063
+ * 创建流式转换器(静态方法)
5064
+ * 新增:提供更精细的流处理控制
5065
+ */
5066
+ createStreamConverter: (options = {}) => {
5067
+ const adapter = new O2ASSEAdapter(options.debug || false, {
5068
+ defaultModel: options.modelName || "claude-sonnet-4",
5069
+ generateUniqueMessageId: !options.messageId,
5070
+ errorDataMaxLength: 500
5071
+ });
5072
+ return adapter.createStreamConverter(options);
4701
5073
  }
4702
5074
  };
4703
5075
 
4704
5076
  // src/core/standard/standard-protocol-adapter.ts
4705
5077
  var StandardProtocolAdapter = class {
4706
5078
  constructor(options = {}) {
4707
- this.debugMode = options.debugMode || false;
5079
+ this.debugMode = options.debugMode !== void 0 ? options.debugMode : true;
4708
5080
  this.sseAdapter = new O2ASSEAdapter(this.debugMode);
4709
5081
  }
4710
5082
  /**
@@ -4781,6 +5153,8 @@ var StandardProtocolAdapter = class {
4781
5153
  };
4782
5154
  let currentTextContent = "";
4783
5155
  const toolCalls = /* @__PURE__ */ new Map();
5156
+ const toolInputBuffers = /* @__PURE__ */ new Map();
5157
+ const indexToToolId = /* @__PURE__ */ new Map();
4784
5158
  let processedDataLines = 0;
4785
5159
  for (const line of lines) {
4786
5160
  if (line.startsWith("data: ")) {
@@ -4793,15 +5167,22 @@ var StandardProtocolAdapter = class {
4793
5167
  if (data.type === "content_block_start") {
4794
5168
  const contentBlock = data.content_block;
4795
5169
  if (contentBlock.type === "tool_use") {
5170
+ const toolIndex = data.index;
4796
5171
  toolCalls.set(contentBlock.id, {
4797
5172
  type: "tool_use",
4798
5173
  id: contentBlock.id,
4799
5174
  name: contentBlock.name,
4800
5175
  input: contentBlock.input || {}
5176
+ // 初始为空对象,稍后会被更新
5177
+ });
5178
+ toolInputBuffers.set(toolIndex, "");
5179
+ indexToToolId.set(toolIndex, contentBlock.id);
5180
+ console.log("\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", {
5181
+ index: toolIndex,
5182
+ toolId: contentBlock.id,
5183
+ name: contentBlock.name,
5184
+ indexToToolIdSize: indexToToolId.size
4801
5185
  });
4802
- if (this.debugMode) {
4803
- console.log("\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", contentBlock);
4804
- }
4805
5186
  }
4806
5187
  }
4807
5188
  if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
@@ -4811,6 +5192,46 @@ var StandardProtocolAdapter = class {
4811
5192
  }
4812
5193
  }
4813
5194
  if (data.type === "content_block_delta" && data.delta?.type === "input_json_delta") {
5195
+ const toolIndex = data.index;
5196
+ const toolId = indexToToolId.get(toolIndex);
5197
+ console.log(`\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u68C0\u6D4B\u5230input_json_delta\u4E8B\u4EF6\uFF01`, {
5198
+ toolIndex,
5199
+ toolId: toolId || "NOT_FOUND",
5200
+ delta: data.delta.partial_json
5201
+ });
5202
+ if (toolId) {
5203
+ const currentBuffer = toolInputBuffers.get(toolIndex) || "";
5204
+ const newBuffer = currentBuffer + data.delta.partial_json;
5205
+ toolInputBuffers.set(toolIndex, newBuffer);
5206
+ console.log(`\u{1F527} [StandardProtocolAdapter] \u7D2F\u79EF\u5DE5\u5177\u53C2\u6570 (index=${toolIndex}, id=${toolId}):`, {
5207
+ delta: data.delta.partial_json,
5208
+ bufferLength: newBuffer.length
5209
+ });
5210
+ } else {
5211
+ console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u627E\u4E0D\u5230toolId for index=${toolIndex}`);
5212
+ }
5213
+ }
5214
+ if (data.type === "content_block_stop") {
5215
+ const toolIndex = data.index;
5216
+ const toolId = indexToToolId.get(toolIndex);
5217
+ if (toolId) {
5218
+ const jsonBuffer = toolInputBuffers.get(toolIndex);
5219
+ const tool = toolCalls.get(toolId);
5220
+ if (jsonBuffer && tool) {
5221
+ try {
5222
+ const parsedInput = JSON.parse(jsonBuffer);
5223
+ tool.input = parsedInput;
5224
+ if (this.debugMode) {
5225
+ console.log(`\u2705 [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570\u89E3\u6790\u5B8C\u6210 (index=${toolIndex}, id=${toolId}):`, parsedInput);
5226
+ }
5227
+ } catch (parseError) {
5228
+ console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570JSON\u89E3\u6790\u5931\u8D25 (index=${toolIndex}, id=${toolId}):`, {
5229
+ buffer: jsonBuffer,
5230
+ error: parseError
5231
+ });
5232
+ }
5233
+ }
5234
+ }
4814
5235
  }
4815
5236
  if (data.type === "message_delta") {
4816
5237
  if (data.delta?.stop_reason) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-protocol-adapters",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.3",
4
4
  "description": "Universal AI Protocol Converter - OpenAI ⇄ Anthropic with full TypeScript support",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",