-
Notifications
You must be signed in to change notification settings - Fork 267
feat(skills): add aiq-customize-prompts-models and aiq-maintain-ci #282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cdgamarose-nv
merged 5 commits into
NVIDIA-AI-Blueprints:develop
from
zhongxuanwang-nv:feat/maintainer-skills-prompts-and-ci
Jun 25, 2026
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
475a54e
feat(skills): add aiq-customize-prompts-models and aiq-maintain-ci ma…
zhongxuanwang-nv 1029442
docs(skills): fix accuracy issues in the two new maintainer skills
zhongxuanwang-nv fbc6062
docs(skills): list the two new skills in the maintainer skill tables
zhongxuanwang-nv 9ab1e88
Merge branch 'develop' into feat/maintainer-skills-prompts-and-ci
cdgamarose-nv ba03b1b
docs(skills): warn against hardcoding queries/domains in prompts
zhongxuanwang-nv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| --- | ||
| name: aiq-customize-prompts-models | ||
| description: Use when customizing AI-Q agent behavior through Jinja2 prompt templates or per-agent model selection — editing prompts under src/aiq_agent/agents/*/prompts/, adding template variables, or assigning/swapping LLMs per agent role via config (the llms section plus per-agent fields like orchestrator_llm, planner_llm, researcher_llm, writer_llm, source_router_llm). | ||
| license: Apache-2.0 | ||
| compatibility: Claude Code, Codex, Cursor, OpenCode, and Agent Skills-compatible tools. | ||
| metadata: | ||
| version: "0.1.0" | ||
| source-repo: "NVIDIA-AI-Blueprints/aiq" | ||
| tags: "aiq nemo-agent-toolkit prompts models jinja2 customization" | ||
| allowed-tools: Read Bash Edit | ||
| --- | ||
|
|
||
| # Customize AI-Q Prompts and Models | ||
|
|
||
| Use this skill when a developer wants to change *how* an AI-Q agent reasons or | ||
| *which* model it uses — by editing a Jinja2 prompt template or by assigning a | ||
| different LLM to an agent role — usually without touching agent code. AI-Q agent | ||
| behavior is driven by prompts and config, so most tuning is a template or YAML | ||
| change. The one exception is adding a brand-new template, which needs a one-line | ||
| `load_prompt` wiring in the agent (see the prompt-templates reference). | ||
|
|
||
| ## Start Here | ||
|
|
||
| - Confirm the change is prompt or model customization, not new tool/agent logic. | ||
| For a new retrieval source use `aiq-add-data-source`; for a new tool use | ||
| `aiq-add-tool`. | ||
| - Read the authoritative docs and the existing templates/config below first. | ||
| - Prefer editing an existing template or config field over adding new machinery. | ||
| - Keep the prompt's STRICT citation rules intact, and never hard-code a model | ||
| name where an `llms:` ref belongs. | ||
| - Keep templates general-purpose: don't hard-code specific queries, domains, or | ||
| source/tool names — those come from the user's request and the | ||
| `data_source_registry` at runtime. | ||
|
|
||
| ## Authoritative References | ||
|
|
||
| - `docs/source/customization/prompts.md`: prompt guide — template inventory, | ||
| `load_prompt(path, name)`, `render_prompt_template(template, ...)`, the | ||
| documented template variables, the STRICT citation rules, and "Creating a New | ||
| Template". Note it does not document every template's variables (e.g. | ||
| `source_router.j2`, `writer.j2`, `source_registry.j2`) — the `.j2` files are | ||
| authoritative for the variables they actually use. | ||
| - `docs/source/customization/swapping-models.md`: choosing hosted vs. self-hosted | ||
| NIMs and pointing config at them. | ||
| - `docs/source/customization/configuration-reference.md`: the `llms` section and | ||
| each agent's config fields (`deep_research_agent`, `clarifier_agent`, …). | ||
| - `src/aiq_agent/common/prompt_utils.py`: `load_prompt` and | ||
| `render_prompt_template`. | ||
| - `src/aiq_agent/common/llm_provider.py`: `LLMRole` and `LLMProvider.configure`, | ||
| which bind a resolved LLM to an agent role (used by the deep research agent). | ||
| - Templates to model on: `src/aiq_agent/agents/deep_researcher/prompts/*.j2` | ||
| (orchestrator, planner, researcher, source_router, writer) and | ||
| `src/aiq_agent/agents/clarifier/prompts/*.j2`. Other agents have prompts too | ||
| (e.g. `shallow_researcher`, `chat_researcher`) — check | ||
| `src/aiq_agent/agents/*/prompts/`. | ||
|
|
||
| Longer procedures live in this bundle: | ||
|
|
||
| - [references/prompt-templates.md](references/prompt-templates.md): where templates | ||
| live, how they load and render, template variables, citation rules, and how to | ||
| edit or add one safely. | ||
| - [references/model-selection.md](references/model-selection.md): the `llms` | ||
| section, per-agent LLM fields, role binding via `LLMProvider`, and swapping models. | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. Identify the target agent and whether the change is a prompt or a model. | ||
| 2. For a prompt: edit the relevant `src/aiq_agent/agents/<agent>/prompts/*.j2` | ||
| template; keep its variables and citation rules intact (see the references). | ||
| 3. For a model: add or point an `llms:` entry in the config and set the agent's | ||
| role field (e.g. `orchestrator_llm`, `planner_llm`, `researcher_llm`, | ||
| `writer_llm`, `source_router_llm`) to that ref — do not edit Python to swap a | ||
| model. | ||
| 4. Keep token cost in mind: prefer reordering static instructions before dynamic | ||
| content (KV-cache reuse) and a cheaper model for low-stakes roles. | ||
| 5. Validate (below): lint any changed Python, run the agent's tests, and | ||
| smoke-run the CLI against the config you changed. | ||
| 6. Summarize changed files and paste the validation evidence. | ||
|
|
||
| ## Validation | ||
|
|
||
| Run the narrowest checks first; broaden only if you touched shared code. | ||
|
|
||
| ```bash | ||
| uv run ruff check src/aiq_agent # only if you changed Python | ||
| uv run pytest tests/aiq_agent/agents/<agent> # the agent's tests (a prompt-only edit may have none) | ||
| ./scripts/start_cli.sh --config_file <your config> # smoke against the config you edited | ||
| ``` | ||
|
|
||
| Expected: the agent loads its templates without a Jinja2 error and runs with the | ||
| configured model. A bare `./scripts/start_cli.sh` uses the fixed default | ||
| (`configs/config_cli_default.yml`), so pass `--config_file` to exercise your | ||
| change. For a prompt-only edit (which often has no dedicated unit test), the | ||
| smoke run is the real check; a config/prompt-only change needs no Python lint. | ||
|
|
||
| ## Common Mistakes | ||
|
|
||
| - Breaking a template variable or the STRICT citation rules in | ||
| `docs/source/customization/prompts.md`, which degrades report grounding. | ||
| - Hard-coding specific queries, domains, or source/tool names into a template, | ||
| which biases the agent toward one task and breaks generalization. Source/domain | ||
| selection is data-driven (`data_source_registry`, `source_router.j2`); keep | ||
| prompts task-agnostic. | ||
| - Hard-coding a model name in Python instead of using an `llms:` ref and the | ||
| agent's role field, so the model can no longer be swapped from config. | ||
| - Changing an agent's default model when you meant a single sub-role. The deep | ||
| research agent's default is `orchestrator_llm` (there is no generic `llm` | ||
| field); the clarifier's default is `llm`. Editing the default shifts every | ||
| unset role. | ||
| - Introducing a large dynamic prefix that defeats KV-cache reuse and raises cost. | ||
| - Pointing an agent's role at a model whose entry is not defined in `llms:`. | ||
|
|
||
| ## Related Skills | ||
|
|
||
| - `aiq-add-tool` | ||
| - `aiq-add-data-source` | ||
| - `aiq-release-qa` | ||
| - `aiq-prepare-pr` | ||
84 changes: 84 additions & 0 deletions
84
.agents/skills/aiq-customize-prompts-models/references/model-selection.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| <!-- | ||
| SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| SPDX-License-Identifier: Apache-2.0 | ||
| --> | ||
|
|
||
| # Model selection | ||
|
|
||
| Authoritative sources: `docs/source/customization/swapping-models.md` and the | ||
| `llms` section of `docs/source/customization/configuration-reference.md`. | ||
|
|
||
| ## Define models once, reference them by name | ||
|
|
||
| Declare each model in the config `llms:` section, then reference it by name from | ||
| an agent. Do not hard-code model names in Python. | ||
|
|
||
| ```yaml | ||
| llms: | ||
| nemotron_super_llm: | ||
| _type: nim | ||
| model_name: <a capable model> | ||
| gpt_oss_llm: | ||
| _type: nim # `openai` is also supported (also takes model_name) | ||
| model_name: <a cheaper model> | ||
| ``` | ||
|
|
||
| ## Assign a model to an agent role | ||
|
|
||
| Agents expose per-role LLM fields, but the two agents wire them differently — so | ||
| check the agent you are editing. | ||
|
|
||
| **Deep research agent** (`src/aiq_agent/agents/deep_researcher/register.py`) | ||
| defines `orchestrator_llm` (required) plus `source_router_llm`, `researcher_llm`, | ||
| `planner_llm`, and `writer_llm` (`LLMRef | None`). It seeds the provider default | ||
| from `orchestrator_llm` (`LLMProvider.set_default(...)`) and binds each set role | ||
| with `LLMProvider.configure(LLMRole.<ROLE>, llm)` | ||
| (`src/aiq_agent/common/llm_provider.py`). Field → role: | ||
|
|
||
| | Config field | `LLMRole` | | ||
| | :-- | :-- | | ||
| | `orchestrator_llm` (required) | `ORCHESTRATOR` — also the provider default | | ||
| | `source_router_llm` | `ROUTER` | | ||
| | `researcher_llm` | `RESEARCHER` | | ||
| | `planner_llm` | `PLANNER` | | ||
| | `writer_llm` | `REPORT_WRITER` | | ||
|
|
||
| An unset role falls back to the provider default (the `orchestrator_llm` model). | ||
| There is **no** generic `llm` field on the deep research agent. | ||
|
|
||
| **Clarifier** (`src/aiq_agent/agents/clarifier/register.py`) defines `llm` (its | ||
| default) and `planner_llm`. It does **not** use `LLMProvider.configure` for the | ||
| role — it passes `planner_llm` straight to the agent constructor, and `planner_llm` | ||
| falls back to `llm` when unset. | ||
|
|
||
| ```yaml | ||
| functions: | ||
| deep_research_agent: | ||
| _type: deep_research_agent | ||
| orchestrator_llm: nemotron_super_llm # required; also the default for unset roles | ||
| source_router_llm: nemotron_super_llm | ||
| researcher_llm: nemotron_super_llm | ||
| planner_llm: gpt_oss_llm # cheaper model for planning | ||
| writer_llm: gpt_oss_llm | ||
| ``` | ||
|
|
||
| This mirrors the real configs (for example | ||
| `configs/config_domain_routing_and_skills.yml`); copy field names from there | ||
| rather than guessing. | ||
|
|
||
| ## Swapping to a self-hosted NIM | ||
|
|
||
| Follow `swapping-models.md`: run the NIM locally, then point the `llms:` entry's | ||
| endpoint/model at it. Mind the hosted-API limitations and mitigations the doc | ||
| lists. | ||
|
|
||
| ## Validation | ||
|
|
||
| ```bash | ||
| ./scripts/start_cli.sh --config_file <the config where you set the role LLMs> # agent starts with the assigned models | ||
| uv run pytest tests/aiq_agent/agents/deep_researcher | ||
| ``` | ||
|
|
||
| Expected: the agent starts with the configured models and its tests pass. A bare | ||
| `start_cli.sh` runs the fixed default config, so pass the config you edited. Every | ||
| role ref must resolve to an entry in `llms:`. |
65 changes: 65 additions & 0 deletions
65
.agents/skills/aiq-customize-prompts-models/references/prompt-templates.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| <!-- | ||
| SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| SPDX-License-Identifier: Apache-2.0 | ||
| --> | ||
|
|
||
| # Prompt templates | ||
|
|
||
| Authoritative sources: the `.j2` files themselves (for the variables a template | ||
| actually uses) and `docs/source/customization/prompts.md` (for the documented | ||
| workflow and many template variables). Note `prompts.md` does not cover every | ||
| template — e.g. `source_router.j2`, `writer.j2`, and `source_registry.j2` have no | ||
| variable section there yet — so read the `.j2` file when in doubt. | ||
|
|
||
| ## Where templates live | ||
|
|
||
| Each agent owns its Jinja2 templates under | ||
| `src/aiq_agent/agents/<agent>/prompts/*.j2`. For example, the deep researcher has | ||
| `orchestrator.j2`, `planner.j2`, `researcher.j2`, `source_router.j2`, `writer.j2`, | ||
| and `source_registry.j2`; the clarifier has `plan_generation.j2` and | ||
| `research_clarification.j2`; `shallow_researcher` and `chat_researcher` have their | ||
| own as well. | ||
|
|
||
| ## How templates load and render | ||
|
|
||
| - `load_prompt(path, name)` in `src/aiq_agent/common/prompt_utils.py` reads a | ||
| template file as a string. | ||
| - `render_prompt_template(template, **kwargs)` (same module) renders it with | ||
| Jinja2, injecting the variables. `prompts.md` has a "Template Variables" section | ||
| for many agents; for a template it doesn't list, read the `.j2` to see which | ||
| variables it references. | ||
|
|
||
| ## Editing a template safely | ||
|
|
||
| 1. Keep every `{{ variable }}` the agent passes in; removing one breaks rendering | ||
| or silently drops context. | ||
| 2. Preserve the **Citation Rules (STRICT)** section in `prompts.md` — report | ||
| grounding depends on the model emitting citations exactly as instructed. | ||
| 3. Prefer putting static instructions before dynamic content so the KV cache is | ||
| reused across calls (lower latency and token cost). | ||
| 4. Keep the template task-agnostic — don't hard-code specific queries, domains, or | ||
| source/tool names; source/domain routing is data-driven (`data_source_registry`, | ||
| `source_router.j2`), and hard-coding it bypasses that routing. | ||
| 5. Editing an existing `.j2` needs **no** code change. | ||
|
|
||
| ## Adding a new template | ||
|
|
||
| This is the one prompt change that touches Python. Follow "Creating a New | ||
| Template" in `prompts.md`: | ||
|
|
||
| 1. Add the `.j2` under the agent's `prompts/` directory. | ||
| 2. Write the template (keep variable names consistent with what the agent passes). | ||
| 3. **Wire it in the agent's Python** — load it with `load_prompt` and render it | ||
| with `render_prompt_template` (this is `prompts.md` Step 3). Without this step | ||
| the new template is never used. | ||
|
|
||
| ## Validation | ||
|
|
||
| ```bash | ||
| ./scripts/start_cli.sh --config_file <a config using that agent> # template loads (no Jinja2 error) | ||
| uv run pytest tests/aiq_agent/agents/<agent> # if the agent has tests | ||
| ``` | ||
|
|
||
| Expected: the agent starts and renders the template without error. A bare | ||
| `start_cli.sh` runs the fixed default config, so pass the config that exercises | ||
| the agent whose template you changed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| --- | ||
| name: aiq-maintain-ci | ||
| description: Use when changing AI-Q continuous integration, pre-commit, or contributor governance — editing .github/workflows/ (ci, ui, skills-eval, request-nvskills-ci), .pre-commit-config.yaml hooks, .github/CODEOWNERS, .coderabbit.yaml, copy-pr-bot, or the .github/skill-eval harness — and validating those changes without breaking the gate. | ||
| license: Apache-2.0 | ||
| compatibility: Claude Code, Codex, Cursor, OpenCode, and Agent Skills-compatible tools. | ||
| metadata: | ||
| version: "0.1.0" | ||
| source-repo: "NVIDIA-AI-Blueprints/aiq" | ||
| tags: "aiq ci github-actions pre-commit governance skill-eval" | ||
| allowed-tools: Read Bash Edit | ||
| --- | ||
|
|
||
| # Maintain AI-Q CI and Governance | ||
|
|
||
| Use this skill when a developer changes AI-Q's CI, pre-commit hooks, or | ||
| contributor governance — the GitHub Actions workflows, the pre-commit config, | ||
| CODEOWNERS, the CodeRabbit review config, the copy-pr-bot mirror, or the | ||
| product-level skill-eval harness. These surfaces gate every PR, so a change must | ||
| keep the gate working and must not weaken security or review rules. | ||
|
|
||
| ## Start Here | ||
|
|
||
| - Identify the surface: a workflow (`.github/workflows/`), a pre-commit hook | ||
| (`.pre-commit-config.yaml`), governance (`.github/CODEOWNERS`, | ||
| `.coderabbit.yaml`, `.github/copy-pr-bot.yaml`), or the skill-eval harness | ||
| (`.github/skill-eval/`). | ||
| - Read the authoritative files below and `CONTRIBUTING.md` "CI and Bot Workflow" | ||
| before editing — the bot/mirror flow is easy to break. | ||
| - Make the smallest change; do not weaken secret detection, auth gating, or | ||
| code-owner review without a prior design discussion (see `AGENTS.md`). | ||
| - Remember CI runs on the copy-pr-bot mirror after `/ok to test`, not on push. | ||
|
|
||
| ## Authoritative References | ||
|
|
||
| - [CONTRIBUTING.md](../../../CONTRIBUTING.md): "CI and Bot Workflow" — copy-pr-bot | ||
| mirroring to `pull-request/<N>`, `/ok to test`, `/nvskills-ci`, `/merge`. | ||
| - [AGENTS.md](../../../AGENTS.md): "Git and PR hygiene" and the validation | ||
| commands CI mirrors. | ||
| - `.github/workflows/ci.yml`: jobs `pre-commit`, `test` (pytest + coverage), | ||
| `helm-lint`, `test-scripts`. The `pre-commit` job runs Ruff separately and | ||
| `SKIP=ruff-check,ruff-format,pytest,helm-lint pre-commit run --all-files` — so | ||
| pytest/helm-lint run as their own jobs, not via the hook. | ||
| - `.github/workflows/ui.yml`: jobs `install`, `lint`, `type-check`, `unit-test`, | ||
| `build`. | ||
| - `.github/workflows/skills-eval.yml`: the Skills Eval gate (push + | ||
| `workflow_dispatch`; `detect-changes` path gate → `generate-datasets` spec | ||
| validation → `harbor-eval` on the self-hosted `aiq-eval` runner). | ||
| - `.github/workflows/request-nvskills-ci.yml`: comment-triggered NVSkills CI. | ||
| - `.pre-commit-config.yaml`: the hook set. Note `pytest` and `helm-lint` are | ||
| `stages: [push]` (see the reference for what that means locally). | ||
| - `.github/CODEOWNERS`, `.coderabbit.yaml`, `.github/copy-pr-bot.yaml`: review | ||
| routing, path-scoped automated review, and the PR mirror. | ||
|
|
||
| Longer procedures live in this bundle: | ||
|
|
||
| - [references/workflows-and-hooks.md](references/workflows-and-hooks.md): the | ||
| workflows, their jobs/triggers, the copy-pr-bot mirror flow, and the pre-commit | ||
| hook inventory (incl. the push-stage hooks). | ||
| - [references/skill-eval-harness.md](references/skill-eval-harness.md): how the | ||
| `.github/skill-eval/` regression gate finds specs, runs adapters, and verifies. | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. Locate the exact workflow, hook, or governance file and read it plus the | ||
| relevant `CONTRIBUTING.md` section. | ||
| 2. Make the smallest scoped change; keep job names, triggers, and the | ||
| `detect-changes` path gate intact unless that is the change. | ||
| 3. Lint the change: validate YAML and, for workflows, run `actionlint` if it is | ||
| installed. | ||
| 4. Reproduce the affected gate locally where possible — run the pre-commit hooks | ||
| or the job's underlying command (see the references). | ||
| 5. Note that the real CI run happens on the copy-pr-bot mirror after a maintainer | ||
| comments `/ok to test`. | ||
| 6. Summarize changed files and the local validation evidence. | ||
|
|
||
| ## Validation | ||
|
|
||
| ```bash | ||
| uv run pre-commit run --all-files # default-stage hooks (NOT pytest/helm-lint) | ||
| uv run pre-commit run --all-files --hook-stage push # adds the push-stage pytest + helm-lint hooks | ||
| uv run pre-commit run --files <changed> # faster, during iteration | ||
| actionlint .github/workflows/<file>.yml # if actionlint is installed | ||
| ``` | ||
|
|
||
| Expected: hooks pass (or only auto-fix) and any edited workflow is valid YAML. | ||
| `pytest` and `helm-lint` are push-stage, so the default `--all-files` run skips | ||
| them — CI runs them as the dedicated `test` and `helm-lint` jobs. For skill-eval | ||
| changes, see the harness reference: full Harbor runs need the self-hosted runner, | ||
| so validate spec/adapter shape locally and rely on the mirrored CI run. | ||
|
|
||
| ## Common Mistakes | ||
|
|
||
| - Adding a trigger `paths:` filter to `skills-eval.yml` instead of using the | ||
| `detect-changes` job — the comment in that workflow explains why path-filtering | ||
| the trigger is wrong here. | ||
| - Weakening `detect-secrets`, auth gating, or code-owner review to make CI pass. | ||
| - Expecting CI to run on push; it runs on the copy-pr-bot mirror after | ||
| `/ok to test`. | ||
| - Assuming `pre-commit run --all-files` reproduces the whole gate — `pytest` and | ||
| `helm-lint` are `stages: [push]`, so they do not run at the default stage. Use | ||
| `--hook-stage push` (or run them directly), and remember CI runs them as | ||
| separate jobs. | ||
| - Editing `.github/CODEOWNERS` without updating the paths it routes, so reviews | ||
| go to the wrong owners. | ||
|
|
||
| ## Related Skills | ||
|
|
||
| - `aiq-release-qa` | ||
| - `aiq-prepare-pr` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.