From 029ddc95994457e0a481b1f1817ec06fe31f12fc Mon Sep 17 00:00:00 2001 From: Ranga Rao Date: Mon, 16 Feb 2026 22:53:30 -0800 Subject: [PATCH 1/2] Support `documentation` meta tag on entity/event/relationship definitions Make `documentation` a proper, externally-visible meta field by relocating meta key constants, adding an InternalMetaKeys set that excludes `documentation`, and surfacing it as a first-class field in the /meta API endpoint. User-authored documentation now takes precedence over auto-generated agent event documentation. Co-Authored-By: Claude Opus 4.6 --- src/api/http.ts | 11 +++++++++-- src/runtime/module.ts | 31 +++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/api/http.ts b/src/api/http.ts index 8e680a13..77928bbd 100644 --- a/src/api/http.ts +++ b/src/api/http.ts @@ -19,6 +19,7 @@ import { Module, getAllBetweenRelationshipNames, linkInstancesEvent, + getPublicMeta, } from '../runtime/module.js'; import { isNodeEnv } from '../utils/runtime.js'; import { parseAndEvaluateStatement, Result } from '../runtime/interpreter.js'; @@ -812,6 +813,8 @@ async function handleMetaGet(req: Request, res: Response): Promise { : rel.isOneToMany() ? 'one-to-many' : 'many-to-many', + documentation: rel.getDocumentation(), + meta: getPublicMeta(rel), }); } else if ( childNode.path.getModuleName() === moduleName && @@ -827,6 +830,8 @@ async function handleMetaGet(req: Request, res: Response): Promise { : rel.isOneToMany() ? 'one-to-many' : 'many-to-many', + documentation: rel.getDocumentation(), + meta: getPublicMeta(rel), }); } }); @@ -839,7 +844,8 @@ async function handleMetaGet(req: Request, res: Response): Promise { type: 'entity', attributes: attributes, relationships: relationships, - meta: entity instanceof Record && entity.meta ? Object.fromEntries(entity.meta) : {}, + documentation: entity instanceof Record ? entity.getDocumentation() : undefined, + meta: entity instanceof Record ? getPublicMeta(entity) : {}, }; entities.push(entityInfo); } catch (err: any) { @@ -906,7 +912,8 @@ async function handleMetaGet(req: Request, res: Response): Promise { fqName: makeFqName(moduleName, eventName), type: 'event', attributes: attributes, - meta: event instanceof Record && event.meta ? Object.fromEntries(event.meta) : {}, + documentation: event instanceof Record ? event.getDocumentation() : undefined, + meta: event instanceof Record ? getPublicMeta(event) : {}, }; events.push(eventInfo); } catch (err: any) { diff --git a/src/runtime/module.ts b/src/runtime/module.ts index 7c16d66a..c037d801 100644 --- a/src/runtime/module.ts +++ b/src/runtime/module.ts @@ -135,6 +135,16 @@ function normalizePropertyNames(props: Map) { const SystemAttributeProperty: string = 'system-attribute'; const SystemDefinedEvent = 'system-event'; const McpToolEvent = 'mcp-tool'; +const IsAgentEventMeta = 'is-agent-event'; +const EventAgentName = 'event-agent-name'; +const DocumentationMetaTag = 'documentation'; + +const InternalMetaKeys = new Set([ + IsAgentEventMeta, + EventAgentName, + SystemDefinedEvent, + McpToolEvent, +]); function asSystemAttribute(attrSpec: AttributeSpec): AttributeSpec { const props: Map = attrSpec.properties ? attrSpec.properties : new Map(); @@ -238,6 +248,15 @@ export function newMeta(): Meta { return new Map(); } +export function getPublicMeta(record: Record): { [key: string]: any } { + if (!record.meta || record.meta.size === 0) return {}; + const result: { [key: string]: any } = {}; + record.meta.forEach((v: any, k: string) => { + if (!InternalMetaKeys.has(k)) result[k] = v; + }); + return result; +} + export enum RecordType { RECORD, ENTITY, @@ -513,6 +532,10 @@ export class Record extends ModuleEntry { } } + getDocumentation(): string | undefined { + return this.getMeta(DocumentationMetaTag) as string | undefined; + } + getFullTextSearchAttributes(): string[] | undefined { let fts: string[] | string | undefined = this.getMeta('fullTextSearchAttributes'); if (!fts) { @@ -701,7 +724,7 @@ export class Record extends ModuleEntry { if (isevent && isAgentEvent(this) && toolCall) { const m = new Map(); this.meta?.forEach((v: any, k: string) => { - if (!(k === IsAgentEventMeta || k === EventAgentName || k === DocumentationMetaTag)) + if (!InternalMetaKeys.has(k)) m.set(k, v); }); if (m.size > 0) { @@ -4362,10 +4385,6 @@ export function assertInstance(obj: any) { } } -const IsAgentEventMeta = 'is-agent-event'; -const EventAgentName = 'event-agent-name'; -const DocumentationMetaTag = 'documentation'; - function markAsAgentEvent(event: Event): Event { event.addMeta(IsAgentEventMeta, 'y'); return event; @@ -4382,7 +4401,7 @@ export function defineAgentEvent(moduleName: string, agentName: string, instruct .addMeta(SystemDefinedEvent, 'true'); } markAsAgentEvent(event as Event).addMeta(EventAgentName, agentName); - if (instruction) { + if (instruction && !event.getMeta(DocumentationMetaTag)) { event.addMeta( DocumentationMetaTag, `This event will trigger an agent which has the instruction - "${instruction}". From 8e7cc9efb13bf71083102374ce048d34a7b6eaf8 Mon Sep 17 00:00:00 2001 From: Ranga Rao Date: Tue, 17 Feb 2026 10:52:31 -0800 Subject: [PATCH 2/2] Prettier fix --- src/runtime/module.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/runtime/module.ts b/src/runtime/module.ts index c037d801..1fd703ef 100644 --- a/src/runtime/module.ts +++ b/src/runtime/module.ts @@ -724,8 +724,7 @@ export class Record extends ModuleEntry { if (isevent && isAgentEvent(this) && toolCall) { const m = new Map(); this.meta?.forEach((v: any, k: string) => { - if (!InternalMetaKeys.has(k)) - m.set(k, v); + if (!InternalMetaKeys.has(k)) m.set(k, v); }); if (m.size > 0) { metaObj = Object.fromEntries(m);