iop/apps/edge/internal/openai/run_result.go
toki 6b684ee5cf refactor: edge service split and OpenAI surface separation
- Split edge service into dedicated modules (control_command, node_command, run_dispatch, status_provider)
- Separate OpenAI handlers (chat_handler, ollama_passthrough, routes, stream, strict_output, types)
- Archive completed milestone documents (02_edge_service_split, 03+02_openai_surface_split)
- Update architecture refactor foundation milestone
2026-06-06 12:18:33 +09:00

58 lines
1.5 KiB
Go

package openai
import (
"context"
"fmt"
"strings"
"time"
edgeservice "iop/apps/edge/internal/service"
)
func collectRunResult(ctx context.Context, handle *edgeservice.RunHandle) (string, string, *openAIUsage, error) {
var contentBuilder strings.Builder
var reasoningBuilder strings.Builder
var usage *openAIUsage
timer := time.NewTimer(handle.WaitTimeout())
defer timer.Stop()
for {
select {
case <-ctx.Done():
return "", "", nil, ctx.Err()
case <-timer.C:
return "", "", nil, fmt.Errorf("run timed out")
case nodeEvent := <-handle.NodeEvents:
if edgeservice.IsNodeDisconnected(nodeEvent) {
return "", "", nil, fmt.Errorf("node disconnected")
}
case event := <-handle.Events:
if event == nil {
continue
}
switch event.GetType() {
case "delta":
contentBuilder.WriteString(event.GetDelta())
case "reasoning_delta":
reasoningBuilder.WriteString(event.GetDelta())
case "complete":
if u := event.GetUsage(); u != nil {
usage = &openAIUsage{
PromptTokens: int(u.GetInputTokens()),
CompletionTokens: int(u.GetOutputTokens()),
TotalTokens: int(u.GetInputTokens() + u.GetOutputTokens()),
}
}
return contentBuilder.String(), reasoningBuilder.String(), usage, nil
case "error", "cancelled":
msg := event.GetError()
if msg == "" {
msg = event.GetMessage()
}
if msg == "" {
msg = "run failed"
}
return "", "", nil, fmt.Errorf("%s", msg)
}
}
}
}