mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
chore: migrate active GPT-5.5 references to GPT-5.6 (#104452)
* chore(models): migrate active GPT-5.5 references * test(workboard): expect GPT-5.6 Sol default * chore: keep release notes in PR body * test(models): align picker fixtures with Sol default * test: update PDF default model expectation * test(qa): migrate thinking smoke to Luna * test(gateway): align mock catalog with Sol default * ci: retrigger exact-head PR checks * test(gateway): document default catalog invariant
This commit is contained in:
@@ -7,7 +7,7 @@ description: "Pre-commit/ship code review: Codex default; optional Claude, Pi, D
|
||||
|
||||
Run the bundled structured review helper as a closeout check. This is code review, not Guardian `auto_review` approval routing.
|
||||
|
||||
Codex review is the default when no engine is set. It uses `gpt-5.5` by default, usually delivers the best review results, and should remain the normal final closeout engine. Claude review is optional and uses `claude-fable-5` by default.
|
||||
Codex review is the default when no engine is set. It uses `gpt-5.6-sol` by default, usually delivers the best review results, and should remain the normal final closeout engine. Claude review is optional and uses `claude-fable-5` by default.
|
||||
|
||||
For user-visible behavior, pair autoreview with `behavior-validator`. Autoreview is source-aware and judges the change bundle; behavior validation is source-blind and judges the running product or tool against a behavior contract. A clean autoreview is not proof that a UI, CLI, API, or generated artifact works from the user's perspective.
|
||||
|
||||
@@ -185,13 +185,13 @@ Run multiple reviewers against one frozen bundle:
|
||||
Set reviewer models and thinking/effort explicitly:
|
||||
|
||||
```bash
|
||||
"$AUTOREVIEW" --reviewers codex,claude --model codex=gpt-5.5 --thinking codex=high --model claude=claude-fable-5 --thinking claude=max
|
||||
"$AUTOREVIEW" --reviewers codex,claude --model codex=gpt-5.6-sol --thinking codex=high --model claude=claude-fable-5 --thinking claude=max
|
||||
```
|
||||
|
||||
Inline syntax is also supported for simple model IDs:
|
||||
|
||||
```bash
|
||||
"$AUTOREVIEW" --reviewers codex:gpt-5.5:high,claude:claude-fable-5:max
|
||||
"$AUTOREVIEW" --reviewers codex:gpt-5.6-sol:high,claude:claude-fable-5:max
|
||||
```
|
||||
|
||||
For models with slashes or extra colons, prefer keyed form:
|
||||
@@ -200,9 +200,9 @@ For models with slashes or extra colons, prefer keyed form:
|
||||
"$AUTOREVIEW" --engine pi --model anthropic/claude-sonnet-4 --thinking high
|
||||
"$AUTOREVIEW" --engine opencode --model opencode/north-mini-code-free --thinking high
|
||||
"$AUTOREVIEW" --engine cursor --model auto --cursor-allow-workspace-instructions
|
||||
"$AUTOREVIEW" --reviewers codex,pi --model codex=gpt-5.5 --model pi=anthropic/claude-sonnet-4
|
||||
"$AUTOREVIEW" --reviewers codex,opencode --model codex=gpt-5.5 --model opencode=opencode/north-mini-code-free
|
||||
"$AUTOREVIEW" --reviewers codex,cursor --model codex=gpt-5.5 --model cursor=auto --cursor-allow-workspace-instructions
|
||||
"$AUTOREVIEW" --reviewers codex,pi --model codex=gpt-5.6-sol --model pi=anthropic/claude-sonnet-4
|
||||
"$AUTOREVIEW" --reviewers codex,opencode --model codex=gpt-5.6-sol --model opencode=opencode/north-mini-code-free
|
||||
"$AUTOREVIEW" --reviewers codex,cursor --model codex=gpt-5.6-sol --model cursor=auto --cursor-allow-workspace-instructions
|
||||
```
|
||||
|
||||
`--reviewers all` covers Codex, Claude, Copilot, Pi, and OpenCode. Cursor requires both explicit selection (`--engine cursor` or named in `--reviewers`) and `--cursor-allow-workspace-instructions` because the current Cursor CLI does not document a per-run flag that ignores project-local instructions/config. Droid selection currently fails closed because its CLI cannot disable both project instructions and all tools.
|
||||
@@ -215,14 +215,14 @@ Recommended model defaults:
|
||||
|
||||
| Engine | Default model | Source note |
|
||||
| ------------------- | ---------------- | ----------------------------------------------------- |
|
||||
| **codex** (default) | `gpt-5.5` | OpenAI's current GPT-5.5 alias |
|
||||
| **codex** (default) | `gpt-5.6-sol` | OpenAI's current high-capability GPT-5.6 tier |
|
||||
| **claude** | `claude-fable-5` | Anthropic's most capable widely released Claude model |
|
||||
|
||||
CLI flags and environment variables override these defaults. Droid, Copilot, Pi, Cursor, and OpenCode do not get built-in model defaults here because their provider catalogs are external to the Codex/Claude closeout path and may vary by installation.
|
||||
|
||||
| Engine | Model flag | Example model IDs | Thinking flag | Accepted levels |
|
||||
| ------------------- | -------------------------- | ---------------------------------------------------------------------------- | ----------------------------- | ------------------------------------------------------ |
|
||||
| **codex** (default) | `codex --model X exec ...` | `gpt-5.5`, `gpt-5.5-2026-04-23` | `-c model_reasoning_effort=Y` | `none`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
||||
| **codex** (default) | `codex --model X exec ...` | `gpt-5.6-sol`, `gpt-5.6-luna` | `-c model_reasoning_effort=Y` | `none`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
||||
| **claude** | `claude --model X` | `claude-fable-5`, `claude-opus-4-8`, `claude-sonnet-4-6`, `claude-haiku-4-5` | `--effort Y` | `low`, `medium`, `high`, `xhigh`, `max` |
|
||||
| **droid** | currently refused | Factory model IDs | `-r, --reasoning-effort Y` | `off`, `none`, `low`, `medium`, `high`, `xhigh`, `max` |
|
||||
| **copilot** | `copilot --model X` | `gpt-5.2`, Copilot model aliases | not supported | n/a |
|
||||
@@ -236,7 +236,7 @@ Examples matching current `main` behavior:
|
||||
|
||||
```bash
|
||||
# Codex with explicit model and reasoning
|
||||
"$AUTOREVIEW" --engine codex --model gpt-5.5 --thinking high
|
||||
"$AUTOREVIEW" --engine codex --model gpt-5.6-sol --thinking high
|
||||
|
||||
# Codex fast mode (priority service tier); needs a model whose catalog lists the tier, silently standard otherwise
|
||||
"$AUTOREVIEW" --engine codex --codex-speed fast
|
||||
@@ -277,7 +277,7 @@ loader such as an untracked `.envrc`; the helper does not write a config file.
|
||||
| `AUTOREVIEW_MODEL` | Override the built-in default `--model` for all engines |
|
||||
| `AUTOREVIEW_THINKING` | Default `--thinking` for all engines |
|
||||
| `AUTOREVIEW_FALLBACK_MODEL` | Default Claude `--fallback-model` chain |
|
||||
| `AUTOREVIEW_<ENGINE>_MODEL` | Per-engine model override, for example `AUTOREVIEW_CODEX_MODEL=gpt-5.5` |
|
||||
| `AUTOREVIEW_<ENGINE>_MODEL` | Per-engine model override, for example `AUTOREVIEW_CODEX_MODEL=gpt-5.6-sol` |
|
||||
| `AUTOREVIEW_<ENGINE>_THINKING` | Per-engine thinking override |
|
||||
| `AUTOREVIEW_CODEX_CONFIG` | Default Codex `-c key=value` overrides, semicolon-separated, e.g. `service_tier="fast"`; isolation flags still win |
|
||||
| `AUTOREVIEW_CODEX_SPEED` | Default Codex service tier: `fast` (priority), `flex`, or `default`; silently standard when the model does not list the tier |
|
||||
@@ -346,7 +346,7 @@ The helper:
|
||||
- supports `--dry-run`, `--parallel-tests`, `--parallel-tests-shell`, `--prompt`, repo-relative `--prompt-file`, repo-relative `--dataset`, `--no-tools`, `--no-web-search`, repeatable Codex-only `--codex-config key=value`, Codex-only `--codex-speed fast|flex|default`, and commit refs
|
||||
- supports `--stream-engine-output` or `AUTOREVIEW_STREAM_ENGINE_OUTPUT=1` for live engine text while preserving structured validation; Codex, Claude, and Cursor hide tool/file event details, emit compact activity summaries, and report usage at turn completion
|
||||
- supports opt-in review panels with `--panel` / `--reviewers`, plus per-engine `--model`, `--thinking`, and Claude `--fallback-model`
|
||||
- uses built-in model defaults `codex=gpt-5.5` and `claude=claude-fable-5`; honors `AUTOREVIEW_MODEL`, `AUTOREVIEW_THINKING`, `AUTOREVIEW_FALLBACK_MODEL`, and per-engine `AUTOREVIEW_<ENGINE>_MODEL` / `AUTOREVIEW_<ENGINE>_THINKING` environment overrides when CLI flags are omitted
|
||||
- uses built-in model defaults `codex=gpt-5.6-sol` and `claude=claude-fable-5`; honors `AUTOREVIEW_MODEL`, `AUTOREVIEW_THINKING`, `AUTOREVIEW_FALLBACK_MODEL`, and per-engine `AUTOREVIEW_<ENGINE>_MODEL` / `AUTOREVIEW_<ENGINE>_THINKING` environment overrides when CLI flags are omitted
|
||||
- allows read-only tools and web search by default where the selected CLI supports them; forbids nested review in the prompt; Codex is run through `codex exec` with auth-only user settings, read-only sandbox, reviewed-repo instruction/config/rule isolation flags, and structured output
|
||||
- runs Claude with `--safe-mode` (`v2.1.169+`), `--setting-sources user`, MCP disabled, explicit allowed tools, and `--fallback-model` when set, so reviewed-repo hooks/skills/MCP do not affect the review run while normal auth still works; managed settings policy can still apply
|
||||
- refuses Droid reviews until the CLI exposes a complete project-instruction and tool-isolation contract
|
||||
|
||||
@@ -87,7 +87,7 @@ SECRET_VALUE_PATTERNS = [
|
||||
MAX_BUNDLE_TEXT_BYTES = 180_000
|
||||
DEFAULT_ENGINE_PATHS = ("/usr/local/bin", "/usr/bin", "/bin")
|
||||
DEFAULT_MODEL_BY_ENGINE = {
|
||||
"codex": "gpt-5.5",
|
||||
"codex": "gpt-5.6-sol",
|
||||
"claude": "claude-fable-5",
|
||||
}
|
||||
THINKING_LEVELS_BY_ENGINE = {
|
||||
@@ -3123,12 +3123,12 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--base")
|
||||
parser.add_argument("--commit", default="HEAD")
|
||||
parser.add_argument("--engine", choices=ENGINE_CHOICES, default=os.environ.get("AUTOREVIEW_ENGINE", "codex"))
|
||||
parser.add_argument("--reviewers", help="Comma-separated review panel, e.g. codex,claude,cursor or codex:gpt-5.5:high.")
|
||||
parser.add_argument("--reviewers", help="Comma-separated review panel, e.g. codex,claude,cursor or codex:gpt-5.6-sol:high.")
|
||||
parser.add_argument("--panel", action="store_true", help="Run a Codex/Claude review panel unless --engine changes the first reviewer.")
|
||||
parser.add_argument(
|
||||
"--model",
|
||||
action="append",
|
||||
help="Model for all reviewers or engine=model. Repeatable. Defaults: codex=gpt-5.5, claude=claude-fable-5.",
|
||||
help="Model for all reviewers or engine=model. Repeatable. Defaults: codex=gpt-5.6-sol, claude=claude-fable-5.",
|
||||
)
|
||||
parser.add_argument("--thinking", action="append", help="Thinking/effort for all reviewers or engine=level. Repeatable. Codex: none, minimal, low, medium, high, xhigh. Claude: low, medium, high, xhigh, max. Droid: off, none, low, medium, high. Pi: off, minimal, low, medium, high, xhigh. OpenCode: minimal, low, medium, high, max. Cursor: none.")
|
||||
parser.add_argument(
|
||||
@@ -3533,7 +3533,7 @@ def self_test_config_defaults() -> None:
|
||||
]
|
||||
with preserve_env(keys):
|
||||
default_codex = reviewer_args(reviewer_test_args(engine="codex"))[0]
|
||||
if default_codex.model != "gpt-5.5":
|
||||
if default_codex.model != "gpt-5.6-sol":
|
||||
raise SystemExit(f"self-test config defaults failed: default codex model={default_codex.model!r}")
|
||||
default_claude = reviewer_args(reviewer_test_args(engine="claude"))[0]
|
||||
if default_claude.model != "claude-fable-5":
|
||||
|
||||
@@ -140,7 +140,7 @@ pnpm run repair:dispatch -- jobs/openclaw/inbox/clawsweeper-openclaw-openclaw-12
|
||||
--mode autonomous \
|
||||
--runner blacksmith-4vcpu-ubuntu-2404 \
|
||||
--execution-runner blacksmith-16vcpu-ubuntu-2404 \
|
||||
--model gpt-5.5
|
||||
--model gpt-5.6-sol
|
||||
```
|
||||
|
||||
Do not dispatch a just-created job before the job file is committed and pushed;
|
||||
|
||||
@@ -159,7 +159,7 @@ jobs:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
ANTHROPIC_MODEL: claude-opus-4-8
|
||||
OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.5' }}
|
||||
OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.6-sol' }}
|
||||
OPENCLAW_CONTROL_UI_I18N_THINKING: low
|
||||
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "0"
|
||||
LOCALE: ${{ matrix.locale }}
|
||||
|
||||
@@ -346,8 +346,8 @@ jobs:
|
||||
--repo-root "$repo_root" \
|
||||
--output-dir "$output_dir" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.5 \
|
||||
--alt-model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-luna \
|
||||
--alt-model openai/gpt-5.6-luna \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci \
|
||||
|
||||
@@ -319,8 +319,8 @@ jobs:
|
||||
--credential-role ci \
|
||||
--provider-mode live-frontier \
|
||||
--hydrate-mode "$HYDRATE_MODE" \
|
||||
--model openai/gpt-5.5 \
|
||||
--alt-model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-luna \
|
||||
--alt-model openai/gpt-5.6-luna \
|
||||
--fast \
|
||||
"${scenario_args[@]}" \
|
||||
"${approval_args[@]}" \
|
||||
|
||||
@@ -416,7 +416,7 @@ jobs:
|
||||
output_rel=".artifacts/qa-e2e/mantis/telegram-live"
|
||||
root="$candidate_repo/$output_rel"
|
||||
echo "output_dir=${root}" >> "$GITHUB_OUTPUT"
|
||||
model="${OPENCLAW_CI_OPENAI_MODEL:-openai/gpt-5.5}"
|
||||
model="${OPENCLAW_CI_OPENAI_MODEL:-openai/gpt-5.6-luna}"
|
||||
|
||||
scenario_args=()
|
||||
if [[ -n "${SCENARIO_INPUT// }" ]]; then
|
||||
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
ANTHROPIC_MODEL: claude-opus-4-8
|
||||
OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.5' }}
|
||||
OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.6-sol' }}
|
||||
OPENCLAW_CONTROL_UI_I18N_THINKING: low
|
||||
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "0"
|
||||
LOCALE: ${{ matrix.locale }}
|
||||
|
||||
@@ -234,7 +234,7 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.15.0"
|
||||
OPENCLAW_REPOSITORY: openclaw/openclaw
|
||||
OPENCLAW_CROSS_OS_OPENAI_MODEL: ${{ inputs.openai_model || vars.OPENCLAW_CROSS_OS_OPENAI_MODEL || 'openai/gpt-5.5' }}
|
||||
OPENCLAW_CROSS_OS_OPENAI_MODEL: ${{ inputs.openai_model || vars.OPENCLAW_CROSS_OS_OPENAI_MODEL || 'openai/gpt-5.6-luna' }}
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
|
||||
@@ -2860,7 +2860,7 @@ jobs:
|
||||
profiles: stable full
|
||||
- suite_id: native-live-src-gateway-profiles-openai
|
||||
label: Native live gateway profiles OpenAI
|
||||
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=180000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
|
||||
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.6-luna OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=180000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
|
||||
timeout_minutes: 60
|
||||
profile_env_only: false
|
||||
profiles: beta minimum stable full
|
||||
@@ -3159,7 +3159,7 @@ jobs:
|
||||
include:
|
||||
- suite_id: live-gateway-docker
|
||||
label: Docker live gateway OpenAI
|
||||
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
|
||||
command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.6-luna OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
|
||||
timeout_minutes: 40
|
||||
profile_env_only: false
|
||||
profiles: beta minimum stable full
|
||||
|
||||
@@ -70,7 +70,7 @@ env:
|
||||
OCM_VERSION: v0.2.15
|
||||
OCM_LINUX_X64_SHA256: b849b8de5d77e97e0df9319703254ae95e29d7f26a7552ea79bf173ff110ea0a
|
||||
KOVA_REPOSITORY: openclaw/Kova
|
||||
PERFORMANCE_MODEL_ID: gpt-5.6
|
||||
PERFORMANCE_MODEL_ID: gpt-5.6-luna
|
||||
KOVA_SCENARIO_TIMEOUT_MS: "300000"
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -103,7 +103,7 @@ concurrency:
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.15.0"
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.6-luna' }}
|
||||
|
||||
jobs:
|
||||
resolve_target:
|
||||
@@ -677,7 +677,7 @@ jobs:
|
||||
candidate_sha256: ${{ needs.prepare_release_package.outputs.package_sha256 }}
|
||||
candidate_version: ${{ needs.prepare_release_package.outputs.package_version }}
|
||||
candidate_source_sha: ${{ needs.prepare_release_package.outputs.source_sha }}
|
||||
openai_model: openai/gpt-5.5
|
||||
openai_model: openai/gpt-5.6-luna
|
||||
ubuntu_runner: ubuntu-24.04
|
||||
windows_runner: windows-2025
|
||||
macos_runner: macos-26
|
||||
@@ -947,7 +947,7 @@ jobs:
|
||||
case "${QA_PARITY_LANE}" in
|
||||
candidate)
|
||||
model="${OPENCLAW_CI_OPENAI_MODEL}"
|
||||
alt_model="openai/gpt-5.5-alt"
|
||||
alt_model="openai/gpt-5.6-luna-alt"
|
||||
;;
|
||||
baseline)
|
||||
model="anthropic/claude-opus-4-8"
|
||||
@@ -1158,7 +1158,7 @@ jobs:
|
||||
--parity-pack agentic \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "openai/gpt-5.5-alt" \
|
||||
--alt-model "openai/gpt-5.6-luna-alt" \
|
||||
--runtime-pair openclaw,codex \
|
||||
--output-dir ".artifacts/qa-e2e/runtime-parity"
|
||||
|
||||
@@ -1172,7 +1172,7 @@ jobs:
|
||||
--runtime-parity-tier standard \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "openai/gpt-5.5-alt" \
|
||||
--alt-model "openai/gpt-5.6-luna-alt" \
|
||||
--runtime-pair openclaw,codex \
|
||||
--output-dir ".artifacts/qa-e2e/runtime-parity-standard"
|
||||
|
||||
@@ -1186,7 +1186,7 @@ jobs:
|
||||
--runtime-parity-tier soak \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "openai/gpt-5.5-alt" \
|
||||
--alt-model "openai/gpt-5.6-luna-alt" \
|
||||
--runtime-pair openclaw,codex \
|
||||
--output-dir ".artifacts/qa-e2e/runtime-parity-soak"
|
||||
|
||||
@@ -1408,8 +1408,8 @@ jobs:
|
||||
matrix_args=(
|
||||
--repo-root . \
|
||||
--provider-mode mock-openai \
|
||||
--model mock-openai/gpt-5.5 \
|
||||
--alt-model mock-openai/gpt-5.5-alt \
|
||||
--model mock-openai/gpt-5.6-luna \
|
||||
--alt-model mock-openai/gpt-5.6-luna-alt \
|
||||
--profile fast \
|
||||
--fast
|
||||
)
|
||||
@@ -1658,8 +1658,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${attempt_output_dir}" \
|
||||
--provider-mode mock-openai \
|
||||
--model mock-openai/gpt-5.5 \
|
||||
--alt-model mock-openai/gpt-5.5-alt \
|
||||
--model mock-openai/gpt-5.6-luna \
|
||||
--alt-model mock-openai/gpt-5.6-luna-alt \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci; then
|
||||
@@ -1758,8 +1758,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${attempt_output_dir}" \
|
||||
--provider-mode mock-openai \
|
||||
--model mock-openai/gpt-5.5 \
|
||||
--alt-model mock-openai/gpt-5.5-alt \
|
||||
--model mock-openai/gpt-5.6-luna \
|
||||
--alt-model mock-openai/gpt-5.6-luna-alt \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci; then
|
||||
@@ -1855,8 +1855,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${attempt_output_dir}" \
|
||||
--provider-mode mock-openai \
|
||||
--model mock-openai/gpt-5.5 \
|
||||
--alt-model mock-openai/gpt-5.5-alt \
|
||||
--model mock-openai/gpt-5.6-luna \
|
||||
--alt-model mock-openai/gpt-5.6-luna-alt \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci; then
|
||||
|
||||
@@ -1992,8 +1992,8 @@ jobs:
|
||||
--repo-root "$CANDIDATE_ROOT" \
|
||||
--output-dir "${EVIDENCE_RELATIVE}/${output_name}" \
|
||||
--provider-mode mock-openai \
|
||||
--model mock-openai/gpt-5.5 \
|
||||
--alt-model mock-openai/gpt-5.5-alt \
|
||||
--model mock-openai/gpt-5.6-luna \
|
||||
--alt-model mock-openai/gpt-5.6-luna-alt \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci \
|
||||
|
||||
@@ -51,7 +51,7 @@ concurrency:
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.x"
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.6-luna' }}
|
||||
OPENCLAW_CI_OPENAI_FALLBACK_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_FALLBACK_MODEL || 'openai/gpt-5.4' }}
|
||||
OPENCLAW_BUILD_PRIVATE_QA: "1"
|
||||
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
--parity-pack agentic \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model openai/gpt-5.5-alt \
|
||||
--alt-model openai/gpt-5.6-luna-alt \
|
||||
--output-dir .artifacts/qa-e2e/openai-candidate
|
||||
|
||||
- name: Run Opus 4.8 lane
|
||||
@@ -634,7 +634,7 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${output_dir}" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-luna \
|
||||
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
|
||||
@@ -218,7 +218,7 @@ Skills own workflows; root owns hard policy and routing.
|
||||
|
||||
## Tests
|
||||
|
||||
- Vitest. Colocated `*.test.ts`; e2e `*.e2e.test.ts`; example models `sonnet-4.6`, `gpt-5.5`; test GPT with 5.5 preferred, 5.4 ok; no GPT-4.x agent-smoke defaults.
|
||||
- Vitest. Colocated `*.test.ts`; e2e `*.e2e.test.ts`; example models `sonnet-4.6`, `gpt-5.6-luna`; test GPT with Luna preferred; use Sol when capability matters; no GPT-4.x agent-smoke defaults.
|
||||
- Prefer behavior tests over workflow/docs string greps. Put operator policy reminders in AGENTS/docs.
|
||||
- QA scenario sources are YAML only: `qa/scenarios/index.yaml` and `qa/scenarios/<theme>/*.yaml`. Do not add fenced `qa-scenario`/`qa-flow` Markdown files under `qa/scenarios/`.
|
||||
- Clean timers/env/globals/mocks/sockets/temp dirs/module state; `--isolate=false` safe.
|
||||
|
||||
@@ -78,8 +78,8 @@ struct LocalChatFixture {
|
||||
subject: "Mobile command center",
|
||||
workspace: "OpenClaw",
|
||||
modelProvider: "openai",
|
||||
modelID: "gpt-5.5",
|
||||
modelName: "GPT-5.5",
|
||||
modelID: "gpt-5.6-sol",
|
||||
modelName: "GPT-5.6 Sol",
|
||||
responsePrefix: "OpenClaw is connected to your gateway.",
|
||||
seedMessages: ProcessInfo.processInfo.arguments.contains("--openclaw-empty-chat-fixture")
|
||||
? []
|
||||
@@ -91,7 +91,7 @@ struct LocalChatFixture {
|
||||
identity: ["emoji": AnyCodable("M")],
|
||||
workspace: "OpenClaw",
|
||||
workspacegit: false,
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.5")],
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.6-sol")],
|
||||
agentruntime: ["kind": AnyCodable("gateway")],
|
||||
thinkinglevels: nil,
|
||||
thinkingoptions: ["auto", "low", "medium", "high"],
|
||||
@@ -102,7 +102,7 @@ struct LocalChatFixture {
|
||||
identity: ["emoji": AnyCodable("RS")],
|
||||
workspace: "OpenClaw",
|
||||
workspacegit: false,
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.5")],
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.6-sol")],
|
||||
agentruntime: ["kind": AnyCodable("gateway")],
|
||||
thinkinglevels: nil,
|
||||
thinkingoptions: ["auto", "low", "medium", "high"],
|
||||
@@ -113,7 +113,7 @@ struct LocalChatFixture {
|
||||
identity: ["emoji": AnyCodable("AU")],
|
||||
workspace: "OpenClaw",
|
||||
workspacegit: false,
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.5")],
|
||||
model: ["provider": AnyCodable("openai"), "model": AnyCodable("gpt-5.6-sol")],
|
||||
agentruntime: ["kind": AnyCodable("gateway")],
|
||||
thinkinglevels: nil,
|
||||
thinkingoptions: ["auto", "low", "medium", "high"],
|
||||
|
||||
@@ -534,7 +534,7 @@ struct SettingsRootView_Previews: PreviewProvider {
|
||||
state: .preview,
|
||||
updater: DisabledUpdaterController(),
|
||||
initialTab: tab,
|
||||
configuredInferenceModel: tab == .crestodian ? "openai/gpt-5.5" : nil)
|
||||
configuredInferenceModel: tab == .crestodian ? "openai/gpt-5.6-sol" : nil)
|
||||
.previewDisplayName(tab.title)
|
||||
.frame(width: SettingsTab.windowWidth, height: SettingsTab.windowHeight)
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ private struct OpenClawChatPreviewTransport: OpenClawChatTransport {
|
||||
func listModels() async throws -> [OpenClawChatModelChoice] {
|
||||
[
|
||||
OpenClawChatModelChoice(
|
||||
modelID: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
modelID: "gpt-5.6-luna",
|
||||
name: "GPT-5.6 Luna",
|
||||
provider: "openai",
|
||||
contextWindow: 400_000),
|
||||
OpenClawChatModelChoice(
|
||||
@@ -104,7 +104,7 @@ private struct OpenClawChatPreviewTransport: OpenClawChatTransport {
|
||||
count: 2,
|
||||
defaults: OpenClawChatSessionsDefaults(
|
||||
modelProvider: "openai",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
contextTokens: 400_000,
|
||||
thinkingLevels: [
|
||||
OpenClawChatThinkingLevelOption(id: "off", label: "off"),
|
||||
@@ -202,7 +202,7 @@ private struct OpenClawChatPreviewTransport: OpenClawChatTransport {
|
||||
outputTokens: 900,
|
||||
totalTokens: 3400,
|
||||
modelProvider: "openai",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
contextTokens: 400_000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ Every job carries exactly one payload kind, chosen by flag:
|
||||
Model override; must resolve to an allowed model or the run fails with a validation error.
|
||||
</ParamField>
|
||||
<ParamField path="--fallbacks" type="string">
|
||||
Per-job fallback model list, for example `--fallbacks openai/gpt-5.5,openrouter/meta-llama/llama-3.3-70b-instruct:free`. Pass `--fallbacks ""` for a strict run with no fallbacks.
|
||||
Per-job fallback model list, for example `--fallbacks openai/gpt-5.6-sol,openrouter/meta-llama/llama-3.3-70b-instruct:free`. Pass `--fallbacks ""` for a strict run with no fallbacks.
|
||||
</ParamField>
|
||||
<ParamField path="--clear-fallbacks" type="boolean">
|
||||
On `cron edit`, removes the per-job fallback override so the job follows configured fallback precedence. Cannot combine with `--fallbacks`.
|
||||
@@ -437,7 +437,7 @@ Query-string tokens are rejected.
|
||||
curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
-H 'Authorization: Bearer SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.5"}'
|
||||
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.6-sol"}'
|
||||
```
|
||||
|
||||
Fields: `message` (required), `name`, `agentId`, `sessionKey` (requires `hooks.allowRequestSessionKey=true`), `idempotencyKey`, `wakeMode`, `deliver`, `channel`, `to`, `model`, `thinking`, `timeoutSeconds`.
|
||||
|
||||
@@ -179,7 +179,7 @@ The agent-specific `agents.list[].groupChat.unmentionedInbound` value overrides
|
||||
|
||||
`messages.groupChat.visibleReplies` defaults to `"automatic"` for normal group/channel user requests. Keep that default when final assistant text should post visibly without an explicit message-tool call.
|
||||
|
||||
For ambient always-on rooms, `messages.groupChat.visibleReplies: "message_tool"` is still recommended, especially with latest-generation, tool-reliable models such as GPT 5.5. It lets the agent decide when to speak by calling the message tool. If the model returns final text without calling the tool, OpenClaw keeps that final text private and logs suppressed-delivery metadata.
|
||||
For ambient always-on rooms, `messages.groupChat.visibleReplies: "message_tool"` is still recommended, especially with latest-generation, tool-reliable models such as GPT-5.6 Sol. It lets the agent decide when to speak by calling the message tool. If the model returns final text without calling the tool, OpenClaw keeps that final text private and logs suppressed-delivery metadata.
|
||||
|
||||
Room events stay strict even when other group requests use automatic replies. Unmentioned ambient room events always require `message(action=send)` for visible output.
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ Once DMs work, you can turn your server into a full workspace where each channel
|
||||
<Step title="Allow responses without @mention">
|
||||
By default, the agent only responds in guild channels when @mentioned. On a private server you probably want it to respond to every message.
|
||||
|
||||
In guild channels, normal replies post automatically by default. For shared always-on rooms, opt into `messages.groupChat.visibleReplies: "message_tool"` so the agent can lurk and only post when it decides a channel reply is useful. This works best with latest-generation, tool-reliable models such as GPT 5.5. Ambient room events stay quiet unless the tool sends. See [Ambient room events](/channels/ambient-room-events) for the full lurk-mode config.
|
||||
In guild channels, normal replies post automatically by default. For shared always-on rooms, opt into `messages.groupChat.visibleReplies: "message_tool"` so the agent can lurk and only post when it decides a channel reply is useful. This works best with latest-generation, tool-reliable models such as GPT-5.6 Sol. Ambient room events stay quiet unless the tool sends. See [Ambient room events](/channels/ambient-room-events) for the full lurk-mode config.
|
||||
|
||||
If Discord shows typing and the logs show token usage but no posted message, check whether the turn was configured as an ambient room event or opted into message-tool visible replies.
|
||||
|
||||
@@ -1174,7 +1174,7 @@ Auto-join example:
|
||||
discord: {
|
||||
voice: {
|
||||
enabled: true,
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
autoJoin: [
|
||||
{
|
||||
guildId: "123456789012345678",
|
||||
@@ -1211,7 +1211,7 @@ Notes:
|
||||
- `voice.followUsers` lets the bot join, move, and leave Discord voice with selected users. See [Follow users in voice](#follow-users-in-voice).
|
||||
- `agent-proxy` routes speech through `discord-voice`, which preserves normal owner/tool authorization for the speaker and target session but hides the agent `tts` tool because Discord voice owns playback. By default, `agent-proxy` gives the consult full owner-equivalent tool access for owner speakers (`voice.realtime.toolPolicy: "owner"`) and strongly prefers consulting the OpenClaw agent before substantive answers (`voice.realtime.consultPolicy: "always"`). In that default `always` mode, the realtime layer does not auto-speak filler before the consult answer; it captures and transcribes speech, then speaks the routed OpenClaw answer. If multiple forced consult answers finish while Discord is still playing the first answer, later exact-speech answers are queued until playback idles instead of replacing speech mid-sentence.
|
||||
- In `stt-tts` mode, STT uses `tools.media.audio`; `voice.model` does not affect transcription.
|
||||
- In realtime modes, `voice.realtime.provider`, `voice.realtime.model`, and `voice.realtime.speakerVoice` configure the realtime audio session. For OpenAI Realtime 2.1 plus the Codex brain, use `voice.realtime.model: "gpt-realtime-2.1"` and `voice.model: "openai/gpt-5.5"`.
|
||||
- In realtime modes, `voice.realtime.provider`, `voice.realtime.model`, and `voice.realtime.speakerVoice` configure the realtime audio session. For OpenAI Realtime 2.1 plus the Codex brain, use `voice.realtime.model: "gpt-realtime-2.1"` and `voice.model: "openai/gpt-5.6-sol"`.
|
||||
- Realtime voice modes include small `IDENTITY.md`, `USER.md`, and `SOUL.md` profile files in the realtime provider instructions by default so fast direct turns keep the same identity, user grounding, and persona as the routed OpenClaw agent. Set `voice.realtime.bootstrapContextFiles` to a subset to customize this, or `[]` to disable it. Only those profile files are supported; `AGENTS.md` stays in the normal agent context. The injected profile context does not replace `openclaw_agent_consult` for workspace work, current facts, memory lookup, or tool-backed actions.
|
||||
- In OpenAI `agent-proxy` realtime mode, set `voice.realtime.requireWakeName: true` to keep Discord realtime voice silent until a transcript starts or ends with a wake name. Configured wake names must be one or two words. If `voice.realtime.wakeNames` is unset, OpenClaw uses the routed agent `name` plus `OpenClaw`, falling back to the agent id plus `OpenClaw`. Wake-name gating disables realtime provider auto-response, routes accepted turns through the OpenClaw agent consult path, and gives a short spoken acknowledgement when a leading wake name is recognized from partial transcription before the final transcript arrives.
|
||||
- The OpenAI realtime provider accepts current Realtime 2 event names and legacy Codex-compatible aliases for output audio and transcript events, so compatible provider snapshots can drift without dropping assistant audio.
|
||||
@@ -1299,7 +1299,7 @@ Default agent-proxy voice-channel session example:
|
||||
discord: {
|
||||
voice: {
|
||||
enabled: true,
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
followUsersEnabled: true,
|
||||
followUsers: ["123456789012345678"],
|
||||
realtime: {
|
||||
@@ -1349,7 +1349,7 @@ Realtime bidi example:
|
||||
voice: {
|
||||
enabled: true,
|
||||
mode: "bidi",
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
realtime: {
|
||||
provider: "openai",
|
||||
model: "gpt-realtime-2.1",
|
||||
@@ -1372,7 +1372,7 @@ Voice as an extension of an existing Discord channel session:
|
||||
voice: {
|
||||
enabled: true,
|
||||
mode: "agent-proxy",
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
agentSession: {
|
||||
mode: "target",
|
||||
target: "channel:123456789012345678",
|
||||
@@ -1407,7 +1407,7 @@ Echo-heavy OpenAI Realtime example:
|
||||
voice: {
|
||||
enabled: true,
|
||||
mode: "bidi",
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
realtime: {
|
||||
provider: "openai",
|
||||
model: "gpt-realtime-2.1",
|
||||
|
||||
@@ -46,7 +46,7 @@ always-on group chatter -> user request, or room event when configured
|
||||
|
||||
For normal group/channel requests, OpenClaw defaults to `messages.groupChat.visibleReplies: "automatic"`: the final assistant text posts to the room as the visible reply.
|
||||
|
||||
Use `messages.groupChat.visibleReplies: "message_tool"` when a shared room should let the agent decide when to speak by calling `message(action=send)`. This works best with tool-reliable models (for example GPT 5.5). If the model misses the tool and returns substantive final text, OpenClaw keeps that text private instead of posting it to the room.
|
||||
Use `messages.groupChat.visibleReplies: "message_tool"` when a shared room should let the agent decide when to speak by calling `message(action=send)`. This works best with tool-reliable models (for example GPT-5.6 Sol). If the model misses the tool and returns substantive final text, OpenClaw keeps that text private instead of posting it to the room.
|
||||
|
||||
Use `"automatic"` for models or runtimes that do not reliably follow tool-only delivery: normal text finals post directly to the room, and the agent may still call `message(action=send)` for files, images, or other attachments that cannot ride along with the final text.
|
||||
|
||||
|
||||
+3
-3
@@ -229,7 +229,7 @@ The workflow installs OCM from a pinned release and Kova from `openclaw/Kova` at
|
||||
|
||||
- `mock-provider`: Kova diagnostic scenarios against a local-build runtime with deterministic fake OpenAI-compatible auth.
|
||||
- `mock-deep-profile`: CPU/heap/trace profiling for startup, gateway, and agent-turn hotspots. Runs on schedule, or on dispatch with `deep_profile=true`.
|
||||
- `live-openai-candidate`: a real OpenAI `openai/gpt-5.6` agent turn, skipped when `OPENAI_API_KEY` is unavailable. Runs on schedule, or on dispatch with `live_openai_candidate=true`.
|
||||
- `live-openai-candidate`: a real OpenAI `openai/gpt-5.6-luna` agent turn, skipped when `OPENAI_API_KEY` is unavailable. Runs on schedule, or on dispatch with `live_openai_candidate=true`.
|
||||
|
||||
The mock-provider lane also runs OpenClaw-native source probes after the Kova pass: gateway boot timing and memory across default, skipped-channel, internal-hook, and fifty-plugin startup cases; bundled plugin import RSS, repeated mock-OpenAI `channel-chat-baseline` hello loops, CLI startup commands against the booted gateway, and the SQLite state smoke performance probe. When the previous published mock-provider source report is available for the tested ref, the source summary compares current RSS and heap values against that baseline and marks large RSS increases as `watch`. The source probe Markdown summary lives at `source/index.md` in the report bundle, with raw JSON beside it.
|
||||
|
||||
@@ -373,7 +373,7 @@ see [Testing updates and plugins](/help/testing-updates-plugins).
|
||||
|
||||
Release checks call Package Acceptance with `source=artifact`, the prepared release package artifact, `suite_profile=custom`, `docker_lanes='doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update plugin-binding-command-escape'`, and `telegram_mode=mock-openai`. This keeps package migration, update, live ClawHub skill install, stale-plugin-dependency cleanup, configured-plugin install repair, offline plugin, plugin-update, and Telegram proof on the same resolved package tarball. Set `release_package_spec` on Full Release Validation or OpenClaw Release Checks after publishing a beta to run the same matrix against the shipped npm package without rebuilding; set `package_acceptance_package_spec` only when Package Acceptance needs a different package from the rest of release validation. Cross-OS release checks still cover OS-specific onboarding, installer, and platform behavior; package/update product validation should start with Package Acceptance.
|
||||
|
||||
The `published-upgrade-survivor` Docker lane validates one published package baseline per run in the blocking release path. In Package Acceptance, the resolved `package-under-test` tarball is always the candidate and `published_upgrade_survivor_baseline` selects the fallback published baseline, defaulting to `openclaw@latest`; failed-lane rerun commands preserve that baseline. Full Release Validation with `run_release_soak=true` or `release_profile=full` sets `published_upgrade_survivor_baselines='last-stable-4 2026.4.23 2026.5.2 2026.4.15'` and `published_upgrade_survivor_scenarios=reported-issues` to expand across the four latest stable npm releases plus pinned plugin-compatibility boundary releases and issue-shaped fixtures for Feishu config, preserved bootstrap/persona files, configured OpenClaw plugin installs, tilde log paths, and stale legacy plugin dependency roots. Multi-baseline published-upgrade survivor selections are sharded by baseline into separate targeted Docker runner jobs. The separate `Update Migration` workflow uses the `update-migration` Docker lane with `all-since-2026.4.23` baselines and `plugin-deps-cleanup` scenarios when the question is exhaustive published update cleanup, not normal Full Release CI breadth. Local aggregate runs can pass exact package specs with `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`, keep a single lane with `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` such as `openclaw@2026.4.15`, or set `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` for the scenario matrix. The published lane configures the baseline with a baked `openclaw config set` command recipe, records recipe steps in `summary.json`, and probes `/healthz`, `/readyz`, plus RPC status after Gateway start. The Windows packaged and installer fresh lanes also verify that an installed package can import a browser-control override from a raw absolute Windows path. The OpenAI cross-OS agent-turn smoke defaults to `OPENCLAW_CROSS_OS_OPENAI_MODEL` when set, otherwise `openai/gpt-5.5`, so the install and gateway proof stays on a GPT-5 test model while avoiding GPT-4.x defaults.
|
||||
The `published-upgrade-survivor` Docker lane validates one published package baseline per run in the blocking release path. In Package Acceptance, the resolved `package-under-test` tarball is always the candidate and `published_upgrade_survivor_baseline` selects the fallback published baseline, defaulting to `openclaw@latest`; failed-lane rerun commands preserve that baseline. Full Release Validation with `run_release_soak=true` or `release_profile=full` sets `published_upgrade_survivor_baselines='last-stable-4 2026.4.23 2026.5.2 2026.4.15'` and `published_upgrade_survivor_scenarios=reported-issues` to expand across the four latest stable npm releases plus pinned plugin-compatibility boundary releases and issue-shaped fixtures for Feishu config, preserved bootstrap/persona files, configured OpenClaw plugin installs, tilde log paths, and stale legacy plugin dependency roots. Multi-baseline published-upgrade survivor selections are sharded by baseline into separate targeted Docker runner jobs. The separate `Update Migration` workflow uses the `update-migration` Docker lane with `all-since-2026.4.23` baselines and `plugin-deps-cleanup` scenarios when the question is exhaustive published update cleanup, not normal Full Release CI breadth. Local aggregate runs can pass exact package specs with `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`, keep a single lane with `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` such as `openclaw@2026.4.15`, or set `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` for the scenario matrix. The published lane configures the baseline with a baked `openclaw config set` command recipe, records recipe steps in `summary.json`, and probes `/healthz`, `/readyz`, plus RPC status after Gateway start. The Windows packaged and installer fresh lanes also verify that an installed package can import a browser-control override from a raw absolute Windows path. The OpenAI cross-OS agent-turn smoke defaults to `OPENCLAW_CROSS_OS_OPENAI_MODEL` when set, otherwise `openai/gpt-5.6-luna`, so the install and gateway proof uses the lower-cost GPT-5.6 test tier.
|
||||
|
||||
### Legacy compatibility windows
|
||||
|
||||
@@ -517,7 +517,7 @@ QA Lab has dedicated CI lanes outside the main smart-scoped workflow. Agentic pa
|
||||
|
||||
- The `QA-Lab - All Lanes` workflow runs nightly on `main` and on manual dispatch; it fans out the mock parity lane, live Matrix lane, and live Telegram and Discord lanes as parallel jobs. Live jobs use the `qa-live-shared` environment, and Telegram/Discord use Convex leases.
|
||||
|
||||
Release checks run Matrix and Telegram live transport lanes with the deterministic mock provider and mock-qualified models (`mock-openai/gpt-5.5` and `mock-openai/gpt-5.5-alt`) so the channel contract is isolated from live model latency and normal provider-plugin startup. The live transport gateway disables memory search because QA parity covers memory behavior separately; provider connectivity is covered by the separate live model, native provider, and Docker provider suites.
|
||||
Release checks run Matrix and Telegram live transport lanes with the deterministic mock provider and mock-qualified models (`mock-openai/gpt-5.6-luna` and `mock-openai/gpt-5.6-luna-alt`) so the channel contract is isolated from live model latency and normal provider-plugin startup. The live transport gateway disables memory search because QA parity covers memory behavior separately; provider connectivity is covered by the separate live model, native provider, and Docker provider suites.
|
||||
|
||||
Matrix uses `--profile fast` for scheduled and release gates, adding `--fail-fast` only when the checked-out CLI supports it. The CLI default and manual workflow input remain `all`; manual `matrix_profile=all` dispatch always shards full Matrix coverage into `transport`, `media`, `e2ee-smoke`, `e2ee-deep`, and `e2ee-cli` jobs.
|
||||
|
||||
|
||||
+2
-2
@@ -285,9 +285,9 @@ Example patch:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
model: { primary: "openai/gpt-5.6-sol" },
|
||||
models: {
|
||||
"openai/gpt-5.5": { params: { fastMode: true } },
|
||||
"openai/gpt-5.6-sol": { params: { fastMode: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -250,7 +250,7 @@ OpenClaw: Applied. Audit entry written.
|
||||
Agent creation can also be queued locally or via rescue:
|
||||
|
||||
```text
|
||||
create agent work workspace ~/Projects/work model openai/gpt-5.5
|
||||
create agent work workspace ~/Projects/work model openai/gpt-5.6-sol
|
||||
/crestodian create agent work workspace ~/Projects/work
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ openclaw infer model run --prompt "Summarize this changelog entry" --model opena
|
||||
openclaw infer model run --prompt "Describe this image in one sentence" --file ./photo.jpg --model google/gemini-2.5-flash --json
|
||||
openclaw infer model run --prompt "Use more reasoning here" --thinking high --json
|
||||
openclaw infer model providers --json
|
||||
openclaw infer model inspect --model gpt-5.5 --json
|
||||
openclaw infer model inspect --model gpt-5.6-sol --json
|
||||
```
|
||||
|
||||
Use full `<provider/model>` refs with `--local` to smoke-test one provider without starting the Gateway or loading the agent tool surface:
|
||||
@@ -133,7 +133,7 @@ openclaw infer model run --local --model google/gemini-2.5-flash --prompt "Reply
|
||||
openclaw infer model run --local --model groq/llama-3.1-8b-instant --prompt "Reply with exactly: pong" --json
|
||||
openclaw infer model run --local --model mistral/mistral-medium-3-5 --prompt "Reply with exactly: pong" --json
|
||||
openclaw infer model run --local --model mistral/mistral-small-latest --prompt "Reply with exactly: pong" --json
|
||||
openclaw infer model run --local --model openai/gpt-5.5 --prompt "Reply with exactly: pong" --json
|
||||
openclaw infer model run --local --model openai/gpt-5.6-luna --prompt "Reply with exactly: pong" --json
|
||||
openclaw infer model run --local --model ollama/qwen2.5vl:7b --prompt "Describe this image." --file ./photo.jpg --json
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -614,9 +614,9 @@ Example JSON output:
|
||||
],
|
||||
"modelRefs": [
|
||||
{
|
||||
"ref": "openai/gpt-5.5",
|
||||
"ref": "openai/gpt-5.6-sol",
|
||||
"provider": "openai",
|
||||
"model": "gpt-5.5",
|
||||
"model": "gpt-5.6-sol",
|
||||
"source": "oc://openclaw.config/agents/defaults/model"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -72,7 +72,7 @@ symlinks and out-of-root paths are skipped.
|
||||
"hasMore": false,
|
||||
"activeMinutes": null,
|
||||
"sessions": [
|
||||
{ "agentId": "main", "key": "agent:main:main", "model": "openai/gpt-5.5" },
|
||||
{ "agentId": "main", "key": "agent:main:main", "model": "openai/gpt-5.6-sol" },
|
||||
{ "agentId": "work", "key": "agent:work:main", "model": "anthropic/claude-sonnet-4-6" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ configuration. They are different layers:
|
||||
| Layer | Examples | Meaning |
|
||||
| ------------- | -------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| Provider | `anthropic`, `github-copilot`, `openai` | How OpenClaw authenticates, discovers models, and names model refs. |
|
||||
| Model | `claude-opus-4-6`, `gpt-5.5` | The model selected for the agent turn. |
|
||||
| Model | `claude-opus-4-6`, `gpt-5.6-sol` | The model selected for the agent turn. |
|
||||
| Agent runtime | `claude-cli`, `codex`, `copilot`, `openclaw` | The low-level loop or backend that executes the prepared turn. |
|
||||
| Channel | Discord, Slack, Telegram, WhatsApp | Where messages enter and leave OpenClaw. |
|
||||
|
||||
@@ -68,7 +68,7 @@ keeps the model ref as `openai/*` and selects the `codex` runtime:
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -244,7 +244,7 @@ The Codex runtime support contract is documented in
|
||||
Status output can show both `Execution` and `Runtime` labels. Read them as
|
||||
diagnostics, not provider names:
|
||||
|
||||
- A model ref such as `openai/gpt-5.5` is the selected provider/model.
|
||||
- A model ref such as `openai/gpt-5.6-sol` is the selected provider/model.
|
||||
- A runtime id such as `codex` is the loop executing the turn.
|
||||
- A channel label such as Telegram or Discord is where the conversation is happening.
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ For an agent/CV style desktop task, run:
|
||||
pnpm openclaw qa mantis visual-task \
|
||||
--browser-url https://example.net \
|
||||
--expect-text "Example Domain" \
|
||||
--vision-model openai/gpt-5.5
|
||||
--vision-model openai/gpt-5.6-luna
|
||||
```
|
||||
|
||||
`visual-task` leases or reuses a Crabbox desktop/browser machine, starts
|
||||
@@ -560,8 +560,8 @@ Run the Mantis status-reaction scenario explicitly:
|
||||
pnpm openclaw qa discord \
|
||||
--scenario discord-status-reactions-tool-only \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.5 \
|
||||
--alt-model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-luna \
|
||||
--alt-model openai/gpt-5.6-luna \
|
||||
--fast
|
||||
```
|
||||
|
||||
@@ -1219,7 +1219,7 @@ model refs and write a judged Markdown report:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa character-eval \
|
||||
--model openai/gpt-5.5,thinking=medium,fast \
|
||||
--model openai/gpt-5.6-luna,thinking=medium,fast \
|
||||
--model openai/gpt-5.2,thinking=xhigh \
|
||||
--model openai/gpt-5,thinking=xhigh \
|
||||
--model anthropic/claude-opus-4-8,thinking=high \
|
||||
@@ -1227,7 +1227,7 @@ pnpm openclaw qa character-eval \
|
||||
--model zai/glm-5.1,thinking=high \
|
||||
--model moonshot/kimi-k2.5,thinking=high \
|
||||
--model google/gemini-3.1-pro-preview,thinking=high \
|
||||
--judge-model openai/gpt-5.5,thinking=xhigh,fast \
|
||||
--judge-model openai/gpt-5.6-sol,thinking=xhigh,fast \
|
||||
--judge-model anthropic/claude-opus-4-8,thinking=high \
|
||||
--blind-judge-models \
|
||||
--concurrency 16 \
|
||||
@@ -1245,7 +1245,7 @@ providers: the judge prompt still gets every transcript and run status, but
|
||||
candidate refs are replaced with neutral labels such as `candidate-01`; the
|
||||
report maps rankings back to real refs after parsing.
|
||||
|
||||
Candidate runs default to `high` thinking, with `medium` for GPT-5.5 and
|
||||
Candidate runs default to `high` thinking, with `medium` for GPT-5.6 Luna and
|
||||
`xhigh` for older OpenAI eval refs that support it. Override a specific
|
||||
candidate inline with `--model provider/model,thinking=<level>`; inline
|
||||
options also support `fast`, `no-fast`, and `fast=<bool>`. `--thinking
|
||||
@@ -1260,11 +1260,11 @@ Lower `--concurrency` or `--judge-concurrency` when provider limits or local
|
||||
gateway pressure make a run too noisy.
|
||||
|
||||
When no candidate `--model` is passed, the character eval defaults to
|
||||
`openai/gpt-5.5`, `openai/gpt-5.2`, `openai/gpt-5`,
|
||||
`openai/gpt-5.6-luna`, `openai/gpt-5.2`, `openai/gpt-5`,
|
||||
`anthropic/claude-opus-4-8`, `anthropic/claude-sonnet-4-6`, `zai/glm-5.1`,
|
||||
`moonshot/kimi-k2.5`, and `google/gemini-3.1-pro-preview`. When no
|
||||
`--judge-model` is passed, the judges default to
|
||||
`openai/gpt-5.5,thinking=xhigh,fast` and
|
||||
`openai/gpt-5.6-sol,thinking=xhigh,fast` and
|
||||
`anthropic/claude-opus-4-8,thinking=high`.
|
||||
|
||||
## Related docs
|
||||
|
||||
@@ -315,7 +315,7 @@ Higher values preserve more visual detail.
|
||||
Image-tool compression/detail preference for images loaded from file paths, URLs, and media references.
|
||||
Default: `auto`.
|
||||
|
||||
OpenClaw adapts the resize ladder to the selected image model. For example, Claude Opus 4.8, OpenAI GPT-5.5, Qwen VL, and hosted Llama 4 vision models can use larger images than older/default high-detail vision paths, while multi-image turns are compressed more aggressively in `auto` mode to control token and latency cost.
|
||||
OpenClaw adapts the resize ladder to the selected image model. For example, Claude Opus 4.8, OpenAI GPT-5.6 Sol, Qwen VL, and hosted Llama 4 vision models can use larger images than older/default high-detail vision paths, while multi-image turns are compressed more aggressively in `auto` mode to control token and latency cost.
|
||||
|
||||
Values:
|
||||
|
||||
@@ -431,7 +431,7 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
- `toolProgressDetail`: detail mode for `/verbose` tool summaries and progress-draft tool lines. Values: `"explain"` (default, compact human labels) or `"raw"` (append raw command/detail when available). Per-agent `agents.list[].toolProgressDetail` overrides this default.
|
||||
- `reasoningDefault`: default reasoning visibility for agents. Values: `"off"`, `"on"`, `"stream"`. Per-agent `agents.list[].reasoningDefault` overrides this default. Configured reasoning defaults are only applied for owners, authorized senders, or operator-admin gateway contexts when no per-message or session reasoning override is set.
|
||||
- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`.
|
||||
- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.5` for OpenAI API-key or Codex OAuth access). If you omit the provider, OpenClaw tries an alias first, then a unique configured-provider match for that exact model id, and only then falls back to the configured default provider (deprecated compatibility behavior, so prefer explicit `provider/model`). If that provider no longer exposes the configured default model, OpenClaw falls back to the first configured provider/model instead of surfacing a stale removed-provider default.
|
||||
- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.6-sol` for Codex OAuth access). If you omit the provider, OpenClaw tries an alias first, then a unique configured-provider match for that exact model id, and only then falls back to the configured default provider (deprecated compatibility behavior, so prefer explicit `provider/model`). If that provider no longer exposes the configured default model, OpenClaw falls back to the first configured provider/model instead of surfacing a stale removed-provider default.
|
||||
- `models`: the configured model catalog and allowlist for `/model`. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`, `responsesServerCompaction`, `responsesCompactThreshold`, OpenRouter `provider` routing, `chat_template_kwargs`, `extra_body`/`extraBody`).
|
||||
- Use `provider/*` entries such as `"openai/*": {}` or `"vllm/*": {}` to show all discovered models for selected providers without manually listing every model id.
|
||||
- Add `agentRuntime` to a `provider/*` entry when every dynamically discovered model for that provider should use the same runtime. Exact `provider/model` runtime policy still wins over the wildcard.
|
||||
@@ -464,7 +464,7 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
models: {
|
||||
"anthropic/claude-opus-4-8": {
|
||||
agentRuntime: { id: "claude-cli" },
|
||||
|
||||
@@ -61,7 +61,7 @@ For group/thread conversations, keys are channel-specific group IDs, topic IDs,
|
||||
"123456789012345678": "anthropic/claude-opus-4-6",
|
||||
},
|
||||
slack: {
|
||||
C1234567890: "openai/gpt-5.5",
|
||||
C1234567890: "openai/gpt-5.6-sol",
|
||||
"user:U12345": "openai/gpt-5.4-mini",
|
||||
},
|
||||
telegram: {
|
||||
@@ -826,7 +826,7 @@ Group messages default to **require mention** (metadata mention or safe regex pa
|
||||
|
||||
Visible replies are controlled separately. Normal group, channel, and internal WebChat direct requests default to automatic final delivery: final assistant text posts through the legacy visible reply path. Opt into `messages.visibleReplies: "message_tool"` or `messages.groupChat.visibleReplies: "message_tool"` when visible output should only post after the agent calls `message(action=send)`. If the model returns a substantive final answer without calling the message tool in an opted-in tool-only mode, that final text stays private, the gateway verbose log records suppressed payload metadata, and OpenClaw enqueues one recovery retry asking the model to deliver the same reply via `message(action=send)`.
|
||||
|
||||
Tool-only visible replies require a model/runtime that reliably calls tools, and are recommended for shared ambient rooms on latest-generation models such as GPT 5.5. Some weaker models can answer final text but fail to understand that source-visible output must be sent with `message(action=send)`. OpenClaw recovers the common stranded-final case by default only when the final is substantive, the source turn was not a room event, send policy did not deny delivery, and no source reply was already sent. Recovery is bounded to one retry; it suppresses persistence for the synthetic retry prompt and keeps that retry out of collect batching so it cannot merge with unrelated queued prompts. If the retry also strands or cannot be enqueued, OpenClaw delivers only a sanitized diagnostic such as "I generated a reply but could not deliver it to this chat. Please try again." The original private final text is never marked for automatic source delivery. For models that repeatedly strand replies, use `"automatic"` so the final assistant turn is the visible reply path, switch to a stronger tool-calling model, inspect the gateway verbose log for the suppressed payload summary, or set `messages.groupChat.visibleReplies: "automatic"` to use visible final replies for every group/channel request.
|
||||
Tool-only visible replies require a model/runtime that reliably calls tools, and are recommended for shared ambient rooms on latest-generation models such as GPT-5.6 Sol. Some weaker models can answer final text but fail to understand that source-visible output must be sent with `message(action=send)`. OpenClaw recovers the common stranded-final case by default only when the final is substantive, the source turn was not a room event, send policy did not deny delivery, and no source reply was already sent. Recovery is bounded to one retry; it suppresses persistence for the synthetic retry prompt and keeps that retry out of collect batching so it cannot merge with unrelated queued prompts. If the retry also strands or cannot be enqueued, OpenClaw delivers only a sanitized diagnostic such as "I generated a reply but could not deliver it to this chat. Please try again." The original private final text is never marked for automatic source delivery. For models that repeatedly strand replies, use `"automatic"` so the final assistant turn is the visible reply path, switch to a stronger tool-calling model, inspect the gateway verbose log for the suppressed payload summary, or set `messages.groupChat.visibleReplies: "automatic"` to use visible final replies for every group/channel request.
|
||||
|
||||
If the message tool is unavailable under the active tool policy, OpenClaw falls back to automatic visible replies instead of silently suppressing the response. `openclaw doctor` warns about this mismatch.
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ Controls elevated exec access outside the sandbox:
|
||||
commandHighlighting: false,
|
||||
applyPatch: {
|
||||
enabled: true,
|
||||
allowModels: ["gpt-5.5"],
|
||||
allowModels: ["gpt-5.6-sol"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ OpenClaw has two log surfaces:
|
||||
At startup, the Gateway logs the resolved default agent model plus the mode defaults that affect new sessions:
|
||||
|
||||
```text
|
||||
agent model: openai/gpt-5.5 (thinking=medium, fast=on)
|
||||
agent model: openai/gpt-5.6-sol (thinking=medium, fast=on)
|
||||
```
|
||||
|
||||
`thinking` comes from the default agent, model params, or the global agent default; when unset it shows `medium`. `fast` comes from the default agent or the model's `fastMode` params.
|
||||
|
||||
@@ -81,7 +81,7 @@ MiniMax M3 uses `minimax/MiniMax-M3` as its default provider/model reference.
|
||||
- `OPENCLAW_LIVE_MODELS=modern` runs the curated high-signal priority list (see [Live: model matrix](#live-model-matrix-what-we-cover))
|
||||
- `OPENCLAW_LIVE_MODELS=small` runs the curated small-model priority list
|
||||
- `OPENCLAW_LIVE_MODELS=all` is an alias for `modern`
|
||||
- or `OPENCLAW_LIVE_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,..."` (comma allowlist)
|
||||
- or `OPENCLAW_LIVE_MODELS="openai/gpt-5.6-luna,anthropic/claude-opus-4-6,..."` (comma allowlist)
|
||||
- Local Ollama small-model runs default to `http://127.0.0.1:11434`; set `OPENCLAW_LIVE_OLLAMA_BASE_URL` only for LAN, custom, or Ollama Cloud endpoints.
|
||||
- Modern/all and small sweeps default to their curated-list length as a cap; set `OPENCLAW_LIVE_MAX_MODELS=0` for an exhaustive selected-profile sweep or a positive number for a smaller cap.
|
||||
- Exhaustive sweeps use `OPENCLAW_LIVE_TEST_TIMEOUT_MS` for the whole direct-model test timeout. Default: 60 minutes.
|
||||
@@ -239,11 +239,11 @@ Notes:
|
||||
- `OPENCLAW_LIVE_ACP_BIND_AGENT=opencode`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex,gemini`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND='npx -y @agentclientprotocol/claude-agent-acp@<version>'`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_CODEX_MODEL=gpt-5.5`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_CODEX_MODEL=gpt-5.6-luna`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_OPENCODE_MODEL=opencode/kimi-k2.6`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_IMAGE_PROBE=1` (or `on`/`true`/`yes`) to force the image probe on; any other value forces it off. Runs by default for every agent except `opencode`.
|
||||
- `OPENCLAW_LIVE_ACP_BIND_REQUIRE_CRON=1`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_PARENT_MODEL=openai/gpt-5.5`
|
||||
- `OPENCLAW_LIVE_ACP_BIND_PARENT_MODEL=openai/gpt-5.6-luna`
|
||||
- Notes:
|
||||
- This lane uses the gateway `chat.send` surface with admin-only synthetic originating-route fields so tests can attach message-channel context without pretending to deliver externally.
|
||||
- When `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND` is unset, the test uses the embedded `acpx` plugin's built-in agent registry for the selected ACP harness agent.
|
||||
@@ -299,7 +299,7 @@ Docker notes:
|
||||
denied so the agent asks back
|
||||
- Test: `src/gateway/gateway-codex-harness.live.test.ts`
|
||||
- Enable: `OPENCLAW_LIVE_CODEX_HARNESS=1`
|
||||
- Harness baseline model: `codex/gpt-5.5`
|
||||
- Harness baseline model: `openai/gpt-5.6-luna`
|
||||
- Fresh OpenAI API-key selection default: `openai/gpt-5.6`
|
||||
- Default thinking: `low`
|
||||
- Model override: `OPENCLAW_LIVE_CODEX_HARNESS_MODEL=openai/<model>`
|
||||
@@ -323,7 +323,7 @@ OPENCLAW_LIVE_CODEX_HARNESS=1 \
|
||||
OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=1 \
|
||||
OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=1 \
|
||||
OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=1 \
|
||||
OPENCLAW_LIVE_CODEX_HARNESS_MODEL=openai/gpt-5.5 \
|
||||
OPENCLAW_LIVE_CODEX_HARNESS_MODEL=openai/gpt-5.6-luna \
|
||||
pnpm test:live -- src/gateway/gateway-codex-harness.live.test.ts
|
||||
```
|
||||
|
||||
@@ -385,7 +385,7 @@ Docker notes:
|
||||
Narrow, explicit allowlists are fastest and least flaky:
|
||||
|
||||
- Single model, direct (no gateway):
|
||||
- `OPENCLAW_LIVE_MODELS="openai/gpt-5.5" pnpm test:live src/agents/models.profiles.live.test.ts`
|
||||
- `OPENCLAW_LIVE_MODELS="openai/gpt-5.6-luna" pnpm test:live src/agents/models.profiles.live.test.ts`
|
||||
|
||||
- Small-model direct profile:
|
||||
- `OPENCLAW_LIVE_MODELS=small pnpm test:live src/agents/models.profiles.live.test.ts`
|
||||
@@ -397,10 +397,10 @@ Narrow, explicit allowlists are fastest and least flaky:
|
||||
- `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_OLLAMA=1 OPENCLAW_LIVE_OLLAMA_BASE_URL=https://ollama.com OPENCLAW_LIVE_OLLAMA_MODEL=glm-5.1:cloud OPENCLAW_LIVE_OLLAMA_WEB_SEARCH=0 pnpm test:live -- extensions/ollama/ollama.live.test.ts`
|
||||
|
||||
- Single model, gateway smoke:
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.6-luna" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
- Tool calling across several providers:
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3.5-flash,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M3" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.6-luna,anthropic/claude-opus-4-6,google/gemini-3.5-flash,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M3" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
- Z.AI Coding Plan GLM-5.2 direct smoke:
|
||||
- `ZAI_CODING_LIVE_TEST=1 pnpm test:live src/agents/zai.live.test.ts`
|
||||
@@ -473,7 +473,7 @@ Notes on the modern list:
|
||||
Run gateway smoke with tools + image across a hand-picked cross-provider set:
|
||||
|
||||
```bash
|
||||
OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3.5-flash,google-antigravity/claude-opus-4-6-thinking,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M3" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts
|
||||
OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.6-luna,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3.5-flash,google-antigravity/claude-opus-4-6-thinking,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M3" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts
|
||||
```
|
||||
|
||||
Optional additional coverage outside the curated lists (nice to have, pick a "tools"-capable model you have enabled):
|
||||
|
||||
@@ -84,9 +84,9 @@ When debugging real providers/models (requires real creds):
|
||||
- Live suite (models + gateway tool/image probes): `pnpm test:live`
|
||||
- Target one live file quietly: `pnpm test:live -- src/agents/models.profiles.live.test.ts`
|
||||
- Runtime performance reports: dispatch `OpenClaw Performance` with
|
||||
`live_openai_candidate=true` for a real `openai/gpt-5.5` agent turn or
|
||||
`live_openai_candidate=true` for a real `openai/gpt-5.6-luna` agent turn or
|
||||
`deep_profile=true` for Kova CPU/heap/trace artifacts. Daily scheduled runs
|
||||
publish mock-provider, deep-profile, and GPT 5.5 lane reports to
|
||||
publish mock-provider, deep-profile, and GPT-5.6 Luna lane reports to
|
||||
`openclaw/clawgrit-reports` from a separate artifact-consuming publisher job;
|
||||
missing or invalid publisher authentication fails scheduled and
|
||||
`profile=release` runs. Manual non-release dispatches keep the GitHub artifacts
|
||||
@@ -173,7 +173,7 @@ explicitly, while the Matrix CLI and manual workflow input default remains
|
||||
`all`; manual dispatch can shard `all` into `transport`, `media`,
|
||||
`e2ee-smoke`, `e2ee-deep`, and `e2ee-cli` jobs. `OpenClaw Release Checks` runs
|
||||
parity plus the fast Matrix and Telegram lanes before release approval, using
|
||||
`mock-openai/gpt-5.5` for release transport checks so they stay deterministic
|
||||
`mock-openai/gpt-5.6-luna` for release transport checks so they stay deterministic
|
||||
and avoid normal provider-plugin startup. These live transport gateways
|
||||
disable memory search; memory behavior stays covered by the QA parity suites.
|
||||
|
||||
@@ -369,7 +369,7 @@ gh workflow run package-acceptance.yml --ref main \
|
||||
- Use `--platform macos`, `--platform windows`, or `--platform linux`
|
||||
while iterating on one guest. Use `--json` for the summary artifact
|
||||
path and per-lane status.
|
||||
- The OpenAI lane uses `openai/gpt-5.5` for the live agent-turn proof by
|
||||
- The OpenAI lane uses `openai/gpt-5.6-luna` for the live agent-turn proof by
|
||||
default. Pass `--model <provider/model>` or set
|
||||
`OPENCLAW_PARALLELS_OPENAI_MODEL` to validate another OpenAI model.
|
||||
- Wrap long local runs in a host timeout so Parallels transport stalls
|
||||
|
||||
@@ -157,9 +157,9 @@ From your local machine, create a patch file and pipe it to the VM:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
model: { primary: "openai/gpt-5.6-sol" },
|
||||
models: {
|
||||
"openai/gpt-5.5": { params: { fastMode: true } },
|
||||
"openai/gpt-5.6-sol": { params: { fastMode: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -82,7 +82,7 @@ Each `models[]` entry is a **provider** entry (default) or a **CLI** entry:
|
||||
{
|
||||
type: "provider", // default if omitted
|
||||
provider: "openai",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-sol",
|
||||
prompt: "Describe the image in <= 500 chars.",
|
||||
maxChars: 500,
|
||||
maxBytes: 10485760,
|
||||
@@ -276,7 +276,7 @@ When `mode: "all"`, outputs are labeled `[Image 1/2]`, `[Audio 2/2]`, etc.
|
||||
tools: {
|
||||
media: {
|
||||
models: [
|
||||
{ provider: "openai", model: "gpt-5.5", capabilities: ["image"] },
|
||||
{ provider: "openai", model: "gpt-5.6-sol", capabilities: ["image"] },
|
||||
{
|
||||
provider: "google",
|
||||
model: "gemini-3-flash-preview",
|
||||
@@ -355,7 +355,7 @@ When `mode: "all"`, outputs are labeled `[Image 1/2]`, `[Audio 2/2]`, etc.
|
||||
maxBytes: 10485760,
|
||||
maxChars: 500,
|
||||
models: [
|
||||
{ provider: "openai", model: "gpt-5.5" },
|
||||
{ provider: "openai", model: "gpt-5.6-sol" },
|
||||
{ provider: "anthropic", model: "claude-opus-4-8" },
|
||||
{
|
||||
type: "cli",
|
||||
@@ -419,7 +419,7 @@ When `mode: "all"`, outputs are labeled `[Image 1/2]`, `[Audio 2/2]`, etc.
|
||||
When media understanding runs, `/status` includes a per-capability summary line:
|
||||
|
||||
```
|
||||
📎 Media: image ok (openai/gpt-5.5) · audio ok (whisper-cli observed=metal)
|
||||
📎 Media: image ok (openai/gpt-5.6-sol) · audio ok (whisper-cli observed=metal)
|
||||
```
|
||||
|
||||
For preflight inventory, run `openclaw capability audio providers`. Local rows show the local fallback winner separately from global provider selection, readiness, and separate capable/requested/observed backend fields. The same local selection is available as an informational doctor finding:
|
||||
|
||||
@@ -526,7 +526,7 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({
|
||||
|
||||
const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({
|
||||
provider: "codex",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-sol",
|
||||
input: [
|
||||
{
|
||||
type: "image",
|
||||
|
||||
@@ -300,7 +300,7 @@ Users can override any backend default:
|
||||
},
|
||||
},
|
||||
model: {
|
||||
primary: "openai/gpt-5.5",
|
||||
primary: "openai/gpt-5.6-sol",
|
||||
fallbacks: ["acme-cli/large"],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@ Computer Use in and lets OpenClaw install or re-enable it before the turn:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ native compaction, and app-server execution. OpenClaw still owns chat
|
||||
channels, session files, model selection, OpenClaw dynamic tools, approvals,
|
||||
media delivery, and the visible transcript mirror.
|
||||
|
||||
Use canonical OpenAI model refs such as `openai/gpt-5.5`. Do not configure
|
||||
Use canonical OpenAI model refs such as `openai/gpt-5.6-sol`. Do not configure
|
||||
legacy Codex GPT refs; put OpenAI agent auth order under `auth.order.openai`.
|
||||
Legacy Codex auth profile ids and legacy Codex auth order entries are
|
||||
repaired by `openclaw doctor --fix`.
|
||||
@@ -36,7 +36,7 @@ This Codex-native feature is separate from
|
||||
[OpenClaw code mode](/reference/code-mode), an opt-in QuickJS-WASI runtime
|
||||
for generic OpenClaw runs with a different `exec` input shape. For the
|
||||
broader model/provider/runtime split, start with
|
||||
[Agent runtimes](/concepts/agent-runtimes): `openai/gpt-5.5` is the model
|
||||
[Agent runtimes](/concepts/agent-runtimes): `openai/gpt-5.6-sol` is the model
|
||||
ref, `codex` is the runtime, and Telegram, Discord, Slack, or another
|
||||
channel is the communication surface.
|
||||
|
||||
@@ -77,7 +77,7 @@ Enable the `codex` plugin and select an OpenAI agent model:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -316,7 +316,7 @@ default:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -348,7 +348,7 @@ Keep Claude as the default agent and add a named Codex agent:
|
||||
{
|
||||
id: "codex",
|
||||
name: "Codex",
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -376,7 +376,7 @@ available. Add explicit runtime policy for a written fail-closed rule:
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
@@ -932,7 +932,7 @@ OpenClaw host:
|
||||
| tail -200
|
||||
```
|
||||
|
||||
Useful excerpts usually include `openai/gpt-5.5` or `openai/gpt-5.4`,
|
||||
Useful excerpts usually include `openai/gpt-5.6-sol` or `openai/gpt-5.6-luna`,
|
||||
`Runtime: OpenAI Codex`, `agentRuntime.id` or `harnessRuntime`,
|
||||
`candidateProvider: "openai"`, and a `401`, `Incorrect API key`, or
|
||||
`No API key` result. A corrected run should show the OpenAI OAuth path
|
||||
|
||||
@@ -58,7 +58,7 @@ Configure an explicit vision model for deterministic startup:
|
||||
logbook: {
|
||||
enabled: true,
|
||||
config: {
|
||||
visionModel: "codex/gpt-5.5",
|
||||
visionModel: "codex/gpt-5.6-sol",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -140,7 +140,7 @@ text.
|
||||
nodeId: "my-mac",
|
||||
screenIndex: 0,
|
||||
maxWidth: 1440,
|
||||
visionModel: "codex/gpt-5.5",
|
||||
visionModel: "codex/gpt-5.6-sol",
|
||||
retentionDays: 14,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -806,7 +806,7 @@ Keep `preferOver` scoped to plugin ids that can really provide the same channel.
|
||||
|
||||
## modelSupport reference
|
||||
|
||||
Use `modelSupport` when OpenClaw should infer your provider plugin from shorthand model ids like `gpt-5.5` or `claude-sonnet-4.6` before plugin runtime loads.
|
||||
Use `modelSupport` when OpenClaw should infer your provider plugin from shorthand model ids like `gpt-5.6-sol` or `claude-sonnet-4.6` before plugin runtime loads.
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -166,7 +166,7 @@ OpenClaw. The harness then claims that provider in `supports(...)`.
|
||||
|
||||
The bundled Codex plugin follows this pattern:
|
||||
|
||||
- preferred user model refs: `openai/gpt-5.5`
|
||||
- preferred user model refs: `openai/gpt-5.6-sol`
|
||||
- compatibility refs: legacy `codex/gpt-*` refs remain accepted, but new
|
||||
configs should not use them as normal provider/model refs
|
||||
- harness id: `codex`
|
||||
@@ -288,7 +288,7 @@ For Codex-only embedded runs:
|
||||
},
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": "openai/gpt-5.5"
|
||||
"model": "openai/gpt-5.6-sol"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,9 +322,9 @@ Per-agent overrides use the same model-scoped shape:
|
||||
"list": [
|
||||
{
|
||||
"id": "codex-only",
|
||||
"model": "openai/gpt-5.5",
|
||||
"model": "openai/gpt-5.6-sol",
|
||||
"models": {
|
||||
"openai/gpt-5.5": {
|
||||
"openai/gpt-5.6-sol": {
|
||||
"agentRuntime": { "id": "codex" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ two-party event loops that do not go through the shared inbound reply runner.
|
||||
Default model and provider constants:
|
||||
|
||||
```typescript
|
||||
const model = api.runtime.agent.defaults.model; // e.g. "gpt-5.5"
|
||||
const model = api.runtime.agent.defaults.model; // e.g. "gpt-5.6-sol"
|
||||
const provider = api.runtime.agent.defaults.provider; // e.g. "openai"
|
||||
```
|
||||
|
||||
@@ -294,7 +294,7 @@ two-party event loops that do not go through the shared inbound reply runner.
|
||||
sessionKey: "agent:main:subagent:search-helper",
|
||||
message: "Expand this query into focused follow-up searches.",
|
||||
provider: "openai", // optional override
|
||||
model: "gpt-5.5", // optional override
|
||||
model: "gpt-5.6-sol", // optional override
|
||||
deliver: false,
|
||||
});
|
||||
|
||||
@@ -443,7 +443,7 @@ two-party event loops that do not go through the shared inbound reply runner.
|
||||
// Include at least one image; text inputs are supplemental context.
|
||||
const evidence = await api.runtime.mediaUnderstanding.extractStructuredWithModel({
|
||||
provider: "codex",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-sol",
|
||||
input: [
|
||||
{
|
||||
type: "image",
|
||||
|
||||
@@ -96,7 +96,7 @@ Unlinked cards can start work directly:
|
||||
|
||||
- **Run Codex** / **Run Claude** starts a task-tracked agent run with an
|
||||
explicit engine, sends the card prompt, and marks the card `running`. Codex
|
||||
runs use `openai/gpt-5.5`; Claude runs use `anthropic/claude-sonnet-4-6`.
|
||||
runs use `openai/gpt-5.6-sol`; Claude runs use `anthropic/claude-sonnet-4-6`.
|
||||
- **Open Codex** / **Open Claude** creates a linked dashboard session without
|
||||
sending the card prompt or moving the card, for manual work that stays
|
||||
attached to the board.
|
||||
|
||||
@@ -315,7 +315,7 @@ Stable and full validation always run the exhaustive live/E2E, Docker release-pa
|
||||
|
||||
`OpenClaw Release Checks` uses the trusted workflow ref to resolve the target ref once as `release-package-under-test` and reuses that artifact in cross-OS, Package Acceptance, and release-path Docker checks when soak runs. This keeps all package-facing boxes on the same bytes and avoids repeated package builds. After a beta is already on npm, set `release_package_spec=openclaw@YYYY.M.PATCH-beta.N` so release checks download the shipped package once, extract its build source SHA from `dist/build-info.json`, and reuse that artifact for cross-OS, Package Acceptance, release-path Docker, and package Telegram lanes.
|
||||
|
||||
The cross-OS OpenAI install smoke uses `OPENCLAW_CROSS_OS_OPENAI_MODEL` when the repo/org variable is set, otherwise `openai/gpt-5.5`, because this lane is proving package install, onboarding, gateway startup, and one live agent turn rather than benchmarking the slowest default model. The broader live provider matrix remains the place for model-specific coverage.
|
||||
The cross-OS OpenAI install smoke uses `OPENCLAW_CROSS_OS_OPENAI_MODEL` when the repo/org variable is set, otherwise `openai/gpt-5.6-luna`, because this lane is proving package install, onboarding, gateway startup, and one live agent turn rather than benchmarking the most capable model. The broader live provider matrix remains the place for model-specific coverage.
|
||||
|
||||
Use these variants depending on release stage:
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ Use this reference page for flag semantics and step ordering.
|
||||
```bash
|
||||
openclaw agents add work \
|
||||
--workspace ~/.openclaw/workspace-work \
|
||||
--model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-sol \
|
||||
--bind whatsapp:biz \
|
||||
--non-interactive \
|
||||
--json
|
||||
|
||||
@@ -183,7 +183,7 @@ Anthropic setup-token auth remains supported, but OpenClaw prefers Claude CLI re
|
||||
```bash
|
||||
openclaw agents add work \
|
||||
--workspace ~/.openclaw/workspace-work \
|
||||
--model openai/gpt-5.5 \
|
||||
--model openai/gpt-5.6-sol \
|
||||
--bind whatsapp:biz \
|
||||
--non-interactive \
|
||||
--json
|
||||
|
||||
+1
-1
@@ -244,7 +244,7 @@ Paste (bracketed by default):
|
||||
{
|
||||
tools: {
|
||||
exec: {
|
||||
applyPatch: { workspaceOnly: true, allowModels: ["gpt-5.5"] },
|
||||
applyPatch: { workspaceOnly: true, allowModels: ["gpt-5.6-sol"] },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ allowlist mode instead.
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"defaultProvider": "openai",
|
||||
"defaultModel": "gpt-5.5",
|
||||
"defaultModel": "gpt-5.6-sol",
|
||||
"defaultAuthProfileId": "main",
|
||||
"allowedModels": ["openai/gpt-5.5"],
|
||||
"allowedModels": ["openai/gpt-5.6-sol"],
|
||||
"maxTokens": 800,
|
||||
"timeoutMs": 30000
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ improves subsequent results. Max 1000 chars on `parallel`; the free
|
||||
|
||||
<ParamField path="client_model" type="string">
|
||||
Optional identifier of the model making the call (e.g. `claude-opus-4-7`,
|
||||
`gpt-5.5`), max 100 chars. Lets Parallel tailor default settings for your
|
||||
`gpt-5.6-sol`), max 100 chars. Lets Parallel tailor default settings for your
|
||||
model's capabilities. Pass the exact active model slug; do not shorten to a
|
||||
family alias.
|
||||
</ParamField>
|
||||
|
||||
@@ -20,16 +20,16 @@ const MODELS = {
|
||||
maxTokens: 8192,
|
||||
},
|
||||
openai: {
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
id: "gpt-5.6-sol",
|
||||
name: "GPT-5.6 Sol",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
||||
contextWindow: 400_000,
|
||||
maxTokens: 16_384,
|
||||
cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 },
|
||||
contextWindow: 1_050_000,
|
||||
maxTokens: 128_000,
|
||||
},
|
||||
// Local Ollama server; no API key required.
|
||||
ollama: {
|
||||
|
||||
@@ -106,7 +106,7 @@ describe("codex plugin", () => {
|
||||
expect(typeof agentHarnessRegistration.dispose).toBe("function");
|
||||
expect(mediaProviderRegistration?.id).toBe("codex");
|
||||
expect(mediaProviderRegistration?.capabilities).toEqual(["image"]);
|
||||
expect(mediaProviderRegistration?.defaultModels).toEqual({ image: "gpt-5.5" });
|
||||
expect(mediaProviderRegistration?.defaultModels).toEqual({ image: "gpt-5.6-sol" });
|
||||
expect(typeof mediaProviderRegistration?.describeImage).toBe("function");
|
||||
expect(typeof mediaProviderRegistration?.describeImages).toBe("function");
|
||||
const webSearchRegistration = mockCallArg(registerWebSearchProvider) as
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"codex": {
|
||||
"capabilities": ["image"],
|
||||
"defaultModels": {
|
||||
"image": "gpt-5.5"
|
||||
"image": "gpt-5.6-sol"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -16,15 +16,38 @@ export const CODEX_APP_SERVER_AUTH_MARKER = "codex-app-server";
|
||||
|
||||
const DEFAULT_CONTEXT_WINDOW = 272_000;
|
||||
const DEFAULT_MAX_TOKENS = 128_000;
|
||||
const KNOWN_CONTEXT_WINDOW_BY_MODEL_ID: Readonly<Record<string, number>> = Object.freeze({
|
||||
"gpt-5.6-sol": 372_000,
|
||||
"gpt-5.6-terra": 372_000,
|
||||
"gpt-5.6-luna": 372_000,
|
||||
});
|
||||
|
||||
/** Offline fallback catalog used when live app-server discovery is unavailable. */
|
||||
export const FALLBACK_CODEX_MODELS = [
|
||||
{
|
||||
id: "gpt-5.5",
|
||||
model: "gpt-5.5",
|
||||
displayName: "gpt-5.5",
|
||||
id: "gpt-5.6-sol",
|
||||
model: "gpt-5.6-sol",
|
||||
displayName: "GPT-5.6 Sol",
|
||||
description: "Latest frontier agentic coding model.",
|
||||
isDefault: true,
|
||||
contextWindow: 372_000,
|
||||
inputModalities: ["text", "image"],
|
||||
supportedReasoningEfforts: ["low", "medium", "high", "xhigh", "max", "ultra"],
|
||||
},
|
||||
{
|
||||
id: "gpt-5.6-luna",
|
||||
model: "gpt-5.6-luna",
|
||||
displayName: "GPT-5.6 Luna",
|
||||
description: "High-throughput frontier agentic coding model.",
|
||||
contextWindow: 372_000,
|
||||
inputModalities: ["text", "image"],
|
||||
supportedReasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
||||
},
|
||||
{
|
||||
id: "gpt-5.5",
|
||||
model: "gpt-5.5",
|
||||
displayName: "GPT-5.5",
|
||||
description: "Previous frontier agentic coding model.",
|
||||
inputModalities: ["text", "image"],
|
||||
supportedReasoningEfforts: ["low", "medium", "high", "xhigh"],
|
||||
},
|
||||
@@ -36,7 +59,7 @@ export const FALLBACK_CODEX_MODELS = [
|
||||
inputModalities: ["text", "image"],
|
||||
supportedReasoningEfforts: ["low", "medium", "high", "xhigh"],
|
||||
},
|
||||
] satisfies CodexAppServerModel[];
|
||||
] satisfies Array<CodexAppServerModel & { contextWindow?: number }>;
|
||||
|
||||
/**
|
||||
* Converts a Codex app-server model record into OpenClaw provider model config.
|
||||
@@ -45,6 +68,7 @@ export function buildCodexModelDefinition(model: {
|
||||
id: string;
|
||||
model: string;
|
||||
displayName?: string;
|
||||
contextWindow?: number;
|
||||
inputModalities: string[];
|
||||
supportedReasoningEfforts?: string[];
|
||||
}): ModelDefinitionConfig {
|
||||
@@ -60,7 +84,8 @@ export function buildCodexModelDefinition(model: {
|
||||
: shouldDefaultToReasoningModel(id),
|
||||
input: model.inputModalities.includes("image") ? ["text", "image"] : ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||
contextWindow:
|
||||
model.contextWindow ?? KNOWN_CONTEXT_WINDOW_BY_MODEL_ID[id] ?? DEFAULT_CONTEXT_WINDOW,
|
||||
maxTokens: DEFAULT_MAX_TOKENS,
|
||||
compat: {
|
||||
...(supportedReasoningEfforts !== undefined
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Codex tests cover provider plugin behavior.
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { CODEX_GPT5_BEHAVIOR_CONTRACT } from "./prompt-overlay.js";
|
||||
import { buildCodexModelDefinition } from "./provider-catalog.js";
|
||||
import { codexProviderDiscovery } from "./provider-discovery.js";
|
||||
import {
|
||||
buildCodexProvider,
|
||||
@@ -23,7 +24,12 @@ afterEach(() => {
|
||||
function expectStaticFallbackCatalog(
|
||||
result: Awaited<ReturnType<typeof buildCodexProviderCatalog>>,
|
||||
) {
|
||||
expect(result.provider.models.map((model) => model.id)).toEqual(["gpt-5.5", "gpt-5.4-mini"]);
|
||||
expect(result.provider.models.map((model) => model.id)).toEqual([
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-luna",
|
||||
"gpt-5.5",
|
||||
"gpt-5.4-mini",
|
||||
]);
|
||||
}
|
||||
|
||||
function createFakeCodexClient(): CodexAppServerClient {
|
||||
@@ -84,6 +90,19 @@ function mockCallArg(mockFn: { mock: { calls: unknown[][] } }, callIndex: number
|
||||
}
|
||||
|
||||
describe("codex provider", () => {
|
||||
it.each(["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"])(
|
||||
"uses the known context window for discovered %s models",
|
||||
(modelId) => {
|
||||
const model = buildCodexModelDefinition({
|
||||
id: modelId,
|
||||
model: modelId,
|
||||
inputModalities: ["text", "image"],
|
||||
});
|
||||
|
||||
expect(model.contextWindow).toBe(372_000);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(["gpt-5.5-pro", "gpt-5.4-pro"] as const)(
|
||||
"classifies %s as a modern Codex model",
|
||||
(modelId) => {
|
||||
@@ -377,7 +396,7 @@ describe("codex provider", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps undiscovered GPT-5.6 models on family reasoning rules", () => {
|
||||
it("uses fallback reasoning metadata for GPT-5.6 Luna", () => {
|
||||
const provider = buildCodexProvider();
|
||||
const model = provider.resolveDynamicModel?.({
|
||||
provider: "codex",
|
||||
@@ -388,7 +407,12 @@ describe("codex provider", () => {
|
||||
expectRecordFields(model, {
|
||||
id: "gpt-5.6-luna",
|
||||
reasoning: true,
|
||||
compat: { supportsUsageInStreaming: true },
|
||||
contextWindow: 372_000,
|
||||
compat: {
|
||||
supportsReasoningEffort: true,
|
||||
supportedReasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
||||
supportsUsageInStreaming: true,
|
||||
},
|
||||
});
|
||||
expect(
|
||||
provider
|
||||
@@ -639,7 +663,7 @@ describe("codex provider", () => {
|
||||
const authResult = await authChoice?.run({} as never);
|
||||
expectRecordFields(authResult, {
|
||||
profiles: [],
|
||||
defaultModel: "codex/gpt-5.5",
|
||||
defaultModel: "codex/gpt-5.6-sol",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -657,9 +681,15 @@ describe("codex provider", () => {
|
||||
agentDir: "/tmp/openclaw-agent",
|
||||
} as never);
|
||||
|
||||
expect(
|
||||
result && "provider" in result ? result.provider.models.map((model) => model.id) : [],
|
||||
).toEqual(["gpt-5.5", "gpt-5.4-mini"]);
|
||||
const models = result && "provider" in result ? result.provider.models : [];
|
||||
expect(models.map((model) => model.id)).toEqual([
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-luna",
|
||||
"gpt-5.5",
|
||||
"gpt-5.4-mini",
|
||||
]);
|
||||
expect(models.find((model) => model.id === "gpt-5.6-sol")?.contextWindow).toBe(372_000);
|
||||
expect(models.find((model) => model.id === "gpt-5.6-luna")?.contextWindow).toBe(372_000);
|
||||
});
|
||||
|
||||
it("adds the GPT-5 prompt overlay to Codex provider runs", () => {
|
||||
|
||||
@@ -212,7 +212,7 @@ export const discordChannelConfigUiHints = {
|
||||
},
|
||||
"voice.model": {
|
||||
label: "Discord Voice Model",
|
||||
help: "Optional LLM model override for Discord voice channel responses and realtime agent consults (for example openai/gpt-5.5). Leave unset to inherit the routed agent model.",
|
||||
help: "Optional LLM model override for Discord voice channel responses and realtime agent consults (for example openai/gpt-5.6-sol). Leave unset to inherit the routed agent model.",
|
||||
},
|
||||
"voice.mode": {
|
||||
label: "Discord Voice Mode",
|
||||
|
||||
@@ -45,9 +45,9 @@ Designed to be called from workflow engines (for example, Lobster via
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"defaultProvider": "openai",
|
||||
"defaultModel": "gpt-5.5",
|
||||
"defaultModel": "gpt-5.6-sol",
|
||||
"defaultAuthProfileId": "main",
|
||||
"allowedModels": ["openai/gpt-5.5"],
|
||||
"allowedModels": ["openai/gpt-5.6-sol"],
|
||||
"maxTokens": 800,
|
||||
"timeoutMs": 30000
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default defineToolPlugin({
|
||||
defaultAuthProfileId: Type.Optional(Type.String()),
|
||||
allowedModels: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description: "Allowlist of provider/model keys like openai/gpt-5.5.",
|
||||
description: "Allowlist of provider/model keys like openai/gpt-5.6-sol.",
|
||||
}),
|
||||
),
|
||||
maxTokens: optionalPositiveIntegerSchema(),
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"visionModel": {
|
||||
"label": "Vision Model",
|
||||
"placeholder": "codex/gpt-5.5",
|
||||
"placeholder": "codex/gpt-5.6-sol",
|
||||
"help": "provider/model used to read snapshots; the provider must support structured extraction (the bundled Codex plugin does). Defaults to the first image-capable Codex entry under tools.media."
|
||||
},
|
||||
"captureEnabled": {
|
||||
|
||||
@@ -1021,7 +1021,7 @@ describe("openai image generation provider", () => {
|
||||
const body = request.body as Record<string, unknown>;
|
||||
expect(request.url).toBe("https://chatgpt.com/backend-api/codex/responses");
|
||||
expect(request.timeoutMs).toBe(180_000);
|
||||
expect(body.model).toBe("gpt-5.5");
|
||||
expect(body.model).toBe("gpt-5.6-sol");
|
||||
expect(body.instructions).toBe("You are an image generation assistant.");
|
||||
expect(body.stream).toBe(true);
|
||||
expect(body.store).toBe(false);
|
||||
@@ -1039,7 +1039,7 @@ describe("openai image generation provider", () => {
|
||||
expect(body.tool_choice).toEqual({ type: "image_generation" });
|
||||
expect(postMultipartRequestMock).not.toHaveBeenCalled();
|
||||
expect(logInfoMock).toHaveBeenCalledWith(
|
||||
"image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.5 timeoutMs=180000",
|
||||
"image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.6-sol timeoutMs=180000",
|
||||
);
|
||||
expect(result.images).toEqual([
|
||||
{
|
||||
@@ -1356,7 +1356,7 @@ describe("openai image generation provider", () => {
|
||||
expect(authResolutionCall().store).toBe(authStore);
|
||||
expect(jsonRequestCall().url).toBe("https://chatgpt.com/backend-api/codex/responses");
|
||||
expect(logInfoMock).toHaveBeenCalledWith(
|
||||
"image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.5 timeoutMs=180000",
|
||||
"image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=gpt-image-2 responsesModel=gpt-5.6-sol timeoutMs=180000",
|
||||
);
|
||||
expect(result.images[0]?.buffer).toEqual(Buffer.from("codex-image"));
|
||||
});
|
||||
@@ -1506,7 +1506,7 @@ describe("openai image generation provider", () => {
|
||||
});
|
||||
|
||||
expect(logInfoMock).toHaveBeenCalledWith(
|
||||
"image auth selected: provider=openai mode=oauth fakeignored transport=codex-responses requestedModel=gpt-image-2 forged=true next responsesModel=gpt-5.5 timeoutMs=180000",
|
||||
"image auth selected: provider=openai mode=oauth fakeignored transport=codex-responses requestedModel=gpt-image-2 forged=true next responsesModel=gpt-5.6-sol timeoutMs=180000",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1524,7 +1524,7 @@ describe("openai image generation provider", () => {
|
||||
});
|
||||
|
||||
expect(logInfoMock).toHaveBeenCalledWith(
|
||||
`image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=${"a".repeat(255)}... responsesModel=gpt-5.5 timeoutMs=180000`,
|
||||
`image auth selected: provider=openai mode=oauth transport=codex-responses requestedModel=${"a".repeat(255)}... responsesModel=gpt-5.6-sol timeoutMs=180000`,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import { resolveConfiguredOpenAIBaseUrl } from "./shared.js";
|
||||
|
||||
const DEFAULT_OPENAI_IMAGE_BASE_URL = "https://api.openai.com/v1";
|
||||
const DEFAULT_OPENAI_CODEX_IMAGE_BASE_URL = OPENAI_CODEX_RESPONSES_BASE_URL;
|
||||
const DEFAULT_OPENAI_CODEX_IMAGE_RESPONSES_MODEL = "gpt-5.5";
|
||||
const DEFAULT_OPENAI_CODEX_IMAGE_RESPONSES_MODEL = "gpt-5.6-sol";
|
||||
const OPENAI_CODEX_IMAGE_INSTRUCTIONS = "You are an image generation assistant.";
|
||||
const OPENAI_TRANSPARENT_BACKGROUND_IMAGE_MODEL = "gpt-image-1.5";
|
||||
const DEFAULT_OPENAI_IMAGE_TIMEOUT_MS = 180_000;
|
||||
|
||||
@@ -16,7 +16,7 @@ describe("openaiMediaUnderstandingProvider", () => {
|
||||
it("declares audio support with the transcription default", () => {
|
||||
expect(openaiMediaUnderstandingProvider.capabilities).toEqual(["image", "audio"]);
|
||||
expect(openaiMediaUnderstandingProvider.defaultModels).toEqual({
|
||||
image: "gpt-5.5",
|
||||
image: "gpt-5.6-sol",
|
||||
audio: "gpt-4o-transcribe",
|
||||
});
|
||||
expect(openaiMediaUnderstandingProvider.autoPriority).toEqual({ image: 20, audio: 20 });
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function transcribeOpenAiAudio(params: AudioTranscriptionRequest) {
|
||||
export const openaiMediaUnderstandingProvider: MediaUnderstandingProvider = {
|
||||
id: "openai",
|
||||
capabilities: ["image", "audio"],
|
||||
defaultModels: { image: "gpt-5.5", audio: OPENAI_DEFAULT_AUDIO_TRANSCRIPTION_MODEL },
|
||||
defaultModels: { image: "gpt-5.6-sol", audio: OPENAI_DEFAULT_AUDIO_TRANSCRIPTION_MODEL },
|
||||
autoPriority: { image: 20, audio: 20 },
|
||||
describeImage: describeImageWithModel,
|
||||
describeImages: describeImagesWithModel,
|
||||
|
||||
@@ -22,7 +22,7 @@ import { describe, expect, it } from "vitest";
|
||||
import plugin from "./index.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
|
||||
const LIVE_MODEL_ID = process.env.OPENCLAW_LIVE_OPENAI_PLUGIN_MODEL?.trim() || "gpt-5.5";
|
||||
const LIVE_MODEL_ID = process.env.OPENCLAW_LIVE_OPENAI_PLUGIN_MODEL?.trim() || "gpt-5.6-luna";
|
||||
const LIVE_IMAGE_MODEL = process.env.OPENCLAW_LIVE_OPENAI_IMAGE_MODEL?.trim() || "gpt-image-2";
|
||||
const LIVE_VISION_MODEL = process.env.OPENCLAW_LIVE_OPENAI_VISION_MODEL?.trim() || "gpt-5.4-mini";
|
||||
const liveEnabled = OPENAI_API_KEY.trim().length > 0 && process.env.OPENCLAW_LIVE_TEST === "1";
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
"openai": {
|
||||
"capabilities": ["image", "audio"],
|
||||
"defaultModels": {
|
||||
"image": "gpt-5.5",
|
||||
"image": "gpt-5.6-sol",
|
||||
"audio": "gpt-4o-transcribe"
|
||||
},
|
||||
"autoPriority": {
|
||||
|
||||
@@ -144,7 +144,7 @@ describe("OpenAI plugin manifest", () => {
|
||||
it("keeps OpenAI media-understanding manifest metadata aligned with runtime audio support", () => {
|
||||
const metadata = manifest.mediaUnderstandingProviderMetadata?.openai;
|
||||
expect(metadata?.capabilities).toEqual(["image", "audio"]);
|
||||
expect(metadata?.defaultModels?.image).toBe("gpt-5.5");
|
||||
expect(metadata?.defaultModels?.image).toBe("gpt-5.6-sol");
|
||||
expect(metadata?.defaultModels?.audio).toBe("gpt-4o-transcribe");
|
||||
expect(metadata?.autoPriority?.image).toBe(20);
|
||||
expect(metadata?.autoPriority?.audio).toBe(20);
|
||||
|
||||
@@ -47,7 +47,7 @@ export const ParallelSearchSchema = {
|
||||
client_model: {
|
||||
type: "string",
|
||||
description:
|
||||
"The identifier of the LLM model making this tool call (e.g. 'claude-opus-4-7', 'gpt-5.5', 'gemini-3.1-pro'). Pass the exact active model slug verbatim; never shorten or substitute a family alias like 'gpt-5'. Lets Parallel tailor default settings for your model's capabilities.",
|
||||
"The identifier of the LLM model making this tool call (e.g. 'claude-opus-4-7', 'gpt-5.6-sol', 'gemini-3.1-pro'). Pass the exact active model slug verbatim; never shorten or substitute a family alias like 'gpt-5'. Lets Parallel tailor default settings for your model's capabilities.",
|
||||
maxLength: PARALLEL_MAX_CLIENT_MODEL_CHARS,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -103,7 +103,7 @@ function makeRuntimeParitySummary(): QaRuntimeParitySuiteSummary {
|
||||
},
|
||||
run: {
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
runtimePair: ["openclaw", "codex"],
|
||||
},
|
||||
};
|
||||
@@ -233,7 +233,7 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
it("fails the parity gate when the candidate regresses against baseline", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: [
|
||||
@@ -262,10 +262,10 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"openai/gpt-5.5 completion rate 80.0% is below anthropic/claude-opus-4-8 100.0%.",
|
||||
"openai/gpt-5.6-luna completion rate 80.0% is below anthropic/claude-opus-4-8 100.0%.",
|
||||
);
|
||||
expect(comparison.failures).toContain(
|
||||
"openai/gpt-5.5 unintended-stop rate 20.0% exceeds anthropic/claude-opus-4-8 0.0%.",
|
||||
"openai/gpt-5.6-luna unintended-stop rate 20.0% exceeds anthropic/claude-opus-4-8 0.0%.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -280,7 +280,7 @@ describe("qa agentic parity report", () => {
|
||||
passScenario("Extra non-parity lane"),
|
||||
];
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: baselineScenarios.filter(
|
||||
@@ -293,13 +293,13 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"Scenario coverage mismatch for Extra non-parity lane: openai/gpt-5.5=missing, anthropic/claude-opus-4-8=pass.",
|
||||
"Scenario coverage mismatch for Extra non-parity lane: openai/gpt-5.6-luna=missing, anthropic/claude-opus-4-8=pass.",
|
||||
);
|
||||
});
|
||||
|
||||
it("reports each missing required parity scenario exactly once (no double-counting)", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: [{ name: "Approval turn tool followthrough", status: "pass" }],
|
||||
@@ -341,7 +341,7 @@ describe("qa agentic parity report", () => {
|
||||
};
|
||||
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: summaryWithExtras,
|
||||
baselineSummary: scopedSummary,
|
||||
@@ -363,7 +363,7 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
it("fails the parity gate when required parity scenarios are missing on both sides", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: [{ name: "Approval turn tool followthrough", status: "pass" }],
|
||||
@@ -376,13 +376,13 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"Missing required parity scenario coverage for Image understanding from attachment: openai/gpt-5.5=missing, anthropic/claude-opus-4-8=missing.",
|
||||
"Missing required parity scenario coverage for Image understanding from attachment: openai/gpt-5.6-luna=missing, anthropic/claude-opus-4-8=missing.",
|
||||
);
|
||||
});
|
||||
|
||||
it("fails the parity gate when required parity scenarios are skipped", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: [
|
||||
@@ -407,7 +407,7 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"Missing required parity scenario coverage for Compaction retry after mutating tool: openai/gpt-5.5=skip, anthropic/claude-opus-4-8=skip.",
|
||||
"Missing required parity scenario coverage for Compaction retry after mutating tool: openai/gpt-5.6-luna=skip, anthropic/claude-opus-4-8=skip.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -423,7 +423,7 @@ describe("qa agentic parity report", () => {
|
||||
status: "fail",
|
||||
});
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: { scenarios: scenariosWithBothFail },
|
||||
baselineSummary: { scenarios: scenariosWithBothFail },
|
||||
@@ -432,7 +432,7 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"Required parity scenario Approval turn tool followthrough failed: openai/gpt-5.5=fail, anthropic/claude-opus-4-8=fail.",
|
||||
"Required parity scenario Approval turn tool followthrough failed: openai/gpt-5.6-luna=fail, anthropic/claude-opus-4-8=fail.",
|
||||
);
|
||||
// Metric comparisons are relative, so a same-on-both-sides failure
|
||||
// must not appear as a relative metric failure. The required-scenario
|
||||
@@ -451,7 +451,7 @@ describe("qa agentic parity report", () => {
|
||||
status: "fail",
|
||||
});
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: { scenarios: candidateWithOneFail },
|
||||
baselineSummary: { scenarios: FULL_PARITY_PASS_SCENARIOS },
|
||||
@@ -460,7 +460,7 @@ describe("qa agentic parity report", () => {
|
||||
|
||||
expect(comparison.pass).toBe(false);
|
||||
expect(comparison.failures).toContain(
|
||||
"Required parity scenario Approval turn tool followthrough failed: openai/gpt-5.5=fail, anthropic/claude-opus-4-8=pass.",
|
||||
"Required parity scenario Approval turn tool followthrough failed: openai/gpt-5.6-luna=fail, anthropic/claude-opus-4-8=pass.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -468,7 +468,7 @@ describe("qa agentic parity report", () => {
|
||||
// Cover the full second-wave pack on both sides so the suspicious-pass assertion
|
||||
// below is the isolated gate failure under test (no coverage-gap noise).
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
@@ -652,7 +652,7 @@ status=done`,
|
||||
|
||||
expect(() =>
|
||||
buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: parityPassScenarios,
|
||||
@@ -674,7 +674,7 @@ status=done`,
|
||||
|
||||
expect(() =>
|
||||
buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: parityPassScenarios,
|
||||
@@ -682,25 +682,25 @@ status=done`,
|
||||
},
|
||||
baselineSummary: {
|
||||
scenarios: parityPassScenarios,
|
||||
run: { primaryProvider: "openai", primaryModel: "gpt-5.5" },
|
||||
run: { primaryProvider: "openai", primaryModel: "gpt-5.6-luna" },
|
||||
},
|
||||
comparedAt: "2026-04-11T00:00:00.000Z",
|
||||
}),
|
||||
).toThrow(
|
||||
/baseline summary run\.primaryProvider=openai and run\.primaryModel=gpt-5\.5 do not match --baseline-label/,
|
||||
/baseline summary run\.primaryProvider=openai and run\.primaryModel=gpt-5\.6-luna do not match --baseline-label/,
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts matching run.primaryProvider labels without throwing", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
run: {
|
||||
primaryProvider: "openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModelName: "gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
primaryModelName: "gpt-5.6-luna",
|
||||
},
|
||||
},
|
||||
baselineSummary: {
|
||||
@@ -720,7 +720,7 @@ status=done`,
|
||||
// Pre-PR-L summaries don't carry a `run` block. The gate must still
|
||||
// work against those, trusting the caller-supplied label.
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: { scenarios: FULL_PARITY_PASS_SCENARIOS },
|
||||
baselineSummary: { scenarios: FULL_PARITY_PASS_SCENARIOS },
|
||||
@@ -731,14 +731,14 @@ status=done`,
|
||||
|
||||
it("skips provider verification for arbitrary display labels when run metadata is present", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "GPT-5.5 candidate",
|
||||
candidateLabel: "GPT-5.6 Luna candidate",
|
||||
baselineLabel: "Opus 4.8 baseline",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
run: {
|
||||
primaryProvider: "openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModelName: "gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
primaryModelName: "gpt-5.6-luna",
|
||||
},
|
||||
},
|
||||
baselineSummary: {
|
||||
@@ -757,14 +757,14 @@ status=done`,
|
||||
|
||||
it("skips provider verification for mixed-case or decorated display labels", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "Candidate: GPT-5.5",
|
||||
candidateLabel: "Candidate: GPT-5.6 Luna",
|
||||
baselineLabel: "Opus 4.8 / baseline",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
run: {
|
||||
primaryProvider: "openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModelName: "gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
primaryModelName: "gpt-5.6-luna",
|
||||
},
|
||||
},
|
||||
baselineSummary: {
|
||||
@@ -784,14 +784,14 @@ status=done`,
|
||||
it("throws when a structured label mismatches the recorded model even if the provider matches", () => {
|
||||
expect(() =>
|
||||
buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
run: {
|
||||
primaryProvider: "openai",
|
||||
primaryModel: "openai/gpt-5.5-alt",
|
||||
primaryModelName: "gpt-5.5-alt",
|
||||
primaryModel: "openai/gpt-5.6-luna-alt",
|
||||
primaryModelName: "gpt-5.6-luna-alt",
|
||||
},
|
||||
},
|
||||
baselineSummary: {
|
||||
@@ -805,20 +805,20 @@ status=done`,
|
||||
comparedAt: "2026-04-11T00:00:00.000Z",
|
||||
}),
|
||||
).toThrow(
|
||||
/candidate summary run\.primaryProvider=openai and run\.primaryModel=openai\/gpt-5\.5-alt do not match --candidate-label=openai\/gpt-5\.5/,
|
||||
/candidate summary run\.primaryProvider=openai and run\.primaryModel=openai\/gpt-5\.6-luna-alt do not match --candidate-label=openai\/gpt-5\.6-luna/,
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts colon-delimited structured labels when provider and model both match", () => {
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai:gpt-5.5",
|
||||
candidateLabel: "openai:gpt-5.6-luna",
|
||||
baselineLabel: "anthropic:claude-opus-4-8",
|
||||
candidateSummary: {
|
||||
scenarios: FULL_PARITY_PASS_SCENARIOS,
|
||||
run: {
|
||||
primaryProvider: "openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModelName: "gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
primaryModelName: "gpt-5.6-luna",
|
||||
},
|
||||
},
|
||||
baselineSummary: {
|
||||
@@ -840,7 +840,7 @@ status=done`,
|
||||
// verdict is not disrupted by required-scenario coverage failures
|
||||
// added by the second-wave expansion.
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna",
|
||||
baselineLabel: "anthropic/claude-opus-4-8",
|
||||
candidateSummary: { scenarios: FULL_PARITY_PASS_SCENARIOS },
|
||||
baselineSummary: { scenarios: FULL_PARITY_PASS_SCENARIOS },
|
||||
@@ -850,7 +850,7 @@ status=done`,
|
||||
const report = renderQaAgenticParityMarkdownReport(comparison);
|
||||
|
||||
expect(report).toContain(
|
||||
"# OpenClaw Agentic Parity Report — openai/gpt-5.5 vs anthropic/claude-opus-4-8",
|
||||
"# OpenClaw Agentic Parity Report — openai/gpt-5.6-luna vs anthropic/claude-opus-4-8",
|
||||
);
|
||||
expect(report).toContain("| Completion rate | 100.0% | 100.0% |");
|
||||
expect(report).toContain("### Approval turn tool followthrough");
|
||||
@@ -859,20 +859,20 @@ status=done`,
|
||||
|
||||
it("parametrizes the markdown header from the comparison labels", () => {
|
||||
// Regression for the loop-7 Copilot finding: callers that configure
|
||||
// non-gpt-5.5 / non-opus labels (for example an internal candidate vs
|
||||
// non-gpt-5.6-luna / non-opus labels (for example an internal candidate vs
|
||||
// another candidate) must see the labels in the rendered H1 instead of
|
||||
// the hardcoded "GPT-5.5 / Opus 4.8" title that would otherwise confuse
|
||||
// the hardcoded "GPT-5.6 Luna / Opus 4.8" title that would otherwise confuse
|
||||
// readers of saved reports.
|
||||
const comparison = buildQaAgenticParityComparison({
|
||||
candidateLabel: "openai/gpt-5.5-alt",
|
||||
baselineLabel: "openai/gpt-5.5",
|
||||
candidateLabel: "openai/gpt-5.6-luna-alt",
|
||||
baselineLabel: "openai/gpt-5.6-luna",
|
||||
candidateSummary: { scenarios: [] },
|
||||
baselineSummary: { scenarios: [] },
|
||||
comparedAt: "2026-04-11T00:00:00.000Z",
|
||||
});
|
||||
const report = renderQaAgenticParityMarkdownReport(comparison);
|
||||
expect(report).toContain(
|
||||
"# OpenClaw Agentic Parity Report — openai/gpt-5.5-alt vs openai/gpt-5.5",
|
||||
"# OpenClaw Agentic Parity Report — openai/gpt-5.6-luna-alt vs openai/gpt-5.6-luna",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ type StructuredQaParityLabel = {
|
||||
/**
|
||||
* Only treat caller labels as provenance-checked identifiers when they are
|
||||
* exact lower-case provider/model refs. Human-facing display labels like
|
||||
* "GPT-5.5 candidate" or "Candidate: GPT-5.5" should render in the report
|
||||
* "GPT-5.6 Luna candidate" or "Candidate: GPT-5.6 Luna" should render in the report
|
||||
* without being misread as structured provider ids.
|
||||
*/
|
||||
function parseStructuredLabelRef(label: string): StructuredQaParityLabel | null {
|
||||
@@ -591,9 +591,9 @@ export function buildQaAgenticParityComparison(params: {
|
||||
|
||||
export function renderQaAgenticParityMarkdownReport(comparison: QaAgenticParityComparison): string {
|
||||
// Title is parametrized from the candidate / baseline labels so reports
|
||||
// for any candidate/baseline pair (not only gpt-5.5 vs opus 4.6) render
|
||||
// for any candidate/baseline pair (not only gpt-5.6-luna vs opus 4.6) render
|
||||
// with an accurate header. The default CLI labels are still
|
||||
// openai/gpt-5.5 vs anthropic/claude-opus-4-8, but the helper works for
|
||||
// openai/gpt-5.6-luna vs anthropic/claude-opus-4-8, but the helper works for
|
||||
// any parity comparison a caller configures.
|
||||
const lines = [
|
||||
`# OpenClaw Agentic Parity Report — ${comparison.candidateLabel} vs ${comparison.baselineLabel}`,
|
||||
|
||||
@@ -193,7 +193,7 @@ describe("runQaCharacterEval", () => {
|
||||
});
|
||||
const runJudge = makeRunJudge([
|
||||
{
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
rank: 1,
|
||||
score: 9.1,
|
||||
summary: "Most natural.",
|
||||
@@ -213,10 +213,10 @@ describe("runQaCharacterEval", () => {
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "codex-cli/test-model", "openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna", "codex-cli/test-model", "openai/gpt-5.6-luna"],
|
||||
scenarioId: "character-vibes-gollum",
|
||||
candidateFastMode: true,
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -224,28 +224,28 @@ describe("runQaCharacterEval", () => {
|
||||
expect(runSuite).toHaveBeenCalledTimes(2);
|
||||
const firstRunParams = requireRunSuiteParams(runSuite);
|
||||
expect(firstRunParams.providerMode).toBe("live-frontier");
|
||||
expect(firstRunParams.primaryModel).toBe("openai/gpt-5.5");
|
||||
expect(firstRunParams.alternateModel).toBe("openai/gpt-5.5");
|
||||
expect(firstRunParams.primaryModel).toBe("openai/gpt-5.6-luna");
|
||||
expect(firstRunParams.alternateModel).toBe("openai/gpt-5.6-luna");
|
||||
expect(firstRunParams.fastMode).toBe(true);
|
||||
expect(firstRunParams.scenarioIds).toEqual(["character-vibes-gollum"]);
|
||||
const judgeParams = requireRunJudgeParams(runJudge);
|
||||
expect(judgeParams.judgeModel).toBe("openai/gpt-5.5");
|
||||
expect(judgeParams.judgeModel).toBe("openai/gpt-5.6-luna");
|
||||
expect(judgeParams.judgeThinkingDefault).toBe("xhigh");
|
||||
expect(judgeParams.judgeFastMode).toBe(true);
|
||||
expect(judgeParams.judgeFastMode).toBe(false);
|
||||
expect(judgeParams.timeoutMs).toBe(300_000);
|
||||
expect(result.judgments).toHaveLength(1);
|
||||
expect(result.judgments[0]?.rankings.map((ranking) => ranking.model)).toEqual([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"codex-cli/test-model",
|
||||
]);
|
||||
|
||||
const report = await fs.readFile(result.reportPath, "utf8");
|
||||
expect(report).toContain("Execution: local QA gateway child processes, not Docker");
|
||||
expect(report).toContain("Judges: openai/gpt-5.5");
|
||||
expect(report).toContain("Judges: openai/gpt-5.6-luna");
|
||||
expect(report).toContain("Judge model labels: visible");
|
||||
expect(report).toContain("## Judge Rankings");
|
||||
expect(report).toContain("### openai/gpt-5.5");
|
||||
expect(report).toContain("reply from openai/gpt-5.5");
|
||||
expect(report).toContain("### openai/gpt-5.6-luna");
|
||||
expect(report).toContain("reply from openai/gpt-5.6-luna");
|
||||
expect(report).toContain("reply from codex-cli/test-model");
|
||||
expect(report).toContain("Judge thinking: xhigh");
|
||||
expect(report).toContain("- Timeout: 5m");
|
||||
@@ -265,7 +265,7 @@ describe("runQaCharacterEval", () => {
|
||||
);
|
||||
const runJudge = makeRunJudge([
|
||||
{
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
rank: 1,
|
||||
score: 8,
|
||||
summary: "solid",
|
||||
@@ -276,7 +276,7 @@ describe("runQaCharacterEval", () => {
|
||||
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
models: ["openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -297,7 +297,7 @@ describe("runQaCharacterEval", () => {
|
||||
const runJudge = vi.fn(async (params: CharacterRunJudgeParams) => {
|
||||
expect(params.prompt).toContain("## CANDIDATE candidate-01");
|
||||
expect(params.prompt).toContain("## CANDIDATE candidate-02");
|
||||
expect(params.prompt).not.toContain("openai/gpt-5.5");
|
||||
expect(params.prompt).not.toContain("openai/gpt-5.6-luna");
|
||||
expect(params.prompt).not.toContain("codex-cli/test-model");
|
||||
return makeJudgeReply([
|
||||
{
|
||||
@@ -318,8 +318,8 @@ describe("runQaCharacterEval", () => {
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "codex-cli/test-model"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna", "codex-cli/test-model"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
judgeBlindModels: true,
|
||||
runSuite,
|
||||
runJudge,
|
||||
@@ -328,7 +328,7 @@ describe("runQaCharacterEval", () => {
|
||||
expect(result.judgments[0]?.blindModels).toBe(true);
|
||||
expect(result.judgments[0]?.rankings.map((ranking) => ranking.model)).toEqual([
|
||||
"codex-cli/test-model",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
]);
|
||||
const report = await fs.readFile(result.reportPath, "utf8");
|
||||
expect(report).toContain("Judge model labels: blind");
|
||||
@@ -338,7 +338,7 @@ describe("runQaCharacterEval", () => {
|
||||
it("defaults to the character eval model panel when no models are provided", async () => {
|
||||
const runSuite = makeRunSuite();
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "openai/gpt-5.5", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "openai/gpt-5.6-luna", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "openai/gpt-5.2", rank: 2, score: 7.5, summary: "ok" },
|
||||
{ model: "openai/gpt-5", rank: 3, score: 7.2, summary: "ok" },
|
||||
{ model: "anthropic/claude-opus-4-8", rank: 4, score: 7, summary: "ok" },
|
||||
@@ -358,7 +358,7 @@ describe("runQaCharacterEval", () => {
|
||||
|
||||
expect(runSuite).toHaveBeenCalledTimes(8);
|
||||
expect(runSuite.mock.calls.map(([params]) => params.primaryModel)).toEqual([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"openai/gpt-5.2",
|
||||
"openai/gpt-5",
|
||||
"anthropic/claude-opus-4-8",
|
||||
@@ -389,7 +389,7 @@ describe("runQaCharacterEval", () => {
|
||||
]);
|
||||
expect(runJudge).toHaveBeenCalledTimes(2);
|
||||
expect(runJudge.mock.calls.map(([params]) => params.judgeModel)).toEqual([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-sol",
|
||||
"anthropic/claude-opus-4-8",
|
||||
]);
|
||||
expect(runJudge.mock.calls.map(([params]) => params.judgeThinkingDefault)).toEqual([
|
||||
@@ -405,7 +405,7 @@ describe("runQaCharacterEval", () => {
|
||||
runGate.run(() => makeReplySuiteResult(params)),
|
||||
);
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "openai/gpt-5.5", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "openai/gpt-5.6-luna", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "anthropic/claude-sonnet-4-6", rank: 2, score: 7, summary: "ok" },
|
||||
{ model: "moonshot/kimi-k2.5", rank: 3, score: 6, summary: "ok" },
|
||||
]);
|
||||
@@ -413,9 +413,9 @@ describe("runQaCharacterEval", () => {
|
||||
const resultPromise = runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "anthropic/claude-sonnet-4-6", "moonshot/kimi-k2.5"],
|
||||
models: ["openai/gpt-5.6-luna", "anthropic/claude-sonnet-4-6", "moonshot/kimi-k2.5"],
|
||||
candidateConcurrency: 2,
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -425,7 +425,7 @@ describe("runQaCharacterEval", () => {
|
||||
runGate.releaseStartedTasks();
|
||||
const result = await resultPromise;
|
||||
expect(result.runs.map((run) => run.model)).toEqual([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"anthropic/claude-sonnet-4-6",
|
||||
"moonshot/kimi-k2.5",
|
||||
]);
|
||||
@@ -485,7 +485,7 @@ describe("runQaCharacterEval", () => {
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["qwen/qwen3.6-plus"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -507,14 +507,14 @@ describe("runQaCharacterEval", () => {
|
||||
}),
|
||||
);
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "openai/gpt-5.5", rank: 1, score: 0.5, summary: "failed" },
|
||||
{ model: "openai/gpt-5.6-luna", rank: 1, score: 0.5, summary: "failed" },
|
||||
]);
|
||||
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -539,7 +539,7 @@ describe("runQaCharacterEval", () => {
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["qwen/qwen3.5-plus"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -567,7 +567,7 @@ describe("runQaCharacterEval", () => {
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["qa/generic-fallback-model"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -595,7 +595,7 @@ describe("runQaCharacterEval", () => {
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["google/gemini-test"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -616,20 +616,20 @@ describe("runQaCharacterEval", () => {
|
||||
}),
|
||||
);
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "codex/gpt-5.5", rank: 1, score: 0.5, summary: "failed" },
|
||||
{ model: "codex/gpt-5.6-luna", rank: 1, score: 0.5, summary: "failed" },
|
||||
]);
|
||||
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["codex/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
models: ["codex/gpt-5.6-luna"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
|
||||
expectFirstRunFailure(result, {
|
||||
model: "codex/gpt-5.5",
|
||||
model: "codex/gpt-5.6-luna",
|
||||
error: "internal harness/meta text leaked into transcript",
|
||||
});
|
||||
});
|
||||
@@ -637,17 +637,17 @@ describe("runQaCharacterEval", () => {
|
||||
it("lets explicit candidate thinking override the default panel", async () => {
|
||||
const runSuite = makeRunSuite();
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "openai/gpt-5.5", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "openai/gpt-5.6-luna", rank: 1, score: 8, summary: "ok" },
|
||||
{ model: "moonshot/kimi-k2.5", rank: 2, score: 7, summary: "ok" },
|
||||
]);
|
||||
|
||||
await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "moonshot/kimi-k2.5"],
|
||||
models: ["openai/gpt-5.6-luna", "moonshot/kimi-k2.5"],
|
||||
candidateThinkingDefault: "medium",
|
||||
candidateThinkingByModel: { "moonshot/kimi-k2.5": "high" },
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
@@ -660,21 +660,23 @@ describe("runQaCharacterEval", () => {
|
||||
|
||||
it("lets model-specific options override candidate and judge defaults", async () => {
|
||||
const runSuite = makeRunSuite();
|
||||
const runJudge = makeRunJudge([{ model: "openai/gpt-5.5", rank: 1, score: 8, summary: "ok" }]);
|
||||
const runJudge = makeRunJudge([
|
||||
{ model: "openai/gpt-5.6-luna", rank: 1, score: 8, summary: "ok" },
|
||||
]);
|
||||
|
||||
await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "moonshot/kimi-k2.5"],
|
||||
models: ["openai/gpt-5.6-luna", "moonshot/kimi-k2.5"],
|
||||
candidateFastMode: true,
|
||||
candidateThinkingDefault: "medium",
|
||||
candidateModelOptions: {
|
||||
"openai/gpt-5.5": { thinkingDefault: "xhigh", fastMode: false },
|
||||
"openai/gpt-5.6-luna": { thinkingDefault: "xhigh", fastMode: false },
|
||||
},
|
||||
judgeModels: ["openai/gpt-5.5", "anthropic/claude-opus-4-8"],
|
||||
judgeModels: ["openai/gpt-5.6-luna", "anthropic/claude-opus-4-8"],
|
||||
judgeThinkingDefault: "medium",
|
||||
judgeModelOptions: {
|
||||
"openai/gpt-5.5": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"openai/gpt-5.6-luna": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"anthropic/claude-opus-4-8": { thinkingDefault: "high" },
|
||||
},
|
||||
runSuite,
|
||||
@@ -706,15 +708,15 @@ describe("runQaCharacterEval", () => {
|
||||
});
|
||||
const runJudge = vi.fn(async (_params: CharacterRunJudgeParams) =>
|
||||
JSON.stringify({
|
||||
rankings: [{ model: "openai/gpt-5.5", rank: 1, score: 8, summary: "ok" }],
|
||||
rankings: [{ model: "openai/gpt-5.6-luna", rank: 1, score: 8, summary: "ok" }],
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await runQaCharacterEval({
|
||||
repoRoot: tempRoot,
|
||||
outputDir: path.join(tempRoot, "character"),
|
||||
models: ["openai/gpt-5.5", "codex-cli/test-model"],
|
||||
judgeModels: ["openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna", "codex-cli/test-model"],
|
||||
judgeModels: ["openai/gpt-5.6-luna"],
|
||||
runSuite,
|
||||
runJudge,
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ const QA_SMOKE_CI_SCENARIO_IDS = new Set([
|
||||
"crestodian-ring-zero-setup",
|
||||
"dreaming-shadow-trial-report",
|
||||
"gateway-smoke",
|
||||
"gpt55-thinking-visibility-switch",
|
||||
"luna-thinking-visibility-switch",
|
||||
"group-visible-reply-tool",
|
||||
"long-running-release-audit",
|
||||
"matrix-restart-resume",
|
||||
|
||||
@@ -285,7 +285,7 @@ describe("qa cli runtime", () => {
|
||||
summaryPath: "/tmp/character-summary.json",
|
||||
});
|
||||
runQaManualLane.mockResolvedValue({
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
waited: { status: "ok" },
|
||||
reply: "done",
|
||||
watchUrl: "http://127.0.0.1:43124",
|
||||
@@ -382,7 +382,7 @@ describe("qa cli runtime", () => {
|
||||
await runQaSuiteCommand({
|
||||
repoRoot: process.cwd(),
|
||||
outputDir: ".artifacts/qa-e2e/scenario-test",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
scenarioIds: ["control-ui-chat-flow-playwright"],
|
||||
});
|
||||
|
||||
@@ -392,7 +392,7 @@ describe("qa cli runtime", () => {
|
||||
transportId: "qa-channel",
|
||||
channelDriver: undefined,
|
||||
channelDriverSelection: undefined,
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: undefined,
|
||||
fastMode: undefined,
|
||||
scenarioIds: ["control-ui-chat-flow-playwright"],
|
||||
@@ -449,8 +449,8 @@ describe("qa cli runtime", () => {
|
||||
id: "openai",
|
||||
live: false,
|
||||
model: {
|
||||
name: "gpt-5.5",
|
||||
ref: "mock-openai/gpt-5.5",
|
||||
name: "gpt-5.6-luna",
|
||||
ref: "mock-openai/gpt-5.6-luna",
|
||||
},
|
||||
fixture: "mock-openai",
|
||||
},
|
||||
@@ -671,7 +671,7 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
outputDir: ".artifacts/qa/frontier",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-sonnet-4-6",
|
||||
fastMode: true,
|
||||
thinking: "medium",
|
||||
@@ -685,7 +685,7 @@ describe("qa cli runtime", () => {
|
||||
channelDriver: undefined,
|
||||
channelDriverSelection: undefined,
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-sonnet-4-6",
|
||||
fastMode: true,
|
||||
thinkingDefault: "medium",
|
||||
@@ -936,8 +936,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
outputDir: ".artifacts/qa/telegram",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
scenarioIds: ["telegram-help-command"],
|
||||
sutAccountId: "sut-live",
|
||||
@@ -950,8 +950,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
outputDir: path.resolve("/tmp/openclaw-repo", ".artifacts/qa/telegram"),
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
sutAccountId: "sut-live",
|
||||
}),
|
||||
@@ -1413,7 +1413,7 @@ describe("qa cli runtime", () => {
|
||||
await runQaSuiteCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-opus-4-8",
|
||||
preflight: true,
|
||||
});
|
||||
@@ -1423,7 +1423,7 @@ describe("qa cli runtime", () => {
|
||||
repoRoot,
|
||||
transportId: "qa-channel",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-opus-4-8",
|
||||
scenarioIds: ["approval-turn-tool-followthrough"],
|
||||
concurrency: 1,
|
||||
@@ -1807,7 +1807,7 @@ describe("qa cli runtime", () => {
|
||||
counts: { total: 1, passed: 1, failed: 0 },
|
||||
run: {
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
runtimePair: ["openclaw", "codex"],
|
||||
},
|
||||
}),
|
||||
@@ -1880,7 +1880,7 @@ describe("qa cli runtime", () => {
|
||||
counts: { total: 1, passed: 1, failed: 0 },
|
||||
run: {
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
runtimePair: ["openclaw", "codex"],
|
||||
},
|
||||
}),
|
||||
@@ -2079,14 +2079,17 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
outputDir: ".artifacts/qa/character",
|
||||
model: [
|
||||
"openai/gpt-5.5,thinking=xhigh,fast=false",
|
||||
"openai/gpt-5.6-luna,thinking=xhigh,fast=false",
|
||||
"codex-cli/test-model,thinking=high,fast",
|
||||
],
|
||||
scenario: "character-vibes-gollum",
|
||||
fast: true,
|
||||
thinking: "medium",
|
||||
modelThinking: ["codex-cli/test-model=medium"],
|
||||
judgeModel: ["openai/gpt-5.5,thinking=xhigh,fast", "anthropic/claude-opus-4-8,thinking=high"],
|
||||
judgeModel: [
|
||||
"openai/gpt-5.6-luna,thinking=xhigh,fast",
|
||||
"anthropic/claude-opus-4-8,thinking=high",
|
||||
],
|
||||
judgeTimeoutMs: 180_000,
|
||||
blindJudgeModels: true,
|
||||
concurrency: 4,
|
||||
@@ -2098,18 +2101,18 @@ describe("qa cli runtime", () => {
|
||||
expectFields(characterEvalArgs, {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
outputDir: path.resolve("/tmp/openclaw-repo", ".artifacts/qa/character"),
|
||||
models: ["openai/gpt-5.5", "codex-cli/test-model"],
|
||||
models: ["openai/gpt-5.6-luna", "codex-cli/test-model"],
|
||||
scenarioId: "character-vibes-gollum",
|
||||
candidateFastMode: true,
|
||||
candidateThinkingDefault: "medium",
|
||||
candidateThinkingByModel: { "codex-cli/test-model": "medium" },
|
||||
candidateModelOptions: {
|
||||
"openai/gpt-5.5": { thinkingDefault: "xhigh", fastMode: false },
|
||||
"openai/gpt-5.6-luna": { thinkingDefault: "xhigh", fastMode: false },
|
||||
"codex-cli/test-model": { thinkingDefault: "high", fastMode: true },
|
||||
},
|
||||
judgeModels: ["openai/gpt-5.5", "anthropic/claude-opus-4-8"],
|
||||
judgeModels: ["openai/gpt-5.6-luna", "anthropic/claude-opus-4-8"],
|
||||
judgeModelOptions: {
|
||||
"openai/gpt-5.5": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"openai/gpt-5.6-luna": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"anthropic/claude-opus-4-8": { thinkingDefault: "high" },
|
||||
},
|
||||
judgeTimeoutMs: 180_000,
|
||||
@@ -2122,7 +2125,7 @@ describe("qa cli runtime", () => {
|
||||
it("lets character eval auto-select candidate fast mode when --fast is omitted", async () => {
|
||||
await runQaCharacterEvalCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
model: ["openai/gpt-5.5"],
|
||||
model: ["openai/gpt-5.6-luna"],
|
||||
});
|
||||
|
||||
const characterEvalArgs = mockFirstObjectArg(runQaCharacterEval);
|
||||
@@ -2130,7 +2133,7 @@ describe("qa cli runtime", () => {
|
||||
expectFields(characterEvalArgs, {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
outputDir: undefined,
|
||||
models: ["openai/gpt-5.5"],
|
||||
models: ["openai/gpt-5.6-luna"],
|
||||
scenarioId: undefined,
|
||||
candidateFastMode: undefined,
|
||||
candidateThinkingDefault: undefined,
|
||||
@@ -2149,7 +2152,7 @@ describe("qa cli runtime", () => {
|
||||
await expect(
|
||||
runQaCharacterEvalCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
model: ["openai/gpt-5.5"],
|
||||
model: ["openai/gpt-5.6-luna"],
|
||||
thinking: "enormous",
|
||||
}),
|
||||
).rejects.toThrow("--thinking must be one of");
|
||||
@@ -2157,22 +2160,22 @@ describe("qa cli runtime", () => {
|
||||
await expect(
|
||||
runQaCharacterEvalCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
model: ["openai/gpt-5.5,thinking=galaxy"],
|
||||
model: ["openai/gpt-5.6-luna,thinking=galaxy"],
|
||||
}),
|
||||
).rejects.toThrow("--model thinking must be one of");
|
||||
|
||||
await expect(
|
||||
runQaCharacterEvalCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
model: ["openai/gpt-5.5,warp"],
|
||||
model: ["openai/gpt-5.6-luna,warp"],
|
||||
}),
|
||||
).rejects.toThrow("--model options must be thinking=<level>");
|
||||
|
||||
await expect(
|
||||
runQaCharacterEvalCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
model: ["openai/gpt-5.5"],
|
||||
modelThinking: ["openai/gpt-5.5"],
|
||||
model: ["openai/gpt-5.6-luna"],
|
||||
modelThinking: ["openai/gpt-5.6-luna"],
|
||||
}),
|
||||
).rejects.toThrow("--model-thinking must use provider/model=level");
|
||||
});
|
||||
@@ -2181,8 +2184,8 @@ describe("qa cli runtime", () => {
|
||||
await runQaManualLaneCommand({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: 45_000,
|
||||
@@ -2192,8 +2195,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: 45_000,
|
||||
@@ -2271,8 +2274,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
runner: "multipass",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
allowFailures: true,
|
||||
scenarioIds: ["channel-chat-baseline"],
|
||||
@@ -2282,8 +2285,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
allowFailures: true,
|
||||
scenarioIds: ["channel-chat-baseline"],
|
||||
@@ -2496,7 +2499,7 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
parityPack: "agentic",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-opus-4-8",
|
||||
});
|
||||
|
||||
@@ -2507,7 +2510,7 @@ describe("qa cli runtime", () => {
|
||||
channelDriver: undefined,
|
||||
channelDriverSelection: undefined,
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-opus-4-8",
|
||||
fastMode: undefined,
|
||||
scenarioIds: [
|
||||
@@ -2548,8 +2551,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
fastMode: undefined,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: undefined,
|
||||
@@ -2567,8 +2570,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "aimock",
|
||||
primaryModel: "aimock/gpt-5.5",
|
||||
alternateModel: "aimock/gpt-5.5-alt",
|
||||
primaryModel: "aimock/gpt-5.6-luna",
|
||||
alternateModel: "aimock/gpt-5.6-luna-alt",
|
||||
fastMode: undefined,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: undefined,
|
||||
@@ -2616,7 +2619,7 @@ describe("qa cli runtime", () => {
|
||||
it("defaults manual frontier runs onto Codex OAuth when the runtime resolver prefers it", async () => {
|
||||
defaultQaRuntimeModelForMode.mockImplementation((mode, options) =>
|
||||
mode === "live-frontier"
|
||||
? "openai/gpt-5.5"
|
||||
? "openai/gpt-5.6-luna"
|
||||
: defaultQaProviderModelForMode(mode as QaProviderModeInput, options),
|
||||
);
|
||||
|
||||
@@ -2629,8 +2632,8 @@ describe("qa cli runtime", () => {
|
||||
repoRoot: path.resolve("/tmp/openclaw-repo"),
|
||||
transportId: "qa-channel",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: undefined,
|
||||
message: "read qa kickoff and reply short",
|
||||
timeoutMs: undefined,
|
||||
|
||||
@@ -226,7 +226,7 @@ describe("qa cli registration", () => {
|
||||
"--provider-mode",
|
||||
"mock-openai",
|
||||
"--model",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"--alt-model",
|
||||
"anthropic/claude-sonnet-4-6",
|
||||
"--concurrency",
|
||||
@@ -245,7 +245,7 @@ describe("qa cli registration", () => {
|
||||
evidenceMode: "slim",
|
||||
transportId: "qa-channel",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "anthropic/claude-sonnet-4-6",
|
||||
concurrency: 2,
|
||||
allowFailures: true,
|
||||
@@ -263,7 +263,7 @@ describe("qa cli registration", () => {
|
||||
["--exclude-test-execution-evidence", []],
|
||||
["--transport", ["qa-channel"]],
|
||||
["--provider-mode", ["mock-openai"]],
|
||||
["--model", ["openai/gpt-5.5"]],
|
||||
["--model", ["openai/gpt-5.6-luna"]],
|
||||
["--alt-model", ["anthropic/claude-sonnet-4-6"]],
|
||||
["--concurrency", ["2"]],
|
||||
["--allow-failures", []],
|
||||
@@ -551,9 +551,9 @@ describe("qa cli registration", () => {
|
||||
"--provider-mode",
|
||||
"live-frontier",
|
||||
"--model",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"--alt-model",
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"--scenario",
|
||||
"slack-canary",
|
||||
"--credential-source",
|
||||
@@ -565,7 +565,7 @@ describe("qa cli registration", () => {
|
||||
]);
|
||||
|
||||
expect(runMantisSlackDesktopSmokeCommand).toHaveBeenCalledWith({
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
crabboxBin: "/tmp/crabbox",
|
||||
credentialRole: "maintainer",
|
||||
credentialSource: "env",
|
||||
@@ -578,7 +578,7 @@ describe("qa cli registration", () => {
|
||||
machineClass: "beast",
|
||||
market: "on-demand",
|
||||
outputDir: ".artifacts/qa-e2e/mantis/slack-desktop",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
provider: "hetzner",
|
||||
providerMode: "live-frontier",
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
|
||||
@@ -62,7 +62,7 @@ function vitestArtifactEvidence(params: {
|
||||
provider: {
|
||||
id: "mock-openai",
|
||||
live: false,
|
||||
model: { name: "mock-openai/gpt-5.5", ref: "mock-openai/gpt-5.5" },
|
||||
model: { name: "mock-openai/gpt-5.6-luna", ref: "mock-openai/gpt-5.6-luna" },
|
||||
},
|
||||
packageSource: { kind: "source-checkout" },
|
||||
artifacts: [{ ...params.artifact, source: "vitest" }],
|
||||
@@ -90,7 +90,7 @@ describe("evidence gallery", () => {
|
||||
OPENCLAW_QA_REF: "gallery-test",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-17T12:00:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
targets: [
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_QA_REF: "abc123",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:00:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
scenarioResults: [{ name: "DM baseline conversation", status: "pass" }],
|
||||
});
|
||||
@@ -87,8 +87,8 @@ describe("evidence summary", () => {
|
||||
id: "openai",
|
||||
live: false,
|
||||
model: {
|
||||
name: "gpt-5.5",
|
||||
ref: "mock-openai/gpt-5.5",
|
||||
name: "gpt-5.6-luna",
|
||||
ref: "mock-openai/gpt-5.6-luna",
|
||||
},
|
||||
fixture: "mock-openai",
|
||||
},
|
||||
@@ -137,7 +137,7 @@ describe("evidence summary", () => {
|
||||
GITHUB_SHA: "bd479958c04a1eadbda8b6105e0722588d71e9ad",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-24T12:00:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
repoRoot,
|
||||
scenarioDefinitions: [{ id: "ref-probe", title: "Ref probe" }],
|
||||
@@ -157,7 +157,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_QA_RUNNER: "crabbox",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:05:00.000Z",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
@@ -199,8 +199,8 @@ describe("evidence summary", () => {
|
||||
id: "openai",
|
||||
live: true,
|
||||
model: {
|
||||
name: "gpt-5.5",
|
||||
ref: "openai/gpt-5.5",
|
||||
name: "gpt-5.6-luna",
|
||||
ref: "openai/gpt-5.6-luna",
|
||||
},
|
||||
auth: "live-frontier",
|
||||
},
|
||||
@@ -239,7 +239,7 @@ describe("evidence summary", () => {
|
||||
const evidence = buildLiveTransportEvidenceSummary({
|
||||
artifactPaths: [{ kind: "summary", path: QA_EVIDENCE_FILENAME }],
|
||||
generatedAt: "2026-06-07T12:05:00.000Z",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
@@ -283,7 +283,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_QA_REF: "abc123",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:06:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
targets: [
|
||||
{
|
||||
@@ -365,7 +365,7 @@ describe("evidence summary", () => {
|
||||
GITHUB_SHA: "def456",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:07:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
targets: [
|
||||
{
|
||||
@@ -459,7 +459,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_QA_PROFILE: "experimental-profile",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:09:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
scenarioResults: [{ name: "DM baseline conversation", status: "pass" }],
|
||||
});
|
||||
@@ -488,7 +488,7 @@ describe("evidence summary", () => {
|
||||
],
|
||||
channelId: "qa-channel",
|
||||
generatedAt: "2026-06-07T12:09:00.000Z",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
providerMode: "mock-openai",
|
||||
scenarioResults: [{ name: "DM baseline conversation", status: "pass" }],
|
||||
});
|
||||
@@ -547,7 +547,7 @@ describe("evidence summary", () => {
|
||||
spec: "/tmp/openclaw.tgz",
|
||||
sha: "abc123",
|
||||
},
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
@@ -577,7 +577,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_QA_PACKAGE_SOURCE_SHA: "def456",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:15:00.000Z",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
@@ -605,7 +605,7 @@ describe("evidence summary", () => {
|
||||
OPENCLAW_NPM_TELEGRAM_INSTALL_SOURCE: "openclaw@beta",
|
||||
} as NodeJS.ProcessEnv,
|
||||
generatedAt: "2026-06-07T12:16:00.000Z",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
@@ -633,7 +633,7 @@ describe("evidence summary", () => {
|
||||
{ kind: "report", path: "discord-qa-report.md" },
|
||||
],
|
||||
generatedAt: "2026-06-07T12:20:00.000Z",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
providerMode: "live-frontier",
|
||||
checks: [
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ describe("gateway log sentinels", () => {
|
||||
"[plugins] plugin must declare contracts.tools for: runtime_tool",
|
||||
"2026-05-13T00:00:04Z codex app-server attempt timed out after 180000ms",
|
||||
"2026-05-13T00:00:05Z codex_app_server progress stalled for run abc123",
|
||||
"2026-05-13T00:00:06Z cron payload model openai/gpt-5.5 is not in model allowlist",
|
||||
"2026-05-13T00:00:06Z cron payload model openai/gpt-5.6-luna is not in model allowlist",
|
||||
"2026-05-13T00:00:07Z OpenAI quota exceeded for live-frontier request",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
@@ -182,7 +182,7 @@ describe("harness parity", () => {
|
||||
classify(
|
||||
{
|
||||
transcriptBytes:
|
||||
'{"type":"model_change","modelId":"gpt-5.5"}\n' +
|
||||
'{"type":"model_change","modelId":"gpt-5.6-luna"}\n' +
|
||||
'{"type":"thinking_level_change","thinkingLevel":"off"}\n' +
|
||||
'{"type":"custom","customType":"model-snapshot"}\n' +
|
||||
'{"message":{"role":"assistant","content":"same"}}\n',
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("qa-lab server capture helpers", () => {
|
||||
metaJson: JSON.stringify({
|
||||
provider: "openai",
|
||||
api: "responses",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
captureOrigin: "shared-fetch",
|
||||
}),
|
||||
}) as ReturnType<typeof mapCaptureEventForQa> & { flowId?: string };
|
||||
@@ -27,7 +27,7 @@ describe("qa-lab server capture helpers", () => {
|
||||
expect(record.payloadPreview).toBe('{"hello":"world"}');
|
||||
expect(record.provider).toBe("openai");
|
||||
expect(record.api).toBe("responses");
|
||||
expect(record.model).toBe("gpt-5.5");
|
||||
expect(record.model).toBe("gpt-5.6-luna");
|
||||
expect(record.captureOrigin).toBe("shared-fetch");
|
||||
});
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ describe("qa-lab server", () => {
|
||||
provider: {
|
||||
id: "mock-openai",
|
||||
live: false,
|
||||
model: { name: "mock-openai/gpt-5.5", ref: "mock-openai/gpt-5.5" },
|
||||
model: { name: "mock-openai/gpt-5.6-luna", ref: "mock-openai/gpt-5.6-luna" },
|
||||
},
|
||||
packageSource: { kind: "source-checkout" },
|
||||
artifacts: [{ kind: "log", path: "artifact.log", source: "vitest" }],
|
||||
@@ -869,9 +869,9 @@ describe("qa-lab server", () => {
|
||||
`fs.writeFileSync(${JSON.stringify(markerPath)}, process.argv.slice(2).join(" "), "utf8");`,
|
||||
"process.stdout.write(JSON.stringify({",
|
||||
" models: [{",
|
||||
' key: "openai/gpt-5.5",',
|
||||
' name: "GPT-5.5",',
|
||||
' input: "openai/gpt-5.5",',
|
||||
' key: "openai/gpt-5.6-luna",',
|
||||
' name: "GPT-5.6 Luna",',
|
||||
' input: "openai/gpt-5.6-luna",',
|
||||
" available: true,",
|
||||
" missing: false,",
|
||||
" }],",
|
||||
@@ -1083,7 +1083,7 @@ describe("qa-lab server", () => {
|
||||
metaJson: JSON.stringify({
|
||||
provider: "openai",
|
||||
api: "responses",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
captureOrigin: "shared-fetch",
|
||||
}),
|
||||
});
|
||||
@@ -1104,7 +1104,7 @@ describe("qa-lab server", () => {
|
||||
metaJson: JSON.stringify({
|
||||
provider: "openai",
|
||||
api: "responses",
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
captureOrigin: "shared-fetch",
|
||||
}),
|
||||
});
|
||||
@@ -1148,7 +1148,7 @@ describe("qa-lab server", () => {
|
||||
expect(events.events.map((event) => event.flowId)).toContain("flow-1");
|
||||
const flow1 = events.events.find((event) => event.flowId === "flow-1");
|
||||
expect(flow1?.provider).toBe("openai");
|
||||
expect(flow1?.model).toBe("gpt-5.5");
|
||||
expect(flow1?.model).toBe("gpt-5.6-luna");
|
||||
expect(flow1?.captureOrigin).toBe("shared-fetch");
|
||||
|
||||
const flow3 = events.events.find((event) => event.flowId === "flow-3");
|
||||
@@ -1174,7 +1174,7 @@ describe("qa-lab server", () => {
|
||||
expect(coverage.coverage.providers.find((provider) => provider.value === "ollama")?.count).toBe(
|
||||
1,
|
||||
);
|
||||
expect(coverage.coverage.models.find((model) => model.value === "gpt-5.5")?.count).toBe(2);
|
||||
expect(coverage.coverage.models.find((model) => model.value === "gpt-5.6-luna")?.count).toBe(2);
|
||||
expect(coverage.coverage.models.find((model) => model.value === "kimi-k2.5:cloud")?.count).toBe(
|
||||
1,
|
||||
);
|
||||
|
||||
@@ -21,8 +21,8 @@ describe("qa live timeout policy", () => {
|
||||
resolveQaLiveTurnTimeoutMs(
|
||||
{
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
},
|
||||
30_000,
|
||||
),
|
||||
|
||||
@@ -88,8 +88,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -110,8 +110,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -162,8 +162,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -178,8 +178,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -202,8 +202,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
}),
|
||||
).rejects.toThrow("gateway failed");
|
||||
@@ -221,8 +221,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
@@ -239,8 +239,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -259,8 +259,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
@@ -276,8 +276,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
const stopOptions = { preserveToDir: ".artifacts/qa-e2e/debug" };
|
||||
@@ -297,8 +297,8 @@ describe("startQaLiveLaneGateway", () => {
|
||||
transport: createStubTransport(),
|
||||
transportBaseUrl: "http://127.0.0.1:43123",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
controlUiEnabled: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -114,8 +114,12 @@ describe("Slack live QA runtime helpers", () => {
|
||||
});
|
||||
|
||||
it("accepts only Codex harness providers for Codex approval scenarios", () => {
|
||||
expect(() => testing.assertSlackCodexApprovalModelSupported("openai/gpt-5.5")).not.toThrow();
|
||||
expect(() => testing.assertSlackCodexApprovalModelSupported("codex/gpt-5.5")).not.toThrow();
|
||||
expect(() =>
|
||||
testing.assertSlackCodexApprovalModelSupported("openai/gpt-5.6-luna"),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
testing.assertSlackCodexApprovalModelSupported("codex/gpt-5.6-luna"),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
testing.assertSlackCodexApprovalModelSupported("anthropic/claude-sonnet-4-6"),
|
||||
).toThrow(
|
||||
@@ -176,7 +180,7 @@ describe("Slack live QA runtime helpers", () => {
|
||||
list: [
|
||||
{
|
||||
id: "qa",
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
model: { primary: "openai/gpt-5.6-luna" },
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -192,7 +196,7 @@ describe("Slack live QA runtime helpers", () => {
|
||||
},
|
||||
codexApproval: true,
|
||||
},
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
sutAccountId: "sut",
|
||||
sutAppToken: "xapp-sut",
|
||||
sutBotToken: "xoxb-sut",
|
||||
@@ -209,7 +213,7 @@ describe("Slack live QA runtime helpers", () => {
|
||||
},
|
||||
});
|
||||
expect(cfg.tools?.exec?.mode).toBe("ask");
|
||||
expect(cfg.agents?.defaults?.models?.["openai/gpt-5.5"]?.agentRuntime).toEqual({
|
||||
expect(cfg.agents?.defaults?.models?.["openai/gpt-5.6-luna"]?.agentRuntime).toEqual({
|
||||
id: "codex",
|
||||
});
|
||||
expect(cfg.approvals?.plugin).toEqual({ enabled: true, mode: "session" });
|
||||
@@ -924,7 +928,7 @@ describe("Slack live QA runtime helpers", () => {
|
||||
approvalKind: "plugin",
|
||||
appServerMethod: "item/fileChange/requestApproval",
|
||||
channelId: "C123456789",
|
||||
codexModelKey: "openai/gpt-5.5",
|
||||
codexModelKey: "openai/gpt-5.6-luna",
|
||||
decision: "allow-once",
|
||||
finalCodexTurnStatus: "ok",
|
||||
operationVerified: true,
|
||||
@@ -947,7 +951,7 @@ describe("Slack live QA runtime helpers", () => {
|
||||
approvalId: "<redacted>",
|
||||
appServerMethod: "item/fileChange/requestApproval",
|
||||
channelId: undefined,
|
||||
codexModelKey: "openai/gpt-5.5",
|
||||
codexModelKey: "openai/gpt-5.6-luna",
|
||||
finalCodexTurnStatus: "ok",
|
||||
operationVerified: true,
|
||||
pendingActionValues: undefined,
|
||||
|
||||
@@ -381,7 +381,7 @@ describe("telegram live qa runtime", () => {
|
||||
});
|
||||
|
||||
expect(next.agents?.defaults?.skipBootstrap).toBe(true);
|
||||
expect(next.agents?.defaults?.models?.["openai/gpt-5.5"]?.agentRuntime).toEqual({
|
||||
expect(next.agents?.defaults?.models?.["openai/gpt-5.6-luna"]?.agentRuntime).toEqual({
|
||||
id: "openclaw",
|
||||
});
|
||||
expect(next.plugins?.allow).toContain("telegram");
|
||||
|
||||
@@ -677,8 +677,8 @@ function buildTelegramQaConfig(
|
||||
...baseCfg.agents?.defaults,
|
||||
models: {
|
||||
...baseCfg.agents?.defaults?.models,
|
||||
"openai/gpt-5.5": {
|
||||
...baseCfg.agents?.defaults?.models?.["openai/gpt-5.5"],
|
||||
"openai/gpt-5.6-luna": {
|
||||
...baseCfg.agents?.defaults?.models?.["openai/gpt-5.6-luna"],
|
||||
agentRuntime: { id: "openclaw" },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2695,7 +2695,7 @@ describe("WhatsApp QA live runtime", () => {
|
||||
agents: {
|
||||
defaults: {
|
||||
maxConcurrent: 7,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
workspace: "/workspace/qa",
|
||||
},
|
||||
list: [
|
||||
@@ -2703,7 +2703,7 @@ describe("WhatsApp QA live runtime", () => {
|
||||
default: true,
|
||||
id: "main",
|
||||
identity: { name: "Main WhatsApp QA" },
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2712,14 +2712,14 @@ describe("WhatsApp QA live runtime", () => {
|
||||
|
||||
expect(cfg.agents?.defaults).toEqual({
|
||||
maxConcurrent: 7,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
workspace: "/workspace/qa",
|
||||
});
|
||||
expect(cfg.agents?.list?.map((agent) => agent.id)).toEqual(["main", "qa-second"]);
|
||||
expect(cfg.agents?.list?.find((agent) => agent.id === "main")).toMatchObject({
|
||||
default: true,
|
||||
identity: { name: "Main WhatsApp QA" },
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
});
|
||||
expect(cfg.broadcast?.strategy).toBe("sequential");
|
||||
expect(cfg.broadcast?.[groupJid]).toEqual(["main", "qa-second"]);
|
||||
|
||||
@@ -85,8 +85,8 @@ describe("runQaManualLane", () => {
|
||||
const result = await runQaManualLane({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
message: "check the kickoff file",
|
||||
timeoutMs: 5_000,
|
||||
replySettleMs: 0,
|
||||
@@ -111,8 +111,8 @@ describe("runQaManualLane", () => {
|
||||
const result = await runQaManualLane({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
message: "check the kickoff file",
|
||||
timeoutMs: 5_000,
|
||||
replySettleMs: 0,
|
||||
@@ -136,8 +136,8 @@ describe("runQaManualLane", () => {
|
||||
runQaManualLane({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
message: "check the kickoff file",
|
||||
timeoutMs: 5_000,
|
||||
replySettleMs: 0,
|
||||
@@ -156,8 +156,8 @@ describe("runQaManualLane", () => {
|
||||
runQaManualLane({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
message: "check the kickoff file",
|
||||
timeoutMs: 5_000,
|
||||
replySettleMs: 0,
|
||||
@@ -173,8 +173,8 @@ describe("runQaManualLane", () => {
|
||||
const result = await runQaManualLane({
|
||||
repoRoot: "/tmp/openclaw-repo",
|
||||
providerMode: "mock-openai",
|
||||
primaryModel: "mock-openai/gpt-5.5",
|
||||
alternateModel: "mock-openai/gpt-5.5-alt",
|
||||
primaryModel: "mock-openai/gpt-5.6-luna",
|
||||
alternateModel: "mock-openai/gpt-5.6-luna-alt",
|
||||
message: "check the kickoff file",
|
||||
timeoutMs: 9e15,
|
||||
replySettleMs: 0,
|
||||
|
||||
@@ -51,7 +51,7 @@ async function waitForDead(pid: number, timeoutMs: number): Promise<void> {
|
||||
}
|
||||
|
||||
describe("qa runner model catalog", () => {
|
||||
it("filters to available rows and prefers gpt-5.5 first", () => {
|
||||
it("filters to available rows and prefers gpt-5.6-luna first", () => {
|
||||
expect(
|
||||
selectQaRunnerModelOptions([
|
||||
{
|
||||
@@ -62,8 +62,8 @@ describe("qa runner model catalog", () => {
|
||||
missing: false,
|
||||
},
|
||||
{
|
||||
key: "openai/gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
key: "openai/gpt-5.6-luna",
|
||||
name: "gpt-5.6-luna",
|
||||
input: "text,image",
|
||||
available: true,
|
||||
missing: false,
|
||||
@@ -76,7 +76,7 @@ describe("qa runner model catalog", () => {
|
||||
missing: false,
|
||||
},
|
||||
]).map((entry) => entry.key),
|
||||
).toEqual(["openai/gpt-5.5", "anthropic/claude-sonnet-4-6"]);
|
||||
).toEqual(["openai/gpt-5.6-luna", "anthropic/claude-sonnet-4-6"]);
|
||||
});
|
||||
|
||||
it("reports malformed catalog JSON with an owned error", () => {
|
||||
@@ -92,8 +92,8 @@ describe("qa runner model catalog", () => {
|
||||
models: [
|
||||
null,
|
||||
{
|
||||
key: "openai/gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
key: "openai/gpt-5.6-luna",
|
||||
name: "gpt-5.6-luna",
|
||||
input: "text,image",
|
||||
available: true,
|
||||
missing: false,
|
||||
@@ -101,7 +101,7 @@ describe("qa runner model catalog", () => {
|
||||
],
|
||||
}),
|
||||
).map((entry) => entry.key),
|
||||
).toEqual(["openai/gpt-5.5"]);
|
||||
).toEqual(["openai/gpt-5.6-luna"]);
|
||||
});
|
||||
|
||||
it.runIf(process.platform !== "win32")(
|
||||
|
||||
@@ -51,8 +51,8 @@ describe("qa model selection runtime", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(resolveQaPreferredLiveModel()).toBe("openai/gpt-5.5");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.5");
|
||||
expect(resolveQaPreferredLiveModel()).toBe("openai/gpt-5.6-luna");
|
||||
expect(defaultQaRuntimeModelForMode("live-frontier")).toBe("openai/gpt-5.6-luna");
|
||||
expect(loadAuthProfileStoreForRuntime).toHaveBeenCalledWith(undefined, {
|
||||
readOnly: true,
|
||||
allowKeychainPrompt: false,
|
||||
@@ -75,11 +75,13 @@ describe("qa model selection runtime", () => {
|
||||
});
|
||||
|
||||
it("leaves mock defaults unchanged", () => {
|
||||
expect(defaultQaRuntimeModelForMode("mock-openai")).toBe("mock-openai/gpt-5.5");
|
||||
expect(defaultQaRuntimeModelForMode("mock-openai")).toBe("mock-openai/gpt-5.6-luna");
|
||||
expect(defaultQaRuntimeModelForMode("mock-openai", { alternate: true })).toBe(
|
||||
"mock-openai/gpt-5.5-alt",
|
||||
"mock-openai/gpt-5.6-luna-alt",
|
||||
);
|
||||
expect(defaultQaRuntimeModelForMode("aimock")).toBe("aimock/gpt-5.6-luna");
|
||||
expect(defaultQaRuntimeModelForMode("aimock", { alternate: true })).toBe(
|
||||
"aimock/gpt-5.6-luna-alt",
|
||||
);
|
||||
expect(defaultQaRuntimeModelForMode("aimock")).toBe("aimock/gpt-5.5");
|
||||
expect(defaultQaRuntimeModelForMode("aimock", { alternate: true })).toBe("aimock/gpt-5.5-alt");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,8 +116,8 @@ describe("qa multipass runtime", () => {
|
||||
repoRoot: process.cwd(),
|
||||
outputDir: path.join(process.cwd(), ".artifacts", "qa-e2e", "multipass-live-test"),
|
||||
providerMode: "live-frontier",
|
||||
primaryModel: "openai/gpt-5.5",
|
||||
alternateModel: "openai/gpt-5.5",
|
||||
primaryModel: "openai/gpt-5.6-luna",
|
||||
alternateModel: "openai/gpt-5.6-luna",
|
||||
fastMode: true,
|
||||
scenarioIds: ["channel-chat-baseline"],
|
||||
});
|
||||
@@ -127,7 +127,7 @@ describe("qa multipass runtime", () => {
|
||||
expect(plan.qaCommand).toContain("--provider-mode");
|
||||
expect(plan.qaCommand).toContain("live-frontier");
|
||||
expect(plan.qaCommand).toContain("--model");
|
||||
expect(plan.qaCommand).toContain("openai/gpt-5.5");
|
||||
expect(plan.qaCommand).toContain("openai/gpt-5.6-luna");
|
||||
expect(plan.qaCommand).toContain("--alt-model");
|
||||
expect(plan.qaCommand).toContain("--fast");
|
||||
expect(plan.forwardedEnv.OPENAI_API_KEY).toBe("test-openai-key");
|
||||
|
||||
@@ -25,7 +25,7 @@ describe("qa aimock server", () => {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [makeResponsesInput("hello aimock")],
|
||||
}),
|
||||
@@ -33,12 +33,12 @@ describe("qa aimock server", () => {
|
||||
expect(response.status).toBe(200);
|
||||
const responseBody = (await response.json()) as { model?: unknown; status?: unknown };
|
||||
expect(responseBody.status).toBe("completed");
|
||||
expect(responseBody.model).toBe("aimock/gpt-5.5");
|
||||
expect(responseBody.model).toBe("aimock/gpt-5.6-luna");
|
||||
|
||||
const debug = await fetch(`${server.baseUrl}/debug/last-request`);
|
||||
expect(debug.status).toBe(200);
|
||||
const expectedBody = {
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
messages: [{ role: "user", content: "hello aimock" }],
|
||||
stream: false,
|
||||
_endpointType: "chat",
|
||||
@@ -49,7 +49,7 @@ describe("qa aimock server", () => {
|
||||
prompt: "hello aimock",
|
||||
allInputText: "hello aimock",
|
||||
toolOutput: "",
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
providerVariant: "openai",
|
||||
imageInputCount: 0,
|
||||
});
|
||||
@@ -68,7 +68,7 @@ describe("qa aimock server", () => {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [makeResponsesInput("@openclaw explain the QA lab")],
|
||||
}),
|
||||
@@ -80,7 +80,7 @@ describe("qa aimock server", () => {
|
||||
const debug = await fetch(`${server.baseUrl}/debug/requests`);
|
||||
expect(debug.status).toBe(200);
|
||||
const expectedBody = {
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
messages: [{ role: "user", content: "@openclaw explain the QA lab" }],
|
||||
stream: false,
|
||||
_endpointType: "chat",
|
||||
@@ -92,7 +92,7 @@ describe("qa aimock server", () => {
|
||||
prompt: "@openclaw explain the QA lab",
|
||||
allInputText: "@openclaw explain the QA lab",
|
||||
toolOutput: "",
|
||||
model: "aimock/gpt-5.5",
|
||||
model: "aimock/gpt-5.6-luna",
|
||||
providerVariant: "openai",
|
||||
imageInputCount: 0,
|
||||
},
|
||||
@@ -112,7 +112,7 @@ describe("qa aimock server", () => {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [makeResponsesInput("hello codex-compatible aimock")],
|
||||
}),
|
||||
@@ -122,7 +122,7 @@ describe("qa aimock server", () => {
|
||||
const debug = await fetch(`${server.baseUrl}/debug/last-request`);
|
||||
expect(debug.status).toBe(200);
|
||||
const expectedBody = {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
messages: [{ role: "user", content: "hello codex-compatible aimock" }],
|
||||
stream: false,
|
||||
_endpointType: "chat",
|
||||
@@ -133,7 +133,7 @@ describe("qa aimock server", () => {
|
||||
prompt: "hello codex-compatible aimock",
|
||||
allInputText: "hello codex-compatible aimock",
|
||||
toolOutput: "",
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
providerVariant: "openai",
|
||||
imageInputCount: 0,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Qa Lab plugin module implements catalog behavior.
|
||||
export const QA_FRONTIER_PROVIDER_IDS = ["anthropic", "google", "openai"] as const;
|
||||
export const QA_FRONTIER_CATALOG_PRIMARY_MODEL = "openai/gpt-5.5";
|
||||
export const QA_FRONTIER_CATALOG_PRIMARY_MODEL = "openai/gpt-5.6-luna";
|
||||
export const QA_FRONTIER_CATALOG_ALTERNATE_MODEL = "anthropic/claude-sonnet-4-6";
|
||||
|
||||
export function isPreferredQaLiveFrontierCatalogModel(modelRef: string) {
|
||||
|
||||
@@ -7,7 +7,7 @@ type QaFrontierCharacterModelOptions = {
|
||||
};
|
||||
|
||||
export const QA_FRONTIER_CHARACTER_EVAL_MODELS = Object.freeze([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-luna",
|
||||
"openai/gpt-5.2",
|
||||
"openai/gpt-5",
|
||||
"anthropic/claude-opus-4-8",
|
||||
@@ -19,19 +19,19 @@ export const QA_FRONTIER_CHARACTER_EVAL_MODELS = Object.freeze([
|
||||
|
||||
export const QA_FRONTIER_CHARACTER_THINKING_BY_MODEL: Readonly<Record<string, QaThinkingLevel>> =
|
||||
Object.freeze({
|
||||
"openai/gpt-5.5": "medium",
|
||||
"openai/gpt-5.6-luna": "medium",
|
||||
"openai/gpt-5.2": "xhigh",
|
||||
"openai/gpt-5": "xhigh",
|
||||
});
|
||||
|
||||
export const QA_FRONTIER_CHARACTER_JUDGE_MODELS = Object.freeze([
|
||||
"openai/gpt-5.5",
|
||||
"openai/gpt-5.6-sol",
|
||||
"anthropic/claude-opus-4-8",
|
||||
]);
|
||||
|
||||
export const QA_FRONTIER_CHARACTER_JUDGE_MODEL_OPTIONS: Readonly<
|
||||
Record<string, QaFrontierCharacterModelOptions>
|
||||
> = Object.freeze({
|
||||
"openai/gpt-5.5": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"openai/gpt-5.6-sol": { thinkingDefault: "xhigh", fastMode: true },
|
||||
"anthropic/claude-opus-4-8": { thinkingDefault: "high" },
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/agent-runtime";
|
||||
import { resolveEnvApiKey } from "openclaw/plugin-sdk/provider-auth";
|
||||
|
||||
const QA_CODEX_OAUTH_LIVE_MODEL = "openai/gpt-5.5";
|
||||
const QA_CODEX_OAUTH_LIVE_MODEL = "openai/gpt-5.6-luna";
|
||||
|
||||
export function resolveQaLiveFrontierPreferredModel() {
|
||||
if (resolveEnvApiKey("openai")?.apiKey) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// Qa Lab plugin module implements parity behavior.
|
||||
export const QA_FRONTIER_PARITY_CANDIDATE_LABEL = "openai/gpt-5.5";
|
||||
export const QA_FRONTIER_PARITY_CANDIDATE_LABEL = "openai/gpt-5.6-luna";
|
||||
export const QA_FRONTIER_PARITY_BASELINE_LABEL = "anthropic/claude-opus-4-8";
|
||||
|
||||
@@ -238,7 +238,7 @@ describe("qa mock openai server", () => {
|
||||
for (let index = 0; index < 250; index += 1) {
|
||||
await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(`debug retention request ${index}`)],
|
||||
});
|
||||
}
|
||||
@@ -300,7 +300,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
"Before acting, tell me the single file you would start with in six words or fewer. Do not use tools yet.",
|
||||
@@ -320,7 +320,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
"Before acting, tell me the single file you would start with in six words or fewer. Do not use tools yet.",
|
||||
@@ -339,7 +339,7 @@ describe("qa mock openai server", () => {
|
||||
const debugResponse = await fetch(`${server.baseUrl}/debug/last-request`);
|
||||
expect(debugResponse.status).toBe(200);
|
||||
const debugPayload = requireRecord(await debugResponse.json(), "debug request");
|
||||
expect(debugPayload.model).toBe("gpt-5.5");
|
||||
expect(debugPayload.model).toBe("gpt-5.6-luna");
|
||||
expect(debugPayload.prompt).toBe(
|
||||
"ok do it. read `QA_KICKOFF_TASK.md` now and reply with the QA mission in one short sentence.",
|
||||
);
|
||||
@@ -354,7 +354,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
"qa private final reply warning check. Reply to me directly in two complete sentences with `QA-STRANDED-85714` in the first sentence and a short explanation in the second sentence. Do NOT call any tool. Do NOT use the message tool.",
|
||||
@@ -375,7 +375,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(
|
||||
@@ -391,7 +391,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const retryBody = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(
|
||||
@@ -418,7 +418,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(
|
||||
@@ -474,7 +474,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const toolPlan = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [{ type: "function", name: "sessions_send" }],
|
||||
input: [makeUserInput(prompt)],
|
||||
});
|
||||
@@ -500,7 +500,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const final = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [{ type: "function", name: "sessions_send" }],
|
||||
input: [
|
||||
makeUserInput(prompt),
|
||||
@@ -515,7 +515,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const targetToolPlan = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [
|
||||
{ type: "function", name: "sessions_send" },
|
||||
{ type: "function", name: "message" },
|
||||
@@ -1054,7 +1054,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -1081,7 +1081,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5-alt",
|
||||
model: "gpt-5.6-luna-alt",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -1113,8 +1113,8 @@ describe("qa mock openai server", () => {
|
||||
const requests = await fetch(`${server.baseUrl}/debug/requests`);
|
||||
expect(requests.status).toBe(200);
|
||||
const requestLog = requireArray(await requests.json(), "debug requests");
|
||||
expect(requireRecord(requestLog[0], "debug request 0").model).toBe("gpt-5.5");
|
||||
expect(requireRecord(requestLog[1], "debug request 1").model).toBe("gpt-5.5-alt");
|
||||
expect(requireRecord(requestLog[0], "debug request 0").model).toBe("gpt-5.6-luna");
|
||||
expect(requireRecord(requestLog[1], "debug request 1").model).toBe("gpt-5.6-luna-alt");
|
||||
});
|
||||
|
||||
it("keeps remember prompts prose-only even when they mention repo cleanup", async () => {
|
||||
@@ -1133,7 +1133,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -1170,7 +1170,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: prompt }] }],
|
||||
}),
|
||||
});
|
||||
@@ -1182,7 +1182,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1201,7 +1201,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1219,7 +1219,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1240,7 +1240,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1277,7 +1277,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: prompt }] }],
|
||||
}),
|
||||
});
|
||||
@@ -1290,7 +1290,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1314,7 +1314,7 @@ describe("qa mock openai server", () => {
|
||||
const server = await startMockServer();
|
||||
const body = {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput("Read QA_KICKOFF_TASK.md, then answer with exactly QA-READ-OK.")],
|
||||
};
|
||||
|
||||
@@ -1336,7 +1336,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const undeclaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(SLACK_CHART_PROMPT)],
|
||||
});
|
||||
expect(
|
||||
@@ -1347,7 +1347,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const declaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [makeUserInput(SLACK_CHART_PROMPT)],
|
||||
});
|
||||
@@ -1356,7 +1356,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const afterToolPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(SLACK_CHART_PROMPT),
|
||||
@@ -1380,7 +1380,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const undeclaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(WHATSAPP_AGENT_REACT_PROMPT)],
|
||||
});
|
||||
|
||||
@@ -1392,7 +1392,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const unrelatedToolPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [READ_TOOL],
|
||||
input: [makeUserInput(WHATSAPP_AGENT_REACT_PROMPT)],
|
||||
});
|
||||
@@ -1405,13 +1405,13 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const declaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [makeUserInput(WHATSAPP_AGENT_REACT_PROMPT)],
|
||||
});
|
||||
const groupDeclaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [makeUserInput(WHATSAPP_GROUP_AGENT_REACT_PROMPT)],
|
||||
});
|
||||
@@ -1434,7 +1434,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const afterToolPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(WHATSAPP_AGENT_REACT_PROMPT),
|
||||
@@ -1464,7 +1464,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const undeclaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(WHATSAPP_AGENT_UPLOAD_PROMPT)],
|
||||
});
|
||||
|
||||
@@ -1476,13 +1476,13 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const declaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [makeUserInput(WHATSAPP_AGENT_UPLOAD_PROMPT)],
|
||||
});
|
||||
const groupDeclaredPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [makeUserInput(WHATSAPP_GROUP_AGENT_UPLOAD_PROMPT)],
|
||||
});
|
||||
@@ -1504,7 +1504,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const afterToolPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
tools: [MESSAGE_TOOL],
|
||||
input: [
|
||||
makeUserInput(WHATSAPP_AGENT_UPLOAD_PROMPT),
|
||||
@@ -1536,7 +1536,7 @@ describe("qa mock openai server", () => {
|
||||
]);
|
||||
const withStructuredHistory = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput([historyContext, WHATSAPP_PENDING_HISTORY_TRIGGER_PROMPT].join("\n\n")),
|
||||
],
|
||||
@@ -1546,7 +1546,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const triggerTextOnly = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
[
|
||||
@@ -1562,7 +1562,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const currentMessageOnlySentinel = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
[
|
||||
@@ -1585,7 +1585,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const currentPromptBeforeTrigger = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
[
|
||||
@@ -1607,7 +1607,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const contextWithoutCurrentTrigger = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(
|
||||
[historyContext, "openclawqa pending history context check without current trigger"].join(
|
||||
@@ -1625,7 +1625,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const mainPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeDeveloperInput("Runtime: agent=main | channel=whatsapp | capabilities=messageactions"),
|
||||
makeUserInput(WHATSAPP_BROADCAST_PROMPT),
|
||||
@@ -1633,7 +1633,7 @@ describe("qa mock openai server", () => {
|
||||
});
|
||||
const secondPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeDeveloperInput(
|
||||
"Runtime: agent=qa-second | channel=whatsapp | capabilities=messageactions",
|
||||
@@ -1643,7 +1643,7 @@ describe("qa mock openai server", () => {
|
||||
});
|
||||
const noIdentityPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeDeveloperInput("Runtime: channel=whatsapp | capabilities=messageactions"),
|
||||
makeUserInput(WHATSAPP_BROADCAST_PROMPT),
|
||||
@@ -1662,12 +1662,12 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const activationPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(WHATSAPP_ACTIVATION_ALWAYS_PROMPT)],
|
||||
});
|
||||
const unrelatedPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput("Group activation visible behavior marker WHATSAPP_QA_UNRELATED_TEST")],
|
||||
});
|
||||
|
||||
@@ -1680,17 +1680,17 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const seedPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(WHATSAPP_REPLY_TO_BOT_SEED_PROMPT)],
|
||||
});
|
||||
const triggerPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(WHATSAPP_REPLY_TO_BOT_TRIGGER_PROMPT)],
|
||||
});
|
||||
const unrelatedPayload = await expectResponsesJson(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput("Quoted implicit reply trigger marker WHATSAPP_QA_UNRELATED_TEST")],
|
||||
});
|
||||
|
||||
@@ -1717,7 +1717,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1754,7 +1754,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1795,7 +1795,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1839,7 +1839,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: prompt }] }],
|
||||
}),
|
||||
});
|
||||
@@ -1853,7 +1853,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1897,7 +1897,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: prompt }] }],
|
||||
}),
|
||||
});
|
||||
@@ -1911,7 +1911,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1943,7 +1943,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -1979,7 +1979,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: prompt }] }],
|
||||
}),
|
||||
});
|
||||
@@ -1993,7 +1993,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -2026,7 +2026,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: prompt }] },
|
||||
{
|
||||
@@ -2061,7 +2061,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -2091,7 +2091,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -2132,7 +2132,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(prompt),
|
||||
{
|
||||
@@ -2151,7 +2151,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
type: "function_call_output",
|
||||
@@ -2169,7 +2169,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(prompt),
|
||||
{
|
||||
@@ -4251,7 +4251,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4298,7 +4298,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4342,7 +4342,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4382,7 +4382,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput("Control UI bridge check. Marker exact marker: `ui bridge armed`"),
|
||||
{
|
||||
@@ -4431,7 +4431,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4478,7 +4478,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4534,7 +4534,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4564,7 +4564,7 @@ describe("qa mock openai server", () => {
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "mock-openai/gpt-5.5",
|
||||
model: "mock-openai/gpt-5.6-luna",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4651,7 +4651,7 @@ describe("qa mock openai server", () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: false,
|
||||
model: "gpt-5.5-alt",
|
||||
model: "gpt-5.6-luna-alt",
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
@@ -4721,7 +4721,7 @@ describe("qa mock openai server", () => {
|
||||
const body = (await response.json()) as { data: Array<{ id: string }> };
|
||||
const ids = body.data.map((entry) => entry.id);
|
||||
expect(ids).toContain("claude-opus-4-8");
|
||||
expect(ids).toContain("gpt-5.5");
|
||||
expect(ids).toContain("gpt-5.6-luna");
|
||||
expect(ids).toContain("gpt-4o-transcribe");
|
||||
});
|
||||
|
||||
@@ -5397,7 +5397,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const toolPlan = await expectResponsesText(server, {
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_REASONING_ONLY_RECOVERY_PROMPT)],
|
||||
});
|
||||
expect(toolPlan).toContain('"name":"read"');
|
||||
@@ -5407,7 +5407,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ type?: string; id?: string; summary?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_REASONING_ONLY_RECOVERY_PROMPT),
|
||||
{
|
||||
@@ -5428,7 +5428,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_REASONING_ONLY_RECOVERY_PROMPT),
|
||||
makeUserInput(QA_REASONING_ONLY_RETRY_INSTRUCTION),
|
||||
@@ -5452,14 +5452,14 @@ describe("qa mock openai server", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("scripts the GPT-5.5 thinking visibility switch prompts", async () => {
|
||||
it("scripts the GPT-5.6 Luna thinking visibility switch prompts", async () => {
|
||||
const server = await startMockServer();
|
||||
|
||||
const offPayload = await expectResponsesJson<{
|
||||
output?: Array<{ type?: string; content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_THINKING_VISIBILITY_OFF_PROMPT)],
|
||||
});
|
||||
expect(outputItem(offPayload).type).toBe("message");
|
||||
@@ -5474,7 +5474,7 @@ describe("qa mock openai server", () => {
|
||||
}>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_THINKING_VISIBILITY_MAX_PROMPT)],
|
||||
});
|
||||
const maxReasoning = outputItem(maxPayload);
|
||||
@@ -5486,7 +5486,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const maxStream = await expectResponsesText(server, {
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_THINKING_VISIBILITY_MAX_PROMPT)],
|
||||
});
|
||||
expect(maxStream).toContain('"type":"response.output_text.delta"');
|
||||
@@ -5500,7 +5500,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_THINKING_VISIBILITY_MAX_PROMPT),
|
||||
{
|
||||
@@ -5518,7 +5518,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const toolPlan = await expectResponsesText(server, {
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_REASONING_ONLY_SIDE_EFFECT_PROMPT)],
|
||||
});
|
||||
expect(toolPlan).toContain('"name":"write"');
|
||||
@@ -5528,7 +5528,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ type?: string; id?: string }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_REASONING_ONLY_SIDE_EFFECT_PROMPT),
|
||||
{
|
||||
@@ -5551,7 +5551,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
const toolPlan = await expectResponsesText(server, {
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_EMPTY_RESPONSE_RECOVERY_PROMPT)],
|
||||
});
|
||||
expect(toolPlan).toContain('"name":"read"');
|
||||
@@ -5560,7 +5560,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ type?: string; text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_EMPTY_RESPONSE_RECOVERY_PROMPT),
|
||||
{
|
||||
@@ -5577,7 +5577,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_EMPTY_RESPONSE_RECOVERY_PROMPT),
|
||||
makeUserInput(QA_EMPTY_RESPONSE_RETRY_INSTRUCTION),
|
||||
@@ -5595,7 +5595,7 @@ describe("qa mock openai server", () => {
|
||||
|
||||
await expectResponsesText(server, {
|
||||
stream: true,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [makeUserInput(QA_EMPTY_RESPONSE_EXHAUSTION_PROMPT)],
|
||||
});
|
||||
|
||||
@@ -5603,7 +5603,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_EMPTY_RESPONSE_EXHAUSTION_PROMPT),
|
||||
{
|
||||
@@ -5618,7 +5618,7 @@ describe("qa mock openai server", () => {
|
||||
output?: Array<{ content?: Array<{ text?: string }> }>;
|
||||
}>(server, {
|
||||
stream: false,
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
input: [
|
||||
makeUserInput(QA_EMPTY_RESPONSE_EXHAUSTION_PROMPT),
|
||||
makeUserInput(QA_EMPTY_RESPONSE_RETRY_INSTRUCTION),
|
||||
@@ -5634,9 +5634,9 @@ describe("qa mock openai server", () => {
|
||||
|
||||
describe("resolveProviderVariant", () => {
|
||||
it("tags prefix-qualified openai models", () => {
|
||||
expect(resolveProviderVariant("openai/gpt-5.5")).toBe("openai");
|
||||
expect(resolveProviderVariant("openai:gpt-5.5")).toBe("openai");
|
||||
expect(resolveProviderVariant("openai/gpt-5.5")).toBe("openai");
|
||||
expect(resolveProviderVariant("openai/gpt-5.6-luna")).toBe("openai");
|
||||
expect(resolveProviderVariant("openai:gpt-5.6-luna")).toBe("openai");
|
||||
expect(resolveProviderVariant("openai/gpt-5.6-luna")).toBe("openai");
|
||||
});
|
||||
|
||||
it("tags prefix-qualified anthropic models", () => {
|
||||
@@ -5646,8 +5646,8 @@ describe("resolveProviderVariant", () => {
|
||||
});
|
||||
|
||||
it("tags bare model names by prefix", () => {
|
||||
expect(resolveProviderVariant("gpt-5.5")).toBe("openai");
|
||||
expect(resolveProviderVariant("gpt-5.5-alt")).toBe("openai");
|
||||
expect(resolveProviderVariant("gpt-5.6-luna")).toBe("openai");
|
||||
expect(resolveProviderVariant("gpt-5.6-luna-alt")).toBe("openai");
|
||||
expect(resolveProviderVariant("gpt-4.5")).toBe("openai");
|
||||
expect(resolveProviderVariant("o1-preview")).toBe("openai");
|
||||
expect(resolveProviderVariant("claude-opus-4-8")).toBe("anthropic");
|
||||
@@ -5655,7 +5655,7 @@ describe("resolveProviderVariant", () => {
|
||||
});
|
||||
|
||||
it("handles case drift and whitespace", () => {
|
||||
expect(resolveProviderVariant(" OpenAI/GPT-5.5 ")).toBe("openai");
|
||||
expect(resolveProviderVariant(" OpenAI/GPT-5.6 Luna ")).toBe("openai");
|
||||
expect(resolveProviderVariant("ANTHROPIC/CLAUDE-OPUS-4-6")).toBe("anthropic");
|
||||
});
|
||||
|
||||
@@ -5678,7 +5678,7 @@ describe("qa mock openai server provider variant tagging", () => {
|
||||
|
||||
const openaiSourceServer = await startMockServer();
|
||||
const openaiSource = await expectResponsesJson(openaiSourceServer, {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [makeUserInput(sourcePrompt)],
|
||||
});
|
||||
@@ -5694,7 +5694,7 @@ describe("qa mock openai server provider variant tagging", () => {
|
||||
|
||||
const openaiHandoffServer = await startMockServer();
|
||||
const openaiHandoff = await expectResponsesJson(openaiHandoffServer, {
|
||||
model: "gpt-5.5",
|
||||
model: "gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [makeUserInput(handoffPrompt)],
|
||||
});
|
||||
@@ -5716,7 +5716,7 @@ describe("qa mock openai server provider variant tagging", () => {
|
||||
|
||||
const openaiFanoutServer = await startMockServer();
|
||||
const openaiFanout = await expectResponsesJson(openaiFanoutServer, {
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
stream: false,
|
||||
tools: [SESSIONS_SPAWN_TOOL],
|
||||
input: [makeUserInput(fanoutPrompt)],
|
||||
@@ -5752,7 +5752,7 @@ describe("qa mock openai server provider variant tagging", () => {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model: "openai/gpt-5.5",
|
||||
model: "openai/gpt-5.6-luna",
|
||||
stream: false,
|
||||
input: [{ role: "user", content: [{ type: "input_text", text: "Heartbeat check" }] }],
|
||||
}),
|
||||
@@ -5762,7 +5762,7 @@ describe("qa mock openai server provider variant tagging", () => {
|
||||
model: string;
|
||||
providerVariant: string;
|
||||
};
|
||||
expect(debug.model).toBe("openai/gpt-5.5");
|
||||
expect(debug.model).toBe("openai/gpt-5.6-luna");
|
||||
expect(debug.providerVariant).toBe("openai");
|
||||
});
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ type StreamEvent =
|
||||
* - Everything else (including empty strings) → `"unknown"`
|
||||
*
|
||||
* The `/v1/messages` route always feeds `body.model` straight through,
|
||||
* so an Anthropic request with an `openai/gpt-5.5` model string is still
|
||||
* so an Anthropic request with an `openai/gpt-5.6-luna` model string is still
|
||||
* classified as `"openai"`. That matches the parity program's convention
|
||||
* where the provider label is the source of truth, not the HTTP route.
|
||||
*/
|
||||
@@ -86,7 +86,7 @@ export function resolveProviderVariant(model: string | undefined): MockOpenAiPro
|
||||
return "anthropic";
|
||||
}
|
||||
// Fall back to model-name prefix matching for bare model strings like
|
||||
// `gpt-5.5` or `claude-opus-4-8`.
|
||||
// `gpt-5.6-luna` or `claude-opus-4-8`.
|
||||
if (/^(?:gpt-|o1-|openai-)/.test(trimmed)) {
|
||||
return "openai";
|
||||
}
|
||||
@@ -3237,7 +3237,7 @@ async function buildResponsesPayload(
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// The QA parity gate needs two comparable scenario runs: one against the
|
||||
// "candidate" (openai/gpt-5.5) and one against the "baseline"
|
||||
// "candidate" (openai/gpt-5.6-luna) and one against the "baseline"
|
||||
// (anthropic/claude-opus-4-8). The OpenAI mock above already dispatches all
|
||||
// the scenario prompt branches we care about. Rather than duplicating that
|
||||
// machinery, the /v1/messages route below translates Anthropic request
|
||||
@@ -3756,8 +3756,8 @@ export async function startQaMockOpenAiServer(params?: {
|
||||
if (req.method === "GET" && url.pathname === "/v1/models") {
|
||||
writeJson(res, 200, {
|
||||
data: [
|
||||
{ id: "gpt-5.5", object: "model" },
|
||||
{ id: "gpt-5.5-alt", object: "model" },
|
||||
{ id: "gpt-5.6-luna", object: "model" },
|
||||
{ id: "gpt-5.6-luna-alt", object: "model" },
|
||||
{ id: "gpt-image-1", object: "model" },
|
||||
{ id: "gpt-4o-transcribe", object: "model" },
|
||||
{ id: "text-embedding-3-small", object: "model" },
|
||||
|
||||
@@ -29,8 +29,8 @@ function createMockOpenAiResponsesProvider(baseUrl: string): ModelProviderConfig
|
||||
},
|
||||
models: [
|
||||
{
|
||||
id: "gpt-5.5",
|
||||
name: "gpt-5.5",
|
||||
id: "gpt-5.6-luna",
|
||||
name: "gpt-5.6-luna",
|
||||
api: "openai-responses",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
@@ -39,8 +39,8 @@ function createMockOpenAiResponsesProvider(baseUrl: string): ModelProviderConfig
|
||||
maxTokens: 4096,
|
||||
},
|
||||
{
|
||||
id: "gpt-5.5-alt",
|
||||
name: "gpt-5.5-alt",
|
||||
id: "gpt-5.6-luna-alt",
|
||||
name: "gpt-5.6-luna-alt",
|
||||
api: "openai-responses",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user