From 511972c132f178b90c89670959024be56973b23d Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Thu, 9 Apr 2026 01:59:51 +0000 Subject: [PATCH 1/2] fix: bridge SchemaRegistry objects to metadata service for AI chat visibility Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/9cc89a9f-9105-4283-9392-af18ad52aa5b Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/objectql/src/plugin.ts | 44 +++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/objectql/src/plugin.ts b/packages/objectql/src/plugin.ts index c0e7e3e4c..13201128a 100644 --- a/packages/objectql/src/plugin.ts +++ b/packages/objectql/src/plugin.ts @@ -365,6 +365,9 @@ export class ObjectQLPlugin implements Plugin { * This closes the persistence loop so that user-created schemas survive * kernel cold starts and redeployments. * + * Also registers loaded objects with the metadata service so they are + * visible to tools like AI chat that query the metadata service. + * * Gracefully degrades when: * - The protocol service is unavailable (e.g., in-memory-only mode). * - `loadMetaFromDb` is not implemented by the protocol shim. @@ -387,14 +390,51 @@ export class ObjectQLPlugin implements Plugin { return; } - // Phase 2: DB hydration + // Phase 2: DB hydration (loads into SchemaRegistry) try { const { loaded, errors } = await protocol.loadMetaFromDb(); if (loaded > 0 || errors > 0) { - ctx.logger.info('Metadata restored from database', { loaded, errors }); + ctx.logger.info('Metadata restored from database to SchemaRegistry', { loaded, errors }); } else { ctx.logger.debug('No persisted metadata found in database'); + return; + } + + // Phase 3: Bridge SchemaRegistry objects to metadata service + // This ensures objects loaded from sys_metadata are visible to AI tools and other + // consumers that query via IMetadataService.listObjects() + if (loaded > 0) { + try { + const metadataService = ctx.getService('metadata'); + if (metadataService && typeof metadataService.register === 'function' && this.ql?.registry) { + const objects = this.ql.registry.getAllObjects(); + let bridged = 0; + for (const obj of objects) { + try { + // Check if object is already in metadata service to avoid duplicates + const existing = await metadataService.getObject(obj.name); + if (!existing) { + // Register object that exists in SchemaRegistry but not in metadata service + await metadataService.register('object', obj.name, obj); + bridged++; + } + } catch (e: unknown) { + ctx.logger.debug('Failed to bridge object to metadata service', { + object: obj.name, + error: e instanceof Error ? e.message : String(e), + }); + } + } + if (bridged > 0) { + ctx.logger.info('Bridged objects from SchemaRegistry to metadata service', { count: bridged }); + } + } + } catch (e: unknown) { + ctx.logger.debug('Metadata service unavailable for bridging, skipping', { + error: e instanceof Error ? e.message : String(e), + }); + } } } catch (e: unknown) { // Non-fatal: first-run or in-memory driver may not have sys_metadata yet From 862ab8e6365d9ee9b320930c48289fe4d4dc9dd6 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Thu, 9 Apr 2026 02:23:13 +0000 Subject: [PATCH 2/2] fix: bridge ALL SchemaRegistry objects to metadata service, not just DB-loaded ones Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/9416386f-16ce-4a3e-83b8-b2c80c7cc6d4 Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/objectql/src/plugin.ts | 89 ++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/packages/objectql/src/plugin.ts b/packages/objectql/src/plugin.ts index 13201128a..4fef7aabe 100644 --- a/packages/objectql/src/plugin.ts +++ b/packages/objectql/src/plugin.ts @@ -129,12 +129,16 @@ export class ObjectQLPlugin implements Plugin { // object registered by plugins (e.g., sys_user from plugin-auth). await this.syncRegisteredSchemas(ctx); + // Bridge all SchemaRegistry objects to metadata service + // This ensures AI tools and other IMetadataService consumers can see all objects + await this.bridgeObjectsToMetadataService(ctx); + // Register built-in audit hooks this.registerAuditHooks(ctx); // Register tenant isolation middleware this.registerTenantMiddleware(ctx); - + ctx.logger.info('ObjectQL engine started', { driversRegistered: this.ql?.['drivers']?.size || 0, objectsRegistered: this.ql?.registry?.getAllObjects?.()?.length || 0 @@ -365,9 +369,6 @@ export class ObjectQLPlugin implements Plugin { * This closes the persistence loop so that user-created schemas survive * kernel cold starts and redeployments. * - * Also registers loaded objects with the metadata service so they are - * visible to tools like AI chat that query the metadata service. - * * Gracefully degrades when: * - The protocol service is unavailable (e.g., in-memory-only mode). * - `loadMetaFromDb` is not implemented by the protocol shim. @@ -398,47 +399,67 @@ export class ObjectQLPlugin implements Plugin { ctx.logger.info('Metadata restored from database to SchemaRegistry', { loaded, errors }); } else { ctx.logger.debug('No persisted metadata found in database'); + } + } catch (e: unknown) { + // Non-fatal: first-run or in-memory driver may not have sys_metadata yet + ctx.logger.debug('DB metadata restore failed (non-fatal)', { + error: e instanceof Error ? e.message : String(e), + }); + } + } + + /** + * Bridge all SchemaRegistry objects to the metadata service. + * + * This ensures objects registered by plugins and loaded from sys_metadata + * are visible to AI tools and other consumers that query IMetadataService. + * + * Runs after both restoreMetadataFromDb() and syncRegisteredSchemas() to + * catch all objects in the SchemaRegistry regardless of their source. + */ + private async bridgeObjectsToMetadataService(ctx: PluginContext): Promise { + try { + const metadataService = ctx.getService('metadata'); + if (!metadataService || typeof metadataService.register !== 'function') { + ctx.logger.debug('Metadata service unavailable for bridging, skipping'); + return; + } + + if (!this.ql?.registry) { + ctx.logger.debug('SchemaRegistry unavailable for bridging, skipping'); return; } - // Phase 3: Bridge SchemaRegistry objects to metadata service - // This ensures objects loaded from sys_metadata are visible to AI tools and other - // consumers that query via IMetadataService.listObjects() - if (loaded > 0) { + const objects = this.ql.registry.getAllObjects(); + let bridged = 0; + + for (const obj of objects) { try { - const metadataService = ctx.getService('metadata'); - if (metadataService && typeof metadataService.register === 'function' && this.ql?.registry) { - const objects = this.ql.registry.getAllObjects(); - let bridged = 0; - for (const obj of objects) { - try { - // Check if object is already in metadata service to avoid duplicates - const existing = await metadataService.getObject(obj.name); - if (!existing) { - // Register object that exists in SchemaRegistry but not in metadata service - await metadataService.register('object', obj.name, obj); - bridged++; - } - } catch (e: unknown) { - ctx.logger.debug('Failed to bridge object to metadata service', { - object: obj.name, - error: e instanceof Error ? e.message : String(e), - }); - } - } - if (bridged > 0) { - ctx.logger.info('Bridged objects from SchemaRegistry to metadata service', { count: bridged }); - } + // Check if object is already in metadata service to avoid duplicates + const existing = await metadataService.getObject(obj.name); + if (!existing) { + // Register object that exists in SchemaRegistry but not in metadata service + await metadataService.register('object', obj.name, obj); + bridged++; } } catch (e: unknown) { - ctx.logger.debug('Metadata service unavailable for bridging, skipping', { + ctx.logger.debug('Failed to bridge object to metadata service', { + object: obj.name, error: e instanceof Error ? e.message : String(e), }); } } + + if (bridged > 0) { + ctx.logger.info('Bridged objects from SchemaRegistry to metadata service', { + count: bridged, + total: objects.length + }); + } else { + ctx.logger.debug('No objects needed bridging (all already in metadata service)'); + } } catch (e: unknown) { - // Non-fatal: first-run or in-memory driver may not have sys_metadata yet - ctx.logger.debug('DB metadata restore failed (non-fatal)', { + ctx.logger.debug('Failed to bridge objects to metadata service', { error: e instanceof Error ? e.message : String(e), }); }