From 7c1bd9a5a54dca1163e743b53ed0ea67b1ea297e Mon Sep 17 00:00:00 2001 From: Jin Hai Date: Wed, 10 Jun 2026 10:57:00 +0800 Subject: [PATCH] Go CLI: switch to admin/api server (#15861) ### What problem does this PR solve? ``` RAGFlow(api/default)> use admin SUCCESS RAGFlow(api/default)> use api 'abc'; SUCCESS ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai --- internal/cli/admin_parser.go | 12 +++++ internal/cli/cli_http.go | 9 +++- internal/cli/common_command.go | 84 ++++++++++++++++++++++++++++++++-- internal/cli/parser.go | 8 ++-- internal/cli/user_parser.go | 45 ++++++++++++++++-- 5 files changed, 147 insertions(+), 11 deletions(-) diff --git a/internal/cli/admin_parser.go b/internal/cli/admin_parser.go index dc2af91bc1..b4bf964cec 100644 --- a/internal/cli/admin_parser.go +++ b/internal/cli/admin_parser.go @@ -1674,6 +1674,18 @@ func (p *Parser) parseAdminSaveCommand() (*Command, error) { } } +func (p *Parser) parseAdminUseCommand() (*Command, error) { + p.nextToken() // consume USE + switch p.curToken.Type { + case TokenAPI: + return p.parseUseAPIServer() + case TokenAdmin: + return p.parseUseAdminServer() + default: + return nil, fmt.Errorf("expected MODEL or SKILL after USE") + } +} + func (p *Parser) parseStartIngestion() (*Command, error) { p.nextToken() // consume Start diff --git a/internal/cli/cli_http.go b/internal/cli/cli_http.go index 6135a79a97..33435a2024 100644 --- a/internal/cli/cli_http.go +++ b/internal/cli/cli_http.go @@ -127,7 +127,10 @@ func (c *CLI) ExecuteAdminCommand(cmd *Command) (ResponseIf, error) { return nil, fmt.Errorf("cannot delete admin server in admin mode") case "save_config_command": return c.SaveServerConfig(cmd) - // TODO: Implement other commands + case "use_api_server": + return c.UseAPIServer(cmd) + case "use_admin_server": + return c.UseAdminServer(cmd) default: return nil, fmt.Errorf("command '%s' would be executed with API", cmd.Type) } @@ -240,6 +243,10 @@ func (c *CLI) ExecuteUserCommand(cmd *Command) (ResponseIf, error) { return c.CheckProviderWithKey(cmd) case "use_model": return c.UseModel(cmd) + case "use_api_server": + return c.UseAPIServer(cmd) + case "use_admin_server": + return c.UseAdminServer(cmd) case "set_default_model": return c.SetDefaultModel(cmd) case "reset_default_model": diff --git a/internal/cli/common_command.go b/internal/cli/common_command.go index b1161f4b99..fd1de23d8e 100644 --- a/internal/cli/common_command.go +++ b/internal/cli/common_command.go @@ -713,10 +713,6 @@ func (c *CLI) AddAPIServer(cmd *Command) (ResponseIf, error) { c.Config.APIClientConfig.APIServerMap[apiServerName].ApiToken = &apiServerToken } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - if c.APIServerClientMap == nil { c.APIServerClientMap = make(map[string]*HTTPClient) } @@ -725,6 +721,10 @@ func (c *CLI) AddAPIServer(cmd *Command) (ResponseIf, error) { return nil, fmt.Errorf("api server: %s already exists", apiServerName) } + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + c.APIServerClientMap[apiServerName] = &HTTPClient{ Host: apiServerIP, Port: apiServerPort, @@ -788,6 +788,23 @@ func (c *CLI) AddAdminServer(cmd *Command) (ResponseIf, error) { c.Config.AdminClientConfig.AdminPort = adminServerPort } + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + c.AdminServerClient = &HTTPClient{ + Host: adminServerIP, + Port: adminServerPort, + APIVersion: "v1", + ConnectTimeout: 5 * time.Second, + ReadTimeout: 60 * time.Second, + VerifySSL: false, + client: &http.Client{ + Transport: transport, + Timeout: 300 * time.Second, + }, + } + var result SimpleResponse result.Code = 0 result.Message = "admin server added successfully" @@ -1027,3 +1044,62 @@ func FlattenMap(data map[string]interface{}, prefix string, result *[]map[string } } } + +func (c *CLI) UseAPIServer(cmd *Command) (ResponseIf, error) { + serverName, ok := cmd.Params["server_name"].(string) + if !ok { + return nil, fmt.Errorf("server_name not provided") + } + + if c.Config.CLIMode == APIMode { + if c.Config.APIClientConfig.CurrentAPIServer == serverName { + return nil, fmt.Errorf("api server %s is already used", serverName) + } + } + + var httpClient *HTTPClient + httpClient, ok = c.APIServerClientMap[serverName] + if !ok { + return nil, fmt.Errorf("api server %s not found", serverName) + } + if httpClient == nil { + return nil, fmt.Errorf("api server %s is nil", serverName) + } + var apiServerConfig *APIServerConfig + apiServerConfig, ok = c.Config.APIClientConfig.APIServerMap[serverName] + if !ok { + return nil, fmt.Errorf("api server %s not found in config", serverName) + } + if apiServerConfig == nil { + return nil, fmt.Errorf("api server %s is nil", serverName) + } + + c.Config.APIClientConfig.CurrentAPIServer = serverName + c.Config.CLIMode = APIMode + + var result SimpleResponse + result.Code = 0 + result.Message = fmt.Sprintf("switch to api server %s", serverName) + result.Duration = 0 + return &result, nil + +} + +func (c *CLI) UseAdminServer(cmd *Command) (ResponseIf, error) { + + if c.Config.CLIMode == AdminMode { + return nil, fmt.Errorf("already in admin mode") + } + + if c.AdminServerClient == nil || c.Config.AdminClientConfig == nil { + return nil, fmt.Errorf("admin server not added") + } + + c.Config.CLIMode = AdminMode + + var result SimpleResponse + result.Code = 0 + result.Message = "switch to admin server" + result.Duration = 0 + return &result, nil +} diff --git a/internal/cli/parser.go b/internal/cli/parser.go index 04253b051a..67af77b9e5 100644 --- a/internal/cli/parser.go +++ b/internal/cli/parser.go @@ -134,6 +134,8 @@ func (p *Parser) parseAdminCommand() (*Command, error) { return p.parseAdminDeleteCommand() case TokenSave: return p.parseAdminSaveCommand() + case TokenUse: + return p.parseAdminUseCommand() default: return nil, fmt.Errorf("unknown command: %s", p.curToken.Value) } @@ -328,7 +330,9 @@ func (p *Parser) parseFloat() (float64, error) { } // parseQuotedStringList consumes a bracket-delimited list of quoted strings: -// [ 'a', 'b', 'c' ] +// +// [ 'a', 'b', 'c' ] +// // Empty list [] is allowed. The cursor must be positioned on '[' when called; // on return, the cursor is positioned just past the closing ']'. func (p *Parser) parseQuotedStringList() ([]string, error) { @@ -398,5 +402,3 @@ func (p *Parser) parseFileSystemCommand() (*Command, error) { return cmd, nil } - - diff --git a/internal/cli/user_parser.go b/internal/cli/user_parser.go index 006675c6e2..6f5640a7dc 100644 --- a/internal/cli/user_parser.go +++ b/internal/cli/user_parser.go @@ -3692,12 +3692,21 @@ func (p *Parser) parseCheckProviderByKeyCommand() (*Command, error) { func (p *Parser) parseUseCommand() (*Command, error) { p.nextToken() // consume USE - if p.curToken.Type != TokenModel { - return nil, fmt.Errorf("expected MODEL after USE") + switch p.curToken.Type { + case TokenModel: + return p.parseUseModel() + case TokenAPI: + return p.parseUseAPIServer() + case TokenAdmin: + return p.parseUseAdminServer() + default: + return nil, fmt.Errorf("expected MODEL or SKILL after USE") } +} + +func (p *Parser) parseUseModel() (*Command, error) { p.nextToken() // consume MODEL - // Parse model identifier in format 'model@instance@provider' compositeModelName, err := p.parseQuotedString() if err != nil { return nil, fmt.Errorf("expected model identifier in format 'model@instance@provider': %w", err) @@ -3714,6 +3723,36 @@ func (p *Parser) parseUseCommand() (*Command, error) { return cmd, nil } +func (p *Parser) parseUseAPIServer() (*Command, error) { + p.nextToken() // consume API + + serverName, err := p.parseQuotedString() + if err != nil { + return nil, err + } + p.nextToken() + cmd := NewCommand("use_api_server") + cmd.Params["server_name"] = serverName + + // Semicolon is optional + if p.curToken.Type == TokenSemicolon { + p.nextToken() + } + return cmd, nil +} + +func (p *Parser) parseUseAdminServer() (*Command, error) { + p.nextToken() // consume ADMIN + + cmd := NewCommand("use_admin_server") + + // Semicolon is optional + if p.curToken.Type == TokenSemicolon { + p.nextToken() + } + return cmd, nil +} + func (p *Parser) parseParseCommand() (*Command, error) { p.nextToken() // consume PARSE