Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
cc5a3b8
[Quality] Integrate 8 quality benchmarks into CI
Noridom1 Sep 3, 2026
23a3758
[Quality] Smoke run GPQA-Diamond 10 samples via GreenNode
Noridom1 Sep 3, 2026
be31a3a
[Quality] Fix runner: bench-client_01 -> bench-client_00
Noridom1 Sep 3, 2026
c7d94c6
fix(quality-eval): dispatch quality scenarios directly, bypass runner…
Noridom1 Sep 3, 2026
79fd53a
fix(quality-eval): install lm-eval[api] extra for tenacity dependency
Noridom1 Sep 3, 2026
bcda255
feat(quality-eval): add smoke configs for 7 remaining benchmarks
Noridom1 Sep 3, 2026
972df81
fix(quality-eval): repair 6 broken benchmark smoke setups
Noridom1 Sep 3, 2026
9d1ad25
fix(quality-eval): venv --clear on rebuild, deepswe LIMIT map, scicod…
Noridom1 Sep 3, 2026
32de4e3
fix(quality-eval): 5 smoke fixes + job naming + skip passed benchmarks
Noridom1 Sep 4, 2026
7655d70
fix(quality-eval): swebench_pro imports + scicode pyarrow + hle max_g…
Noridom1 Sep 4, 2026
3e20597
fix(bfcl): honor LIMIT/EVAL_LIMIT via auto-generated run-ids subset
Noridom1 Sep 4, 2026
5a5ec34
fix(quality-eval): swebench_pro submodules + lcb anthropic + bfcl res…
Noridom1 Sep 4, 2026
e81faa4
fix(quality-eval): lcb anthropic patch + scicode numpy<2 + swebench r…
Noridom1 Sep 4, 2026
6b2e013
fix(quality-eval): lcb --limit, scicode datasets>=2.16, swebench dir …
Noridom1 Sep 4, 2026
8c2dd5f
fix(livecodebench): patch lm_styles.py with z-ai/glm-5.2 model
Noridom1 Sep 4, 2026
37fbc2f
ci: skip hle+bfcl (already passed), focus on lcb+scicode+swebench_pro
Noridom1 Sep 4, 2026
0f3e97d
fix: lcb dataset config name, scicode datasets==5.0.1, results.json f…
Noridom1 Sep 4, 2026
8da87f4
fix: lcb LCB_LIMIT env var for smoke subset, scicode inspect log coll…
Noridom1 Sep 4, 2026
4b8d505
feat: enable streaming for all 8 quality benchmarks
Noridom1 Sep 4, 2026
cf4b08b
fix: LCB output path + SciCode validate_scores non-dict metrics
Noridom1 Sep 6, 2026
c6e7522
fix: convert LCB list output to dict format for validate_scores
Noridom1 Sep 6, 2026
220747b
fix: cap SciCode smoke generations at 8k
Noridom1 Sep 6, 2026
be616cb
ci: retry SciCode smoke only
Noridom1 Sep 6, 2026
340da3a
fix: repair SciCode streamed response assembly
Noridom1 Sep 6, 2026
d8cc1e0
fix: reject invalid quality smoke outputs
Noridom1 Sep 7, 2026
ae574e7
test: include quality eval scenarios
Noridom1 Sep 7, 2026
a34138e
ci: rerun HLE and SWE-bench Pro smoke
Noridom1 Sep 7, 2026
898766b
fix: preserve HLE streamed reasoning responses
Noridom1 Sep 7, 2026
ad39155
ci: dispatch HLE smoke only
Noridom1 Sep 7, 2026
bb370c6
fix: repair lm-eval quality smoke
Noridom1 Sep 7, 2026
f4af9c4
fix: extend HLE request timeout
Noridom1 Sep 7, 2026
78bfa5d
ci: run balanced coding benchmarks at ccu4
Noridom1 Sep 7, 2026
48c5ce2
ci: balanced coding + agentic coding | GLM-5.2 | CCU4
Noridom1 Sep 7, 2026
499636c
fix: validate native quality benchmark metrics
Noridom1 Sep 7, 2026
62a47bd
fix: provision cached SciCode test data
Noridom1 Sep 7, 2026
a57d20c
fix: validate all quality benchmark formats
Noridom1 Sep 7, 2026
4c4a132
ci: smoke GLM-5.2 on VNG Cloud MaaS endpoint
Noridom1 Sep 8, 2026
6d2e134
fix: harden coding benchmark smoke harnesses
Noridom1 Sep 8, 2026
b35c252
[Quality] Balanced Coding + Agentic Coding | GLM-5.2 | VNG Cloud MaaS…
Noridom1 Sep 8, 2026
7a18d97
[Quality] Balanced Coding + Agentic Coding | GLM-5.2 | VNG Cloud MaaS…
Noridom1 Sep 8, 2026
1d48932
fix: harden quality benchmark retries
Noridom1 Sep 9, 2026
02741c2
ci: target failed quality benchmarks
Noridom1 Sep 9, 2026
6ee2480
fix: scope quality benchmark rerun
Noridom1 Sep 9, 2026
4955147
ci: dispatch filtered quality evaluations [skip-sweep]
Noridom1 Sep 9, 2026
b6e1793
fix: apply 64k quality generation defaults [skip-sweep]
Noridom1 Sep 9, 2026
aab35a5
fix: read nested BFCL subset results [skip-sweep]
Noridom1 Sep 9, 2026
1bce6ff
fix: extend SWE-bench Pro container startup timeout
Noridom1 Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 66 additions & 4 deletions .github/workflows/benchmark-tmpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,39 @@ on:
required: false
type: string
default: ""
# Quality-eval inputs. Only consumed by quality-eval scenario types
# (runner: cluster:quality-eval); every other recipe leaves these
# empty and is unaffected.
benchmark-name:
description: "Quality benchmark to run (gpqa, mmlu_pro, hle, livecodebench, bfcl, scicode, swebench_pro, deepswe)"
required: false
type: string
default: ""
quality-endpoint:
description: "OpenAI-compatible endpoint URL for quality evals"
required: false
type: string
default: ""
quality-model-name:
description: "Model name for quality evals (e.g. openai/z-ai/glm-5.2)"
required: false
type: string
default: ""
smoke:
description: "Smoke-test mode: skip threshold validation, only verify artifact exists"
required: false
type: boolean
default: false
num-concurrent:
description: "API request concurrency for quality evals (passed as NUM_CONCURRENT env var)"
required: false
type: string
default: ""
max-gen-tokens:
description: "Per-request output-token ceiling; empty uses the benchmark-specific default"
required: false
type: string
default: ""
env:
RANDOM_RANGE_RATIO: 0.8
HF_TOKEN: ${{ secrets.INFERENCEX_OFFICIAL_RO_HF_TOKEN }}
Expand All @@ -208,7 +241,7 @@ env:
EVAL_ONLY: ${{ inputs.eval-only }}
# Agentic-coding env. Fixed-seq-len jobs leave these empty.
SCENARIO_TYPE: ${{ inputs.scenario-type }}
SCENARIO_SUBDIR: ${{ inputs.scenario-type == 'agentic-coding' && 'agentic/' || 'fixed_seq_len/' }}
SCENARIO_SUBDIR: ${{ (inputs.scenario-type == 'agentic-coding' && 'agentic/') || (startsWith(inputs.scenario-type, 'quality-') && 'quality/') || 'fixed_seq_len/' }}
IS_AGENTIC: ${{ inputs.scenario-type == 'agentic-coding' && '1' || '0' }}
KV_OFFLOADING: ${{ inputs.kv-offloading }}
KV_OFFLOAD_BACKEND: ${{ inputs.kv-offload-backend }}
Expand All @@ -228,6 +261,14 @@ env:
REMOTE_RESET_URL: ${{ inputs.remote-reset-url }}
REMOTE_RUNNER_TYPE: ${{ inputs.remote-runner-type }}
REMOTE_MAX_CONTEXT_LENGTH: ${{ inputs.remote-max-context-length }}
# Quality-eval env. Only consumed by quality-eval scenario types.
QUALITY_BENCHMARK_NAME: ${{ inputs.benchmark-name }}
QUALITY_ENDPOINT: ${{ inputs.quality-endpoint }}
QUALITY_API_KEY: ${{ secrets.GREENNODE_API_KEY }}
QUALITY_MODEL_NAME: ${{ inputs.quality-model-name }}
SMOKE: ${{ inputs.smoke }}
NUM_CONCURRENT: ${{ inputs.num-concurrent }}
MAX_GEN_TOKENS: ${{ inputs.max-gen-tokens }}
AIPERF_FAILED_REQUEST_THRESHOLD: '0.10'
RESULT_DIR: /workspace/results
PYTHONDONTWRITEBYTECODE: '1'
Expand Down Expand Up @@ -268,6 +309,7 @@ jobs:
timeout-minutes: 500
name: >-
p${{ inputs.priority }} | ${{ inputs.model-prefix }} ${{ inputs.precision }} ${{ inputs.runner }} ${{ inputs.framework == 'sglang' && 'sgl' || inputs.framework == 'dynamo-sglang' && 'dyn-sgl' || inputs.framework == 'sglang-disagg' && 'sgl-disagg' || inputs.framework }}
${{ inputs.benchmark-name != '' && inputs.benchmark-name || '' }}
TP${{ inputs.tp }}${{ inputs.pp != '' && inputs.pp != '1' && format('/PP{0}', inputs.pp) || '' }}${{ inputs.dcp-size != '' && inputs.dcp-size != '1' && format('/DCP{0}', inputs.dcp-size) || '' }}${{ inputs.pcp-size != '' && inputs.pcp-size != '1' && format('/PCP{0}', inputs.pcp-size) || '' }}${{ inputs.ep != '' && inputs.ep != '1' && format('/EP{0}', inputs.ep) || '' }}${{ inputs.dp-attn && '/DPA' || '' }}
${{ inputs.spec-decoding != 'none' && inputs.spec-decoding || '' }}
${{ inputs.kv-offloading != '' && inputs.kv-offloading != 'none' && format('{0} KV offload', inputs.kv-offloading) || '' }}
Expand Down Expand Up @@ -321,7 +363,13 @@ jobs:
# Export RESULT_FILENAME early so it's available for artifact uploads even if cancelled
echo "RESULT_FILENAME=${RESULT_FILENAME}" >> $GITHUB_ENV

