Release v1.4.8 remote detection fixes
This commit is contained in:
@@ -135,7 +135,7 @@ func (c *Client) ListModels(ctx context.Context) ([]Model, error) {
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode >= 400 {
|
||||
return nil, fmt.Errorf("remote model list status %d: %s", resp.StatusCode, truncate(string(body), 500))
|
||||
return nil, c.modelListStatusError(resp.StatusCode, string(body))
|
||||
}
|
||||
var payload struct {
|
||||
Chat []Model `json:"chat"`
|
||||
@@ -147,6 +147,14 @@ func (c *Client) ListModels(ctx context.Context) ([]Model, error) {
|
||||
return append(payload.Chat, payload.Inline...), nil
|
||||
}
|
||||
|
||||
func (c *Client) modelListStatusError(statusCode int, body string) error {
|
||||
message := fmt.Sprintf("remote model list status %d from %s: %s", statusCode, c.cfg.BaseURL, truncate(body, 500))
|
||||
if statusCode == http.StatusNotFound || strings.Contains(body, "NoSuchKey") {
|
||||
message += "。这通常表示远端 API 域名自动探测命中了错误地址,请到设置页手动填写 Lingma 官方或企业专属远端 API 域名;官方默认域名为 https://lingma.alibabacloud.com。"
|
||||
}
|
||||
return fmt.Errorf("%s", message)
|
||||
}
|
||||
|
||||
func (c *Client) Chat(ctx context.Context, request ChatRequest, onDelta func(string)) (*ChatResult, error) {
|
||||
cred, err := LoadCredential(c.cfg.AuthFile)
|
||||
if err != nil {
|
||||
@@ -592,12 +600,29 @@ func normalizeRemoteBaseURLHint(raw string) string {
|
||||
return ""
|
||||
}
|
||||
host := strings.ToLower(parsed.Host)
|
||||
if !strings.Contains(host, "lingma") && !strings.Contains(host, "rdc.aliyuncs.com") {
|
||||
if !isRemoteAPIHost(host) {
|
||||
return ""
|
||||
}
|
||||
return parsed.Scheme + "://" + parsed.Host
|
||||
}
|
||||
|
||||
func isRemoteAPIHost(host string) bool {
|
||||
if host == "" {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(host, ".oss-") || strings.Contains(host, "oss-rg-") || strings.Contains(host, ".oss.") {
|
||||
return false
|
||||
}
|
||||
switch host {
|
||||
case "lingma.alibabacloud.com", "lingma-api.tongyi.aliyun.com":
|
||||
return true
|
||||
}
|
||||
if strings.HasSuffix(host, ".rdc.aliyuncs.com") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func estimateTokens(text string) int {
|
||||
text = strings.TrimSpace(text)
|
||||
if text == "" {
|
||||
|
||||
@@ -3,6 +3,7 @@ package remote
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -22,43 +23,76 @@ func TestNewKeepsPositiveTimeout(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExtractBaseURLFromEndpointLog(t *testing.T) {
|
||||
got := extractBaseURLFromText(`2026-04-10 INFO Update endpoint success. endpoint config: https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com`)
|
||||
want := "https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com"
|
||||
got := extractBaseURLFromText(`2026-04-10 INFO Update endpoint success. endpoint config: https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com`)
|
||||
want := "https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com"
|
||||
if got != want {
|
||||
t.Fatalf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractBaseURLFromMarketplaceLog(t *testing.T) {
|
||||
got := extractBaseURLFromText(`2026-04-30 [info] [Marketplace] Using service url: https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com/marketplace/_apis/public/gallery`)
|
||||
want := "https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com"
|
||||
got := extractBaseURLFromText(`2026-04-30 [info] [Marketplace] Using service url: https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com/marketplace/_apis/public/gallery`)
|
||||
want := "https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com"
|
||||
if got != want {
|
||||
t.Fatalf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractBaseURLFromRawWindowsLogURL(t *testing.T) {
|
||||
got := extractBaseURLFromText(`2026-05-06T12:00:00 endpoint=https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com/algo/api/v2/model/list`)
|
||||
want := "https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com"
|
||||
got := extractBaseURLFromText(`2026-05-06T12:00:00 endpoint=https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com/algo/api/v2/model/list`)
|
||||
want := "https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com"
|
||||
if got != want {
|
||||
t.Fatalf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractBaseURLIgnoresLingmaOSSAssetHost(t *testing.T) {
|
||||
got := extractBaseURLFromText(`2026-05-06 endpoint config: https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com
|
||||
2026-05-06 Download asset from: https://lingma-ide.oss-rg-china-mainland.aliyuncs.com/lingma-extension/download?name=plugin.zip`)
|
||||
want := "https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com"
|
||||
if got != want {
|
||||
t.Fatalf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeBaseURLRepairsMissingLeadingH(t *testing.T) {
|
||||
got := normalizeRemoteBaseURLHint(`ttps://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com`)
|
||||
want := "https://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com"
|
||||
got := normalizeRemoteBaseURLHint(`ttps://ai-lingma-example-cn-beijing.rdc.aliyuncs.com`)
|
||||
want := "https://ai-lingma-example-cn-beijing.rdc.aliyuncs.com"
|
||||
if got != want {
|
||||
t.Fatalf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeBaseURLRejectsUnsupportedScheme(t *testing.T) {
|
||||
if got := normalizeRemoteBaseURLHint(`ftp://ai-lingma-cmb01-cn-beijing.rdc.aliyuncs.com`); got != "" {
|
||||
func TestNormalizeBaseURLRejectsLingmaOSSAssetHost(t *testing.T) {
|
||||
if got := normalizeRemoteBaseURLHint(`https://lingma-ide.oss-rg-china-mainland.aliyuncs.com/lingma-extension/download`); got != "" {
|
||||
t.Fatalf("got %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeBaseURLRejectsUnsupportedScheme(t *testing.T) {
|
||||
if got := normalizeRemoteBaseURLHint(`ftp://ai-lingma-example-cn-beijing.rdc.aliyuncs.com`); got != "" {
|
||||
t.Fatalf("got %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelListStatusErrorSuggestsManualRemoteBaseURLOn404(t *testing.T) {
|
||||
client := New(Config{BaseURL: "https://lingma-ide.oss-rg-china-mainland.aliyuncs.com"})
|
||||
err := client.modelListStatusError(404, `<Error><Code>NoSuchKey</Code></Error>`)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
text := err.Error()
|
||||
for _, want := range []string{
|
||||
"https://lingma-ide.oss-rg-china-mainland.aliyuncs.com",
|
||||
"远端 API 域名自动探测命中了错误地址",
|
||||
"https://lingma.alibabacloud.com",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("error %q missing %q", text, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractMachineIDFromTextMarkers(t *testing.T) {
|
||||
got := extractMachineIDFromText(`2026-05-06 info using machine id from file: abcdef1234567890abcdef`)
|
||||
if got != "abcdef1234567890abcdef" {
|
||||
|
||||
Reference in New Issue
Block a user