microsoft / microsoft/conductor

!file include parses YAML-shaped Markdown prompts as mappings, breaking prompt/system_prompt validation

Open
#528 0 comments 0 reactions 0 assignees View on GitHub

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:

  1. 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.
  2. A targeted error message: when a string-typed field (prompt, system_prompt, command, reason, …) receives a dict/list produced by a !file include, fail with a message naming the included file and explaining the YAML heuristic — instead of a bare pydantic string_type that blames the user's value.
  3. Documentation: call the heuristic out in the !file section of docs/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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.