63 lines
2.1 KiB
Go
63 lines
2.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/nyoungo/dsfree2api/internal/openai"
|
|
"github.com/nyoungo/dsfree2api/internal/upstream"
|
|
)
|
|
|
|
// continuationFor builds the prompt function that asks the model to resume a
|
|
// tool-call reply the site's per-reply output cap cut off. It returns nil
|
|
// when no tools were offered, which disables continuation entirely.
|
|
func continuationFor(tools []openai.ToolDef, messages []openai.ChatMessage, rounds int) openai.ContinuationFunc {
|
|
if len(tools) == 0 || len(messages) == 0 {
|
|
return nil
|
|
}
|
|
base := append([]openai.ChatMessage{}, messages...)
|
|
return func(partial string, round int) string {
|
|
history := append(append([]openai.ChatMessage{}, base...),
|
|
openai.ChatMessage{Role: "assistant", Content: openai.MessageContent{Text: openai.ContinuationContext(partial, 400, 2000)}},
|
|
openai.ChatMessage{Role: "user", Content: openai.MessageContent{Text: openai.ContinueInstruction(partial, round, rounds)}},
|
|
)
|
|
return openai.BuildPrompt(history, openai.PromptOptions{})
|
|
}
|
|
}
|
|
|
|
// continueRounds reads the configured number of continuation turns.
|
|
func (s *Server) continueRounds() int {
|
|
s.cfg.RLock()
|
|
defer s.cfg.RUnlock()
|
|
return s.cfg.Upstream.ContinueRounds
|
|
}
|
|
|
|
// chatWithContinue runs one upstream conversation and transparently stitches
|
|
// truncated tool-call JSON replies across extra continuation turns. emit
|
|
// receives the reply text in order; firstDelta is stamped on the first delta
|
|
// of any turn.
|
|
func (s *Server) chatWithContinue(
|
|
ctx context.Context,
|
|
modelID, prompt string,
|
|
cont openai.ContinuationFunc,
|
|
info *upstream.ServeInfo,
|
|
onFirstDelta func(),
|
|
emit func(text string) error,
|
|
) error {
|
|
return openai.RunContinued(ctx, prompt, cont, s.continueRounds(),
|
|
func(ctx context.Context, p string, emitText func(string) error) error {
|
|
return s.up.Chat(ctx, modelID, p, info, func(ev upstream.Event) error {
|
|
if ev.Kind == upstream.KindDelta && ev.Value != "" {
|
|
if onFirstDelta != nil {
|
|
onFirstDelta()
|
|
}
|
|
return emitText(ev.Value)
|
|
}
|
|
return nil
|
|
})
|
|
},
|
|
emit,
|
|
func(msg string, args ...any) { s.log.Info(msg, args...) },
|
|
func(msg string, args ...any) { s.log.Warn(msg, args...) },
|
|
)
|
|
}
|