Files
egutierrez 4881eeb7de feat(registry): claude_stream + mcp_server_stdio para chat con tool-use
- claude_stream_go_core: lanza claude -p --output-format stream-json
  --verbose, decodifica NDJSON y emite eventos sinteticos (text_delta,
  tool_use, tool_result, result, error) por canal Go. 10 tests con fake
  claude bash.
- mcp_server_stdio_go_infra: scaffold de MCP server JSON-RPC 2.0 sobre
  stdio (initialize, tools/list, tools/call, ping). Usuario registra
  tool defs y handler unico. 9 tests.

Usadas por apps/kanban backend para reemplazar el chat HTTP one-shot
con XML actions por WebSocket streaming + tool-use nativa.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:54:56 +02:00

4.3 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, params, output
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path params output
claude_stream function go core 1.0.0 impure func StreamClaude(ctx context.Context, opts ClaudeStreamOpts) (<-chan ClaudeEvent, error) Lanza `claude -p --output-format stream-json --verbose` como subprocess y retorna un canal de eventos decodificados (text_delta, tool_use, tool_result, result, error). Expande automaticamente los bloques de contenido de los mensajes assistant/user en eventos sinteticos de grano fino.
claude
streaming
subprocess
agent
ndjson
tool-use
false error_go_core
bufio
context
encoding/json
fmt
io
os
os/exec
strings
true
system event
text delta
multiple text blocks
tool use
tool result string content
tool result array content
result event
non-zero exit
non-json line
ctx cancel
functions/core/claude_stream_test.go functions/core/claude_stream.go
name desc
ctx Contexto de cancelacion. Al cancelar, el subprocess recibe SIGTERM/SIGKILL y el canal se cierra.
name desc
opts Opciones de lanzamiento: Bin (path al binario claude, default 'claude'), Args (args extra sin -p ni --output-format ni --verbose), Stdin (prompt como io.Reader), Workdir (CWD del subprocess), Env (env extra mergeado con os.Environ()), Stderr (destino del stderr del subprocess).
Canal de ClaudeEvent cerrado cuando el subprocess termina. Cada evento tiene Type discriminador y campos especificos segun el tipo. Raw contiene siempre la linea NDJSON original. Retorna error solo si el spawn falla.

Tipos exportados

ClaudeEventType — constantes de tipo de evento:

  • system — evento de inicializacion con session_id y model
  • assistant — mensaje raw del asistente (tambien genera text_delta y/o tool_use sinteticos)
  • user — mensaje raw de usuario/tool_result (tambien genera tool_result sintetico)
  • result — evento final con stop_reason, is_error, result
  • text_delta — (sintetico) porcion de texto del asistente
  • tool_use — (sintetico) llamada a herramienta con tool_use_id, tool_name, tool_input
  • tool_result — (sintetico) resultado de herramienta con tool_result_id, content, is_error
  • error — (sintetico) linea no-JSON o exit code != 0

ClaudeStreamOpts — configura el subprocess:

  • Bin string — path al binario. Si vacio, usa exec.LookPath("claude").
  • Args []string — args extra. Se anteponen automaticamente -p --output-format stream-json --verbose.
  • Stdin io.Reader — prompt user. Puede ser strings.NewReader("prompt") o nil.
  • Workdir string — CWD del subprocess.
  • Env map[string]string — variables extra mergeadas con os.Environ().
  • Stderr io.Writer — destino del stderr en vivo (ej. os.Stderr para debug). Si nil, se descarta.

Ejemplo

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

ch, err := core.StreamClaude(ctx, core.ClaudeStreamOpts{
    Args:  []string{"responde en una frase: que es Go"},
    Stderr: os.Stderr,
})
if err != nil {
    log.Fatal(err)
}
for ev := range ch {
    switch ev.Type {
    case core.ClaudeEventTextDelta:
        fmt.Print(ev.Text)
    case core.ClaudeEventToolUse:
        fmt.Printf("\n[tool] %s(%s)\n", ev.ToolName, ev.ToolInput)
    case core.ClaudeEventToolResult:
        fmt.Printf("[result] %s\n", ev.ToolResultContent)
    case core.ClaudeEventResult:
        fmt.Printf("\n[done] stop_reason=%s\n", ev.StopReason)
    case core.ClaudeEventError:
        fmt.Fprintf(os.Stderr, "[error] %s\n", ev.Error)
    }
}

Notas

  • El caller DEBE consumir el canal hasta que se cierre, o cancelar el ctx. No consumir bloquea la goroutine interna.
  • El canal tiene buffer de 64 para absorber ráfagas sin bloquear la lectura de stdout.
  • Los eventos assistant y user raw se emiten ademas de los sinteticos, para casos no contemplados.
  • tool_result.content puede ser string o array [{type:text,text:"..."}] — la funcion concatena los bloques text en ambos casos.
  • Los tests usan un fake claude bash; se skipean si bash no esta disponible en el PATH.
  • Equivalente Go de projects/osint_graph/apps/graph_explorer/chat.cpp (C++).