bash ./runners/launch_${RUNNER_NAME%%_*}.sh
# Quality-eval scenarios run on any runner with the quality-eval label;
# dispatch directly to launch_quality-eval.sh regardless of runner name.
if [ "${SCENARIO_SUBDIR}" = "quality/" ]; then
bash ./runners/launch_quality-eval.sh
else
bash ./runners/launch_${RUNNER_NAME%%_*}.sh
fi

if [ "${{ inputs.eval-only }}" = "true" ]; then
echo "Eval-only mode: skipping benchmark result file check"
Expand Down Expand Up @@ -436,12 +484,24 @@ jobs:
agent_preds.json
predictions.jsonl
swebench_report_*.json
eval_results*.json
*.traj*
*.csv
lcb_results*.json
*.jsonl
bfcl_inference_audit.json
bfcl_result_*.json
scicode_debug.tar.gz
if-no-files-found: ${{ inputs.eval-only && 'error' || 'ignore' }}

- name: Verify eval scores
if: ${{ (success() || failure()) && inputs.eval-only }}
run: python3 utils/evals/validate_scores.py
run: |
SMOKE_FLAG=""
if [ "${{ inputs.smoke }}" = "true" ]; then
SMOKE_FLAG="--smoke"
fi
python3 utils/evals/validate_scores.py $SMOKE_FLAG

