Skip to content

SwisperStudio SDK Upgrade to v0.5.1

For Swisper Team
Date: 2025-11-26
Priority: ๐Ÿ”ด CRITICAL (Production Fix)


๐Ÿšจ Problem Summary

SDK v0.5.0 can hang Swisper indefinitely when: - Redis is misconfigured - Redis is unreachable - SwisperStudio is not running

This happened in production because initialize_redis_publisher() has no timeout and blocks forever on connection attempts.


โœ… Solution

SDK v0.5.1 introduces completely safe initialization that: - NEVER blocks indefinitely (all operations have timeouts) - NEVER raises exceptions - NEVER crashes Swisper - Gracefully disables tracing if Redis unavailable


๐Ÿ“‹ Required Changes in Swisper

Step 1: Update SDK Version

File: backend/pyproject.toml (or requirements.txt)

- swisper-studio-sdk = "0.5.0"
+ swisper-studio-sdk = "0.5.1"

Step 2: Update Initialization Code

File: apps/backend/app/main.py

Find this code (around line 118-151):

# Initialize SwisperStudio observability (SDK v0.5.0)
# SDK installed from GitHub Releases as proper pip package
if settings.SWISPER_STUDIO_ENABLED:
    try:
        from swisper_studio_sdk import initialize_redis_publisher, wrap_llm_adapter

        # Initialize Redis Streams publisher for observability
        await initialize_redis_publisher(
            redis_url=settings.SWISPER_STUDIO_REDIS_URL,
            stream_name=settings.SWISPER_STUDIO_STREAM_NAME,
            project_id=settings.SWISPER_STUDIO_PROJECT_ID,
            verify_consumer=True,  # Check if SwisperStudio consumer is running
        )
        logger.info("โœ… SwisperStudio observability initialized (Redis Streams)")
        logger.info(f"   Redis: {settings.SWISPER_STUDIO_REDIS_URL}")
        logger.info(f"   Stream: {settings.SWISPER_STUDIO_STREAM_NAME}")
        logger.info(f"   Project ID: {settings.SWISPER_STUDIO_PROJECT_ID}")

        # Enable LLM prompt capture (includes streaming support)
        try:
            wrap_llm_adapter()
            logger.info("โœ… LLM prompt capture enabled (structured + streaming)")
        except Exception as e:
            logger.warning(f"โš ๏ธ LLM prompt capture disabled: {e}")
            logger.warning("   State capture will still work")

    except ImportError:
        logger.warning("โš ๏ธ SwisperStudio SDK not installed - observability disabled")
        logger.warning("   Install with: pip install swisper-studio-sdk==0.5.0")
    except Exception as e:
        logger.warning(f"โš ๏ธ SwisperStudio observability initialization failed: {e}")
        logger.warning(
            "   Continuing without observability - events will queue in Redis"
        )

Replace with:

