Go CLI: Add create and drop commands (#16430)

### What problem does this PR solve?

1. Add CREATE and DROP DATASET / MEMORY / AGENT / SEARCH / CHAT.
2. Add option to build.sh to strip RAGFlow binary.

### Type of change

- [x] Refactoring

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-06-29 11:13:14 +08:00
committed by GitHub
parent b6dbb2f71e
commit d4ef3d21d1
11 changed files with 530 additions and 203 deletions

View File

@@ -19,6 +19,9 @@ ADMIN_SERVER_BINARY="$PROJECT_ROOT/bin/admin_server"
INGESTOR_BINARY="$PROJECT_ROOT/bin/ingestor"
RAGFLOW_CLI_BINARY="$PROJECT_ROOT/bin/ragflow-cli"
# Strip symbols from Go binaries (set via --strip / -s)
STRIP_SYMBOLS=""
# office_oxide native library settings
OFFICE_OXIDE_PREFIX="${HOME}/.office_oxide"
OFFICE_OXIDE_VERSION="0.1.2"
@@ -255,19 +258,22 @@ build_go() {
setup_cgo_env
local strip_flags=()
[ -n "$STRIP_SYMBOLS" ] && strip_flags=(-ldflags="-s -w")
echo "Building RAGFlow binary: $RAGFLOW_SERVER_BINARY, $ADMIN_SERVER_BINARY, $INGESTOR_BINARY, and $RAGFLOW_CLI_BINARY"
GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 \
CGO_CFLAGS="$CGO_CFLAGS" CGO_LDFLAGS="$CGO_LDFLAGS" \
go build -o "$RAGFLOW_SERVER_BINARY" cmd/server_main.go
go build "${strip_flags[@]}" -o "$RAGFLOW_SERVER_BINARY" cmd/server_main.go
GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 \
CGO_CFLAGS="$CGO_CFLAGS" CGO_LDFLAGS="$CGO_LDFLAGS" \
go build -o "$ADMIN_SERVER_BINARY" cmd/admin_server.go
go build "${strip_flags[@]}" -o "$ADMIN_SERVER_BINARY" cmd/admin_server.go
GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 \
CGO_CFLAGS="$CGO_CFLAGS" CGO_LDFLAGS="$CGO_LDFLAGS" \
go build -o "$INGESTOR_BINARY" cmd/ingestor.go
go build "${strip_flags[@]}" -o "$INGESTOR_BINARY" cmd/ingestor.go
GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 \
CGO_CFLAGS="$CGO_CFLAGS" CGO_LDFLAGS="$CGO_LDFLAGS" \
go build -o "$RAGFLOW_CLI_BINARY" cmd/ragflow-cli.go
go build "${strip_flags[@]}" -o "$RAGFLOW_CLI_BINARY" cmd/ragflow-cli.go
if [ ! -f "$RAGFLOW_SERVER_BINARY" ]; then
echo -e "${RED}Error: Failed to build RAGFlow server binary${NC}"
@@ -389,6 +395,8 @@ OPTIONS:
`$0 --test -- -run TestFoo ./internal/admin/...`
--clean, -C Clean all build artifacts
--run, -r Build and run the server
--strip, -s Strip debug symbols from Go binaries (-ldflags="-s -w")
(disabled by default, useful for smaller production binaries)
--help, -h Show this help message
EXAMPLES:
@@ -415,7 +423,16 @@ EOF
# Main function
main() {
case "${1:-}" in
# Parse --strip / -s before other arguments
local args=()
for arg in "$@"; do
case "$arg" in
--strip|-s) STRIP_SYMBOLS="1" ;;
*) args+=("$arg") ;;
esac
done
case "${args[0]:-}" in
--cpp|-c)
check_cpp_deps
build_cpp

View File

