From 30d211ceba6691c410e0d23ae09112785c4a0f49 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 09:38:50 +0000 Subject: [PATCH] docs(instructions): split oversized .github/aw files, fix accuracy gaps - Split three files that exceeded the 400-line instruction limit: github-mcp-server.md (431->382, extracted pagination guidance), syntax-agentic.md (440->361, extracted engine: field to syntax-engine.md), token-optimization.md (422->374, extracted caching/budget techniques). - Fixed internal duplication in triggers.md's workflow_run escalation rules and cross-linked to the incident dedup-key templates. - Documented safe-outputs.data (structured-data schema for body-based safe outputs) and engine.auth provider: gcp (Vertex AI WIF), both present in the compiler schema but missing from instructions. --- .github/aw/github-agentic-workflows.md | 1 + .github/aw/github-mcp-server-pagination.md | 54 ++++++++++++ .github/aw/github-mcp-server.md | 51 +---------- .github/aw/safe-outputs-runtime.md | 15 ++++ .github/aw/syntax-agentic.md | 81 +---------------- .github/aw/syntax-engine.md | 88 +++++++++++++++++++ .github/aw/syntax.md | 3 +- .../aw/token-optimization-caching-budgets.md | 60 +++++++++++++ .github/aw/token-optimization.md | 54 +----------- .github/aw/triggers.md | 9 +- 10 files changed, 227 insertions(+), 189 deletions(-) create mode 100644 .github/aw/github-mcp-server-pagination.md create mode 100644 .github/aw/syntax-engine.md create mode 100644 .github/aw/token-optimization-caching-budgets.md diff --git a/.github/aw/github-agentic-workflows.md b/.github/aw/github-agentic-workflows.md index abcb072815e..7fb20e60a82 100644 --- a/.github/aw/github-agentic-workflows.md +++ b/.github/aw/github-agentic-workflows.md @@ -146,6 +146,7 @@ Permissions: `pull-requests: read` only; all writes route through `add-comment` | Skills | [skills.md](skills.md) | | Token cost optimization | [token-optimization.md](token-optimization.md) | | GitHub MCP server configuration | [github-mcp-server.md](github-mcp-server.md) | +| GitHub MCP server pagination limits | [github-mcp-server-pagination.md](github-mcp-server-pagination.md) | | Campaign and KPI patterns | [campaign.md](campaign.md) | | Experiments and A/B testing | [experiments.md](experiments.md) | | Charts and Python data visualization | [charts.md](charts.md) | diff --git a/.github/aw/github-mcp-server-pagination.md b/.github/aw/github-mcp-server-pagination.md new file mode 100644 index 00000000000..65ea9474312 --- /dev/null +++ b/.github/aw/github-mcp-server-pagination.md @@ -0,0 +1,54 @@ +# GitHub MCP Server — Pagination + +See [github-mcp-server.md](github-mcp-server.md) for toolset and tool reference. + +MCP tool responses have a **25,000 token limit**. Fetching large result sets without pagination causes the response to be truncated or rejected, forcing costly retry turns. + +## `perPage` Defaults by Item Type + +| Item type | Recommended `perPage` | +|-----------|----------------------| +| PRs with diffs / issues with comments (detailed) | 10–20 | +| Simple list operations (commits, branches, labels) | 50–100 | +| Exploratory / schema-discovery queries | 1–5 | + +Always pass an explicit `perPage` value. Do **not** rely on server defaults. + +## Tool-Specific Guidance + +**Pull Requests** +- `list_pull_requests` — use `perPage: 10`, `sort: updated`, `direction: desc` +- `pull_request_read` with `method: get_files` — use `perPage: 30` +- Fetch diff and comments **separately** when full detail is needed + +**Issues** +- `list_issues` — `perPage: 20` +- `issue_read` with `method: get_comments` — `perPage: 20` + +**Search** +- `search_issues`, `search_pull_requests`, `search_code` — `perPage: 10` +- `search_repositories` exploratory calls — `perPage: 3–5`; increase only after narrowing the query + +## Pagination Loop (when all pages are needed) + +``` +page 1 → check total_count or has_next_page → fetch page 2, 3, … until done +``` + +Process results incrementally rather than accumulating all pages in memory. + +## Known Tool Quirks + +Two built-in GitHub MCP tools ignore standard pagination parameters: + +- **`list_label`** — uses a hardcoded GraphQL `labels(first: 100)` query; `perPage` is silently ignored. Use the `shared/github-mcp-pagination-wrappers.md` wrapper instead. +- **`list_workflows`** — uses snake_case `per_page` (inconsistent with every other list tool). Use the `shared/github-mcp-pagination-wrappers.md` wrapper for consistent camelCase `perPage` support. + +## Oversized-Response Errors + +If you encounter errors like: + +- `MCP tool "list_pull_requests" response (75897 tokens) exceeds maximum allowed tokens (25000)` +- `Response too large for tool [tool_name]` + +add `perPage: 10` (or smaller) and retry. diff --git a/.github/aw/github-mcp-server.md b/.github/aw/github-mcp-server.md index 3993c142694..3dd3abcb8fd 100644 --- a/.github/aw/github-mcp-server.md +++ b/.github/aw/github-mcp-server.md @@ -359,56 +359,7 @@ When calling `list_code_scanning_alerts` in workflow prompts/templates, always b ## Pagination -MCP tool responses have a **25,000 token limit**. Fetching large result sets without pagination causes the response to be truncated or rejected, forcing costly retry turns. - -### `perPage` Defaults by Item Type - -| Item type | Recommended `perPage` | -|-----------|----------------------| -| PRs with diffs / issues with comments (detailed) | 10–20 | -| Simple list operations (commits, branches, labels) | 50–100 | -| Exploratory / schema-discovery queries | 1–5 | - -Always pass an explicit `perPage` value. Do **not** rely on server defaults. - -### Tool-Specific Guidance - -**Pull Requests** -- `list_pull_requests` — use `perPage: 10`, `sort: updated`, `direction: desc` -- `pull_request_read` with `method: get_files` — use `perPage: 30` -- Fetch diff and comments **separately** when full detail is needed - -**Issues** -- `list_issues` — `perPage: 20` -- `issue_read` with `method: get_comments` — `perPage: 20` - -**Search** -- `search_issues`, `search_pull_requests`, `search_code` — `perPage: 10` -- `search_repositories` exploratory calls — `perPage: 3–5`; increase only after narrowing the query - -### Pagination Loop (when all pages are needed) - -``` -page 1 → check total_count or has_next_page → fetch page 2, 3, … until done -``` - -Process results incrementally rather than accumulating all pages in memory. - -### Known Tool Quirks - -Two built-in GitHub MCP tools ignore standard pagination parameters: - -- **`list_label`** — uses a hardcoded GraphQL `labels(first: 100)` query; `perPage` is silently ignored. Use the `shared/github-mcp-pagination-wrappers.md` wrapper instead. -- **`list_workflows`** — uses snake_case `per_page` (inconsistent with every other list tool). Use the `shared/github-mcp-pagination-wrappers.md` wrapper for consistent camelCase `perPage` support. - -### Oversized-Response Errors - -If you encounter errors like: - -- `MCP tool "list_pull_requests" response (75897 tokens) exceeds maximum allowed tokens (25000)` -- `Response too large for tool [tool_name]` - -add `perPage: 10` (or smaller) and retry. +MCP tool responses have a **25,000 token limit**; always pass an explicit `perPage`. See [github-mcp-server-pagination.md](github-mcp-server-pagination.md) for per-tool `perPage` defaults, the pagination loop pattern, known tool quirks (`list_label`, `list_workflows`), and oversized-response recovery. --- diff --git a/.github/aw/safe-outputs-runtime.md b/.github/aw/safe-outputs-runtime.md index 001de514c68..e769039c10a 100644 --- a/.github/aw/safe-outputs-runtime.md +++ b/.github/aw/safe-outputs-runtime.md @@ -91,6 +91,21 @@ The `report-incomplete` safe-output is enabled by default and is distinct from ` - `allowed-domains:` - Allowed domains for URLs in safe output content (array) - URLs from unlisted domains are replaced with `(redacted)` - GitHub domains are always included by default +- `data:` - Structured data configuration for body-based safe outputs (boolean, object, or GitHub Actions expression) + - Applies to `create-issue`, `add-comment`, `create-pull-request`, `create-pull-request-review-comment`, `submit-pull-request-review`, and `reply-to-pull-request-review-comment` + - `false` or omitted (default) - no structured `data` field accepted + - `true` - accept any object as the `data` field alongside `body` + - Inline schema object - enforce shape; supports full JSON Schema keywords (`type`, `properties`, `required`, `items`, `enum`, etc.) or shorthand (`{ verdict: string, score: number }`) + - `${{ ... }}` expression - resolves to one of the above at runtime + - Example: + + ```yaml + safe-outputs: + data: + verdict: string + score: number + add-comment: + ``` - `allowed-github-references:` - Allowed repositories for GitHub-style references (array) - Controls which GitHub references (`#123`, `owner/repo#456`) are allowed in workflow output - References to unlisted repositories are escaped with backticks to prevent timeline items diff --git a/.github/aw/syntax-agentic.md b/.github/aw/syntax-agentic.md index b1af6bcab9d..09d9a38c832 100644 --- a/.github/aw/syntax-agentic.md +++ b/.github/aw/syntax-agentic.md @@ -270,86 +270,7 @@ description: Agentic workflow specific frontmatter fields for GitHub Agentic Wor - `setup-steps`/`pre-steps` also apply to built-in jobs (e.g. `activation`): use `setup-steps` for OIDC/secret bootstrap that must run before framework token minting, then verify the result in `pre-steps`. -- **`engine:`** - AI processor configuration - - String format: `"copilot"` (default, recommended), `"claude"`, `"codex"`, `"gemini"`, or the experimental `"antigravity"`, `"opencode"`, `"pi"` - - Object format for extended configuration: - - ```yaml - engine: - id: copilot # Required: coding agent identifier (copilot, claude, codex, gemini; experimental: antigravity, opencode, pi) - version: beta # Optional: version of the action (has sensible default); also accepts GitHub Actions expressions: ${{ inputs.engine-version }} - model: gpt-5 # Deprecated alias for the top-level `model`; prefer the top-level field - permission-mode: acceptEdits # Optional (claude only): auto | acceptEdits | plan | bypassPermissions. Default: acceptEdits (auto when tools.edit is false) - agent: technical-doc-writer # Optional: custom agent file (Copilot only, references .github/agents/{agent}.agent.md) - max-turns: 5 # Deprecated alias for the top-level `max-turns`; prefer the top-level field - max-continuations: 3 # Optional: max autopilot continuations (copilot only; >1 enables --autopilot mode, default: 1) - concurrency: "gh-aw-${{ github.workflow }}" # Optional: agent job concurrency group (string or GitHub Actions concurrency object) - env: # Optional: custom environment variables (object) - DEBUG_MODE: "true" - args: ["--verbose"] # Optional: custom CLI arguments injected before prompt (array) - api-target: api.acme.ghe.com # Optional: custom API endpoint hostname for GHEC/GHES (hostname only, no protocol/path) - command: /usr/local/bin/copilot # Optional: override default engine executable (skips installation) - bare: true # Optional: disable automatic context loading (copilot: --no-custom-instructions; claude: --bare; codex: --no-system-prompt; gemini: GEMINI_SYSTEM_MD=/dev/null). Default: false - user-agent: "myapp/1.0" # Optional: custom user agent string (codex engine only) - config: | # Optional: additional TOML config appended to config.toml (codex engine only) - [extra] - key = "value" - ``` - - - **`gemini` engine**: Google Gemini CLI. Requires `GEMINI_API_KEY` secret. Does not support `max-turns`, `web-fetch`, or `web-search`. Supports AWF firewall and LLM gateway. - - **`antigravity` engine** (experimental): Google Antigravity CLI in headless mode. Requires `ANTIGRAVITY_API_KEY` secret; model via `model:` (maps to `ANTIGRAVITY_MODEL`). Supports `max-turns`, tools allow-list, AWF firewall, and LLM gateway. Does not support `web-search`, `max-continuations`, or native agent files (agent content is prepended to the prompt). - - **`opencode` engine** (experimental): Provider-agnostic, open-source AI coding agent (BYOK). Defaults to Copilot routing via `COPILOT_GITHUB_TOKEN` (or `${{ github.token }}` with `copilot-requests` feature). Supports 75+ models via `provider/model` format. Supports AWF firewall and LLM gateway. - - **`engine.driver:`** — canonical field to run a custom inner driver script instead of the engine's built-in CLI. For the `pi` engine it launches the driver directly with Node.js (e.g. built-in `pi_agent_core_driver.cjs`, or a workspace-relative path like `.github/drivers/pi_agent_core_driver_sample_node.cjs`); the driver must emit JSONL compatible with `parse_pi_log.cjs` so step summaries and token tracking keep working. Accepts a bare basename (resolved from the setup-action directory) or a workspace-relative path; no absolute paths, no `..`, only `.js`/`.cjs`/`.mjs` (pi). - - **`copilot-sdk`** (copilot only): set `copilot-sdk: true` to start a headless Copilot CLI SDK sidecar. **`engine.driver`** (experimental, copilot only): set `driver: ` to supply a custom SDK driver (`.js`/`.cjs`/`.mjs`/`.py`/`.ts`/`.mts`/`.rb`, or a bare PATH command); this also enables `copilot-sdk: true` automatically. Tune the repeated-tool-denial safeguard with the top-level `max-tool-denials:` field (default `5`). - - **Inline driver source** (copilot engine only): instead of pointing to a checked-in file, you can embed the driver source directly in the frontmatter using an object with exactly one runtime key (`node`, `python`, `go`, or `java`). The compiler materializes the source under `.gh-aw/copilot-sdk/` at runtime and generates a launcher wrapper. The required SDK package is installed automatically. - - ```yaml - # Node.js / TypeScript inline driver (SDK installed via npm) - engine: - id: copilot - driver: - node: | - const sdk = require("@github/copilot-sdk"); - // ... driver implementation - ``` - - ```yaml - # Python inline driver (SDK installed via pip into workspace target dir) - engine: - id: copilot - driver: - python: | - import sys - from github_copilot_sdk import CopilotAgent - # ... driver implementation - ``` - - ```yaml - # Go inline driver (SDK installed via go get; go.mod generated automatically) - engine: - id: copilot - driver: - go: | - package main - import "github.com/github/copilot-sdk/go" - func main() { /* driver implementation */ } - ``` - - ```yaml - # Java inline driver (SDK resolved via Maven pom.xml generated automatically) - engine: - id: copilot - driver: - java: | - public class Main { - public static void main(String[] args) { /* driver implementation */ } - } - ``` - - Constraints: exactly one runtime key per `driver` object; source must be non-empty; only supported on the `copilot` engine. Use `runtimes..version` to pin the runtime version used for the generated module files (e.g. `runtimes.go.version: "1.22"`). - - **`engine.auth:`** — keyless Workload Identity Federation via the AWF API proxy instead of a static API key; requires `id-token: write`. Set `type: github-oidc` (only supported type) plus `provider: azure` (`azure-tenant-id`, `azure-client-id`, optional `azure-scope`/`azure-cloud`) for Azure OpenAI, or `provider: anthropic` (`federation-rule-id`, `organization-id`, `service-account-id`, `workspace-id`) for Claude. Optional `audience:`. Maps to `AWF_AUTH_*` env vars. - - **Advanced engine sub-fields** (see the `engine_config` definition in `pkg/parser/schemas/main_workflow_schema.json`): `model-provider` (`github` | `anthropic` | `openai`), `harness` (retry policy), engine-level `mcp` (`session-timeout`/`tool-timeout`), `extensions`, and `cwd`. +- **`engine:`** - AI processor configuration (string or object: `id`, `model`, `permission-mode`, `agent`, `max-continuations`, `driver`, `copilot-sdk`, `auth`, and more). See [syntax-engine.md](syntax-engine.md) for the full field reference, per-engine support notes, and inline driver examples. - **`network:`** - Network access control for AI engines (top-level field) - String format: `"defaults"` (curated allow-list of development domains) diff --git a/.github/aw/syntax-engine.md b/.github/aw/syntax-engine.md new file mode 100644 index 00000000000..1d22c6cb918 --- /dev/null +++ b/.github/aw/syntax-engine.md @@ -0,0 +1,88 @@ +--- +description: `engine:` frontmatter field detail for GitHub Agentic Workflows. +--- + +# Engine Configuration + +See [syntax-agentic.md](syntax-agentic.md) for the full frontmatter field index. + +- **`engine:`** - AI processor configuration + - String format: `"copilot"` (default, recommended), `"claude"`, `"codex"`, `"gemini"`, or the experimental `"antigravity"`, `"opencode"`, `"pi"` + - Object format for extended configuration: + + ```yaml + engine: + id: copilot # Required: coding agent identifier (copilot, claude, codex, gemini; experimental: antigravity, opencode, pi) + version: beta # Optional: version of the action (has sensible default); also accepts GitHub Actions expressions: ${{ inputs.engine-version }} + model: gpt-5 # Deprecated alias for the top-level `model`; prefer the top-level field + permission-mode: acceptEdits # Optional (claude only): auto | acceptEdits | plan | bypassPermissions. Default: acceptEdits (auto when tools.edit is false) + agent: technical-doc-writer # Optional: custom agent file (Copilot only, references .github/agents/{agent}.agent.md) + max-turns: 5 # Deprecated alias for the top-level `max-turns`; prefer the top-level field + max-continuations: 3 # Optional: max autopilot continuations (copilot only; >1 enables --autopilot mode, default: 1) + concurrency: "gh-aw-${{ github.workflow }}" # Optional: agent job concurrency group (string or GitHub Actions concurrency object) + env: # Optional: custom environment variables (object) + DEBUG_MODE: "true" + args: ["--verbose"] # Optional: custom CLI arguments injected before prompt (array) + api-target: api.acme.ghe.com # Optional: custom API endpoint hostname for GHEC/GHES (hostname only, no protocol/path) + command: /usr/local/bin/copilot # Optional: override default engine executable (skips installation) + bare: true # Optional: disable automatic context loading (copilot: --no-custom-instructions; claude: --bare; codex: --no-system-prompt; gemini: GEMINI_SYSTEM_MD=/dev/null). Default: false + user-agent: "myapp/1.0" # Optional: custom user agent string (codex engine only) + config: | # Optional: additional TOML config appended to config.toml (codex engine only) + [extra] + key = "value" + ``` + + - **`gemini` engine**: Google Gemini CLI. Requires `GEMINI_API_KEY` secret. Does not support `max-turns`, `web-fetch`, or `web-search`. Supports AWF firewall and LLM gateway. + - **`antigravity` engine** (experimental): Google Antigravity CLI in headless mode. Requires `ANTIGRAVITY_API_KEY` secret; model via `model:` (maps to `ANTIGRAVITY_MODEL`). Supports `max-turns`, tools allow-list, AWF firewall, and LLM gateway. Does not support `web-search`, `max-continuations`, or native agent files (agent content is prepended to the prompt). + - **`opencode` engine** (experimental): Provider-agnostic, open-source AI coding agent (BYOK). Defaults to Copilot routing via `COPILOT_GITHUB_TOKEN` (or `${{ github.token }}` with `copilot-requests` feature). Supports 75+ models via `provider/model` format. Supports AWF firewall and LLM gateway. + - **`engine.driver:`** — canonical field to run a custom inner driver script instead of the engine's built-in CLI. For the `pi` engine it launches the driver directly with Node.js (e.g. built-in `pi_agent_core_driver.cjs`, or a workspace-relative path like `.github/drivers/pi_agent_core_driver_sample_node.cjs`); the driver must emit JSONL compatible with `parse_pi_log.cjs` so step summaries and token tracking keep working. Accepts a bare basename (resolved from the setup-action directory) or a workspace-relative path; no absolute paths, no `..`, only `.js`/`.cjs`/`.mjs` (pi). + - **`copilot-sdk`** (copilot only): set `copilot-sdk: true` to start a headless Copilot CLI SDK sidecar. **`engine.driver`** (experimental, copilot only): set `driver: ` to supply a custom SDK driver (`.js`/`.cjs`/`.mjs`/`.py`/`.ts`/`.mts`/`.rb`, or a bare PATH command); this also enables `copilot-sdk: true` automatically. Tune the repeated-tool-denial safeguard with the top-level `max-tool-denials:` field (default `5`). + + **Inline driver source** (copilot engine only): instead of pointing to a checked-in file, you can embed the driver source directly in the frontmatter using an object with exactly one runtime key (`node`, `python`, `go`, or `java`). The compiler materializes the source under `.gh-aw/copilot-sdk/` at runtime and generates a launcher wrapper. The required SDK package is installed automatically. + + ```yaml + # Node.js / TypeScript inline driver (SDK installed via npm) + engine: + id: copilot + driver: + node: | + const sdk = require("@github/copilot-sdk"); + // ... driver implementation + ``` + + ```yaml + # Python inline driver (SDK installed via pip into workspace target dir) + engine: + id: copilot + driver: + python: | + import sys + from github_copilot_sdk import CopilotAgent + # ... driver implementation + ``` + + ```yaml + # Go inline driver (SDK installed via go get; go.mod generated automatically) + engine: + id: copilot + driver: + go: | + package main + import "github.com/github/copilot-sdk/go" + func main() { /* driver implementation */ } + ``` + + ```yaml + # Java inline driver (SDK resolved via Maven pom.xml generated automatically) + engine: + id: copilot + driver: + java: | + public class Main { + public static void main(String[] args) { /* driver implementation */ } + } + ``` + + Constraints: exactly one runtime key per `driver` object; source must be non-empty; only supported on the `copilot` engine. Use `runtimes..version` to pin the runtime version used for the generated module files (e.g. `runtimes.go.version: "1.22"`). + - **`engine.auth:`** — keyless Workload Identity Federation via the AWF API proxy instead of a static API key; requires `id-token: write`. Set `type: github-oidc` (only supported type) plus `provider: azure` (`azure-tenant-id`, `azure-client-id`, optional `azure-scope`/`azure-cloud`) for Azure OpenAI, `provider: anthropic` (`federation-rule-id`, `organization-id`, `service-account-id`, `workspace-id`) for Claude, or `provider: gcp` (`workload-identity-provider`, `service-account`, optional `project`/`location`, default region `us-central1`) for Vertex AI / Gemini Enterprise. Optional `audience:`. Maps to `AWF_AUTH_*` env vars. + - **Advanced engine sub-fields** (see the `engine_config` definition in `pkg/parser/schemas/main_workflow_schema.json`): `model-provider` (`github` | `anthropic` | `openai`), `harness` (retry policy), engine-level `mcp` (`session-timeout`/`tool-timeout`), `extensions`, and `cwd`. diff --git a/.github/aw/syntax.md b/.github/aw/syntax.md index 0a87d00948c..c267e0c0f99 100644 --- a/.github/aw/syntax.md +++ b/.github/aw/syntax.md @@ -9,7 +9,8 @@ Use the smallest relevant reference instead of loading one large schema file. | Topic | File | |---|---| | Core GitHub Actions fields (`on`, `permissions`, `runs-on`, `steps`, `env`, `secrets`) | [syntax-core.md](syntax-core.md) | -| Agentic workflow specific fields (`strict`, `bots`, `labels`, metadata, engine-specific fields) | [syntax-agentic.md](syntax-agentic.md) | +| Agentic workflow specific fields (`strict`, `bots`, `labels`, metadata) | [syntax-agentic.md](syntax-agentic.md) | +| `engine:` field detail (per-engine support, inline drivers, auth) | [syntax-engine.md](syntax-engine.md) | | Cache configuration, tools, imports, and permission patterns | [syntax-tools-imports.md](syntax-tools-imports.md) | | `skills` field | [skills.md](skills.md) | | `lsp` field | [lsp.md](lsp.md) | diff --git a/.github/aw/token-optimization-caching-budgets.md b/.github/aw/token-optimization-caching-budgets.md new file mode 100644 index 00000000000..4d782498958 --- /dev/null +++ b/.github/aw/token-optimization-caching-budgets.md @@ -0,0 +1,60 @@ +--- +description: Prompt caching, AI-credit budget guardrails, and bounded file reads for GitHub Agentic Workflows. +--- + +# Token Optimization — Caching, Budgets, and Bounded Reads + +See [token-optimization.md](token-optimization.md) for the full technique index and quick-reference checklist. + +## Technique 9 — Enable Prompt Caching + +Prompt caching is automatic via the AWF gateway. Cached input tokens are weighted at `0.1` versus `1.0` for uncached input — repeated context (system prompt, shared preamble) costs ~10× less when cached. + +To maximize cache hits: + +- **Keep stable content at the top of the prompt** — instructions that don't change between runs (role, output format, schema) before dynamic content (issue body, event context). +- **Use `cache-memory`** for workflows that re-read the same large knowledge base across runs; avoids duplicate context every turn. +- **Minimize dynamic context** — inject only the fields the agent needs: `${{ github.event.issue.number }}` instead of the full event payload. + +--- + +## Technique 10 — Cap Spend with AI-Credit Guardrails + +Two top-level frontmatter fields enforce AI Credit budgets directly, independent of the techniques above. Both accept an integer or a `K`/`M` short-form string (e.g. `100M`, `500K`). Typical workflow range: `100` to `2500`. + +Do not treat a workflow exhausting its per-run budget as a reason to increase `max-ai-credits` immediately. First apply and measure every applicable cost optimization in this guide. Increase the limit only as a last resort when the workflow still cannot complete with acceptable quality within the existing budget. + +- **`max-ai-credits:`** — Per-run AI credit budget enforced by the AWF firewall/API proxy (default `1000`). The agent is steered to stay within budget; set a negative value to disable enforcement and steering. +- **`max-daily-ai-credits:`** — Per-user 24-hour guardrail. At activation, gh-aw sums the triggering user's AI credits across their runs of this workflow over the last 24 hours and blocks execution once the total exceeds the threshold. Enabled by default with a system default threshold; set `-1` to disable, or an explicit value to override the default. + +```yaml +max-ai-credits: 100M # per-run cap (short-form string) +max-daily-ai-credits: 500M # per-user 24h cap; -1 disables +``` + +For custom or private models, the top-level **`models:`** frontmatter field supplies pricing in the same structure as `models.json` (keyed `providers..models..cost` with `input`/`output`/`cache_read`/`cache_write` per-token costs). Entries are merged with the built-in `models.json` at runtime — they override matching models and fill gaps for unknown ones — so AI Credit accounting stays accurate for models gh-aw does not price by default. + +For self-hosted or BYOK models absent from the built-in table (e.g. Ollama, vLLM), set **`models.default-ai-credits-pricing`** (`input`/`output` in $/1M tokens, both `0` for free/local models); without it the AWF proxy rejects unrecognized models with HTTP 400 `unknown_model_ai_credits`. + +--- + +## Technique 11 — Cap Session Context Growth from Large File Reads + +> **Files larger than 20 KB must not be read in full.** Use targeted reads instead. + +Before calling `get_file_contents`, check size with `wc -c `. If > 20 KB, use `grep`, `glob`, `bash head`, or `view` with `view_range` to read only the section you need. The same rule applies after `glob **/*.md` — read each matched file with `grep` or `view_range`, not full-file reads. + +For GitHub-hosted files, prefer `mode: gh-proxy` and access via `gh`/`bash` so output can be piped through `jq`, `grep`, or `head` before it enters context — the agent never receives the full file: + +```bash +# gh-proxy: fetch only the lines you need, no full-file injection +gh api repos/{owner}/{repo}/contents/.github/aw/syntax-agentic.md \ + --jq '.content' | base64 -d | grep -n "## Sub-agents" +``` + +```bash +# Without gh-proxy: targeted local read +bash: grep -n "## Sub-agents" .github/aw/syntax-agentic.md +# or +view: .github/aw/syntax-agentic.md view_range=[45, 90] +``` diff --git a/.github/aw/token-optimization.md b/.github/aw/token-optimization.md index bf74375f83e..414ff6ebd28 100644 --- a/.github/aw/token-optimization.md +++ b/.github/aw/token-optimization.md @@ -354,58 +354,9 @@ Prioritize this for long-horizon, tool-heavy workflows with measurable headroom; --- -## Technique 9 — Enable Prompt Caching +## Techniques 9–11 — Caching, AI-Credit Guardrails, and Bounded File Reads -Prompt caching is automatic via the AWF gateway. Cached input tokens are weighted at `0.1` versus `1.0` for uncached input — repeated context (system prompt, shared preamble) costs ~10× less when cached. - -To maximize cache hits: - -- **Keep stable content at the top of the prompt** — instructions that don't change between runs (role, output format, schema) before dynamic content (issue body, event context). -- **Use `cache-memory`** for workflows that re-read the same large knowledge base across runs; avoids duplicate context every turn. -- **Minimize dynamic context** — inject only the fields the agent needs: `${{ github.event.issue.number }}` instead of the full event payload. - ---- - -## Technique 10 — Cap Spend with AI-Credit Guardrails - -Two top-level frontmatter fields enforce AI Credit budgets directly, independent of the techniques above. Both accept an integer or a `K`/`M` short-form string (e.g. `100M`, `500K`). Typical workflow range: `100` to `2500`. - -Do not treat a workflow exhausting its per-run budget as a reason to increase `max-ai-credits` immediately. First apply and measure every applicable cost optimization in this guide. Increase the limit only as a last resort when the workflow still cannot complete with acceptable quality within the existing budget. - -- **`max-ai-credits:`** — Per-run AI credit budget enforced by the AWF firewall/API proxy (default `1000`). The agent is steered to stay within budget; set a negative value to disable enforcement and steering. -- **`max-daily-ai-credits:`** — Per-user 24-hour guardrail. At activation, gh-aw sums the triggering user's AI credits across their runs of this workflow over the last 24 hours and blocks execution once the total exceeds the threshold. Enabled by default with a system default threshold; set `-1` to disable, or an explicit value to override the default. - -```yaml -max-ai-credits: 100M # per-run cap (short-form string) -max-daily-ai-credits: 500M # per-user 24h cap; -1 disables -``` - -For custom or private models, the top-level **`models:`** frontmatter field supplies pricing in the same structure as `models.json` (keyed `providers..models..cost` with `input`/`output`/`cache_read`/`cache_write` per-token costs). Entries are merged with the built-in `models.json` at runtime — they override matching models and fill gaps for unknown ones — so AI Credit accounting stays accurate for models gh-aw does not price by default. - -For self-hosted or BYOK models absent from the built-in table (e.g. Ollama, vLLM), set **`models.default-ai-credits-pricing`** (`input`/`output` in $/1M tokens, both `0` for free/local models); without it the AWF proxy rejects unrecognized models with HTTP 400 `unknown_model_ai_credits`. - ---- - -## Technique 11 — Cap Session Context Growth from Large File Reads - -> **Files larger than 20 KB must not be read in full.** Use targeted reads instead. - -Before calling `get_file_contents`, check size with `wc -c `. If > 20 KB, use `grep`, `glob`, `bash head`, or `view` with `view_range` to read only the section you need. The same rule applies after `glob **/*.md` — read each matched file with `grep` or `view_range`, not full-file reads. - -For GitHub-hosted files, prefer `mode: gh-proxy` and access via `gh`/`bash` so output can be piped through `jq`, `grep`, or `head` before it enters context — the agent never receives the full file: - -```bash -# gh-proxy: fetch only the lines you need, no full-file injection -gh api repos/{owner}/{repo}/contents/.github/aw/syntax-agentic.md \ - --jq '.content' | base64 -d | grep -n "## Sub-agents" -``` - -```bash -# Without gh-proxy: targeted local read -bash: grep -n "## Sub-agents" .github/aw/syntax-agentic.md -# or -view: .github/aw/syntax-agentic.md view_range=[45, 90] -``` +See [token-optimization-caching-budgets.md](token-optimization-caching-budgets.md) for prompt-caching mechanics, `max-ai-credits`/`max-daily-ai-credits` guardrails, custom model pricing, and the 20 KB bounded-file-read rule. --- @@ -413,6 +364,7 @@ view: .github/aw/syntax-agentic.md view_range=[45, 90] | Topic | File | |---|---| +| Prompt caching, AI-credit guardrails, bounded file reads | [token-optimization-caching-budgets.md](token-optimization-caching-budgets.md) | | Inline sub-agents syntax | [subagents.md](subagents.md) | | A/B experiments | [experiments.md](experiments.md) | | Persistent memory | [memory.md](memory.md) | diff --git a/.github/aw/triggers.md b/.github/aw/triggers.md index 9a1caafc36d..79dcbdb34a2 100644 --- a/.github/aw/triggers.md +++ b/.github/aw/triggers.md @@ -114,14 +114,9 @@ These are "non-success outcomes requiring triage"; keep the list explicit so rea Escalation rules for this pattern (required): -- Derive a stable failure key before any write (for example `:::`). +- Derive a stable failure key before any write (for example `:::`). See [create-agentic-workflow-trigger-details.md](create-agentic-workflow-trigger-details.md#incident-dedup-key-templates-workflow_run-and-deployment_status) for concrete key-format templates. - Search for an existing open incident by that key **before** calling `create-issue`. -- Call `noop` instead of creating a new issue when an open incident already exists for the same key. - -No-op expectations for this pattern: - -- `noop` when the monitored run concludes `success`. -- `noop` when the same failure already has an open incident issue (duplicate suppression). +- `noop` when the monitored run concludes `success`, or when an open incident already exists for the same key (duplicate suppression). #### Fuzzy Scheduling