feat: add agent management functionality

- Introduced a new package for managing custom agents, including CRUD operations for agent creation, retrieval, updating, and deletion.
- Implemented API endpoints for listing agents and retrieving agent placeholders.
- Added data structures for agent configuration and requests, enhancing the overall agent management capabilities.
- Enhanced the client with methods to interact with the new agent management features, improving user experience in managing agents.

These changes significantly expand the application's functionality for handling custom agents, providing users with a comprehensive toolset for agent management.
This commit is contained in:
wizardchen
2026-03-09 14:56:01 +08:00
committed by lyingbug
parent 125d3e5e4a
commit daa9ef500c
27 changed files with 5134 additions and 8 deletions
+206
View File
@@ -0,0 +1,206 @@
// Package client provides the implementation for interacting with the WeKnora API
// The Agent management interfaces are used to manage custom agents (CRUD operations)
package client
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// Agent represents an agent entity
type Agent struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Avatar string `json:"avatar"`
IsBuiltin bool `json:"is_builtin"`
TenantID uint64 `json:"tenant_id"`
CreatedBy string `json:"created_by"`
Config *AgentConfig `json:"config"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// AgentConfig represents the configuration for an agent
type AgentConfig struct {
AgentMode string `json:"agent_mode"` // "quick-answer" or "smart-reasoning"
SystemPrompt string `json:"system_prompt,omitempty"`
ContextTemplate string `json:"context_template,omitempty"`
ModelID string `json:"model_id,omitempty"`
RerankModelID string `json:"rerank_model_id,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
MaxIterations int `json:"max_iterations,omitempty"`
AllowedTools []string `json:"allowed_tools,omitempty"`
ReflectionEnabled bool `json:"reflection_enabled,omitempty"`
MCPSelectionMode string `json:"mcp_selection_mode,omitempty"` // "all", "selected", "none"
MCPServices []string `json:"mcp_services,omitempty"`
KBSelectionMode string `json:"kb_selection_mode,omitempty"` // "all", "selected", "none"
KnowledgeBases []string `json:"knowledge_bases,omitempty"`
SupportedFileTypes []string `json:"supported_file_types,omitempty"`
FAQPriorityEnabled bool `json:"faq_priority_enabled,omitempty"`
FAQDirectAnswerThreshold float64 `json:"faq_direct_answer_threshold,omitempty"`
FAQScoreBoost float64 `json:"faq_score_boost,omitempty"`
WebSearchEnabled bool `json:"web_search_enabled,omitempty"`
WebSearchMaxResults int `json:"web_search_max_results,omitempty"`
MultiTurnEnabled bool `json:"multi_turn_enabled,omitempty"`
HistoryTurns int `json:"history_turns,omitempty"`
EmbeddingTopK int `json:"embedding_top_k,omitempty"`
KeywordThreshold float64 `json:"keyword_threshold,omitempty"`
VectorThreshold float64 `json:"vector_threshold,omitempty"`
RerankTopK int `json:"rerank_top_k,omitempty"`
RerankThreshold float64 `json:"rerank_threshold,omitempty"`
EnableQueryExpansion bool `json:"enable_query_expansion,omitempty"`
EnableRewrite bool `json:"enable_rewrite,omitempty"`
RewritePromptSystem string `json:"rewrite_prompt_system,omitempty"`
RewritePromptUser string `json:"rewrite_prompt_user,omitempty"`
FallbackStrategy string `json:"fallback_strategy,omitempty"` // "fixed" or "model"
FallbackResponse string `json:"fallback_response,omitempty"`
FallbackPrompt string `json:"fallback_prompt,omitempty"`
}
// CreateAgentRequest represents the request to create an agent
type CreateAgentRequest struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Avatar string `json:"avatar,omitempty"`
Config *AgentConfig `json:"config,omitempty"`
}
// UpdateAgentRequest represents the request to update an agent
type UpdateAgentRequest struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Avatar string `json:"avatar,omitempty"`
Config *AgentConfig `json:"config,omitempty"`
}
// AgentResponse represents the API response containing a single agent
type AgentResponse struct {
Success bool `json:"success"`
Data Agent `json:"data"`
}
// AgentListResponse represents the API response containing a list of agents
type AgentListResponse struct {
Success bool `json:"success"`
Data []Agent `json:"data"`
}
// AgentPlaceholdersResponse represents the API response for placeholder definitions
type AgentPlaceholdersResponse struct {
Success bool `json:"success"`
Data map[string]json.RawMessage `json:"data"`
}
// CreateAgent creates a new custom agent
func (c *Client) CreateAgent(ctx context.Context, request *CreateAgentRequest) (*Agent, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/agents", request, nil)
if err != nil {
return nil, err
}
var response AgentResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// ListAgents retrieves all agents for the current tenant
func (c *Client) ListAgents(ctx context.Context) ([]Agent, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/agents", nil, nil)
if err != nil {
return nil, err
}
var response AgentListResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return response.Data, nil
}
// GetAgent retrieves an agent by its ID
func (c *Client) GetAgent(ctx context.Context, agentID string) (*Agent, error) {
path := fmt.Sprintf("/api/v1/agents/%s", agentID)
resp, err := c.doRequest(ctx, http.MethodGet, path, nil, nil)
if err != nil {
return nil, err
}
var response AgentResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// UpdateAgent updates an existing agent
func (c *Client) UpdateAgent(ctx context.Context, agentID string, request *UpdateAgentRequest) (*Agent, error) {
path := fmt.Sprintf("/api/v1/agents/%s", agentID)
resp, err := c.doRequest(ctx, http.MethodPut, path, request, nil)
if err != nil {
return nil, err
}
var response AgentResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// DeleteAgent deletes a custom agent by its ID
func (c *Client) DeleteAgent(ctx context.Context, agentID string) error {
path := fmt.Sprintf("/api/v1/agents/%s", agentID)
resp, err := c.doRequest(ctx, http.MethodDelete, path, nil, nil)
if err != nil {
return err
}
var response struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
return parseResponse(resp, &response)
}
// CopyAgent creates a copy of an existing agent
func (c *Client) CopyAgent(ctx context.Context, agentID string) (*Agent, error) {
path := fmt.Sprintf("/api/v1/agents/%s/copy", agentID)
resp, err := c.doRequest(ctx, http.MethodPost, path, nil, nil)
if err != nil {
return nil, err
}
var response AgentResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// GetAgentPlaceholders retrieves all available prompt placeholder definitions
func (c *Client) GetAgentPlaceholders(ctx context.Context) (map[string]json.RawMessage, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/agents/placeholders", nil, nil)
if err != nil {
return nil, err
}
var response AgentPlaceholdersResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return response.Data, nil
}
+33
View File
@@ -154,6 +154,39 @@ func (c *Client) DeleteChunk(ctx context.Context, knowledgeID string, chunkID st
return parseResponse(resp, &response)
}
// GetChunkByIDOnly retrieves a chunk by its ID without requiring knowledge ID
func (c *Client) GetChunkByIDOnly(ctx context.Context, chunkID string) (*Chunk, error) {
path := fmt.Sprintf("/api/v1/chunks/get-by-id/%s", chunkID)
resp, err := c.doRequest(ctx, http.MethodGet, path, nil, nil)
if err != nil {
return nil, err
}
var response ChunkResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// DeleteGeneratedQuestion deletes a generated question from a chunk
func (c *Client) DeleteGeneratedQuestion(ctx context.Context, chunkID string, questionID string) error {
path := fmt.Sprintf("/api/v1/chunks/%s/delete-question", chunkID)
req := map[string]string{"question_id": questionID}
resp, err := c.doRequest(ctx, http.MethodDelete, path, req, nil)
if err != nil {
return err
}
var response struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
return parseResponse(resp, &response)
}
// DeleteChunksByKnowledgeID deletes all chunks under a knowledge document
// Batch deletes all chunks under the specified knowledge document
// Parameters:
+255
View File
@@ -0,0 +1,255 @@
package client
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// InitializationConfig represents the initialization configuration for a knowledge base
type InitializationConfig struct {
ChatModelID string `json:"chat_model_id,omitempty"`
EmbeddingModelID string `json:"embedding_model_id,omitempty"`
RerankModelID string `json:"rerank_model_id,omitempty"`
MultimodalID string `json:"multimodal_id,omitempty"`
}
// OllamaModelInfo represents info about an Ollama model
type OllamaModelInfo struct {
Name string `json:"name"`
Size int64 `json:"size"`
ModifiedAt string `json:"modified_at"`
}
// DownloadTask represents an Ollama model download task
type DownloadTask struct {
ID string `json:"id"`
ModelName string `json:"modelName"`
Status string `json:"status"`
Progress float64 `json:"progress"`
Message string `json:"message"`
StartTime time.Time `json:"startTime"`
EndTime *time.Time `json:"endTime,omitempty"`
}
// ModelCheckResult represents the result of checking a remote model
type ModelCheckResult struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
// GetInitializationConfig gets the current initialization config for a knowledge base
func (c *Client) GetInitializationConfig(ctx context.Context, kbID string) (*InitializationConfig, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/initialization/config/%s", kbID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *InitializationConfig `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// InitializeByKB initializes a knowledge base with model configuration
func (c *Client) InitializeByKB(ctx context.Context, kbID string, config *InitializationConfig) error {
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/initialization/initialize/%s", kbID), config, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// UpdateKBConfig updates the model configuration for a knowledge base
func (c *Client) UpdateKBConfig(ctx context.Context, kbID string, config *InitializationConfig) error {
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/initialization/config/%s", kbID), config, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// CheckOllamaStatus checks if Ollama is running and accessible
func (c *Client) CheckOllamaStatus(ctx context.Context) (bool, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/initialization/ollama/status", nil, nil)
if err != nil {
return false, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Available bool `json:"available"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return false, err
}
return result.Data.Available, nil
}
// ListOllamaModels lists all locally available Ollama models
func (c *Client) ListOllamaModels(ctx context.Context) ([]OllamaModelInfo, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/initialization/ollama/models", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []OllamaModelInfo `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// CheckOllamaModels checks if specific Ollama models are available
func (c *Client) CheckOllamaModels(ctx context.Context, models []string) (map[string]bool, error) {
req := map[string][]string{"models": models}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/ollama/models/check", req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data map[string]bool `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// DownloadOllamaModel starts downloading an Ollama model
func (c *Client) DownloadOllamaModel(ctx context.Context, modelName string) (*DownloadTask, error) {
req := map[string]string{"model": modelName}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/ollama/models/download", req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *DownloadTask `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// GetOllamaDownloadProgress gets the download progress of an Ollama model
func (c *Client) GetOllamaDownloadProgress(ctx context.Context, taskID string) (*DownloadTask, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/initialization/ollama/download/progress/%s", taskID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *DownloadTask `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListOllamaDownloadTasks lists all Ollama download tasks
func (c *Client) ListOllamaDownloadTasks(ctx context.Context) ([]*DownloadTask, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/initialization/ollama/download/tasks", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []*DownloadTask `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// CheckRemoteModel checks if a remote model API is accessible
func (c *Client) CheckRemoteModel(ctx context.Context, params map[string]string) (*ModelCheckResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/remote/check", params, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *ModelCheckResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// TestEmbeddingModel tests an embedding model
func (c *Client) TestEmbeddingModel(ctx context.Context, params map[string]string) (*ModelCheckResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/embedding/test", params, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *ModelCheckResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// CheckRerankModel checks if a rerank model is accessible
func (c *Client) CheckRerankModel(ctx context.Context, params map[string]string) (*ModelCheckResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/rerank/check", params, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *ModelCheckResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// TestMultimodalFunction tests multimodal model functionality
func (c *Client) TestMultimodalFunction(ctx context.Context, params map[string]string) (*ModelCheckResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/multimodal/test", params, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *ModelCheckResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ExtractTextRelations extracts text relations for knowledge graph
func (c *Client) ExtractTextRelations(ctx context.Context, params any) (json.RawMessage, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/initialization/extract/text-relation", params, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data json.RawMessage `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
+174
View File
@@ -432,3 +432,177 @@ func (c *Client) UpdateImageInfo(ctx context.Context,
return parseResponse(resp, &response)
}
// CreateManualKnowledgeRequest contains the parameters for creating a manual Markdown knowledge entry.
type CreateManualKnowledgeRequest struct {
Title string `json:"title"`
Content string `json:"content"`
TagID string `json:"tag_id,omitempty"`
}
// UpdateManualKnowledgeRequest contains the parameters for updating a manual Markdown knowledge entry.
type UpdateManualKnowledgeRequest struct {
Title string `json:"title,omitempty"`
Content string `json:"content,omitempty"`
}
// BatchUpdateKnowledgeTagsRequest contains the mapping of knowledge IDs to tag IDs.
type BatchUpdateKnowledgeTagsRequest struct {
Updates map[string]*string `json:"updates"` // knowledge_id -> tag_id (nil to clear)
}
// CreateManualKnowledge creates a knowledge entry from manual Markdown content.
func (c *Client) CreateManualKnowledge(ctx context.Context, knowledgeBaseID string, request *CreateManualKnowledgeRequest) (*Knowledge, error) {
path := fmt.Sprintf("/api/v1/knowledge-bases/%s/knowledge/manual", knowledgeBaseID)
resp, err := c.doRequest(ctx, http.MethodPost, path, request, nil)
if err != nil {
return nil, err
}
var response KnowledgeResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// UpdateManualKnowledge updates a manual Markdown knowledge entry.
func (c *Client) UpdateManualKnowledge(ctx context.Context, knowledgeID string, request *UpdateManualKnowledgeRequest) (*Knowledge, error) {
path := fmt.Sprintf("/api/v1/knowledge/manual/%s", knowledgeID)
resp, err := c.doRequest(ctx, http.MethodPut, path, request, nil)
if err != nil {
return nil, err
}
var response KnowledgeResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// FilterKnowledgeResponse represents the response from filter knowledge API
type FilterKnowledgeResponse struct {
Success bool `json:"success"`
Data []Knowledge `json:"data"`
HasMore bool `json:"has_more"`
}
// FilterKnowledge searches/filters knowledge entries across knowledge bases
func (c *Client) FilterKnowledge(ctx context.Context, keyword string, offset, limit int, fileTypes []string, agentID string) ([]Knowledge, bool, error) {
queryParams := url.Values{}
if keyword != "" {
queryParams.Set("keyword", keyword)
}
queryParams.Set("offset", strconv.Itoa(offset))
queryParams.Set("limit", strconv.Itoa(limit))
if len(fileTypes) > 0 {
for _, ft := range fileTypes {
queryParams.Add("file_types", ft)
}
}
if agentID != "" {
queryParams.Set("agent_id", agentID)
}
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/knowledge/search", nil, queryParams)
if err != nil {
return nil, false, err
}
var response FilterKnowledgeResponse
if err := parseResponse(resp, &response); err != nil {
return nil, false, err
}
return response.Data, response.HasMore, nil
}
// MoveKnowledgeRequest contains the parameters for moving knowledge between KBs
type MoveKnowledgeRequest struct {
KnowledgeIDs []string `json:"knowledge_ids"`
SourceKBID string `json:"source_kb_id"`
TargetKBID string `json:"target_kb_id"`
Mode string `json:"mode"` // "reuse_vectors" or "reparse"
}
// MoveKnowledgeResponse represents the response from move knowledge API
type MoveKnowledgeResponse struct {
TaskID string `json:"task_id"`
SourceKBID string `json:"source_kb_id"`
TargetKBID string `json:"target_kb_id"`
KnowledgeCount int `json:"knowledge_count"`
Message string `json:"message"`
}
// MoveKnowledge moves knowledge items from one knowledge base to another (async task)
func (c *Client) MoveKnowledge(ctx context.Context, req *MoveKnowledgeRequest) (*MoveKnowledgeResponse, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/knowledge/move", req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MoveKnowledgeResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// KnowledgeMoveProgress represents the progress of a knowledge move task
type KnowledgeMoveProgress struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
Progress int `json:"progress"`
Total int `json:"total"`
Processed int `json:"processed"`
Message string `json:"message"`
Error string `json:"error,omitempty"`
}
// GetKnowledgeMoveProgress gets the progress of a knowledge move task
func (c *Client) GetKnowledgeMoveProgress(ctx context.Context, taskID string) (*KnowledgeMoveProgress, error) {
path := fmt.Sprintf("/api/v1/knowledge/move/progress/%s", taskID)
resp, err := c.doRequest(ctx, http.MethodGet, path, nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *KnowledgeMoveProgress `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// PreviewKnowledgeFile returns the file content for inline preview.
// The caller is responsible for reading and closing the response body.
func (c *Client) PreviewKnowledgeFile(ctx context.Context, knowledgeID string) (*http.Response, error) {
path := fmt.Sprintf("/api/v1/knowledge/%s/preview", knowledgeID)
return c.doRequest(ctx, http.MethodGet, path, nil, nil)
}
// BatchUpdateKnowledgeTags batch updates knowledge tags.
// The updates map contains knowledge_id -> tag_id mappings. Set tag_id to nil to clear the tag.
func (c *Client) BatchUpdateKnowledgeTags(ctx context.Context, updates map[string]*string) error {
request := &BatchUpdateKnowledgeTagsRequest{Updates: updates}
resp, err := c.doRequest(ctx, http.MethodPut, "/api/v1/knowledge/tags", request, nil)
if err != nil {
return err
}
var batchResponse struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
return parseResponse(resp, &batchResponse)
}
+40
View File
@@ -311,6 +311,46 @@ func (c *Client) HybridSearch(ctx context.Context, knowledgeBaseID string, param
return response.Data, nil
}
// TogglePinKnowledgeBase toggles the pin status of a knowledge base
func (c *Client) TogglePinKnowledgeBase(ctx context.Context, knowledgeBaseID string) (*KnowledgeBase, error) {
path := fmt.Sprintf("/api/v1/knowledge-bases/%s/pin", knowledgeBaseID)
resp, err := c.doRequest(ctx, http.MethodPost, path, nil, nil)
if err != nil {
return nil, err
}
var response KnowledgeBaseResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return &response.Data, nil
}
// MoveTarget represents a knowledge base that can receive moved knowledge
type MoveTarget struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
}
// ListMoveTargets lists knowledge bases eligible as move targets for the given source KB
func (c *Client) ListMoveTargets(ctx context.Context, knowledgeBaseID string) ([]KnowledgeBase, error) {
path := fmt.Sprintf("/api/v1/knowledge-bases/%s/move-targets", knowledgeBaseID)
resp, err := c.doRequest(ctx, http.MethodGet, path, nil, nil)
if err != nil {
return nil, err
}
var response KnowledgeBaseListResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return response.Data, nil
}
// CopyKnowledgeBase copies a knowledge base asynchronously and returns task info
func (c *Client) CopyKnowledgeBase(ctx context.Context, request *CopyKnowledgeBaseRequest) (*CopyKnowledgeBaseResponse, error) {
path := "/api/v1/knowledge-bases/copy"
+207
View File
@@ -0,0 +1,207 @@
package client
import (
"context"
"encoding/json"
"fmt"
"net/http"
)
// MCPTransportType represents the transport type for MCP service
type MCPTransportType string
const (
MCPTransportSSE MCPTransportType = "sse"
MCPTransportHTTPStreamable MCPTransportType = "http-streamable"
MCPTransportStdio MCPTransportType = "stdio"
)
// MCPService represents an MCP service configuration
type MCPService struct {
ID string `json:"id"`
TenantID uint64 `json:"tenant_id"`
Name string `json:"name"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
TransportType MCPTransportType `json:"transport_type"`
URL *string `json:"url,omitempty"`
Headers map[string]string `json:"headers"`
AuthConfig *MCPAuthConfig `json:"auth_config"`
AdvancedConfig *MCPAdvancedConfig `json:"advanced_config"`
StdioConfig *MCPStdioConfig `json:"stdio_config,omitempty"`
EnvVars map[string]string `json:"env_vars,omitempty"`
IsBuiltin bool `json:"is_builtin"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// MCPAuthConfig represents authentication configuration for MCP service
type MCPAuthConfig struct {
APIKey string `json:"api_key,omitempty"`
Token string `json:"token,omitempty"`
CustomHeaders map[string]string `json:"custom_headers,omitempty"`
}
// MCPAdvancedConfig represents advanced configuration for MCP service
type MCPAdvancedConfig struct {
Timeout int `json:"timeout"`
RetryCount int `json:"retry_count"`
RetryDelay int `json:"retry_delay"`
}
// MCPStdioConfig represents stdio transport configuration
type MCPStdioConfig struct {
Command string `json:"command"`
Args []string `json:"args"`
}
// MCPTool represents a tool exposed by an MCP service
type MCPTool struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"inputSchema"`
}
// MCPResource represents a resource exposed by an MCP service
type MCPResource struct {
URI string `json:"uri"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
MimeType string `json:"mimeType,omitempty"`
}
// MCPTestResult represents the result of testing an MCP service connection
type MCPTestResult struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
Tools []*MCPTool `json:"tools,omitempty"`
Resources []*MCPResource `json:"resources,omitempty"`
}
// CreateMCPService creates a new MCP service
func (c *Client) CreateMCPService(ctx context.Context, service *MCPService) (*MCPService, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/mcp-services", service, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MCPService `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListMCPServices lists all MCP services for the current tenant
func (c *Client) ListMCPServices(ctx context.Context) ([]*MCPService, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/mcp-services", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []*MCPService `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// GetMCPService gets an MCP service by ID
func (c *Client) GetMCPService(ctx context.Context, serviceID string) (*MCPService, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/mcp-services/%s", serviceID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MCPService `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// UpdateMCPService updates an MCP service
func (c *Client) UpdateMCPService(ctx context.Context, serviceID string, updates map[string]interface{}) (*MCPService, error) {
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/mcp-services/%s", serviceID), updates, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MCPService `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// DeleteMCPService deletes an MCP service
func (c *Client) DeleteMCPService(ctx context.Context, serviceID string) error {
resp, err := c.doRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/mcp-services/%s", serviceID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// TestMCPService tests an MCP service connection
func (c *Client) TestMCPService(ctx context.Context, serviceID string) (*MCPTestResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/mcp-services/%s/test", serviceID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MCPTestResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// GetMCPServiceTools gets the tools provided by an MCP service
func (c *Client) GetMCPServiceTools(ctx context.Context, serviceID string) ([]*MCPTool, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/mcp-services/%s/tools", serviceID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []*MCPTool `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// GetMCPServiceResources gets the resources provided by an MCP service
func (c *Client) GetMCPServiceResources(ctx context.Context, serviceID string) ([]*MCPResource, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/mcp-services/%s/resources", serviceID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []*MCPResource `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
+70
View File
@@ -102,6 +102,76 @@ func (c *Client) GetMessagesBefore(
return c.LoadMessages(ctx, sessionID, limit, &beforeTime)
}
// SearchMessagesRequest defines the request structure for searching messages
type SearchMessagesRequest struct {
Query string `json:"query"`
Mode string `json:"mode"`
Limit int `json:"limit"`
SessionIDs []string `json:"session_ids,omitempty"`
}
// MessageSearchGroupItem represents a grouped search result item
type MessageSearchGroupItem struct {
RequestID string `json:"request_id"`
SessionID string `json:"session_id"`
SessionTitle string `json:"session_title"`
QueryContent string `json:"query_content"`
AnswerContent string `json:"answer_content"`
Score float64 `json:"score"`
MatchType string `json:"match_type"`
CreatedAt time.Time `json:"created_at"`
}
// MessageSearchResult represents the result of a message search
type MessageSearchResult struct {
Items []*MessageSearchGroupItem `json:"items"`
Total int `json:"total"`
}
// ChatHistoryKBStats represents statistics about the chat history knowledge base
type ChatHistoryKBStats struct {
Enabled bool `json:"enabled"`
EmbeddingModelID string `json:"embedding_model_id,omitempty"`
KnowledgeBaseID string `json:"knowledge_base_id,omitempty"`
KnowledgeBaseName string `json:"knowledge_base_name,omitempty"`
IndexedMessageCount int64 `json:"indexed_message_count"`
HasIndexedMessages bool `json:"has_indexed_messages"`
}
// SearchMessages searches chat history messages
func (c *Client) SearchMessages(ctx context.Context, req *SearchMessagesRequest) (*MessageSearchResult, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/messages/search", req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *MessageSearchResult `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// GetChatHistoryKBStats gets chat history knowledge base statistics
func (c *Client) GetChatHistoryKBStats(ctx context.Context) (*ChatHistoryKBStats, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/messages/chat-history-stats", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *ChatHistoryKBStats `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// DeleteMessage deletes a message
func (c *Client) DeleteMessage(ctx context.Context, sessionID string, messageID string) error {
path := fmt.Sprintf("/api/v1/messages/%s/%s", sessionID, messageID)
+38
View File
@@ -7,6 +7,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
)
// ModelType model type
@@ -153,3 +154,40 @@ func (c *Client) DeleteModel(ctx context.Context, modelID string) error {
return parseResponse(resp, &response)
}
// ModelProvider represents a model provider with its supported types and default URLs
type ModelProvider struct {
Value string `json:"value"`
Label string `json:"label"`
Description string `json:"description"`
DefaultURLs map[string]string `json:"defaultUrls"`
ModelTypes []string `json:"modelTypes"`
}
// ModelProviderListResponse represents the API response for listing model providers
type ModelProviderListResponse struct {
Success bool `json:"success"`
Data []ModelProvider `json:"data"`
}
// ListModelProviders retrieves the list of supported model providers.
// modelType is optional and can be used to filter by type: "chat", "embedding", "rerank", "vllm".
func (c *Client) ListModelProviders(ctx context.Context, modelType string) ([]ModelProvider, error) {
var queryParams url.Values
if modelType != "" {
queryParams = url.Values{}
queryParams.Add("model_type", modelType)
}
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/models/providers", nil, queryParams)
if err != nil {
return nil, err
}
var response ModelProviderListResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return response.Data, nil
}
+630
View File
@@ -0,0 +1,630 @@
package client
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
)
// Organization represents a collaboration organization
type Organization struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Avatar string `json:"avatar,omitempty"`
OwnerID string `json:"owner_id"`
InviteCode string `json:"invite_code,omitempty"`
InviteCodeExpiresAt *time.Time `json:"invite_code_expires_at,omitempty"`
InviteCodeValidityDays int `json:"invite_code_validity_days"`
RequireApproval bool `json:"require_approval"`
Searchable bool `json:"searchable"`
MemberLimit int `json:"member_limit"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// OrganizationResponse represents an organization in API responses (with counts)
type OrganizationResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Avatar string `json:"avatar,omitempty"`
OwnerID string `json:"owner_id"`
InviteCode string `json:"invite_code,omitempty"`
InviteCodeExpiresAt *time.Time `json:"invite_code_expires_at,omitempty"`
InviteCodeValidityDays int `json:"invite_code_validity_days"`
RequireApproval bool `json:"require_approval"`
Searchable bool `json:"searchable"`
MemberLimit int `json:"member_limit"`
MemberCount int `json:"member_count"`
ShareCount int `json:"share_count"`
AgentShareCount int `json:"agent_share_count"`
PendingJoinRequestCount int `json:"pending_join_request_count"`
IsOwner bool `json:"is_owner"`
MyRole string `json:"my_role,omitempty"`
HasPendingUpgrade bool `json:"has_pending_upgrade"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// CreateOrganizationRequest represents a request to create an organization
type CreateOrganizationRequest struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Avatar string `json:"avatar,omitempty"`
InviteCodeValidityDays *int `json:"invite_code_validity_days,omitempty"`
MemberLimit *int `json:"member_limit,omitempty"`
}
// UpdateOrganizationRequest represents a request to update an organization
type UpdateOrganizationRequest struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Avatar *string `json:"avatar,omitempty"`
RequireApproval *bool `json:"require_approval,omitempty"`
Searchable *bool `json:"searchable,omitempty"`
InviteCodeValidityDays *int `json:"invite_code_validity_days,omitempty"`
MemberLimit *int `json:"member_limit,omitempty"`
}
// OrganizationMemberResponse represents a member in API responses
type OrganizationMemberResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
Avatar string `json:"avatar"`
Role string `json:"role"`
TenantID uint64 `json:"tenant_id"`
JoinedAt time.Time `json:"joined_at"`
}
// KnowledgeBaseShareResponse represents a KB share record in API responses
type KnowledgeBaseShareResponse struct {
ID string `json:"id"`
KnowledgeBaseID string `json:"knowledge_base_id"`
KnowledgeBaseName string `json:"knowledge_base_name"`
OrganizationID string `json:"organization_id"`
OrganizationName string `json:"organization_name"`
SharedByUserID string `json:"shared_by_user_id"`
SharedByUsername string `json:"shared_by_username"`
SourceTenantID uint64 `json:"source_tenant_id"`
Permission string `json:"permission"`
MyRoleInOrg string `json:"my_role_in_org"`
MyPermission string `json:"my_permission"`
CreatedAt time.Time `json:"created_at"`
}
// AgentShareResponse represents an agent share record in API responses
type AgentShareResponse struct {
ID string `json:"id"`
AgentID string `json:"agent_id"`
AgentName string `json:"agent_name"`
OrganizationID string `json:"organization_id"`
OrganizationName string `json:"organization_name"`
SharedByUserID string `json:"shared_by_user_id"`
SharedByUsername string `json:"shared_by_username"`
SourceTenantID uint64 `json:"source_tenant_id"`
Permission string `json:"permission"`
CreatedAt time.Time `json:"created_at"`
}
// JoinRequestResponse represents a join request in API responses
type JoinRequestResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
Message string `json:"message"`
RequestType string `json:"request_type"`
PrevRole string `json:"prev_role"`
RequestedRole string `json:"requested_role"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
}
// SharedKnowledgeBaseInfo represents a shared knowledge base
type SharedKnowledgeBaseInfo struct {
ShareID string `json:"share_id"`
OrganizationID string `json:"organization_id"`
OrgName string `json:"org_name"`
Permission string `json:"permission"`
SourceTenantID uint64 `json:"source_tenant_id"`
SharedAt time.Time `json:"shared_at"`
}
// SharedAgentInfo represents a shared agent
type SharedAgentInfo struct {
ShareID string `json:"share_id"`
OrganizationID string `json:"organization_id"`
OrgName string `json:"org_name"`
Permission string `json:"permission"`
SourceTenantID uint64 `json:"source_tenant_id"`
SharedAt time.Time `json:"shared_at"`
}
// --- Organization CRUD ---
// CreateOrganization creates a new organization
func (c *Client) CreateOrganization(ctx context.Context, req *CreateOrganizationRequest) (*OrganizationResponse, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/organizations", req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *OrganizationResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListMyOrganizations lists organizations the current user belongs to
func (c *Client) ListMyOrganizations(ctx context.Context) ([]OrganizationResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/organizations", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Organizations []OrganizationResponse `json:"organizations"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Organizations, nil
}
// GetOrganization gets an organization by ID
func (c *Client) GetOrganization(ctx context.Context, orgID string) (*OrganizationResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s", orgID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *OrganizationResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// UpdateOrganization updates an organization
func (c *Client) UpdateOrganization(ctx context.Context, orgID string, req *UpdateOrganizationRequest) (*OrganizationResponse, error) {
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/organizations/%s", orgID), req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *OrganizationResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// DeleteOrganization deletes an organization
func (c *Client) DeleteOrganization(ctx context.Context, orgID string) error {
resp, err := c.doRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/organizations/%s", orgID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// --- Organization membership ---
// JoinOrganizationByInviteCode joins an organization using an invite code
func (c *Client) JoinOrganizationByInviteCode(ctx context.Context, inviteCode string) error {
req := map[string]string{"invite_code": inviteCode}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/organizations/join", req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// SubmitJoinRequest submits a join request for organizations that require approval
func (c *Client) SubmitJoinRequest(ctx context.Context, inviteCode, message, role string) error {
req := map[string]string{
"invite_code": inviteCode,
"message": message,
"role": role,
}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/organizations/join-request", req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// SearchOrganizations searches for discoverable organizations
func (c *Client) SearchOrganizations(ctx context.Context, keyword string, page, pageSize int) ([]OrganizationResponse, error) {
q := url.Values{}
if keyword != "" {
q.Set("keyword", keyword)
}
if page > 0 {
q.Set("page", fmt.Sprintf("%d", page))
}
if pageSize > 0 {
q.Set("page_size", fmt.Sprintf("%d", pageSize))
}
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/organizations/search", nil, q)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Organizations []OrganizationResponse `json:"organizations"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Organizations, nil
}
// JoinByOrganizationID joins a searchable organization by its ID
func (c *Client) JoinByOrganizationID(ctx context.Context, orgID, message, role string) error {
req := map[string]string{
"organization_id": orgID,
"message": message,
"role": role,
}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/organizations/join-by-id", req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// PreviewOrganizationByInviteCode previews an organization before joining
func (c *Client) PreviewOrganizationByInviteCode(ctx context.Context, code string) (*OrganizationResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/preview/%s", code), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *OrganizationResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// LeaveOrganization leaves an organization
func (c *Client) LeaveOrganization(ctx context.Context, orgID string) error {
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/organizations/%s/leave", orgID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// RequestRoleUpgrade requests a role upgrade in an organization
func (c *Client) RequestRoleUpgrade(ctx context.Context, orgID, requestedRole, message string) error {
req := map[string]string{
"requested_role": requestedRole,
"message": message,
}
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/organizations/%s/request-upgrade", orgID), req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// GenerateInviteCode generates a new invite code for an organization
func (c *Client) GenerateInviteCode(ctx context.Context, orgID string) (string, error) {
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/organizations/%s/invite-code", orgID), nil, nil)
if err != nil {
return "", err
}
var result struct {
Success bool `json:"success"`
Data struct {
InviteCode string `json:"invite_code"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return "", err
}
return result.Data.InviteCode, nil
}
// SearchUsersForInvite searches users to invite into an organization (admin only)
func (c *Client) SearchUsersForInvite(ctx context.Context, orgID, keyword string) ([]UserInfo, error) {
q := url.Values{}
if keyword != "" {
q.Set("keyword", keyword)
}
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s/search-users", orgID), nil, q)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []UserInfo `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// InviteMember directly invites a user to an organization (admin only)
func (c *Client) InviteMember(ctx context.Context, orgID, userID, role string) error {
req := map[string]string{
"user_id": userID,
"role": role,
}
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/organizations/%s/invite", orgID), req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// ListMembers lists members of an organization
func (c *Client) ListOrgMembers(ctx context.Context, orgID string) ([]OrganizationMemberResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s/members", orgID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Members []OrganizationMemberResponse `json:"members"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Members, nil
}
// UpdateMemberRole updates a member's role in an organization
func (c *Client) UpdateMemberRole(ctx context.Context, orgID, userID, role string) error {
req := map[string]string{"role": role}
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/organizations/%s/members/%s", orgID, userID), req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// RemoveMember removes a member from an organization
func (c *Client) RemoveMember(ctx context.Context, orgID, userID string) error {
resp, err := c.doRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/organizations/%s/members/%s", orgID, userID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// --- Join request management ---
// ListJoinRequests lists pending join requests (admin only)
func (c *Client) ListJoinRequests(ctx context.Context, orgID string) ([]JoinRequestResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s/join-requests", orgID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Requests []JoinRequestResponse `json:"requests"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Requests, nil
}
// ReviewJoinRequest reviews a join request (approve/reject)
func (c *Client) ReviewJoinRequest(ctx context.Context, orgID, requestID string, approved bool, message, role string) error {
req := map[string]any{
"approved": approved,
"message": message,
"role": role,
}
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/organizations/%s/join-requests/%s/review", orgID, requestID), req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// --- Knowledge base sharing ---
// ShareKnowledgeBase shares a knowledge base with an organization
func (c *Client) ShareKnowledgeBase(ctx context.Context, kbID, orgID, permission string) (*KnowledgeBaseShareResponse, error) {
req := map[string]string{
"organization_id": orgID,
"permission": permission,
}
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/knowledge-bases/%s/shares", kbID), req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *KnowledgeBaseShareResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListKBShares lists shares of a knowledge base
func (c *Client) ListKBShares(ctx context.Context, kbID string) ([]KnowledgeBaseShareResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/knowledge-bases/%s/shares", kbID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Shares []KnowledgeBaseShareResponse `json:"shares"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Shares, nil
}
// UpdateSharePermission updates a KB share's permission
func (c *Client) UpdateSharePermission(ctx context.Context, kbID, shareID, permission string) error {
req := map[string]string{"permission": permission}
resp, err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/knowledge-bases/%s/shares/%s", kbID, shareID), req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// RemoveKBShare removes a KB share
func (c *Client) RemoveKBShare(ctx context.Context, kbID, shareID string) error {
resp, err := c.doRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/knowledge-bases/%s/shares/%s", kbID, shareID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// --- Agent sharing ---
// ShareAgent shares an agent with an organization
func (c *Client) ShareAgent(ctx context.Context, agentID, orgID, permission string) (*AgentShareResponse, error) {
req := map[string]string{
"organization_id": orgID,
"permission": permission,
}
resp, err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/agents/%s/shares", agentID), req, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data *AgentShareResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListAgentShares lists shares of an agent
func (c *Client) ListAgentShares(ctx context.Context, agentID string) ([]AgentShareResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/agents/%s/shares", agentID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Shares []AgentShareResponse `json:"shares"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Shares, nil
}
// RemoveAgentShare removes an agent share
func (c *Client) RemoveAgentShare(ctx context.Context, agentID, shareID string) error {
resp, err := c.doRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/agents/%s/shares/%s", agentID, shareID), nil, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// --- Organization shared resources ---
// ListOrgShares lists knowledge bases shared to an organization
func (c *Client) ListOrgShares(ctx context.Context, orgID string) ([]KnowledgeBaseShareResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s/shares", orgID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Shares []KnowledgeBaseShareResponse `json:"shares"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Shares, nil
}
// ListOrgAgentShares lists agents shared to an organization
func (c *Client) ListOrgAgentShares(ctx context.Context, orgID string) ([]AgentShareResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/organizations/%s/agent-shares", orgID), nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data struct {
Shares []AgentShareResponse `json:"shares"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Shares, nil
}
// ListSharedKnowledgeBases lists all knowledge bases shared to the current user
func (c *Client) ListSharedKnowledgeBases(ctx context.Context) ([]SharedKnowledgeBaseInfo, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/shared-knowledge-bases", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []SharedKnowledgeBaseInfo `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListSharedAgents lists all agents shared to the current user
func (c *Client) ListSharedAgents(ctx context.Context) ([]SharedAgentInfo, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/shared-agents", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []SharedAgentInfo `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
+19
View File
@@ -147,6 +147,25 @@ func (c *Client) DeleteSession(ctx context.Context, sessionID string) error {
return parseResponse(resp, &response)
}
// BatchDeleteSessions deletes multiple sessions by their IDs.
func (c *Client) BatchDeleteSessions(ctx context.Context, sessionIDs []string) error {
request := struct {
IDs []string `json:"ids"`
}{IDs: sessionIDs}
resp, err := c.doRequest(ctx, http.MethodDelete, "/api/v1/sessions/batch", request, nil)
if err != nil {
return err
}
var response struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
return parseResponse(resp, &response)
}
// GenerateTitleRequest title generation request
type GenerateTitleRequest struct {
Messages []Message `json:"messages"`
+34
View File
@@ -0,0 +1,34 @@
package client
import (
"context"
"net/http"
)
// SkillInfo represents skill metadata
type SkillInfo struct {
Name string `json:"name"`
Description string `json:"description"`
}
// SkillListResponse represents the response from listing skills
type SkillListResponse struct {
Success bool `json:"success"`
Data []SkillInfo `json:"data"`
SkillsAvailable bool `json:"skills_available"`
}
// ListSkills lists all preloaded agent skills
func (c *Client) ListSkills(ctx context.Context) ([]SkillInfo, bool, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/skills", nil, nil)
if err != nil {
return nil, false, err
}
var response SkillListResponse
if err := parseResponse(resp, &response); err != nil {
return nil, false, err
}
return response.Data, response.SkillsAvailable, nil
}
+174
View File
@@ -0,0 +1,174 @@
package client
import (
"context"
"encoding/json"
"net/http"
)
// SystemInfo represents system version and configuration information
type SystemInfo struct {
Version string `json:"version"`
Edition string `json:"edition"`
CommitID string `json:"commit_id,omitempty"`
BuildTime string `json:"build_time,omitempty"`
GoVersion string `json:"go_version,omitempty"`
KeywordIndexEngine string `json:"keyword_index_engine,omitempty"`
VectorStoreEngine string `json:"vector_store_engine,omitempty"`
GraphDatabaseEngine string `json:"graph_database_engine,omitempty"`
MinioEnabled bool `json:"minio_enabled,omitempty"`
DBVersion string `json:"db_version,omitempty"`
}
// ParserEngine represents a document parser engine
type ParserEngine struct {
Name string `json:"name"`
Label string `json:"label"`
Description string `json:"description"`
Available bool `json:"available"`
}
// StorageEngineStatusItem describes one storage engine's availability
type StorageEngineStatusItem struct {
Name string `json:"name"`
Available bool `json:"available"`
Description string `json:"description"`
}
// StorageEngineStatusResponse is the response for storage engine status
type StorageEngineStatusResponse struct {
Engines []StorageEngineStatusItem `json:"engines"`
MinioEnvAvailable bool `json:"minio_env_available"`
}
// StorageCheckRequest is the body for storage engine connectivity check
type StorageCheckRequest struct {
Provider string `json:"provider"`
MinIO json.RawMessage `json:"minio,omitempty"`
COS json.RawMessage `json:"cos,omitempty"`
TOS json.RawMessage `json:"tos,omitempty"`
S3 json.RawMessage `json:"s3,omitempty"`
}
// StorageCheckResponse is the response for storage engine check
type StorageCheckResponse struct {
OK bool `json:"ok"`
Message string `json:"message"`
BucketCreated bool `json:"bucket_created,omitempty"`
}
// MinioBucketInfo represents MinIO bucket information
type MinioBucketInfo struct {
Name string `json:"name"`
Policy string `json:"policy"`
CreatedAt string `json:"created_at,omitempty"`
}
// GetSystemInfo gets system version and configuration information
func (c *Client) GetSystemInfo(ctx context.Context) (*SystemInfo, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/system/info", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data *SystemInfo `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListParserEngines lists available document parser engines
func (c *Client) ListParserEngines(ctx context.Context) ([]ParserEngine, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/system/parser-engines", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data []ParserEngine `json:"data"`
Connected bool `json:"connected"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// CheckParserEngines checks parser engine availability with given config overrides
func (c *Client) CheckParserEngines(ctx context.Context, config any) ([]ParserEngine, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/system/parser-engines/check", config, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data []ParserEngine `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ReconnectDocReader reconnects the document parser service to a new address
func (c *Client) ReconnectDocReader(ctx context.Context, addr string) error {
req := map[string]string{"addr": addr}
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/system/docreader/reconnect", req, nil)
if err != nil {
return err
}
return parseResponse(resp, nil)
}
// GetStorageEngineStatus gets the availability status of all storage engines
func (c *Client) GetStorageEngineStatus(ctx context.Context) (*StorageEngineStatusResponse, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/system/storage-engine-status", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data *StorageEngineStatusResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// CheckStorageEngine tests connectivity for a storage engine
func (c *Client) CheckStorageEngine(ctx context.Context, req *StorageCheckRequest) (*StorageCheckResponse, error) {
resp, err := c.doRequest(ctx, http.MethodPost, "/api/v1/system/storage-engine-check", req, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data *StorageCheckResponse `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// ListMinioBuckets lists all MinIO buckets with their access policies
func (c *Client) ListMinioBuckets(ctx context.Context) ([]MinioBucketInfo, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/system/minio/buckets", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Data struct {
Buckets []MinioBucketInfo `json:"buckets"`
} `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data.Buckets, nil
}
+90
View File
@@ -6,8 +6,11 @@ package client
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
@@ -138,3 +141,90 @@ func (c *Client) ListTenants(ctx context.Context) ([]Tenant, error) {
return response.Data.Items, nil
}
// ListAllTenants retrieves all tenants in the system (requires cross-tenant access)
func (c *Client) ListAllTenants(ctx context.Context) ([]Tenant, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/tenants/all", nil, nil)
if err != nil {
return nil, err
}
var response TenantListResponse
if err := parseResponse(resp, &response); err != nil {
return nil, err
}
return response.Data.Items, nil
}
// TenantSearchResponse represents the API response for searching tenants
type TenantSearchResponse struct {
Success bool `json:"success"`
Data struct {
Items []Tenant `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
} `json:"data"`
}
// SearchTenants searches tenants with pagination (requires cross-tenant access)
func (c *Client) SearchTenants(ctx context.Context, keyword string, tenantID uint64, page, pageSize int) ([]Tenant, int64, error) {
queryParams := url.Values{}
if keyword != "" {
queryParams.Set("keyword", keyword)
}
if tenantID > 0 {
queryParams.Set("tenant_id", strconv.FormatUint(tenantID, 10))
}
queryParams.Set("page", strconv.Itoa(page))
queryParams.Set("page_size", strconv.Itoa(pageSize))
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/tenants/search", nil, queryParams)
if err != nil {
return nil, 0, err
}
var response TenantSearchResponse
if err := parseResponse(resp, &response); err != nil {
return nil, 0, err
}
return response.Data.Items, response.Data.Total, nil
}
// GetTenantKV retrieves a tenant KV configuration by key
func (c *Client) GetTenantKV(ctx context.Context, key string) (json.RawMessage, error) {
path := fmt.Sprintf("/api/v1/tenants/kv/%s", key)
resp, err := c.doRequest(ctx, http.MethodGet, path, nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data json.RawMessage `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
// UpdateTenantKV updates a tenant KV configuration by key
func (c *Client) UpdateTenantKV(ctx context.Context, key string, value any) (json.RawMessage, error) {
path := fmt.Sprintf("/api/v1/tenants/kv/%s", key)
resp, err := c.doRequest(ctx, http.MethodPut, path, value, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data json.RawMessage `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
+32
View File
@@ -0,0 +1,32 @@
package client
import (
"context"
"encoding/json"
"net/http"
)
// WebSearchProvider represents a web search provider
type WebSearchProvider struct {
Name string `json:"name"`
Label string `json:"label"`
Description string `json:"description,omitempty"`
Enabled bool `json:"enabled"`
}
// GetWebSearchProviders returns the list of available web search providers
func (c *Client) GetWebSearchProviders(ctx context.Context) ([]json.RawMessage, error) {
resp, err := c.doRequest(ctx, http.MethodGet, "/api/v1/web-search/providers", nil, nil)
if err != nil {
return nil, err
}
var result struct {
Success bool `json:"success"`
Data []json.RawMessage `json:"data"`
}
if err := parseResponse(resp, &result); err != nil {
return nil, err
}
return result.Data, nil
}
+7
View File
@@ -59,6 +59,7 @@ WeKnora API 按功能分为以下几类:
| 分类 | 描述 | 文档链接 |
|------|------|----------|
| 认证管理 | 用户注册、登录、令牌管理 | [auth.md](./auth.md) |
| 租户管理 | 创建和管理租户账户 | [tenant.md](./tenant.md) |
| 知识库管理 | 创建、查询和管理知识库 | [knowledge-base.md](./knowledge-base.md) |
| 知识管理 | 上传、检索和管理知识内容 | [knowledge.md](./knowledge.md) |
@@ -72,3 +73,9 @@ WeKnora API 按功能分为以下几类:
| 聊天功能 | 基于知识库和 Agent 进行问答 | [chat.md](./chat.md) |
| 消息管理 | 获取和管理对话消息 | [message.md](./message.md) |
| 评估功能 | 评估模型性能 | [evaluation.md](./evaluation.md) |
| 初始化管理 | 知识库模型配置与 Ollama 管理 | [initialization.md](./initialization.md) |
| 系统管理 | 系统信息、解析引擎、存储引擎 | [system.md](./system.md) |
| MCP 服务 | MCP 工具服务管理 | [mcp-service.md](./mcp-service.md) |
| 组织管理 | 组织、成员、知识库/智能体共享 | [organization.md](./organization.md) |
| Skills | 预装智能体技能 | [skill.md](./skill.md) |
| 网络搜索 | 网络搜索服务商 | [web-search.md](./web-search.md) |
+129
View File
@@ -5,8 +5,11 @@
| 方法 | 路径 | 描述 |
| ------ | --------------------------- | ------------------------ |
| GET | `/chunks/:knowledge_id` | 获取知识的分块列表 |
| PUT | `/chunks/:knowledge_id/:id` | 更新分块 |
| DELETE | `/chunks/:knowledge_id/:id` | 删除分块 |
| DELETE | `/chunks/:knowledge_id` | 删除知识下的所有分块 |
| GET | `/chunks/get-by-id/:id` | 根据ID直接获取分块 |
| DELETE | `/chunks/:id/delete-question` | 删除分块的生成问题 |
## GET `/chunks/:knowledge_id?page=&page_size=` - 获取知识的分块列表
@@ -56,6 +59,63 @@ curl --location 'http://localhost:8080/api/v1/chunks/4c4e7c1a-09cf-485b-a7b5-24b
}
```
## PUT `/chunks/:knowledge_id/:id` - 更新分块
更新指定分块的内容和属性。
**请求参数**:
- `content`: 分块内容(可选)
- `chunk_index`: 分块索引(可选)
- `is_enabled`: 是否启用(可选)
- `start_at`: 起始位置(可选)
- `end_at`: 结束位置(可选)
- `image_info`: 图片信息(可选)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/chunks/4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5/df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"content": "更新后的分块内容",
"is_enabled": true
}'
```
**响应**:
```json
{
"data": {
"id": "df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7",
"tenant_id": 1,
"knowledge_id": "4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5",
"knowledge_base_id": "kb-00000001",
"tag_id": "",
"content": "更新后的分块内容",
"chunk_index": 0,
"is_enabled": true,
"status": 2,
"start_at": 0,
"end_at": 964,
"pre_chunk_id": "",
"next_chunk_id": "",
"chunk_type": "text",
"parent_chunk_id": "",
"relation_chunks": null,
"indirect_relation_chunks": null,
"metadata": null,
"content_hash": "",
"image_info": "",
"created_at": "2025-08-12T11:52:36.168632+08:00",
"updated_at": "2025-08-12T12:00:00.000000+08:00",
"deleted_at": null
},
"success": true
}
```
## DELETE `/chunks/:knowledge_id/:id` - 删除分块
**请求**:
@@ -93,3 +153,72 @@ curl --location --request DELETE 'http://localhost:8080/api/v1/chunks/4c4e7c1a-0
"success": true
}
```
## GET `/chunks/get-by-id/:id` - 根据ID直接获取分块
根据分块ID直接获取分块信息,无需提供知识ID。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/chunks/get-by-id/df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7",
"tenant_id": 1,
"knowledge_id": "4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5",
"knowledge_base_id": "kb-00000001",
"tag_id": "",
"content": "彗星xxxx",
"chunk_index": 0,
"is_enabled": true,
"status": 2,
"start_at": 0,
"end_at": 964,
"pre_chunk_id": "",
"next_chunk_id": "",
"chunk_type": "text",
"parent_chunk_id": "",
"relation_chunks": null,
"indirect_relation_chunks": null,
"metadata": null,
"content_hash": "",
"image_info": "",
"created_at": "2025-08-12T11:52:36.168632+08:00",
"updated_at": "2025-08-12T11:52:53.376871+08:00",
"deleted_at": null
},
"success": true
}
```
## DELETE `/chunks/:id/delete-question` - 删除分块的生成问题
删除指定分块关联的生成问题。
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/chunks/df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7/delete-question' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"question_id": "q-00000001"
}'
```
**响应**:
```json
{
"message": "Question deleted successfully",
"success": true
}
```
+181 -8
View File
@@ -7,11 +7,16 @@
| GET | `/knowledge-bases/:id/faq/entries` | 获取FAQ条目列表 |
| POST | `/knowledge-bases/:id/faq/entries` | 批量导入FAQ条目 |
| POST | `/knowledge-bases/:id/faq/entry` | 创建单个FAQ条目 |
| GET | `/knowledge-bases/:id/faq/entries/:entry_id`| 获取单个FAQ条目 |
| PUT | `/knowledge-bases/:id/faq/entries/:entry_id`| 更新单个FAQ条目 |
| PUT | `/knowledge-bases/:id/faq/entries/status` | 批量更新FAQ启用状态 |
| POST | `/knowledge-bases/:id/faq/entries/:entry_id/similar-questions` | 添加相似问题 |
| PUT | `/knowledge-bases/:id/faq/entries/fields` | 批量更新FAQ字段 |
| PUT | `/knowledge-bases/:id/faq/entries/tags` | 批量更新FAQ标签 |
| DELETE | `/knowledge-bases/:id/faq/entries` | 批量删除FAQ条目 |
| POST | `/knowledge-bases/:id/faq/search` | 混合搜索FAQ |
| GET | `/knowledge-bases/:id/faq/entries/export` | 导出FAQ条目(CSV) |
| GET | `/faq/import/progress/:task_id` | 获取FAQ导入进度 |
| PUT | `/knowledge-bases/:id/faq/import/last-result/display` | 更新导入结果显示状态 |
## GET `/knowledge-bases/:id/faq/entries` - 获取FAQ条目列表
@@ -209,20 +214,109 @@ curl --location --request PUT 'http://localhost:8080/api/v1/knowledge-bases/kb-0
}
```
## PUT `/knowledge-bases/:id/faq/entries/status` - 批量更新FAQ启用状态
## GET `/knowledge-bases/:id/faq/entries/:entry_id` - 获取单个FAQ条目
根据 seq_id 获取单个 FAQ 条目的详细信息。
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/entries/status' \
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/entries/1' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "faq-00000001",
"seq_id": 1,
"chunk_id": "chunk-00000001",
"knowledge_id": "knowledge-00000001",
"knowledge_base_id": "kb-00000001",
"tag_id": "tag-00000001",
"is_enabled": true,
"standard_question": "如何重置密码?",
"similar_questions": ["忘记密码怎么办", "密码找回"],
"negative_questions": [],
"answers": ["您可以通过点击登录页面的'忘记密码'链接来重置密码。"],
"index_mode": "hybrid",
"chunk_type": "faq",
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## POST `/knowledge-bases/:id/faq/entries/:entry_id/similar-questions` - 添加相似问题
为指定的 FAQ 条目追加相似问法。
**请求参数**:
- `similar_questions`: 要追加的相似问题数组(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/entries/1/similar-questions' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"updates": {
"faq-00000001": true,
"faq-00000002": false,
"faq-00000003": true
}
"similar_questions": ["怎样修改密码", "密码重置方法"]
}'
```
**响应**:
```json
{
"data": {
"id": "faq-00000001",
"seq_id": 1,
"standard_question": "如何重置密码?",
"similar_questions": ["忘记密码怎么办", "密码找回", "怎样修改密码", "密码重置方法"],
"answers": ["您可以通过点击登录页面的'忘记密码'链接来重置密码。"],
"is_enabled": true,
"chunk_type": "faq",
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T11:00:00+08:00"
},
"success": true
}
```
## PUT `/knowledge-bases/:id/faq/entries/fields` - 批量更新FAQ字段
支持按条目ID或按标签ID批量更新 FAQ 条目的多个字段(启用状态、推荐状态、标签等)。
**请求参数**:
- `by_id`: 按条目 seq_id 更新(可选),键为 seq_id,值为要更新的字段
- `by_tag`: 按标签 seq_id 更新(可选),键为 tag_seq_id,值为要更新的字段
- `exclude_ids`: 排除的条目 seq_id 列表(与 by_tag 配合使用,可选)
每个更新对象支持的字段:
- `is_enabled`: 是否启用(可选)
- `is_recommended`: 是否推荐(可选)
- `tag_id`: 标签ID(可选)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/entries/fields' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"by_id": {
"1": {"is_enabled": true, "is_recommended": false},
"2": {"is_enabled": false}
},
"by_tag": {
"100": {"is_enabled": true}
},
"exclude_ids": [3, 4]
}'
```
@@ -327,3 +421,82 @@ curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/se
"success": true
}
```
## GET `/knowledge-bases/:id/faq/entries/export` - 导出FAQ条目
将知识库下的所有 FAQ 条目导出为 CSV 文件。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/entries/export' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--output faq_export.csv
```
**响应**:
CSV 文件下载(Content-Type: text/csv
## GET `/faq/import/progress/:task_id` - 获取FAQ导入进度
查询异步 FAQ 导入任务的执行进度。任务 ID 由批量导入接口返回。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/faq/import/progress/task-00000001' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"task_id": "task-00000001",
"status": "completed",
"total": 100,
"success_count": 98,
"failed_count": 2,
"failed_entries": [
{
"index": 5,
"standard_question": "重复的问题",
"error": "标准问与已有FAQ重复"
}
],
"success_entries": []
},
"success": true
}
```
注:`status` 可能的值为 `pending``processing``completed``failed`
## PUT `/knowledge-bases/:id/faq/import/last-result/display` - 更新导入结果显示状态
更新上一次 FAQ 导入结果的显示状态,用于控制前端是否展示导入结果提示。
**请求参数**:
- `display_status`: 显示状态(如 `"dismissed"`
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/faq/import/last-result/display' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"display_status": "dismissed"
}'
```
**响应**:
```json
{
"success": true
}
```
+402
View File
@@ -0,0 +1,402 @@
# 初始化配置 API
[返回目录](./README.md)
| 方法 | 路径 | 描述 |
| ------ | ------------------------------------------------- | -------------------------- |
| GET | `/initialization/config/:kb_id` | 获取知识库初始化配置 |
| POST | `/initialization/initialize/:kb_id` | 初始化知识库模型配置 |
| PUT | `/initialization/config/:kb_id` | 更新知识库模型配置 |
| GET | `/initialization/ollama/status` | 检查 Ollama 状态 |
| GET | `/initialization/ollama/models` | 获取本地 Ollama 模型列表 |
| POST | `/initialization/ollama/models/check` | 检查 Ollama 模型是否可用 |
| POST | `/initialization/ollama/models/download` | 下载 Ollama 模型 |
| GET | `/initialization/ollama/download/progress/:task_id` | 获取下载进度 |
| GET | `/initialization/ollama/download/tasks` | 获取所有下载任务 |
| POST | `/initialization/remote/check` | 检查远程模型 API |
| POST | `/initialization/embedding/test` | 测试嵌入模型 |
| POST | `/initialization/rerank/check` | 检查重排序模型 |
| POST | `/initialization/multimodal/test` | 测试多模态模型 |
| POST | `/initialization/extract/text-relation` | 提取文本关系 |
## GET `/initialization/config/:kb_id` - 获取知识库初始化配置
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/config/kb-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"chat_model_id": "model-00000001",
"embedding_model_id": "model-00000002",
"rerank_model_id": "model-00000003",
"multimodal_id": "model-00000004"
},
"success": true
}
```
## POST `/initialization/initialize/:kb_id` - 初始化知识库模型配置
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/initialize/kb-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"chat_model_id": "model-00000001",
"embedding_model_id": "model-00000002",
"rerank_model_id": "model-00000003",
"multimodal_id": "model-00000004"
}'
```
**响应**:
```json
{
"success": true
}
```
## PUT `/initialization/config/:kb_id` - 更新知识库模型配置
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/initialization/config/kb-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"chat_model_id": "model-00000010",
"embedding_model_id": "model-00000002"
}'
```
**响应**:
```json
{
"success": true
}
```
## GET `/initialization/ollama/status` - 检查 Ollama 状态
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/status' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"available": true
},
"success": true
}
```
## GET `/initialization/ollama/models` - 获取本地 Ollama 模型列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/models' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"name": "llama3:8b",
"size": 4661211648,
"modified_at": "2025-08-10T15:30:00+08:00"
},
{
"name": "nomic-embed-text:latest",
"size": 274302976,
"modified_at": "2025-08-11T09:00:00+08:00"
}
],
"success": true
}
```
## POST `/initialization/ollama/models/check` - 检查 Ollama 模型是否可用
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/models/check' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"models": ["llama3:8b", "nomic-embed-text:latest", "mistral:7b"]
}'
```
**响应**:
```json
{
"data": {
"llama3:8b": true,
"nomic-embed-text:latest": true,
"mistral:7b": false
},
"success": true
}
```
## POST `/initialization/ollama/models/download` - 下载 Ollama 模型
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/models/download' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"model": "mistral:7b"
}'
```
**响应**:
```json
{
"data": {
"id": "task-00000001",
"modelName": "mistral:7b",
"status": "downloading",
"progress": 0,
"message": "开始下载",
"startTime": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## GET `/initialization/ollama/download/progress/:task_id` - 获取下载进度
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/download/progress/task-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "task-00000001",
"modelName": "mistral:7b",
"status": "downloading",
"progress": 45.6,
"message": "正在下载 2.1GB / 4.6GB",
"startTime": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## GET `/initialization/ollama/download/tasks` - 获取所有下载任务
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/ollama/download/tasks' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"id": "task-00000001",
"modelName": "mistral:7b",
"status": "completed",
"progress": 100,
"message": "下载完成",
"startTime": "2025-08-12T10:00:00+08:00",
"endTime": "2025-08-12T10:15:00+08:00"
},
{
"id": "task-00000002",
"modelName": "llama3:70b",
"status": "downloading",
"progress": 30.2,
"message": "正在下载 12.5GB / 41.4GB",
"startTime": "2025-08-12T10:20:00+08:00"
}
],
"success": true
}
```
## POST `/initialization/remote/check` - 检查远程模型 API
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/remote/check' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"api_url": "https://api.openai.com/v1",
"api_key": "sk-xxxxx",
"model": "gpt-4o"
}'
```
**响应**:
```json
{
"data": {
"success": true,
"message": "模型可用"
},
"success": true
}
```
## POST `/initialization/embedding/test` - 测试嵌入模型
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/embedding/test' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"api_url": "https://api.openai.com/v1",
"api_key": "sk-xxxxx",
"model": "text-embedding-3-small"
}'
```
**响应**:
```json
{
"data": {
"success": true,
"message": "嵌入模型测试通过"
},
"success": true
}
```
## POST `/initialization/rerank/check` - 检查重排序模型
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/rerank/check' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"api_url": "https://api.cohere.ai/v1",
"api_key": "sk-xxxxx",
"model": "rerank-english-v3.0"
}'
```
**响应**:
```json
{
"data": {
"success": true,
"message": "重排序模型可用"
},
"success": true
}
```
## POST `/initialization/multimodal/test` - 测试多模态模型
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/multimodal/test' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"api_url": "https://api.openai.com/v1",
"api_key": "sk-xxxxx",
"model": "gpt-4o"
}'
```
**响应**:
```json
{
"data": {
"success": true,
"message": "多模态模型测试通过"
},
"success": true
}
```
## POST `/initialization/extract/text-relation` - 提取文本关系
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/initialization/extract/text-relation' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"text": "WeKnora 是一个知识管理平台,支持多种文档格式的解析和检索。",
"model_id": "model-00000001"
}'
```
**响应**:
```json
{
"data": {
"entities": [
{"name": "WeKnora", "type": "Product"},
{"name": "知识管理平台", "type": "Concept"}
],
"relations": [
{
"source": "WeKnora",
"target": "知识管理平台",
"relation": "is_a"
}
]
},
"success": true
}
```
+125
View File
@@ -10,7 +10,10 @@
| PUT | `/knowledge-bases/:id` | 更新知识库 |
| DELETE | `/knowledge-bases/:id` | 删除知识库 |
| POST | `/knowledge-bases/copy` | 拷贝知识库 |
| GET | `/knowledge-bases/copy/progress/:task_id` | 获取拷贝进度 |
| GET | `/knowledge-bases/:id/hybrid-search` | 混合搜索(向量+关键词) |
| POST | `/knowledge-bases/:id/pin` | 置顶/取消置顶知识库 |
| GET | `/knowledge-bases/:id/move-targets` | 获取可迁移目标知识库列表 |
## POST `/knowledge-bases` - 创建知识库
@@ -316,6 +319,68 @@ curl --location --request DELETE 'http://localhost:8080/api/v1/knowledge-bases/b
}
```
## POST `/knowledge-bases/copy` - 拷贝知识库
异步拷贝一个知识库,包括知识库配置和所有知识内容。返回任务ID用于查询拷贝进度。
**请求参数**:
- `source_id`: 源知识库ID(必填)
- `name`: 新知识库名称(可选,默认使用原名称加"(副本)"后缀)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/copy' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"source_id": "kb-00000001",
"name": "知识库副本"
}'
```
**响应**:
```json
{
"data": {
"task_id": "task-copy-00000001",
"target_id": "kb-00000002"
},
"success": true
}
```
## GET `/knowledge-bases/copy/progress/:task_id` - 获取拷贝进度
查询知识库拷贝任务的执行进度。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/copy/progress/task-copy-00000001' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"task_id": "task-copy-00000001",
"status": "completed",
"total": 10,
"finished": 10,
"source_id": "kb-00000001",
"target_id": "kb-00000002"
},
"success": true
}
```
注:`status` 可能的值为 `pending``processing``completed``failed`
## GET `/knowledge-bases/:id/hybrid-search` - 混合搜索
执行向量搜索和关键词搜索的混合检索。
@@ -368,3 +433,63 @@ curl --location --request GET 'http://localhost:8080/api/v1/knowledge-bases/kb-0
"success": true
}
```
## POST `/knowledge-bases/:id/pin` - 置顶/取消置顶知识库
切换知识库的置顶状态。无需请求体,每次调用会自动切换当前置顶状态。
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/pin' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "kb-00000001",
"name": "Default Knowledge Base",
"description": "System Default Knowledge Base",
"tenant_id": 1,
"is_pinned": true,
"created_at": "2025-08-11T20:10:41.817794+08:00",
"updated_at": "2025-08-12T15:00:00.000000+08:00",
"deleted_at": null
},
"success": true
}
```
## GET `/knowledge-bases/:id/move-targets` - 获取可迁移目标知识库列表
获取当前知识库可以迁移知识到的目标知识库列表。返回结果会排除当前知识库本身。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/move-targets' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"id": "kb-00000002",
"name": "技术文档知识库",
"description": "技术文档相关知识",
"embedding_model_id": "dff7bc94-7885-4dd1-bfd5-bd96e4df2fc3",
"created_at": "2025-08-12T11:30:09.206238+08:00",
"updated_at": "2025-08-12T11:30:09.206238+08:00"
}
],
"success": true
}
```
+348
View File
@@ -16,6 +16,11 @@
| PUT | `/knowledge/image/:id/:chunk_id` | 更新图像分块信息 |
| PUT | `/knowledge/tags` | 批量更新知识标签 |
| GET | `/knowledge/batch` | 批量获取知识 |
| POST | `/knowledge/:id/reparse` | 重新解析知识 |
| GET | `/knowledge/search` | 搜索/过滤知识条目 |
| POST | `/knowledge/move` | 迁移知识到另一个知识库 |
| GET | `/knowledge/move/progress/:task_id` | 获取知识迁移进度 |
| GET | `/knowledge/:id/preview` | 预览知识文件 |
## POST `/knowledge-bases/:id/knowledge/file` - 从文件创建知识
@@ -311,3 +316,346 @@ curl --location 'http://localhost:8080/api/v1/knowledge/4c4e7c1a-09cf-485b-a7b5-
```
attachment
```
## PUT `/knowledge/:id` - 更新知识
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge/4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"title": "更新的标题",
"description": "更新的描述",
"tag_id": "tag-00000001"
}'
```
**响应**:
```json
{
"message": "Updated successfully",
"success": true
}
```
## POST `/knowledge-bases/:id/knowledge/manual` - 创建手工 Markdown 知识
创建手工 Markdown 知识条目,适用于直接编写内容而非上传文件的场景。
**请求参数**:
- `title`: 知识标题(必填)
- `content`: Markdown 内容(必填)
- `tag_id`: 标签ID(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/knowledge/manual' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"title": "产品使用指南",
"content": "# 产品使用指南\n\n## 快速入门\n\n这是一份产品使用指南...",
"tag_id": "tag-00000001"
}'
```
**响应**:
```json
{
"data": {
"id": "5a3b2c1d-0e9f-4a8b-7c6d-5e4f3a2b1c0d",
"tenant_id": 1,
"knowledge_base_id": "kb-00000001",
"type": "manual",
"title": "产品使用指南",
"description": "",
"source": "",
"parse_status": "processing",
"enable_status": "disabled",
"embedding_model_id": "dff7bc94-7885-4dd1-bfd5-bd96e4df2fc3",
"file_name": "",
"file_type": "md",
"file_size": 0,
"file_hash": "",
"file_path": "",
"storage_size": 0,
"metadata": null,
"created_at": "2025-08-12T12:00:00.000000+08:00",
"updated_at": "2025-08-12T12:00:00.000000+08:00",
"processed_at": null,
"error_message": "",
"deleted_at": null
},
"success": true
}
```
## PUT `/knowledge/manual/:id` - 更新手工 Markdown 知识
**请求参数**:
- `title`: 新标题(可选)
- `content`: 新 Markdown 内容(可选)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge/manual/5a3b2c1d-0e9f-4a8b-7c6d-5e4f3a2b1c0d' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"title": "产品使用指南 V2",
"content": "# 产品使用指南 V2\n\n## 更新内容\n\n..."
}'
```
**响应**:
```json
{
"data": {
"id": "5a3b2c1d-0e9f-4a8b-7c6d-5e4f3a2b1c0d",
"tenant_id": 1,
"knowledge_base_id": "kb-00000001",
"type": "manual",
"title": "产品使用指南 V2",
"parse_status": "processing",
"created_at": "2025-08-12T12:00:00.000000+08:00",
"updated_at": "2025-08-12T12:30:00.000000+08:00"
},
"success": true
}
```
## PUT `/knowledge/image/:id/:chunk_id` - 更新图像分块信息
更新知识条目中指定分块的图像描述信息。
**请求参数**:
- `image_info`: 图像信息(JSON 格式字符串)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge/image/4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5/df10b37d-cd05-4b14-ba8a-e1bd0eb3bbd7' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"image_info": "{\"description\": \"产品架构图\", \"alt_text\": \"WeKnora 系统架构\"}"
}'
```
**响应**:
```json
{
"message": "Updated successfully",
"success": true
}
```
## PUT `/knowledge/tags` - 批量更新知识标签
批量更新多个知识条目的标签关联。
**请求参数**:
- `updates`: 知识ID到标签ID的映射(设为 `null` 可清除标签)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge/tags' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"updates": {
"4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5": "tag-00000001",
"9c8af585-ae15-44ce-8f73-45ad18394651": null
}
}'
```
注:设置为 `null` 可清除标签关联。
**响应**:
```json
{
"success": true
}
```
## POST `/knowledge/:id/reparse` - 重新解析知识
触发知识的异步重新解析。此操作会删除现有的文档内容,然后使用最新的解析配置重新解析知识。
适用于解析配置更新后需要刷新内容,或者原始解析失败需要重试的场景。
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/knowledge/4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5/reparse' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5",
"tenant_id": 1,
"knowledge_base_id": "kb-00000001",
"type": "file",
"title": "彗星.txt",
"parse_status": "pending",
"enable_status": "enabled",
"created_at": "2025-08-12T11:52:36.168632+08:00",
"updated_at": "2025-08-12T13:00:00.000000+08:00"
},
"success": true
}
```
注:重新解析为异步操作,返回后 `parse_status` 将变为 `pending`,随后进入 `processing` 状态。
## GET `/knowledge/search` - 搜索/过滤知识条目
按关键词搜索和过滤知识条目,支持按文件类型和 Agent ID 筛选。
**查询参数**:
- `keyword`: 搜索关键词(可选)
- `offset`: 偏移量(默认 0
- `limit`: 返回数量(默认 20
- `file_types`: 文件类型过滤,多个类型用逗号分隔(可选)
- `agent_id`: 按 Agent ID 筛选(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge/search?keyword=%E5%BD%97%E6%98%9F&offset=0&limit=10&file_types=txt,pdf' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"data": [
{
"id": "4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5",
"tenant_id": 1,
"knowledge_base_id": "kb-00000001",
"type": "file",
"title": "彗星.txt",
"description": "彗星是由冰和尘埃构成的太阳系小天体...",
"file_name": "彗星.txt",
"file_type": "txt",
"file_size": 7710,
"parse_status": "completed",
"enable_status": "enabled",
"created_at": "2025-08-12T11:52:36.168632+08:00",
"updated_at": "2025-08-12T11:52:53.376871+08:00"
}
],
"has_more": false
},
"success": true
}
```
## POST `/knowledge/move` - 迁移知识到另一个知识库
将知识条目从一个知识库迁移到另一个知识库。此操作为异步任务,返回任务ID用于查询迁移进度。
**请求参数**:
- `knowledge_ids`: 待迁移的知识ID列表(必填)
- `source_kb_id`: 源知识库ID(必填)
- `target_kb_id`: 目标知识库ID(必填)
- `mode`: 迁移模式,`reuse_vectors` 复用向量数据,`reparse` 重新解析(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge/move' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"knowledge_ids": ["4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5"],
"source_kb_id": "kb-00000001",
"target_kb_id": "kb-00000002",
"mode": "reuse_vectors"
}'
```
**响应**:
```json
{
"data": {
"task_id": "task-move-00000001",
"source_kb_id": "kb-00000001",
"target_kb_id": "kb-00000002",
"knowledge_count": 1,
"message": "知识迁移任务已创建"
},
"success": true
}
```
## GET `/knowledge/move/progress/:task_id` - 获取知识迁移进度
查询知识迁移任务的执行进度。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge/move/progress/task-move-00000001' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"task_id": "task-move-00000001",
"status": "completed",
"progress": 100,
"total": 1,
"processed": 1,
"message": "迁移完成",
"error": ""
},
"success": true
}
```
注:`status` 可能的值为 `pending``processing``completed``failed`
## GET `/knowledge/:id/preview` - 预览知识文件
在浏览器中内联预览知识文件内容。响应会设置相应的 `Content-Type``Content-Disposition` 头,用于浏览器端直接展示文件。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge/4c4e7c1a-09cf-485b-a7b5-24b8cdc5acf5/preview' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ'
```
**响应**:
```
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline; filename="彗星.txt"
(文件内容)
```
+396
View File
@@ -0,0 +1,396 @@
# MCP Service API
[返回目录](./README.md)
| 方法 | 路径 | 描述 |
| ------ | --------------------------------- | ---------------------- |
| POST | `/mcp-services` | 创建 MCP 服务 |
| GET | `/mcp-services` | 获取 MCP 服务列表 |
| GET | `/mcp-services/:id` | 获取 MCP 服务详情 |
| PUT | `/mcp-services/:id` | 更新 MCP 服务 |
| DELETE | `/mcp-services/:id` | 删除 MCP 服务 |
| POST | `/mcp-services/:id/test` | 测试 MCP 服务连接 |
| GET | `/mcp-services/:id/tools` | 获取 MCP 服务工具列表 |
| GET | `/mcp-services/:id/resources` | 获取 MCP 服务资源列表 |
## POST `/mcp-services` - 创建 MCP 服务
**请求参数**:
- `name`: 服务名称(必填)
- `description`: 服务描述(可选)
- `transport_type`: 传输类型,可选值:`sse``http-streamable``stdio`(必填)
- `url`: 服务地址,当 transport_type 为 `sse``http-streamable` 时必填
- `headers`: 自定义请求头(可选)
- `auth_config`: 认证配置(可选),包含 `api_key``token``custom_headers`
- `advanced_config`: 高级配置(可选),包含 `timeout``retry_count``retry_delay`
- `stdio_config`: stdio 传输配置(可选),包含 `command``args`
- `env_vars`: 环境变量(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"name": "天气查询服务",
"description": "提供全球天气信息查询",
"transport_type": "sse",
"url": "https://mcp.example.com/weather/sse",
"headers": {
"X-Custom-Header": "value"
},
"auth_config": {
"api_key": "weather-api-key-xxxxx"
},
"advanced_config": {
"timeout": 30,
"retry_count": 3,
"retry_delay": 1
}
}'
```
**响应**:
```json
{
"data": {
"id": "mcp-00000001",
"tenant_id": 1,
"name": "天气查询服务",
"description": "提供全球天气信息查询",
"enabled": true,
"transport_type": "sse",
"url": "https://mcp.example.com/weather/sse",
"headers": {
"X-Custom-Header": "value"
},
"auth_config": {
"api_key": "weather-api-key-xxxxx"
},
"advanced_config": {
"timeout": 30,
"retry_count": 3,
"retry_delay": 1
},
"is_builtin": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
**创建 stdio 类型的 MCP 服务**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"name": "本地文件服务",
"description": "通过 stdio 访问本地文件系统",
"transport_type": "stdio",
"stdio_config": {
"command": "/usr/local/bin/mcp-file-server",
"args": ["--root", "/data"]
},
"env_vars": {
"MCP_LOG_LEVEL": "info"
}
}'
```
## GET `/mcp-services` - 获取 MCP 服务列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"id": "mcp-00000001",
"tenant_id": 1,
"name": "天气查询服务",
"description": "提供全球天气信息查询",
"enabled": true,
"transport_type": "sse",
"url": "https://mcp.example.com/weather/sse",
"headers": {},
"auth_config": {
"api_key": "weather-api-key-xxxxx"
},
"advanced_config": {
"timeout": 30,
"retry_count": 3,
"retry_delay": 1
},
"is_builtin": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
{
"id": "mcp-00000002",
"tenant_id": 1,
"name": "本地文件服务",
"description": "通过 stdio 访问本地文件系统",
"enabled": true,
"transport_type": "stdio",
"headers": {},
"auth_config": null,
"advanced_config": null,
"stdio_config": {
"command": "/usr/local/bin/mcp-file-server",
"args": ["--root", "/data"]
},
"env_vars": {
"MCP_LOG_LEVEL": "info"
},
"is_builtin": false,
"created_at": "2025-08-12T11:00:00+08:00",
"updated_at": "2025-08-12T11:00:00+08:00"
}
],
"success": true
}
```
## GET `/mcp-services/:id` - 获取 MCP 服务详情
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services/mcp-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "mcp-00000001",
"tenant_id": 1,
"name": "天气查询服务",
"description": "提供全球天气信息查询",
"enabled": true,
"transport_type": "sse",
"url": "https://mcp.example.com/weather/sse",
"headers": {},
"auth_config": {
"api_key": "weather-api-key-xxxxx"
},
"advanced_config": {
"timeout": 30,
"retry_count": 3,
"retry_delay": 1
},
"is_builtin": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## PUT `/mcp-services/:id` - 更新 MCP 服务
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/mcp-services/mcp-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"name": "天气查询服务(更新)",
"description": "提供全球天气信息查询,支持实时数据",
"enabled": false
}'
```
**响应**:
```json
{
"data": {
"id": "mcp-00000001",
"tenant_id": 1,
"name": "天气查询服务(更新)",
"description": "提供全球天气信息查询,支持实时数据",
"enabled": false,
"transport_type": "sse",
"url": "https://mcp.example.com/weather/sse",
"headers": {},
"auth_config": {
"api_key": "weather-api-key-xxxxx"
},
"advanced_config": {
"timeout": 30,
"retry_count": 3,
"retry_delay": 1
},
"is_builtin": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T12:00:00+08:00"
},
"success": true
}
```
## DELETE `/mcp-services/:id` - 删除 MCP 服务
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/mcp-services/mcp-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
## POST `/mcp-services/:id/test` - 测试 MCP 服务连接
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/mcp-services/mcp-00000001/test' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"success": true,
"message": "连接成功",
"tools": [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
],
"resources": [
{
"uri": "weather://cities",
"name": "城市列表",
"description": "支持查询的城市列表",
"mimeType": "application/json"
}
]
},
"success": true
}
```
## GET `/mcp-services/:id/tools` - 获取 MCP 服务工具列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services/mcp-00000001/tools' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
},
{
"name": "get_forecast",
"description": "获取未来天气预报",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"days": {
"type": "integer",
"description": "预报天数"
}
},
"required": ["city"]
}
}
],
"success": true
}
```
## GET `/mcp-services/:id/resources` - 获取 MCP 服务资源列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/mcp-services/mcp-00000001/resources' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"uri": "weather://cities",
"name": "城市列表",
"description": "支持查询的城市列表",
"mimeType": "application/json"
},
{
"uri": "weather://config",
"name": "服务配置",
"description": "当前服务配置信息",
"mimeType": "application/json"
}
],
"success": true
}
```
+77
View File
@@ -6,6 +6,8 @@
| ------ | ---------------------------- | ------------------------ |
| GET | `/messages/:session_id/load` | 获取最近的会话消息列表 |
| DELETE | `/messages/:session_id/:id` | 删除消息 |
| POST | `/messages/search` | 搜索历史对话 |
| GET | `/messages/chat-history-stats` | 获取聊天历史知识库统计 |
## GET `/messages/:session_id/load` - 获取最近的会话消息列表
@@ -178,3 +180,78 @@ curl --location --request DELETE 'http://localhost:8080/api/v1/messages/ceb9babb
"success": true
}
```
## POST `/messages/search` - 搜索历史对话
搜索历史对话消息,支持混合搜索、关键词搜索和向量搜索模式。
**请求参数**:
- `query`: 搜索关键词(必填)
- `mode`: 搜索模式,可选 `hybrid``keyword``vector`(可选,默认 `hybrid`
- `limit`: 返回结果数量(可选,默认 20
- `session_ids`: 限定搜索的会话ID列表(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/messages/search' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json' \
--data '{
"query": "彗星的结构",
"mode": "hybrid",
"limit": 20,
"session_ids": []
}'
```
**响应**:
```json
{
"data": {
"items": [
{
"request_id": "3475c004-0ada-4306-9d30-d7f5efce50d2",
"session_id": "ceb9babb-1e30-41d7-817d-fd584954304b",
"session_title": "彗星知识问答",
"query_content": "彗尾的形状",
"answer_content": "彗尾的形状主要取决于...",
"score": 0.85,
"match_type": "hybrid",
"created_at": "2025-08-12T14:30:39.732246+08:00"
}
],
"total": 1
},
"success": true
}
```
## GET `/messages/chat-history-stats` - 获取聊天历史知识库统计
获取当前租户的聊天历史知识库索引统计信息。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/messages/chat-history-stats' \
--header 'X-API-Key: sk-vQHV2NZI_LK5W7wHQvH3yGYExX8YnhaHwZipUYbiZKCYJbBQ' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"enabled": true,
"embedding_model_id": "dff7bc94-7885-4dd1-bfd5-bd96e4df2fc3",
"knowledge_base_id": "kb-chat-00000001",
"knowledge_base_name": "聊天历史知识库",
"indexed_message_count": 1024,
"has_indexed_messages": true
},
"success": true
}
```
+983
View File
@@ -0,0 +1,983 @@
# 组织管理 API
[返回目录](./README.md)
## 组织 CRUD
| 方法 | 路径 | 描述 |
| ------ | ------------------------- | ---------------- |
| POST | `/organizations` | 创建组织 |
| GET | `/organizations` | 获取我的组织列表 |
| GET | `/organizations/:id` | 获取组织详情 |
| PUT | `/organizations/:id` | 更新组织 |
| DELETE | `/organizations/:id` | 删除组织 |
## 成员管理
| 方法 | 路径 | 描述 |
| ------ | --------------------------------------------- | ------------------ |
| POST | `/organizations/join` | 通过邀请码加入组织 |
| POST | `/organizations/join-request` | 提交加入申请 |
| GET | `/organizations/search` | 搜索组织 |
| POST | `/organizations/join-by-id` | 通过组织ID加入 |
| GET | `/organizations/preview/:invite_code` | 预览组织信息 |
| POST | `/organizations/:id/leave` | 离开组织 |
| POST | `/organizations/:id/request-upgrade` | 请求角色升级 |
| POST | `/organizations/:id/invite-code` | 生成邀请码 |
| GET | `/organizations/:id/search-users` | 搜索可邀请用户 |
| POST | `/organizations/:id/invite` | 邀请成员 |
| GET | `/organizations/:id/members` | 获取成员列表 |
| PUT | `/organizations/:id/members/:user_id` | 更新成员角色 |
| DELETE | `/organizations/:id/members/:user_id` | 移除成员 |
## 加入请求
| 方法 | 路径 | 描述 |
| ---- | ------------------------------------------------------- | ---------------- |
| GET | `/organizations/:id/join-requests` | 获取加入请求列表 |
| PUT | `/organizations/:id/join-requests/:request_id/review` | 审核加入请求 |
## 知识库共享
| 方法 | 路径 | 描述 |
| ------ | --------------------------------------------- | ---------------- |
| POST | `/knowledge-bases/:id/shares` | 共享知识库 |
| GET | `/knowledge-bases/:id/shares` | 获取知识库共享列表 |
| PUT | `/knowledge-bases/:id/shares/:share_id` | 更新共享权限 |
| DELETE | `/knowledge-bases/:id/shares/:share_id` | 取消知识库共享 |
## 智能体共享
| 方法 | 路径 | 描述 |
| ------ | --------------------------------------- | ---------------- |
| POST | `/agents/:id/shares` | 共享智能体 |
| GET | `/agents/:id/shares` | 获取智能体共享列表 |
| DELETE | `/agents/:id/shares/:share_id` | 取消智能体共享 |
## 共享资源
| 方法 | 路径 | 描述 |
| ---- | --------------------------- | ------------------ |
| GET | `/shared-knowledge-bases` | 获取共享知识库列表 |
| GET | `/shared-agents` | 获取共享智能体列表 |
---
## POST `/organizations` - 创建组织
**请求参数**:
- `name`: 组织名称(必填)
- `description`: 组织描述(可选)
- `avatar`: 组织头像 URL(可选)
- `invite_code_validity_days`: 邀请码有效天数(可选)
- `member_limit`: 成员上限(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"invite_code_validity_days": 7,
"member_limit": 50
}'
```
**响应**:
```json
{
"data": {
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"avatar": "",
"owner_id": "user-00000001",
"invite_code": "",
"invite_code_validity_days": 7,
"require_approval": false,
"searchable": false,
"member_limit": 50,
"member_count": 1,
"share_count": 0,
"agent_share_count": 0,
"pending_join_request_count": 0,
"is_owner": true,
"my_role": "owner",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## GET `/organizations` - 获取我的组织列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"organizations": [
{
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"avatar": "",
"owner_id": "user-00000001",
"invite_code_validity_days": 7,
"require_approval": false,
"searchable": false,
"member_limit": 50,
"member_count": 3,
"share_count": 2,
"agent_share_count": 1,
"pending_join_request_count": 0,
"is_owner": true,
"my_role": "owner",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
}
]
},
"success": true
}
```
## GET `/organizations/:id` - 获取组织详情
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/org-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"avatar": "",
"owner_id": "user-00000001",
"invite_code": "ABC123XY",
"invite_code_expires_at": "2025-08-19T10:00:00+08:00",
"invite_code_validity_days": 7,
"require_approval": false,
"searchable": true,
"member_limit": 50,
"member_count": 3,
"share_count": 2,
"agent_share_count": 1,
"pending_join_request_count": 1,
"is_owner": true,
"my_role": "owner",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## PUT `/organizations/:id` - 更新组织
**请求参数**(均为可选):
- `name`: 组织名称
- `description`: 组织描述
- `avatar`: 组织头像 URL
- `require_approval`: 是否需要审核加入
- `searchable`: 是否可被搜索
- `invite_code_validity_days`: 邀请码有效天数
- `member_limit`: 成员上限
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/organizations/org-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"description": "专注于 AI 技术研究与知识管理(更新)",
"require_approval": true,
"searchable": true
}'
```
**响应**:
```json
{
"data": {
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理(更新)",
"avatar": "",
"owner_id": "user-00000001",
"invite_code_validity_days": 7,
"require_approval": true,
"searchable": true,
"member_limit": 50,
"member_count": 3,
"share_count": 2,
"agent_share_count": 1,
"pending_join_request_count": 0,
"is_owner": true,
"my_role": "owner",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T12:00:00+08:00"
},
"success": true
}
```
## DELETE `/organizations/:id` - 删除组织
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/organizations/org-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
---
## POST `/organizations/join` - 通过邀请码加入组织
**请求参数**:
- `invite_code`: 邀请码(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/join' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"invite_code": "ABC123XY"
}'
```
**响应**:
```json
{
"success": true
}
```
## POST `/organizations/join-request` - 提交加入申请
当组织开启了审核加入(`require_approval: true`)时使用。
**请求参数**:
- `invite_code`: 邀请码(必填)
- `message`: 申请留言(可选)
- `role`: 申请角色(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/join-request' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"invite_code": "ABC123XY",
"message": "希望加入团队参与知识库建设",
"role": "editor"
}'
```
**响应**:
```json
{
"success": true
}
```
## GET `/organizations/search` - 搜索组织
**查询参数**:
- `keyword`: 搜索关键字(可选)
- `page`: 页码(默认 1
- `page_size`: 每页条数(默认 20
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/search?keyword=AI&page=1&page_size=10' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"organizations": [
{
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"avatar": "",
"owner_id": "user-00000001",
"invite_code_validity_days": 7,
"require_approval": true,
"searchable": true,
"member_limit": 50,
"member_count": 3,
"share_count": 2,
"agent_share_count": 1,
"pending_join_request_count": 0,
"is_owner": false,
"my_role": "",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
}
]
},
"success": true
}
```
## POST `/organizations/join-by-id` - 通过组织ID加入
**请求参数**:
- `organization_id`: 组织 ID(必填)
- `message`: 申请留言(可选)
- `role`: 申请角色(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/join-by-id' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"organization_id": "org-00000001",
"message": "希望加入贵团队",
"role": "viewer"
}'
```
**响应**:
```json
{
"success": true
}
```
## GET `/organizations/preview/:invite_code` - 预览组织信息
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/preview/ABC123XY' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"id": "org-00000001",
"name": "AI 技术团队",
"description": "专注于 AI 技术研究与知识管理",
"avatar": "",
"owner_id": "user-00000001",
"invite_code_validity_days": 7,
"require_approval": true,
"searchable": true,
"member_limit": 50,
"member_count": 3,
"share_count": 0,
"agent_share_count": 0,
"pending_join_request_count": 0,
"is_owner": false,
"my_role": "",
"has_pending_upgrade": false,
"created_at": "2025-08-12T10:00:00+08:00",
"updated_at": "2025-08-12T10:00:00+08:00"
},
"success": true
}
```
## POST `/organizations/:id/leave` - 离开组织
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/organizations/org-00000001/leave' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
## POST `/organizations/:id/request-upgrade` - 请求角色升级
**请求参数**:
- `requested_role`: 期望角色(必填)
- `message`: 申请理由(可选)
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/organizations/org-00000001/request-upgrade' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"requested_role": "admin",
"message": "需要管理员权限来管理知识库共享"
}'
```
**响应**:
```json
{
"success": true
}
```
## POST `/organizations/:id/invite-code` - 生成邀请码
**请求**:
```curl
curl --location --request POST 'http://localhost:8080/api/v1/organizations/org-00000001/invite-code' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"invite_code": "NEW1CODE"
},
"success": true
}
```
## GET `/organizations/:id/search-users` - 搜索可邀请用户
**查询参数**:
- `keyword`: 用户名或邮箱关键字(可选)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/org-00000001/search-users?keyword=zhang' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"id": "user-00000002",
"username": "zhangsan",
"email": "zhangsan@example.com"
},
{
"id": "user-00000003",
"username": "zhangwei",
"email": "zhangwei@example.com"
}
],
"success": true
}
```
## POST `/organizations/:id/invite` - 邀请成员
**请求参数**:
- `user_id`: 用户 ID(必填)
- `role`: 角色(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/org-00000001/invite' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"user_id": "user-00000002",
"role": "editor"
}'
```
**响应**:
```json
{
"success": true
}
```
## GET `/organizations/:id/members` - 获取成员列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/org-00000001/members' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"members": [
{
"id": "mem-00000001",
"user_id": "user-00000001",
"username": "admin",
"email": "admin@example.com",
"avatar": "",
"role": "owner",
"tenant_id": 1,
"joined_at": "2025-08-12T10:00:00+08:00"
},
{
"id": "mem-00000002",
"user_id": "user-00000002",
"username": "zhangsan",
"email": "zhangsan@example.com",
"avatar": "",
"role": "editor",
"tenant_id": 2,
"joined_at": "2025-08-13T09:00:00+08:00"
}
]
},
"success": true
}
```
## PUT `/organizations/:id/members/:user_id` - 更新成员角色
**请求参数**:
- `role`: 新角色(必填)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/organizations/org-00000001/members/user-00000002' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"role": "admin"
}'
```
**响应**:
```json
{
"success": true
}
```
## DELETE `/organizations/:id/members/:user_id` - 移除成员
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/organizations/org-00000001/members/user-00000002' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
---
## GET `/organizations/:id/join-requests` - 获取加入请求列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/organizations/org-00000001/join-requests' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"requests": [
{
"id": "jr-00000001",
"user_id": "user-00000003",
"username": "zhangwei",
"email": "zhangwei@example.com",
"message": "希望加入团队参与知识库建设",
"request_type": "join",
"prev_role": "",
"requested_role": "editor",
"status": "pending",
"created_at": "2025-08-14T10:00:00+08:00"
}
]
},
"success": true
}
```
## PUT `/organizations/:id/join-requests/:request_id/review` - 审核加入请求
**请求参数**:
- `approved`: 是否批准(必填,布尔值)
- `message`: 审核留言(可选)
- `role`: 分配角色(可选,批准时生效)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/organizations/org-00000001/join-requests/jr-00000001/review' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"approved": true,
"message": "欢迎加入",
"role": "editor"
}'
```
**响应**:
```json
{
"success": true
}
```
---
## POST `/knowledge-bases/:id/shares` - 共享知识库
**请求参数**:
- `organization_id`: 目标组织 ID(必填)
- `permission`: 权限级别(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/shares' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"organization_id": "org-00000001",
"permission": "read"
}'
```
**响应**:
```json
{
"data": {
"id": "kbs-00000001",
"knowledge_base_id": "kb-00000001",
"knowledge_base_name": "技术文档库",
"organization_id": "org-00000001",
"organization_name": "AI 技术团队",
"shared_by_user_id": "user-00000001",
"shared_by_username": "admin",
"source_tenant_id": 1,
"permission": "read",
"my_role_in_org": "owner",
"my_permission": "read",
"created_at": "2025-08-15T10:00:00+08:00"
},
"success": true
}
```
## GET `/knowledge-bases/:id/shares` - 获取知识库共享列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/shares' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"shares": [
{
"id": "kbs-00000001",
"knowledge_base_id": "kb-00000001",
"knowledge_base_name": "技术文档库",
"organization_id": "org-00000001",
"organization_name": "AI 技术团队",
"shared_by_user_id": "user-00000001",
"shared_by_username": "admin",
"source_tenant_id": 1,
"permission": "read",
"my_role_in_org": "owner",
"my_permission": "read",
"created_at": "2025-08-15T10:00:00+08:00"
}
]
},
"success": true
}
```
## PUT `/knowledge-bases/:id/shares/:share_id` - 更新共享权限
**请求参数**:
- `permission`: 新权限级别(必填)
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/shares/kbs-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"permission": "write"
}'
```
**响应**:
```json
{
"success": true
}
```
## DELETE `/knowledge-bases/:id/shares/:share_id` - 取消知识库共享
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/knowledge-bases/kb-00000001/shares/kbs-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
---
## POST `/agents/:id/shares` - 共享智能体
**请求参数**:
- `organization_id`: 目标组织 ID(必填)
- `permission`: 权限级别(必填)
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/agents/agent-00000001/shares' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"organization_id": "org-00000001",
"permission": "read"
}'
```
**响应**:
```json
{
"data": {
"id": "as-00000001",
"agent_id": "agent-00000001",
"agent_name": "智能客服助手",
"organization_id": "org-00000001",
"organization_name": "AI 技术团队",
"shared_by_user_id": "user-00000001",
"shared_by_username": "admin",
"source_tenant_id": 1,
"permission": "read",
"created_at": "2025-08-15T11:00:00+08:00"
},
"success": true
}
```
## GET `/agents/:id/shares` - 获取智能体共享列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/agents/agent-00000001/shares' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"shares": [
{
"id": "as-00000001",
"agent_id": "agent-00000001",
"agent_name": "智能客服助手",
"organization_id": "org-00000001",
"organization_name": "AI 技术团队",
"shared_by_user_id": "user-00000001",
"shared_by_username": "admin",
"source_tenant_id": 1,
"permission": "read",
"created_at": "2025-08-15T11:00:00+08:00"
}
]
},
"success": true
}
```
## DELETE `/agents/:id/shares/:share_id` - 取消智能体共享
**请求**:
```curl
curl --location --request DELETE 'http://localhost:8080/api/v1/agents/agent-00000001/shares/as-00000001' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"success": true
}
```
---
## GET `/shared-knowledge-bases` - 获取共享知识库列表
获取当前用户通过组织共享获得的所有知识库。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/shared-knowledge-bases' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"share_id": "kbs-00000001",
"organization_id": "org-00000001",
"org_name": "AI 技术团队",
"permission": "read",
"source_tenant_id": 1,
"shared_at": "2025-08-15T10:00:00+08:00"
}
],
"success": true
}
```
## GET `/shared-agents` - 获取共享智能体列表
获取当前用户通过组织共享获得的所有智能体。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/shared-agents' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"share_id": "as-00000001",
"organization_id": "org-00000001",
"org_name": "AI 技术团队",
"permission": "read",
"source_tenant_id": 1,
"shared_at": "2025-08-15T11:00:00+08:00"
}
],
"success": true
}
```
+52
View File
@@ -0,0 +1,52 @@
# Skills API
[返回目录](./README.md)
| 方法 | 路径 | 描述 |
| ---- | --------- | ------------------ |
| GET | `/skills` | 获取预装 Skills 列表 |
## GET `/skills` - 获取预装 Skills 列表
获取系统中所有预装的智能体技能列表。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/skills' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"name": "web_search",
"description": "搜索互联网获取最新信息"
},
{
"name": "code_interpreter",
"description": "执行代码并返回结果"
},
{
"name": "image_generation",
"description": "根据文本描述生成图片"
}
],
"skills_available": true,
"success": true
}
```
当系统未配置 Skills 时,`skills_available` 返回 `false``data` 为空数组:
```json
{
"data": [],
"skills_available": false,
"success": true
}
```
+229
View File
@@ -0,0 +1,229 @@
# 系统管理 API
[返回目录](./README.md)
| 方法 | 路径 | 描述 |
| ------ | --------------------------------- | ---------------------- |
| GET | `/system/info` | 获取系统信息 |
| GET | `/system/parser-engines` | 获取解析引擎列表 |
| POST | `/system/parser-engines/check` | 检查解析引擎可用性 |
| POST | `/system/docreader/reconnect` | 重连文档解析服务 |
| GET | `/system/storage-engine-status` | 获取存储引擎状态 |
| POST | `/system/storage-engine-check` | 检查存储引擎连通性 |
| GET | `/system/minio/buckets` | 获取 MinIO 桶列表 |
## GET `/system/info` - 获取系统信息
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/info' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"version": "1.2.0",
"edition": "community",
"commit_id": "a1b2c3d",
"build_time": "2025-08-12T08:00:00Z",
"go_version": "go1.21.5",
"keyword_index_engine": "bleve",
"vector_store_engine": "milvus",
"graph_database_engine": "neo4j",
"minio_enabled": true,
"db_version": "20250810_001"
},
"success": true
}
```
## GET `/system/parser-engines` - 获取解析引擎列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/parser-engines' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"name": "docreader",
"label": "DocReader",
"description": "高精度文档解析引擎",
"available": true
},
{
"name": "tika",
"label": "Apache Tika",
"description": "通用文档解析引擎",
"available": false
}
],
"connected": true,
"success": true
}
```
## POST `/system/parser-engines/check` - 检查解析引擎可用性
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/parser-engines/check' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"addr": "http://docreader:8000"
}'
```
**响应**:
```json
{
"data": [
{
"name": "docreader",
"label": "DocReader",
"description": "高精度文档解析引擎",
"available": true
}
],
"success": true
}
```
## POST `/system/docreader/reconnect` - 重连文档解析服务
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/docreader/reconnect' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"addr": "http://docreader:8000"
}'
```
**响应**:
```json
{
"success": true
}
```
## GET `/system/storage-engine-status` - 获取存储引擎状态
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/storage-engine-status' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"engines": [
{
"name": "minio",
"available": true,
"description": "MinIO 对象存储"
},
{
"name": "cos",
"available": false,
"description": "腾讯云 COS 对象存储"
},
{
"name": "s3",
"available": false,
"description": "AWS S3 对象存储"
}
],
"minio_env_available": true
},
"success": true
}
```
## POST `/system/storage-engine-check` - 检查存储引擎连通性
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/storage-engine-check' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json' \
--data '{
"provider": "minio",
"minio": {
"endpoint": "localhost:9000",
"access_key": "minioadmin",
"secret_key": "minioadmin",
"bucket": "weknora",
"use_ssl": false
}
}'
```
**响应**:
```json
{
"data": {
"ok": true,
"message": "连接成功",
"bucket_created": false
},
"success": true
}
```
## GET `/system/minio/buckets` - 获取 MinIO 桶列表
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/system/minio/buckets' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": {
"buckets": [
{
"name": "weknora",
"policy": "read-write",
"created_at": "2025-08-01T10:00:00+08:00"
},
{
"name": "weknora-backup",
"policy": "read-only",
"created_at": "2025-08-05T14:00:00+08:00"
}
]
},
"success": true
}
```
+156
View File
@@ -9,6 +9,10 @@
| PUT | `/tenants/:id` | 更新租户信息 |
| DELETE | `/tenants/:id` | 删除租户 |
| GET | `/tenants` | 获取租户列表 |
| GET | `/tenants/all` | 获取所有租户列表(需跨租户权限) |
| GET | `/tenants/search` | 搜索租户(需跨租户权限) |
| GET | `/tenants/kv/:key` | 获取租户KV配置 |
| PUT | `/tenants/kv/:key` | 更新租户KV配置 |
## POST `/tenants` - 创建新租户
@@ -241,3 +245,155 @@ curl --location 'http://localhost:8080/api/v1/tenants' \
"success": true
}
```
## GET `/tenants/all` - 获取所有租户列表
获取系统中所有租户列表,需要跨租户权限。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/tenants/all' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: sk-An7_t_izCKFIJ4iht9Xjcjnj_MC48ILvwezEDki9ScfIa7KA'
```
**响应**:
```json
{
"data": {
"items": [
{
"id": 10001,
"name": "weknora-1",
"description": "weknora tenants 1",
"status": "active",
"business": "wechat",
"created_at": "2025-08-11T20:37:28.39698+08:00",
"updated_at": "2025-08-11T20:37:28.405693+08:00"
},
{
"id": 10002,
"name": "weknora-2",
"description": "weknora tenants 2",
"status": "active",
"business": "wechat",
"created_at": "2025-08-11T20:52:58.05679+08:00",
"updated_at": "2025-08-11T20:52:58.060495+08:00"
}
]
},
"success": true
}
```
## GET `/tenants/search` - 搜索租户
按关键词搜索租户,需要跨租户权限。
**查询参数**:
- `keyword`: 搜索关键词(可选)
- `tenant_id`: 按租户ID筛选(可选)
- `page`: 页码(默认 1
- `page_size`: 每页条数(默认 20
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/tenants/search?keyword=weknora&page=1&page_size=10' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: sk-An7_t_izCKFIJ4iht9Xjcjnj_MC48ILvwezEDki9ScfIa7KA'
```
**响应**:
```json
{
"data": {
"items": [
{
"id": 10002,
"name": "weknora",
"description": "weknora tenants",
"status": "active",
"business": "wechat",
"created_at": "2025-08-11T20:52:58.05679+08:00",
"updated_at": "2025-08-11T20:52:58.060495+08:00"
}
],
"total": 1,
"page": 1,
"page_size": 10
},
"success": true
}
```
## GET `/tenants/kv/:key` - 获取租户KV配置
获取指定键名的租户配置项。
**支持的 key 值**:
- `agent-config`: Agent 配置
- `web-search-config`: 网页搜索配置
- `conversation-config`: 对话配置
- `prompt-templates`: 提示词模板
- `parser-engine-config`: 解析引擎配置
- `storage-engine-config`: 存储引擎配置
- `chat-history-config`: 聊天历史配置
- `retrieval-config`: 检索配置
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/tenants/kv/agent-config' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: sk-An7_t_izCKFIJ4iht9Xjcjnj_MC48ILvwezEDki9ScfIa7KA'
```
**响应**:
```json
{
"data": {
"key": "agent-config",
"value": {
"enabled": true,
"max_iterations": 10
}
},
"success": true
}
```
## PUT `/tenants/kv/:key` - 更新租户KV配置
更新指定键名的租户配置项。请求体内容根据不同的 key 值而有所不同。
**请求**:
```curl
curl --location --request PUT 'http://localhost:8080/api/v1/tenants/kv/agent-config' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: sk-An7_t_izCKFIJ4iht9Xjcjnj_MC48ILvwezEDki9ScfIa7KA' \
--data '{
"enabled": true,
"max_iterations": 20
}'
```
**响应**:
```json
{
"data": {
"key": "agent-config",
"value": {
"enabled": true,
"max_iterations": 20
}
},
"success": true
}
```
+47
View File
@@ -0,0 +1,47 @@
# Web Search API
[返回目录](./README.md)
| 方法 | 路径 | 描述 |
| ---- | ------------------------ | ---------------------- |
| GET | `/web-search/providers` | 获取网络搜索服务商列表 |
## GET `/web-search/providers` - 获取网络搜索服务商列表
获取系统中可用的网络搜索服务商列表。
**请求**:
```curl
curl --location 'http://localhost:8080/api/v1/web-search/providers' \
--header 'X-API-Key: sk-xxxxx' \
--header 'Content-Type: application/json'
```
**响应**:
```json
{
"data": [
{
"name": "google",
"label": "Google Search",
"description": "通过 Google 自定义搜索 API 进行网络搜索",
"enabled": true
},
{
"name": "bing",
"label": "Bing Search",
"description": "通过 Bing Search API 进行网络搜索",
"enabled": true
},
{
"name": "serpapi",
"label": "SerpAPI",
"description": "通过 SerpAPI 进行搜索引擎结果抓取",
"enabled": false
}
],
"success": true
}
```