Skip to content

feat(bfcl): multi-model nightly A/B matrix on per-model runners - #1791

Merged
key4ng merged 15 commits into
mainfrom
feat/bfcl-multimodel-matrix
Jun 21, 2026
Merged

key4ng merged 15 commits into
mainfrom
feat/bfcl-multimodel-matrix

Conversation

@key4ng

@key4ng key4ng commented Jun 19, 2026 •

Copy link
Copy Markdown
Member

Description

Problem

The nightly BFCL A/B (scripts/bfcl/) — the parser-parity comparison of pure vLLM vs SMG→vLLM gRPC — only exercised a single model (Qwen/Qwen3.6-27B) on one 4-gpu-h100 node. We want coverage of the mid-2026 target SKUs (Kimi K2.6, DeepSeek V4, MiniMax M2.7, gpt-oss-120b) and the ability to run the large models on Blackwell (B300) hardware.

Solution

Convert the single A/B job into a 5-model matrix, each leg on its own runner with its own parser config. Because the A/B isolates the parser frontend (model size is irrelevant — a smaller same-family checkpoint exercises the identical parse path), the large legs use flash/int4 checkpoints that fit half a B300 node at TP=4, so every leg runs both arms concurrently with no perf tuning. gpt-oss needs no SMG tool-call-parser — SMG's HarmonyDetector auto-routes it through the harmony pipeline — so launch_arm.sh now omits the flag when unset.

leg runner TP/arm vLLM tool/reason SMG tool/reason
qwen3.6 4-gpu-h100 2 qwen3_xml/qwen3 qwen_xml/qwen3
gpt-oss 4-gpu-h100 2 openai/— (none → harmony auto)/—
deepseek-v4 (Flash) blackwell 4 deepseek_v4/deepseek_v4 deepseek_v4/deepseek_v31†
minimax-m2.7 blackwell 4 minimax_m2/minimax_m2 minimax_m2/minimax
kimi-k2.6 (int4) blackwell 4 kimi_k2/kimi_k2 kimik2/kimi_k25†

Changes

  • scripts/bfcl/launch_arm.sh: make the SMG arm's --tool-call-parser conditional (omit when BFCL_SMG_TOOL_PARSER is empty → gpt-oss harmony auto-detect).
  • .github/workflows/nightly-bfcl.yml: convert bfcl-ab to a 5-leg matrix on per-model runners (4-gpu-h100, blackwell); leg filtering (dispatch only, PR-runs-H100-only) lives in a new setup job that emits the matrix as JSON, since the matrix context isn't allowed in a job-level if.
  • scripts/bfcl/README.md: per-model parser table + matrix/runner docs.
  • run_ab.py is unchanged — it already loops over both arms.

† To confirm on the first nightly: SMG has no exact deepseek_v4/kimi_k2 reasoning parser yet (using closest deepseek_v31/kimi_k25, marked TODO(confirm)); the new model IDs and the int4 Kimi invocation should be verified against the installed vLLM build.

Test Plan

  • shellcheck scripts/bfcl/launch_arm.sh passes; behavioral check confirms the SMG tool-call-parser is omitted when empty and included when set.
  • actionlint .github/workflows/nightly-bfcl.yml clean (only pre-existing custom-runner-label warnings); matrix parses to the 5 expected legs; setup filter logic verified for schedule / PR / dispatch-only / unknown-leg (guarded) cases.
  • PR trigger runs the quick non-live subset on the 4-gpu-h100 legs only as an end-to-end pipeline sanity check; full validation is the scheduled nightly on real runners.
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • (Optional) Documentation updated
  • (Optional) Please join us on Slack #sig-smg to discuss, review, and merge PRs

Summary by CodeRabbit

  • New Features
    • Nightly BFCL workflow can run a single selected matrix leg; the matrix is generated dynamically and dispatch overrides now fall back to leg defaults.
  • Bug Fixes
    • SMG gateway only applies the tool-call parser when explicitly provided, otherwise it auto-detects routing.
  • Documentation
    • Updated BFCL nightly documentation with the new per-model parser flags and clearer matrix/runner behavior.
  • Chores
    • Improved arm startup logging with live log streaming; updated teardown to reliably stop full process groups.

key4ng added 5 commits June 18, 2026 17:48
…to-detect)

Signed-off-by: key4ng <rukeyang@gmail.com>
…ntext in if

