feat: enable per-provider SSE streaming via model_list stream field
Wire ModelConfig.Stream (*bool) through to openai_compat.WithStream so each model_list entry can opt in to SSE streaming independently. - Add NewHTTPProviderFromConfig that reads all ModelConfig fields including stream - Implement StreamingProvider interface (CanStream/ChatStream) on HTTPProvider by delegating to openai_compat.Provider - Switch factory_provider.go (openai, openai-compat, anthropic API-key paths) to use NewHTTPProviderFromConfig Usage: set "stream": true in a model_list entry to enable streaming. Default behavior (no stream field) is unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2548880ca7
commit
42f587c6bc
2 changed files with 36 additions and 21 deletions
|
|
@ -87,13 +87,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
|||
if apiBase == "" {
|
||||
apiBase = getDefaultAPIBase(protocol)
|
||||
}
|
||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||
cfg.APIKey,
|
||||
apiBase,
|
||||
cfg.Proxy,
|
||||
cfg.MaxTokensField,
|
||||
cfg.RequestTimeout,
|
||||
), modelID, nil
|
||||
return NewHTTPProviderFromConfig(cfg, apiBase), modelID, nil
|
||||
|
||||
case "azure", "azure-openai":
|
||||
// Azure OpenAI uses deployment-based URLs, api-key header auth,
|
||||
|
|
@ -126,13 +120,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
|||
if apiBase == "" {
|
||||
apiBase = getDefaultAPIBase(protocol)
|
||||
}
|
||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||
cfg.APIKey,
|
||||
apiBase,
|
||||
cfg.Proxy,
|
||||
cfg.MaxTokensField,
|
||||
cfg.RequestTimeout,
|
||||
), modelID, nil
|
||||
return NewHTTPProviderFromConfig(cfg, apiBase), modelID, nil
|
||||
|
||||
case "anthropic":
|
||||
if cfg.AuthMethod == "oauth" || cfg.AuthMethod == "token" {
|
||||
|
|
@ -151,13 +139,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
|||
if cfg.APIKey == "" {
|
||||
return nil, "", fmt.Errorf("api_key is required for anthropic protocol (model: %s)", cfg.Model)
|
||||
}
|
||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||
cfg.APIKey,
|
||||
apiBase,
|
||||
cfg.Proxy,
|
||||
cfg.MaxTokensField,
|
||||
cfg.RequestTimeout,
|
||||
), modelID, nil
|
||||
return NewHTTPProviderFromConfig(cfg, apiBase), modelID, nil
|
||||
|
||||
case "anthropic-messages":
|
||||
// Anthropic Messages API with native format (HTTP-based, no SDK)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/providers/openai_compat"
|
||||
"github.com/sipeed/picoclaw/pkg/providers/protocoltypes"
|
||||
)
|
||||
|
||||
type HTTPProvider struct {
|
||||
|
|
@ -42,6 +44,21 @@ func NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
|||
}
|
||||
}
|
||||
|
||||
// NewHTTPProviderFromConfig creates an HTTPProvider from a ModelConfig,
|
||||
// honoring all optional fields including stream.
|
||||
func NewHTTPProviderFromConfig(cfg *config.ModelConfig, apiBase string) *HTTPProvider {
|
||||
opts := []openai_compat.Option{
|
||||
openai_compat.WithMaxTokensField(cfg.MaxTokensField),
|
||||
openai_compat.WithRequestTimeout(time.Duration(cfg.RequestTimeout) * time.Second),
|
||||
}
|
||||
if cfg.Stream != nil && *cfg.Stream {
|
||||
opts = append(opts, openai_compat.WithStream(true))
|
||||
}
|
||||
return &HTTPProvider{
|
||||
delegate: openai_compat.NewProvider(cfg.APIKey, apiBase, cfg.Proxy, opts...),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) Chat(
|
||||
ctx context.Context,
|
||||
messages []Message,
|
||||
|
|
@ -52,6 +69,22 @@ func (p *HTTPProvider) Chat(
|
|||
return p.delegate.Chat(ctx, messages, tools, model, options)
|
||||
}
|
||||
|
||||
// CanStream returns true when SSE streaming is enabled.
|
||||
func (p *HTTPProvider) CanStream() bool {
|
||||
return p.delegate.CanStream()
|
||||
}
|
||||
|
||||
// ChatStream opens an SSE connection and returns a channel of StreamEvent.
|
||||
func (p *HTTPProvider) ChatStream(
|
||||
ctx context.Context,
|
||||
messages []Message,
|
||||
tools []ToolDefinition,
|
||||
model string,
|
||||
options map[string]any,
|
||||
) (<-chan protocoltypes.StreamEvent, error) {
|
||||
return p.delegate.ChatStream(ctx, messages, tools, model, options)
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) GetDefaultModel() string {
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue