Fix bug
This commit is contained in:
@@ -3,9 +3,10 @@
|
||||
// Anthropic tool_use.id must match: ^[a-zA-Z0-9_-]+$
|
||||
const TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
// Generate unique tool call ID (always valid for Anthropic)
|
||||
export function generateToolCallId() {
|
||||
return `call_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
||||
// Generate deterministic tool call ID from position + tool name (cache-friendly)
|
||||
export function generateToolCallId(msgIndex = 0, tcIndex = 0, toolName = "") {
|
||||
const name = toolName ? `_${toolName.replace(/[^a-zA-Z0-9_-]/g, "")}` : "";
|
||||
return `call_msg${msgIndex}_tc${tcIndex}${name}`;
|
||||
}
|
||||
|
||||
// Sanitize ID to match Anthropic pattern: keep only alphanumeric, underscore, hyphen
|
||||
@@ -19,13 +20,15 @@ function sanitizeToolId(id) {
|
||||
export function ensureToolCallIds(body) {
|
||||
if (!body.messages || !Array.isArray(body.messages)) return body;
|
||||
|
||||
for (const msg of body.messages) {
|
||||
for (let i = 0; i < body.messages.length; i++) {
|
||||
const msg = body.messages[i];
|
||||
if (msg.role === "assistant" && msg.tool_calls && Array.isArray(msg.tool_calls)) {
|
||||
for (const tc of msg.tool_calls) {
|
||||
for (let j = 0; j < msg.tool_calls.length; j++) {
|
||||
const tc = msg.tool_calls[j];
|
||||
// Validate or regenerate ID for Anthropic compatibility
|
||||
if (!tc.id || !TOOL_ID_PATTERN.test(tc.id)) {
|
||||
const sanitized = sanitizeToolId(tc.id);
|
||||
tc.id = sanitized || generateToolCallId();
|
||||
tc.id = sanitized || generateToolCallId(i, j, tc.function?.name);
|
||||
}
|
||||
if (!tc.type) {
|
||||
tc.type = "function";
|
||||
@@ -40,20 +43,21 @@ export function ensureToolCallIds(body) {
|
||||
// Validate tool_call_id in tool messages (role: "tool")
|
||||
if (msg.role === "tool" && msg.tool_call_id && !TOOL_ID_PATTERN.test(msg.tool_call_id)) {
|
||||
const sanitized = sanitizeToolId(msg.tool_call_id);
|
||||
msg.tool_call_id = sanitized || generateToolCallId();
|
||||
msg.tool_call_id = sanitized || generateToolCallId(i, 0);
|
||||
}
|
||||
|
||||
// Also validate tool_use blocks in content (Claude format)
|
||||
if (Array.isArray(msg.content)) {
|
||||
for (const block of msg.content) {
|
||||
for (let k = 0; k < msg.content.length; k++) {
|
||||
const block = msg.content[k];
|
||||
if (block.type === "tool_use" && block.id && !TOOL_ID_PATTERN.test(block.id)) {
|
||||
const sanitized = sanitizeToolId(block.id);
|
||||
block.id = sanitized || generateToolCallId();
|
||||
block.id = sanitized || generateToolCallId(i, k, block.name);
|
||||
}
|
||||
// Validate tool_use_id in tool_result blocks
|
||||
if (block.type === "tool_result" && block.tool_use_id && !TOOL_ID_PATTERN.test(block.tool_use_id)) {
|
||||
const sanitized = sanitizeToolId(block.tool_use_id);
|
||||
block.tool_use_id = sanitized || generateToolCallId();
|
||||
block.tool_use_id = sanitized || generateToolCallId(i, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,27 +496,21 @@ export function openaiResponsesToOpenAIResponse(chunk, state) {
|
||||
if (responseUsage && typeof responseUsage === "object") {
|
||||
const inputTokens = responseUsage.input_tokens || responseUsage.prompt_tokens || 0;
|
||||
const outputTokens = responseUsage.output_tokens || responseUsage.completion_tokens || 0;
|
||||
const cacheReadTokens = responseUsage.cache_read_input_tokens || 0;
|
||||
const cacheCreationTokens = responseUsage.cache_creation_input_tokens || 0;
|
||||
|
||||
// prompt_tokens = input_tokens + cache_read + cache_creation (all prompt-side tokens)
|
||||
const promptTokens = inputTokens + cacheReadTokens + cacheCreationTokens;
|
||||
// OpenAI Responses API: input_tokens already includes cached_tokens
|
||||
// Cache info is in input_tokens_details.cached_tokens
|
||||
const cacheReadTokens = responseUsage.input_tokens_details?.cached_tokens || responseUsage.cache_read_input_tokens || 0;
|
||||
|
||||
state.usage = {
|
||||
prompt_tokens: promptTokens,
|
||||
prompt_tokens: inputTokens,
|
||||
completion_tokens: outputTokens,
|
||||
total_tokens: promptTokens + outputTokens
|
||||
total_tokens: inputTokens + outputTokens
|
||||
};
|
||||
|
||||
// Add prompt_tokens_details if cache tokens exist
|
||||
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
||||
state.usage.prompt_tokens_details = {};
|
||||
if (cacheReadTokens > 0) {
|
||||
state.usage.prompt_tokens_details.cached_tokens = cacheReadTokens;
|
||||
}
|
||||
if (cacheCreationTokens > 0) {
|
||||
state.usage.prompt_tokens_details.cache_creation_tokens = cacheCreationTokens;
|
||||
}
|
||||
if (cacheReadTokens > 0) {
|
||||
state.usage.prompt_tokens_details = {
|
||||
cached_tokens: cacheReadTokens
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user