Skip to content

T-LN3V-transclusion-rendering-in-agent-manager

State: closed/done · Impact: medium · Complexity: medium

A skill body composed from embedded notes shows those embeds as inert pills, because the Agent Manager’s editor provider implements no loadNote. Everything downstream of that one optional method is off: the transclusion body widget never mounts, and the hover preview gates itself out. Implementing it turns an embed into the content it stands for, foldable and badged with the kind of what it includes.

LocationRole today
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.tsImplements searchNotes, searchTags (empty), resolveLink and assetUrl (null). No loadNote, no searchHeadings
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.ts#agentPantsEditorProviderresolveLink returns path as the note’s route, /apps/agent-pants/notes/<vault path>, not the vault-relative path
packages/ts/obsidian-editor/src/plugins/embeds.ts#TransclusionBodyWidgetRenders the embed’s body below the line, loaded through provider.loadNote, depth 1, cached in transclusionCache
packages/ts/obsidian-editor/src/plugins/embeds.ts#TransclusionPillWidgetThe inline pill, and the whole story when the provider cannot load notes
packages/ts/obsidian-editor/src/types.ts#EditorIndexProviderloadNote? and searchHeadings? are optional; absent loadNote means embeds stay collapsed
packages/ts/obsidian-md/src/types.ts#LoadedNote{body, frontmatterYaml?} — no kind, no icon
packages/ts/markdown-ui/app/components/MdSurface.vueshowHoverPreview gates on provider.loadNote !== undefined; the surface’s own loadNote resolves null when the provider has none
packages/ts/markdown-ui/app/components/MdHoverPreview.vueSelf-gates on provider.loadNote and renders nothing without it
packages/ts/obsidian-editor/src/theme.tsStyles .cm-transclusion-embed, .cm-transclusion-pill and .cm-transclusion-missing
solutions/determined/crates/determined-core/src/wire/mod.rs#AgentSkillNoteDetailagentSkillGetNote(entry) returns the raw body and the resolved kind — everything loadNote needs

agentPantsEditorProvider implements loadNote, a real assetUrl and searchHeadings. Embeds expand inline: the body widget renders the target’s content behind a fold toggle, indented under a left rule, with a badge naming the included note’s kind. LoadedNote carries an optional kind and icon so the badge is read from what the loader returned rather than looked up a second time by the widget. The hover preview needs no work of its own — both gates read provider.loadNote, so it lights up as a consequence.

resolveLink returns the vault-relative path rather than a route. LinkResolution.path is what loadNote, searchHeadings and the hover preview all receive, and no Agent Manager page listens to MdSurface’s open-link today, so nothing is relying on the route shape.

  1. Settle the path shape first: resolveLink returns the vault-relative path, and each page’s open-link handler maps that to /apps/agent-pants/notes/<path>. Open decision inside this step: the alternative is leaving resolveLink alone and stripping the route prefix inside loadNote. Rejected — two spellings of one path is the bug this avoids.
  2. Implement loadNote(path) over agentSkillGetNote(entry), returning the raw body. Cache per path for the editor’s lifetime; the widget’s own transclusionCache handles redraw.
  3. Implement assetUrl(target, fromPath) over the note’s own resources, so an image a bundle ships renders instead of resolving missing.
  4. Implement searchHeadings(notePath, q) over the loaded body, which turns on [[Note# completion across notes.
  5. LoadedNote gains optional kind and icon in packages/ts/obsidian-md/src/types.ts; the provider fills them from AgentSkillNoteDetail.kind and the experience’s KIND_ICON.
  6. TransclusionBodyWidget: a fold toggle in a header row, a left rule and indent on the container, and the kind badge when the loaded note carried one. Style the new parts in theme.ts beside the existing .cm-transclusion-* rules, and mirror them in packages/ts/markdown-ui/app/assets/css/markdown-ui.css where the surface restyles the pill. Open decision in this step: whether the fold state is per widget instance or remembered per target. Per instance, matching every other CodeMirror widget.
  7. Add the open-link handler to the four agentPantsEditorProvider call sites — the notes page, the plugins page, the marketplace page and the wizard.
  8. Tests: an obsidian-editor test that a provider with loadNote produces a body widget and one without produces only a pill; a provider test for loadNote, assetUrl and searchHeadings.
LocationKindChange
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.tsmodifyImplement loadNote, assetUrl and searchHeadings; resolveLink returns the vault-relative path
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.test.tsmodifyCover the three new methods and the path shape
packages/ts/obsidian-md/src/types.tsmodifyLoadedNote gains optional kind and icon
packages/ts/obsidian-editor/src/plugins/embeds.tsmodifyTransclusionBodyWidget gains the fold toggle, the left rule and the kind badge
packages/ts/obsidian-editor/src/theme.tsmodifyRules for the fold header, the rule/indent and the badge
packages/ts/markdown-ui/app/assets/css/markdown-ui.cssmodifyMirror the new transclusion chrome in the surface’s own styling
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/notes/[...path].vuemodifyHandle open-link against the vault-relative path
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/plugins/[...path].vuemodifySame
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/index.vuemodifySame
solutions/determined/experiences/agent-pants/app/components/ApNewComponentWizard.vuemodifySame
packages/ts/obsidian-editor/test/modifyBody widget present with loadNote, pill only without it
  • AC-1: A skill body containing other-skill renders that note’s content below the line in the Agent Manager editor.
  • AC-2: The rendered embed carries a fold toggle; collapsing it leaves the inline pill and the document text unchanged.
  • AC-3: The embed’s header badge names the included note’s kind, and the kind comes from the LoadedNote the provider returned.
  • AC-4: Hovering a wikilink in the Agent Manager editor shows the hover-preview card, with no change to MdSurface.vue or MdHoverPreview.vue.
  • AC-5: image.png for a file the bundle carries renders the image rather than resolving missing.
  • AC-6: Typing [[other-skill# offers that note’s headings.
  • AC-7: An embed of a note that does not exist renders the missing pill and no body widget.
  • AC-8: An unedited save of a note containing an embed leaves the file’s sha unchanged.
  • Nested transclusion past depth 1. The renderer emits nested embeds as inert placeholders and that stays.
  • Editing inside an expanded embed; the body widget is read-only.
  • The Related tree over the same links (T-7UDE-related-files-tab).
  • searchTags, which still answers empty — this experience has no tag census.
  • Markdown styling beyond the transclusion chrome (T-XGF1-markdown-styling-pass).
  • none

The user’s planning request of 2026-09-07 asked for transclusions to render inline, foldable, with the kind of what they include. Member of milestone M-BMFD. solutions/agent-pants/docs/vault/reference/obsidian-transclusion.md and solutions/agent-pants/docs/vault/research/obsidian-inline-rendering.md record the behaviour being matched. The provider’s own doc comment states why assetUrl answers null today — a skill’s peer files were listed by name and never fetched — which this task changes.

Done in #2011 (commit ec8474c2b), with the kind’s icon glyph following in #2016 (commit b6f3bad04). Asserted by solutions/determined/products/agent-pants/tests/e2e/transclusion.e2e.ts.


← Back to Tasks