- name: Cleanup eval outputs (post-upload)
if: ${{ always() && (env.RUN_EVAL == 'true' || inputs.eval-only) }}
Expand All @@ -450,7 +510,9 @@ jobs:
# Remove any eval results JSONs that were moved into workspace
rm -f results*.json || true
rm -f sample*.jsonl || true
rm -f agent_preds.json predictions.jsonl swebench_report_*.json *.traj* || true
rm -f agent_preds.json predictions.jsonl swebench_report_*.json eval_results*.json *.traj* || true
rm -f *.csv lcb_results*.json || true
rm -f bfcl_inference_audit.json bfcl_result_*.json scicode_debug.tar.gz || true

- name: Resource cleanup (post-run)
if: always()
Expand Down
56 changes: 52 additions & 4 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ jobs:
agentic-eval-config: ${{ steps.get-jobs.outputs.agentic-eval-config }}
multi-node-agentic-config: ${{ steps.get-jobs.outputs.multi-node-agentic-config }}
multi-node-agentic-eval-config: ${{ steps.get-jobs.outputs.multi-node-agentic-eval-config }}
quality-eval-config: ${{ steps.get-jobs.outputs.quality-eval-config }}
steps:
- name: Checkout code (ref)
if: ${{ inputs.ref && inputs.ref != '' }}
Expand Down Expand Up @@ -259,20 +260,67 @@ jobs:
AGENTIC_EVAL=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if x.get('scenario-type') == 'agentic-coding' and 'prefill' not in x and x.get('run-eval', False)]))" | score_matrix agentic-eval)
MULTI_AGENTIC=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if x.get('scenario-type') == 'agentic-coding' and 'prefill' in x and not x.get('run-eval', False)]))" | score_matrix multi-agentic)
MULTI_AGENTIC_EVAL=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if x.get('scenario-type') == 'agentic-coding' and 'prefill' in x and x.get('run-eval', False)]))" | score_matrix multi-agentic-eval)
SINGLE=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if 'prefill' not in x and x.get('scenario-type') != 'agentic-coding' and not x.get('eval-only', False)]))" | score_matrix single)
MULTI=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if 'prefill' in x and x.get('scenario-type') != 'agentic-coding' and not x.get('eval-only', False)]))" | score_matrix multi)
QUALITY=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if x.get('scenario-type', '').startswith('quality-')]))" | score_matrix quality-eval)
SINGLE=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if 'prefill' not in x and x.get('scenario-type') != 'agentic-coding' and not x.get('scenario-type', '').startswith('quality-') and not x.get('eval-only', False)]))" | score_matrix single)
MULTI=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if 'prefill' in x and x.get('scenario-type') != 'agentic-coding' and not x.get('scenario-type', '').startswith('quality-') and not x.get('eval-only', False)]))" | score_matrix multi)
MULTI_EVAL=$(echo "$CONFIG_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps([x for x in d if 'prefill' in x and x.get('scenario-type') != 'agentic-coding' and x.get('run-eval', False)]))" | score_matrix multi-eval)
{
echo "agentic-config=$AGENTIC"
echo "agentic-eval-config=$AGENTIC_EVAL"
echo "multi-node-agentic-config=$MULTI_AGENTIC"
echo "multi-node-agentic-eval-config=$MULTI_AGENTIC_EVAL"
echo "quality-eval-config=$QUALITY"
echo "single-node-config=$SINGLE"
echo "multi-node-config=$MULTI"
echo "eval-config=$EVALS"
echo "multi-node-eval-config=$MULTI_EVAL"
} >> "$GITHUB_OUTPUT"