GitHub Actions does not allow the \`matrix\` context in a job-level \`if\`
(only github/inputs/needs/vars are permitted there). The \`bfcl-ab\` job was
referencing \`matrix.name\` and \`matrix.runner\` in its \`if\`, causing a
runtime "Unrecognized named-value: 'matrix'" error.

Fix: add a lightweight \`setup\` job that emits the filtered leg list as JSON
via a Python heredoc (dispatch \`only\` selector; exclude Blackwell legs on
PRs). \`bfcl-ab\` now consumes it with \`fromJSON(needs.setup.outputs.matrix)\`
and its \`if\` no longer references \`matrix\`. The static \`strategy.matrix.include\`
list in \`bfcl-ab\` is deleted (the leg definitions live in the \`setup\` Python).

Signed-off-by: key4ng <rukeyang@gmail.com>
Signed-off-by: key4ng <rukeyang@gmail.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation ci CI/CD configuration changes labels Jun 19, 2026
@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The nightly BFCL workflow is refactored to drive model legs from a dynamically generated matrix. A new setup job emits per-leg JSON filtered by a new only dispatch input. The bfcl-ab job consumes this matrix; env vars, GPU lists, and TP are sourced per-leg. launch_arm.sh adds real-time log streaming to both arms, makes --tool-call-parser conditional on SMG_TOOL_PARSER being set, and improves process group cleanup on shutdown. The README is updated with matching parser and matrix documentation.

Changes

BFCL Nightly Matrix Refactor

Layer / File(s) Summary
workflow_dispatch inputs: only selector and empty defaults
.github/workflows/nightly-bfcl.yml
Adds an only leg selector to workflow_dispatch and changes all model/parser override inputs to empty defaults so matrix values are used when overrides are absent.
setup job: matrix generation and filtering
.github/workflows/nightly-bfcl.yml
Adds a setup job that emits per-leg matrix JSON via an inline Python script, validates against known leg names, filters legs by only, and passes the result to bfcl-ab for downstream consumption.
Job dependencies and per-leg environment wiring
.github/workflows/nightly-bfcl.yml
Wires bfcl-ab to depend on both build-wheel and setup; consumes the generated matrix in strategy.matrix; and sources MODEL, BFCL_MODEL_FC, GPU partitions (matrix.gpu_a/matrix.gpu_b), BFCL_TP, and tool/reasoning parsers from dispatch overrides or matrix defaults.
Real-time log streaming and conditional tool-call-parser
scripts/bfcl/launch_arm.sh
Introduces a stream_log helper that tails logfiles to stderr in the background. Arm A startup streams its log while waiting for the server health endpoint. Arm B worker and gateway startup both stream their logs; the SMG command appends --tool-call-parser only when SMG_TOOL_PARSER is non-empty, enabling auto-routing when unset.
Process group cleanup and graceful shutdown
scripts/bfcl/launch_arm.sh
Updates the stop logic to terminate entire process groups (using negative PIDs) for each recorded session PID, replacing the prior single-PID kill approach, with staged SIGTERM then SIGKILL and a drain delay.
Summary header and artifact naming with matrix.name
.github/workflows/nightly-bfcl.yml
Prefixes rendered markdown summaries with a leg-specific header (matrix name and model) and includes matrix.name in the uploaded artifact name alongside github.run_id.
README: parser flag table and matrix/runners docs
scripts/bfcl/README.md
Replaces the old vLLM-specific parser table with a nightly-matrix-keyed table covering runner/TP and tool-call/reasoning parser values per model, adds fallback and auto-routing notes, and documents the Matrix & runners section with runner assignments, concurrent A/B execution, checkpoint rationale, dispatch override behavior, and PR subset sanity checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • lightseekorg/smg#1724: Introduced the original nightly BFCL A/B framework in the same workflow, README, and launch_arm.sh files that this PR directly extends with matrix-driven legs and improved shutdown handling.

Suggested reviewers

  • gongwei-130
  • CatherineSue
  • XinyueZhang369
  • slin1237

Poem

🐇 The matrix springs to life at last,
Each model leg runs unsurpassed!
No hardcoded values here to stay—
The only flag picks the right way.
Logs stream live as arms take flight,
A bunny's CI: pure delight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: converting the nightly BFCL A/B test to a multi-model matrix on per-model runners, which aligns perfectly with the changeset's core objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/bfcl-multimodel-matrix

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the README documentation to detail the nightly matrix configurations, runners, and reasoning-parser fallbacks, and modifies launch_arm.sh to conditionally append the --tool-call-parser flag. Feedback identifies a bug where SMG_TOOL_PARSER falls back to a default value when BFCL_SMG_TOOL_PARSER is explicitly set to an empty string, and suggests refactoring the conditional check to a standard if block for better compatibility with set -e.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

)
# Empty tool-call-parser => let SMG auto-detect (e.g. gpt-oss routes through
# the harmony pipeline via HarmonyDetector; passing a parser there is wrong).
[ -n "$SMG_TOOL_PARSER" ] && smg_cmd+=(--tool-call-parser "$SMG_TOOL_PARSER")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There is a bug that prevents BFCL_SMG_TOOL_PARSER="" from actually omitting the --tool-call-parser flag.

On line 36, SMG_TOOL_PARSER is initialized using the :- operator:

SMG_TOOL_PARSER="${BFCL_SMG_TOOL_PARSER:-qwen}"

Because of :-, if BFCL_SMG_TOOL_PARSER is set to an empty string (""), it falls back to "qwen". Thus, SMG_TOOL_PARSER will never be empty, and --tool-call-parser qwen will always be appended, breaking the gpt-oss leg.

To fix this, change line 36 to use ${BFCL_SMG_TOOL_PARSER-qwen} (without the colon), which only falls back to "qwen" if the variable is completely unset, preserving the explicit empty string.

Additionally, for better compatibility with set -e (to avoid returning a non-zero exit code when the condition is false), refactor the one-liner && into a standard if block.

Suggested change
[ -n "$SMG_TOOL_PARSER" ] && smg_cmd+=(--tool-call-parser "$SMG_TOOL_PARSER")
if [ -n "$SMG_TOOL_PARSER" ]; then
smg_cmd+=(--tool-call-parser "$SMG_TOOL_PARSER")
fi
References
  1. In shell scripts with set -e enabled, avoid chaining commands with && if you expect the script to exit immediately upon the failure of the first command.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-structured PR. Matrix generation, leg filtering, conditional parser flags, and env var fallback semantics all look correct. No issues found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cbc70e91d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

)
# Empty tool-call-parser => let SMG auto-detect (e.g. gpt-oss routes through
# the harmony pipeline via HarmonyDetector; passing a parser there is wrong).
[ -n "$SMG_TOOL_PARSER" ] && smg_cmd+=(--tool-call-parser "$SMG_TOOL_PARSER")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep the SMG parser truly unset for gpt-oss

When the gpt-oss matrix leg sets BFCL_SMG_TOOL_PARSER to the empty matrix.smg_tool, launch_arm.sh still initializes SMG_TOOL_PARSER with ${BFCL_SMG_TOOL_PARSER:-qwen}, so the value becomes qwen; this added condition is then true and the gateway is launched with --tool-call-parser qwen. That bypasses the Harmony auto-detect path the gpt-oss leg depends on, so this leg is tested with the wrong parser or can fail at startup. The default needs to apply only when the variable is unset, not when it is explicitly empty.

Useful? React with 👍 / 👎.

Comment on lines +133 to +135
{"name": "deepseek-v4", "runner": "blackwell", "tp": 4,
"gpu_a": "0,1,2,3", "gpu_b": "4,5,6,7",
"model": "deepseek-ai/DeepSeek-V4-Flash", "bfcl_model": "deepseek-ai/DeepSeek-V4-Flash-FC",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Download the matrix-selected checkpoint

For these new Blackwell matrix legs, the selected checkpoints are TP=4 models, but the later Stage model weights step is still hard-coded to scripts/ci_download_model.sh --gpu-tier 2; that script's tier resolver only downloads models with spec['tp'] <= tier (scripts/ci_download_model.sh:37-48). On a cold Blackwell runner these checkpoints are not pre-staged, so launch_arm.sh has only its 420s startup wait while vLLM tries to fetch hundreds of GB outside the download lock, which makes the new nightly legs time out before serving.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/nightly-bfcl.yml:
- Around line 30-35: The workflow descriptions for `model` and `bfcl_model` warn
users not to override only one parameter, but there is no actual validation
enforcing this constraint. Add a setup-time validation step that implements an
XOR check before matrix execution to ensure either both `model` and `bfcl_model`
are provided together or neither is provided. If the check detects that only one
of these parameters is set (anywhere in the workflow where they appear,
including around lines 185-186), the workflow should fail immediately with a
clear error message about the mismatched pair requirement, preventing any
downstream matrix jobs from executing.
- Line 247: The `actions/upload-artifact@v7` action reference uses a mutable
version tag which poses a supply-chain security risk. Replace the `@v7` tag with
a full-length commit SHA (format: `actions/upload-artifact@{COMMIT_SHA} #
v7.0.1`) to pin the action to an immutable reference. Apply this same fix to all
other mutable action references in the workflow file (also present at lines 72,
75, 92, and 190-191) to ensure consistent security practices across the entire
workflow.
- Line 213: The bash parameter expansion in scripts/bfcl/launch_arm.sh at line
40 uses the `${BFCL_SMG_TOOL_PARSER:-qwen}` syntax which treats empty strings as
unset variables and defaults to qwen, breaking the auto-detect feature that
relies on empty parser values. Change the parameter expansion from `:-`
(colon-dash) to just `-` (dash only) so that empty string values pass through
unchanged and only truly unset variables trigger the qwen default, preserving
the intended auto-detection behavior via HarmonyDetector.

In `@scripts/bfcl/README.md`:
- Line 66: In the gpt-oss note that explains the tool-call-parser behavior
(after line 74), add a clarification statement that gpt-oss also lacks a
reasoning-parser for both the openai arm and the secondary arm. This will ensure
readers understand that the "—" symbols in both reasoning-parser columns for
gpt-oss are intentional and explained, preventing confusion about missing
configuration details.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3174226b-125a-4f0c-b380-cdd0e455b8fd

📥 Commits

Reviewing files that changed from the base of the PR and between a13ab18 and 0cbc70e.

📒 Files selected for processing (3)
  • .github/workflows/nightly-bfcl.yml
  • scripts/bfcl/README.md
  • scripts/bfcl/launch_arm.sh

Comment thread .github/workflows/nightly-bfcl.yml
Comment thread .github/workflows/nightly-bfcl.yml
} >> "$GITHUB_STEP_SUMMARY" || echo "no report produced for ${{ matrix.name }}" >> "$GITHUB_STEP_SUMMARY"
- name: Upload comparison
if: always()
uses: actions/upload-artifact@v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only check for mutable action refs in this workflow.
nl -ba .github/workflows/nightly-bfcl.yml | rg -n 'uses:\s*[^#]+@v[0-9]+'

Repository: lightseekorg/smg

Length of output: 101


🏁 Script executed:

# First, check if the file exists and read around line 247
if [ -f ".github/workflows/nightly-bfcl.yml" ]; then
  echo "=== File exists, reading around line 247 ==="
  sed -n '240,255p' .github/workflows/nightly-bfcl.yml | cat -n
else
  echo "File not found"
  git ls-files | grep -i nightly
fi

Repository: lightseekorg/smg

Length of output: 830


🏁 Script executed:

# Count lines and find all 'uses' directives with version tags
echo "=== Total lines and all 'uses' with version tags ==="
wc -l .github/workflows/nightly-bfcl.yml
echo ""
echo "=== All 'uses' directives with `@v` or `@tags` ==="
grep -n "uses:" .github/workflows/nightly-bfcl.yml | head -20

Repository: lightseekorg/smg

Length of output: 538


🌐 Web query:

GitHub Actions security best practice pin commit SHA vs version tag

💡 Result:

In GitHub Actions, pinning to a full-length commit SHA is considered the security gold standard, whereas pinning to a version tag is a matter of convenience that carries inherent risks [1][2]. The fundamental difference lies in immutability: 1. Commit SHA (Immutable): A full-length commit SHA is a unique, fixed identifier for a specific state of a repository [3][4]. Once pinned to a SHA, your workflow is guaranteed to execute the exact same code every time, making it immune to "tag retargeting" or "force-push" attacks where a malicious actor alters the code behind a seemingly legitimate tag [1][2][5]. 2. Version Tag (Mutable): Tags (e.g., v4, v4.1.0) are references that can be moved or deleted by repository maintainers [1][5]. Even if you trust an action's author, a compromised account or repository could allow an attacker to update a tag to point to malicious code, which your workflows would then automatically adopt [1][2][4]. Best Practices: - Always use the full-length commit SHA (e.g., actions/checkout@3df4ab1) instead of an abbreviated one [3][4]. - Maintain readability and auditability by including the version tag as a comment in your workflow file (e.g., uses: actions/checkout@3df4ab1 # v4.0.0) [4][6]. - Automate the maintenance of these pins. Tools like Renovate (using presets such as helpers:pinGitHubActionDigests) or Dependabot can automatically open pull requests to update your SHAs when new releases are published, allowing you to review changes before merging [7][4][5]. - If you are an administrator, consider enabling organization or repository-level policies that enforce commit SHA pinning, which will cause any non-pinned actions to fail [1][4][8]. While pinning to a tag is permissible if you strictly trust the creator, it remains a secondary choice compared to the immutability and security provided by commit SHAs [1][2].

Citations:


🌐 Web query:

actions/upload-artifact@v7 commit SHA pinning security

💡 Result:

Pinning actions/upload-artifact to a commit SHA is a recommended security best practice for GitHub Actions workflows [1][2][3]. As of June 2026, the latest version is v7.0.1 [4][5]. Security Context Using a tag like @v7 is a mutable reference; if the action's repository is compromised, an attacker could force-push a new commit to that tag, potentially injecting malicious code into your workflows [1][3]. Pinning to an immutable 40-character commit SHA ensures that your workflow always executes the exact same code version, protecting against supply chain attacks [6][1][3]. Implementation To use SHA pinning, replace the tag in your workflow file with the full commit hash. To maintain readability and allow automated tools to track updates, it is standard practice to include the version as a comment [6][7][3]: uses: actions/upload-artifact@bbbca2d # v7.0.1 Automated Maintenance You do not need to manually hunt for SHA updates. Tools like Dependabot and Renovate support SHA-pinned actions and will automatically open pull requests to update the SHA when a new release is published, keeping your workflows both secure and current [6][7][3]. Policy Enforcement Note that many organizations now enforce SHA pinning via GitHub organization-level policies [8][7]. If such a policy is active, workflows using tag-based references (e.g., @v7) will fail [7]. Furthermore, if you maintain actions that reference other actions internally, those sub-actions should also be SHA-pinned to ensure compatibility with these strict security policies [7].

Citations:


Pin actions/upload-artifact@v7 to a commit SHA.

Line 247 uses a mutable version tag (@v7), which is vulnerable to tag retargeting attacks. Pinning to a full-length commit SHA (e.g., actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.1) eliminates this supply-chain risk by making the action reference immutable. This aligns with GitHub's security best practices for Actions.

Note: This same pattern exists elsewhere in the workflow (e.g., lines 72, 75, 92, 190–191). Consider fixing all mutable action references.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 247-247: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/nightly-bfcl.yml at line 247, The
`actions/upload-artifact@v7` action reference uses a mutable version tag which
poses a supply-chain security risk. Replace the `@v7` tag with a full-length
commit SHA (format: `actions/upload-artifact@{COMMIT_SHA} # v7.0.1`) to pin the
action to an immutable reference. Apply this same fix to all other mutable
action references in the workflow file (also present at lines 72, 75, 92, and
190-191) to ensure consistent security practices across the entire workflow.

