microsoft / microsoft/conductor
!file include parses YAML-shaped Markdown prompts as mappings, breaking prompt/system_prompt validation
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 448
- Forks
- 65
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 39
Description
Summary
The !file tag in src/conductor/config/loader.py (construct_file_tag) does not just read the referenced file — it attempts to parse the content as YAML and returns the parsed structure whenever it happens to be a mapping or a list:
parsed = sub_yaml.load(content)
if isinstance(parsed, (dict, list)):
return parsed
# Scalar YAML or None → return raw string content
return FileString(content, source_path=file_path)
For structured includes (tools:, output:) that is the intended behavior, but for prompt: / system_prompt: — which usually reference Markdown — it is a footgun: a Markdown prompt whose line ends with a colon followed by - bullets is a valid YAML mapping, so system_prompt: str | None rejects it.
The resulting error blames the schema value, not the include heuristic, and is very hard to trace back to the actual cause:
1 validation error for WorkflowConfig
for_each.1.agent.agent.system_prompt
Input should be a valid string [type=string_type, input_value={'Сожми changelog д...обновления.']}, input_type=dict]
(The doubled agent.agent in the path is just the discriminated-union tag from #517 — cosmetic. The heuristic itself predates the v0.1.x releases, so this reproduces on any recent version.)
Why it bites in both directions
The failure mode is silent in both directions, and an ordinary content edit can flip a file across the boundary without any config change:
- A Markdown file that is invalid YAML (e.g. contains free-floating prose paragraphs) is returned as raw text and works fine.
- Remove or reword that prose — as a normal prompt edit would — and the file can become valid YAML, at which point validation starts failing with the error above.
Observed in the wild exactly like that: a prompt file worked for weeks because a trailing paragraph made it invalid YAML; deleting that paragraph (an unrelated prompt cleanup) turned it into a valid 3-key mapping and broke conductor validate on a freshly installed build, presenting as an apparent version regression.
Reproduction
prompts/system.md.jinja:
Summarize the changelog, keeping only what affects the triage of a dependency update:
- breaking changes and migration notes;
- security fixes.
Answer in markdown:
- a short header with the package name and version range;
- one or two closing sentences on upgrade risk.
workflow.yaml:
workflow:
name: repro
entry_point: worker
agents:
- name: worker
system_prompt: !file prompts/system.md.jinja
prompt: "Summarize {{ workflow.input.text }}"
routes:
- to: $end
conductor validate workflow.yaml fails with:
agents.0.agent.system_prompt
Input should be a valid string [type=string_type, input_value={'Summarize the changelog, ...risk.']}, input_type=dict]
The Markdown parses as a two-key YAML mapping (Summarize the changelog, ... update: → list, Answer in markdown → list).
Suggested directions
Any of these would defuse the trap; they are not mutually exclusive:
- A raw-text include tag (e.g.
!rawfile) that guarantees the file content is returned verbatim, so prompt files have an include form whose type cannot silently change under them. - A targeted error message: when a string-typed field (
prompt,system_prompt,command,reason, …) receives a dict/list produced by a!fileinclude, fail with a message naming the included file and explaining the YAML heuristic — instead of a bare pydanticstring_typethat blames the user's value. - Documentation: call the heuristic out in the
!filesection ofdocs/workflow-syntax.md, including the "a prose edit can flip YAML validity" trap.
Workaround
Make the prompt file invalid as YAML — e.g. ensure it starts with a plain prose line without a colon. That forces the except YAMLError path and the raw text is returned. It works, but it is exactly as fragile as the failure it fixes: any later edit that restores YAML validity re-breaks the workflow.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/conductor/config/loader.py at construct_file_tag and reproduce the failure with the Markdown and workflow examples from the issue. Read docs/workflow-syntax.md and compare the proposed raw-text tag, targeted validation error, and documentation approaches with maintainers. Done means the YAML-shaped Markdown case no longer produces a misleading string validation failure, with the chosen behavior documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100