Skip to content

feat(agents): serve a Fabric agent manifest at GET /manifest - #1174

Draft
marcusds wants to merge 1 commit into
mainfrom
astd-382-fabric-agent-manifest/mschwab
Draft

feat(agents): serve a Fabric agent manifest at GET /manifest#1174
marcusds wants to merge 1 commit into
mainfrom
astd-382-fabric-agent-manifest/mschwab

Conversation

@marcusds

@marcusds marcusds commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

A Fabric agent server exposes only /health and /v1/chat/completions, so anything driving it — Studio, eval, intake — has to guess the contract it must respect. This adds GET /manifest, an allowlist projection of the AgentConfig the server already holds in app.state, describing the agent's operational contract.

Groundwork for external agents on Fabric (ASTD-314): once an agent can describe itself, registering one by URL can discover it instead of asking the user to type everything. Nothing consumes the endpoint yet — that is ASTD-383.

Related Issue

ASTD-382 (Linear). Parent: ASTD-314.

Changes

  • fabric/manifest.py (new) — manifest models and build_agent_manifest(). Pure read model over AgentConfig, no I/O.
  • fabric/server.py — builds the manifest once during lifespan startup, serves it at GET /manifest.
  • fabric/serving_models.pySESSION_ID_HEADER moved here so the manifest and the server can both read it without an import cycle. server.SESSION_ID_HEADER still resolves via re-export, so existing imports are unchanged.
  • tests/unit/test_fabric_manifest.py (new) — 13 tests.

What the manifest carries, and why

Descriptive fields are the cheap part. These are the ones the platform gets wrong when it has to guess:

  • environment.workspace_scopeopen_session passes the same base_dir to ensure_local_workspace_dir and fabric.start_runtime on every session, so one workspace is shared by all of them. Reported as agent scope, which tells a caller invocations are not isolated. An eval that doesn't know this lets row 1 leak into row 200 and reads the result as variance.
  • serving.max_concurrent_invocations — surfaces the semaphore FabricSessionManager already enforces, so a caller can size its batch instead of queueing or tripping the 503 path.
  • telemetry.emits — keeps intake from double-instrumenting an agent that already ships ATIF.
  • agent.revision — content hash, so a consumer can tell whether the agent changed underneath a set of results.
  • tunable — knob names for nemo-optimization (prompt keys, harness settings keys). Names only.