# Initialize SwisperStudio observability (SDK v0.5.1)
# SDK v0.5.1: ROBUST - safe_initialize() NEVER blocks or crashes Swisper
if settings.SWISPER_STUDIO_ENABLED:
    try:
        from swisper_studio_sdk import safe_initialize, wrap_llm_adapter

        # safe_initialize() is completely safe:
        # - NEVER raises exceptions
        # - NEVER blocks indefinitely (has timeouts)
        # - Returns status dict instead of raising
        # - If Redis unavailable, tracing is silently disabled
        status = await safe_initialize(
            redis_url=settings.SWISPER_STUDIO_REDIS_URL,
            project_id=settings.SWISPER_STUDIO_PROJECT_ID,
            stream_name=settings.SWISPER_STUDIO_STREAM_NAME,
            verify_consumer=True,
            connection_timeout=5.0,  # Max 5 seconds to connect
        )

        if status.get("initialized"):
            logger.info("โœ… SwisperStudio observability initialized (Redis Streams)")
            logger.info(f"   Redis: {settings.SWISPER_STUDIO_REDIS_URL}")
            logger.info(f"   Project ID: {settings.SWISPER_STUDIO_PROJECT_ID}")

            # Enable LLM prompt capture (includes streaming support)
            try:
                wrap_llm_adapter()
                logger.info("โœ… LLM prompt capture enabled (structured + streaming)")
            except Exception as e:
                logger.debug(f"LLM prompt capture skipped: {e}")
        else:
            logger.warning("โš ๏ธ SwisperStudio tracing disabled (Swisper continues normally)")
            if not status.get("redis"):
                logger.warning("   Reason: Redis connection failed or timed out")
            elif not status.get("write"):
                logger.warning("   Reason: Redis write permission denied")

    except ImportError:
        logger.warning("โš ๏ธ SwisperStudio SDK not installed - observability disabled")
        logger.warning("   Install with: pip install swisper-studio-sdk==0.5.1")
    except Exception as e:
        # This should NEVER happen with safe_initialize, but just in case
        logger.warning(f"โš ๏ธ SwisperStudio unexpected error: {e}")
        logger.warning("   Continuing without observability")

๐Ÿ”‘ Key API Changes

v0.5.0 (OLD) v0.5.1 (NEW) Behavior
initialize_redis_publisher() safe_initialize() Never blocks, never raises
Raises on error Returns {"initialized": False} Safe for production
No timeout 5s connection timeout Configurable

New Function: safe_initialize()

status = await safe_initialize(
    redis_url: str,              # Required: Redis URL
    project_id: str,             # Required: Project ID
    stream_name: str = "...",    # Optional: Stream name
    verify_consumer: bool = True, # Optional: Check consumer
    connection_timeout: float = 5.0,  # Optional: Max connect time
)

# Returns dict (NEVER raises):
{
    "enabled": True,       # Was initialization attempted
    "redis": True/False,   # Redis connectivity OK
    "write": True/False,   # Write permission OK
    "consumer": True/False, # Consumer detected
    "initialized": True/False,  # Overall success
}

๐Ÿงช Testing the Fix

You can test that the new SDK handles misconfiguration gracefully:

# Test with WRONG Redis URL (simulates misconfiguration)
python -c "
import asyncio
from swisper_studio_sdk import safe_initialize

async def test():
    status = await safe_initialize(
        redis_url='redis://nonexistent:6379',  # Wrong URL
        project_id='test',
        connection_timeout=3.0
    )
    print(f'Status: {status}')
    print(f'Initialized: {status[\"initialized\"]}')  # Should be False
    print('โœ… Swisper would continue normally!')

asyncio.run(test())
"

Expected output:

โš ๏ธ Redis connection timed out after 3.0s
   Tracing will be DISABLED (Swisper continues normally)
Status: {'enabled': True, 'redis': False, 'write': False, 'consumer': False, 'initialized': False}
Initialized: False
โœ… Swisper would continue normally!


๐Ÿ“ฆ Deployment Steps

  1. Wait for SDK v0.5.1 to be published (SwisperStudio team will tag and publish)
  2. Update Swisper's SDK version in pyproject.toml
  3. Update initialization code in main.py as shown above
  4. Test locally with the test script above
  5. Deploy to production

๐Ÿ›ก๏ธ What's Fixed in SDK v0.5.1

Issue Fix
ping() hangs forever on unreachable Redis All operations have timeouts (default 3s)
Exceptions crash Swisper safe_initialize() never raises
No way to recover from failed init Tracing silently disabled, Swisper continues
Mid-operation disconnects cause hangs Health checks before every Redis operation

๐Ÿ“ž Questions?

Contact SwisperStudio team or check: - SDK CHANGELOG: swisper_studio/sdk/CHANGELOG.md - SDK source: swisper_studio/sdk/swisper_studio_sdk/


Document Owner: SwisperStudio Team
Created: 2025-11-26