Improve logging, rate limiting, and error handling (#29)

* feat: apply local user changes and fixes

* ;D

* Clean up PR #28: Remove duplicate code lines and unnecessary file

- Remove pullrequest.md (PR notes file not needed in repo)
- Fix duplicate lines in account-manager.js:
  - rateLimitResetTime assignment
  - saveToDisk() calls in markRateLimited and markInvalid
  - invalidReason/invalidAt assignments
  - double return statement in discoverProject

Original PR by M2noa: fix sticky accs, 500s, logging updates, and rate limit handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: M2noa <226494568+M2noa@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>

* chore: replace console.log with logger methods for consistency

- Replace all console.log calls with logger.warn/debug in:
  - src/cloudcode-client.js (4 places)
  - src/format/thinking-utils.js (7 places)

This ensures consistent logging behavior with the new logger utility,
respecting --debug mode for verbose output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: M1noa <minoa@minoa.cat>
Co-authored-by: M2noa <226494568+M2noa@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Badri Narayanan S
2026-01-01 14:35:06 +05:30
committed by GitHub
parent d05fb64e29
commit 1d91bc0d30
11 changed files with 351 additions and 108 deletions

View File

@@ -5,6 +5,7 @@
import { MIN_SIGNATURE_LENGTH, GEMINI_SKIP_SIGNATURE } from '../constants.js';
import { getCachedSignature } from './signature-cache.js';
import { logger } from '../utils/logger.js';
/**
* Convert Anthropic role to Google role
@@ -101,7 +102,7 @@ export function convertContentToParts(content, isClaudeModel = false, isGeminiMo
if (!signature && block.id) {
signature = getCachedSignature(block.id);
if (signature) {
console.log('[ContentConverter] Restored signature from cache for:', block.id);
logger.debug(`[ContentConverter] Restored signature from cache for: ${block.id}`);
}
}

View File

@@ -18,6 +18,7 @@ import {
needsThinkingRecovery,
closeToolLoopForThinking
} from './thinking-utils.js';
import { logger } from '../utils/logger.js';
/**
* Convert Anthropic Messages API request to the format expected by Cloud Code
@@ -81,7 +82,7 @@ export function convertAnthropicToGoogle(anthropicRequest) {
// Claude models handle this differently and don't need this recovery
let processedMessages = messages;
if (isGeminiModel && isThinking && needsThinkingRecovery(messages)) {
console.log('[RequestConverter] Applying thinking recovery for Gemini');
logger.debug('[RequestConverter] Applying thinking recovery for Gemini');
processedMessages = closeToolLoopForThinking(messages);
}
@@ -105,7 +106,7 @@ export function convertAnthropicToGoogle(anthropicRequest) {
// SAFETY: Google API requires at least one part per content message
// This happens when all thinking blocks are filtered out (unsigned)
if (parts.length === 0) {
console.log('[RequestConverter] WARNING: Empty parts array after filtering, adding placeholder');
logger.warn('[RequestConverter] WARNING: Empty parts array after filtering, adding placeholder');
parts.push({ text: '' });
}
@@ -150,9 +151,9 @@ export function convertAnthropicToGoogle(anthropicRequest) {
const thinkingBudget = thinking?.budget_tokens;
if (thinkingBudget) {
thinkingConfig.thinking_budget = thinkingBudget;
console.log('[RequestConverter] Claude thinking enabled with budget:', thinkingBudget);
logger.debug(`[RequestConverter] Claude thinking enabled with budget: ${thinkingBudget}`);
} else {
console.log('[RequestConverter] Claude thinking enabled (no budget specified)');
logger.debug('[RequestConverter] Claude thinking enabled (no budget specified)');
}
googleRequest.generationConfig.thinkingConfig = thinkingConfig;
@@ -162,7 +163,8 @@ export function convertAnthropicToGoogle(anthropicRequest) {
includeThoughts: true,
thinkingBudget: thinking?.budget_tokens || 16000
};
console.log('[RequestConverter] Gemini thinking enabled with budget:', thinkingConfig.thinkingBudget);
logger.debug(`[RequestConverter] Gemini thinking enabled with budget: ${thinkingConfig.thinkingBudget}`);
googleRequest.generationConfig.thinkingConfig = thinkingConfig;
}
@@ -201,12 +203,12 @@ export function convertAnthropicToGoogle(anthropicRequest) {
});
googleRequest.tools = [{ functionDeclarations }];
console.log('[RequestConverter] Tools:', JSON.stringify(googleRequest.tools).substring(0, 300));
logger.debug(`[RequestConverter] Tools: ${JSON.stringify(googleRequest.tools).substring(0, 300)}`);
}
// Cap max tokens for Gemini models
if (isGeminiModel && googleRequest.generationConfig.maxOutputTokens > GEMINI_MAX_OUTPUT_TOKENS) {
console.log(`[RequestConverter] Capping Gemini max_tokens from ${googleRequest.generationConfig.maxOutputTokens} to ${GEMINI_MAX_OUTPUT_TOKENS}`);
logger.debug(`[RequestConverter] Capping Gemini max_tokens from ${googleRequest.generationConfig.maxOutputTokens} to ${GEMINI_MAX_OUTPUT_TOKENS}`);
googleRequest.generationConfig.maxOutputTokens = GEMINI_MAX_OUTPUT_TOKENS;
}

View File

@@ -4,6 +4,7 @@
*/
import { MIN_SIGNATURE_LENGTH } from '../constants.js';
import { logger } from '../utils/logger.js';
/**
* Check if a part is a thinking block
@@ -95,7 +96,7 @@ function filterContentArray(contentArray) {
}
// Drop unsigned thinking blocks
console.log('[ThinkingUtils] Dropping unsigned thinking block');
logger.debug('[ThinkingUtils] Dropping unsigned thinking block');
}
return filtered;
@@ -152,7 +153,7 @@ export function removeTrailingThinkingBlocks(content) {
}
if (endIndex < content.length) {
console.log('[ThinkingUtils] Removed', content.length - endIndex, 'trailing unsigned thinking blocks');
logger.debug('[ThinkingUtils] Removed', content.length - endIndex, 'trailing unsigned thinking blocks');
return content.slice(0, endIndex);
}
@@ -187,7 +188,7 @@ export function restoreThinkingSignatures(content) {
}
if (filtered.length < originalLength) {
console.log(`[ThinkingUtils] Dropped ${originalLength - filtered.length} unsigned thinking block(s)`);
logger.debug(`[ThinkingUtils] Dropped ${originalLength - filtered.length} unsigned thinking block(s)`);
}
return filtered;
@@ -241,7 +242,7 @@ export function reorderAssistantContent(content) {
}
if (droppedEmptyBlocks > 0) {
console.log(`[ThinkingUtils] Dropped ${droppedEmptyBlocks} empty text block(s)`);
logger.debug(`[ThinkingUtils] Dropped ${droppedEmptyBlocks} empty text block(s)`);
}
const reordered = [...thinkingBlocks, ...textBlocks, ...toolUseBlocks];
@@ -251,7 +252,7 @@ export function reorderAssistantContent(content) {
const originalOrder = content.map(b => b?.type || 'unknown').join(',');
const newOrder = reordered.map(b => b?.type || 'unknown').join(',');
if (originalOrder !== newOrder) {
console.log('[ThinkingUtils] Reordered assistant content');
logger.debug('[ThinkingUtils] Reordered assistant content');
}
}
@@ -455,7 +456,7 @@ export function closeToolLoopForThinking(messages) {
content: [{ type: 'text', text: '[Tool call was interrupted.]' }]
});
console.log('[ThinkingUtils] Applied thinking recovery for interrupted tool');
logger.debug('[ThinkingUtils] Applied thinking recovery for interrupted tool');
} else {
// For tool loops: add synthetic messages to close the loop
const syntheticText = state.toolResultCount === 1
@@ -474,7 +475,7 @@ export function closeToolLoopForThinking(messages) {
content: [{ type: 'text', text: '[Continue]' }]
});
console.log('[ThinkingUtils] Applied thinking recovery for tool loop');
logger.debug('[ThinkingUtils] Applied thinking recovery for tool loop');
}
return modified;