Refactor repo memory prompt generation to use template files#17544
Refactor repo memory prompt generation to use template files#17544
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors the repo memory prompt generation from inline Go string construction to template files following the established pattern used by other prompts (like cache memory). The refactoring moves prompt content into two new template files (repo_memory_prompt.md for single default memory and repo_memory_prompt_multi.md for multiple/non-default memories) with placeholder substitution via environment variables.
Changes:
- Created template files for repo memory prompts with
__GH_AW_*__placeholder pattern - Refactored
buildRepoMemoryPromptSection()to returnPromptSectionwith template file reference and environment variables - Updated all tests to verify template file references and environment variable values instead of inline content
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
actions/setup/md/repo_memory_prompt.md |
New template for single default memory with placeholders for dir, description, branch, target repo, and constraints |
actions/setup/md/repo_memory_prompt_multi.md |
New template for multiple memories with placeholders for memory list and allowed extensions |
pkg/workflow/sh.go |
Added constants for new template file names |
pkg/workflow/repo_memory_prompt.go |
Refactored to build PromptSection with EnvVars map instead of inline string building |
pkg/workflow/unified_prompt_step.go |
Updated to use new function signature returning PromptSection pointer |
pkg/workflow/*_test.go (multiple) |
Updated assertions to check template file references and EnvVars instead of content |
.github/workflows/*.lock.yml (multiple) |
Regenerated lock files showing template file references and environment variables |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - **Automatic Push**: Changes are automatically committed and pushed after the workflow completes | ||
| - **Merge Strategy**: In case of conflicts, your changes (current version) win | ||
| - **Persistence**: Files persist across workflow runs via git branch storage | ||
| - **Allowed File Types**: Only the following file extensions are allowed: `__GH_AW_MEMORY_ALLOWED_EXTENSIONS__`. Files with other extensions will be rejected during validation. |
There was a problem hiding this comment.
The multi-memory template produces incorrect output when allowed-extensions is empty (which means all files are allowed).
When AllowedExtensions is an empty slice (the default value per constants.DefaultAllowedMemoryExtensions), the allowedExtsText variable becomes an empty string. This causes the template to render as:
- **Allowed File Types**: Only the following file extensions are allowed: ``. Files with other extensions will be rejected during validation.This is misleading because:
- The empty backticks look like a rendering error
- It states files will be "rejected during validation" when in fact NO validation step is emitted for empty allowed-extensions (per the comment in constants.go: "When this is empty, the validation step is not emitted")
The template should handle the empty case explicitly, similar to how it's done for constraints. Consider adding conditional text based on whether the extensions list is empty or not.
| - **Automatic Push**: Changes are automatically committed and pushed after the workflow completes | ||
| - **Merge Strategy**: In case of conflicts, your changes (current version) win | ||
| - **Persistence**: Files persist across workflow runs via git branch storage | ||
| - **Allowed File Types**: Only the following file extensions are allowed: `.json`, `.jsonl`, `.txt`, `.md`, `.csv`. Files with other extensions will be rejected during validation.__GH_AW_MEMORY_CONSTRAINTS__ |
There was a problem hiding this comment.
The single default memory template hardcodes the allowed file extensions as .json, .jsonl, .txt, .md, .csv, but this list should be dynamic based on the actual AllowedExtensions configuration.
If a workflow defines custom allowed-extensions for the default memory, this hardcoded list will be incorrect and misleading to the agent. The template should use a placeholder like __GH_AW_MEMORY_ALLOWED_EXTENSIONS__ instead of hardcoding the list, similar to how the multi-memory template handles it.
Additionally, the same empty-extensions issue exists here: if allowed-extensions is empty (meaning all files are allowed), the hardcoded list is incorrect.
| - **Allowed File Types**: Only the following file extensions are allowed: `.json`, `.jsonl`, `.txt`, `.md`, `.csv`. Files with other extensions will be rejected during validation.__GH_AW_MEMORY_CONSTRAINTS__ | |
| - **Allowed File Types**: Allowed file extensions are: __GH_AW_MEMORY_ALLOWED_EXTENSIONS__. If this list is empty, all file types are allowed and no extension-based validation will be applied.__GH_AW_MEMORY_CONSTRAINTS__ |
The compiler was building the repo memory prompt by constructing strings inline in Go code, unlike every other built-in prompt section which uses runtime template files in
actions/setup/md/with__GH_AW_*__placeholder substitutions.Changes
New template files (
actions/setup/md/)repo_memory_prompt.md— single default memory; placeholders:__GH_AW_MEMORY_DIR__,__GH_AW_MEMORY_DESCRIPTION__,__GH_AW_MEMORY_BRANCH_NAME__,__GH_AW_MEMORY_TARGET_REPO__,__GH_AW_MEMORY_CONSTRAINTS__repo_memory_prompt_multi.md— multiple/non-default memories; placeholders:__GH_AW_MEMORY_LIST__,__GH_AW_MEMORY_ALLOWED_EXTENSIONS__pkg/workflow/sh.goAdded
repoMemoryPromptFile/repoMemoryPromptMultiFileconstants alongside the existing cache memory constants.pkg/workflow/repo_memory_prompt.goReplaced
generateRepoMemoryPromptSection(*strings.Builder, *RepoMemoryConfig)withbuildRepoMemoryPromptSection(*RepoMemoryConfig) *PromptSection— same signature pattern asbuildCacheMemoryPromptSection. The function now returns aPromptSectionwithIsFile: trueand anEnvVarsmap driving the substitution step.pkg/workflow/unified_prompt_step.goUpdated
collectPromptSectionsto callbuildRepoMemoryPromptSectionand append its result directly, replacing the inline string-builder call.Tests
Updated unit and integration tests to assert on template file references and
EnvVarsvalues rather than the previously-inlined prompt text.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/graphql/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw -embedcfg /tmp/go-build3430076369/b333/embedcfg -pack(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw all("session") aapi(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha graphql -f 3173766/b357/vet.cfg -f owner=github -f /usr/bin/gh api graphql -f /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile -f owner=github -f /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile(http block)/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha source '/home/REDACTED/work/gh-aw/gh-aw/actions/setup/sh/sanitize_path.sh' ':/usr/bin:/usr/local/bgit git /usr/bin/git /home/REDACTED/worgit config 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git /home/REDACTED/worgit .cfg /opt/hostedtoolc--show-toplevel git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/11bd71901bbe5b1630ceea73d27597364c9af683/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/11bd71901bbe5b1630ceea73d27597364c9af683 --jq .object.sha js/**/*.json' --ignore-path ../../../.prettierignore(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha g_.a ../../../**/*.json x_amd64/vet --ignore-path ole x_amd64/vet x_amd64/vet api VAyE7WnBC -f(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha ithub-script/git/ref/tags/v8 64/pkg/tool/linu-importcfg /usr/bin/git k/gh-aw/gh-aw/.ggit(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha auto-triage-issues.md x_amd64/vet /usr/bin/git re(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha /home/REDACTED/work/gh-aw/gh-aw/.g-test.timeout=10m0s rev-parse /usr/bin/infocmp it}(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha y Initial commit /usr/bin/git --noprofile(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha 3661553735/.github/workflows -extld=gcc /home/REDACTED/work/gh-aw/gh-aw/actions/setup/node_modules/.bin/node l(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha o stmain.go clusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle th .prettierignobash(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel /opt/hostedtoolcrev-parse /usr/bin/git -unreachable=falgit /tmp/go-build259rev-parse 5343992/b306/vet--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolc/home/REDACTED/work/gh-aw/gh-aw/pkg/cli/actionlint.go /usr/bin/gh rite '**/*.cjs' git /tmp/go-build259rev-parse k/node_modules/.--show-toplevel gh(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha js/**/*.json' --ignore-path ../../../.prettierignore(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v7/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha ry on_test.go x_amd64/vet r(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha get .cfg 64/pkg/tool/linux_amd64/vet user.name(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha ../pkg/workflow/js/**/*.json' --ignore-path ../../../.prettierignore --hidden de/node/bin/bash !.git --with-filename cacheMemoryPrompgraphql ache/go/1.25.0/x-f(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha php-fpm8.3 php8.3 ules/.bin/sh(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -c=4 -nolocalimports -importcfg /tmp/go-build2703173766/b394/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil.go /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil_test.go(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/4dc6199c7b1a012772edbd06daecab0f50c9053c/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/4dc6199c7b1a012772edbd06daecab0f50c9053c --jq .object.sha get .cfg odules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin/sh user.name(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha auto-triage-issues.md x_amd64/vet 3173766/b123=> re b/gh-aw/cmd/gh-arev-parse 64/pkg/tool/linu--show-toplevel git -C runs/20260221-182210-15290/test-2821475200/.github/workflows config /usr/bin/git remote.origin.urgit .cfg 64/pkg/tool/linu--show-toplevel 3173766/b123/importcfg(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha --show-toplevel git /usr/bin/git 15 rev-parse 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git g_.a config 0/x64/bin/node git(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v5 --jq .object.sha -prompt(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v5 --jq .object.sha submodules | hea!../../../pkg/workflow/js/**/*.json(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha at.Core.RunCommandLinux.slice(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha js/**/*.json' ---n1 g/workflow/repo_--format=format:%H %ct %D 64/pkg/tool/linu08c42ca8c73b4c0d6c70880cc312945f713dfa01(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha /home/REDACTED/work/gh-aw/gh-aw/.github/workflows config /usr/bin/git remote.origin.urgit(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha --show-toplevel ortcfg /usr/bin/git edcfg -f /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git /home/REDACTED/worgit config /usr/bin/git git(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha --local .cfg r: $owner, name:-f(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha on' --ignore-pat-f .cfg _modules/.bin/sh-f(http block)https://api.github.com/repos/anchore/sbom-action/git/ref/tags/v0/usr/bin/gh gh api /repos/anchore/sbom-action/git/ref/tags/v0 --jq .object.sha get .cfg $name) { hasDiscussionsEnabled } } credential.userngit(http block)/usr/bin/gh gh api /repos/anchore/sbom-action/git/ref/tags/v0 --jq .object.sha get .cfg 64/pkg/tool/linux_amd64/vet user.name(http block)https://api.github.com/repos/docker/build-push-action/git/ref/tags/v6/usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v6 --jq .object.sha g_.a --local $name) { hasDiscussionsEnabled } } credential.usern/usr/bin/gh ire(http block)/usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v6 --jq .object.sha get --local rompt|TestGenerateUnified|TestBuildRepoMemory|TestBuildCacheMemory|TestRepoMemoryPrompt user.name(http block)https://api.github.com/repos/docker/login-action/git/ref/tags/v3/usr/bin/gh gh api /repos/docker/login-action/git/ref/tags/v3 --jq .object.sha k/gh-aw/gh-aw/pkremote.origin.url .cfg _modules/.bin/sh credential.usern/usr/bin/gh(http block)/usr/bin/gh gh api /repos/docker/login-action/git/ref/tags/v3 --jq .object.sha get .cfg 64/pkg/tool/linu-f user.name(http block)https://api.github.com/repos/docker/metadata-action/git/ref/tags/v5/usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v5 --jq .object.sha ationAndTemplateremote.origin.url .cfg sh user.name(http block)/usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v5 --jq .object.sha get .cfg 64/pkg/tool/linux_amd64/vet user.email(http block)https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v3/usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha ./cmd/gh-aw --local 64/pkg/tool/linux_amd64/vet credential.userngit(http block)/usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha get .cfg $name) { hasDiscussionsEnabled } } user.name(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1 -buildtags repository(owner: $owner, name:-lang=go1.25 -errorsas -ifaceassert -nilfunc bash --no�� --noprofile -tests(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 -buildtags /opt/hostedtoolcache/go/1.25.0/x64/bin/bash -errorsas -ifaceassert -nilfunc bash --no�� ithub/workflows -tests /snap/bin/sh(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 -buildtags /opt/hostedtoolcache/node/24.13.-nilfunc -errorsas -ifaceassert -nilfunc bash --no�� ithub/workflows -tests(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2 -buildtags x_amd64/link -errorsas -ifaceassert -nilfunc x_amd64/link --no�� tags/v6 -tests /home/REDACTED/wor-test.short=true ./../.prettieriggit(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3 -buildtags /usr/local/sbin/bash -errorsas -ifaceassert ed } } bash --no�� ithub/workflows -tests /usr/bin/sh ./../.prettieriggit %H %ct %D(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4 -buildtags /usr/local/bin/bash -errorsas -ifaceassert ode-gyp-bin/sh bash --no�� ub/workflows 6c70880cc312945f713dfa01:go.mod /opt/hostedtoolcache/node/24.13.-importcfg ./../.prettieriggit(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5 -buildtags me: String!) { repository(owne-lang=go1.24 -errorsas -ifaceassert -nilfunc ache/go/1.25.0/x64/pkg/tool/linuconfig --no�� ub/workflows -tests(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path ../pkg/workflow/-f(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 -ifaceassert -nilfunc x_amd64/vet k/gh�� ithub/workflows on(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/a70c5eada06553e3510ac27f2c3bda9d3705bccb/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/a70c5eada06553e3510ac27f2c3bda9d3705bccb --jq .object.sha ath ../../../.prettierignore(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha ithub/workflows on rkflow/js/**/*.json /../../.prettiergit erignore de/node/bin/git bash --no�� k/gh-aw/gh-aw/.github/workflows(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha test/concurrent-image:v1.0.0 x_amd64/vet /usr/bin/git te '../../../**/git(http block)https://api.github.com/repos/githubnext/agentics/git/ref/tags//usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/# --jq .object.sha submodules | head -n 10(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -stringintconv on me: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } /../../.prettiernode erignore ed } } bash --no�� 959200168/.github/workflows(http block)/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git rev-�� --show-toplevel -tests /usr/bin/git 2821475200/.githgit /home/REDACTED/wordiff /home/node_modul--name-only git(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion rkflow/js/**/*.jgit -ifaceassert erignore ache/go/1.25.0/xtest@example.com estl�� ithub/workflows -tests /home/REDACTED/node_modules/.bin/sh ndLinux.slice(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo .cfg(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 0/x64/bin/bash(http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build2703173766/b380/cli.test /tmp/go-build2703173766/b380/cli.test -test.testlogfile=/tmp/go-build2703173766/b380/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true --hidden --glob !.git 64/pkg/tool/linu--jq(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name ../pkg/workflow/js/**/*.json' --ignore-path ../../../.prettierignore(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.