WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/Tencent/WeKnora/internal/types"
|
||||
"github.com/Tencent/WeKnora/internal/types/interfaces"
|
||||
"github.com/Tencent/WeKnora/internal/utils"
|
||||
)
|
||||
|
||||
var dataSchemaTool = BaseTool{
|
||||
name: ToolDataSchema,
|
||||
description: "Use this tool to get the schema information of a CSV or Excel file loaded into DuckDB. It returns the table name, columns, and row count.",
|
||||
schema: utils.GenerateSchema[DataSchemaInput](),
|
||||
}
|
||||
|
||||
type DataSchemaInput struct {
|
||||
KnowledgeID string `json:"knowledge_id" jsonschema:"short dN document ID to query"`
|
||||
}
|
||||
|
||||
type DataSchemaTool struct {
|
||||
BaseTool
|
||||
knowledgeService interfaces.KnowledgeService
|
||||
chunkRepo interfaces.ChunkRepository
|
||||
targetChunkTypes []types.ChunkType
|
||||
searchTargets types.SearchTargets
|
||||
scopeEnforced bool
|
||||
}
|
||||
|
||||
// WithSearchTargets enables Agent request-scope authorization. An Agent turn
|
||||
// with no search target must reject every document rather than fall back to
|
||||
// the unrestricted service-owned lookup.
|
||||
func (t *DataSchemaTool) WithSearchTargets(searchTargets types.SearchTargets) *DataSchemaTool {
|
||||
t.searchTargets = searchTargets
|
||||
t.scopeEnforced = true
|
||||
return t
|
||||
}
|
||||
|
||||
func NewDataSchemaTool(knowledgeService interfaces.KnowledgeService, chunkRepo interfaces.ChunkRepository, targetChunkTypes ...types.ChunkType) *DataSchemaTool {
|
||||
if len(targetChunkTypes) == 0 {
|
||||
targetChunkTypes = []types.ChunkType{types.ChunkTypeTableSummary, types.ChunkTypeTableColumn}
|
||||
}
|
||||
return &DataSchemaTool{
|
||||
BaseTool: dataSchemaTool,
|
||||
knowledgeService: knowledgeService,
|
||||
chunkRepo: chunkRepo,
|
||||
targetChunkTypes: targetChunkTypes,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the tool logic
|
||||
func (t *DataSchemaTool) Execute(ctx context.Context, args json.RawMessage) (*types.ToolResult, error) {
|
||||
var input DataSchemaInput
|
||||
if err := json.Unmarshal(args, &input); err != nil {
|
||||
return &types.ToolResult{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("Failed to parse input args: %v", err),
|
||||
}, err
|
||||
}
|
||||
|
||||
// Get knowledge to get TenantID (use IDOnly to support cross-tenant shared KB)
|
||||
var knowledge *types.Knowledge
|
||||
var err error
|
||||
if t.scopeEnforced {
|
||||
knowledge, err = authorizeKnowledgeInSearchTargets(ctx, t.searchTargets, input.KnowledgeID, t.knowledgeService)
|
||||
} else {
|
||||
knowledge, err = t.knowledgeService.GetKnowledgeByIDOnly(ctx, input.KnowledgeID)
|
||||
}
|
||||
if err != nil || knowledge == nil {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("knowledge service returned an empty result")
|
||||
}
|
||||
return &types.ToolResult{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("Failed to get knowledge '%s': %v", input.KnowledgeID, err),
|
||||
}, err
|
||||
}
|
||||
|
||||
// Get chunks for the knowledge ID using ChunkRepository
|
||||
// We only need table summary and column chunks
|
||||
chunkTypes := t.targetChunkTypes
|
||||
page := &types.Pagination{
|
||||
Page: 1,
|
||||
PageSize: 100, // Should be enough for schema chunks
|
||||
}
|
||||
enabled := true
|
||||
|
||||
chunks, _, err := t.chunkRepo.ListPagedChunksByKnowledgeID(
|
||||
ctx,
|
||||
knowledge.TenantID,
|
||||
input.KnowledgeID,
|
||||
page,
|
||||
chunkTypes,
|
||||
nil, // tagIDs
|
||||
"", // keyword
|
||||
"", // searchField
|
||||
"", // sortOrder
|
||||
"", // knowledgeType
|
||||
&enabled,
|
||||
)
|
||||
if err != nil {
|
||||
return &types.ToolResult{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("Failed to list chunks for knowledge ID '%s': %v", input.KnowledgeID, err),
|
||||
}, err
|
||||
}
|
||||
|
||||
var summaryContent, columnContent string
|
||||
for _, chunk := range chunks {
|
||||
if chunk.ChunkType == types.ChunkTypeTableSummary {
|
||||
summaryContent = chunk.Content
|
||||
} else if chunk.ChunkType == types.ChunkTypeTableColumn {
|
||||
columnContent = chunk.Content
|
||||
}
|
||||
}
|
||||
|
||||
if summaryContent == "" || columnContent == "" {
|
||||
return &types.ToolResult{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("No table schema information found for knowledge ID '%s'", input.KnowledgeID),
|
||||
}, fmt.Errorf("no schema info found")
|
||||
}
|
||||
|
||||
output := fmt.Sprintf("%s\n\n%s", summaryContent, columnContent)
|
||||
|
||||
return &types.ToolResult{
|
||||
Success: true,
|
||||
Output: output,
|
||||
Data: map[string]interface{}{
|
||||
"summary": summaryContent,
|
||||
"columns": columnContent,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user