mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-08 02:47:29 +08:00
Slim subagent runtime surface and remove legacy interfaces
This commit is contained in:
@@ -234,7 +234,7 @@ func TestAIStudioChannelIDPrefersHealthyAvailableRelay(t *testing.T) {
|
||||
}
|
||||
providerRuntimeRegistry.mu.Unlock()
|
||||
|
||||
got := aistudioChannelID("aistudio", nil)
|
||||
got := aistudioChannelCandidates("aistudio", nil)[0]
|
||||
if got != "aistudio-good" {
|
||||
t.Fatalf("expected aistudio-good, got %q", got)
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func TestAIStudioChannelIDExplicitOptionWins(t *testing.T) {
|
||||
}
|
||||
providerRuntimeRegistry.mu.Unlock()
|
||||
|
||||
got := aistudioChannelID("aistudio", map[string]interface{}{"aistudio_channel": "manual"})
|
||||
got := aistudioChannelCandidates("aistudio", map[string]interface{}{"aistudio_channel": "manual"})[0]
|
||||
if got != "manual" {
|
||||
t.Fatalf("expected explicit channel manual, got %q", got)
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func TestAIStudioChannelIDPrefersMostRecentSuccessfulRelay(t *testing.T) {
|
||||
aistudioRelayRegistry.succeeded["aistudio-b"] = time.Now()
|
||||
aistudioRelayRegistry.mu.Unlock()
|
||||
|
||||
got := aistudioChannelID("aistudio", nil)
|
||||
got := aistudioChannelCandidates("aistudio", nil)[0]
|
||||
if got != "aistudio-b" {
|
||||
t.Fatalf("expected most recent successful relay aistudio-b, got %q", got)
|
||||
}
|
||||
|
||||
@@ -35,14 +35,6 @@ func getAIStudioRelayManager() *wsrelay.Manager {
|
||||
return aistudioRelayRegistry.manager
|
||||
}
|
||||
|
||||
func aistudioChannelID(providerName string, options map[string]interface{}) string {
|
||||
channels := aistudioChannelCandidates(providerName, options)
|
||||
if len(channels) > 0 {
|
||||
return channels[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func aistudioChannelCandidates(providerName string, options map[string]interface{}) []string {
|
||||
for _, key := range []string{"aistudio_channel", "aistudio_provider", "relay_provider", "channel_id", "provider_id"} {
|
||||
if value, ok := stringOption(options, key); ok && strings.TrimSpace(value) != "" {
|
||||
|
||||
@@ -311,10 +311,6 @@ func (p *HTTPProvider) callResponses(ctx context.Context, messages []Message, to
|
||||
return p.postJSON(ctx, endpointFor(p.apiBase, "/responses"), requestBody)
|
||||
}
|
||||
|
||||
func toResponsesInputItems(msg Message) []map[string]interface{} {
|
||||
return toResponsesInputItemsWithState(msg, nil)
|
||||
}
|
||||
|
||||
func toResponsesInputItemsWithState(msg Message, pendingCalls map[string]struct{}) []map[string]interface{} {
|
||||
role := strings.ToLower(strings.TrimSpace(msg.Role))
|
||||
switch role {
|
||||
@@ -2231,13 +2227,6 @@ func (p *HTTPProvider) codexCompatRequestBody(requestBody map[string]interface{}
|
||||
return codexCompatRequestBody(requestBody)
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) useClaudeCompat() bool {
|
||||
if p == nil || p.oauth == nil {
|
||||
return false
|
||||
}
|
||||
return strings.EqualFold(strings.TrimSpace(p.oauth.cfg.Provider), defaultClaudeOAuthProvider)
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) oauthProvider() string {
|
||||
if p == nil || p.oauth == nil {
|
||||
return ""
|
||||
@@ -2723,40 +2712,6 @@ func CreateProviderByName(cfg *config.Config, name string) (LLMProvider, error)
|
||||
return NewHTTPProvider(routeName, pc.APIKey, pc.APIBase, defaultModel, pc.SupportsResponsesCompact, pc.Auth, time.Duration(pc.TimeoutSec)*time.Second, oauth), nil
|
||||
}
|
||||
|
||||
func CreateProviders(cfg *config.Config) (map[string]LLMProvider, error) {
|
||||
configs := getAllProviderConfigs(cfg)
|
||||
if len(configs) == 0 {
|
||||
return nil, fmt.Errorf("no providers configured")
|
||||
}
|
||||
out := make(map[string]LLMProvider, len(configs))
|
||||
for name := range configs {
|
||||
p, err := CreateProviderByName(cfg, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[name] = p
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func GetProviderModels(cfg *config.Config, name string) []string {
|
||||
pc, err := getProviderConfigByName(cfg, name)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
out := make([]string, 0, len(pc.Models))
|
||||
seen := map[string]bool{}
|
||||
for _, m := range pc.Models {
|
||||
model := strings.TrimSpace(m)
|
||||
if model == "" || seen[model] {
|
||||
continue
|
||||
}
|
||||
seen[model] = true
|
||||
out = append(out, model)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func ProviderSupportsResponsesCompact(cfg *config.Config, name string) bool {
|
||||
pc, err := getProviderConfigByName(cfg, name)
|
||||
if err != nil {
|
||||
@@ -2765,18 +2720,6 @@ func ProviderSupportsResponsesCompact(cfg *config.Config, name string) bool {
|
||||
return pc.SupportsResponsesCompact
|
||||
}
|
||||
|
||||
func ListProviderNames(cfg *config.Config) []string {
|
||||
configs := getAllProviderConfigs(cfg)
|
||||
if len(configs) == 0 {
|
||||
return nil
|
||||
}
|
||||
names := make([]string, 0, len(configs))
|
||||
for name := range configs {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func getAllProviderConfigs(cfg *config.Config) map[string]config.ProviderConfig {
|
||||
return config.AllProviderConfigs(cfg)
|
||||
}
|
||||
|
||||
@@ -318,10 +318,6 @@ func (m *OAuthLoginManager) CredentialFile() string {
|
||||
return m.manager.cfg.CredentialFile
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) StartManualFlow() (*OAuthPendingFlow, error) {
|
||||
return m.StartManualFlowWithOptions(OAuthLoginOptions{})
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) StartManualFlowWithOptions(opts OAuthLoginOptions) (*OAuthPendingFlow, error) {
|
||||
if m == nil || m.manager == nil {
|
||||
return nil, fmt.Errorf("oauth login manager not configured")
|
||||
@@ -351,10 +347,6 @@ func (m *OAuthLoginManager) StartManualFlowWithOptions(opts OAuthLoginOptions) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) CompleteManualFlow(ctx context.Context, apiBase string, flow *OAuthPendingFlow, callbackURL string) (*OAuthSessionInfo, []string, error) {
|
||||
return m.CompleteManualFlowWithOptions(ctx, apiBase, flow, callbackURL, OAuthLoginOptions{})
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) CompleteManualFlowWithOptions(ctx context.Context, apiBase string, flow *OAuthPendingFlow, callbackURL string, opts OAuthLoginOptions) (*OAuthSessionInfo, []string, error) {
|
||||
if m == nil || m.manager == nil {
|
||||
return nil, nil, fmt.Errorf("oauth login manager not configured")
|
||||
@@ -392,10 +384,6 @@ func (m *OAuthLoginManager) CompleteManualFlowWithOptions(ctx context.Context, a
|
||||
}, models, nil
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) ImportAuthJSON(ctx context.Context, apiBase string, fileName string, data []byte) (*OAuthSessionInfo, []string, error) {
|
||||
return m.ImportAuthJSONWithOptions(ctx, apiBase, fileName, data, OAuthLoginOptions{})
|
||||
}
|
||||
|
||||
func (m *OAuthLoginManager) ImportAuthJSONWithOptions(ctx context.Context, apiBase string, fileName string, data []byte, opts OAuthLoginOptions) (*OAuthSessionInfo, []string, error) {
|
||||
if m == nil || m.manager == nil {
|
||||
return nil, nil, fmt.Errorf("oauth login manager not configured")
|
||||
@@ -746,47 +734,6 @@ func defaultRefreshLead(provider string, overrideSec int) time.Duration {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *oauthManager) models(ctx context.Context, apiBase string) ([]string, error) {
|
||||
attempts, err := m.prepareAttemptsLocked(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(attempts) == 0 {
|
||||
return nil, fmt.Errorf("oauth session not found, run `clawgo provider login` first")
|
||||
}
|
||||
var merged []string
|
||||
seen := map[string]struct{}{}
|
||||
var lastErr error
|
||||
for _, attempt := range attempts {
|
||||
client, err := m.httpClientForSession(attempt.Session)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
models, err := fetchOpenAIModels(ctx, client, apiBase, attempt.Token)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
attempt.Session.Models = append([]string(nil), models...)
|
||||
_ = m.persistSessionLocked(attempt.Session)
|
||||
for _, model := range models {
|
||||
if _, ok := seen[model]; ok {
|
||||
continue
|
||||
}
|
||||
seen[model] = struct{}{}
|
||||
merged = append(merged, model)
|
||||
}
|
||||
}
|
||||
if len(merged) > 0 {
|
||||
return merged, nil
|
||||
}
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
return nil, fmt.Errorf("no oauth sessions available")
|
||||
}
|
||||
|
||||
func (m *oauthManager) login(ctx context.Context, apiBase string, opts OAuthLoginOptions) (*oauthSession, []string, error) {
|
||||
if m == nil {
|
||||
return nil, nil, fmt.Errorf("oauth manager not configured")
|
||||
|
||||
@@ -17,85 +17,6 @@ func openAICompatDefaultModel(base *HTTPProvider) string {
|
||||
return base.GetDefaultModel()
|
||||
}
|
||||
|
||||
func runQwenChat(ctx context.Context, base *HTTPProvider, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) {
|
||||
if base == nil {
|
||||
return nil, fmt.Errorf("provider not configured")
|
||||
}
|
||||
requestBody := buildQwenChatRequest(base, messages, tools, model, options, false)
|
||||
body, statusCode, contentType, err := doOpenAICompatJSONWithAttempts(ctx, base, "/chat/completions", requestBody, qwenProviderHooks{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
return parseOpenAICompatResponse(body)
|
||||
}
|
||||
|
||||
func runQwenChatStream(ctx context.Context, base *HTTPProvider, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}, onDelta func(string)) (*LLMResponse, error) {
|
||||
if base == nil {
|
||||
return nil, fmt.Errorf("provider not configured")
|
||||
}
|
||||
if onDelta == nil {
|
||||
onDelta = func(string) {}
|
||||
}
|
||||
requestBody := buildQwenChatRequest(base, messages, tools, model, options, true)
|
||||
body, statusCode, contentType, err := doOpenAICompatStreamWithAttempts(ctx, base, "/chat/completions", requestBody, onDelta, qwenProviderHooks{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
return parseOpenAICompatResponse(body)
|
||||
}
|
||||
|
||||
func runOpenAICompatChat(ctx context.Context, base *HTTPProvider, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) {
|
||||
if base == nil {
|
||||
return nil, fmt.Errorf("provider not configured")
|
||||
}
|
||||
body, statusCode, contentType, err := doOpenAICompatJSONWithAttempts(ctx, base, "/chat/completions", base.buildOpenAICompatChatRequest(messages, tools, model, options), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
return parseOpenAICompatResponse(body)
|
||||
}
|
||||
|
||||
func runOpenAICompatChatStream(ctx context.Context, base *HTTPProvider, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}, onDelta func(string)) (*LLMResponse, error) {
|
||||
if base == nil {
|
||||
return nil, fmt.Errorf("provider not configured")
|
||||
}
|
||||
if onDelta == nil {
|
||||
onDelta = func(string) {}
|
||||
}
|
||||
chatBody := base.buildOpenAICompatChatRequest(messages, tools, model, options)
|
||||
chatBody["stream"] = true
|
||||
chatBody["stream_options"] = map[string]interface{}{"include_usage": true}
|
||||
body, statusCode, contentType, err := doOpenAICompatStreamWithAttempts(ctx, base, "/chat/completions", chatBody, onDelta, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
||||
}
|
||||
return parseOpenAICompatResponse(body)
|
||||
}
|
||||
|
||||
type openAICompatHooks interface {
|
||||
beforeAttempt(attempt authAttempt) (int, []byte, string, bool)
|
||||
endpoint(base *HTTPProvider, attempt authAttempt, path string) string
|
||||
|
||||
Reference in New Issue
Block a user