SSE en formato Claude Code CLI via ?format=claude

Nuevo ClaudeFormatEmitter traduce eventos nativos al formato exacto
que produce Claude Code CLI: content_block_start/delta/stop, tool_result,
assistant snapshots, result con usage/cost, done.

- streaming/claude_format.py: ClaudeFormatEmitter + DualEmitter
- base.py: enriquecer eventos con tool_call_id, raw_output, tool_arguments
- engine.py: usage/cost en EXECUTION_COMPLETED
- routes.py: ?format=claude en /sessions/{id}/stream
- main.py: DualEmitter wiring (emite a ambos formatos)

El frontend puede consumir el stream sin cambios — mismos event types
que Claude Code CLI. El formato nativo sigue disponible para el dashboard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jordan Diaz
2026-04-03 18:48:07 +00:00
parent 6978764540
commit df7dfbc280
5 changed files with 382 additions and 24 deletions

View File

@@ -27,6 +27,7 @@ from .mcp.registry import MCPRegistry
from .memory.store import MemoryStore
from .orchestrator.engine import OrchestratorEngine
from .storage.redis import RedisStorage
from .streaming.claude_format import ClaudeFormatEmitter, DualEmitter
from .streaming.sse import SSEEmitter
logging.basicConfig(
@@ -38,6 +39,8 @@ logger = logging.getLogger(__name__)
# Global instances (initialized in lifespan)
redis_storage = RedisStorage()
sse_emitter = SSEEmitter(redis_storage=redis_storage)
claude_emitter = ClaudeFormatEmitter()
dual_emitter = DualEmitter(sse_emitter, claude_emitter)
mcp_registry = MCPRegistry()
@@ -48,7 +51,6 @@ async def lifespan(app: FastAPI):
# 1. Connect Redis
await redis_storage.connect()
sse_emitter.set_storage(redis_storage)
# 2. Initialize model adapter
if settings.default_model_provider == "openai":
@@ -82,12 +84,14 @@ async def lifespan(app: FastAPI):
mcp_registry.load_config()
# 6. Wire dependencies (orchestrator is created per-message with session's MCP)
dual_emitter.set_storage(redis_storage)
set_dependencies(
storage=redis_storage,
model_adapter=model_adapter,
context_engine=context_engine,
memory_store=memory_store,
sse_emitter=sse_emitter,
sse_emitter=dual_emitter,
claude_emitter=claude_emitter,
mcp_registry=mcp_registry,
)