Source: Linters/SAST tools

Comment thread scripts/bfcl/README.md
… names

Signed-off-by: key4ng <rukeyang@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
scripts/bfcl/README.md (1)

71-74: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Clarify that gpt-oss has no reasoning-parser for either arm.

The table shows gpt-oss with "—" for both reasoning-parser columns, and the explanation (lines 71–74) covers only the tool-call-parser behavior. The absence of reasoning-parser for gpt-oss deserves a brief mention to prevent confusion.

💡 Suggested clarification

Extend the gpt-oss note (after line 74) to clarify reasoning-parser absence:

 > **gpt-oss has no SMG tool-call-parser.** SMG handles gpt-oss through its harmony
 > pipeline (`model_gateway/src/routers/grpc/harmony/`), auto-activated by
 > `HarmonyDetector` on a `gpt-oss` model id / `GptOssForCausalLM` architecture. So
 > the SMG arm passes **no** `--tool-call-parser` (`BFCL_SMG_TOOL_PARSER=""`).
+> Similarly, gpt-oss reasoning-content is handled natively; no explicit
+> reasoning-parser is needed on either arm.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/bfcl/README.md` around lines 71 - 74, The existing gpt-oss
explanation in the README (lines 71-74) only clarifies the absence of a
tool-call-parser for the SMG arm, but the table shows gpt-oss with "—" for both
reasoning-parser columns as well, which is not explained. Extend the gpt-oss
note after line 74 to add a brief clarification that gpt-oss also has no
reasoning-parser for either the SMG arm or the direct arm, to align with what
the table displays and prevent confusion about why both reasoning-parser columns
show dashes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/nightly-bfcl.yml:
- Around line 157-161: The setup function in the nightly-bfcl workflow currently
includes Blackwell legs in PR validation runs, which contradicts the intent to
limit PR checks to a quick H100-only sanity subset. Modify the logic in the
setup function where legs are determined or filtered to exclude Blackwell
runners when the workflow is triggered by a pull request event, ensuring that
only H100 legs are included in PR matrix runs while maintaining the full matrix
(H100 and Blackwell) for nightly/main branch runs. The validation error at line
157 checking for unknown leg values should remain unchanged.

In `@scripts/bfcl/launch_arm.sh`:
- Around line 109-111: The script uses stream_log to create background tail
processes and stores their PIDs in variables like log_tail, but if wait_http or
wait_grpc fails due to set -euo pipefail, the script exits immediately without
cleaning up these background processes. Add a trap handler near the top of the
script after variable declarations that will be triggered on EXIT to ensure all
tracked background tail process PIDs are killed. Modify the pattern wherever
stream_log is called to capture and track the returned PID in a variable, then
reference these variables in the trap handler to clean up all background
processes when the script exits, whether normally or due to an error. This
applies to the stream_log calls for log_tail variables at multiple locations
throughout the script.

---

Duplicate comments:
In `@scripts/bfcl/README.md`:
- Around line 71-74: The existing gpt-oss explanation in the README (lines
71-74) only clarifies the absence of a tool-call-parser for the SMG arm, but the
table shows gpt-oss with "—" for both reasoning-parser columns as well, which is
not explained. Extend the gpt-oss note after line 74 to add a brief
clarification that gpt-oss also has no reasoning-parser for either the SMG arm
or the direct arm, to align with what the table displays and prevent confusion
about why both reasoning-parser columns show dashes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 02855d75-a2c2-49f3-aa9b-ca06cfd63b62

📥 Commits

Reviewing files that changed from the base of the PR and between 0cbc70e and 1a95dd6.

📒 Files selected for processing (3)
  • .github/workflows/nightly-bfcl.yml
  • scripts/bfcl/README.md
  • scripts/bfcl/launch_arm.sh

Comment thread .github/workflows/nightly-bfcl.yml Outdated
Comment on lines +109 to +111
log_tail=$(stream_log "$RUN_DIR/arm_a_vllm.log")
wait_http "http://127.0.0.1:$ARM_A_PORT/health" "${BFCL_STARTUP_TIMEOUT:-420}"
kill "$log_tail" 2>/dev/null || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Tail processes may be orphaned if health checks fail.

If wait_http or wait_grpc returns non-zero (timeout or failure), the script exits immediately due to set -euo pipefail, leaving the background tail process running. In CI, the runner typically cleans up child processes when the job terminates, but on development machines these tail processes might persist.

Consider adding a trap handler to ensure cleanup on early exit.

🧹 Proposed trap-based cleanup

Add near the top of the script (after variable declarations):

+TAIL_PIDS=()
+cleanup_tails() {
+  for pid in "${TAIL_PIDS[@]}"; do
+    kill "$pid" 2>/dev/null || true
+  done
+}
+trap cleanup_tails EXIT

Then modify the pattern to track PIDs:

-    log_tail=$(stream_log "$RUN_DIR/arm_a_vllm.log")
+    log_tail=$(stream_log "$RUN_DIR/arm_a_vllm.log")
+    TAIL_PIDS+=("$log_tail")
     wait_http "http://127.0.0.1:$ARM_A_PORT/health" "${BFCL_STARTUP_TIMEOUT:-420}"
-    kill "$log_tail" 2>/dev/null || true
+    kill "$log_tail" 2>/dev/null || true

Also applies to: 128-130, 144-146

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/bfcl/launch_arm.sh` around lines 109 - 111, The script uses
stream_log to create background tail processes and stores their PIDs in
variables like log_tail, but if wait_http or wait_grpc fails due to set -euo
pipefail, the script exits immediately without cleaning up these background
processes. Add a trap handler near the top of the script after variable
declarations that will be triggered on EXIT to ensure all tracked background
tail process PIDs are killed. Modify the pattern wherever stream_log is called
to capture and track the returned PID in a variable, then reference these
variables in the trap handler to clean up all background processes when the
script exits, whether normally or due to an error. This applies to the
stream_log calls for log_tail variables at multiple locations throughout the
script.

