From 60d138f47336ba3be4345bd284b4c92a13d66cd9 Mon Sep 17 00:00:00 2001 From: Stefan Gasser Date: Thu, 20 Nov 2025 09:35:21 +0100 Subject: [PATCH 1/2] fix: update chat message API to match current Claude.ai format The Claude.ai chat completion API has changed its request/response format. This fix adds the minimal required fields to make it work. Changes: - Add required field to completion API request: - rendering_mode: "messages" (critical - without this the API times out) - Ensure attachments and files arrays are present (even if empty) - Update CLI event handler to process new SSE format: - Handle content_block_delta events with text_delta type - Extract text from delta.text field (was event.completion before) - Maintain backward compatibility with old format Root cause: API was timing out because the rendering_mode field was missing. The API would accept connections but never send response events without it. Tested: Successfully creates chats and sends/receives messages with proper streaming responses from Claude. --- src/claudesync/cli/chat.py | 8 +++++++- src/claudesync/providers/base_claude_ai.py | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/claudesync/cli/chat.py b/src/claudesync/cli/chat.py index 5e6eba186..9eef71dc5 100644 --- a/src/claudesync/cli/chat.py +++ b/src/claudesync/cli/chat.py @@ -219,7 +219,13 @@ def message(config, message, chat, timezone, model): for event in provider.send_message( active_organization_id, chat, message, timezone, model ): - if "completion" in event: + # Handle new API format (content_block_delta with text_delta) + if event.get("type") == "content_block_delta": + delta = event.get("delta", {}) + if delta.get("type") == "text_delta": + click.echo(delta.get("text", ""), nl=False) + # Handle legacy format (for backward compatibility) + elif "completion" in event: click.echo(event["completion"], nl=False) elif "content" in event: click.echo(event["content"], nl=False) diff --git a/src/claudesync/providers/base_claude_ai.py b/src/claudesync/providers/base_claude_ai.py index b3a66ca0a..2786eb9a1 100644 --- a/src/claudesync/providers/base_claude_ai.py +++ b/src/claudesync/providers/base_claude_ai.py @@ -423,6 +423,7 @@ def send_message( data = { "prompt": prompt, "timezone": timezone, + "rendering_mode": "messages", "attachments": [], "files": [], } From 292b204a0c7b8d0aca3f9d6428adc63b5937b662 Mon Sep 17 00:00:00 2001 From: Stefan Gasser Date: Thu, 20 Nov 2025 12:26:37 +0100 Subject: [PATCH 2/2] refactor: reduce cyclomatic complexity in message function Extract event processing logic into process_message_event helper function to reduce complexity from 11 to 5, fixing flake8 C901 error. --- src/claudesync/cli/chat.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/claudesync/cli/chat.py b/src/claudesync/cli/chat.py index 9eef71dc5..91b8dedad 100644 --- a/src/claudesync/cli/chat.py +++ b/src/claudesync/cli/chat.py @@ -180,6 +180,24 @@ def init(config, name, project): click.echo(f"Failed to create chat conversation: {str(e)}") +def process_message_event(event): + """Process a single streaming event from the message response.""" + # Handle new API format (content_block_delta with text_delta) + if event.get("type") == "content_block_delta": + delta = event.get("delta", {}) + if delta.get("type") == "text_delta": + click.echo(delta.get("text", ""), nl=False) + # Handle legacy format (for backward compatibility) + elif "completion" in event: + click.echo(event["completion"], nl=False) + elif "content" in event: + click.echo(event["content"], nl=False) + elif "error" in event: + click.echo(f"\nError: {event['error']}") + elif "message_limit" in event: + click.echo(f"\nRemaining messages: {event['message_limit']['remaining']}") + + @chat.command() @click.argument("message", nargs=-1, required=True) @click.option("--chat", help="UUID of the chat to send the message to") @@ -219,22 +237,7 @@ def message(config, message, chat, timezone, model): for event in provider.send_message( active_organization_id, chat, message, timezone, model ): - # Handle new API format (content_block_delta with text_delta) - if event.get("type") == "content_block_delta": - delta = event.get("delta", {}) - if delta.get("type") == "text_delta": - click.echo(delta.get("text", ""), nl=False) - # Handle legacy format (for backward compatibility) - elif "completion" in event: - click.echo(event["completion"], nl=False) - elif "content" in event: - click.echo(event["content"], nl=False) - elif "error" in event: - click.echo(f"\nError: {event['error']}") - elif "message_limit" in event: - click.echo( - f"\nRemaining messages: {event['message_limit']['remaining']}" - ) + process_message_event(event) click.echo() # Print a newline at the end of the response