test-sweep-quality-evals:
needs: get-jobs
if: ${{ needs.get-jobs.outputs.quality-eval-config != '[]' }}
uses: ./.github/workflows/benchmark-tmpl.yml
name: quality eval /
strategy:
fail-fast: ${{ inputs.fail-fast }}
matrix:
config: ${{ fromJson(needs.get-jobs.outputs.quality-eval-config) }}
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
skip-queue-pr: ${{ matrix.config['skip-queue-pr'] || '' }}
image: ${{ matrix.config.image }}
model: ${{ matrix.config.model }}
model-prefix: ${{ matrix.config.model-prefix }}
framework: ${{ matrix.config.framework }}
precision: ${{ matrix.config.precision }}
tp: '1'
pp: '1'
dcp-size: '1'
pcp-size: '1'
ep: '1'
dp-attn: false
conc: '1'
spec-decoding: 'none'
disagg: 'false'
isl: '0'
osl: '0'
max-model-len: '0'
run-eval: true
eval-only: true
scenario-type: ${{ matrix.config.scenario-type }}
benchmark-name: ${{ matrix.config.benchmark-name }}
quality-endpoint: ${{ matrix.config.quality-endpoint }}
quality-model-name: ${{ matrix.config.quality-model-name }}
smoke: ${{ matrix.config.smoke || false }}
num-concurrent: ${{ matrix.config.num-concurrent || '' }}
max-gen-tokens: ${{ matrix.config.max-gen-tokens || '' }}
eval-limit: ${{ matrix.config.eval-limit || inputs.eval-limit }}
ref: ${{ inputs.ref }}

