readRealmFile: fetch file-meta for .md files, raw source for everything else#5484
readRealmFile: fetch file-meta for .md files, raw source for everything else#5484lukemelia wants to merge 2 commits into
Conversation
…ng else A markdown file read now requests the indexed file-meta document, yielding the frontmatter-stripped body as the attached content plus the skill's frontmatter tools (with index-stamped definition, resolved codeRef, functionName, requiresApproval) returned structurally for the fulfillment layer. When the index can't serve a usable document — no row yet, an error-state row, or a document without content — the read degrades to raw source and returns instructions-only, so index lag never fails a read. Auth and network failures skip the fallback since raw source would fail identically. Non-markdown files keep the raw-source path byte-identical. The markdown predicate is hoisted to runtime-common (isMarkdownFile) so the host's isMarkdownSkillId, prompt assembly's isMarkdownSkillFile, and the ai-bot read path share one definition. The tool description now tells the model that reading a skill file unlocks its tools on the next turn. CS-12045 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e4c1d56 to
e782e42
Compare
Observability diff (vs staging)Show diffdiff --git a/tmp/remote-canon.v6M2Wx/dashboards/boxel-status/indexing.json b/tmp/committed-canon.qhiVzR/dashboards/boxel-status/indexing.json
index fd785f2..d7bf03e 100644
--- a/tmp/remote-canon.v6M2Wx/dashboards/boxel-status/indexing.json
+++ b/tmp/committed-canon.qhiVzR/dashboards/boxel-status/indexing.json
@@ -80,6 +80,10 @@
"uid": "cef5v5sl9k7i8f"
},
"description": "System-wide operator action: queue a full reindex across every realm. The button disables itself while a `full-reindex` orchestration job is already pending or running. Per-realm reindex moved to the Realms dashboard. Click POSTs with `Authorization: Bearer ${grafana_secret}` (substituted from SSM at apply time, CS-10929).",
+ "fieldConfig": {
+ "defaults": {},
+ "overrides": []
+ },
"gridPos": {
"h": 8,
"w": 24,
(Run: https://github.com/cardstack/boxel/actions/runs/29280170242) |
Grafana previewPreview deployed for 1 dashboard in the staging Grafana.
Dashboards: Preview is torn down automatically when this PR is closed or merged. (Run: https://github.com/cardstack/boxel/actions/runs/29280170231) |
There was a problem hiding this comment.
Pull request overview
This PR updates executeReadRealmFile (ai-bot) to treat markdown URLs specially: markdown reads prefer the indexed file-meta document (to return frontmatter-stripped body plus stamped tool metadata), while all other files continue to fetch raw source byte-identically to the prior behavior. It also centralizes “is this markdown?” detection into a shared isMarkdownFile helper in runtime-common, and wires callers to use it.
Changes:
- Add
isMarkdownFile()inpackages/runtime-common/paths.tsand switch prompt/host markdown detection to use it. - Update ai-bot
executeReadRealmFileto request file-meta for markdown, parseattributes.content+attributes.frontmatter.tools, and fall back to raw source on HTTP/unusable file-meta bodies. - Add/adjust ai-bot tests to cover markdown file-meta behavior (happy path, gating/auth flow, and fallback scenarios) and to pin the raw-source path for non-markdown URLs.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime-common/paths.ts | Introduces shared isMarkdownFile() predicate for consistent markdown detection across packages. |
| packages/runtime-common/ai/prompt.ts | Switches markdown-skill-file detection to delegate to isMarkdownFile(). |
| packages/host/app/lib/skill-tools.ts | Removes local markdown predicate and uses isMarkdownFile() for markdown skill IDs. |
| packages/ai-bot/lib/read-realm-file.ts | Implements markdown=file-meta branching + parsing + fallback behavior; extends result shape with optional tools. |
| packages/ai-bot/tests/read-realm-file-test.ts | Adds a dedicated markdown file-meta test module and updates existing tests to use a non-markdown URL for raw-source transport/auth invariants. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
typeof [] === 'object', so a malformed tools array whose entries are themselves arrays would have passed the object filter and reached the fulfillment layer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Linear: CS-12045
The pull model's second leg (independent of the index-time schema stamping — it reads whatever
frontmatter.toolsthe index serves, and behaves as today until that enrichment lands).executeReadRealmFilenow branches per URL on file type: markdown fetches the indexed file-meta document; every other file keeps requesting raw source, byte-identical to before. The auth/realm-discovery flow (header probe, delegated token, retry-on-revoke) is shared — only the Accept header and result handling differ.Behavior
Accept: application/vnd.card.file-meta+json. From the document,attributes.content(the frontmatter-stripped body) becomes the attached content — the downstream prompt-inlining path is unchanged — andattributes.frontmatter.tools(index-stampeddefinition, resolved codeRef, functionName, requiresApproval) are returned structurally on the result astoolsfor the fulfillment layer. Relative links keep absolutizing against the attachment'ssourceUrl, which remains the file URL (indexed content is as-authored).contentstring — the read degrades to the raw-source fetch and returns instructions-only. Index lag never fails a read. Auth and network failures skip the fallback: raw source would fail identically, so the error surfaces directly.isMarkdownFilelives in runtime-common (paths.ts); the host'sisMarkdownSkillId, prompt assembly'sisMarkdownSkillFile, and this read path all delegate to it.Landable before the indexer enrichment serves stamped schemas: tools simply come back absent and reads behave as today.
Testing
pnpm testin ai-bot: the newexecuteReadRealmFile markdown file-metamodule covers the happy path (body + stamped tools, single fetch), a plain markdown file (body, no tools), fallback on 404 / contentless document / non-JSON body, the gated-skill token flow on the file-meta Accept type, fallback re-running the auth flow, and no-fallback on access failure. The transport/auth-flow tests now exercise a non-markdown URL, pinning the raw-source path unchanged. 232/234 pass locally — the two failures are the pre-existing locking tests needing a CI-provisioned Postgres role, untouched by this change.🤖 Generated with Claude Code