Repository navigation
Inject runtime parameter values into the agent prompt via ado-script (sanitization at runtime, not compile time) #432
Description
Motivation
We want authors to flag a runtime template parameter as "feed this value into the agent prompt", so its value can vary per-run (manual queue or queue-build safe output) without re-compiling the pipeline. A first attempt (#430, since reverted) put both the sanitization rules and the prompt-append logic into the Rust compiler, generating bash heredocs and validating defaults at ado-aw compile time. That coupled the security policy to compiler releases, duplicated work the runtime already has to do for queue-build-supplied values, and made the bash hard to test in isolation.
This issue tracks the redo: keep the compiler dumb (just pass values through env vars), and let the ado-script runtime bundle (the same one that ships gate-eval.py today, and prompt.js / gate.js going forward) own validation and prompt assembly.
Proposed design
Front matter (compiler)
Add an opt-in flag on PipelineParameter:
parameters:
- name: focusArea
displayName: "Focus area for this run"
type: string
default: "no specific focus"
prompt-context: trueCompiler responsibilities, and only these:
- Parse the new
prompt-context: boolfield (kebab-case,skip_serializingso it never leaks into emitted ADO YAML). - For each opted-in parameter, emit a step-level
env:mappingADO_AW_CTX_<UPPER_NAME>: ${{ parameters.<name> }}on the existing "Prepare agent prompt" step. - Emit one additional env var,
ADO_AW_PROMPT_CONTEXT_SPEC, holding a small base64-encoded JSON spec: an ordered list of{ envKey, displayName }entries plus the prompt-file path. (Mirrors theADO_AW_PROMPT_SPECpattern used byprompt.js.) - No bash generation. No
printfheredocs. No validation of default values at compile time — the runtime will validate the same way it validates queue-build-supplied parameter values.
Runtime (ado-script)
Sanitization and injection live in a new module under scripts/ado-script/src/prompt-context/ (TypeScript, NodeNext imports with .js, consistent with prompt/ and gate/). Wired into prompt.js so it runs as part of the existing prompt-render step — no new pipeline step, no extra script download.
Validation rules (applied per value at runtime; reject the run on violation):
- Bounded byte length (≤ 4 KiB) and bounded newline count (≤ 64).
- Reject ADO expression syntax:
${{,$(,$[. - Reject pipeline logging commands:
##vso[,##[. - Reject the compiler's template-marker delimiter
{{. - Reject CR and non-tab control characters.
displayName(validated when the spec is decoded) rejects",\,`,$.
On success, append a clearly delimited "Additional Run Context" section to the rendered prompt — one sub-section per non-empty value, using displayName as the header — with a preamble that explicitly tells the agent the section is untrusted user input.
Why ado-script, not the compiler
- Single source of truth for the policy: the same sanitizer that already gates queue-build parameter values can be reused, instead of two implementations drifting.
- Policy updates ship as
scripts.zipreleases (already verified viachecksums.txt+sha256sum, seesrc/compile/extensions/trigger_filters.rs:102-109); no compiler release required. - Testable in TS with the rest of the runtime; the compiler stays free of bash codegen.
- Defaults that look fine statically but resolve through ADO expression evaluation can still be caught (the runtime sees the post-evaluation string).
Acceptance criteria
-
prompt-context: trueround-trips through front-matter and is stripped from emitted YAML. - Compiled pipelines with no opted-in parameter are byte-equivalent to today's output.
- Compiled pipelines with ≥ 1 opted-in parameter add the
ADO_AW_CTX_*env vars andADO_AW_PROMPT_CONTEXT_SPECto the "Prepare agent prompt" step, with no other changes. -
prompt.jsdecodes the spec, validates each value with the rules above, and either appends the section or fails the step with a clear error. - Manual queue and queue-build paths both work end-to-end.
- Tests cover each rejection rule in TS, plus a Rust test confirming the env mapping and spec are emitted (and absent when no parameter opts in).
-
docs/parameters.md,docs/front-matter.md, anddocs/ado-script.mddescribe the feature and the runtime-side validation contract.
Out of scope
- Changing how queue-build allowlists or validates parameters (already covered by
allowed-parameters+ expression-syntax rejection). - Surfacing values to anything other than the agent prompt.
References
- Reverted attempt: commit
131c6edoncopilot/optional-context-parameter(revert in461b443). - Existing
scripts.zipdelivery pattern:src/compile/extensions/trigger_filters.rs:102-109. - Existing runtime spec-via-base64-env pattern:
prompt.jsandADO_AW_PROMPT_SPEC.
Activity