test-sweep-multi-node:
needs: get-jobs
if: ${{ needs.get-jobs.outputs.multi-node-config != '[]' }}
Expand Down Expand Up @@ -665,8 +713,8 @@ jobs:
result-prefix: "bmk"

collect-evals:
needs: [test-sweep-evals, test-sweep-multi-node-evals, test-sweep-agentic-evals, test-sweep-multi-node-agentic-evals]
if: ${{ always() && (needs.test-sweep-evals.result != 'skipped' || needs.test-sweep-multi-node-evals.result != 'skipped' || needs.test-sweep-agentic-evals.result != 'skipped' || needs.test-sweep-multi-node-agentic-evals.result != 'skipped') }}
needs: [test-sweep-evals, test-sweep-multi-node-evals, test-sweep-agentic-evals, test-sweep-multi-node-agentic-evals, test-sweep-quality-evals]
if: ${{ always() && (needs.test-sweep-evals.result != 'skipped' || needs.test-sweep-multi-node-evals.result != 'skipped' || needs.test-sweep-agentic-evals.result != 'skipped' || needs.test-sweep-multi-node-agentic-evals.result != 'skipped' || needs.test-sweep-quality-evals.result != 'skipped') }}
uses: ./.github/workflows/collect-evals.yml
secrets: inherit

Expand Down
59 changes: 57 additions & 2 deletions .github/workflows/run-sweep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,61 @@ jobs:
eval-conc: ${{ matrix.config['eval-conc'] }}
scenario-type: agentic-coding

# Quality-eval rows carry the quality-eval input shape (benchmark-name,
# quality-endpoint, quality-model-name, smoke), so they are dispatched
# with their own job rather than sweep-evals' fixed-seq-len inputs.
sweep-quality-evals:
needs: [setup, canary-select, canary-sweep]
if: >-
${{
!cancelled() &&
needs.setup.result == 'success' &&
needs.setup.outputs.reuse-enabled != 'true' &&
(needs.canary-sweep.result == 'success' || needs.canary-sweep.result == 'skipped') &&
toJson(fromJson(needs.setup.outputs.search-space-config).quality_evals) != '[]' &&
toJson(fromJson(needs.setup.outputs.search-space-config).quality_evals) != 'null'
}}
uses: ./.github/workflows/benchmark-tmpl.yml
name: quality eval /
strategy:
fail-fast: ${{ contains(github.event.pull_request.labels.*.name, 'full-sweep-fail-fast') || contains(github.event.pull_request.labels.*.name, 'full-sweep-fail-fast-no-canary') }}
matrix:
config: ${{ fromJson(needs.setup.outputs.search-space-config).quality_evals }}
secrets: inherit
with:
exp-name: ${{ matrix.config.exp-name }}
runner: ${{ matrix.config.runner }}
priority: ${{ matrix.config.priority }}
queue-token: ${{ matrix.config['queue-token'] }}
skip-queue-pr: ${{ matrix.config['skip-queue-pr'] || '' }}
image: ${{ matrix.config.image }}
model: ${{ matrix.config.model }}
model-prefix: ${{ matrix.config.model-prefix }}
framework: ${{ matrix.config.framework }}
precision: ${{ matrix.config.precision }}
tp: '1'
pp: '1'
dcp-size: '1'
pcp-size: '1'
ep: '1'
dp-attn: false
conc: '1'
spec-decoding: 'none'
disagg: 'false'
isl: '0'
osl: '0'
max-model-len: '0'
run-eval: true
eval-only: true
scenario-type: ${{ matrix.config.scenario-type }}
benchmark-name: ${{ matrix.config.benchmark-name }}
quality-endpoint: ${{ matrix.config.quality-endpoint }}
quality-model-name: ${{ matrix.config.quality-model-name }}
smoke: ${{ matrix.config.smoke || false }}
num-concurrent: ${{ matrix.config.num-concurrent || '' }}
max-gen-tokens: ${{ matrix.config.max-gen-tokens || '' }}
eval-limit: ${{ matrix.config.eval-limit || (contains(github.event.pull_request.labels.*.name, 'sweep-enabled') && '10' || '') }}