@@ -1269,42 +1269,6 @@ func (p *Parser) parseAdminDropRole() (*Command, error) {
return cmd, nil
}
func (p *Parser) parseAdminDropDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user_dataset")
cmd.Params["dataset_name"] = datasetName
p.nextToken()
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
func (p *Parser) parseAdminDropChat() (*Command, error) {
p.nextToken() // consume CHAT
chatName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user_chat")
cmd.Params["chat_name"] = chatName
p.nextToken()
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
// endregion DROP commands
// region ALTER commands

View File

@@ -312,6 +312,8 @@ func (c *CLI) ExecuteUserCommand(cmd *Command) (ResponseIf, error) {
return c.APIListChatsCommand(cmd)
case "api_list_searches":
return c.APIListSearchesCommand(cmd)
case "api_list_memories":
return c.APIListMemoriesCommand(cmd)
case "list_dataset_documents":
return c.ListDatasetDocumentUserCommand(cmd)
case "search_on_datasets":
@@ -380,6 +382,16 @@ func (c *CLI) ExecuteUserCommand(cmd *Command) (ResponseIf, error) {
return c.APIListProviders(cmd)
case "delete_provider":
return c.DeleteProvider(cmd)
case "api_drop_dataset":
return c.APIDropDatasetCommand(cmd)
case "api_drop_chat":
return c.APIDropChatCommand(cmd)
case "api_drop_search":
return c.APIDropSearchCommand(cmd)
case "api_drop_memory":
return c.APIDropMemoryCommand(cmd)
case "api_drop_agent":
return c.APIDropAgentCommand(cmd)
// Provider instance commands
case "api_create_provider_instance":
return c.APICreateProviderInstanceCommand(cmd)

View File

@@ -1613,3 +1613,79 @@ func (c *CLI) getDatasetIDByName(datasetName string) (string, error) {
}
return "", fmt.Errorf("dataset %s not found", datasetName)
}
func (c *CLI) getAgentIDByName(agentName string) (string, error) {
response, err := c.APIListAgentsCommand(nil)
if err != nil {
return "", err
}
commonResponse, ok := response.(*CommonResponse)
if !ok {
return "", fmt.Errorf("invalid response")
}
for _, agent := range commonResponse.Data {
if agent["name"] == agentName {
return agent["id"].(string), nil
}
}
return "", fmt.Errorf("agent %s not found", agentName)
}
func (c *CLI) getSearchIDByName(searchName string) (string, error) {
response, err := c.APIListSearchesCommand(nil)
if err != nil {
return "", err
}
searchesResponse, ok := response.(*ListSearchesResponse)
if !ok {
return "", fmt.Errorf("invalid response")
}
searches := searchesResponse.Data["search_apps"].([]interface{})
for _, search := range searches {
searchMap := search.(map[string]interface{})
if searchMap["name"] == searchName {
return searchMap["id"].(string), nil
}
}
return "", fmt.Errorf("search %s not found", searchName)
}
func (c *CLI) getChatIDByName(chatName string) (string, error) {
response, err := c.APIListChatsCommand(nil)
if err != nil {
return "", err
}
commonResponse, ok := response.(*CommonResponse)
if !ok {
return "", fmt.Errorf("invalid response")
}
for _, chat := range commonResponse.Data {
if chat["name"] == chatName {
return chat["id"].(string), nil
}
}
return "", fmt.Errorf("chat %s not found", chatName)
}
func (c *CLI) getMemoryIDByName(memoryName string) (string, error) {
response, err := c.APIListMemoriesCommand(nil)
if err != nil {
return "", err
}
listMemoriesResponse, ok := response.(*ListMemoriesResponse)
memories := listMemoriesResponse.Data["memory_list"].([]interface{})
if !ok {
return "", fmt.Errorf("invalid response")
}
for _, memory := range memories {
var memoryMap map[string]interface{}
memoryMap, ok = memory.(map[string]interface{})
if !ok {
continue
}
if memoryMap["name"] == memoryName {
return memoryMap["id"].(string), nil
}
}
return "", fmt.Errorf("memory %s not found", memoryName)
}

View File

@@ -365,6 +365,8 @@ func (l *Lexer) lookupIdent(ident string) Token {
return Token{Type: TokenAgent, Value: ident}
case "MEMORY":
return Token{Type: TokenMemory, Value: ident}
case "MEMORIES":
return Token{Type: TokenMemories, Value: ident}
case "RETRIEVE":
return Token{Type: TokenRetrieve, Value: ident}
case "CURRENT":

View File

@@ -288,6 +288,42 @@ func (r *ListSearchesResponse) PrintOut() {
}
}
type ListMemoriesResponse struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
Message string `json:"message"`
Duration float64
OutputFormat OutputFormat
}
func (r *ListMemoriesResponse) Type() string {
return "list_memories"
}
func (r *ListMemoriesResponse) TimeCost() float64 {
return r.Duration
}
func (r *ListMemoriesResponse) SetOutputFormat(format OutputFormat) {
r.OutputFormat = format
}
func (r *ListMemoriesResponse) PrintOut() {
if r.Code == 0 {
total := r.Data["total_count"].(float64)
fmt.Printf("Total: %0.0f\n", total)
docs := r.Data["memory_list"].([]interface{})
table := make([]map[string]interface{}, 0)
for _, doc := range docs {
table = append(table, doc.(map[string]interface{}))
}
PrintTableSimpleByFormat(table, r.OutputFormat)
} else {
fmt.Println("ERROR")
fmt.Printf("%d, %s\n", r.Code, r.Message)
}
}
type ChunkResponse struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
@@ -414,6 +450,20 @@ func (r *SimpleResponse) PrintOut() {
}
}
func HandleSimpleResponse(response *Response, command string) (ResponseIf, error) {
var result SimpleResponse
if err := json.Unmarshal(response.Body, &result); err != nil {
return nil, fmt.Errorf("%s failed: invalid JSON (%w)", command, err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = response.Duration
return &result, nil
}
type MessageResponse struct {
Code int `json:"code"`
Message string `json:"message"`

View File

@@ -102,6 +102,7 @@ const (
TokenPipeline
TokenSearch
TokenAgent
TokenMemories
TokenMemory
TokenRetrieve
TokenCurrent

View File

@@ -248,16 +248,10 @@ func (c *CLI) APISetLogLevelCommand(cmd *Command) (ResponseIf, error) {
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to register user: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
return nil, fmt.Errorf("failed to change log level: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("change log level failed: invalid JSON (%w)", err)
}
result.Code = 0
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "change log level")
}
func (c *CLI) RegisterUser(cmd *Command) (ResponseIf, error) {
@@ -602,6 +596,50 @@ func (c *CLI) APIListSearchesCommand(cmd *Command) (ResponseIf, error) {
return &result, nil
}
// APIListMemoriesCommand lists memories
func (c *CLI) APIListMemoriesCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
authKind := "web"
if httpClient.useAPIKey {
authKind = "api"
}
if httpClient.LoginToken != nil {
authKind = "web"
}
// Normal mode
resp, err := httpClient.Request("GET", "/memories", authKind, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to list memories: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to list memories: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result ListMemoriesResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("list memories failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
}
// ListDatasetDocumentUserCommand lists dataset documents
func (c *CLI) ListDatasetDocumentUserCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
@@ -1000,7 +1038,16 @@ func (c *CLI) APICreateDatasetCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("no authorization")
}
resp, err := httpClient.Request("POST", "/datasets", "web", nil, nil)
datasetName, ok := cmd.Params["dataset_name"].(string)
if !ok {
return nil, fmt.Errorf("dataset_name parameter is required")
}
payload := map[string]interface{}{
"name": datasetName,
}
resp, err := httpClient.Request("POST", "/datasets", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create dataset: %w", err)
}
@@ -1009,20 +1056,7 @@ func (c *CLI) APICreateDatasetCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to create dataset: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var createResult CommonDataResponse
if err = json.Unmarshal(resp.Body, &createResult); err != nil {
return nil, fmt.Errorf("create dataset failed: invalid JSON (%w)", err)
}
if createResult.Code != 0 {
return nil, fmt.Errorf("error code: %d, message: %s", createResult.Code, createResult.Message)
}
var result SimpleResponse
result.Code = 0
result.Message = "Dataset created successfully"
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "create dataset")
}
func (c *CLI) APICreateAgentCommand(cmd *Command) (ResponseIf, error) {
@@ -1111,7 +1145,16 @@ func (c *CLI) APICreateSearchCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("no authorization")
}
resp, err := httpClient.Request("POST", "/searches", "web", nil, nil)
searchName, ok := cmd.Params["search_name"].(string)
if !ok {
return nil, fmt.Errorf("search_name parameter is required")
}
payload := map[string]interface{}{
"name": searchName,
}
resp, err := httpClient.Request("POST", "/searches", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create search: %w", err)
}
@@ -1148,7 +1191,16 @@ func (c *CLI) APICreateMemoryCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("no authorization")
}
resp, err := httpClient.Request("POST", "/memories", "web", nil, nil)
memoryName, ok := cmd.Params["memory_name"].(string)
if !ok {
return nil, fmt.Errorf("memory_name parameter is required")
}
payload := map[string]interface{}{
"name": memoryName,
}
resp, err := httpClient.Request("POST", "/memories", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create memory: %w", err)
}
@@ -1221,16 +1273,7 @@ func (c *CLI) APIDeleteAPIKeyCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to delete key: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("delete key failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "delete key")
}
// APISetAPIKeyCommand sets the API key after validating it
@@ -1628,17 +1671,7 @@ func (c *CLI) AddProvider(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to add provider: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("add provider failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "add provider")
}
// APIListProviders lists added providers
@@ -1702,17 +1735,196 @@ func (c *CLI) DeleteProvider(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to delete provider: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("delete provider failed: invalid JSON (%w)", err)
return HandleSimpleResponse(resp, "delete provider")
}
// APIDropDatasetCommand DROP DATASET 'dataset_name'
func (c *CLI) APIDropDatasetCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
result.Duration = resp.Duration
return &result, nil
datasetName, ok := cmd.Params["dataset_name"].(string)
if !ok {
return nil, fmt.Errorf("dataset_name parameter is required")
}
datasetID, err := c.getDatasetIDByName(datasetName)
if err != nil {
return nil, fmt.Errorf("failed to get dataset ID: %w by dataset name: %s", err, datasetName)
}
payload := map[string]interface{}{
"ids": []string{datasetID},
"delete_all": true,
}
resp, err := httpClient.Request("DELETE", "/datasets", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create dataset: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to create dataset: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
return HandleSimpleResponse(resp, "create provider instance")
}
// APIDropAgentCommand DROP AGENT 'agent_name'
func (c *CLI) APIDropAgentCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
agentName, ok := cmd.Params["agent_name"].(string)
if !ok {
return nil, fmt.Errorf("agent_name parameter is required")
}
agentID, err := c.getAgentIDByName(agentName)
if err != nil {
return nil, fmt.Errorf("failed to get agent ID: %w by agent name: %s", err, agentName)
}
payload := map[string]interface{}{
"ids": []string{agentID},
"delete_all": true,
}
resp, err := httpClient.Request("DELETE", "/agents", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create agent: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to create agent: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
return HandleSimpleResponse(resp, "delete agent")
}
// APIDropChatCommand DROP CHAT 'chat_name'
func (c *CLI) APIDropChatCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
chatName, ok := cmd.Params["chat_name"].(string)
if !ok {
return nil, fmt.Errorf("chat_name parameter is required")
}
chatID, err := c.getChatIDByName(chatName)
if err != nil {
return nil, fmt.Errorf("failed to get chat ID: %w by chat name: %s", err, chatName)
}
payload := map[string]interface{}{
"ids": []string{chatID},
"delete_all": true,
}
resp, err := httpClient.Request("DELETE", "/chats", "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to create chat: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to create chat: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
return HandleSimpleResponse(resp, "delete chat")
}
// APIDropSearchCommand DROP SEARCH 'search_name'
func (c *CLI) APIDropSearchCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
searchName, ok := cmd.Params["search_name"].(string)
if !ok {
return nil, fmt.Errorf("search_name parameter is required")
}
searchID, err := c.getSearchIDByName(searchName)
if err != nil {
return nil, fmt.Errorf("failed to get search ID: %w by search name: %s", err, searchName)
}
endPoint := fmt.Sprintf("/searches/%s", searchID)
resp, err := httpClient.Request("DELETE", endPoint, "web", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to delete search: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to delete search: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
return HandleSimpleResponse(resp, "delete search")
}
// APIDropMemoryCommand DROP MEMORY 'memory_name'
func (c *CLI) APIDropMemoryCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != APIMode {
return nil, fmt.Errorf("this command is only allowed in USER mode")
}
httpClient := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer]
if httpClient.LoginToken == nil && !c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].useAPIKey {
return nil, fmt.Errorf("no authorization")
}
memoryName, ok := cmd.Params["memory_name"].(string)
if !ok {
return nil, fmt.Errorf("memory_name parameter is required")
}
memoryID, err := c.getMemoryIDByName(memoryName)
if err != nil {
return nil, fmt.Errorf("failed to get memory ID: %w by memory name: %s", err, memoryName)
}
endPoint := fmt.Sprintf("/memories/%s", memoryID)
resp, err := httpClient.Request("DELETE", endPoint, "web", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to delete memory: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to delete memory: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
return HandleSimpleResponse(resp, "delete memory")
}
// APICreateProviderInstanceCommand creates a new provider instance
@@ -1770,17 +1982,7 @@ func (c *CLI) APICreateProviderInstanceCommand(cmd *Command) (ResponseIf, error)
return nil, fmt.Errorf("failed to create provider instance: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("create provider instance failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "create provider instance")
}
// ShowInstanceBalance shows balance of a specific instance
@@ -1856,17 +2058,7 @@ func (c *CLI) DropProviderInstance(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to drop instance: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("drop instance failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "drop instance")
}
// DROP MODEL <name1 name2 name3> FROM <provider_name> <instance_name>
@@ -1899,24 +2091,14 @@ func (c *CLI) DropInstanceModel(cmd *Command) (ResponseIf, error) {
resp, err := c.APIServerClientMap[c.Config.APIClientConfig.CurrentAPIServer].Request("DELETE", url, "web", nil, payload)
if err != nil {
return nil, fmt.Errorf("failed to drop instance: %w", err)
return nil, fmt.Errorf("failed to drop model: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to drop instance: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
return nil, fmt.Errorf("failed to drop model: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("drop instance failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "drop model")
}
func isValidURL(str string) bool {
@@ -3043,16 +3225,8 @@ func (c *CLI) AddCustomModel(cmd *Command) (ResponseIf, error) {
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to add custom model: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("add custom model failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "add custom model")
}
// InsertChunksFromFile inserts chunks from a JSON file
@@ -3522,17 +3696,7 @@ func (c *CLI) ParseDocumentsUserCommand(cmd *Command) (ResponseIf, error) {
return nil, fmt.Errorf("failed to list documents: HTTP %d, body: %s", resp.StatusCode, string(resp.Body))
}
var result SimpleResponse
if err = json.Unmarshal(resp.Body, &result); err != nil {
return nil, fmt.Errorf("list documents failed: invalid JSON (%w)", err)
}
if result.Code != 0 {
return nil, fmt.Errorf("%s", result.Message)
}
result.Duration = resp.Duration
return &result, nil
return HandleSimpleResponse(resp, "list documents")
}
func (c *CLI) UserParseLocalFile(cmd *Command) (ResponseIf, error) {

View File

@@ -140,6 +140,8 @@ func (p *Parser) parseAPIListCommands() (*Command, error) {
return p.parseAPIListChats()
case TokenSearches:
return p.parseAPIListSearches()
case TokenMemories:
return p.parseAPIListMemories()
case TokenKeys:
return p.parseAPIListAPIKeys()
case TokenProviders:
@@ -283,6 +285,17 @@ func (p *Parser) parseAPIListSearches() (*Command, error) {
return NewCommand("api_list_searches"), nil
}
func (p *Parser) parseAPIListMemories() (*Command, error) {
p.nextToken() // consume MEMORIES
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return NewCommand("api_list_memories"), nil
}
func (p *Parser) parseGetMetadata() (*Command, error) {
p.nextToken() // consume METADATA
@@ -1247,8 +1260,7 @@ func (p *Parser) parseAPISaveConfig() (*Command, error) {
return cmd, nil
}
// CREATE DATASET 'abc' WITH EMBEDDING 'modelName@instanceName@providerName' PARSER 'parserType'
// CREATE DATASET 'abc' WITH EMBEDDING 'modelName@instanceName@providerName' PIPELINE 'pipelineName'
// CREATE DATASET 'abc';
func (p *Parser) parseAPICreateDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
@@ -1256,52 +1268,13 @@ func (p *Parser) parseAPICreateDataset() (*Command, error) {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH")
}
p.nextToken()
if p.curToken.Type != TokenEmbedding {
return nil, fmt.Errorf("expected EMBEDDING")
}
p.nextToken()
embedding, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
cmd := NewCommand("api_create_dataset")
cmd.Params["dataset_name"] = datasetName
cmd.Params["embedding"] = embedding
if p.curToken.Type == TokenParser {
p.nextToken()
var parserType string
parserType, err = p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["parser_type"] = parserType
p.nextToken()
} else if p.curToken.Type == TokenPipeline {
p.nextToken()
var pipeline string
pipeline, err = p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["pipeline"] = pipeline
p.nextToken()
} else {
return nil, fmt.Errorf("expected PARSER or PIPELINE")
}
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
cmd := NewCommand("api_create_dataset")
cmd.Params["dataset_name"] = datasetName
return cmd, nil
}
@@ -1389,9 +1362,15 @@ func (p *Parser) parseAPIDropCommands() (*Command, error) {
switch p.curToken.Type {
case TokenDataset:
return p.parseDropDataset()
return p.parseAPIDropDataset()
case TokenChat:
return p.parseDropChat()
return p.parseAPIDropChat()
case TokenSearch:
return p.parseAPIDropSearch()
case TokenMemory:
return p.parseAPIDropMemory()
case TokenAgent:
return p.parseAPIDropAgent()
case TokenKey:
return p.parseAPIDeleteAPIKey()
case TokenChunkStore:
@@ -1529,16 +1508,52 @@ func (p *Parser) parseDeleteProvider() (*Command, error) {
return cmd, nil
}
func (p *Parser) parseDropDataset() (*Command, error) {
func (p *Parser) parseAPIDropDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
cmd := NewCommand("drop_user_dataset")
cmd := NewCommand("api_drop_dataset")
cmd.Params["dataset_name"] = datasetName
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
func (p *Parser) parseAPIDropSearch() (*Command, error) {
p.nextToken() // consume SEARCH
searchName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
cmd := NewCommand("api_drop_search")
cmd.Params["search_name"] = searchName
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
func (p *Parser) parseAPIDropChat() (*Command, error) {
p.nextToken() // consume CHAT
chatName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("api_drop_chat")
cmd.Params["chat_name"] = chatName
p.nextToken()
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
@@ -1547,15 +1562,33 @@ func (p *Parser) parseDropDataset() (*Command, error) {
return cmd, nil
}
func (p *Parser) parseDropChat() (*Command, error) {
p.nextToken() // consume CHAT
chatName, err := p.parseQuotedString()
func (p *Parser) parseAPIDropMemory() (*Command, error) {
p.nextToken() // consume MEMORY
memoryName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user_chat")
cmd.Params["chat_name"] = chatName
cmd := NewCommand("api_drop_memory")
cmd.Params["memory_name"] = memoryName
p.nextToken()
// Semicolon is optional
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
func (p *Parser) parseAPIDropAgent() (*Command, error) {
p.nextToken() // consume AGENT
agentName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("api_drop_agent")
cmd.Params["agent_name"] = agentName
p.nextToken()
// Semicolon is optional

View File

@@ -19,6 +19,14 @@ docker compose -f docker/docker-compose-base.yml up -d
./build.sh --go
```
- Production builds (strip debug symbols for smaller binaries):
```bash
./build.sh --strip --all
# or
./build.sh -s --go
```
> **Note**: If you use IDEs like GoLand to run/debug directly (via Run/Debug buttons), or run `go build` / `go run` from command line, you must set the following two CGO environment variables in your run configuration or shell:
>
> ```bash

View File

@@ -2488,7 +2488,7 @@ func (s *DatasetService) CreateDataset(req *CreateDatasetRequest, tenantID strin
kb.Language = language
}
if err := s.kbDAO.Create(kb); err != nil {
if err = s.kbDAO.Create(kb); err != nil {
return nil, common.CodeServerError, errors.New("Failed to save dataset")
}