Skip to content

Commit d92822a

Browse files
akoclaude
andcommitted
feat(catalog): index agent-editor documents (schema v5)
Agents, AI models, knowledge bases, and consumed MCP services share one CustomBlobDocuments$CustomBlobDocument BSON wrapper, distinguished by the CustomDocumentType discriminator. The document name is a top-level field of that wrapper (not buried in the inner JSON config blob), so these are read through the raw-unit surface and decoded directly — no CatalogReader/backend change, keeping clear of the modelsdk-branch rewrite. Adds four tables (agents, ai_models, knowledge_bases, consumed_mcp_services) and unions them into the objects view (AGENT / AI_MODEL / KNOWLEDGE_BASE / CONSUMED_MCP_SERVICE). describe auto-detect resolves all four by bare name. Catalog schema bumped to v5; completes the objects index for #658. Verified against test3-app: 8 agent-editor docs across all four types; describe AgentEditorCommons.TranslationAgent round-trips. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9933725 commit d92822a

6 files changed

Lines changed: 142 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
1515
### Changed
1616

1717
- **Catalog `objects` index includes associations** — the unified `objects` view now unions the `associations` table (`ObjectType = ASSOCIATION`), so it is a complete index for the cataloged document types and consumers no longer need a separate associations query. Catalog schema bumped to v3; cached `.mxcli/catalog.db` files rebuild automatically on the next `refresh catalog`.
18-
- **Catalog indexes image collections, JavaScript actions, and data transformers** — these document types had no catalog table at all; they are now built (via the raw-unit surface, so no `CatalogReader`/backend change) into their own tables and unioned into `objects` (`IMAGE_COLLECTION`, `JAVASCRIPT_ACTION`, `DATA_TRANSFORMER`). `describe` auto-detect resolves image collections and data transformers by bare name. Catalog schema bumped to v4. (Agent-editor docs — agent/model/knowledge base/consumed MCP service — remain uncataloged: they are `CustomBlobDocument`s with the name inside a JSON blob; tracked in #658.)
18+
- **Catalog indexes image collections, JavaScript actions, and data transformers** — these document types had no catalog table at all; they are now built (via the raw-unit surface, so no `CatalogReader`/backend change) into their own tables and unioned into `objects` (`IMAGE_COLLECTION`, `JAVASCRIPT_ACTION`, `DATA_TRANSFORMER`). `describe` auto-detect resolves image collections and data transformers by bare name. Catalog schema bumped to v4.
19+
- **Catalog indexes agent-editor documents** — agents, AI models, knowledge bases, and consumed MCP services (one shared `CustomBlobDocuments$CustomBlobDocument` BSON wrapper, distinguished by `CustomDocumentType`) are now cataloged into their own tables and unioned into `objects` (`AGENT`, `AI_MODEL`, `KNOWLEDGE_BASE`, `CONSUMED_MCP_SERVICE`). The document name turned out to be a top-level wrapper field (not buried in the inner JSON blob), so this reads through the raw-unit surface with no `CatalogReader`/backend change, and `describe` auto-detect resolves all four by bare name. Catalog schema bumped to v5; this completes the `objects` index for the document types tracked in #658. (Verified against `test3-app`: 8 agent-editor docs across all four types.)
1920

2021
### Fixed
2122

cmd/mxcli/cmd_describe.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ var objectTypeToDescribe = map[string]string{
307307
"DATABASE_CONNECTION": "databaseconnection",
308308
"IMAGE_COLLECTION": "imagecollection",
309309
"DATA_TRANSFORMER": "datatransformer",
310+
"AGENT": "agent",
311+
"AI_MODEL": "model",
312+
"KNOWLEDGE_BASE": "knowledgebase",
313+
"CONSUMED_MCP_SERVICE": "consumedmcpservice",
310314
// JAVASCRIPT_ACTION is cataloged but has no `describe` CLI form, so it is
311315
// intentionally omitted from auto-detect.
312316
}

mdl/catalog/builder.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ func (b *Builder) Build(progress ProgressFunc) error {
389389
return fmt.Errorf("failed to build data transformers: %w", err)
390390
}
391391

392+
if err := b.buildAgentEditorDocs(); err != nil {
393+
return fmt.Errorf("failed to build agent-editor documents: %w", err)
394+
}
395+
392396
if err := b.buildMicroflows(); err != nil {
393397
return fmt.Errorf("failed to build microflows: %w", err)
394398
}

mdl/catalog/builder_agenteditor.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package catalog
4+
5+
import (
6+
"database/sql"
7+
8+
"go.mongodb.org/mongo-driver/bson"
9+
)
10+
11+
// agentEditorTable maps a CustomBlobDocument's CustomDocumentType to its catalog
12+
// table. The four agent-editor document types share one BSON wrapper
13+
// (CustomBlobDocuments$CustomBlobDocument) and are distinguished by this field.
14+
var agentEditorTable = map[string]string{
15+
"agenteditor.agent": "agents",
16+
"agenteditor.model": "ai_models",
17+
"agenteditor.knowledgebase": "knowledge_bases",
18+
"agenteditor.consumedMCPService": "consumed_mcp_services",
19+
}
20+
21+
// buildAgentEditorDocs catalogs the agent-editor documents (agent / model /
22+
// knowledge base / consumed MCP service). The document name is a top-level field
23+
// of the BSON wrapper (the type-specific config lives in the inner JSON blob,
24+
// which the catalog does not need), so this reads through the raw-unit surface
25+
// and decodes only the wrapper fields — no CatalogReader/backend change.
26+
func (b *Builder) buildAgentEditorDocs() error {
27+
units, err := b.reader.ListRawUnitsByType("CustomBlobDocuments$CustomBlobDocument")
28+
if err != nil {
29+
return err
30+
}
31+
32+
stmts := map[string]*sql.Stmt{}
33+
defer func() {
34+
for _, s := range stmts {
35+
s.Close()
36+
}
37+
}()
38+
stmtFor := func(table string) (*sql.Stmt, error) {
39+
if s, ok := stmts[table]; ok {
40+
return s, nil
41+
}
42+
s, err := b.tx.Prepare("INSERT INTO " + table + "_data " +
43+
"(Id, Name, QualifiedName, ModuleName, Folder, Description, ProjectId, SnapshotId) " +
44+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
45+
if err != nil {
46+
return nil, err
47+
}
48+
stmts[table] = s
49+
return s, nil
50+
}
51+
52+
projectID, snapshotID := b.snapshotMeta()
53+
54+
count := 0
55+
for _, u := range units {
56+
var doc struct {
57+
Name string `bson:"Name"`
58+
Documentation string `bson:"Documentation"`
59+
CustomDocumentType string `bson:"CustomDocumentType"`
60+
}
61+
if err := bson.Unmarshal(u.Contents, &doc); err != nil || doc.Name == "" {
62+
continue
63+
}
64+
table, ok := agentEditorTable[doc.CustomDocumentType]
65+
if !ok {
66+
continue // not an agent-editor document type we catalog
67+
}
68+
stmt, err := stmtFor(table)
69+
if err != nil {
70+
return err
71+
}
72+
moduleID := b.hierarchy.findModuleID(u.ContainerID)
73+
moduleName := b.hierarchy.getModuleName(moduleID)
74+
qualifiedName := moduleName + "." + doc.Name
75+
folderPath := b.hierarchy.buildFolderPath(u.ContainerID)
76+
77+
if _, err := stmt.Exec(
78+
string(u.ID), doc.Name, qualifiedName, moduleName, folderPath,
79+
doc.Documentation, projectID, snapshotID,
80+
); err != nil {
81+
return err
82+
}
83+
count++
84+
}
85+
86+
b.report("Agent-editor documents", count)
87+
return nil
88+
}

mdl/catalog/catalog_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ func TestObjectsView_IncludesNewDocumentTypes(t *testing.T) {
189189
{"javascript_actions", "JAVASCRIPT_ACTION"},
190190
{"image_collections", "IMAGE_COLLECTION"},
191191
{"data_transformers", "DATA_TRANSFORMER"},
192+
{"agents", "AGENT"},
193+
{"ai_models", "AI_MODEL"},
194+
{"knowledge_bases", "KNOWLEDGE_BASE"},
195+
{"consumed_mcp_services", "CONSUMED_MCP_SERVICE"},
192196
}
193197
for _, tc := range cases {
194198
t.Run(tc.objectType, func(t *testing.T) {

mdl/catalog/tables.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ package catalog
1212
// SnapshotSource / SourceId / SourceBranch / SourceRevision columns
1313
// from every row (issue #576).
1414
// 1 — initial flat schema with denormalized snapshot columns on every row.
15-
const CatalogSchemaVersion = "4"
15+
const CatalogSchemaVersion = "5"
1616

1717
// MetaSchemaVersion is the catalog_meta key that records the schema version
1818
// the cache was built against.
@@ -284,6 +284,29 @@ func (c *Catalog) createTables() error {
284284
)`,
285285
viewWithFullSnapshot("data_transformers"),
286286

287+
// agent-editor documents (CustomBlobDocuments, discriminated by
288+
// CustomDocumentType into agent / model / knowledge base / MCP service).
289+
`CREATE TABLE IF NOT EXISTS agents_data (
290+
Id TEXT PRIMARY KEY, Name TEXT, QualifiedName TEXT, ModuleName TEXT,
291+
Folder TEXT, Description TEXT, ProjectId TEXT, SnapshotId TEXT
292+
)`,
293+
viewWithFullSnapshot("agents"),
294+
`CREATE TABLE IF NOT EXISTS ai_models_data (
295+
Id TEXT PRIMARY KEY, Name TEXT, QualifiedName TEXT, ModuleName TEXT,
296+
Folder TEXT, Description TEXT, ProjectId TEXT, SnapshotId TEXT
297+
)`,
298+
viewWithFullSnapshot("ai_models"),
299+
`CREATE TABLE IF NOT EXISTS knowledge_bases_data (
300+
Id TEXT PRIMARY KEY, Name TEXT, QualifiedName TEXT, ModuleName TEXT,
301+
Folder TEXT, Description TEXT, ProjectId TEXT, SnapshotId TEXT
302+
)`,
303+
viewWithFullSnapshot("knowledge_bases"),
304+
`CREATE TABLE IF NOT EXISTS consumed_mcp_services_data (
305+
Id TEXT PRIMARY KEY, Name TEXT, QualifiedName TEXT, ModuleName TEXT,
306+
Folder TEXT, Description TEXT, ProjectId TEXT, SnapshotId TEXT
307+
)`,
308+
viewWithFullSnapshot("consumed_mcp_services"),
309+
287310
// activities
288311
`CREATE TABLE IF NOT EXISTS activities_data (
289312
Id TEXT PRIMARY KEY,
@@ -858,6 +881,22 @@ func (c *Catalog) createTables() error {
858881
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
859882
FROM data_transformers
860883
UNION ALL
884+
SELECT Id, 'AGENT' as ObjectType, Name, QualifiedName, ModuleName, Folder, Description,
885+
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
886+
FROM agents
887+
UNION ALL
888+
SELECT Id, 'AI_MODEL' as ObjectType, Name, QualifiedName, ModuleName, Folder, Description,
889+
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
890+
FROM ai_models
891+
UNION ALL
892+
SELECT Id, 'KNOWLEDGE_BASE' as ObjectType, Name, QualifiedName, ModuleName, Folder, Description,
893+
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
894+
FROM knowledge_bases
895+
UNION ALL
896+
SELECT Id, 'CONSUMED_MCP_SERVICE' as ObjectType, Name, QualifiedName, ModuleName, Folder, Description,
897+
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
898+
FROM consumed_mcp_services
899+
UNION ALL
861900
SELECT Id, 'ODATA_CLIENT' as ObjectType, Name, QualifiedName, ModuleName, '' as Folder, '' as Description,
862901
ProjectId, ProjectName, SnapshotId, SnapshotDate, SnapshotSource
863902
FROM odata_clients

0 commit comments

Comments
 (0)