ai-protocol-adapters 1.0.0-alpha.2 → 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/index.d.mts +138 -26
- package/dist/index.d.ts +138 -26
- package/dist/index.js +470 -7
- package/dist/index.mjs +470 -7
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -581,17 +581,32 @@ var StreamingProtocolAdapter = class {
|
|
|
581
581
|
processToolCalls(toolCalls, state, sseLines) {
|
|
582
582
|
for (const toolCall of toolCalls) {
|
|
583
583
|
if (toolCall.id && toolCall.function?.name) {
|
|
584
|
+
const toolArgs = toolCall.function.arguments || "";
|
|
584
585
|
const toolData = {
|
|
585
586
|
id: toolCall.id,
|
|
586
587
|
name: toolCall.function.name,
|
|
587
|
-
input:
|
|
588
|
+
input: toolArgs
|
|
588
589
|
};
|
|
589
590
|
state.toolCallsMap.set(toolCall.id, toolData);
|
|
591
|
+
const blockIndex = state.completedToolCalls.length + 1;
|
|
590
592
|
sseLines.push(
|
|
591
593
|
"event: content_block_start",
|
|
592
|
-
`data: {"type":"content_block_start","index":${
|
|
594
|
+
`data: {"type":"content_block_start","index":${blockIndex},"content_block":{"type":"tool_use","id":"${toolCall.id}","name":"${toolCall.function.name}","input":{}}}`,
|
|
593
595
|
""
|
|
594
596
|
);
|
|
597
|
+
if (toolArgs) {
|
|
598
|
+
sseLines.push(
|
|
599
|
+
"event: content_block_delta",
|
|
600
|
+
`data: {"type":"content_block_delta","index":${blockIndex},"delta":{"type":"input_json_delta","partial_json":${JSON.stringify(toolArgs)}}}`,
|
|
601
|
+
""
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
sseLines.push(
|
|
605
|
+
"event: content_block_stop",
|
|
606
|
+
`data: {"type":"content_block_stop","index":${blockIndex}}`,
|
|
607
|
+
""
|
|
608
|
+
);
|
|
609
|
+
state.completedToolCalls.push(toolCall.id);
|
|
595
610
|
}
|
|
596
611
|
}
|
|
597
612
|
}
|
|
@@ -616,9 +631,10 @@ var StreamingProtocolAdapter = class {
|
|
|
616
631
|
""
|
|
617
632
|
);
|
|
618
633
|
}
|
|
634
|
+
const stopReason = state.completedToolCalls.length > 0 ? "tool_use" : "end_turn";
|
|
619
635
|
sseLines.push(
|
|
620
636
|
"event: message_delta",
|
|
621
|
-
`data: {"type":"message_delta","delta":{"stop_reason":"
|
|
637
|
+
`data: {"type":"message_delta","delta":{"stop_reason":"${stopReason}","stop_sequence":null},"usage":{"output_tokens":${state.usage.output_tokens}}}`,
|
|
622
638
|
"",
|
|
623
639
|
"event: message_stop",
|
|
624
640
|
'data: {"type":"message_stop"}',
|
|
@@ -4151,15 +4167,28 @@ var ToolCallProcessor = class _ToolCallProcessor {
|
|
|
4151
4167
|
* 处理增量工具调用
|
|
4152
4168
|
*/
|
|
4153
4169
|
static processIncrementalToolCalls(toolCalls, state, sseLines) {
|
|
4170
|
+
console.log("\u{1F50D}\u{1F50D}\u{1F50D} [ToolProcessor] processIncrementalToolCalls called with:", JSON.stringify(toolCalls, null, 2));
|
|
4154
4171
|
for (const toolCall of toolCalls) {
|
|
4155
4172
|
const toolId = toolCall.id;
|
|
4156
4173
|
const toolName = toolCall.function?.name;
|
|
4157
4174
|
const toolArgs = toolCall.function?.arguments;
|
|
4175
|
+
console.log("\u{1F50D} [ToolProcessor] Processing tool call:", {
|
|
4176
|
+
toolId,
|
|
4177
|
+
toolName,
|
|
4178
|
+
toolArgs: toolArgs || "UNDEFINED",
|
|
4179
|
+
toolArgsType: typeof toolArgs,
|
|
4180
|
+
toolArgsLength: toolArgs?.length || 0,
|
|
4181
|
+
hasArgs: !!toolArgs
|
|
4182
|
+
});
|
|
4158
4183
|
if (toolName && toolId && !state.toolCallsMap.has(toolId)) {
|
|
4184
|
+
console.log("\u2705 [ToolProcessor] Starting new tool call:", toolName);
|
|
4159
4185
|
_ToolCallProcessor.processToolCallStart(toolId, toolName, state, sseLines);
|
|
4160
4186
|
}
|
|
4161
4187
|
if (toolArgs) {
|
|
4188
|
+
console.log("\u2705 [ToolProcessor] Processing tool args, calling processToolArgs");
|
|
4162
4189
|
_ToolCallProcessor.processToolArgs(toolId, toolArgs, state, sseLines);
|
|
4190
|
+
} else {
|
|
4191
|
+
console.warn("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F [ToolProcessor] No tool args to process! This will result in empty input!");
|
|
4163
4192
|
}
|
|
4164
4193
|
}
|
|
4165
4194
|
}
|
|
@@ -4167,15 +4196,28 @@ var ToolCallProcessor = class _ToolCallProcessor {
|
|
|
4167
4196
|
* 处理工具调用
|
|
4168
4197
|
*/
|
|
4169
4198
|
static processBatchToolCalls(toolCalls, state, sseLines) {
|
|
4199
|
+
console.log("\u{1F50D}\u{1F50D}\u{1F50D} [ToolProcessor] processBatchToolCalls called with:", JSON.stringify(toolCalls, null, 2));
|
|
4170
4200
|
for (const toolCall of toolCalls) {
|
|
4171
4201
|
const toolId = toolCall.id;
|
|
4172
4202
|
const toolName = toolCall.function?.name;
|
|
4173
4203
|
const toolArgs = toolCall.function?.arguments;
|
|
4204
|
+
console.log("\u{1F50D} [ToolProcessor] Processing batch tool call:", {
|
|
4205
|
+
toolId,
|
|
4206
|
+
toolName,
|
|
4207
|
+
toolArgs: toolArgs || "UNDEFINED",
|
|
4208
|
+
toolArgsType: typeof toolArgs,
|
|
4209
|
+
toolArgsLength: toolArgs?.length || 0,
|
|
4210
|
+
hasArgs: !!toolArgs
|
|
4211
|
+
});
|
|
4174
4212
|
if (toolName && toolId && !state.toolCallsMap.has(toolId)) {
|
|
4213
|
+
console.log("\u2705 [ToolProcessor] Starting new batch tool call:", toolName);
|
|
4175
4214
|
_ToolCallProcessor.processToolCallStart(toolId, toolName, state, sseLines);
|
|
4176
4215
|
}
|
|
4177
4216
|
if (toolArgs) {
|
|
4217
|
+
console.log("\u2705 [ToolProcessor] Processing batch tool args, calling processToolArgs");
|
|
4178
4218
|
_ToolCallProcessor.processToolArgs(toolId, toolArgs, state, sseLines);
|
|
4219
|
+
} else {
|
|
4220
|
+
console.warn("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F [ToolProcessor] No batch tool args to process! This will result in empty input!");
|
|
4179
4221
|
}
|
|
4180
4222
|
}
|
|
4181
4223
|
}
|
|
@@ -4373,6 +4415,247 @@ function generateMessageId() {
|
|
|
4373
4415
|
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
4374
4416
|
}
|
|
4375
4417
|
|
|
4418
|
+
// src/core/o2a-sse-adapter/stream-converter.ts
|
|
4419
|
+
var StreamConverter = class {
|
|
4420
|
+
constructor(adapter, options = {}) {
|
|
4421
|
+
this.buffer = "";
|
|
4422
|
+
this.adapter = adapter;
|
|
4423
|
+
this.options = {
|
|
4424
|
+
bufferTimeout: 5e3,
|
|
4425
|
+
errorRecovery: true,
|
|
4426
|
+
maxRetries: 3,
|
|
4427
|
+
debug: false,
|
|
4428
|
+
...options
|
|
4429
|
+
};
|
|
4430
|
+
this.state = this.adapter.createIncrementalState();
|
|
4431
|
+
this.stats = {
|
|
4432
|
+
chunksProcessed: 0,
|
|
4433
|
+
eventsGenerated: 0,
|
|
4434
|
+
errors: 0,
|
|
4435
|
+
retries: 0,
|
|
4436
|
+
startTime: Date.now(),
|
|
4437
|
+
lastUpdateTime: Date.now(),
|
|
4438
|
+
bufferSize: 0
|
|
4439
|
+
};
|
|
4440
|
+
if (this.options.debug) {
|
|
4441
|
+
console.log("[StreamConverter] \u5DF2\u521D\u59CB\u5316\uFF0C\u914D\u7F6E:", this.options);
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
/**
|
|
4445
|
+
* 获取初始事件
|
|
4446
|
+
*/
|
|
4447
|
+
getInitialEvents() {
|
|
4448
|
+
const events = this.adapter.getInitialSSEEvents(
|
|
4449
|
+
this.options.modelName,
|
|
4450
|
+
this.options.messageId
|
|
4451
|
+
);
|
|
4452
|
+
this.stats.eventsGenerated += events.length;
|
|
4453
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4454
|
+
if (this.options.debug) {
|
|
4455
|
+
console.log("[StreamConverter] \u751F\u6210\u521D\u59CB\u4E8B\u4EF6:", events.length, "\u4E2A");
|
|
4456
|
+
}
|
|
4457
|
+
return events;
|
|
4458
|
+
}
|
|
4459
|
+
/**
|
|
4460
|
+
* 处理单个数据块
|
|
4461
|
+
*/
|
|
4462
|
+
processChunk(chunk) {
|
|
4463
|
+
this.stats.chunksProcessed++;
|
|
4464
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4465
|
+
if (this.options.debug) {
|
|
4466
|
+
console.log("[StreamConverter] \u5904\u7406\u6570\u636E\u5757:", chunk.substring(0, 100) + "...");
|
|
4467
|
+
}
|
|
4468
|
+
try {
|
|
4469
|
+
const events = this.processBufferedData(chunk);
|
|
4470
|
+
this.stats.eventsGenerated += events.length;
|
|
4471
|
+
if (this.options.onChunkProcessed) {
|
|
4472
|
+
this.options.onChunkProcessed(chunk, events);
|
|
4473
|
+
}
|
|
4474
|
+
return events;
|
|
4475
|
+
} catch (error) {
|
|
4476
|
+
return this.handleChunkError(error, chunk);
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
/**
|
|
4480
|
+
* 结束流处理
|
|
4481
|
+
*/
|
|
4482
|
+
finalize() {
|
|
4483
|
+
if (this.options.debug) {
|
|
4484
|
+
console.log("[StreamConverter] \u7ED3\u675F\u6D41\u5904\u7406\uFF0C\u7F13\u51B2\u533A\u5927\u5C0F:", this.buffer.length);
|
|
4485
|
+
}
|
|
4486
|
+
let events = [];
|
|
4487
|
+
if (this.buffer.trim()) {
|
|
4488
|
+
console.warn("[StreamConverter] \u7F13\u51B2\u533A\u4E2D\u6709\u672A\u5904\u7406\u6570\u636E\uFF0C\u5F3A\u5236\u5904\u7406:", this.buffer);
|
|
4489
|
+
events = this.processIncompleteBuffer();
|
|
4490
|
+
}
|
|
4491
|
+
try {
|
|
4492
|
+
const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
|
|
4493
|
+
events.push(...finalEvents);
|
|
4494
|
+
this.stats.eventsGenerated += finalEvents.length;
|
|
4495
|
+
} catch (error) {
|
|
4496
|
+
console.error("[StreamConverter] \u5904\u7406\u7ED3\u675F\u4E8B\u4EF6\u5931\u8D25:", error);
|
|
4497
|
+
}
|
|
4498
|
+
this.clearBufferTimeout();
|
|
4499
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4500
|
+
if (this.options.debug) {
|
|
4501
|
+
console.log("[StreamConverter] \u6D41\u5904\u7406\u5B8C\u6210\uFF0C\u7EDF\u8BA1\u4FE1\u606F:", this.stats);
|
|
4502
|
+
}
|
|
4503
|
+
return events;
|
|
4504
|
+
}
|
|
4505
|
+
/**
|
|
4506
|
+
* 获取当前状态
|
|
4507
|
+
*/
|
|
4508
|
+
getState() {
|
|
4509
|
+
return { ...this.state };
|
|
4510
|
+
}
|
|
4511
|
+
/**
|
|
4512
|
+
* 重置状态
|
|
4513
|
+
*/
|
|
4514
|
+
reset() {
|
|
4515
|
+
this.state = this.adapter.createIncrementalState();
|
|
4516
|
+
this.buffer = "";
|
|
4517
|
+
this.clearBufferTimeout();
|
|
4518
|
+
this.stats = {
|
|
4519
|
+
chunksProcessed: 0,
|
|
4520
|
+
eventsGenerated: 0,
|
|
4521
|
+
errors: 0,
|
|
4522
|
+
retries: 0,
|
|
4523
|
+
startTime: Date.now(),
|
|
4524
|
+
lastUpdateTime: Date.now(),
|
|
4525
|
+
bufferSize: 0
|
|
4526
|
+
};
|
|
4527
|
+
if (this.options.debug) {
|
|
4528
|
+
console.log("[StreamConverter] \u72B6\u6001\u5DF2\u91CD\u7F6E");
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
/**
|
|
4532
|
+
* 获取统计信息
|
|
4533
|
+
*/
|
|
4534
|
+
getStats() {
|
|
4535
|
+
return {
|
|
4536
|
+
...this.stats,
|
|
4537
|
+
bufferSize: this.buffer.length
|
|
4538
|
+
};
|
|
4539
|
+
}
|
|
4540
|
+
/**
|
|
4541
|
+
* 处理缓冲的数据
|
|
4542
|
+
*/
|
|
4543
|
+
processBufferedData(newChunk) {
|
|
4544
|
+
this.buffer += newChunk;
|
|
4545
|
+
this.stats.bufferSize = this.buffer.length;
|
|
4546
|
+
const lines = this.buffer.split("\n");
|
|
4547
|
+
this.buffer = lines.pop() || "";
|
|
4548
|
+
const events = [];
|
|
4549
|
+
for (const line of lines) {
|
|
4550
|
+
if (line.startsWith("data:")) {
|
|
4551
|
+
const jsonStr = line.slice(5).trim();
|
|
4552
|
+
if (jsonStr && jsonStr !== "[DONE]") {
|
|
4553
|
+
const lineEvents = this.processDataLine(jsonStr);
|
|
4554
|
+
events.push(...lineEvents);
|
|
4555
|
+
} else if (jsonStr === "[DONE]") {
|
|
4556
|
+
const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
|
|
4557
|
+
events.push(...finalEvents);
|
|
4558
|
+
}
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
this.resetBufferTimeout();
|
|
4562
|
+
return events;
|
|
4563
|
+
}
|
|
4564
|
+
/**
|
|
4565
|
+
* 处理单行数据
|
|
4566
|
+
*/
|
|
4567
|
+
processDataLine(jsonStr, attempt = 0) {
|
|
4568
|
+
try {
|
|
4569
|
+
const chunkEvents = this.adapter.convertIncrementalChunk(jsonStr, this.state);
|
|
4570
|
+
if (this.options.debug && chunkEvents.length > 0) {
|
|
4571
|
+
console.log("[StreamConverter] \u751F\u6210\u4E8B\u4EF6:", chunkEvents.length, "\u4E2A");
|
|
4572
|
+
}
|
|
4573
|
+
return chunkEvents;
|
|
4574
|
+
} catch (error) {
|
|
4575
|
+
if (this.options.errorRecovery && attempt < (this.options.maxRetries || 3)) {
|
|
4576
|
+
console.warn(`[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u5931\u8D25\uFF0C\u91CD\u8BD5 ${attempt + 1}/${this.options.maxRetries}:`, error);
|
|
4577
|
+
this.stats.retries++;
|
|
4578
|
+
return this.processDataLine(jsonStr, attempt + 1);
|
|
4579
|
+
}
|
|
4580
|
+
this.stats.errors++;
|
|
4581
|
+
console.error("[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u6700\u7EC8\u5931\u8D25:", error, "Data:", jsonStr);
|
|
4582
|
+
if (this.options.onError) {
|
|
4583
|
+
this.options.onError(error, {
|
|
4584
|
+
chunk: jsonStr,
|
|
4585
|
+
state: this.state,
|
|
4586
|
+
attempt,
|
|
4587
|
+
totalRetries: this.stats.retries
|
|
4588
|
+
});
|
|
4589
|
+
}
|
|
4590
|
+
return [];
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
/**
|
|
4594
|
+
* 处理块错误
|
|
4595
|
+
*/
|
|
4596
|
+
handleChunkError(error, chunk) {
|
|
4597
|
+
this.stats.errors++;
|
|
4598
|
+
if (this.options.debug) {
|
|
4599
|
+
console.error("[StreamConverter] \u5757\u5904\u7406\u9519\u8BEF:", error.message);
|
|
4600
|
+
}
|
|
4601
|
+
if (!this.options.errorRecovery) {
|
|
4602
|
+
throw error;
|
|
4603
|
+
}
|
|
4604
|
+
this.state.errors.push(`Chunk processing error: ${error.message}`);
|
|
4605
|
+
if (this.options.onError) {
|
|
4606
|
+
this.options.onError(error, {
|
|
4607
|
+
chunk,
|
|
4608
|
+
state: this.state,
|
|
4609
|
+
totalRetries: this.stats.retries
|
|
4610
|
+
});
|
|
4611
|
+
}
|
|
4612
|
+
return [];
|
|
4613
|
+
}
|
|
4614
|
+
/**
|
|
4615
|
+
* 处理不完整的缓冲区数据
|
|
4616
|
+
*/
|
|
4617
|
+
processIncompleteBuffer() {
|
|
4618
|
+
if (!this.buffer.trim()) {
|
|
4619
|
+
return [];
|
|
4620
|
+
}
|
|
4621
|
+
console.warn("[StreamConverter] \u5904\u7406\u4E0D\u5B8C\u6574\u7F13\u51B2\u533A\u6570\u636E:", this.buffer);
|
|
4622
|
+
if (this.buffer.startsWith("data:")) {
|
|
4623
|
+
const jsonStr = this.buffer.slice(5).trim();
|
|
4624
|
+
if (jsonStr) {
|
|
4625
|
+
return this.processDataLine(jsonStr);
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
return [];
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* 重置缓冲区超时
|
|
4632
|
+
*/
|
|
4633
|
+
resetBufferTimeout() {
|
|
4634
|
+
this.clearBufferTimeout();
|
|
4635
|
+
if (this.options.bufferTimeout && this.options.bufferTimeout > 0) {
|
|
4636
|
+
this.bufferTimeout = setTimeout(() => {
|
|
4637
|
+
if (this.buffer.trim()) {
|
|
4638
|
+
console.warn("[StreamConverter] \u7F13\u51B2\u533A\u8D85\u65F6\uFF0C\u5F3A\u5236\u5904\u7406\u6570\u636E:", this.buffer);
|
|
4639
|
+
const events = this.processIncompleteBuffer();
|
|
4640
|
+
this.buffer = "";
|
|
4641
|
+
if (events.length > 0 && this.options.onChunkProcessed) {
|
|
4642
|
+
this.options.onChunkProcessed("TIMEOUT_FLUSH", events);
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
}, this.options.bufferTimeout);
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
/**
|
|
4649
|
+
* 清理缓冲区超时
|
|
4650
|
+
*/
|
|
4651
|
+
clearBufferTimeout() {
|
|
4652
|
+
if (this.bufferTimeout) {
|
|
4653
|
+
clearTimeout(this.bufferTimeout);
|
|
4654
|
+
this.bufferTimeout = void 0;
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
};
|
|
4658
|
+
|
|
4376
4659
|
// src/core/o2a-sse-adapter/adapter.ts
|
|
4377
4660
|
var O2ASSEAdapter = class {
|
|
4378
4661
|
constructor(debugMode = false, config = {}) {
|
|
@@ -4627,6 +4910,101 @@ var O2ASSEAdapter = class {
|
|
|
4627
4910
|
validateClaudeSSE(sseContent) {
|
|
4628
4911
|
return FormatValidator2.validateClaudeSSE(sseContent);
|
|
4629
4912
|
}
|
|
4913
|
+
/**
|
|
4914
|
+
* 将 OpenAI Response 流直接转换为 Anthropic SSE 流
|
|
4915
|
+
* 这是新增的核心流式处理方法,支持实时转换
|
|
4916
|
+
*/
|
|
4917
|
+
convertResponseStream(openaiResponse, options = {}) {
|
|
4918
|
+
if (!openaiResponse.body) {
|
|
4919
|
+
throw new Error("Response body is null or undefined");
|
|
4920
|
+
}
|
|
4921
|
+
return this.convertReadableStream(openaiResponse.body, options);
|
|
4922
|
+
}
|
|
4923
|
+
/**
|
|
4924
|
+
* 将 ReadableStream 转换为 Anthropic SSE 流
|
|
4925
|
+
*/
|
|
4926
|
+
convertReadableStream(openaiStream, options = {}) {
|
|
4927
|
+
const converter = this.createStreamConverter(options);
|
|
4928
|
+
const decoder = new TextDecoder();
|
|
4929
|
+
return new ReadableStream({
|
|
4930
|
+
async start(controller) {
|
|
4931
|
+
if (options.debug) {
|
|
4932
|
+
console.log("[O2ASSEAdapter] \u5F00\u59CB\u6D41\u5F0F\u8F6C\u6362\uFF0C\u914D\u7F6E:", options);
|
|
4933
|
+
}
|
|
4934
|
+
try {
|
|
4935
|
+
const initialEvents = converter.getInitialEvents();
|
|
4936
|
+
for (const event of initialEvents) {
|
|
4937
|
+
controller.enqueue(event);
|
|
4938
|
+
}
|
|
4939
|
+
} catch (error) {
|
|
4940
|
+
console.error("[O2ASSEAdapter] \u521D\u59CB\u5316\u5931\u8D25:", error);
|
|
4941
|
+
controller.error(error);
|
|
4942
|
+
return;
|
|
4943
|
+
}
|
|
4944
|
+
const reader = openaiStream.getReader();
|
|
4945
|
+
try {
|
|
4946
|
+
while (true) {
|
|
4947
|
+
const { done, value } = await reader.read();
|
|
4948
|
+
if (done) {
|
|
4949
|
+
try {
|
|
4950
|
+
const finalEvents = converter.finalize();
|
|
4951
|
+
for (const event of finalEvents) {
|
|
4952
|
+
controller.enqueue(event);
|
|
4953
|
+
}
|
|
4954
|
+
if (options.debug) {
|
|
4955
|
+
console.log("[O2ASSEAdapter] \u6D41\u5F0F\u8F6C\u6362\u5B8C\u6210\uFF0C\u7EDF\u8BA1:", converter.getStats());
|
|
4956
|
+
}
|
|
4957
|
+
} catch (error) {
|
|
4958
|
+
console.error("[O2ASSEAdapter] \u7ED3\u675F\u5904\u7406\u5931\u8D25:", error);
|
|
4959
|
+
}
|
|
4960
|
+
break;
|
|
4961
|
+
}
|
|
4962
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
4963
|
+
try {
|
|
4964
|
+
const events = converter.processChunk(chunk);
|
|
4965
|
+
for (const event of events) {
|
|
4966
|
+
controller.enqueue(event);
|
|
4967
|
+
}
|
|
4968
|
+
} catch (error) {
|
|
4969
|
+
console.error("[O2ASSEAdapter] \u5757\u5904\u7406\u5931\u8D25:", error);
|
|
4970
|
+
if (options.errorRecovery === false) {
|
|
4971
|
+
controller.error(error);
|
|
4972
|
+
return;
|
|
4973
|
+
}
|
|
4974
|
+
if (options.onError) {
|
|
4975
|
+
options.onError(error, {
|
|
4976
|
+
chunk,
|
|
4977
|
+
state: converter.getState()
|
|
4978
|
+
});
|
|
4979
|
+
}
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
} catch (error) {
|
|
4983
|
+
console.error("[O2ASSEAdapter] \u6D41\u5904\u7406\u5931\u8D25:", error);
|
|
4984
|
+
if (options.onError) {
|
|
4985
|
+
options.onError(error, {
|
|
4986
|
+
chunk: "",
|
|
4987
|
+
state: converter.getState()
|
|
4988
|
+
});
|
|
4989
|
+
}
|
|
4990
|
+
controller.error(error);
|
|
4991
|
+
} finally {
|
|
4992
|
+
controller.close();
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4995
|
+
});
|
|
4996
|
+
}
|
|
4997
|
+
/**
|
|
4998
|
+
* 创建流式转换器实例
|
|
4999
|
+
* 提供更精细的流处理控制
|
|
5000
|
+
*/
|
|
5001
|
+
createStreamConverter(options = {}) {
|
|
5002
|
+
return new StreamConverter(this, {
|
|
5003
|
+
modelName: options.modelName || this.config.defaultModel,
|
|
5004
|
+
debug: options.debug || this.debugMode,
|
|
5005
|
+
...options
|
|
5006
|
+
});
|
|
5007
|
+
}
|
|
4630
5008
|
/**
|
|
4631
5009
|
* 应用增强功能到SSE转换
|
|
4632
5010
|
* 包括输入验证、输出修复等
|
|
@@ -4698,13 +5076,49 @@ var O2ASSEAdapterStatic = {
|
|
|
4698
5076
|
validateClaudeSSE: (sseContent) => {
|
|
4699
5077
|
const adapter = new O2ASSEAdapter(false);
|
|
4700
5078
|
return adapter.validateClaudeSSE(sseContent);
|
|
5079
|
+
},
|
|
5080
|
+
/**
|
|
5081
|
+
* 转换 Response 流为 Anthropic SSE(静态方法)
|
|
5082
|
+
* 新增:直接处理 Response 对象的流式转换
|
|
5083
|
+
*/
|
|
5084
|
+
convertResponseStream: (openaiResponse, options = {}) => {
|
|
5085
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5086
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5087
|
+
generateUniqueMessageId: !options.messageId,
|
|
5088
|
+
errorDataMaxLength: 500
|
|
5089
|
+
});
|
|
5090
|
+
return adapter.convertResponseStream(openaiResponse, options);
|
|
5091
|
+
},
|
|
5092
|
+
/**
|
|
5093
|
+
* 转换 ReadableStream 为 Anthropic SSE(静态方法)
|
|
5094
|
+
* 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
|
|
5095
|
+
*/
|
|
5096
|
+
convertReadableStream: (openaiStream, options = {}) => {
|
|
5097
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5098
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5099
|
+
generateUniqueMessageId: !options.messageId,
|
|
5100
|
+
errorDataMaxLength: 500
|
|
5101
|
+
});
|
|
5102
|
+
return adapter.convertReadableStream(openaiStream, options);
|
|
5103
|
+
},
|
|
5104
|
+
/**
|
|
5105
|
+
* 创建流式转换器(静态方法)
|
|
5106
|
+
* 新增:提供更精细的流处理控制
|
|
5107
|
+
*/
|
|
5108
|
+
createStreamConverter: (options = {}) => {
|
|
5109
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5110
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5111
|
+
generateUniqueMessageId: !options.messageId,
|
|
5112
|
+
errorDataMaxLength: 500
|
|
5113
|
+
});
|
|
5114
|
+
return adapter.createStreamConverter(options);
|
|
4701
5115
|
}
|
|
4702
5116
|
};
|
|
4703
5117
|
|
|
4704
5118
|
// src/core/standard/standard-protocol-adapter.ts
|
|
4705
5119
|
var StandardProtocolAdapter = class {
|
|
4706
5120
|
constructor(options = {}) {
|
|
4707
|
-
this.debugMode = options.debugMode
|
|
5121
|
+
this.debugMode = options.debugMode !== void 0 ? options.debugMode : true;
|
|
4708
5122
|
this.sseAdapter = new O2ASSEAdapter(this.debugMode);
|
|
4709
5123
|
}
|
|
4710
5124
|
/**
|
|
@@ -4781,6 +5195,8 @@ var StandardProtocolAdapter = class {
|
|
|
4781
5195
|
};
|
|
4782
5196
|
let currentTextContent = "";
|
|
4783
5197
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
5198
|
+
const toolInputBuffers = /* @__PURE__ */ new Map();
|
|
5199
|
+
const indexToToolId = /* @__PURE__ */ new Map();
|
|
4784
5200
|
let processedDataLines = 0;
|
|
4785
5201
|
for (const line of lines) {
|
|
4786
5202
|
if (line.startsWith("data: ")) {
|
|
@@ -4793,15 +5209,22 @@ var StandardProtocolAdapter = class {
|
|
|
4793
5209
|
if (data.type === "content_block_start") {
|
|
4794
5210
|
const contentBlock = data.content_block;
|
|
4795
5211
|
if (contentBlock.type === "tool_use") {
|
|
5212
|
+
const toolIndex = data.index;
|
|
4796
5213
|
toolCalls.set(contentBlock.id, {
|
|
4797
5214
|
type: "tool_use",
|
|
4798
5215
|
id: contentBlock.id,
|
|
4799
5216
|
name: contentBlock.name,
|
|
4800
5217
|
input: contentBlock.input || {}
|
|
5218
|
+
// 初始为空对象,稍后会被更新
|
|
5219
|
+
});
|
|
5220
|
+
toolInputBuffers.set(toolIndex, "");
|
|
5221
|
+
indexToToolId.set(toolIndex, contentBlock.id);
|
|
5222
|
+
console.log("\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", {
|
|
5223
|
+
index: toolIndex,
|
|
5224
|
+
toolId: contentBlock.id,
|
|
5225
|
+
name: contentBlock.name,
|
|
5226
|
+
indexToToolIdSize: indexToToolId.size
|
|
4801
5227
|
});
|
|
4802
|
-
if (this.debugMode) {
|
|
4803
|
-
console.log("\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", contentBlock);
|
|
4804
|
-
}
|
|
4805
5228
|
}
|
|
4806
5229
|
}
|
|
4807
5230
|
if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
|
|
@@ -4811,6 +5234,46 @@ var StandardProtocolAdapter = class {
|
|
|
4811
5234
|
}
|
|
4812
5235
|
}
|
|
4813
5236
|
if (data.type === "content_block_delta" && data.delta?.type === "input_json_delta") {
|
|
5237
|
+
const toolIndex = data.index;
|
|
5238
|
+
const toolId = indexToToolId.get(toolIndex);
|
|
5239
|
+
console.log(`\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u68C0\u6D4B\u5230input_json_delta\u4E8B\u4EF6\uFF01`, {
|
|
5240
|
+
toolIndex,
|
|
5241
|
+
toolId: toolId || "NOT_FOUND",
|
|
5242
|
+
delta: data.delta.partial_json
|
|
5243
|
+
});
|
|
5244
|
+
if (toolId) {
|
|
5245
|
+
const currentBuffer = toolInputBuffers.get(toolIndex) || "";
|
|
5246
|
+
const newBuffer = currentBuffer + data.delta.partial_json;
|
|
5247
|
+
toolInputBuffers.set(toolIndex, newBuffer);
|
|
5248
|
+
console.log(`\u{1F527} [StandardProtocolAdapter] \u7D2F\u79EF\u5DE5\u5177\u53C2\u6570 (index=${toolIndex}, id=${toolId}):`, {
|
|
5249
|
+
delta: data.delta.partial_json,
|
|
5250
|
+
bufferLength: newBuffer.length
|
|
5251
|
+
});
|
|
5252
|
+
} else {
|
|
5253
|
+
console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u627E\u4E0D\u5230toolId for index=${toolIndex}`);
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
if (data.type === "content_block_stop") {
|
|
5257
|
+
const toolIndex = data.index;
|
|
5258
|
+
const toolId = indexToToolId.get(toolIndex);
|
|
5259
|
+
if (toolId) {
|
|
5260
|
+
const jsonBuffer = toolInputBuffers.get(toolIndex);
|
|
5261
|
+
const tool = toolCalls.get(toolId);
|
|
5262
|
+
if (jsonBuffer && tool) {
|
|
5263
|
+
try {
|
|
5264
|
+
const parsedInput = JSON.parse(jsonBuffer);
|
|
5265
|
+
tool.input = parsedInput;
|
|
5266
|
+
if (this.debugMode) {
|
|
5267
|
+
console.log(`\u2705 [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570\u89E3\u6790\u5B8C\u6210 (index=${toolIndex}, id=${toolId}):`, parsedInput);
|
|
5268
|
+
}
|
|
5269
|
+
} catch (parseError) {
|
|
5270
|
+
console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570JSON\u89E3\u6790\u5931\u8D25 (index=${toolIndex}, id=${toolId}):`, {
|
|
5271
|
+
buffer: jsonBuffer,
|
|
5272
|
+
error: parseError
|
|
5273
|
+
});
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
4814
5277
|
}
|
|
4815
5278
|
if (data.type === "message_delta") {
|
|
4816
5279
|
if (data.delta?.stop_reason) {
|
package/package.json
CHANGED