Signed-off-by: key4ng <rukeyang@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c923ee471

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# gpt-oss SMG arm passes NO tool parser (smg_tool empty) -> harmony auto-detect.
{"name": "gpt-oss", "runner": "4-gpu-h100", "tp": 2,
"gpu_a": "0,1", "gpu_b": "2,3",
"model": "openai/gpt-oss-120b", "bfcl_model": "openai/gpt-oss-120b-FC",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use matching BFCL handlers for non-Qwen legs

For new legs such as gpt-oss/DeepSeek/MiniMax/Kimi that bfcl-eval does not already ship, the existing registration step registers $MODEL through scripts/bfcl/register_bfcl_model.py with its default QwenFCHandler. In those scenarios BFCL formats and decodes Qwen-style XML instead of the native tool-call protocol these legs are meant to compare, so the run measures Qwen-prompt compatibility or invalid scores rather than SMG/vLLM parser parity; each non-Qwen leg needs a matching/generic FC handler or should avoid this fallback when unsupported.

Useful? React with 👍 / 👎.

…or big MoEs

Signed-off-by: key4ng <rukeyang@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/nightly-bfcl.yml:
- Around line 139-140: Pin immutable model revisions for the deepseek-v4,
minimax-m2.7, and kimi-k2.6 legs in the workflow matrix to prevent supply-chain
risks when executing remote code with the --trust-remote-code flag in
vllm_extra. Modify the model references to use the format model-name@commit-sha
(e.g., deepseek-ai/DeepSeek-V4-Flash@<commit-sha>) in the matrix configuration,
and ensure that both the weight-staging and serving execution paths reference
the same pinned revision to maintain consistency throughout the nightly
automation workflow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 46ea045e-cec2-4824-b0aa-5adde161e802

📥 Commits

Reviewing files that changed from the base of the PR and between 5c923ee and 27dfd69.

📒 Files selected for processing (1)
  • .github/workflows/nightly-bfcl.yml

Comment thread .github/workflows/nightly-bfcl.yml Outdated
Comment on lines +139 to +140
"vllm_extra": "--tokenizer-mode deepseek_v4 --trust-remote-code --kv-cache-dtype fp8 --block-size 256",
"gpu_mem": "0.90", "startup_timeout": "2400"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify evidence for remote-code execution + token presence in this workflow.
# Expected: Lines showing both `HF_TOKEN` and `--trust-remote-code` in the same job.
nl -ba .github/workflows/nightly-bfcl.yml | sed -n '130,160p;184,194p;218,230p'

Repository: lightseekorg/smg

Length of output: 101


🏁 Script executed:

# Read the workflow file to examine the specific lines and context
cat -n .github/workflows/nightly-bfcl.yml | sed -n '130,165p'

Repository: lightseekorg/smg

Length of output: 2889


🏁 Script executed:

# Check for HF_TOKEN environment setup
cat -n .github/workflows/nightly-bfcl.yml | sed -n '180,200p'

Repository: lightseekorg/smg

Length of output: 1427


🏁 Script executed:

# Check if there are model revision pins anywhere (e.g., using `@revision` or similar)
grep -n "revision\|@\|deepseek\|minimax\|kimi" .github/workflows/nightly-bfcl.yml | head -20

Repository: lightseekorg/smg

Length of output: 1522


🏁 Script executed:

# Find scripts that handle model loading/launching
fd -t f "launch" . | head -10

Repository: lightseekorg/smg

Length of output: 336


🏁 Script executed:

# Check if any revision pins exist elsewhere (e.g., in Python setup or launch scripts)
grep -r "revision\|@[a-f0-9]\|--revision" . --include="*.sh" --include="*.py" | grep -i "deepseek\|minimax\|kimi" | head -20

Repository: lightseekorg/smg

Length of output: 42


🏁 Script executed:

# Check how vLLM is invoked with the model
grep -n "python.*vllm\|vLLM\|serve\|MODEL" .github/workflows/nightly-bfcl.yml | grep -A2 -B2 "vllm"

Repository: lightseekorg/smg

Length of output: 483


🏁 Script executed:

# Check launch_arm.sh for how models are specified/loaded
cat scripts/bfcl/launch_arm.sh | head -100

Repository: lightseekorg/smg

Length of output: 4598


🏁 Script executed:

# Also check register_bfcl_model.py to see if it accepts or enforces revision specs
cat bindings/python/src/smg/launch_router.py | grep -A10 -B10 "model\|revision" | head -50

Repository: lightseekorg/smg

Length of output: 42


Pin immutable model revisions when enabling --trust-remote-code on the deepseek-v4, minimax-m2.7, and kimi-k2.6 legs.

These legs execute remote model repo Python during startup while HF_TOKEN is present in the job environment. Without pinned revisions, the models pull from untagged references (default branch), creating a supply-chain path to token/runner compromise if an upstream repo is retagged or compromised. Pin immutable revisions in the workflow matrix (e.g., deepseek-ai/DeepSeek-V4-Flash@<commit-sha>) and ensure both the weight-staging and serving paths consume the same pinned revision before relying on nightly automation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/nightly-bfcl.yml around lines 139 - 140, Pin immutable
model revisions for the deepseek-v4, minimax-m2.7, and kimi-k2.6 legs in the
workflow matrix to prevent supply-chain risks when executing remote code with
the --trust-remote-code flag in vllm_extra. Modify the model references to use
the format model-name@commit-sha (e.g.,
deepseek-ai/DeepSeek-V4-Flash@<commit-sha>) in the matrix configuration, and
ensure that both the weight-staging and serving execution paths reference the
same pinned revision to maintain consistency throughout the nightly automation
workflow.

key4ng added 4 commits June 18, 2026 21:35
…ckstop

Signed-off-by: key4ng <rukeyang@gmail.com>
… paired-override guard + doc

Signed-off-by: key4ng <rukeyang@gmail.com>
…ilure only

Signed-off-by: key4ng <rukeyang@gmail.com>
Signed-off-by: key4ng <rukeyang@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea0ce36ea5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# Per-leg health-wait budget: big MoEs need minutes for load + compile + quant.
BFCL_STARTUP_TIMEOUT: ${{ matrix.startup_timeout }}
# Arm logs + pidfiles under RUNNER_TEMP (per-job, uploadable) not /tmp.
BFCL_RUN_DIR: ${{ runner.temp }}/bfcl_run

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the launch run directory during teardown

When this CI step sets BFCL_RUN_DIR here, the pidfiles are written under ${{ runner.temp }}/bfcl_run, but step-level env does not carry over to the later Teardown arms step, which runs launch_arm.sh stop with the script's default /tmp/bfcl_ab. In any run that reaches arm launch, the intended pidfile/process-group cleanup therefore finds no pids and leaves cleanup to the GPU nuke backstop, including leaking the non-GPU SMG gateway until the job exits.

Useful? React with 👍 / 👎.

Comment on lines +196 to +197
MODEL: ${{ github.event.inputs.model || matrix.model }}
BFCL_MODEL_FC: ${{ github.event.inputs.bfcl_model || matrix.bfcl_model }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require only before applying model overrides

For a workflow_dispatch run where model and bfcl_model are set but only is left at its default empty value, this job-level override is applied to every matrix row while the row-specific parsers, GPU split, runner, and extra vLLM flags still come from qwen/gpt-oss/deepseek/etc. That produces several expensive A/B jobs with mismatched parser configs and weights rather than overriding a single selected leg as the input text promises; fail the setup job unless overrides are paired with only, or apply them only to the intended row.

Useful? React with 👍 / 👎.

key4ng added 2 commits June 19, 2026 10:25
…kip download

Signed-off-by: key4ng <rukeyang@gmail.com>
…on shared host)

Signed-off-by: key4ng <rukeyang@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5dc5b4e844

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/nightly-bfcl.yml Outdated
# hard-killed launch step — exactly the leak that pinned ~250 GiB/GPU
# across jobs. Each bfcl leg uses the whole node (TP fills it), so no
# co-tenant job shares these GPUs.
run: bash scripts/ci_killall_sglang.sh nuke_gpus || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let GPU cleanup failures fail the job

When scripts/ci_killall_sglang.sh nuke_gpus cannot free the device or cannot query it, that helper emits ::error:: and exits nonzero after the dirty-GPU check, but this || true masks the failure. In the exact cleanup scenario this step is meant to catch—surviving vLLM/worker processes holding GPU memory—the workflow will still report success and return a dirty runner to the pool, which can contaminate subsequent GPU jobs.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bda57e2a98

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# picks a port, frees it, then vLLM binds it ~40s later — another leg
# grabs it meanwhile) and on GPU memory. A host-wide flock runs them one
# at a time; the lock releases when this step's shell exits.
exec 9>/tmp/bfcl-host.lock

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use a shared host lock for co-located runners

For the 4-gpu-h100 matrix legs that can be bin-packed onto one H100 node, this lock lives in each runner pod's private /tmp, not on the host. The runner config shows hostNetwork: true and Volcano binpacking, but only mounts /models, /dev/shm, the workspace, /var/run, /var/lib/docker, and /dev/infiniband into the runner (scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml:23-30,45-55,103-115), so co-located PR/nightly legs still do not see the same flock while sharing the host network; the free-port race this step is trying to serialize can still happen. Put the lock on a hostPath/shared mount or enforce this with workflow-level concurrency before launching arms.

Useful? React with 👍 / 👎.

@key4ng
key4ng merged commit 2d077a6 into main Jun 21, 2026
39 checks passed
@key4ng
key4ng deleted the feat/bfcl-multimodel-matrix branch June 21, 2026 03:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD configuration changes documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant