Skip to content

Commit bffad54

Browse files
intel352claude
andcommitted
feat: PTY providers use native JSON streaming, not fragile PTY prompt detection
Stream() now uses each CLI's built-in JSON streaming output instead of trying to detect prompts in rich TUI output: - Claude Code: --output-format stream-json --verbose (structured events) - Gemini CLI: --output-format stream-json - Others: fallback to non-interactive exec + single event emission Removed the isPTYProvider hack that forced Chat() in the chat handler. Stream() is now the universal path for all provider types. Verified both Claude Code and Ollama work through Stream(): - Claude Code: stream-json parsing extracts assistant text events - Ollama: standard Genkit streaming (unchanged) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 738cf99 commit bffad54

3 files changed

Lines changed: 3 additions & 35 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
charm.land/bubbletea/v2 v2.0.1
88
charm.land/lipgloss/v2 v2.0.0
99
github.com/GoCodeAlone/workflow v0.3.56
10-
github.com/GoCodeAlone/workflow-plugin-agent v0.6.6
10+
github.com/GoCodeAlone/workflow-plugin-agent v0.6.7
1111
github.com/charmbracelet/glamour v0.10.0
1212
github.com/creack/pty v1.1.24
1313
github.com/google/generative-ai-go v0.20.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ github.com/GoCodeAlone/modular/modules/scheduler v1.14.0 h1:JSrzo4FB7uGASExv+fCL
6868
github.com/GoCodeAlone/modular/modules/scheduler v1.14.0/go.mod h1:emkR2AnilabLJZv1rOTDO9eGpRBmZs487H00Lnp9jIc=
6969
github.com/GoCodeAlone/workflow v0.3.56 h1:jsJmVwCRLz7XOTLQNoyE7POBDW3SmqbG/18VnAzbaEc=
7070
github.com/GoCodeAlone/workflow v0.3.56/go.mod h1:uATRqpqPubm+g2jJtYoaMTMmjlUaXnLsSdZk5of+jW0=
71-
github.com/GoCodeAlone/workflow-plugin-agent v0.6.6 h1:8tFF6MvA19uE6mD5fJJI2laFzlKjeoBj5Ssucr2g8nw=
72-
github.com/GoCodeAlone/workflow-plugin-agent v0.6.6/go.mod h1:gmyX2n87+ebLEmPj3AbFvDRmVHp/RDw1/Db8FvwKGDk=
71+
github.com/GoCodeAlone/workflow-plugin-agent v0.6.7 h1:As09kXnJIBSqrfegOfYlOoYldnZPrqV7kWVSqEUnb1g=
72+
github.com/GoCodeAlone/workflow-plugin-agent v0.6.7/go.mod h1:gmyX2n87+ebLEmPj3AbFvDRmVHp/RDw1/Db8FvwKGDk=
7373
github.com/GoCodeAlone/workflow-plugin-authz v0.2.2 h1:xnaNLQybNv4u/TeC1+pJuwUHbLPZaCOtcWcUn4HVeq4=
7474
github.com/GoCodeAlone/workflow-plugin-authz v0.2.2/go.mod h1:jyeRNdNl8qCXwTc1lGYPazz97ZjCVrE2OGgqGheBJV0=
7575
github.com/GoCodeAlone/yaegi v0.17.1 h1:aPAwU29L9cGceRAff02c5pjQcT5KapDB4fWFZK9tElE=

internal/daemon/chat.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -176,38 +176,6 @@ func (s *Service) handleChat(ctx context.Context, sessionID, userMessage string,
176176
debugLog("[chat] session=%s sending %d messages: %s", sessionID, len(messages), string(msgJSON))
177177
}
178178

179-
// PTY CLI providers (claude_code, copilot_cli, etc.) don't support streaming
180-
// well — their interactive PTY mode requires complex prompt detection.
181-
// Use Chat() (non-interactive) for these and fake-stream the response.
182-
isPTYProvider := strings.HasSuffix(prov.Name(), "_code") || strings.HasSuffix(prov.Name(), "_cli")
183-
if isPTYProvider {
184-
resp, chatErr := prov.Chat(ctx, messages, nil)
185-
if chatErr != nil {
186-
if isAuthError(chatErr) {
187-
return sendAuthError(stream, session.Provider, chatErr.Error())
188-
}
189-
return sendError(stream, "provider chat: "+chatErr.Error())
190-
}
191-
// Save user message after successful provider call.
192-
if err := s.saveMessage(ctx, sessionID, "user", userMessage, "", ""); err != nil {
193-
log.Printf("save user message: %v", err)
194-
}
195-
// Emit the full response as a single token event.
196-
if resp != nil && resp.Content != "" {
197-
if err := stream.Send(&pb.ChatEvent{
198-
Event: &pb.ChatEvent_Token{Token: &pb.TokenDelta{Content: resp.Content}},
199-
}); err != nil {
200-
return err
201-
}
202-
if err := s.saveMessage(ctx, sessionID, "assistant", resp.Content, "", ""); err != nil {
203-
log.Printf("save assistant message: %v", err)
204-
}
205-
}
206-
return stream.Send(&pb.ChatEvent{
207-
Event: &pb.ChatEvent_Complete{Complete: &pb.SessionComplete{Summary: "done"}},
208-
})
209-
}
210-
211179
// Stream from provider (save user message AFTER successful stream start,
212180
// so failed requests don't pollute conversation history).
213181
eventCh, err := prov.Stream(ctx, messages, nil) // tools will be added in later task

0 commit comments

Comments
 (0)