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 +7 -7
- package/dist/index.d.mts +113 -1
- package/dist/index.d.ts +113 -1
- package/dist/index.js +425 -4
- package/dist/index.mjs +425 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ai-protocol-adapters
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/js/ai-protocol-adapters)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
## 📦 安装
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npm install
|
|
22
|
+
npm install ai-protocol-adapters
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
yarn add
|
|
26
|
+
yarn add ai-protocol-adapters
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
pnpm add
|
|
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 '
|
|
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 '
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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