feat: add effective token template expressions to all footer templates#24150
feat: add effective token template expressions to all footer templates#24150
Conversation
…er template contexts
- In getFooterMessage(): add effectiveTokensFormatted to template context so custom
templates can use {effective_tokens_formatted} (compact form like "1.2K")
- In getFooterWorkflowRecompileMessage/Comment: read GH_AW_EFFECTIVE_TOKENS from env
and add both {effective_tokens} and {effective_tokens_formatted} to template context
- In getFooterAgentFailureIssueMessage/Comment: same - read from env and add to context
- Update messages_core.cjs supported placeholders comment
- Update docs/reference/safe-outputs.md variables list and add description
- Update docs/reference/footers.md to mention the new template expressions
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e681e19e-5f30-4dd7-843b-8ac437940a6b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Address code review feedback: replace duplicated effective tokens reading pattern across four footer functions with a shared getEffectiveTokensFromEnv() helper that properly uses isNaN() instead of parseInt || 0 fallback. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e681e19e-5f30-4dd7-843b-8ac437940a6b Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready. |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation... |
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
@copilot don't add |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Extends footer template rendering so {effective_tokens} and {effective_tokens_formatted} can be used across more footer template contexts, and updates reference docs to describe the new placeholders.
Changes:
- Added an env-based helper to derive effective token counts and a compact formatted string for template contexts.
- Expanded footer template contexts to include
{effective_tokens}/{effective_tokens_formatted}where previously missing. - Updated documentation to list and explain the new template variables.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| docs/src/content/docs/reference/safe-outputs.md | Documents {effective_tokens} and {effective_tokens_formatted} in the Custom Messages variables list and explains availability/usage. |
| docs/src/content/docs/reference/footers.md | Mentions the new token placeholders in messages.footer customization guidance. |
| actions/setup/js/messages_footer.cjs | Adds getEffectiveTokensFromEnv() and injects formatted/raw effective token values into multiple footer template contexts. |
| actions/setup/js/messages_core.cjs | Updates the supported placeholders comment to include effective token placeholders. |
Comments suppressed due to low confidence (2)
actions/setup/js/messages_footer.cjs:63
getFooterMessage()only deriveseffectiveTokensFormattedfromctx.effectiveTokens, and does not fall back toGH_AW_EFFECTIVE_TOKENSwheneffectiveTokensis missing from the provided context. This means callers that construct a minimal ctx (e.g. activation-comment updates) won’t be able to use{effective_tokens}/{effective_tokens_formatted}in a custommessages.footertemplate even when the env var is available. Consider populatingeffectiveTokens/effectiveTokensFormattedingetFooterMessage()viagetEffectiveTokensFromEnv()whenctx.effectiveTokensis undefined (and prefer explicit ctx values when present).
// Pre-compute effective_tokens_formatted using compact format (e.g. "1.2K") for use in custom templates
const effectiveTokensFormatted = ctx.effectiveTokens ? formatET(ctx.effectiveTokens) : undefined;
// Create context with both camelCase and snake_case keys, including computed history_link and agentic_workflow_url
const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl, effectiveTokensFormatted });
actions/setup/js/messages_footer.cjs:135
- There are existing unit tests for footer templating (
actions/setup/js/messages.test.cjs), but the new{effective_tokens_formatted}placeholder (and env-derived{effective_tokens}/{effective_tokens_formatted}for the workflow-recompile / agent-failure footers) is not covered. Adding tests that assert these placeholders resolve whenGH_AW_EFFECTIVE_TOKENSis set (and remain literal when not set) would help prevent regressions.
function getFooterWorkflowRecompileMessage(ctx) {
const messages = getMessages();
// Pre-compute agentic_workflow_url as the direct link to the agentic workflow page
const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : "");
// Read effective tokens from environment variable if available
const { effectiveTokens, effectiveTokensFormatted } = getEffectiveTokensFromEnv();
// Create context with both camelCase and snake_case keys
const templateContext = toSnakeCase({ ...ctx, agenticWorkflowUrl, effectiveTokens, effectiveTokensFormatted });
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function getEffectiveTokensFromEnv() { | ||
| const raw = process.env.GH_AW_EFFECTIVE_TOKENS; | ||
| const parsed = raw ? parseInt(raw, 10) : NaN; | ||
| if (!isNaN(parsed) && parsed > 0) { | ||
| return { effectiveTokens: parsed, effectiveTokensFormatted: formatET(parsed) }; | ||
| } | ||
| return { effectiveTokens: undefined, effectiveTokensFormatted: undefined }; | ||
| } |
There was a problem hiding this comment.
Now that getEffectiveTokensFromEnv() exists, generateFooterWithMessages() still has separate parsing logic for GH_AW_EFFECTIVE_TOKENS later in this file. To avoid future divergence (edge-case parsing, >0 gating, formatting rules), it would be more maintainable to reuse the helper (and/or thread the helper’s result into the ctx) rather than parsing the env var in multiple places.
This issue also appears in the following locations of the same file:
- line 59
- line 124
|
Smoke Test: Copilot - 23913798196
Overall: PR author:
|
There was a problem hiding this comment.
Smoke test review for PR #24150. The {effective_tokens} and {effective_tokens_formatted} additions look well-structured. Two minor observations left as inline comments.
📰 BREAKING: Report filed by Smoke Copilot
| const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl, effectiveTokensFormatted }); | ||
|
|
||
| // Use custom footer template if configured (no automatic suffix appended) | ||
| if (messages?.footer) { |
There was a problem hiding this comment.
Consider also reading effectiveTokens from the environment for getFooterMessage() (not just computing effectiveTokensFormatted), so that {effective_tokens} is available in the messages.footer custom template for users who want the raw count.
actions/setup/js/messages_footer.cjs
Outdated
| const raw = process.env.GH_AW_EFFECTIVE_TOKENS; | ||
| const parsed = raw ? parseInt(raw, 10) : NaN; | ||
| if (!isNaN(parsed) && parsed > 0) { | ||
| return { effectiveTokens: parsed, effectiveTokensFormatted: formatET(parsed) }; |
There was a problem hiding this comment.
The getEffectiveTokensFromEnv() helper nicely centralizes the env var reading. One small nit: using Number.isNaN(parsed) instead of isNaN(parsed) would be slightly more precise since isNaN coerces its argument first.
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
💥 [THE END] — Illustrated by Smoke Claude
| const parsed = raw ? parseInt(raw, 10) : NaN; | ||
| if (!isNaN(parsed) && parsed > 0) { | ||
| return { effectiveTokens: parsed, effectiveTokensFormatted: formatET(parsed) }; | ||
| } |
There was a problem hiding this comment.
The getEffectiveTokensFromEnv helper cleanly centralizes env var parsing. Consider also exporting it so other modules can reuse it without re-parsing the same env var independently.
There was a problem hiding this comment.
Agreed! Exporting getEffectiveTokensFromEnv would improve reusability across modules. 👍
📰 BREAKING: Report filed by Smoke Copilot
| * - {workflow_source} - Source specification (owner/repo/path@ref) | ||
| * - {workflow_source_url} - GitHub URL for the workflow source | ||
| * - {triggering_number} - Issue/PR/Discussion number that triggered this workflow | ||
| * - {effective_tokens} - Raw total effective token count for the run (e.g. 1200), only present when > 0 |
There was a problem hiding this comment.
Good doc comment additions. It would help to clarify the unit for {effective_tokens} — e.g., "token count as defined by the provider" — so users know what to expect when the provider changes.
|
@copilot review all agentic workflows using "messages" and update with the ET expression. |
|
@pelikhan Unfortunately I hit an unexpected error while processing your comment. I've automatically reported this to GitHub. You can ask me to try again later by mentioning me in a new comment. If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: Sorry for the inconvenience! |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
This comment has been minimized.
This comment has been minimized.
|
@copilot debug why this footer does not have effective token data |
|
Smoke Test §23916041313
Overall:
|
There was a problem hiding this comment.
Smoke test review ✅ — The effective token suffix pattern is clean and consistent. Minor: prefer Number.isNaN() over isNaN() for precision.
📰 BREAKING: Report filed by Smoke Copilot
| GH_AW_WORKFLOW_NAME: "Archie" | ||
| GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📊 *Diagram rendered by [{workflow_name}]({run_url})*{history_link}\",\"footerWorkflowRecompile\":\"\\u003e 🔧 *Workflow sync report by [{workflow_name}]({run_url}) for {repository}*\",\"footerWorkflowRecompileComment\":\"\\u003e 🔄 *Update from [{workflow_name}]({run_url}) for {repository}*\",\"runStarted\":\"📐 [{workflow_name}]({run_url}) is analyzing the architecture for this {event_type}...\",\"runSuccess\":\"🎨 [{workflow_name}]({run_url}) has completed the architecture visualization. ✅\",\"runFailure\":\"📐 [{workflow_name}]({run_url}) encountered an issue and could not complete the architecture diagram. Check the [run logs]({run_url}) for details.\"}" | ||
| GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📊 *Diagram rendered by [{workflow_name}]({run_url})*{effective_tokens_suffix}{history_link}\",\"footerWorkflowRecompile\":\"\\u003e 🔧 *Workflow sync report by [{workflow_name}]({run_url}) for {repository}*\",\"footerWorkflowRecompileComment\":\"\\u003e 🔄 *Update from [{workflow_name}]({run_url}) for {repository}*\",\"runStarted\":\"📐 [{workflow_name}]({run_url}) is analyzing the architecture for this {event_type}...\",\"runSuccess\":\"🎨 [{workflow_name}]({run_url}) has completed the architecture visualization. ✅\",\"runFailure\":\"📐 [{workflow_name}]({run_url}) encountered an issue and could not complete the architecture diagram. Check the [run logs]({run_url}) for details.\"}" | ||
| with: |
There was a problem hiding this comment.
The {effective_tokens_suffix} addition here is a clean drop-in pattern — it follows the same "always a string, safe to concatenate" contract as {history_link}. Nice consistency! 🎉
| if (!isNaN(parsed) && parsed > 0) { | ||
| const effectiveTokensFormatted = formatET(parsed); | ||
| return { effectiveTokens: parsed, effectiveTokensFormatted, effectiveTokensSuffix: ` · ● ${effectiveTokensFormatted}` }; | ||
| } |
There was a problem hiding this comment.
Good use of isNaN() for NaN detection. One minor nit: Number.isNaN() would be slightly more precise here since it doesn't coerce non-numeric types, e.g. Number.isNaN(undefined) returns false while isNaN(undefined) returns true. For this use case it likely doesn't matter, but it's worth noting for robustness.
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
💥 [THE END] — Illustrated by Smoke Claude
| @@ -26,7 +26,7 @@ safe-outputs: | |||
| add-comment: | |||
| max: 1 | |||
| messages: | |||
There was a problem hiding this comment.
The {effective_tokens_suffix} template variable is correctly placed between the run URL and the history link. This provides useful token usage context in the footer without disrupting the existing layout. Good addition for observability!
| @@ -16,7 +16,7 @@ safe-outputs: | |||
| add-comment: | |||
| max: 1 | |||
| messages: | |||
There was a problem hiding this comment.
Consistent application of {effective_tokens_suffix} across workflow footer templates. This keeps the token reporting uniform. Consider adding a comment in a shared doc explaining the meaning of this template variable for future workflow authors.
There was a problem hiding this comment.
+1 from the smoke test agent! Exporting getEffectiveTokensFromEnv would make cross-module token reporting cleaner. 🤖
📰 BREAKING: Report filed by Smoke Copilot · ● 985.8K
Root cause: core.exportVariable() only persists env vars within the same job.
The safe_outputs job (which generates footers) is a separate job and cannot
see GH_AW_EFFECTIVE_TOKENS set in the agent job.
Fix:
- Add step ID 'parse-mcp-gateway' to the generateMCPGatewayLogParsing step
- Add 'effective_tokens' to agent job outputs via the step output
- Have parse_mcp_gateway_log.cjs call core.setOutput() in addition to exportVariable()
- Pass GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} to safe_outputs job
- Add ParseMCPGatewayStepID constant in pkg/constants/job_constants.go
- Update golden fixture files to match new output
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/adf67452-a5a1-475a-b48f-d92bf0fcff60
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Root cause: Fixed in c5516a4:
All 179 lock files recompiled. 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation... |
|
✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready. |
Agent Container Tool Check
Result: 12/12 tools available ✅ Overall Status: PASS
|
|
🤖 Smoke test §23917275390 results for
Overall:
|
There was a problem hiding this comment.
Smoke test review: PR adds effective_tokens observability across all workflow lock files — clean, consistent pattern. The getEffectiveTokensFromEnv() helper centralizes env var parsing nicely. LGTM! 🚀
📰 BREAKING: Report filed by Smoke Copilot · ● 985.8K
| env: | ||
| GH_AW_WORKFLOW_ID_SANITIZED: aceeditor | ||
| outputs: | ||
| effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} |
There was a problem hiding this comment.
The effective_tokens output is now correctly wired from steps.parse-mcp-gateway.outputs.effective_tokens. This pattern is consistently applied across all workflow lock files — good for observability! 🔭
| const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl, effectiveTokensFormatted, effectiveTokensSuffix }); | ||
|
|
||
| // Use custom footer template if configured (no automatic suffix appended) | ||
| if (messages?.footer) { |
There was a problem hiding this comment.
Consistent with the getEffectiveTokensFromEnv() helper pattern introduced earlier. The formatted suffix (N tokens) provides a nice human-readable token count in footer messages.
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
|
Warning The Smoke Test 23917275429 — Claude Engine
Overall: PARTIAL (Playwright ❌, 2 skipped)
|
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
💥 [THE END] — Illustrated by Smoke Claude · ● 289.9K
| env: | ||
| GH_AW_WORKFLOW_ID_SANITIZED: aceeditor | ||
| outputs: | ||
| effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} |
There was a problem hiding this comment.
Good addition — exposing effective_tokens as a job output enables downstream footer jobs to consume it. Consider adding a fallback value (e.g. || '') to ensure the output is always defined even if the step is skipped.
| await main(); | ||
| - name: Parse MCP Gateway logs for step summary | ||
| if: always() | ||
| id: parse-mcp-gateway |
There was a problem hiding this comment.
Adding id: parse-mcp-gateway here is necessary so the effective_tokens output reference resolves correctly. This is a clean, targeted change.
Summary
Ensures effective token template variables are available in all footer template contexts (not just the main attribution footer), adds a pre-formatted suffix variable for easy drop-in use, updates all agentic workflow footer templates, fixes a CI dependency list issue, fixes effective token data flowing across the agent→safe_outputs job boundary, and updates documentation.
Changes
JavaScript (
actions/setup/js/messages_footer.cjs)getEffectiveTokensFromEnv()helper that readsGH_AW_EFFECTIVE_TOKENSand returns{ effectiveTokens, effectiveTokensFormatted, effectiveTokensSuffix }— usingisNaN()for clean NaN handlinggetFooterMessage(): addedeffectiveTokensFormattedandeffectiveTokensSuffixto the template contextgetFooterWorkflowRecompileMessage(),getFooterWorkflowRecompileCommentMessage(),getFooterAgentFailureIssueMessage(),getFooterAgentFailureCommentMessage(): all now include{effective_tokens},{effective_tokens_formatted}, and{effective_tokens_suffix}via the shared helpergenerateFooterWithMessages(): refactored to usegetEffectiveTokensFromEnv()instead of its own duplicate env-var parsingJavaScript (
actions/setup/js/parse_mcp_gateway_log.cjs)core.setOutput("effective_tokens", ...)alongside the existingexportVariablecall so the value is accessible as a step output and can flow to downstream jobsJavaScript (
actions/setup/js/messages_core.cjs){effective_tokens},{effective_tokens_formatted}, and{effective_tokens_suffix}to the supported placeholders commentShell (
actions/setup/setup.sh)effective_tokens.cjstoSAFE_OUTPUTS_FILES(it was a transitive dependency ofmessages_footer.cjsbut missing from the list, causing a CI test failure)Workflow Compiler (
pkg/workflow/)id: parse-mcp-gatewaystep ID to theParse MCP Gateway logsstep in the agent job (compiler_yaml_ai_execution.go)effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}to the agent job outputs (compiler_main_job.go)GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}to thesafe_outputsjob env (compiler_safe_outputs_job.go)ParseMCPGatewayStepIDconstant (pkg/constants/job_constants.go)Agentic Workflows (39 files)
{history_link}to also include{effective_tokens_suffix}, e.g.:Documentation
docs/reference/safe-outputs.md: added all three new variables to the Custom Messages variables list with an explanatory paragraphdocs/reference/footers.md: updated the Customizing Footer Messages section to mention{effective_tokens_suffix}and its●formatTemplate Variables
{effective_tokens}1200)undefinedwhen no token data — placeholder stays literal{effective_tokens_formatted}1.2K,3M)undefinedwhen no token data — placeholder stays literal{effective_tokens_suffix}· ● 1.2K) or""{history_link}{effective_tokens_suffix}follows the same{history_link}convention: it is always a string and can be placed directly in templates without conditional logic.Cross-Job Data Flow Fix
core.exportVariable()only persists env vars within the same job. Thesafe_outputsjob (which renders footer comments) is a separate downstream job and previously could not seeGH_AW_EFFECTIVE_TOKENS. The fix uses the standard GitHub Actions job output mechanism: theparse_mcp_gateway_logstep now sets a step output, which is promoted to an agent job output and then passed as an env var into thesafe_outputsjob.✨ PR Review Safe Output Test - Run 23917275429