Two shape notes: workspace_scope is an enum rather than a stateful bool because scope is a fact about the server that survives Fabric gaining per-session environments, where a bool would need redefining. And models includes harness-level models as harness:<name> — the common agent (including this repo's own fixture) declares no top-level models at all, so reading only config.models would report zero.

Redaction

The route is unauthenticated, so this is an allowlist, never a model_dump(). Excluded: api_key_env, base_url, McpServerConfig.url/.env, prompts values, instructions.system.content, and host filesystem paths (skills are emitted as basenames).

revision hashes the redacted projection rather than the raw config, so the fingerprint cannot become a side channel on the values it omits.

Two test layers back this: one sentinel value is planted in every dangerous config slot and asserted absent from the serialized manifest; and test_every_agent_config_field_is_classified walks AgentConfig.model_fields against projected/redacted sets, so a newly added config field fails the suite until someone classifies it.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with documentation updates
  • Documentation only
  • Contributor tooling or automation
  • CI, build, or test infrastructure

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Documentation updated for user-visible behavior
  • Documentation not applicable — justification: the endpoint has no consumer yet; user-facing docs land with ASTD-383, which is what actually surfaces it.

Verification

  • Pull request title follows the repository's Conventional Commit format
  • Every commit includes an appropriate Signed-off-by: trailer
  • uv run pre-commit run -a passes, or any blocked checks are identified below
  • Targeted tests pass, or tests are marked not applicable above
  • No secrets, API keys, or credentials are included

Targeted validation:

  • pytest plugins/nemo-agents/tests/unit/test_fabric_manifest.py plugins/nemo-agents/tests/unit/test_fabric_server.py39 passed
  • pytest plugins/nemo-agents/tests/unit988 passed, 3 failed. All three failures (test_optimize_submit_targets_agents_route, test_deployments_list_defaults_to_table, test_jobs_discovered_via_entry_points) are pre-existing and caused by nemo_optimization not being installed in this venv — confirmed by re-running them with this branch's changes stashed and getting the identical three. test_service.py fails collection for the same reason, also pre-existing.
  • ruff check and ruff format --check on the changed paths → clean
  • ty check on the changed paths → clean
  • uv run pre-commit run -a was not run repo-wide. Pre-commit ran at commit time over the changed files: ruff, ruff format, ty, copyright headers, plugin-import check, merge-conflict check — all passed.

Summary by CodeRabbit

  • New Features

    • Added a public agent manifest describing runtime, serving, capabilities, models, telemetry, and configurable settings.
    • Added a GET /manifest endpoint for retrieving the manifest.
    • Included stable revision identifiers and redaction of sensitive configuration details.
    • Standardized the session ID header as X-Nemo-Session-Id.
  • Tests

    • Added coverage for manifest generation, security redaction, revision stability, and endpoint responses.

A Fabric agent server exposes only /health and /v1/chat/completions, so a
caller has no way to learn the contract it must respect. Add /manifest: an
allowlist projection of the AgentConfig already loaded into app.state.

The manifest carries what the platform otherwise has to guess. Sessions all
share one workspace directory (open_session passes the same base_dir every
time), so workspace_scope reports "agent" and callers know invocations are
not isolated. max_concurrent_invocations exposes the semaphore the server
already enforces. telemetry.emits keeps intake from double-instrumenting an
agent that already ships traces. agent.revision fingerprints the projection
so a consumer can tell whether the agent changed under a set of results.

The route is unauthenticated, so a config field reaches the manifest only by
being named: no api_key_env, base_url, MCP url/env, prompt values, system
instruction, or host paths. The revision hashes the redacted projection
rather than the raw config, so it cannot become a side channel on the values
it omits. A test walks AgentConfig.model_fields against projected/redacted
sets, so a newly added config field fails the suite until it is classified.

SESSION_ID_HEADER moves to serving_models so both the manifest and the
server can read it without an import cycle; server re-exports it.

ASTD-382

Signed-off-by: mschwab <mschwab@nvidia.com>
@github-actions github-actions Bot added the feat label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 31466/40086 78.5% 63.1%
Integration Tests 18326/38038 48.2% 20.8%

@marcusds
marcusds marked this pull request as ready for review August 8, 2026 00:13
@marcusds
marcusds requested review from a team as code owners August 8, 2026 00:13
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3a6498b5-ef29-43d2-b4b6-4e13a6b194f1

📥 Commits

Reviewing files that changed from the base of the PR and between 8944625 and df8998e.

📒 Files selected for processing (4)
  • plugins/nemo-agents/src/nemo_agents_plugin/fabric/manifest.py
  • plugins/nemo-agents/src/nemo_agents_plugin/fabric/server.py
  • plugins/nemo-agents/src/nemo_agents_plugin/fabric/serving_models.py
  • plugins/nemo-agents/tests/unit/test_fabric_manifest.py

📝 Walkthrough

Walkthrough

Changes

Fabric agent manifest

Layer / File(s) Summary
Manifest contract and projection
plugins/nemo-agents/src/nemo_agents_plugin/fabric/manifest.py
Defines public Pydantic manifest models. Projects redacted configuration, capabilities, models, telemetry, tunables, runtime data, and deterministic revisions.
Startup construction and HTTP endpoint
plugins/nemo-agents/src/nemo_agents_plugin/fabric/server.py, plugins/nemo-agents/src/nemo_agents_plugin/fabric/serving_models.py
Builds and stores the manifest during startup. Adds GET /manifest and centralizes SESSION_ID_HEADER.
Manifest behavior validation
plugins/nemo-agents/tests/unit/test_fabric_manifest.py
Tests projections, redaction, revision stability, configuration classification, and endpoint responses.

Sequence Diagram(s)

sequenceDiagram
  participant FabricServer
  participant AgentConfig
  participant FabricClient
  FabricServer->>AgentConfig: load configuration during startup
  FabricServer->>FabricServer: build and store AgentManifest
  FabricClient->>FabricServer: GET /manifest
  FabricServer-->>FabricClient: AgentManifest response
Loading

Possibly related PRs

Suggested reviewers: mikeknep, tylersbray, ajaythorve

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: serving a Fabric agent manifest through GET /manifest.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch astd-382-fabric-agent-manifest/mschwab

Comment @coderabbitai help to get the list of available commands.

@marcusds
marcusds marked this pull request as draft August 10, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant