Skip to content

feat: AGENTS.md prompt support (closes #732) - #1161

Closed
Cedric Vidal (cedricvidal) wants to merge 14 commits into
mainfrom
cedricvidal-microsoft/feat-agents-md-support
Closed

Cedric Vidal (cedricvidal) wants to merge 14 commits into
mainfrom
cedricvidal-microsoft/feat-agents-md-support

Conversation

@cedricvidal

Copy link
Copy Markdown
Collaborator

Original author: Cedric Vidal (@cedricvidal)

Why

Benchmark runs had no way to seed a project-level AGENTS.md instruction file into the agent's workspace. Issue #732 asks for first-class support so a run can carry an AGENTS.md that the worker writes to the workspace root before the agent starts, and so those instruction files can be managed and feature-extracted like other prompts.

This PR is the AGENTS.md slice extracted from the larger GEPA optimizer PR (#1031). It deliberately contains only the AGENTS.md feature and the size-based blob storage that underpins it. experimentId, experiment grouping, the experiment migration, and the gepa-optimizer app stay in #1031.

Video walkthrough

agents-md-walkthrough.mp4

What changed

Typed task-prompt model + agents.md type (shared). Task prompts now carry a type (PromptType = GateId | "agents.md"). AGENTS.md content is stored as an agents.md-typed task prompt, deduplicated by content via findOrCreate, so reusing the same body reuses the same prompt. Prompt-feature extraction is type-scoped (task prompts get task features; AGENTS.md prompts get agents.md features).

Size-based blob storage (shared). Prompt bodies above PROMPT_INLINE_MAX_BYTES are offloaded to blob storage with a contentBlobUrl, and resolved transparently through a /content endpoint. This is the foundation for large AGENTS.md bodies; small bodies stay inline as before.

Worker delivery. Before a run starts, the worker writes the resolved AGENTS.md to <workspace>/AGENTS.md.

Surfaces. API request handling (agentsMd resolves to an agents.md prompt) plus typed task-prompt and prompt-feature routes; CLI --agents-md run flag and type-aware task-prompt / prompt-feature commands; portal support to submit an AGENTS.md with a run, view it on a run, and manage agents.md prompts.

New Run UX. The AGENTS.md field is now discreet: hidden behind an "Add AGENTS.md" trigger that unveils a card (mirroring the existing Codebase disclosure), and it can look up an existing agents.md prompt from the library via the same picker used for task and gate prompts.

Worth a careful look

  • fix(shared): break task-prompt/prompt-feature schema import cycle (ccfce549). task-prompt.ts and prompt-feature.ts imported each other, which threw a temporal-dead-zone ReferenceError under the API's tsx runtime on boot (tsc and vitest tolerated the cycle, so it passed CI but crashed the running API). The fix extracts PromptTypeSchema into a neutral prompt-type.ts that both modules depend on, removing the back-edge. The cycle had also silently emitted an empty features.items: {} in the OpenAPI spec; it now correctly refs PromptFeatureResult (regenerated snapshot).
  • Generated snapshots (openapi-snapshot, cli-commands) were regenerated, not hand-edited.

Verification

  • pnpm -r build clean.
  • Full suite: 2294/2294 passing (182 files); portal 324/324 (added focused tests for the renamed nav, type-adaptive prompt detail heading, and the AGENTS.md library picker).
  • Guard greps over apps + packages (excluding snapshots): no experimentId / gepa / GEPA.
  • API boots cleanly and agent registration completes against the local dev stack.

Closes #732

…rage

Foundation for AGENTS.md prompt support (#732): typed task prompts ('task' | 'agents.md') with content-hash ids, size-based body storage (small bodies inline, large bodies uploaded to blob and referenced via contentBlobUrl), a prompt client/resolver, typed prompt-feature extraction, and request schema fields (agentsMd, agentsMdParentIds, agentsMdPromptId).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ature routes

Wire AGENTS.md support into the API (#732): create-request accepts agentsMd (raw text) and findOrCreates an 'agents.md'-typed prompt, storing agentsMdPromptId and agentsMdParentIds; task-prompt and prompt-feature routes become type-aware and expose a prompt content endpoint that resolves inline or blob-backed bodies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The shared queue processor resolves the agentsMdPromptId body (downloading from blob storage when needed) and writes <workspace>/AGENTS.md once before the first turn. Fails the run loudly if the prompt id is set but cannot be resolved, rather than silently running the baseline (#732).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ture commands

Add CLI parity for AGENTS.md support (#732): 'run submit --agents-md <text|@file>' submits a run with an AGENTS.md prompt, and the task-prompt and prompt-feature commands gain a --type option to manage 'agents.md' prompts alongside task prompts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add portal surfaces for AGENTS.md support (#732): an AGENTS.md field on the Submit Run page, AGENTS.md display on Run Detail, and type-aware task-prompt and prompt-feature views/pickers for 'agents.md' prompts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…h API/CLI snapshots

Document the AGENTS.md delivery flow and size-based prompt storage (PROMPT_INLINE_MAX_BYTES) in app-design.md and ENV_VARIABLES.md, and regenerate the OpenAPI and CLI command snapshots to reflect the agentsMd fields and --agents-md/--type options (#732).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
task-prompt.ts and prompt-feature.ts imported each other (task-prompt
needs PromptFeatureResultSchema; prompt-feature needs PromptTypeSchema),
forming a cycle. At ESM runtime the schemas barrel evaluates
prompt-feature first, so task-prompt's `z.array(PromptFeatureResultSchema)`
ran while the binding was still in the temporal dead zone, crashing the
API on boot with a ReferenceError. tsc and vitest tolerated the cycle, so
it only surfaced under the API's tsx runtime; under vitest the unresolved
binding also silently emitted an empty OpenAPI `features.items: {}`.

Extract PromptTypeSchema into its own neutral prompt-type.ts that both
modules depend on, removing the back-edge from prompt-feature to
task-prompt. task-prompt re-exports PromptTypeSchema so the barrel surface
and existing consumers are unchanged. Regenerate the OpenAPI snapshot,
which now correctly refs PromptFeatureResult.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…New Run

The AGENTS.md input was always rendered as a prominent 6-row textarea even
when unused. Make it discreet behind an "Add AGENTS.md" trigger that unveils
a bordered card, mirroring the existing Codebase disclosure. Inside the card,
add a TaskPromptPicker(type="agents.md") so an existing agents.md prompt can
be looked up from the prompt library, just like the Task and gate prompts;
selecting one fills the editor and the API dedups it by content on submit.

Also restore AGENTS.md when prefilling from a recent run (resolve
agentsMdPromptId to text) and surface an "AGENTS.md" chip in the settings
summary.

TaskPromptPicker previously imported the gates-only PromptType and indexed
GATE_METADATA[type] for its placeholder, which has no agents.md entry. Switch
to the broad PromptType from @/types and use promptTypeLabel(type) so the
non-gate type renders safely; identical output for gate types.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Runs submitted with an AGENTS.md create an 'agents.md' task prompt, but the
Prompt Library hid it: TaskPromptStore.getAll excludes NON_GATE_PROMPT_TYPES
from the default (unfiltered) list. That guard is right for the report-template
trigger picker, so instead of flipping the default this adds an opt-in
'includeNonGate' flag that the Prompt Library uses to list agents.md prompts
alongside task/gate prompts. The library also gains an AGENTS.md type filter and
create option; the CLI 'task-prompt list' gets a matching --include-non-gate flag.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The left-nav Library entry for /task-prompts pointed at the Prompt Library but
was labeled 'Tasks', which read as a task list. Rename it to 'Prompts' to match
the page title and the fact that it now manages task, gate, and AGENTS.md prompts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The task-prompt list previously hid non-gate types (agents.md) from the
default unfiltered list, requiring an opt-in flag to surface them. Remove
that exclusion entirely so the Prompt Library, report-template pickers,
API, and CLI always return every prompt type.

Drops the includeNonGate option/flag/query param across the store, API
route, portal client, and CLI, and regenerates the OpenAPI and CLI
snapshots accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The detail page hard-coded "Task Prompt" / "Task Text", which is wrong for
non-gate prompts such as AGENTS.md. Render the identity card title from the
prompt type (e.g. "AGENTS.md Prompt", "Select Prompt") and rename the body
card to the generic "Prompt Text".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds focused unit tests for the portal changes in the AGENTS.md feature
that previously had no coverage:

- Layout: the Library nav item is labelled 'Prompts' and links to
  /task-prompts (renamed from 'Tasks').
- TaskPromptDetail: the heading adapts to the prompt type
  ('AGENTS.md Prompt' / 'Select Prompt', legacy untyped falls back to
  'Select Prompt') and the body card is the generic 'Prompt Text'.
- TaskPromptPicker: the AGENTS.md library lookup scopes the query to
  type=agents.md, fills the field with the selected prompt text, and
  shows an empty state when there are no matches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback: the GET /task-prompts/:id/content endpoint returns any
prompt body by ID with no authorization check, consistent with the API's current
no-auth/no-tenancy model. Since prompts are globally content-addressed and
deduplicated via findOrCreate, document that this assumes a trusted-network,
single-tenant deployment and must be revisited if auth/multi-tenancy lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2036

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2287 2287 0 0 0 0 0 2m25s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2043

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2289 2289 0 0 0 0 0 2m21s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2044

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2287 2287 0 0 0 0 0 2m30s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2045

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2287 2287 0 0 0 0 0 2m20s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2046

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2294 2294 0 0 0 0 0 2m19s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: @github-actions[bot]

Test Results (Node.js 22)

test: Run #2051

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2294 2294 0 0 0 0 0 2m30s

🎉 All tests passed!

Github Test Reporter

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: Wassim Chegham (@manekinekko)

LGTM.

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: Cedric Vidal (@cedricvidal)

Original review: COMMENTED

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: Wassim Chegham (@manekinekko)

Worth a note here: this /content endpoint returns any prompt body by ID with no authorization check. That's consistent with the rest of the API (no auth/tenancy model today — index.ts is just cors() + express.json()), so it's not a regression. The thing I'd flag is that prompts are globally content-addressed and deduplicated via findOrCreate, so this route implicitly assumes a trusted-network, single-tenant deployment. Could we add a short comment on this route stating that assumption? It'll save a future reader from assuming the dedup store is tenant-safe if auth/multi-tenancy ever lands.

@cedricvidal

Copy link
Copy Markdown
Collaborator Author

Original author: Cedric Vidal (@cedricvidal)

Good call. Added a comment on the route in 61bf19e4 spelling out the trusted-network / single-tenant assumption and flagging that the content-addressed dedup store is not tenant-safe, so this must be revisited if auth/multi-tenancy ever lands. Agreed it's not a regression given the API has no auth model today.

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.

AGENTS.md support

1 participant