Skip to content

fix(macros): tool_describe must publish its descriptor for the describe fan-out#56

Merged
joshuajbouw merged 1 commit into
mainfrom
fix/tool-describe-publish
Jun 10, 2026
Merged

fix(macros): tool_describe must publish its descriptor for the describe fan-out#56
joshuajbouw merged 1 commit into
mainfrom
fix/tool-describe-publish

Conversation

@joshuajbouw

@joshuajbouw joshuajbouw commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

What & why

The #[capsule] macro auto-generates a tool_describe interceptor arm for any capsule with #[astrid::tool] methods. It built the {tools, description} descriptor and returned it as a CapsuleResult{action:"continue", ...} — but under the current ABI an interceptor's return value is no longer fanned out to the caller (the dispatcher drops a lone request handler's Continue payload). So no SDK-macro tool capsule (fs, http, identity, system, skills) ever answered the tool.v1.request.describe fan-out, and every consumer collected 0 tools: prompt-builder, registry, and the sage-mcp MCP bridge behind astrid mcp serve (tools/list returned {tools:[]} on a healthy daemon).

The hand-written LLM providers already do this correctly — astrid-capsule-openai::llm_describe ends with ipc::publish_json("llm.v1.response.describe", ...) and its doc says verbatim "the interceptor return value is no longer fanned out to the caller under the new ABI." The macro was simply never updated to match.

Fix

Publish the descriptor explicitly on tool.v1.response.describe.self before returning (the Continue return is kept for interceptor-chain semantics). One-site change that fixes every SDK-macro tool capsule at once.

Topic suffix is routing-only. Consumers subscribe tool.v1.response.describe.*; the route-layer trailing * requires ≥ 5 segments (a 4-seg unsuffixed publish would not match), and the responder's real source_id rides in the kernel-stamped message metadata (msg.source_id, which prompt-builder uses for per-source permission filtering), so a fixed self suffix is sufficient. Subscribers parse tools from the payload, not the topic. No self-id accessor exists in the SDK today.

Verification

  • cargo test -p astrid-sdk-macros — 46 pass, including the new tool_describe_publishes_response_for_fanout regression guard and capsule_without_tools_has_no_describe_publish.
  • End-to-end (local [patch.crates-io]): rebuilt astrid-capsule-fs against this branch and reinstalled it; astrid mcp servetools/list went from 0 tools to 8 — fs's full set (read_file, write_file, list_directory, grep_search, create_directory, delete_file, move_file, replace_in_file). The other tool capsules still carry the old macro and contribute nothing until rebuilt, which confirms the fan-out now works and this is the sole gating change.

Landing the full surface: merge → publish astrid-sdk to crates.io → rebuild the tool capsules.

Root-cause companion: the empty astrid mcp serve tool surface traced back here; the cli-proxy daemon-down crash and MCP publish-ACL gap on the path were fixed separately in capsule-cli #25.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the capsule_impl macro in astrid-sdk-macros/src/lib.rs to explicitly publish the tool descriptor on the tool.v1.response.describe.self topic, ensuring that tool discovery works correctly under the current ABI. It also adds corresponding regression tests. The feedback suggests logging a warning if the publish_json call fails instead of silently ignoring the error, which will help with troubleshooting IPC or host issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread astrid-sdk-macros/src/lib.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the #[capsule] macro’s auto-generated tool_describe interceptor so it explicitly publishes the tool descriptor on the describe-response IPC topic, aligning macro-generated tool capsules with the current ABI where interceptor return values are no longer fanned out to describe callers.

Changes:

  • Publish the {tools, description} descriptor to tool.v1.response.describe.self from the generated tool_describe arm (while still returning Continue for interceptor-chain semantics).
  • Add macro regression tests to ensure describe publishing occurs for tool capsules and does not occur for capsules without tools.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread astrid-sdk-macros/src/lib.rs Outdated
…be fan-out

The #[capsule] macro's auto-generated tool_describe arm built the {tools, description} descriptor and returned it as a Continue payload, but under the current ABI an interceptor's return value is not fanned out to the caller. So no SDK-macro tool capsule (fs, http, identity, system, skills) answered the tool.v1.request.describe fan-out, and every consumer — prompt-builder, registry, and the sage-mcp MCP bridge behind 'astrid mcp serve' — collected 0 tools.

Publish the descriptor explicitly on tool.v1.response.describe.self, mirroring the hand-written LLM providers that publish llm.v1.response.describe. The topic suffix is routing-only: the route layer's trailing * needs >= 5 segments, and the responder's real source_id rides in the kernel-stamped message metadata (used by prompt-builder for per-source permission filtering). The Continue return is kept for interceptor-chain semantics.

Adds a regression guard asserting the generated tool_describe arm publishes (and that a tool-less capsule emits no stray describe publish).
@joshuajbouw
joshuajbouw force-pushed the fix/tool-describe-publish branch from 9d5b1b1 to 6856cd8 Compare June 10, 2026 01:30
@joshuajbouw
joshuajbouw merged commit 18c8fbb into main Jun 10, 2026
8 checks passed
@joshuajbouw
joshuajbouw deleted the fix/tool-describe-publish branch June 10, 2026 01:43
joshuajbouw added a commit that referenced this pull request Jun 10, 2026
Rebuilt on main post-#53/#56 squash-merge: the branch previously carried its own pre-squash copy of the feature diff; now it is the bump + CHANGELOG only.

- Workspace 0.7.0 -> 0.7.1 (+ the three internal dependency pins).
- CHANGELOG: [Unreleased] -> [0.7.1] - 2026-06-10, with a release synopsis (extracted into the GitHub release body by release.yml), the previously missing Fixed entry for the #56 tool_describe fan-out fix, and PR attribution on the #53 entries.
@joshuajbouw joshuajbouw mentioned this pull request Jun 10, 2026
joshuajbouw added a commit that referenced this pull request Jun 11, 2026
## Summary

`chore: release` — bumps the workspace to **0.7.1**, the patch release
that restores capsule tool discovery (#56) and ships the post-0.7
additive surfaces (#53).

Per the repo rule, a version bump is its own PR. The branch was
originally stacked on #53; after #53 and #56 squash-merged it has been
**rebuilt on `main`** so the diff is exactly the bump + CHANGELOG.

No breaking changes — `astrid-sdk = "0.7"` consumers resolve 0.7.1
automatically once published, so capsules pick up the tool_describe fix
with a rebuild and **no** dep bump.

## Changes

- `[workspace.package].version` `0.7.0` → `0.7.1` (+ the three internal
`[workspace.dependencies]` pins: `astrid-sdk`, `astrid-sdk-macros`,
`astrid-sys`).
- CHANGELOG: `[Unreleased]` → `[0.7.1] - 2026-06-10` with:
- a release **synopsis** paragraph (release.yml extracts the whole `##
[0.7.1]` block into the GitHub release body on tag),
- the previously **missing `Fixed` entry for #56** (the tool_describe
describe-fan-out fix — the fleet-critical one),
- PR attribution on the #53 `Added` entries (`capabilities::enumerate`,
persistent-process tier).

## Release steps (maintainer)

1. Merge this PR.
2. `cargo publish` in dependency order: `astrid-sys`,
`astrid-sdk-macros`, `astrid-sdk`.
3. Tag `v0.7.1` on the merge commit → release.yml creates the GitHub
release from the CHANGELOG block.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants