Command: head -100 /Users/psulin/organon/scripts/llm_capture/reconstruct-model-input.py 2>/dev/null || echo "File may not exist or reading failed"
Output: #!/usr/bin/env python3
"""
Reconstruct the EXACT string the model sees from a captured API request.

The model internally processes:
- System message text
- All messages in conversation history, in order
- Each message formatted as role + content

This reconstructs that exact string.
"""

import json
import sys
from pathlib import Path


def reconstruct_full_context(request_file):
    """Reconstruct the complete context string the model sees."""

    with open(request_file) as f:
        data = json.load(f)

    parts = []

    # 1. SYSTEM MESSAGE
    parts.append("=" * 100)
    parts.append("SYSTEM MESSAGE")
    parts.append("=" * 100)

    system = data.get('system', [])
    if isinstance(system, str):
        parts.append(system)
    elif isinstance(system, list):
        for block in system:
            if isinstance(block, dict) and block.get('type') == 'text':
                parts.append(block['text'])

    # 2. TOOLS AVAILABLE
    tools = data.get('tools', [])
    if tools:
        parts.append("\n" + "=" * 100)
        parts.append(f"TOOLS AVAILABLE ({len(tools)})")
        parts.append("=" * 100)

        for i, tool in enumerate(tools, 1):
            parts.append(f"\n--- Tool {i}: {tool.get('name', 'unknown')} ---")

            # Description
            desc = tool.get('description', '')
            if desc:
                parts.append(f"\nDescription:\n{desc}")

            # Input schema
            schema = tool.get('input_schema', {})
            if schema:
                parts.append(f"\nInput Schema:")
                parts.append(json.dumps(schema, indent=2))

    # 3. CONVERSATION HISTORY (all messages)
    messages = data.get('messages', [])

    for i, msg in enumerate(messages, 1):
        role = msg.get('role', 'unknown').upper()
        parts.append("\n" + "=" * 100)
        parts.append(f"MESSAGE {i}: {role}")
        parts.append("=" * 100)

        content = msg.get('content', [])

        # Handle string or array content
        if isinstance(content, str):
            parts.append(content)
        elif isinstance(content, list):
            for block in content:
                if isinstance(block, dict):
                    block_type = block.get('type', 'unknown')

                    if block_type == 'text':
                        parts.append(block.get('text', ''))
                    elif block_type == 'tool_use':
                        tool_name = block.get('name', 'unknown')
                        tool_input = json.dumps(block.get('input', {}), indent=2)
                        parts.append(f"\n[TOOL_USE: {tool_name}]")
                        parts.append(f"Input: {tool_input}")
                    elif block_type == 'tool_result':
                        tool_id = block.get('tool_use_id', 'unknown')
                        is_error = block.get('is_error', False)
                        result = block.get('content', '')
                        parts.append(f"\n[TOOL_RESULT id={tool_id} error={is_error}]")
                        parts.append(str(result))
                    elif block_type == 'thinking':
                        parts.append(f"\n[THINKING]")
                        parts.append(block.get('thinking', ''))
                    else:
                        parts.append(f"\n[{block_type.upper()}]")
                        parts.append(json.dumps(block, indent=2))
                else:
                    parts.append(str(block))

