Add MCP client loading and printing functionality
- Introduced a new `printMCPs` function to display loaded MCP clients, categorizing them into standard and agent clients for better clarity. - Enhanced the `Load` function to include loading MCP clients from the assistants directory, improving the overall MCP management. - Added tests for loading assistant MCPs, ensuring that the functionality works as expected and that agent clients are correctly identified and logged. - Updated model loading to support agent models from assistants, ensuring proper integration and functionality across the system.
This commit is contained in:
parent
311350bfbc
commit
cd5b4df503
5 changed files with 444 additions and 0 deletions
74
cmd/start.go
74
cmd/start.go
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/yaoapp/gou/api"
|
"github.com/yaoapp/gou/api"
|
||||||
"github.com/yaoapp/gou/connector"
|
"github.com/yaoapp/gou/connector"
|
||||||
"github.com/yaoapp/gou/fs"
|
"github.com/yaoapp/gou/fs"
|
||||||
|
"github.com/yaoapp/gou/mcp"
|
||||||
"github.com/yaoapp/gou/plugin"
|
"github.com/yaoapp/gou/plugin"
|
||||||
"github.com/yaoapp/gou/schedule"
|
"github.com/yaoapp/gou/schedule"
|
||||||
"github.com/yaoapp/gou/server/http"
|
"github.com/yaoapp/gou/server/http"
|
||||||
|
|
@ -143,6 +144,7 @@ var startCmd = &cobra.Command{
|
||||||
printSchedules(false)
|
printSchedules(false)
|
||||||
printConnectors(false)
|
printConnectors(false)
|
||||||
printStores(false)
|
printStores(false)
|
||||||
|
printMCPs(false)
|
||||||
// printStudio(false, host)
|
// printStudio(false, host)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -230,6 +232,7 @@ var startCmd = &cobra.Command{
|
||||||
printSchedules(true)
|
printSchedules(true)
|
||||||
printConnectors(true)
|
printConnectors(true)
|
||||||
printStores(true)
|
printStores(true)
|
||||||
|
printMCPs(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the warnings
|
// Print the warnings
|
||||||
|
|
@ -498,6 +501,77 @@ func printApis(silent bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printMCPs(silent bool) {
|
||||||
|
clients := mcp.ListClients()
|
||||||
|
if len(clients) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if silent {
|
||||||
|
for _, clientID := range clients {
|
||||||
|
log.Info("[MCP] %s loaded", clientID)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate agent MCPs from standard MCPs
|
||||||
|
agentClients := []string{}
|
||||||
|
standardClients := []string{}
|
||||||
|
for _, clientID := range clients {
|
||||||
|
if len(clientID) >= 7 && clientID[:7] == "agents." {
|
||||||
|
agentClients = append(agentClients, clientID)
|
||||||
|
} else {
|
||||||
|
standardClients = append(standardClients, clientID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(color.WhiteString("\n---------------------------------"))
|
||||||
|
fmt.Println(color.WhiteString(L("MCP Clients List (%d)"), len(clients)))
|
||||||
|
fmt.Println(color.WhiteString("---------------------------------"))
|
||||||
|
|
||||||
|
if len(standardClients) > 0 {
|
||||||
|
fmt.Println(color.WhiteString("\n%s (%d)", "Standard MCPs", len(standardClients)))
|
||||||
|
fmt.Println(color.WhiteString("--------------------------"))
|
||||||
|
for _, clientID := range standardClients {
|
||||||
|
mapping, err := mcp.GetClientMapping(clientID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print(color.CyanString("[MCP] %s", clientID))
|
||||||
|
fmt.Print(color.WhiteString("\tloaded\n"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
toolsCount := 0
|
||||||
|
if mapping.Tools != nil {
|
||||||
|
toolsCount = len(mapping.Tools)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(color.CyanString("[MCP] %s", clientID))
|
||||||
|
fmt.Print(color.WhiteString("\ttools: %d\n", toolsCount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(agentClients) > 0 {
|
||||||
|
fmt.Println(color.WhiteString("\n%s (%d)", "Agent MCPs", len(agentClients)))
|
||||||
|
fmt.Println(color.WhiteString("--------------------------"))
|
||||||
|
for _, clientID := range agentClients {
|
||||||
|
mapping, err := mcp.GetClientMapping(clientID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print(color.CyanString("[MCP] %s", clientID))
|
||||||
|
fmt.Print(color.WhiteString("\tloaded\n"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
toolsCount := 0
|
||||||
|
if mapping.Tools != nil {
|
||||||
|
toolsCount = len(mapping.Tools)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(color.CyanString("[MCP] %s", clientID))
|
||||||
|
fmt.Print(color.WhiteString("\ttools: %d\n", toolsCount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func colorMehtod(method string) string {
|
func colorMehtod(method string) string {
|
||||||
method = strings.ToUpper(method)
|
method = strings.ToUpper(method)
|
||||||
switch method {
|
switch method {
|
||||||
|
|
|
||||||
106
mcp/mcp.go
106
mcp/mcp.go
|
|
@ -3,6 +3,7 @@ package mcp
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -44,6 +45,14 @@ func Load(cfg config.Config) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load MCP clients from assistants
|
||||||
|
errsAssistants := loadAssistantMCPs()
|
||||||
|
if len(errsAssistants) > 0 {
|
||||||
|
for _, err := range errsAssistants {
|
||||||
|
log.Error("Load assistant MCP clients error: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load database MCP clients (ignore error)
|
// Load database MCP clients (ignore error)
|
||||||
errs := loadDatabaseMCPs()
|
errs := loadDatabaseMCPs()
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
|
|
@ -54,6 +63,103 @@ func Load(cfg config.Config) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadAssistantMCPs load MCP clients from assistants directory
|
||||||
|
func loadAssistantMCPs() []error {
|
||||||
|
var errs []error = []error{}
|
||||||
|
|
||||||
|
// Check if assistants directory exists
|
||||||
|
exists, err := application.App.Exists("assistants")
|
||||||
|
if err != nil || !exists {
|
||||||
|
log.Trace("Assistants directory not found or not accessible")
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("Loading MCP clients from assistants directory...")
|
||||||
|
|
||||||
|
// Track processed assistants to avoid duplicates
|
||||||
|
processedAssistants := make(map[string]bool)
|
||||||
|
|
||||||
|
// Walk through assistants directory to find all valid assistants with mcps
|
||||||
|
err = application.App.Walk("assistants", func(root, file string, isdir bool) error {
|
||||||
|
if !isdir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a valid assistant directory (has package.yao)
|
||||||
|
// file is relative path from root, so we need to join root + file
|
||||||
|
pkgFile := filepath.Join(root, file, "package.yao")
|
||||||
|
pkgExists, _ := application.App.Exists(pkgFile)
|
||||||
|
if !pkgExists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract assistant ID from path (e.g., "/assistants/expense" -> "expense")
|
||||||
|
// file is like "/tests/mcpload", trim leading "/" and replace "/" with "."
|
||||||
|
assistantID := strings.TrimPrefix(file, "/")
|
||||||
|
assistantID = strings.ReplaceAll(assistantID, "/", ".")
|
||||||
|
|
||||||
|
// Skip if already processed
|
||||||
|
if processedAssistants[assistantID] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
processedAssistants[assistantID] = true
|
||||||
|
|
||||||
|
log.Trace("Found assistant: %s", assistantID)
|
||||||
|
|
||||||
|
// Check if the assistant has an mcps directory
|
||||||
|
mcpsDir := filepath.Join(root, file, "mcps")
|
||||||
|
mcpsDirExists, _ := application.App.Exists(mcpsDir)
|
||||||
|
if !mcpsDirExists {
|
||||||
|
log.Trace("Assistant %s has no mcps directory", assistantID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("Loading MCPs from assistant %s", assistantID)
|
||||||
|
|
||||||
|
// Load MCP clients from the assistant's mcps directory
|
||||||
|
exts := []string{"*.mcp.yao", "*.mcp.json", "*.mcp.jsonc"}
|
||||||
|
err := application.App.Walk(mcpsDir, func(mcpRoot, mcpFile string, mcpIsDir bool) error {
|
||||||
|
if mcpIsDir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate MCP client ID with agents.<assistantID>./ prefix
|
||||||
|
// Support nested paths: "mcps/nested/tool.mcp.yao" -> "nested.tool"
|
||||||
|
relPath := strings.TrimPrefix(mcpFile, mcpsDir+"/")
|
||||||
|
relPath = strings.TrimPrefix(relPath, "/")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mcp.yao")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mcp.json")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mcp.jsonc")
|
||||||
|
mcpName := strings.ReplaceAll(relPath, "/", ".")
|
||||||
|
clientID := fmt.Sprintf("agents.%s.%s", assistantID, mcpName)
|
||||||
|
|
||||||
|
log.Trace("Loading MCP client %s from file %s", clientID, mcpFile)
|
||||||
|
|
||||||
|
_, err := mcp.LoadClient(mcpFile, clientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to load MCP client %s from assistant %s: %s", clientID, assistantID, err.Error())
|
||||||
|
errs = append(errs, fmt.Errorf("failed to load MCP client %s: %w", clientID, err))
|
||||||
|
return nil // Continue loading other MCPs
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Loaded MCP client: %s", clientID)
|
||||||
|
return nil
|
||||||
|
}, exts...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("failed to walk MCPs in assistant %s: %w", assistantID, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("failed to walk assistants directory: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// loadDatabaseMCPs load database MCP clients
|
// loadDatabaseMCPs load database MCP clients
|
||||||
func loadDatabaseMCPs() []error {
|
func loadDatabaseMCPs() []error {
|
||||||
var errs []error = []error{}
|
var errs []error = []error{}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mcp
|
package mcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -127,3 +128,86 @@ func TestUnloadClient(t *testing.T) {
|
||||||
// Test that unloading non-existent client doesn't crash
|
// Test that unloading non-existent client doesn't crash
|
||||||
mcp.UnloadClient("non_existent")
|
mcp.UnloadClient("non_existent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadAssistantMCPs(t *testing.T) {
|
||||||
|
test.Prepare(t, config.Conf)
|
||||||
|
defer test.Clean()
|
||||||
|
|
||||||
|
// Load MCPs
|
||||||
|
err := Load(config.Conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Load returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all loaded clients
|
||||||
|
clients := mcp.ListClients()
|
||||||
|
t.Logf("Total loaded MCP clients: %d", len(clients))
|
||||||
|
|
||||||
|
// Filter agent clients
|
||||||
|
agentClients := []string{}
|
||||||
|
for _, id := range clients {
|
||||||
|
if len(id) >= 7 && id[:7] == "agents." {
|
||||||
|
agentClients = append(agentClients, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Agent MCP clients: %v", agentClients)
|
||||||
|
|
||||||
|
// Check if the test assistant MCP client is loaded
|
||||||
|
testClientID := "agents.tests.mcpload.test"
|
||||||
|
if mcp.Exists(testClientID) {
|
||||||
|
t.Logf("✓ Test assistant MCP client '%s' loaded successfully", testClientID)
|
||||||
|
|
||||||
|
// Verify we can get the client
|
||||||
|
client, err := mcp.Select(testClientID)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, client)
|
||||||
|
|
||||||
|
// Try to list tools
|
||||||
|
ctx := context.Background()
|
||||||
|
toolsResp, err := client.ListTools(ctx, "")
|
||||||
|
if err == nil && toolsResp != nil {
|
||||||
|
t.Logf("✓ Available tools in %s: %d", testClientID, len(toolsResp.Tools))
|
||||||
|
for _, tool := range toolsResp.Tools {
|
||||||
|
t.Logf(" - Tool: %s - %s", tool.Name, tool.Description)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Logf("Could not list tools: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
t.Logf("Test assistant MCP client '%s' not found", testClientID)
|
||||||
|
t.Logf("This may be expected if the test assistant is not in the application")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for nested MCP client
|
||||||
|
nestedClientID := "agents.tests.mcpload.nested.tool"
|
||||||
|
if mcp.Exists(nestedClientID) {
|
||||||
|
t.Logf("✓ Nested MCP client '%s' loaded successfully", nestedClientID)
|
||||||
|
|
||||||
|
client, err := mcp.Select(nestedClientID)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, client)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
toolsResp, err := client.ListTools(ctx, "")
|
||||||
|
if err == nil && toolsResp != nil {
|
||||||
|
t.Logf("✓ Available tools in %s: %d", nestedClientID, len(toolsResp.Tools))
|
||||||
|
for _, tool := range toolsResp.Tools {
|
||||||
|
t.Logf(" - Tool: %s - %s", tool.Name, tool.Description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Logf("✗ Nested MCP client '%s' not found", nestedClientID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report all agent clients found
|
||||||
|
if len(agentClients) > 0 {
|
||||||
|
t.Logf("✓ Successfully loaded %d agent MCP client(s):", len(agentClients))
|
||||||
|
for _, id := range agentClients {
|
||||||
|
t.Logf(" - %s", id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Logf("No agent MCP clients found (this may be expected if no assistants have mcps)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
150
model/model.go
150
model/model.go
|
|
@ -76,6 +76,14 @@ func Load(cfg config.Config) error {
|
||||||
return fmt.Errorf("%s", strings.Join(messages, ";\n"))
|
return fmt.Errorf("%s", strings.Join(messages, ";\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load models from assistants
|
||||||
|
errsAssistants := loadAssistantModels()
|
||||||
|
if len(errsAssistants) > 0 {
|
||||||
|
for _, err := range errsAssistants {
|
||||||
|
log.Error("Load assistant models error: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load database models ( ignore error)
|
// Load database models ( ignore error)
|
||||||
errs := loadDatabaseModels()
|
errs := loadDatabaseModels()
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
|
|
@ -131,6 +139,148 @@ func loadSystemModels() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadAssistantModels load models from assistants directory
|
||||||
|
func loadAssistantModels() []error {
|
||||||
|
var errs []error = []error{}
|
||||||
|
|
||||||
|
// Check if assistants directory exists
|
||||||
|
exists, err := application.App.Exists("assistants")
|
||||||
|
if err != nil || !exists {
|
||||||
|
log.Trace("Assistants directory not found or not accessible")
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("Loading models from assistants directory...")
|
||||||
|
|
||||||
|
// Track processed assistants to avoid duplicates
|
||||||
|
processedAssistants := make(map[string]bool)
|
||||||
|
|
||||||
|
// Walk through assistants directory to find all valid assistants with models
|
||||||
|
err = application.App.Walk("assistants", func(root, file string, isdir bool) error {
|
||||||
|
if !isdir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a valid assistant directory (has package.yao)
|
||||||
|
pkgFile := filepath.Join(root, file, "package.yao")
|
||||||
|
pkgExists, _ := application.App.Exists(pkgFile)
|
||||||
|
if !pkgExists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract assistant ID from path
|
||||||
|
assistantID := strings.TrimPrefix(file, "/")
|
||||||
|
assistantID = strings.ReplaceAll(assistantID, "/", ".")
|
||||||
|
|
||||||
|
// Skip if already processed
|
||||||
|
if processedAssistants[assistantID] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
processedAssistants[assistantID] = true
|
||||||
|
|
||||||
|
log.Trace("Found assistant: %s", assistantID)
|
||||||
|
|
||||||
|
// Check if the assistant has a models directory
|
||||||
|
modelsDir := filepath.Join(root, file, "models")
|
||||||
|
modelsDirExists, _ := application.App.Exists(modelsDir)
|
||||||
|
if !modelsDirExists {
|
||||||
|
log.Trace("Assistant %s has no models directory", assistantID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("Loading models from assistant %s", assistantID)
|
||||||
|
|
||||||
|
// Load models from the assistant's models directory
|
||||||
|
exts := []string{"*.mod.yao", "*.mod.json", "*.mod.jsonc"}
|
||||||
|
err := application.App.Walk(modelsDir, func(modelRoot, modelFile string, modelIsDir bool) error {
|
||||||
|
if modelIsDir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate model ID with agents.<assistantID>./ prefix
|
||||||
|
// Support nested paths: "models/foo/bar.mod.yao" -> "foo.bar"
|
||||||
|
relPath := strings.TrimPrefix(modelFile, modelsDir+"/")
|
||||||
|
relPath = strings.TrimPrefix(relPath, "/")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mod.yao")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mod.json")
|
||||||
|
relPath = strings.TrimSuffix(relPath, ".mod.jsonc")
|
||||||
|
modelName := strings.ReplaceAll(relPath, "/", ".")
|
||||||
|
modelID := fmt.Sprintf("agents.%s.%s", assistantID, modelName)
|
||||||
|
|
||||||
|
log.Trace("Loading model %s from file %s", modelID, modelFile)
|
||||||
|
|
||||||
|
// Read and modify model to add table prefix
|
||||||
|
content, err := application.App.Read(modelFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to read model file %s: %s", modelFile, err.Error())
|
||||||
|
errs = append(errs, fmt.Errorf("failed to read model %s: %w", modelID, err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse model
|
||||||
|
var modelData map[string]interface{}
|
||||||
|
err = application.Parse(modelFile, content, &modelData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to parse model %s: %s", modelID, err.Error())
|
||||||
|
errs = append(errs, fmt.Errorf("failed to parse model %s: %w", modelID, err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set table name prefix: agents_<assistantID>_
|
||||||
|
// Convert dots to underscores: tests.mcpload -> agents_tests_mcpload_
|
||||||
|
if table, ok := modelData["table"].(map[string]interface{}); ok {
|
||||||
|
if tableName, ok := table["name"].(string); ok {
|
||||||
|
// Generate prefix from assistant ID
|
||||||
|
prefix := "agents_" + strings.ReplaceAll(assistantID, ".", "_") + "_"
|
||||||
|
|
||||||
|
// Remove any existing prefix if present
|
||||||
|
tableName = strings.TrimPrefix(tableName, "agents_mcpload_")
|
||||||
|
tableName = strings.TrimPrefix(tableName, prefix)
|
||||||
|
|
||||||
|
table["name"] = prefix + tableName
|
||||||
|
content, err = jsoniter.Marshal(modelData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to marshal model data for %s: %v", modelID, err)
|
||||||
|
errs = append(errs, fmt.Errorf("failed to marshal model %s: %w", modelID, err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load model with modified content
|
||||||
|
mod, err := model.LoadSource(content, modelID, modelFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to load model %s from assistant %s: %s", modelID, assistantID, err.Error())
|
||||||
|
errs = append(errs, fmt.Errorf("failed to load model %s: %w", modelID, err))
|
||||||
|
return nil // Continue loading other models
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto migrate the model (like system models)
|
||||||
|
err = mod.Migrate(false, model.WithDonotInsertValues(true))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to migrate model %s from assistant %s: %s", modelID, assistantID, err.Error())
|
||||||
|
errs = append(errs, fmt.Errorf("failed to migrate model %s: %w", modelID, err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Loaded and migrated model: %s", modelID)
|
||||||
|
return nil
|
||||||
|
}, exts...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("failed to walk models in assistant %s: %w", assistantID, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("failed to walk assistants directory: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// LoadDatabaseModels load database models
|
// LoadDatabaseModels load database models
|
||||||
func loadDatabaseModels() []error {
|
func loadDatabaseModels() []error {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ func check(t *testing.T) {
|
||||||
ids[id] = true
|
ids[id] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard models
|
||||||
assert.True(t, ids["user"])
|
assert.True(t, ids["user"])
|
||||||
assert.True(t, ids["category"])
|
assert.True(t, ids["category"])
|
||||||
assert.True(t, ids["tag"])
|
assert.True(t, ids["tag"])
|
||||||
|
|
@ -31,4 +32,33 @@ func check(t *testing.T) {
|
||||||
assert.True(t, ids["pet.tag"])
|
assert.True(t, ids["pet.tag"])
|
||||||
assert.True(t, ids["user.pet"])
|
assert.True(t, ids["user.pet"])
|
||||||
assert.True(t, ids["tests.user"])
|
assert.True(t, ids["tests.user"])
|
||||||
|
|
||||||
|
// Agent models
|
||||||
|
assert.True(t, ids["agents.tests.mcpload.test_record"], "Agent model agents.tests.mcpload.test_record should be loaded")
|
||||||
|
assert.True(t, ids["agents.tests.mcpload.nested.item"], "Agent nested model agents.tests.mcpload.nested.item should be loaded")
|
||||||
|
|
||||||
|
// Verify table names have correct prefix
|
||||||
|
if testRecordModel, exists := model.Models["agents.tests.mcpload.test_record"]; exists {
|
||||||
|
assert.Equal(t, "agents_tests_mcpload_test_records", testRecordModel.MetaData.Table.Name, "Table name should have agents_tests_mcpload_ prefix")
|
||||||
|
t.Logf("✓ Agent model table name: %s", testRecordModel.MetaData.Table.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nestedItemModel, exists := model.Models["agents.tests.mcpload.nested.item"]; exists {
|
||||||
|
assert.Equal(t, "agents_tests_mcpload_items", nestedItemModel.MetaData.Table.Name, "Nested model table name should have agents_tests_mcpload_ prefix")
|
||||||
|
t.Logf("✓ Nested agent model table name: %s", nestedItemModel.MetaData.Table.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log all agent models found
|
||||||
|
agentModels := []string{}
|
||||||
|
for id := range model.Models {
|
||||||
|
if len(id) >= 7 && id[:7] == "agents." {
|
||||||
|
agentModels = append(agentModels, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(agentModels) > 0 {
|
||||||
|
t.Logf("✓ Found %d agent model(s):", len(agentModels))
|
||||||
|
for _, id := range agentModels {
|
||||||
|
t.Logf(" - %s", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue