MCPcopy Create free account
hub / github.com/github/gh-aw / generateSamplesReplayStep

Method generateSamplesReplayStep

pkg/workflow/samples_replay.go:135–191  ·  view source on GitHub ↗

generateSamplesReplayStep emits the YAML that replaces the agentic `Execute coding agent` step when the hidden `gh aw compile --use-samples` flag is used. It spawns the safe-outputs MCP server over stdio and feeds it a `tools/call` for every collected sample, after pre-staging branches/patches for s

(yaml *strings.Builder, data *WorkflowData, logFile string)

Source from the content-addressed store, hash-verified

133// a `tools/call` for every collected sample, after pre-staging branches/patches
134// for samples that carry them.
135func (c *Compiler) generateSamplesReplayStep(yaml *strings.Builder, data *WorkflowData, logFile string) {
136 entries := collectSampleEntries(data.SafeOutputs)
137 compilerYamlLog.Printf("Generating samples replay step: entries=%d", len(entries))
138
139 // Normalize a nil slice to an empty slice so json.Marshal emits "[]" not "null".
140 // The driver rejects anything that isn't a JSON array; emitting "null" here
141 // would crash the replay step with `GH_AW_SAMPLES must be a JSON array` for
142 // workflows that opt into --use-samples but configure no samples (or whose
143 // configured samples all live on disabled handlers).
144 if entries == nil {
145 entries = []SampleEntry{}
146 }
147
148 // Serialize entries to JSON for the driver. Always emit valid JSON even when
149 // empty so the driver can produce a clear `no samples configured` message
150 // rather than crashing on an empty env var.
151 payload, err := json.Marshal(entries)
152 if err != nil {
153 // Should never happen for map[string]any payloads; fall back to empty
154 // array so the workflow still compiles and the driver reports cleanly.
155 compilerYamlLog.Printf("Warning: failed to marshal samples entries: %v", err)
156 payload = []byte("[]")
157 }
158
159 // Build the per-repo token map so apply_samples.cjs can reach repos that
160 // require a non-default token (cross-repo `checkout:` entries with their
161 // own `github-token:` or `github-app:`).
162 repoTokens := collectSampleRepoTokens(data.CheckoutConfigs)
163 repoTokensPayload := marshalRepoTokens(repoTokens)
164
165 yaml.WriteString(" - name: Replay safe-outputs samples (deterministic)\n")
166 yaml.WriteString(" id: agentic_execution\n")
167 yaml.WriteString(" env:\n")
168 yaml.WriteString(" GH_AW_SAMPLES: |\n")
169 for line := range strings.SplitSeq(string(payload), "\n") {
170 fmt.Fprintf(yaml, " %s\n", line)
171 }
172 fmt.Fprintf(yaml, " GH_AW_AGENT_STDIO_LOG: %s\n", logFile)
173 yaml.WriteString(" GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json\n")
174 yaml.WriteString(" GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl\n")
175 // GITHUB_TOKEN is the fallback used by apply_samples.cjs when resolving a
176 // pull-request head ref via the REST API for issue_comment / slash_command
177 // events. For cross-repo samples whose target repository has its own
178 // `checkout:` entry with `github-token:` or `github-app:`, the driver
179 // prefers the matching token from GH_AW_REPO_TOKENS below.
180 yaml.WriteString(" GITHUB_TOKEN: ${{ github.token }}\n")
181 if repoTokensPayload != nil {
182 yaml.WriteString(" GH_AW_REPO_TOKENS: |\n")
183 for line := range strings.SplitSeq(string(repoTokensPayload), "\n") {
184 fmt.Fprintf(yaml, " %s\n", line)
185 }
186 }
187 yaml.WriteString(" run: |\n")
188 yaml.WriteString(" set -euo pipefail\n")
189 yaml.WriteString(" mkdir -p \"$(dirname \"$GH_AW_AGENT_STDIO_LOG\")\"\n")
190 yaml.WriteString(" node \"${RUNNER_TEMP}/gh-aw/actions/apply_samples.cjs\"\n")
191}

Callers 1

Calls 4

collectSampleEntriesFunction · 0.85
collectSampleRepoTokensFunction · 0.85
marshalRepoTokensFunction · 0.85
PrintfMethod · 0.45

Tested by

no test coverage detected