ai-protocol-adapters 1.0.0-alpha.16 → 1.0.0-alpha.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +288 -4
- package/dist/index.mjs +285 -4
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5606,6 +5606,11 @@ interface A2ORequestAdapterConfig {
|
|
|
5606
5606
|
logLevel: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
5607
5607
|
enableMetrics: boolean;
|
|
5608
5608
|
};
|
|
5609
|
+
imageProxy: {
|
|
5610
|
+
enabled: boolean;
|
|
5611
|
+
timeout: number;
|
|
5612
|
+
maxSize: number;
|
|
5613
|
+
};
|
|
5609
5614
|
}
|
|
5610
5615
|
|
|
5611
5616
|
/**
|
|
@@ -5626,9 +5631,9 @@ declare class A2ORequestAdapter {
|
|
|
5626
5631
|
*/
|
|
5627
5632
|
convertAnthropicRequestToOpenAIEnhanced(anthropicRequest: unknown): Promise<ConversionResult$2<OpenAIRequest>>;
|
|
5628
5633
|
/**
|
|
5629
|
-
*
|
|
5634
|
+
* 执行核心转换逻辑(支持图片代理)
|
|
5630
5635
|
*/
|
|
5631
|
-
|
|
5636
|
+
performCoreConversion(anthropicRequest: ClaudeRequest): Promise<any>;
|
|
5632
5637
|
/**
|
|
5633
5638
|
* 转换Anthropic请求格式为OpenAI兼容格式 - 原有方法保持兼容
|
|
5634
5639
|
*/
|
|
@@ -5723,8 +5728,35 @@ declare const A2ORequestAdapterStatic: {
|
|
|
5723
5728
|
* 获取工具映射(静态方法,已弃用)
|
|
5724
5729
|
*/
|
|
5725
5730
|
getToolMapping: (claudeToolName: string) => string | undefined;
|
|
5731
|
+
/**
|
|
5732
|
+
* 转换Anthropic请求格式为OpenAI兼容格式(异步版本,支持图片URL自动下载)
|
|
5733
|
+
* 解决GitHub Copilot等API不支持外部图片URL的问题
|
|
5734
|
+
* @param anthropicRequest Claude格式的请求
|
|
5735
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true)
|
|
5736
|
+
*/
|
|
5737
|
+
convertAnthropicRequestToOpenAIAsync: (anthropicRequest: ClaudeRequest, downloadImageUrls?: boolean) => Promise<OpenAIRequest>;
|
|
5726
5738
|
};
|
|
5727
5739
|
|
|
5740
|
+
/**
|
|
5741
|
+
* 从URL下载图片并转换为base64 data URI
|
|
5742
|
+
* @param url 图片URL
|
|
5743
|
+
* @param options 下载选项
|
|
5744
|
+
* @returns base64 data URI (例如: "data:image/jpeg;base64,/9j/4AAQ...")
|
|
5745
|
+
*/
|
|
5746
|
+
declare function downloadImageAsBase64(url: string, options?: {
|
|
5747
|
+
timeout?: number;
|
|
5748
|
+
maxSize?: number;
|
|
5749
|
+
userAgent?: string;
|
|
5750
|
+
}): Promise<string>;
|
|
5751
|
+
/**
|
|
5752
|
+
* 判断URL是否是外部URL(http/https开头)
|
|
5753
|
+
*/
|
|
5754
|
+
declare function isExternalUrl(url: string): boolean;
|
|
5755
|
+
/**
|
|
5756
|
+
* 判断URL是否已经是base64 data URI
|
|
5757
|
+
*/
|
|
5758
|
+
declare function isBase64DataUri(url: string): boolean;
|
|
5759
|
+
|
|
5728
5760
|
/**
|
|
5729
5761
|
* A2O格式验证器
|
|
5730
5762
|
* 专门处理Claude和OpenAI请求格式的验证
|
|
@@ -7333,4 +7365,4 @@ declare const FEATURES: {
|
|
|
7333
7365
|
readonly externalPackageVerified: true;
|
|
7334
7366
|
};
|
|
7335
7367
|
|
|
7336
|
-
export { A2ORequestAdapter, A2ORequestAdapterStatic, ADAPTERS_VERSION, type AnthropicContentBlock, AnthropicContentBlockBaseSchema, AnthropicContentBlockDeltaEventSchema, AnthropicContentBlockSchema, AnthropicContentBlockStartEventSchema, AnthropicContentBlockStopEventSchema, AnthropicErrorEventSchema, type AnthropicImageContentBlock, AnthropicImageContentBlockSchema, AnthropicImageSourceSchema, type AnthropicMessage, AnthropicMessageDeltaEventSchema, AnthropicMessageSchema, AnthropicMessageStartEventSchema, AnthropicMessageStopEventSchema, AnthropicMetadataSchema, AnthropicPingEventSchema, type AnthropicRequest, AnthropicRequestSchema, type AnthropicResponse, AnthropicResponseSchema, type AnthropicSDKConfig, AnthropicSDKWrapper, type AnthropicStreamEvent, AnthropicStreamEventBaseSchema, AnthropicStreamEventSchema, AnthropicSystemMessageSchema, type AnthropicTextContentBlock, AnthropicTextContentBlockSchema, type AnthropicTool, AnthropicToolInputSchemaSchema, type AnthropicToolResultContentBlock, AnthropicToolResultContentBlockSchema, AnthropicToolSchema, type AnthropicToolUseContentBlock, AnthropicToolUseContentBlockSchema, type AnthropicUsage, AnthropicUsageSchema, type BaseSDKClient, A2ORequestAdapter as ClaudeToOpenAIConverter, type ConversionFixResult, ConversionFixer, type ConversionResult$1 as ConversionResult, type ConversionState, ConversionValidator, type ConvertedRequest, type ConvertedResponse, EMERGENCY_HEALING_STRATEGIES, type EnhancedAdapterOptions, type EnhancedConversionResult, ErrorDetector, type ErrorInfo, ErrorRecovery, type ErrorSeverity, type ErrorType, FEATURES, FormatValidator, type HealingContext, type HealingResult, type HealingRule, StandardProtocolAdapter as NonStreamingIOConverter, O2ASSEAdapter, O2ASSEAdapterStatic, type OpenAIChoice, OpenAIChoiceSchema, OpenAIFunctionParametersSchema, OpenAIFunctionSchema, type OpenAIMessage, OpenAIMessageContentSchema, OpenAIMessageSchema, type OpenAIRequest$1 as OpenAIRequest, OpenAIRequestSchema, type OpenAIResponse$1 as OpenAIResponse, OpenAIResponseSchema, type OpenAISDKConfig, OpenAISDKWrapper, type OpenAIStreamChunk, OpenAIStreamChunkSchema, O2ASSEAdapter as OpenAIToClaudeSSEConverter, type OpenAITool, type OpenAIToolCall, OpenAIToolCallSchema, OpenAIToolSchema, type OpenAIUsage, OpenAIUsageSchema, ProtocolHealer, RECOVERY_STRATEGIES, REQUEST_HEALING_STRATEGIES, RESPONSE_HEALING_STRATEGIES, type RecoveryResult, type RecoveryStrategy, type RequestOptions, type SDKConfig, SDKFactory, type SDKProvider, type SDKResponse, type SDKStreamEvent, SSEEventGenerator, STREAM_HEALING_STRATEGIES, type ConversionResult as SchemaConversionResult, StandardProtocolAdapter as StandardGateway, StandardProtocolAdapter, type StandardProtocolAdapterOptions, StreamingProtocolAdapter as StreamingGateway, StreamingProtocolAdapter as StreamingIOConverter, StreamingProtocolAdapter, type StreamingProtocolAdapterOptions, type UnifiedSDKConfig, type ValidationResult, attemptRecovery, conversionValidator, createAnthropicSDK, createOpenAISDK, createValidator, errorRecovery, getAllHealingStrategies, getGlobalLogger, getRecoveryRecommendations, getStrategiesForContext, healA2ORequest, healO2ARequest, healO2AResponse, healingValidate, isRecoverable, protocolHealer, safeValidate, sdkFactory, selectSDKByModel, strictValidate, validateA2OConversion, validateAnthropicRequest, validateAnthropicResponse, validateAnthropicStreamEvent, validateBatch, validateO2AConversion, validateOpenAIRequest, validateOpenAIResponse, validateOpenAIStreamChunk, validateSDKConfig, validateStreamConversion };
|
|
7368
|
+
export { A2ORequestAdapter, A2ORequestAdapterStatic, ADAPTERS_VERSION, type AnthropicContentBlock, AnthropicContentBlockBaseSchema, AnthropicContentBlockDeltaEventSchema, AnthropicContentBlockSchema, AnthropicContentBlockStartEventSchema, AnthropicContentBlockStopEventSchema, AnthropicErrorEventSchema, type AnthropicImageContentBlock, AnthropicImageContentBlockSchema, AnthropicImageSourceSchema, type AnthropicMessage, AnthropicMessageDeltaEventSchema, AnthropicMessageSchema, AnthropicMessageStartEventSchema, AnthropicMessageStopEventSchema, AnthropicMetadataSchema, AnthropicPingEventSchema, type AnthropicRequest, AnthropicRequestSchema, type AnthropicResponse, AnthropicResponseSchema, type AnthropicSDKConfig, AnthropicSDKWrapper, type AnthropicStreamEvent, AnthropicStreamEventBaseSchema, AnthropicStreamEventSchema, AnthropicSystemMessageSchema, type AnthropicTextContentBlock, AnthropicTextContentBlockSchema, type AnthropicTool, AnthropicToolInputSchemaSchema, type AnthropicToolResultContentBlock, AnthropicToolResultContentBlockSchema, AnthropicToolSchema, type AnthropicToolUseContentBlock, AnthropicToolUseContentBlockSchema, type AnthropicUsage, AnthropicUsageSchema, type BaseSDKClient, A2ORequestAdapter as ClaudeToOpenAIConverter, type ConversionFixResult, ConversionFixer, type ConversionResult$1 as ConversionResult, type ConversionState, ConversionValidator, type ConvertedRequest, type ConvertedResponse, EMERGENCY_HEALING_STRATEGIES, type EnhancedAdapterOptions, type EnhancedConversionResult, ErrorDetector, type ErrorInfo, ErrorRecovery, type ErrorSeverity, type ErrorType, FEATURES, FormatValidator, type HealingContext, type HealingResult, type HealingRule, StandardProtocolAdapter as NonStreamingIOConverter, O2ASSEAdapter, O2ASSEAdapterStatic, type OpenAIChoice, OpenAIChoiceSchema, OpenAIFunctionParametersSchema, OpenAIFunctionSchema, type OpenAIMessage, OpenAIMessageContentSchema, OpenAIMessageSchema, type OpenAIRequest$1 as OpenAIRequest, OpenAIRequestSchema, type OpenAIResponse$1 as OpenAIResponse, OpenAIResponseSchema, type OpenAISDKConfig, OpenAISDKWrapper, type OpenAIStreamChunk, OpenAIStreamChunkSchema, O2ASSEAdapter as OpenAIToClaudeSSEConverter, type OpenAITool, type OpenAIToolCall, OpenAIToolCallSchema, OpenAIToolSchema, type OpenAIUsage, OpenAIUsageSchema, ProtocolHealer, RECOVERY_STRATEGIES, REQUEST_HEALING_STRATEGIES, RESPONSE_HEALING_STRATEGIES, type RecoveryResult, type RecoveryStrategy, type RequestOptions, type SDKConfig, SDKFactory, type SDKProvider, type SDKResponse, type SDKStreamEvent, SSEEventGenerator, STREAM_HEALING_STRATEGIES, type ConversionResult as SchemaConversionResult, StandardProtocolAdapter as StandardGateway, StandardProtocolAdapter, type StandardProtocolAdapterOptions, StreamingProtocolAdapter as StreamingGateway, StreamingProtocolAdapter as StreamingIOConverter, StreamingProtocolAdapter, type StreamingProtocolAdapterOptions, type UnifiedSDKConfig, type ValidationResult, attemptRecovery, conversionValidator, createAnthropicSDK, createOpenAISDK, createValidator, downloadImageAsBase64, errorRecovery, getAllHealingStrategies, getGlobalLogger, getRecoveryRecommendations, getStrategiesForContext, healA2ORequest, healO2ARequest, healO2AResponse, healingValidate, isBase64DataUri, isExternalUrl, isRecoverable, protocolHealer, safeValidate, sdkFactory, selectSDKByModel, strictValidate, validateA2OConversion, validateAnthropicRequest, validateAnthropicResponse, validateAnthropicStreamEvent, validateBatch, validateO2AConversion, validateOpenAIRequest, validateOpenAIResponse, validateOpenAIStreamChunk, validateSDKConfig, validateStreamConversion };
|
package/dist/index.d.ts
CHANGED
|
@@ -5606,6 +5606,11 @@ interface A2ORequestAdapterConfig {
|
|
|
5606
5606
|
logLevel: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
5607
5607
|
enableMetrics: boolean;
|
|
5608
5608
|
};
|
|
5609
|
+
imageProxy: {
|
|
5610
|
+
enabled: boolean;
|
|
5611
|
+
timeout: number;
|
|
5612
|
+
maxSize: number;
|
|
5613
|
+
};
|
|
5609
5614
|
}
|
|
5610
5615
|
|
|
5611
5616
|
/**
|
|
@@ -5626,9 +5631,9 @@ declare class A2ORequestAdapter {
|
|
|
5626
5631
|
*/
|
|
5627
5632
|
convertAnthropicRequestToOpenAIEnhanced(anthropicRequest: unknown): Promise<ConversionResult$2<OpenAIRequest>>;
|
|
5628
5633
|
/**
|
|
5629
|
-
*
|
|
5634
|
+
* 执行核心转换逻辑(支持图片代理)
|
|
5630
5635
|
*/
|
|
5631
|
-
|
|
5636
|
+
performCoreConversion(anthropicRequest: ClaudeRequest): Promise<any>;
|
|
5632
5637
|
/**
|
|
5633
5638
|
* 转换Anthropic请求格式为OpenAI兼容格式 - 原有方法保持兼容
|
|
5634
5639
|
*/
|
|
@@ -5723,8 +5728,35 @@ declare const A2ORequestAdapterStatic: {
|
|
|
5723
5728
|
* 获取工具映射(静态方法,已弃用)
|
|
5724
5729
|
*/
|
|
5725
5730
|
getToolMapping: (claudeToolName: string) => string | undefined;
|
|
5731
|
+
/**
|
|
5732
|
+
* 转换Anthropic请求格式为OpenAI兼容格式(异步版本,支持图片URL自动下载)
|
|
5733
|
+
* 解决GitHub Copilot等API不支持外部图片URL的问题
|
|
5734
|
+
* @param anthropicRequest Claude格式的请求
|
|
5735
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true)
|
|
5736
|
+
*/
|
|
5737
|
+
convertAnthropicRequestToOpenAIAsync: (anthropicRequest: ClaudeRequest, downloadImageUrls?: boolean) => Promise<OpenAIRequest>;
|
|
5726
5738
|
};
|
|
5727
5739
|
|
|
5740
|
+
/**
|
|
5741
|
+
* 从URL下载图片并转换为base64 data URI
|
|
5742
|
+
* @param url 图片URL
|
|
5743
|
+
* @param options 下载选项
|
|
5744
|
+
* @returns base64 data URI (例如: "data:image/jpeg;base64,/9j/4AAQ...")
|
|
5745
|
+
*/
|
|
5746
|
+
declare function downloadImageAsBase64(url: string, options?: {
|
|
5747
|
+
timeout?: number;
|
|
5748
|
+
maxSize?: number;
|
|
5749
|
+
userAgent?: string;
|
|
5750
|
+
}): Promise<string>;
|
|
5751
|
+
/**
|
|
5752
|
+
* 判断URL是否是外部URL(http/https开头)
|
|
5753
|
+
*/
|
|
5754
|
+
declare function isExternalUrl(url: string): boolean;
|
|
5755
|
+
/**
|
|
5756
|
+
* 判断URL是否已经是base64 data URI
|
|
5757
|
+
*/
|
|
5758
|
+
declare function isBase64DataUri(url: string): boolean;
|
|
5759
|
+
|
|
5728
5760
|
/**
|
|
5729
5761
|
* A2O格式验证器
|
|
5730
5762
|
* 专门处理Claude和OpenAI请求格式的验证
|
|
@@ -7333,4 +7365,4 @@ declare const FEATURES: {
|
|
|
7333
7365
|
readonly externalPackageVerified: true;
|
|
7334
7366
|
};
|
|
7335
7367
|
|
|
7336
|
-
export { A2ORequestAdapter, A2ORequestAdapterStatic, ADAPTERS_VERSION, type AnthropicContentBlock, AnthropicContentBlockBaseSchema, AnthropicContentBlockDeltaEventSchema, AnthropicContentBlockSchema, AnthropicContentBlockStartEventSchema, AnthropicContentBlockStopEventSchema, AnthropicErrorEventSchema, type AnthropicImageContentBlock, AnthropicImageContentBlockSchema, AnthropicImageSourceSchema, type AnthropicMessage, AnthropicMessageDeltaEventSchema, AnthropicMessageSchema, AnthropicMessageStartEventSchema, AnthropicMessageStopEventSchema, AnthropicMetadataSchema, AnthropicPingEventSchema, type AnthropicRequest, AnthropicRequestSchema, type AnthropicResponse, AnthropicResponseSchema, type AnthropicSDKConfig, AnthropicSDKWrapper, type AnthropicStreamEvent, AnthropicStreamEventBaseSchema, AnthropicStreamEventSchema, AnthropicSystemMessageSchema, type AnthropicTextContentBlock, AnthropicTextContentBlockSchema, type AnthropicTool, AnthropicToolInputSchemaSchema, type AnthropicToolResultContentBlock, AnthropicToolResultContentBlockSchema, AnthropicToolSchema, type AnthropicToolUseContentBlock, AnthropicToolUseContentBlockSchema, type AnthropicUsage, AnthropicUsageSchema, type BaseSDKClient, A2ORequestAdapter as ClaudeToOpenAIConverter, type ConversionFixResult, ConversionFixer, type ConversionResult$1 as ConversionResult, type ConversionState, ConversionValidator, type ConvertedRequest, type ConvertedResponse, EMERGENCY_HEALING_STRATEGIES, type EnhancedAdapterOptions, type EnhancedConversionResult, ErrorDetector, type ErrorInfo, ErrorRecovery, type ErrorSeverity, type ErrorType, FEATURES, FormatValidator, type HealingContext, type HealingResult, type HealingRule, StandardProtocolAdapter as NonStreamingIOConverter, O2ASSEAdapter, O2ASSEAdapterStatic, type OpenAIChoice, OpenAIChoiceSchema, OpenAIFunctionParametersSchema, OpenAIFunctionSchema, type OpenAIMessage, OpenAIMessageContentSchema, OpenAIMessageSchema, type OpenAIRequest$1 as OpenAIRequest, OpenAIRequestSchema, type OpenAIResponse$1 as OpenAIResponse, OpenAIResponseSchema, type OpenAISDKConfig, OpenAISDKWrapper, type OpenAIStreamChunk, OpenAIStreamChunkSchema, O2ASSEAdapter as OpenAIToClaudeSSEConverter, type OpenAITool, type OpenAIToolCall, OpenAIToolCallSchema, OpenAIToolSchema, type OpenAIUsage, OpenAIUsageSchema, ProtocolHealer, RECOVERY_STRATEGIES, REQUEST_HEALING_STRATEGIES, RESPONSE_HEALING_STRATEGIES, type RecoveryResult, type RecoveryStrategy, type RequestOptions, type SDKConfig, SDKFactory, type SDKProvider, type SDKResponse, type SDKStreamEvent, SSEEventGenerator, STREAM_HEALING_STRATEGIES, type ConversionResult as SchemaConversionResult, StandardProtocolAdapter as StandardGateway, StandardProtocolAdapter, type StandardProtocolAdapterOptions, StreamingProtocolAdapter as StreamingGateway, StreamingProtocolAdapter as StreamingIOConverter, StreamingProtocolAdapter, type StreamingProtocolAdapterOptions, type UnifiedSDKConfig, type ValidationResult, attemptRecovery, conversionValidator, createAnthropicSDK, createOpenAISDK, createValidator, errorRecovery, getAllHealingStrategies, getGlobalLogger, getRecoveryRecommendations, getStrategiesForContext, healA2ORequest, healO2ARequest, healO2AResponse, healingValidate, isRecoverable, protocolHealer, safeValidate, sdkFactory, selectSDKByModel, strictValidate, validateA2OConversion, validateAnthropicRequest, validateAnthropicResponse, validateAnthropicStreamEvent, validateBatch, validateO2AConversion, validateOpenAIRequest, validateOpenAIResponse, validateOpenAIStreamChunk, validateSDKConfig, validateStreamConversion };
|
|
7368
|
+
export { A2ORequestAdapter, A2ORequestAdapterStatic, ADAPTERS_VERSION, type AnthropicContentBlock, AnthropicContentBlockBaseSchema, AnthropicContentBlockDeltaEventSchema, AnthropicContentBlockSchema, AnthropicContentBlockStartEventSchema, AnthropicContentBlockStopEventSchema, AnthropicErrorEventSchema, type AnthropicImageContentBlock, AnthropicImageContentBlockSchema, AnthropicImageSourceSchema, type AnthropicMessage, AnthropicMessageDeltaEventSchema, AnthropicMessageSchema, AnthropicMessageStartEventSchema, AnthropicMessageStopEventSchema, AnthropicMetadataSchema, AnthropicPingEventSchema, type AnthropicRequest, AnthropicRequestSchema, type AnthropicResponse, AnthropicResponseSchema, type AnthropicSDKConfig, AnthropicSDKWrapper, type AnthropicStreamEvent, AnthropicStreamEventBaseSchema, AnthropicStreamEventSchema, AnthropicSystemMessageSchema, type AnthropicTextContentBlock, AnthropicTextContentBlockSchema, type AnthropicTool, AnthropicToolInputSchemaSchema, type AnthropicToolResultContentBlock, AnthropicToolResultContentBlockSchema, AnthropicToolSchema, type AnthropicToolUseContentBlock, AnthropicToolUseContentBlockSchema, type AnthropicUsage, AnthropicUsageSchema, type BaseSDKClient, A2ORequestAdapter as ClaudeToOpenAIConverter, type ConversionFixResult, ConversionFixer, type ConversionResult$1 as ConversionResult, type ConversionState, ConversionValidator, type ConvertedRequest, type ConvertedResponse, EMERGENCY_HEALING_STRATEGIES, type EnhancedAdapterOptions, type EnhancedConversionResult, ErrorDetector, type ErrorInfo, ErrorRecovery, type ErrorSeverity, type ErrorType, FEATURES, FormatValidator, type HealingContext, type HealingResult, type HealingRule, StandardProtocolAdapter as NonStreamingIOConverter, O2ASSEAdapter, O2ASSEAdapterStatic, type OpenAIChoice, OpenAIChoiceSchema, OpenAIFunctionParametersSchema, OpenAIFunctionSchema, type OpenAIMessage, OpenAIMessageContentSchema, OpenAIMessageSchema, type OpenAIRequest$1 as OpenAIRequest, OpenAIRequestSchema, type OpenAIResponse$1 as OpenAIResponse, OpenAIResponseSchema, type OpenAISDKConfig, OpenAISDKWrapper, type OpenAIStreamChunk, OpenAIStreamChunkSchema, O2ASSEAdapter as OpenAIToClaudeSSEConverter, type OpenAITool, type OpenAIToolCall, OpenAIToolCallSchema, OpenAIToolSchema, type OpenAIUsage, OpenAIUsageSchema, ProtocolHealer, RECOVERY_STRATEGIES, REQUEST_HEALING_STRATEGIES, RESPONSE_HEALING_STRATEGIES, type RecoveryResult, type RecoveryStrategy, type RequestOptions, type SDKConfig, SDKFactory, type SDKProvider, type SDKResponse, type SDKStreamEvent, SSEEventGenerator, STREAM_HEALING_STRATEGIES, type ConversionResult as SchemaConversionResult, StandardProtocolAdapter as StandardGateway, StandardProtocolAdapter, type StandardProtocolAdapterOptions, StreamingProtocolAdapter as StreamingGateway, StreamingProtocolAdapter as StreamingIOConverter, StreamingProtocolAdapter, type StreamingProtocolAdapterOptions, type UnifiedSDKConfig, type ValidationResult, attemptRecovery, conversionValidator, createAnthropicSDK, createOpenAISDK, createValidator, downloadImageAsBase64, errorRecovery, getAllHealingStrategies, getGlobalLogger, getRecoveryRecommendations, getStrategiesForContext, healA2ORequest, healO2ARequest, healO2AResponse, healingValidate, isBase64DataUri, isExternalUrl, isRecoverable, protocolHealer, safeValidate, sdkFactory, selectSDKByModel, strictValidate, validateA2OConversion, validateAnthropicRequest, validateAnthropicResponse, validateAnthropicStreamEvent, validateBatch, validateO2AConversion, validateOpenAIRequest, validateOpenAIResponse, validateOpenAIStreamChunk, validateSDKConfig, validateStreamConversion };
|
package/dist/index.js
CHANGED
|
@@ -453,6 +453,7 @@ __export(index_exports, {
|
|
|
453
453
|
createAnthropicSDK: () => createAnthropicSDK,
|
|
454
454
|
createOpenAISDK: () => createOpenAISDK,
|
|
455
455
|
createValidator: () => createValidator,
|
|
456
|
+
downloadImageAsBase64: () => downloadImageAsBase64,
|
|
456
457
|
errorRecovery: () => errorRecovery,
|
|
457
458
|
getAllHealingStrategies: () => getAllHealingStrategies,
|
|
458
459
|
getGlobalLogger: () => getGlobalLogger,
|
|
@@ -462,6 +463,8 @@ __export(index_exports, {
|
|
|
462
463
|
healO2ARequest: () => healO2ARequest,
|
|
463
464
|
healO2AResponse: () => healO2AResponse,
|
|
464
465
|
healingValidate: () => healingValidate,
|
|
466
|
+
isBase64DataUri: () => isBase64DataUri,
|
|
467
|
+
isExternalUrl: () => isExternalUrl,
|
|
465
468
|
isRecoverable: () => isRecoverable,
|
|
466
469
|
protocolHealer: () => protocolHealer,
|
|
467
470
|
safeValidate: () => safeValidate,
|
|
@@ -532,6 +535,14 @@ var DEFAULT_CONFIG = {
|
|
|
532
535
|
enabled: false,
|
|
533
536
|
logLevel: "warn",
|
|
534
537
|
enableMetrics: false
|
|
538
|
+
},
|
|
539
|
+
imageProxy: {
|
|
540
|
+
enabled: true,
|
|
541
|
+
// 默认启用图片代理(解决GitHub Copilot等不支持外部URL的问题)
|
|
542
|
+
timeout: 1e4,
|
|
543
|
+
// 10秒超时
|
|
544
|
+
maxSize: 10 * 1024 * 1024
|
|
545
|
+
// 10MB最大文件大小
|
|
535
546
|
}
|
|
536
547
|
};
|
|
537
548
|
var SUPPORTED_IMAGE_TYPES = [
|
|
@@ -556,6 +567,61 @@ var TOOL_CONVERSION = {
|
|
|
556
567
|
UNKNOWN_TOOL_FALLBACK: "unknown_tool"
|
|
557
568
|
};
|
|
558
569
|
|
|
570
|
+
// src/core/a2o-request-adapter/image-proxy.ts
|
|
571
|
+
var SUPPORTED_IMAGE_MIME_TYPES = [
|
|
572
|
+
"image/jpeg",
|
|
573
|
+
"image/png",
|
|
574
|
+
"image/gif",
|
|
575
|
+
"image/webp"
|
|
576
|
+
];
|
|
577
|
+
async function downloadImageAsBase64(url, options = {}) {
|
|
578
|
+
const {
|
|
579
|
+
timeout = 1e4,
|
|
580
|
+
maxSize = 10 * 1024 * 1024,
|
|
581
|
+
// 10MB
|
|
582
|
+
userAgent = "ai-protocol-adapters/1.0"
|
|
583
|
+
} = options;
|
|
584
|
+
try {
|
|
585
|
+
const controller = new AbortController();
|
|
586
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
587
|
+
const response = await fetch(url, {
|
|
588
|
+
signal: controller.signal,
|
|
589
|
+
headers: {
|
|
590
|
+
"User-Agent": userAgent
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
clearTimeout(timeoutId);
|
|
594
|
+
if (!response.ok) {
|
|
595
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
596
|
+
}
|
|
597
|
+
const contentType = response.headers.get("content-type");
|
|
598
|
+
if (!contentType || !SUPPORTED_IMAGE_MIME_TYPES.some((type) => contentType.includes(type))) {
|
|
599
|
+
throw new Error(`Unsupported content type: ${contentType}`);
|
|
600
|
+
}
|
|
601
|
+
const contentLength = response.headers.get("content-length");
|
|
602
|
+
if (contentLength && parseInt(contentLength) > maxSize) {
|
|
603
|
+
throw new Error(`Image too large: ${contentLength} bytes (max: ${maxSize} bytes)`);
|
|
604
|
+
}
|
|
605
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
606
|
+
if (arrayBuffer.byteLength > maxSize) {
|
|
607
|
+
throw new Error(`Image too large: ${arrayBuffer.byteLength} bytes (max: ${maxSize} bytes)`);
|
|
608
|
+
}
|
|
609
|
+
const base64 = Buffer.from(arrayBuffer).toString("base64");
|
|
610
|
+
return `data:${contentType};base64,${base64}`;
|
|
611
|
+
} catch (error) {
|
|
612
|
+
if (error.name === "AbortError") {
|
|
613
|
+
throw new Error(`Image download timeout after ${timeout}ms`);
|
|
614
|
+
}
|
|
615
|
+
throw new Error(`Failed to download image from ${url}: ${error.message}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function isExternalUrl(url) {
|
|
619
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
620
|
+
}
|
|
621
|
+
function isBase64DataUri(url) {
|
|
622
|
+
return url.startsWith("data:");
|
|
623
|
+
}
|
|
624
|
+
|
|
559
625
|
// src/core/a2o-request-adapter/message-converter.ts
|
|
560
626
|
var MessageConverter = class {
|
|
561
627
|
/**
|
|
@@ -695,9 +761,23 @@ var MessageConverter = class {
|
|
|
695
761
|
}
|
|
696
762
|
/**
|
|
697
763
|
* 转换图片内容格式
|
|
764
|
+
* 支持两种格式:URL 和 base64
|
|
698
765
|
*/
|
|
699
766
|
static convertImageContent(item) {
|
|
700
|
-
if (item.source
|
|
767
|
+
if (!item.source) {
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
if (item.source.type === "url" && item.source.url) {
|
|
771
|
+
return {
|
|
772
|
+
type: "image_url",
|
|
773
|
+
image_url: {
|
|
774
|
+
url: item.source.url,
|
|
775
|
+
detail: "auto"
|
|
776
|
+
// OpenAI 支持的可选参数
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
if (item.source.type === "base64" && item.source.data && item.source.media_type) {
|
|
701
781
|
if (!SUPPORTED_IMAGE_TYPES.includes(item.source.media_type)) {
|
|
702
782
|
console.warn(`\u4E0D\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${item.source.media_type}`);
|
|
703
783
|
return null;
|
|
@@ -706,7 +786,8 @@ var MessageConverter = class {
|
|
|
706
786
|
return {
|
|
707
787
|
type: "image_url",
|
|
708
788
|
image_url: {
|
|
709
|
-
url: dataUri
|
|
789
|
+
url: dataUri,
|
|
790
|
+
detail: "auto"
|
|
710
791
|
}
|
|
711
792
|
};
|
|
712
793
|
}
|
|
@@ -802,6 +883,170 @@ var MessageConverter = class {
|
|
|
802
883
|
}
|
|
803
884
|
return null;
|
|
804
885
|
}
|
|
886
|
+
/**
|
|
887
|
+
* 异步转换图片内容格式(支持URL自动下载转base64)
|
|
888
|
+
* @param item 图片内容项
|
|
889
|
+
* @param downloadUrls 是否下载URL并转换为base64(默认true)
|
|
890
|
+
*/
|
|
891
|
+
static async convertImageContentAsync(item, downloadUrls = true) {
|
|
892
|
+
if (!item.source) {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
if (item.source.type === "url" && item.source.url) {
|
|
896
|
+
const url = item.source.url;
|
|
897
|
+
if (isBase64DataUri(url)) {
|
|
898
|
+
return {
|
|
899
|
+
type: "image_url",
|
|
900
|
+
image_url: {
|
|
901
|
+
url,
|
|
902
|
+
detail: "auto"
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (downloadUrls && isExternalUrl(url)) {
|
|
907
|
+
try {
|
|
908
|
+
console.log(`[MessageConverter] Downloading image from URL: ${url}`);
|
|
909
|
+
const base64DataUri = await downloadImageAsBase64(url);
|
|
910
|
+
console.log(`[MessageConverter] Successfully converted image to base64`);
|
|
911
|
+
return {
|
|
912
|
+
type: "image_url",
|
|
913
|
+
image_url: {
|
|
914
|
+
url: base64DataUri,
|
|
915
|
+
detail: "auto"
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
} catch (error) {
|
|
919
|
+
console.error(`[MessageConverter] Failed to download image: ${error.message}`);
|
|
920
|
+
return {
|
|
921
|
+
type: "image_url",
|
|
922
|
+
image_url: {
|
|
923
|
+
url,
|
|
924
|
+
detail: "auto"
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return {
|
|
930
|
+
type: "image_url",
|
|
931
|
+
image_url: {
|
|
932
|
+
url,
|
|
933
|
+
detail: "auto"
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
if (item.source.type === "base64" && item.source.data && item.source.media_type) {
|
|
938
|
+
if (!SUPPORTED_IMAGE_TYPES.includes(item.source.media_type)) {
|
|
939
|
+
console.warn(`\u4E0D\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${item.source.media_type}`);
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
942
|
+
const dataUri = `data:${item.source.media_type};base64,${item.source.data}`;
|
|
943
|
+
return {
|
|
944
|
+
type: "image_url",
|
|
945
|
+
image_url: {
|
|
946
|
+
url: dataUri,
|
|
947
|
+
detail: "auto"
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* 异步处理消息内容(支持图片URL下载)
|
|
955
|
+
*/
|
|
956
|
+
static async processMessageContentAsync(content, downloadUrls = true) {
|
|
957
|
+
const textContent = [];
|
|
958
|
+
const toolUses = [];
|
|
959
|
+
const toolResults = [];
|
|
960
|
+
for (const item of content) {
|
|
961
|
+
if (item.type) {
|
|
962
|
+
switch (item.type) {
|
|
963
|
+
case "text":
|
|
964
|
+
if (item.text) {
|
|
965
|
+
textContent.push({ type: "text", text: item.text });
|
|
966
|
+
}
|
|
967
|
+
break;
|
|
968
|
+
case "tool_use":
|
|
969
|
+
toolUses.push(item);
|
|
970
|
+
break;
|
|
971
|
+
case "tool_result":
|
|
972
|
+
toolResults.push(item);
|
|
973
|
+
break;
|
|
974
|
+
case "image":
|
|
975
|
+
const imageContent = await this.convertImageContentAsync(item, downloadUrls);
|
|
976
|
+
if (imageContent) {
|
|
977
|
+
textContent.push(imageContent);
|
|
978
|
+
}
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return { textContent, toolUses, toolResults };
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* 异步转换消息格式(支持图片URL自动下载)
|
|
987
|
+
* @param messages Claude格式的消息数组
|
|
988
|
+
* @param system 系统消息
|
|
989
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true,解决GitHub Copilot等API不支持外部URL的问题)
|
|
990
|
+
*/
|
|
991
|
+
static async convertMessagesAsync(messages, system, downloadImageUrls = true) {
|
|
992
|
+
const debugEnabled = process.env.AI_PROTOCOL_DEBUG === "true";
|
|
993
|
+
if (debugEnabled) {
|
|
994
|
+
console.debug(
|
|
995
|
+
`[MessageConverter] convertMessagesAsync called (downloadImageUrls: ${downloadImageUrls})`
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
const context = this.createConversionContext(messages);
|
|
999
|
+
const convertedMessages = [];
|
|
1000
|
+
for (const msg of messages) {
|
|
1001
|
+
if (Array.isArray(msg.content)) {
|
|
1002
|
+
const processedMessages = await this.processComplexMessageAsync(msg, context, downloadImageUrls);
|
|
1003
|
+
convertedMessages.push(...processedMessages);
|
|
1004
|
+
} else {
|
|
1005
|
+
const safeMsg = { ...msg };
|
|
1006
|
+
if (safeMsg.content === null || safeMsg.content === void 0) {
|
|
1007
|
+
safeMsg.content = "";
|
|
1008
|
+
}
|
|
1009
|
+
convertedMessages.push(safeMsg);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const systemMessage = this.processSystemMessage(system);
|
|
1013
|
+
if (systemMessage) {
|
|
1014
|
+
return [systemMessage, ...convertedMessages];
|
|
1015
|
+
}
|
|
1016
|
+
return convertedMessages;
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* 异步处理复杂消息(支持图片URL下载)
|
|
1020
|
+
*/
|
|
1021
|
+
static async processComplexMessageAsync(msg, context, downloadUrls) {
|
|
1022
|
+
const { textContent, toolUses, toolResults } = await this.processMessageContentAsync(
|
|
1023
|
+
msg.content,
|
|
1024
|
+
downloadUrls
|
|
1025
|
+
);
|
|
1026
|
+
const result = [];
|
|
1027
|
+
if (msg.role === "user") {
|
|
1028
|
+
const toolMessages = this.createToolResultMessages(toolResults, context.toolIdToNameMap);
|
|
1029
|
+
result.push(...toolMessages);
|
|
1030
|
+
const textMessage = this.createTextMessage("user", textContent);
|
|
1031
|
+
if (textMessage) {
|
|
1032
|
+
result.push(textMessage);
|
|
1033
|
+
}
|
|
1034
|
+
} else if (msg.role === "assistant") {
|
|
1035
|
+
if (toolUses.length > 0) {
|
|
1036
|
+
const assistantMessage = this.createAssistantMessageWithToolCalls(textContent, toolUses);
|
|
1037
|
+
result.push(assistantMessage);
|
|
1038
|
+
toolUses.forEach((toolUse) => {
|
|
1039
|
+
context.toolIdToNameMap.set(toolUse.id, toolUse.name);
|
|
1040
|
+
});
|
|
1041
|
+
} else {
|
|
1042
|
+
const textMessage = this.createTextMessage("assistant", textContent);
|
|
1043
|
+
if (textMessage) {
|
|
1044
|
+
result.push(textMessage);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
return result;
|
|
1049
|
+
}
|
|
805
1050
|
};
|
|
806
1051
|
|
|
807
1052
|
// src/core/a2o-request-adapter/tool-converter.ts
|
|
@@ -3454,15 +3699,21 @@ var A2ORequestAdapter = class {
|
|
|
3454
3699
|
}
|
|
3455
3700
|
}
|
|
3456
3701
|
/**
|
|
3457
|
-
*
|
|
3702
|
+
* 执行核心转换逻辑(支持图片代理)
|
|
3458
3703
|
*/
|
|
3459
3704
|
async performCoreConversion(anthropicRequest) {
|
|
3460
3705
|
if (this.config.enableFormatValidation) {
|
|
3461
3706
|
FormatValidator.validateClaudeRequest(anthropicRequest);
|
|
3462
3707
|
}
|
|
3708
|
+
const messages = this.config.imageProxy.enabled ? await MessageConverter.convertMessagesAsync(
|
|
3709
|
+
anthropicRequest.messages,
|
|
3710
|
+
anthropicRequest.system,
|
|
3711
|
+
true
|
|
3712
|
+
// 启用图片下载
|
|
3713
|
+
) : MessageConverter.convertMessages(anthropicRequest.messages, anthropicRequest.system);
|
|
3463
3714
|
const openaiRequest = {
|
|
3464
3715
|
model: anthropicRequest.model,
|
|
3465
|
-
messages
|
|
3716
|
+
messages,
|
|
3466
3717
|
max_tokens: anthropicRequest.max_tokens,
|
|
3467
3718
|
temperature: anthropicRequest.temperature,
|
|
3468
3719
|
stream: anthropicRequest.stream
|
|
@@ -3772,6 +4023,36 @@ var A2ORequestAdapterStatic = {
|
|
|
3772
4023
|
*/
|
|
3773
4024
|
getToolMapping: (claudeToolName) => {
|
|
3774
4025
|
return claudeToolName;
|
|
4026
|
+
},
|
|
4027
|
+
/**
|
|
4028
|
+
* 转换Anthropic请求格式为OpenAI兼容格式(异步版本,支持图片URL自动下载)
|
|
4029
|
+
* 解决GitHub Copilot等API不支持外部图片URL的问题
|
|
4030
|
+
* @param anthropicRequest Claude格式的请求
|
|
4031
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true)
|
|
4032
|
+
*/
|
|
4033
|
+
convertAnthropicRequestToOpenAIAsync: async (anthropicRequest, downloadImageUrls = true) => {
|
|
4034
|
+
const adapter = new A2ORequestAdapter({
|
|
4035
|
+
debugMode: false,
|
|
4036
|
+
maxDescriptionLength: 100,
|
|
4037
|
+
enableToolNameValidation: true,
|
|
4038
|
+
enableFormatValidation: true,
|
|
4039
|
+
validation: { enabled: true, strict: false },
|
|
4040
|
+
healing: { enabled: true, maxAttempts: 2, enableCustomRules: true },
|
|
4041
|
+
recovery: { enabled: false, maxRetries: 0, backoffMs: 1e3 },
|
|
4042
|
+
monitoring: { enabled: false, logLevel: "none", enableMetrics: false },
|
|
4043
|
+
imageProxy: {
|
|
4044
|
+
enabled: downloadImageUrls,
|
|
4045
|
+
timeout: 1e4,
|
|
4046
|
+
maxSize: 10 * 1024 * 1024
|
|
4047
|
+
}
|
|
4048
|
+
});
|
|
4049
|
+
try {
|
|
4050
|
+
const result = await adapter.performCoreConversion(anthropicRequest);
|
|
4051
|
+
return result;
|
|
4052
|
+
} catch (error) {
|
|
4053
|
+
console.warn(`[A2ORequestAdapterStatic] Async conversion failed: ${error?.message || error}`);
|
|
4054
|
+
return adapter.performBasicConversion(anthropicRequest, true);
|
|
4055
|
+
}
|
|
3775
4056
|
}
|
|
3776
4057
|
};
|
|
3777
4058
|
|
|
@@ -6658,6 +6939,7 @@ var FEATURES = {
|
|
|
6658
6939
|
createAnthropicSDK,
|
|
6659
6940
|
createOpenAISDK,
|
|
6660
6941
|
createValidator,
|
|
6942
|
+
downloadImageAsBase64,
|
|
6661
6943
|
errorRecovery,
|
|
6662
6944
|
getAllHealingStrategies,
|
|
6663
6945
|
getGlobalLogger,
|
|
@@ -6667,6 +6949,8 @@ var FEATURES = {
|
|
|
6667
6949
|
healO2ARequest,
|
|
6668
6950
|
healO2AResponse,
|
|
6669
6951
|
healingValidate,
|
|
6952
|
+
isBase64DataUri,
|
|
6953
|
+
isExternalUrl,
|
|
6670
6954
|
isRecoverable,
|
|
6671
6955
|
protocolHealer,
|
|
6672
6956
|
safeValidate,
|
package/dist/index.mjs
CHANGED
|
@@ -425,6 +425,14 @@ var DEFAULT_CONFIG = {
|
|
|
425
425
|
enabled: false,
|
|
426
426
|
logLevel: "warn",
|
|
427
427
|
enableMetrics: false
|
|
428
|
+
},
|
|
429
|
+
imageProxy: {
|
|
430
|
+
enabled: true,
|
|
431
|
+
// 默认启用图片代理(解决GitHub Copilot等不支持外部URL的问题)
|
|
432
|
+
timeout: 1e4,
|
|
433
|
+
// 10秒超时
|
|
434
|
+
maxSize: 10 * 1024 * 1024
|
|
435
|
+
// 10MB最大文件大小
|
|
428
436
|
}
|
|
429
437
|
};
|
|
430
438
|
var SUPPORTED_IMAGE_TYPES = [
|
|
@@ -449,6 +457,61 @@ var TOOL_CONVERSION = {
|
|
|
449
457
|
UNKNOWN_TOOL_FALLBACK: "unknown_tool"
|
|
450
458
|
};
|
|
451
459
|
|
|
460
|
+
// src/core/a2o-request-adapter/image-proxy.ts
|
|
461
|
+
var SUPPORTED_IMAGE_MIME_TYPES = [
|
|
462
|
+
"image/jpeg",
|
|
463
|
+
"image/png",
|
|
464
|
+
"image/gif",
|
|
465
|
+
"image/webp"
|
|
466
|
+
];
|
|
467
|
+
async function downloadImageAsBase64(url, options = {}) {
|
|
468
|
+
const {
|
|
469
|
+
timeout = 1e4,
|
|
470
|
+
maxSize = 10 * 1024 * 1024,
|
|
471
|
+
// 10MB
|
|
472
|
+
userAgent = "ai-protocol-adapters/1.0"
|
|
473
|
+
} = options;
|
|
474
|
+
try {
|
|
475
|
+
const controller = new AbortController();
|
|
476
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
477
|
+
const response = await fetch(url, {
|
|
478
|
+
signal: controller.signal,
|
|
479
|
+
headers: {
|
|
480
|
+
"User-Agent": userAgent
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
clearTimeout(timeoutId);
|
|
484
|
+
if (!response.ok) {
|
|
485
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
486
|
+
}
|
|
487
|
+
const contentType = response.headers.get("content-type");
|
|
488
|
+
if (!contentType || !SUPPORTED_IMAGE_MIME_TYPES.some((type) => contentType.includes(type))) {
|
|
489
|
+
throw new Error(`Unsupported content type: ${contentType}`);
|
|
490
|
+
}
|
|
491
|
+
const contentLength = response.headers.get("content-length");
|
|
492
|
+
if (contentLength && parseInt(contentLength) > maxSize) {
|
|
493
|
+
throw new Error(`Image too large: ${contentLength} bytes (max: ${maxSize} bytes)`);
|
|
494
|
+
}
|
|
495
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
496
|
+
if (arrayBuffer.byteLength > maxSize) {
|
|
497
|
+
throw new Error(`Image too large: ${arrayBuffer.byteLength} bytes (max: ${maxSize} bytes)`);
|
|
498
|
+
}
|
|
499
|
+
const base64 = Buffer.from(arrayBuffer).toString("base64");
|
|
500
|
+
return `data:${contentType};base64,${base64}`;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (error.name === "AbortError") {
|
|
503
|
+
throw new Error(`Image download timeout after ${timeout}ms`);
|
|
504
|
+
}
|
|
505
|
+
throw new Error(`Failed to download image from ${url}: ${error.message}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function isExternalUrl(url) {
|
|
509
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
510
|
+
}
|
|
511
|
+
function isBase64DataUri(url) {
|
|
512
|
+
return url.startsWith("data:");
|
|
513
|
+
}
|
|
514
|
+
|
|
452
515
|
// src/core/a2o-request-adapter/message-converter.ts
|
|
453
516
|
var MessageConverter = class {
|
|
454
517
|
/**
|
|
@@ -588,9 +651,23 @@ var MessageConverter = class {
|
|
|
588
651
|
}
|
|
589
652
|
/**
|
|
590
653
|
* 转换图片内容格式
|
|
654
|
+
* 支持两种格式:URL 和 base64
|
|
591
655
|
*/
|
|
592
656
|
static convertImageContent(item) {
|
|
593
|
-
if (item.source
|
|
657
|
+
if (!item.source) {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
if (item.source.type === "url" && item.source.url) {
|
|
661
|
+
return {
|
|
662
|
+
type: "image_url",
|
|
663
|
+
image_url: {
|
|
664
|
+
url: item.source.url,
|
|
665
|
+
detail: "auto"
|
|
666
|
+
// OpenAI 支持的可选参数
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
if (item.source.type === "base64" && item.source.data && item.source.media_type) {
|
|
594
671
|
if (!SUPPORTED_IMAGE_TYPES.includes(item.source.media_type)) {
|
|
595
672
|
console.warn(`\u4E0D\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${item.source.media_type}`);
|
|
596
673
|
return null;
|
|
@@ -599,7 +676,8 @@ var MessageConverter = class {
|
|
|
599
676
|
return {
|
|
600
677
|
type: "image_url",
|
|
601
678
|
image_url: {
|
|
602
|
-
url: dataUri
|
|
679
|
+
url: dataUri,
|
|
680
|
+
detail: "auto"
|
|
603
681
|
}
|
|
604
682
|
};
|
|
605
683
|
}
|
|
@@ -695,6 +773,170 @@ var MessageConverter = class {
|
|
|
695
773
|
}
|
|
696
774
|
return null;
|
|
697
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* 异步转换图片内容格式(支持URL自动下载转base64)
|
|
778
|
+
* @param item 图片内容项
|
|
779
|
+
* @param downloadUrls 是否下载URL并转换为base64(默认true)
|
|
780
|
+
*/
|
|
781
|
+
static async convertImageContentAsync(item, downloadUrls = true) {
|
|
782
|
+
if (!item.source) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
if (item.source.type === "url" && item.source.url) {
|
|
786
|
+
const url = item.source.url;
|
|
787
|
+
if (isBase64DataUri(url)) {
|
|
788
|
+
return {
|
|
789
|
+
type: "image_url",
|
|
790
|
+
image_url: {
|
|
791
|
+
url,
|
|
792
|
+
detail: "auto"
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
if (downloadUrls && isExternalUrl(url)) {
|
|
797
|
+
try {
|
|
798
|
+
console.log(`[MessageConverter] Downloading image from URL: ${url}`);
|
|
799
|
+
const base64DataUri = await downloadImageAsBase64(url);
|
|
800
|
+
console.log(`[MessageConverter] Successfully converted image to base64`);
|
|
801
|
+
return {
|
|
802
|
+
type: "image_url",
|
|
803
|
+
image_url: {
|
|
804
|
+
url: base64DataUri,
|
|
805
|
+
detail: "auto"
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
} catch (error) {
|
|
809
|
+
console.error(`[MessageConverter] Failed to download image: ${error.message}`);
|
|
810
|
+
return {
|
|
811
|
+
type: "image_url",
|
|
812
|
+
image_url: {
|
|
813
|
+
url,
|
|
814
|
+
detail: "auto"
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return {
|
|
820
|
+
type: "image_url",
|
|
821
|
+
image_url: {
|
|
822
|
+
url,
|
|
823
|
+
detail: "auto"
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
if (item.source.type === "base64" && item.source.data && item.source.media_type) {
|
|
828
|
+
if (!SUPPORTED_IMAGE_TYPES.includes(item.source.media_type)) {
|
|
829
|
+
console.warn(`\u4E0D\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F: ${item.source.media_type}`);
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
const dataUri = `data:${item.source.media_type};base64,${item.source.data}`;
|
|
833
|
+
return {
|
|
834
|
+
type: "image_url",
|
|
835
|
+
image_url: {
|
|
836
|
+
url: dataUri,
|
|
837
|
+
detail: "auto"
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* 异步处理消息内容(支持图片URL下载)
|
|
845
|
+
*/
|
|
846
|
+
static async processMessageContentAsync(content, downloadUrls = true) {
|
|
847
|
+
const textContent = [];
|
|
848
|
+
const toolUses = [];
|
|
849
|
+
const toolResults = [];
|
|
850
|
+
for (const item of content) {
|
|
851
|
+
if (item.type) {
|
|
852
|
+
switch (item.type) {
|
|
853
|
+
case "text":
|
|
854
|
+
if (item.text) {
|
|
855
|
+
textContent.push({ type: "text", text: item.text });
|
|
856
|
+
}
|
|
857
|
+
break;
|
|
858
|
+
case "tool_use":
|
|
859
|
+
toolUses.push(item);
|
|
860
|
+
break;
|
|
861
|
+
case "tool_result":
|
|
862
|
+
toolResults.push(item);
|
|
863
|
+
break;
|
|
864
|
+
case "image":
|
|
865
|
+
const imageContent = await this.convertImageContentAsync(item, downloadUrls);
|
|
866
|
+
if (imageContent) {
|
|
867
|
+
textContent.push(imageContent);
|
|
868
|
+
}
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return { textContent, toolUses, toolResults };
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* 异步转换消息格式(支持图片URL自动下载)
|
|
877
|
+
* @param messages Claude格式的消息数组
|
|
878
|
+
* @param system 系统消息
|
|
879
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true,解决GitHub Copilot等API不支持外部URL的问题)
|
|
880
|
+
*/
|
|
881
|
+
static async convertMessagesAsync(messages, system, downloadImageUrls = true) {
|
|
882
|
+
const debugEnabled = process.env.AI_PROTOCOL_DEBUG === "true";
|
|
883
|
+
if (debugEnabled) {
|
|
884
|
+
console.debug(
|
|
885
|
+
`[MessageConverter] convertMessagesAsync called (downloadImageUrls: ${downloadImageUrls})`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
const context = this.createConversionContext(messages);
|
|
889
|
+
const convertedMessages = [];
|
|
890
|
+
for (const msg of messages) {
|
|
891
|
+
if (Array.isArray(msg.content)) {
|
|
892
|
+
const processedMessages = await this.processComplexMessageAsync(msg, context, downloadImageUrls);
|
|
893
|
+
convertedMessages.push(...processedMessages);
|
|
894
|
+
} else {
|
|
895
|
+
const safeMsg = { ...msg };
|
|
896
|
+
if (safeMsg.content === null || safeMsg.content === void 0) {
|
|
897
|
+
safeMsg.content = "";
|
|
898
|
+
}
|
|
899
|
+
convertedMessages.push(safeMsg);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
const systemMessage = this.processSystemMessage(system);
|
|
903
|
+
if (systemMessage) {
|
|
904
|
+
return [systemMessage, ...convertedMessages];
|
|
905
|
+
}
|
|
906
|
+
return convertedMessages;
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* 异步处理复杂消息(支持图片URL下载)
|
|
910
|
+
*/
|
|
911
|
+
static async processComplexMessageAsync(msg, context, downloadUrls) {
|
|
912
|
+
const { textContent, toolUses, toolResults } = await this.processMessageContentAsync(
|
|
913
|
+
msg.content,
|
|
914
|
+
downloadUrls
|
|
915
|
+
);
|
|
916
|
+
const result = [];
|
|
917
|
+
if (msg.role === "user") {
|
|
918
|
+
const toolMessages = this.createToolResultMessages(toolResults, context.toolIdToNameMap);
|
|
919
|
+
result.push(...toolMessages);
|
|
920
|
+
const textMessage = this.createTextMessage("user", textContent);
|
|
921
|
+
if (textMessage) {
|
|
922
|
+
result.push(textMessage);
|
|
923
|
+
}
|
|
924
|
+
} else if (msg.role === "assistant") {
|
|
925
|
+
if (toolUses.length > 0) {
|
|
926
|
+
const assistantMessage = this.createAssistantMessageWithToolCalls(textContent, toolUses);
|
|
927
|
+
result.push(assistantMessage);
|
|
928
|
+
toolUses.forEach((toolUse) => {
|
|
929
|
+
context.toolIdToNameMap.set(toolUse.id, toolUse.name);
|
|
930
|
+
});
|
|
931
|
+
} else {
|
|
932
|
+
const textMessage = this.createTextMessage("assistant", textContent);
|
|
933
|
+
if (textMessage) {
|
|
934
|
+
result.push(textMessage);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return result;
|
|
939
|
+
}
|
|
698
940
|
};
|
|
699
941
|
|
|
700
942
|
// src/core/a2o-request-adapter/tool-converter.ts
|
|
@@ -3347,15 +3589,21 @@ var A2ORequestAdapter = class {
|
|
|
3347
3589
|
}
|
|
3348
3590
|
}
|
|
3349
3591
|
/**
|
|
3350
|
-
*
|
|
3592
|
+
* 执行核心转换逻辑(支持图片代理)
|
|
3351
3593
|
*/
|
|
3352
3594
|
async performCoreConversion(anthropicRequest) {
|
|
3353
3595
|
if (this.config.enableFormatValidation) {
|
|
3354
3596
|
FormatValidator.validateClaudeRequest(anthropicRequest);
|
|
3355
3597
|
}
|
|
3598
|
+
const messages = this.config.imageProxy.enabled ? await MessageConverter.convertMessagesAsync(
|
|
3599
|
+
anthropicRequest.messages,
|
|
3600
|
+
anthropicRequest.system,
|
|
3601
|
+
true
|
|
3602
|
+
// 启用图片下载
|
|
3603
|
+
) : MessageConverter.convertMessages(anthropicRequest.messages, anthropicRequest.system);
|
|
3356
3604
|
const openaiRequest = {
|
|
3357
3605
|
model: anthropicRequest.model,
|
|
3358
|
-
messages
|
|
3606
|
+
messages,
|
|
3359
3607
|
max_tokens: anthropicRequest.max_tokens,
|
|
3360
3608
|
temperature: anthropicRequest.temperature,
|
|
3361
3609
|
stream: anthropicRequest.stream
|
|
@@ -3665,6 +3913,36 @@ var A2ORequestAdapterStatic = {
|
|
|
3665
3913
|
*/
|
|
3666
3914
|
getToolMapping: (claudeToolName) => {
|
|
3667
3915
|
return claudeToolName;
|
|
3916
|
+
},
|
|
3917
|
+
/**
|
|
3918
|
+
* 转换Anthropic请求格式为OpenAI兼容格式(异步版本,支持图片URL自动下载)
|
|
3919
|
+
* 解决GitHub Copilot等API不支持外部图片URL的问题
|
|
3920
|
+
* @param anthropicRequest Claude格式的请求
|
|
3921
|
+
* @param downloadImageUrls 是否下载图片URL并转换为base64(默认true)
|
|
3922
|
+
*/
|
|
3923
|
+
convertAnthropicRequestToOpenAIAsync: async (anthropicRequest, downloadImageUrls = true) => {
|
|
3924
|
+
const adapter = new A2ORequestAdapter({
|
|
3925
|
+
debugMode: false,
|
|
3926
|
+
maxDescriptionLength: 100,
|
|
3927
|
+
enableToolNameValidation: true,
|
|
3928
|
+
enableFormatValidation: true,
|
|
3929
|
+
validation: { enabled: true, strict: false },
|
|
3930
|
+
healing: { enabled: true, maxAttempts: 2, enableCustomRules: true },
|
|
3931
|
+
recovery: { enabled: false, maxRetries: 0, backoffMs: 1e3 },
|
|
3932
|
+
monitoring: { enabled: false, logLevel: "none", enableMetrics: false },
|
|
3933
|
+
imageProxy: {
|
|
3934
|
+
enabled: downloadImageUrls,
|
|
3935
|
+
timeout: 1e4,
|
|
3936
|
+
maxSize: 10 * 1024 * 1024
|
|
3937
|
+
}
|
|
3938
|
+
});
|
|
3939
|
+
try {
|
|
3940
|
+
const result = await adapter.performCoreConversion(anthropicRequest);
|
|
3941
|
+
return result;
|
|
3942
|
+
} catch (error) {
|
|
3943
|
+
console.warn(`[A2ORequestAdapterStatic] Async conversion failed: ${error?.message || error}`);
|
|
3944
|
+
return adapter.performBasicConversion(anthropicRequest, true);
|
|
3945
|
+
}
|
|
3668
3946
|
}
|
|
3669
3947
|
};
|
|
3670
3948
|
|
|
@@ -6550,6 +6828,7 @@ export {
|
|
|
6550
6828
|
createAnthropicSDK,
|
|
6551
6829
|
createOpenAISDK,
|
|
6552
6830
|
createValidator,
|
|
6831
|
+
downloadImageAsBase64,
|
|
6553
6832
|
errorRecovery,
|
|
6554
6833
|
getAllHealingStrategies,
|
|
6555
6834
|
getGlobalLogger,
|
|
@@ -6559,6 +6838,8 @@ export {
|
|
|
6559
6838
|
healO2ARequest,
|
|
6560
6839
|
healO2AResponse,
|
|
6561
6840
|
healingValidate,
|
|
6841
|
+
isBase64DataUri,
|
|
6842
|
+
isExternalUrl,
|
|
6562
6843
|
isRecoverable,
|
|
6563
6844
|
protocolHealer,
|
|
6564
6845
|
safeValidate,
|
package/package.json
CHANGED