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.js
CHANGED
|
@@ -688,17 +688,32 @@ var StreamingProtocolAdapter = class {
|
|
|
688
688
|
processToolCalls(toolCalls, state, sseLines) {
|
|
689
689
|
for (const toolCall of toolCalls) {
|
|
690
690
|
if (toolCall.id && toolCall.function?.name) {
|
|
691
|
+
const toolArgs = toolCall.function.arguments || "";
|
|
691
692
|
const toolData = {
|
|
692
693
|
id: toolCall.id,
|
|
693
694
|
name: toolCall.function.name,
|
|
694
|
-
input:
|
|
695
|
+
input: toolArgs
|
|
695
696
|
};
|
|
696
697
|
state.toolCallsMap.set(toolCall.id, toolData);
|
|
698
|
+
const blockIndex = state.completedToolCalls.length + 1;
|
|
697
699
|
sseLines.push(
|
|
698
700
|
"event: content_block_start",
|
|
699
|
-
`data: {"type":"content_block_start","index":${
|
|
701
|
+
`data: {"type":"content_block_start","index":${blockIndex},"content_block":{"type":"tool_use","id":"${toolCall.id}","name":"${toolCall.function.name}","input":{}}}`,
|
|
700
702
|
""
|
|
701
703
|
);
|
|
704
|
+
if (toolArgs) {
|
|
705
|
+
sseLines.push(
|
|
706
|
+
"event: content_block_delta",
|
|
707
|
+
`data: {"type":"content_block_delta","index":${blockIndex},"delta":{"type":"input_json_delta","partial_json":${JSON.stringify(toolArgs)}}}`,
|
|
708
|
+
""
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
sseLines.push(
|
|
712
|
+
"event: content_block_stop",
|
|
713
|
+
`data: {"type":"content_block_stop","index":${blockIndex}}`,
|
|
714
|
+
""
|
|
715
|
+
);
|
|
716
|
+
state.completedToolCalls.push(toolCall.id);
|
|
702
717
|
}
|
|
703
718
|
}
|
|
704
719
|
}
|
|
@@ -723,9 +738,10 @@ var StreamingProtocolAdapter = class {
|
|
|
723
738
|
""
|
|
724
739
|
);
|
|
725
740
|
}
|
|
741
|
+
const stopReason = state.completedToolCalls.length > 0 ? "tool_use" : "end_turn";
|
|
726
742
|
sseLines.push(
|
|
727
743
|
"event: message_delta",
|
|
728
|
-
`data: {"type":"message_delta","delta":{"stop_reason":"
|
|
744
|
+
`data: {"type":"message_delta","delta":{"stop_reason":"${stopReason}","stop_sequence":null},"usage":{"output_tokens":${state.usage.output_tokens}}}`,
|
|
729
745
|
"",
|
|
730
746
|
"event: message_stop",
|
|
731
747
|
'data: {"type":"message_stop"}',
|
|
@@ -4258,15 +4274,28 @@ var ToolCallProcessor = class _ToolCallProcessor {
|
|
|
4258
4274
|
* 处理增量工具调用
|
|
4259
4275
|
*/
|
|
4260
4276
|
static processIncrementalToolCalls(toolCalls, state, sseLines) {
|
|
4277
|
+
console.log("\u{1F50D}\u{1F50D}\u{1F50D} [ToolProcessor] processIncrementalToolCalls called with:", JSON.stringify(toolCalls, null, 2));
|
|
4261
4278
|
for (const toolCall of toolCalls) {
|
|
4262
4279
|
const toolId = toolCall.id;
|
|
4263
4280
|
const toolName = toolCall.function?.name;
|
|
4264
4281
|
const toolArgs = toolCall.function?.arguments;
|
|
4282
|
+
console.log("\u{1F50D} [ToolProcessor] Processing tool call:", {
|
|
4283
|
+
toolId,
|
|
4284
|
+
toolName,
|
|
4285
|
+
toolArgs: toolArgs || "UNDEFINED",
|
|
4286
|
+
toolArgsType: typeof toolArgs,
|
|
4287
|
+
toolArgsLength: toolArgs?.length || 0,
|
|
4288
|
+
hasArgs: !!toolArgs
|
|
4289
|
+
});
|
|
4265
4290
|
if (toolName && toolId && !state.toolCallsMap.has(toolId)) {
|
|
4291
|
+
console.log("\u2705 [ToolProcessor] Starting new tool call:", toolName);
|
|
4266
4292
|
_ToolCallProcessor.processToolCallStart(toolId, toolName, state, sseLines);
|
|
4267
4293
|
}
|
|
4268
4294
|
if (toolArgs) {
|
|
4295
|
+
console.log("\u2705 [ToolProcessor] Processing tool args, calling processToolArgs");
|
|
4269
4296
|
_ToolCallProcessor.processToolArgs(toolId, toolArgs, state, sseLines);
|
|
4297
|
+
} else {
|
|
4298
|
+
console.warn("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F [ToolProcessor] No tool args to process! This will result in empty input!");
|
|
4270
4299
|
}
|
|
4271
4300
|
}
|
|
4272
4301
|
}
|
|
@@ -4274,15 +4303,28 @@ var ToolCallProcessor = class _ToolCallProcessor {
|
|
|
4274
4303
|
* 处理工具调用
|
|
4275
4304
|
*/
|
|
4276
4305
|
static processBatchToolCalls(toolCalls, state, sseLines) {
|
|
4306
|
+
console.log("\u{1F50D}\u{1F50D}\u{1F50D} [ToolProcessor] processBatchToolCalls called with:", JSON.stringify(toolCalls, null, 2));
|
|
4277
4307
|
for (const toolCall of toolCalls) {
|
|
4278
4308
|
const toolId = toolCall.id;
|
|
4279
4309
|
const toolName = toolCall.function?.name;
|
|
4280
4310
|
const toolArgs = toolCall.function?.arguments;
|
|
4311
|
+
console.log("\u{1F50D} [ToolProcessor] Processing batch tool call:", {
|
|
4312
|
+
toolId,
|
|
4313
|
+
toolName,
|
|
4314
|
+
toolArgs: toolArgs || "UNDEFINED",
|
|
4315
|
+
toolArgsType: typeof toolArgs,
|
|
4316
|
+
toolArgsLength: toolArgs?.length || 0,
|
|
4317
|
+
hasArgs: !!toolArgs
|
|
4318
|
+
});
|
|
4281
4319
|
if (toolName && toolId && !state.toolCallsMap.has(toolId)) {
|
|
4320
|
+
console.log("\u2705 [ToolProcessor] Starting new batch tool call:", toolName);
|
|
4282
4321
|
_ToolCallProcessor.processToolCallStart(toolId, toolName, state, sseLines);
|
|
4283
4322
|
}
|
|
4284
4323
|
if (toolArgs) {
|
|
4324
|
+
console.log("\u2705 [ToolProcessor] Processing batch tool args, calling processToolArgs");
|
|
4285
4325
|
_ToolCallProcessor.processToolArgs(toolId, toolArgs, state, sseLines);
|
|
4326
|
+
} else {
|
|
4327
|
+
console.warn("\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F [ToolProcessor] No batch tool args to process! This will result in empty input!");
|
|
4286
4328
|
}
|
|
4287
4329
|
}
|
|
4288
4330
|
}
|
|
@@ -4480,6 +4522,247 @@ function generateMessageId() {
|
|
|
4480
4522
|
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
4481
4523
|
}
|
|
4482
4524
|
|
|
4525
|
+
// src/core/o2a-sse-adapter/stream-converter.ts
|
|
4526
|
+
var StreamConverter = class {
|
|
4527
|
+
constructor(adapter, options = {}) {
|
|
4528
|
+
this.buffer = "";
|
|
4529
|
+
this.adapter = adapter;
|
|
4530
|
+
this.options = {
|
|
4531
|
+
bufferTimeout: 5e3,
|
|
4532
|
+
errorRecovery: true,
|
|
4533
|
+
maxRetries: 3,
|
|
4534
|
+
debug: false,
|
|
4535
|
+
...options
|
|
4536
|
+
};
|
|
4537
|
+
this.state = this.adapter.createIncrementalState();
|
|
4538
|
+
this.stats = {
|
|
4539
|
+
chunksProcessed: 0,
|
|
4540
|
+
eventsGenerated: 0,
|
|
4541
|
+
errors: 0,
|
|
4542
|
+
retries: 0,
|
|
4543
|
+
startTime: Date.now(),
|
|
4544
|
+
lastUpdateTime: Date.now(),
|
|
4545
|
+
bufferSize: 0
|
|
4546
|
+
};
|
|
4547
|
+
if (this.options.debug) {
|
|
4548
|
+
console.log("[StreamConverter] \u5DF2\u521D\u59CB\u5316\uFF0C\u914D\u7F6E:", this.options);
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
/**
|
|
4552
|
+
* 获取初始事件
|
|
4553
|
+
*/
|
|
4554
|
+
getInitialEvents() {
|
|
4555
|
+
const events = this.adapter.getInitialSSEEvents(
|
|
4556
|
+
this.options.modelName,
|
|
4557
|
+
this.options.messageId
|
|
4558
|
+
);
|
|
4559
|
+
this.stats.eventsGenerated += events.length;
|
|
4560
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4561
|
+
if (this.options.debug) {
|
|
4562
|
+
console.log("[StreamConverter] \u751F\u6210\u521D\u59CB\u4E8B\u4EF6:", events.length, "\u4E2A");
|
|
4563
|
+
}
|
|
4564
|
+
return events;
|
|
4565
|
+
}
|
|
4566
|
+
/**
|
|
4567
|
+
* 处理单个数据块
|
|
4568
|
+
*/
|
|
4569
|
+
processChunk(chunk) {
|
|
4570
|
+
this.stats.chunksProcessed++;
|
|
4571
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4572
|
+
if (this.options.debug) {
|
|
4573
|
+
console.log("[StreamConverter] \u5904\u7406\u6570\u636E\u5757:", chunk.substring(0, 100) + "...");
|
|
4574
|
+
}
|
|
4575
|
+
try {
|
|
4576
|
+
const events = this.processBufferedData(chunk);
|
|
4577
|
+
this.stats.eventsGenerated += events.length;
|
|
4578
|
+
if (this.options.onChunkProcessed) {
|
|
4579
|
+
this.options.onChunkProcessed(chunk, events);
|
|
4580
|
+
}
|
|
4581
|
+
return events;
|
|
4582
|
+
} catch (error) {
|
|
4583
|
+
return this.handleChunkError(error, chunk);
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
/**
|
|
4587
|
+
* 结束流处理
|
|
4588
|
+
*/
|
|
4589
|
+
finalize() {
|
|
4590
|
+
if (this.options.debug) {
|
|
4591
|
+
console.log("[StreamConverter] \u7ED3\u675F\u6D41\u5904\u7406\uFF0C\u7F13\u51B2\u533A\u5927\u5C0F:", this.buffer.length);
|
|
4592
|
+
}
|
|
4593
|
+
let events = [];
|
|
4594
|
+
if (this.buffer.trim()) {
|
|
4595
|
+
console.warn("[StreamConverter] \u7F13\u51B2\u533A\u4E2D\u6709\u672A\u5904\u7406\u6570\u636E\uFF0C\u5F3A\u5236\u5904\u7406:", this.buffer);
|
|
4596
|
+
events = this.processIncompleteBuffer();
|
|
4597
|
+
}
|
|
4598
|
+
try {
|
|
4599
|
+
const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
|
|
4600
|
+
events.push(...finalEvents);
|
|
4601
|
+
this.stats.eventsGenerated += finalEvents.length;
|
|
4602
|
+
} catch (error) {
|
|
4603
|
+
console.error("[StreamConverter] \u5904\u7406\u7ED3\u675F\u4E8B\u4EF6\u5931\u8D25:", error);
|
|
4604
|
+
}
|
|
4605
|
+
this.clearBufferTimeout();
|
|
4606
|
+
this.stats.lastUpdateTime = Date.now();
|
|
4607
|
+
if (this.options.debug) {
|
|
4608
|
+
console.log("[StreamConverter] \u6D41\u5904\u7406\u5B8C\u6210\uFF0C\u7EDF\u8BA1\u4FE1\u606F:", this.stats);
|
|
4609
|
+
}
|
|
4610
|
+
return events;
|
|
4611
|
+
}
|
|
4612
|
+
/**
|
|
4613
|
+
* 获取当前状态
|
|
4614
|
+
*/
|
|
4615
|
+
getState() {
|
|
4616
|
+
return { ...this.state };
|
|
4617
|
+
}
|
|
4618
|
+
/**
|
|
4619
|
+
* 重置状态
|
|
4620
|
+
*/
|
|
4621
|
+
reset() {
|
|
4622
|
+
this.state = this.adapter.createIncrementalState();
|
|
4623
|
+
this.buffer = "";
|
|
4624
|
+
this.clearBufferTimeout();
|
|
4625
|
+
this.stats = {
|
|
4626
|
+
chunksProcessed: 0,
|
|
4627
|
+
eventsGenerated: 0,
|
|
4628
|
+
errors: 0,
|
|
4629
|
+
retries: 0,
|
|
4630
|
+
startTime: Date.now(),
|
|
4631
|
+
lastUpdateTime: Date.now(),
|
|
4632
|
+
bufferSize: 0
|
|
4633
|
+
};
|
|
4634
|
+
if (this.options.debug) {
|
|
4635
|
+
console.log("[StreamConverter] \u72B6\u6001\u5DF2\u91CD\u7F6E");
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
/**
|
|
4639
|
+
* 获取统计信息
|
|
4640
|
+
*/
|
|
4641
|
+
getStats() {
|
|
4642
|
+
return {
|
|
4643
|
+
...this.stats,
|
|
4644
|
+
bufferSize: this.buffer.length
|
|
4645
|
+
};
|
|
4646
|
+
}
|
|
4647
|
+
/**
|
|
4648
|
+
* 处理缓冲的数据
|
|
4649
|
+
*/
|
|
4650
|
+
processBufferedData(newChunk) {
|
|
4651
|
+
this.buffer += newChunk;
|
|
4652
|
+
this.stats.bufferSize = this.buffer.length;
|
|
4653
|
+
const lines = this.buffer.split("\n");
|
|
4654
|
+
this.buffer = lines.pop() || "";
|
|
4655
|
+
const events = [];
|
|
4656
|
+
for (const line of lines) {
|
|
4657
|
+
if (line.startsWith("data:")) {
|
|
4658
|
+
const jsonStr = line.slice(5).trim();
|
|
4659
|
+
if (jsonStr && jsonStr !== "[DONE]") {
|
|
4660
|
+
const lineEvents = this.processDataLine(jsonStr);
|
|
4661
|
+
events.push(...lineEvents);
|
|
4662
|
+
} else if (jsonStr === "[DONE]") {
|
|
4663
|
+
const finalEvents = this.adapter.convertIncrementalChunk("[DONE]", this.state);
|
|
4664
|
+
events.push(...finalEvents);
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
this.resetBufferTimeout();
|
|
4669
|
+
return events;
|
|
4670
|
+
}
|
|
4671
|
+
/**
|
|
4672
|
+
* 处理单行数据
|
|
4673
|
+
*/
|
|
4674
|
+
processDataLine(jsonStr, attempt = 0) {
|
|
4675
|
+
try {
|
|
4676
|
+
const chunkEvents = this.adapter.convertIncrementalChunk(jsonStr, this.state);
|
|
4677
|
+
if (this.options.debug && chunkEvents.length > 0) {
|
|
4678
|
+
console.log("[StreamConverter] \u751F\u6210\u4E8B\u4EF6:", chunkEvents.length, "\u4E2A");
|
|
4679
|
+
}
|
|
4680
|
+
return chunkEvents;
|
|
4681
|
+
} catch (error) {
|
|
4682
|
+
if (this.options.errorRecovery && attempt < (this.options.maxRetries || 3)) {
|
|
4683
|
+
console.warn(`[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u5931\u8D25\uFF0C\u91CD\u8BD5 ${attempt + 1}/${this.options.maxRetries}:`, error);
|
|
4684
|
+
this.stats.retries++;
|
|
4685
|
+
return this.processDataLine(jsonStr, attempt + 1);
|
|
4686
|
+
}
|
|
4687
|
+
this.stats.errors++;
|
|
4688
|
+
console.error("[StreamConverter] \u5904\u7406\u6570\u636E\u884C\u6700\u7EC8\u5931\u8D25:", error, "Data:", jsonStr);
|
|
4689
|
+
if (this.options.onError) {
|
|
4690
|
+
this.options.onError(error, {
|
|
4691
|
+
chunk: jsonStr,
|
|
4692
|
+
state: this.state,
|
|
4693
|
+
attempt,
|
|
4694
|
+
totalRetries: this.stats.retries
|
|
4695
|
+
});
|
|
4696
|
+
}
|
|
4697
|
+
return [];
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
/**
|
|
4701
|
+
* 处理块错误
|
|
4702
|
+
*/
|
|
4703
|
+
handleChunkError(error, chunk) {
|
|
4704
|
+
this.stats.errors++;
|
|
4705
|
+
if (this.options.debug) {
|
|
4706
|
+
console.error("[StreamConverter] \u5757\u5904\u7406\u9519\u8BEF:", error.message);
|
|
4707
|
+
}
|
|
4708
|
+
if (!this.options.errorRecovery) {
|
|
4709
|
+
throw error;
|
|
4710
|
+
}
|
|
4711
|
+
this.state.errors.push(`Chunk processing error: ${error.message}`);
|
|
4712
|
+
if (this.options.onError) {
|
|
4713
|
+
this.options.onError(error, {
|
|
4714
|
+
chunk,
|
|
4715
|
+
state: this.state,
|
|
4716
|
+
totalRetries: this.stats.retries
|
|
4717
|
+
});
|
|
4718
|
+
}
|
|
4719
|
+
return [];
|
|
4720
|
+
}
|
|
4721
|
+
/**
|
|
4722
|
+
* 处理不完整的缓冲区数据
|
|
4723
|
+
*/
|
|
4724
|
+
processIncompleteBuffer() {
|
|
4725
|
+
if (!this.buffer.trim()) {
|
|
4726
|
+
return [];
|
|
4727
|
+
}
|
|
4728
|
+
console.warn("[StreamConverter] \u5904\u7406\u4E0D\u5B8C\u6574\u7F13\u51B2\u533A\u6570\u636E:", this.buffer);
|
|
4729
|
+
if (this.buffer.startsWith("data:")) {
|
|
4730
|
+
const jsonStr = this.buffer.slice(5).trim();
|
|
4731
|
+
if (jsonStr) {
|
|
4732
|
+
return this.processDataLine(jsonStr);
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
return [];
|
|
4736
|
+
}
|
|
4737
|
+
/**
|
|
4738
|
+
* 重置缓冲区超时
|
|
4739
|
+
*/
|
|
4740
|
+
resetBufferTimeout() {
|
|
4741
|
+
this.clearBufferTimeout();
|
|
4742
|
+
if (this.options.bufferTimeout && this.options.bufferTimeout > 0) {
|
|
4743
|
+
this.bufferTimeout = setTimeout(() => {
|
|
4744
|
+
if (this.buffer.trim()) {
|
|
4745
|
+
console.warn("[StreamConverter] \u7F13\u51B2\u533A\u8D85\u65F6\uFF0C\u5F3A\u5236\u5904\u7406\u6570\u636E:", this.buffer);
|
|
4746
|
+
const events = this.processIncompleteBuffer();
|
|
4747
|
+
this.buffer = "";
|
|
4748
|
+
if (events.length > 0 && this.options.onChunkProcessed) {
|
|
4749
|
+
this.options.onChunkProcessed("TIMEOUT_FLUSH", events);
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
}, this.options.bufferTimeout);
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
/**
|
|
4756
|
+
* 清理缓冲区超时
|
|
4757
|
+
*/
|
|
4758
|
+
clearBufferTimeout() {
|
|
4759
|
+
if (this.bufferTimeout) {
|
|
4760
|
+
clearTimeout(this.bufferTimeout);
|
|
4761
|
+
this.bufferTimeout = void 0;
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
};
|
|
4765
|
+
|
|
4483
4766
|
// src/core/o2a-sse-adapter/adapter.ts
|
|
4484
4767
|
var O2ASSEAdapter = class {
|
|
4485
4768
|
constructor(debugMode = false, config = {}) {
|
|
@@ -4734,6 +5017,101 @@ var O2ASSEAdapter = class {
|
|
|
4734
5017
|
validateClaudeSSE(sseContent) {
|
|
4735
5018
|
return FormatValidator2.validateClaudeSSE(sseContent);
|
|
4736
5019
|
}
|
|
5020
|
+
/**
|
|
5021
|
+
* 将 OpenAI Response 流直接转换为 Anthropic SSE 流
|
|
5022
|
+
* 这是新增的核心流式处理方法,支持实时转换
|
|
5023
|
+
*/
|
|
5024
|
+
convertResponseStream(openaiResponse, options = {}) {
|
|
5025
|
+
if (!openaiResponse.body) {
|
|
5026
|
+
throw new Error("Response body is null or undefined");
|
|
5027
|
+
}
|
|
5028
|
+
return this.convertReadableStream(openaiResponse.body, options);
|
|
5029
|
+
}
|
|
5030
|
+
/**
|
|
5031
|
+
* 将 ReadableStream 转换为 Anthropic SSE 流
|
|
5032
|
+
*/
|
|
5033
|
+
convertReadableStream(openaiStream, options = {}) {
|
|
5034
|
+
const converter = this.createStreamConverter(options);
|
|
5035
|
+
const decoder = new TextDecoder();
|
|
5036
|
+
return new ReadableStream({
|
|
5037
|
+
async start(controller) {
|
|
5038
|
+
if (options.debug) {
|
|
5039
|
+
console.log("[O2ASSEAdapter] \u5F00\u59CB\u6D41\u5F0F\u8F6C\u6362\uFF0C\u914D\u7F6E:", options);
|
|
5040
|
+
}
|
|
5041
|
+
try {
|
|
5042
|
+
const initialEvents = converter.getInitialEvents();
|
|
5043
|
+
for (const event of initialEvents) {
|
|
5044
|
+
controller.enqueue(event);
|
|
5045
|
+
}
|
|
5046
|
+
} catch (error) {
|
|
5047
|
+
console.error("[O2ASSEAdapter] \u521D\u59CB\u5316\u5931\u8D25:", error);
|
|
5048
|
+
controller.error(error);
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
const reader = openaiStream.getReader();
|
|
5052
|
+
try {
|
|
5053
|
+
while (true) {
|
|
5054
|
+
const { done, value } = await reader.read();
|
|
5055
|
+
if (done) {
|
|
5056
|
+
try {
|
|
5057
|
+
const finalEvents = converter.finalize();
|
|
5058
|
+
for (const event of finalEvents) {
|
|
5059
|
+
controller.enqueue(event);
|
|
5060
|
+
}
|
|
5061
|
+
if (options.debug) {
|
|
5062
|
+
console.log("[O2ASSEAdapter] \u6D41\u5F0F\u8F6C\u6362\u5B8C\u6210\uFF0C\u7EDF\u8BA1:", converter.getStats());
|
|
5063
|
+
}
|
|
5064
|
+
} catch (error) {
|
|
5065
|
+
console.error("[O2ASSEAdapter] \u7ED3\u675F\u5904\u7406\u5931\u8D25:", error);
|
|
5066
|
+
}
|
|
5067
|
+
break;
|
|
5068
|
+
}
|
|
5069
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
5070
|
+
try {
|
|
5071
|
+
const events = converter.processChunk(chunk);
|
|
5072
|
+
for (const event of events) {
|
|
5073
|
+
controller.enqueue(event);
|
|
5074
|
+
}
|
|
5075
|
+
} catch (error) {
|
|
5076
|
+
console.error("[O2ASSEAdapter] \u5757\u5904\u7406\u5931\u8D25:", error);
|
|
5077
|
+
if (options.errorRecovery === false) {
|
|
5078
|
+
controller.error(error);
|
|
5079
|
+
return;
|
|
5080
|
+
}
|
|
5081
|
+
if (options.onError) {
|
|
5082
|
+
options.onError(error, {
|
|
5083
|
+
chunk,
|
|
5084
|
+
state: converter.getState()
|
|
5085
|
+
});
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
} catch (error) {
|
|
5090
|
+
console.error("[O2ASSEAdapter] \u6D41\u5904\u7406\u5931\u8D25:", error);
|
|
5091
|
+
if (options.onError) {
|
|
5092
|
+
options.onError(error, {
|
|
5093
|
+
chunk: "",
|
|
5094
|
+
state: converter.getState()
|
|
5095
|
+
});
|
|
5096
|
+
}
|
|
5097
|
+
controller.error(error);
|
|
5098
|
+
} finally {
|
|
5099
|
+
controller.close();
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
});
|
|
5103
|
+
}
|
|
5104
|
+
/**
|
|
5105
|
+
* 创建流式转换器实例
|
|
5106
|
+
* 提供更精细的流处理控制
|
|
5107
|
+
*/
|
|
5108
|
+
createStreamConverter(options = {}) {
|
|
5109
|
+
return new StreamConverter(this, {
|
|
5110
|
+
modelName: options.modelName || this.config.defaultModel,
|
|
5111
|
+
debug: options.debug || this.debugMode,
|
|
5112
|
+
...options
|
|
5113
|
+
});
|
|
5114
|
+
}
|
|
4737
5115
|
/**
|
|
4738
5116
|
* 应用增强功能到SSE转换
|
|
4739
5117
|
* 包括输入验证、输出修复等
|
|
@@ -4805,13 +5183,49 @@ var O2ASSEAdapterStatic = {
|
|
|
4805
5183
|
validateClaudeSSE: (sseContent) => {
|
|
4806
5184
|
const adapter = new O2ASSEAdapter(false);
|
|
4807
5185
|
return adapter.validateClaudeSSE(sseContent);
|
|
5186
|
+
},
|
|
5187
|
+
/**
|
|
5188
|
+
* 转换 Response 流为 Anthropic SSE(静态方法)
|
|
5189
|
+
* 新增:直接处理 Response 对象的流式转换
|
|
5190
|
+
*/
|
|
5191
|
+
convertResponseStream: (openaiResponse, options = {}) => {
|
|
5192
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5193
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5194
|
+
generateUniqueMessageId: !options.messageId,
|
|
5195
|
+
errorDataMaxLength: 500
|
|
5196
|
+
});
|
|
5197
|
+
return adapter.convertResponseStream(openaiResponse, options);
|
|
5198
|
+
},
|
|
5199
|
+
/**
|
|
5200
|
+
* 转换 ReadableStream 为 Anthropic SSE(静态方法)
|
|
5201
|
+
* 新增:处理任意 ReadableStream<Uint8Array> 的流式转换
|
|
5202
|
+
*/
|
|
5203
|
+
convertReadableStream: (openaiStream, options = {}) => {
|
|
5204
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5205
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5206
|
+
generateUniqueMessageId: !options.messageId,
|
|
5207
|
+
errorDataMaxLength: 500
|
|
5208
|
+
});
|
|
5209
|
+
return adapter.convertReadableStream(openaiStream, options);
|
|
5210
|
+
},
|
|
5211
|
+
/**
|
|
5212
|
+
* 创建流式转换器(静态方法)
|
|
5213
|
+
* 新增:提供更精细的流处理控制
|
|
5214
|
+
*/
|
|
5215
|
+
createStreamConverter: (options = {}) => {
|
|
5216
|
+
const adapter = new O2ASSEAdapter(options.debug || false, {
|
|
5217
|
+
defaultModel: options.modelName || "claude-sonnet-4",
|
|
5218
|
+
generateUniqueMessageId: !options.messageId,
|
|
5219
|
+
errorDataMaxLength: 500
|
|
5220
|
+
});
|
|
5221
|
+
return adapter.createStreamConverter(options);
|
|
4808
5222
|
}
|
|
4809
5223
|
};
|
|
4810
5224
|
|
|
4811
5225
|
// src/core/standard/standard-protocol-adapter.ts
|
|
4812
5226
|
var StandardProtocolAdapter = class {
|
|
4813
5227
|
constructor(options = {}) {
|
|
4814
|
-
this.debugMode = options.debugMode
|
|
5228
|
+
this.debugMode = options.debugMode !== void 0 ? options.debugMode : true;
|
|
4815
5229
|
this.sseAdapter = new O2ASSEAdapter(this.debugMode);
|
|
4816
5230
|
}
|
|
4817
5231
|
/**
|
|
@@ -4888,6 +5302,8 @@ var StandardProtocolAdapter = class {
|
|
|
4888
5302
|
};
|
|
4889
5303
|
let currentTextContent = "";
|
|
4890
5304
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
5305
|
+
const toolInputBuffers = /* @__PURE__ */ new Map();
|
|
5306
|
+
const indexToToolId = /* @__PURE__ */ new Map();
|
|
4891
5307
|
let processedDataLines = 0;
|
|
4892
5308
|
for (const line of lines) {
|
|
4893
5309
|
if (line.startsWith("data: ")) {
|
|
@@ -4900,15 +5316,22 @@ var StandardProtocolAdapter = class {
|
|
|
4900
5316
|
if (data.type === "content_block_start") {
|
|
4901
5317
|
const contentBlock = data.content_block;
|
|
4902
5318
|
if (contentBlock.type === "tool_use") {
|
|
5319
|
+
const toolIndex = data.index;
|
|
4903
5320
|
toolCalls.set(contentBlock.id, {
|
|
4904
5321
|
type: "tool_use",
|
|
4905
5322
|
id: contentBlock.id,
|
|
4906
5323
|
name: contentBlock.name,
|
|
4907
5324
|
input: contentBlock.input || {}
|
|
5325
|
+
// 初始为空对象,稍后会被更新
|
|
5326
|
+
});
|
|
5327
|
+
toolInputBuffers.set(toolIndex, "");
|
|
5328
|
+
indexToToolId.set(toolIndex, contentBlock.id);
|
|
5329
|
+
console.log("\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", {
|
|
5330
|
+
index: toolIndex,
|
|
5331
|
+
toolId: contentBlock.id,
|
|
5332
|
+
name: contentBlock.name,
|
|
5333
|
+
indexToToolIdSize: indexToToolId.size
|
|
4908
5334
|
});
|
|
4909
|
-
if (this.debugMode) {
|
|
4910
|
-
console.log("\u{1F527} [StandardProtocolAdapter] \u6DFB\u52A0\u5DE5\u5177\u8C03\u7528:", contentBlock);
|
|
4911
|
-
}
|
|
4912
5335
|
}
|
|
4913
5336
|
}
|
|
4914
5337
|
if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
|
|
@@ -4918,6 +5341,46 @@ var StandardProtocolAdapter = class {
|
|
|
4918
5341
|
}
|
|
4919
5342
|
}
|
|
4920
5343
|
if (data.type === "content_block_delta" && data.delta?.type === "input_json_delta") {
|
|
5344
|
+
const toolIndex = data.index;
|
|
5345
|
+
const toolId = indexToToolId.get(toolIndex);
|
|
5346
|
+
console.log(`\u{1F527}\u{1F527}\u{1F527} [StandardProtocolAdapter] \u68C0\u6D4B\u5230input_json_delta\u4E8B\u4EF6\uFF01`, {
|
|
5347
|
+
toolIndex,
|
|
5348
|
+
toolId: toolId || "NOT_FOUND",
|
|
5349
|
+
delta: data.delta.partial_json
|
|
5350
|
+
});
|
|
5351
|
+
if (toolId) {
|
|
5352
|
+
const currentBuffer = toolInputBuffers.get(toolIndex) || "";
|
|
5353
|
+
const newBuffer = currentBuffer + data.delta.partial_json;
|
|
5354
|
+
toolInputBuffers.set(toolIndex, newBuffer);
|
|
5355
|
+
console.log(`\u{1F527} [StandardProtocolAdapter] \u7D2F\u79EF\u5DE5\u5177\u53C2\u6570 (index=${toolIndex}, id=${toolId}):`, {
|
|
5356
|
+
delta: data.delta.partial_json,
|
|
5357
|
+
bufferLength: newBuffer.length
|
|
5358
|
+
});
|
|
5359
|
+
} else {
|
|
5360
|
+
console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u627E\u4E0D\u5230toolId for index=${toolIndex}`);
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
5363
|
+
if (data.type === "content_block_stop") {
|
|
5364
|
+
const toolIndex = data.index;
|
|
5365
|
+
const toolId = indexToToolId.get(toolIndex);
|
|
5366
|
+
if (toolId) {
|
|
5367
|
+
const jsonBuffer = toolInputBuffers.get(toolIndex);
|
|
5368
|
+
const tool = toolCalls.get(toolId);
|
|
5369
|
+
if (jsonBuffer && tool) {
|
|
5370
|
+
try {
|
|
5371
|
+
const parsedInput = JSON.parse(jsonBuffer);
|
|
5372
|
+
tool.input = parsedInput;
|
|
5373
|
+
if (this.debugMode) {
|
|
5374
|
+
console.log(`\u2705 [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570\u89E3\u6790\u5B8C\u6210 (index=${toolIndex}, id=${toolId}):`, parsedInput);
|
|
5375
|
+
}
|
|
5376
|
+
} catch (parseError) {
|
|
5377
|
+
console.warn(`\u26A0\uFE0F [StandardProtocolAdapter] \u5DE5\u5177\u53C2\u6570JSON\u89E3\u6790\u5931\u8D25 (index=${toolIndex}, id=${toolId}):`, {
|
|
5378
|
+
buffer: jsonBuffer,
|
|
5379
|
+
error: parseError
|
|
5380
|
+
});
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
4921
5384
|
}
|
|
4922
5385
|
if (data.type === "message_delta") {
|
|
4923
5386
|
if (data.delta?.stop_reason) {
|