mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-08-30 16:53:21 +08:00
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:
@@ -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
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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) |
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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"
|
||||
|
||||
(文件内容)
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user