collect-results:
needs:
[
Expand Down Expand Up @@ -955,8 +1010,8 @@ jobs:
result-prefix: "bmk"

collect-evals:
needs: [sweep-evals, sweep-agentic-evals, sweep-multi-node-evals, sweep-multi-node-agentic-evals, setup]
if: ${{ always() && needs.setup.result != 'skipped' && (needs.sweep-evals.result != 'skipped' || needs.sweep-agentic-evals.result != 'skipped' || needs.sweep-multi-node-evals.result != 'skipped' || needs.sweep-multi-node-agentic-evals.result != 'skipped') }}
needs: [sweep-evals, sweep-agentic-evals, sweep-multi-node-evals, sweep-multi-node-agentic-evals, sweep-quality-evals, setup]
if: ${{ always() && needs.setup.result != 'skipped' && (needs.sweep-evals.result != 'skipped' || needs.sweep-agentic-evals.result != 'skipped' || needs.sweep-multi-node-evals.result != 'skipped' || needs.sweep-multi-node-agentic-evals.result != 'skipped' || needs.sweep-quality-evals.result != 'skipped') }}
uses: ./.github/workflows/collect-evals.yml
secrets: inherit

Expand Down
23 changes: 23 additions & 0 deletions BENCHMARK_TIMES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Quality Benchmark Time Estimates

Estimates are for GLM-5.2 at concurrency 4. API latency, reasoning length,
rate limits, image setup, and sandbox execution can change wall time.

| Benchmark | Full size | Full estimate | 20-sample estimate | Default max generation |
|---|---:|---:|---:|---:|
| GPQA-Diamond | 198 | ~20 min | ~2 min | 8K |
| MMLU-Pro | 12,032 | ~22 h | ~2 min* | 8K |
| HLE | 2,158 | ~4.5 h | ~5 min* | 16K |
| LiveCodeBench | 1,055 | ~8 h | ~15 min | 16K |
| BFCL v4 | ~2,000 | ~1.5 h | <1 min | 8K |
| SciCode | 288 subproblems | ~5.5 h | ~23 min | 16K |
| SWE-bench Pro | 731 | ~45 h | ~30 min | 32K per agent turn |
| DeepSWE | 113 | ~29 h | ~5 h | 32K per agent turn |

\* `LIMIT` applies per subtask for MMLU-Pro and HLE, so `LIMIT=20` evaluates
more than 20 total questions.

These are output ceilings, not target lengths. Natural stop conditions still
end generation early. Override any default with `MAX_GEN_TOKENS`; CI matrix
rows may use `max-gen-tokens`. Streaming avoids idle connection timeouts but
does not remove total request deadlines or the cost of long generations.
Loading
Loading