feat: extend proxy runtime parity
This commit is contained in:
@@ -524,6 +524,44 @@ describe('convertOpenAiBodyToAnthropicMessagesBody', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves tool_reference blocks inside tool_result content arrays', () => {
|
||||
const result = sanitizeAnthropicMessagesBody({
|
||||
model: 'claude-opus-4-6',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'tool_1',
|
||||
content: [
|
||||
{ type: 'tool_reference', tool_name: 'lookup' },
|
||||
{ type: 'text', text: 'follow-up' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.messages).toEqual([
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: 'tool_1',
|
||||
content: [
|
||||
{ type: 'tool_reference', tool_name: 'lookup' },
|
||||
{ type: 'text', text: 'follow-up' },
|
||||
],
|
||||
cache_control: { type: 'ephemeral' },
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('adds a second message cache anchor around the 20-block window for long prompts', () => {
|
||||
const longContent = Array.from({ length: 25 }, (_, index) => ({
|
||||
type: 'text',
|
||||
|
||||
@@ -187,12 +187,39 @@ function normalizeTextCandidate(value: unknown): string {
|
||||
return asTrimmedString(value.text ?? value.content ?? value.output_text);
|
||||
}
|
||||
|
||||
function normalizeToolMessageContent(raw: unknown): string {
|
||||
function sanitizeToolReferenceBlock(item: Record<string, unknown>): Record<string, unknown> | null {
|
||||
const toolName = asTrimmedString(item.tool_name ?? item.toolName ?? item.name);
|
||||
if (!toolName) return null;
|
||||
const next: Record<string, unknown> = {
|
||||
...item,
|
||||
type: 'tool_reference',
|
||||
tool_name: toolName,
|
||||
};
|
||||
delete next.toolName;
|
||||
if ('name' in next) delete next.name;
|
||||
return next;
|
||||
}
|
||||
|
||||
function normalizeToolMessageContent(raw: unknown): string | Array<Record<string, unknown>> {
|
||||
if (raw === undefined || raw === null) return '';
|
||||
if (typeof raw === 'string') return raw;
|
||||
if (typeof raw === 'number' || typeof raw === 'boolean') return String(raw);
|
||||
|
||||
if (Array.isArray(raw)) {
|
||||
const structuredBlocks = raw
|
||||
.map((item) => {
|
||||
if (typeof item === 'string') return toAnthropicTextBlock(item);
|
||||
if (!isRecord(item)) return null;
|
||||
const type = asTrimmedString(item.type).toLowerCase();
|
||||
if (type === 'tool_reference') return sanitizeToolReferenceBlock(item);
|
||||
if (type === 'text' || type === 'input_text' || type === 'output_text') {
|
||||
return toAnthropicTextBlock(normalizeTextCandidate(item));
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter((item): item is Record<string, unknown> => item !== null);
|
||||
if (structuredBlocks.length > 0) return structuredBlocks;
|
||||
|
||||
const textParts = raw
|
||||
.map((item) => {
|
||||
if (typeof item === 'string') return item;
|
||||
@@ -329,7 +356,7 @@ function sanitizeAnthropicContentBlock(item: Record<string, unknown>): Record<st
|
||||
if (type === 'tool_result') {
|
||||
const toolUseId = asTrimmedString(item.tool_use_id ?? item.toolUseId);
|
||||
const content = normalizeToolMessageContent(item.content ?? item.result);
|
||||
if (!toolUseId || !content) return null;
|
||||
if (!toolUseId || (typeof content === 'string' ? !content : content.length <= 0)) return null;
|
||||
const next: Record<string, unknown> = {
|
||||
type: 'tool_result',
|
||||
tool_use_id: toolUseId,
|
||||
@@ -355,6 +382,10 @@ function sanitizeAnthropicContentBlock(item: Record<string, unknown>): Record<st
|
||||
return next;
|
||||
}
|
||||
|
||||
if (type === 'tool_reference') {
|
||||
return sanitizeToolReferenceBlock(item);
|
||||
}
|
||||
|
||||
return { ...item };
|
||||
}
|
||||
|
||||
@@ -846,8 +877,11 @@ export function convertOpenAiBodyToAnthropicMessagesBody(
|
||||
asTrimmedString(toolCandidate.tool_call_id)
|
||||
|| asTrimmedString(toolCandidate.id)
|
||||
);
|
||||
const toolResultContent = normalizeToolMessageContent(toolCandidate.content).trim();
|
||||
if (toolUseId && toolResultContent) {
|
||||
const toolResultContent = normalizeToolMessageContent(toolCandidate.content);
|
||||
const hasToolResultContent = typeof toolResultContent === 'string'
|
||||
? toolResultContent.trim().length > 0
|
||||
: toolResultContent.length > 0;
|
||||
if (toolUseId && hasToolResultContent) {
|
||||
toolResultBlocks.push({
|
||||
type: 'tool_result',
|
||||
tool_use_id: toolUseId,
|
||||
|
||||
Reference in New Issue
Block a user