Skip to content

feat(copilot): add a sandboxed Copilot CLI agent server - #5082

Open
yaoyu-33 wants to merge 33 commits into
mainfrom
codex/copilot-agent
Open

yaoyu-33 wants to merge 33 commits into
mainfrom
codex/copilot-agent

Conversation

@yaoyu-33

@yaoyu-33 yaoyu-33 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Adds copilot_agent, a session-only Agent Server for GitHub Copilot CLI 1.0.103. Copilot runs inside the benchmark's task sandbox and sends BYOK Chat Completions through Gym's rollout-prefixed Model Server, including background and compaction calls. No GitHub account is required.

The adapter installs the pinned runtime with package-integrity verification and uses Gym's shared sandbox runner, supervisor and session lifecycle. The sandbox needs only bash and standard tools, not Python. It preserves task HOME, closes the agent before verification, and retains messages, reasoning, tool results, model-call references, usage when available, and sandbox execution evidence. Unsupported controls and required Resources tool grants are rejected. The conformance runner and agent catalogs are included. TB2.1 and SWE-bench Pro pairings remain experimental: their allowed_agents declarations have been removed pending full qualification and benchmark-owner review, and validation runs require --allow-unsupported-pairing. Benchmark prompts, data, and verifiers are unchanged.

Real runs exposed two strict Chat request incompatibilities: replayed annotations: null and client-only __copilotMessageSource on background tool results. Focused normalizers preserve content and call identity while continuing to reject other unsupported extras. Regressions reproduce both failures. Copilot's native telemetry also omits compaction usage; the adapter now reports unknown aggregate usage with an explicit gap instead of publishing a partial total. The adapter checks persisted native session events as well as the next-chat marker, covering late background compaction. Per-call counts remain in Gym Model Server captures.

The full run also exposed a native CLI parsing failure for a task prompt beginning with - . The adapter now binds the unchanged prompt to --prompt=; real-CLI red/green probes and session tests cover this. Native startup stderr is retained, bounded to 4,000 characters, before sandbox cleanup.

A real-model smoke on November 3 found that Copilot masks its BYOK provider secrets as ****** in every event it writes. The adapter had sent the short capture key as x-session-id and EMPTY as the API key, so recorded output masked them inside ordinary text. A timestamp 2026-11-03 became 2026-1******3 for capture key 1-0, losing tool timing; tool-call IDs containing 2-0 were rewritten; and model text was altered. The model itself saw the original text, and captures were unaffected. Each session now sends a random copilot-<hex> invocation ID as x-session-id (also used in close observations) and a random unused API key. The rollout ID stays in the Model Server URL.

Related: follows the add-harness workflow in #5074. A separate issue is unnecessary for this focused adapter.

Current review corrections at e69363b55 (November 6)

  • Root reasoning stays in its own turn; child conversations/tool events no longer contaminate root output. Child model-call references and usage remain retained; child conversations and tool observations are explicitly documented as not projected.
  • Normal and interrupted activations assemble the same observation gaps.
  • Recovered root session errors survive in the canonical failure report across activation, repeated activation and close, with stable event IDs and no terminal failure selection.
  • Failed provider cleanup cannot replace the original connect exception or its event ID/stage.
  • The retained-artifact checker accepts incomplete tools with absent/null output while still requiring output for terminal tools.
  • Removed premature benchmark declarations and corrected their documentation.
  • Merged main through 21027c9e9; the conformance setup preserves both Nooa's installer branch and Copilot's sandbox runtime setup.

Validation on the final tree:

  • python -m pytest responses_api_agents/copilot_agent/tests -q -o addopts='': 120 passed on Linux.
  • Adapter, retained-artifact checks, scripted-conformance tests, TB2.1 tests, conformance CI routing, Responses types and session contract: 943 passed, 15 skipped on macOS after the merge.
  • All 12 new adapter regressions fail against the previous adapter source; the 2 new incomplete-tool acceptance cases fail against the previous checker. Fixed suites pass.
  • Changed-file pre-commit (including import-linter), git diff --check, Fern check (0 errors, 1 warning) and DCO sign-off passed.
  • Current-source real-model TB2.1 regex-log smoke, Docker with NVIDIA NIM nvidia/nemotron-3.5-super-vl-120b-a12b, 300-second harness budget: reward 1.0, completed and unmasked; 11 model responses with no faults, health 1/1 passed, strict sandbox evidence fulfilled, profiling passed. Task sandbox and Gym listeners were removed.
  • This is one integration smoke, not full qualification. Concurrent background compaction support in the scripted model remains a separate follow-up; the native compaction conformance scenario was not repaired or rerun in this fix round.

Earlier update at 6c9a967bb

6c9a967bb reverts one line of 1f7c89bb5: the conformance episode again gives Copilot its default window in the
compaction scenario. With the 32k window Copilot compacts for real and sends its summary request in the background,
concurrently with the policy loop. The scripted conformance model answers strictly in sequence, so it refused those
requests and the whole context_compaction scenario failed (71 P1 checks) instead of the 3 known compaction-record
gaps. Serving concurrent background compaction is a conformance-model change for a separate PR.
scripts/harness_conformance/tests: 185 passed, 10 skipped; pre-commit passed.
Linux run_harness_conformance.py --harness copilot at 6c9a967bb: P0 fulfilled in 8/8 scenarios; 696 passed,
108 N/A, 3 failed (the known P1 compaction-record checks), the same as at ab1699750.

Linux results at 1f7c89bb5 (Docker host; the revert touches only the conformance episode):

  • gym env test +entrypoint=responses_api_agents/copilot_agent after root uv sync --locked: 108 passed.
  • run_harness_conformance.py --harness copilot: P0 fulfilled in 8/8 scenarios (625 passed, 111 N/A, 71 failed, all
    in the P1 context_compaction scenario fixed above).
  • TB2.1 real-model smoke (same five tasks and model as November 3, concurrency 1): 4/5. cancel-async-tasks
    failed test_tasks_cancel_above_max_concurrent, the same test as on November 3. 88/88 model calls returned 200,
    response usage equals the captures, no masked spans. Health: 5 passed, 0 flagged, 0 unobserved; strict
    --require-sandbox evidence fulfilled. Agent close finished 0.55–0.86 s before verification in every sandbox.
  • Bash-only install: none of the 112 adapter and Resources execs mentions Python. The regex-log image (Ubuntu
    24.04) has no python3, curl or wget; the installer added curl with apt-get and the task passed. No
    Alpine/BusyBox image was tried.

Update at 1f7c89bb5: Copilot runs with only bash in the task sandbox

The previous head needed the task image's Python for its installer, its runner and its compaction probe. The harness contract rules that out for a CLI harness, so Copilot now installs and launches the way the other CLI adapters do:

  • Bootstrap: only bash, installed as root with apk or apt-get when missing; otherwise seed refuses with a clear message.
  • Platform: one shell probe reports the OS, CPU and C library, and the Agent Server picks the npm platform package. A non-Linux sandbox, another CPU, or glibc older than 2.28 is refused at seed (422). Unreadable probe output and registry failures stay retryable (500).
  • Package: the Agent Server reads the tarball URL and sha512 from the registry through Gym's HTTP client, once per registry, package and version.
  • Install: the new install_copilot_runtime.sh takes flock when available, reuses only a runtime with its ready marker that passes a health check, downloads with curl or wget, checks the sha512, unpacks the binary with a private HOME, and publishes the staged directory atomically. Setup fails with the installer's output when it prints no runtime record.
  • Launch: Copilot runs through the shared harness_runner.sh with a params.sh. The Agent Server reads Copilot's persisted session events for compaction. sandbox_runner.py, install_copilot_runtime.py and their tests are removed.

Also in this commit:

  • Setup budget: the whole seed, including the start of an owned sandbox, is bounded by sandbox_install_timeout_seconds, so the owned sandbox's TTL holds.
  • context_window is the total window. Copilot's prompt limit is context_window minus max_output_tokens, and a validator rejects max_output_tokens >= context_window. The TB2.1 README row is now context_window: 32768 with max_output_tokens: 8192, the same 24576-token prompt limit as before. A config that set context_window as a prompt limit now gets a prompt limit smaller by max_output_tokens.
  • Usage: aggregate usage stays unknown when the telemetry file has an unreadable line, with a model_usage_telemetry_malformed gap. The unused --usage-output-file is dropped.
  • Prompt: a prompt that cannot be one command-line argument (a NUL byte, or 128 KiB) gets 422.
  • Declarations: Copilot joins allowed_agents in the TB2.1 benchmark recipe (terminal_bench_2_1_benchmark.yaml), which test_nooa_terminal_bench_2_1.py requires. (This commit also added Copilot to the conformance episode's compaction settings; 6c9a967bb reverts that.)
  • Docs: the adapter README lists the sandbox prerequisites and notes that SWE-bench Pro tasks with a task_network_policy cannot install Copilot, because the sandbox downloads it from npm.

Checks on macOS. Each fix was reverted once, and its tests failed.

  • responses_api_agents/copilot_agent/tests: 108 passed (73 before). The installer tests run real bash with an isolated PATH, no python3, a fake curl and a fake tarball. The fake sandbox asserts that no command contains python.
  • benchmarks/terminal_bench_2_1/tests: 16 passed, 1 skipped.
  • tests/unit_tests/core/test_responses_api_types.py 271, test_public_api_facades.py 803, tooling/test_add_legacy_agent_environment_servers.py 119, tooling/test_harness_conformance_ci.py 58, tooling/test_migrate_imports.py 55 and test_session_contract_repo.py 2: all passed.
  • scripts/harness_conformance/tests: 185 passed, 10 skipped.
  • pre-commit run --files <the changed files> and DCO sign-off: passed.
  • Not run on macOS: a real Linux sandbox or Copilot download. The Linux results above cover that, except BusyBox/Alpine behavior of sha512sum, tar, flock and env -i.

Update at ab1699750

This head merges main through c0a069705. The only conflict was in scripts/harness_conformance/ci.py; the resolution
keeps main's locked uv sync install and keeps Copilot among the harnesses that install their runtime in the task sandbox.
Two adapter changes follow from #4837 and later moves:

  • d8ec05d35: requirements.txt is replaced by pyproject.toml and uv.lock. Copilot's requirement was the same as Pi's,
    so the project mirrors Pi's and the lock is Pi's with only the project name changed. uv lock --check passes.
  • ab1699750: the test imports NgFailureEvent from nemo_gym.core, where main now exports it.

Checks:

  • Local: 1842 passed, 10 skipped. This covers the adapter tests, test_session_contract_repo.py,
    test_public_api_facades.py, config/test_global_config.py and core/test_responses_api_types.py, plus tooling/
    (composition, component dependencies, conformance CI and checks), cli/ (locked env, component compatibility,
    server config validation) and scripts/harness_conformance/tests.
  • Linux: gym env test +entrypoint=responses_api_agents/copilot_agent, which now builds the server environment with
    uv sync --locked: 73 passed.
  • Conformance: P0 verdict fulfilled, with all nine artifact gates fulfilled. 696 checks passed, 108 N/A and 3 failed.
    The three failures are all P1 checks in context_compaction, a scenario new on main (compaction.event,
    compaction.helper_references, compaction.summary_reuse). They need compaction records, which the adapter has
    always reported as the compaction_observations_unavailable gap.
  • pre-commit run --files <changed files> and DCO sign-off: passed. Real-model smokes were not rerun for this merge.

Validation at be384a24d

The head merges main through 11b28add6 with no conflicts. Since the last tested head (e9a1e9cfe), main moved the agent,
rollout, orchestration, eval and environment modules and added causal failure reports (#5072). Adapter changes since then:

  • 902e3ca45: the provider-secret masking fix above, with the regression test test_provider_secrets_cannot_mask_task_text.
    The test fails with the previous header and key values.
  • 7482fbc28: since feat(eval): report causal failures across service boundaries #5072, the agent route raises an NgFailureEvent whose cause is the adapter's RuntimeError.
    test_native_startup_error_preserves_bounded_stderr now checks the bounded stderr on that cause.

Checks on Linux at 7482fbc28. be384a24d adds only the merge of #5527, #5530 and #5525.

  • gym env test +entrypoint=responses_api_agents/copilot_agent: 73 passed.
  • Core and contract tests: 1608 passed, 10 skipped. They are tests/unit_tests/test_session_contract_repo.py,
    test_add_legacy_agent_environment_servers.py, core/test_responses_api_types.py, test_ci_environment.py,
    config/test_global_config.py, test_harness_conformance_ci.py, test_harness_conformance_checks.py,
    test_public_api_facades.py and scripts/harness_conformance/tests.
  • python scripts/run_harness_conformance.py --harness copilot --output <new-dir>: verdict fulfilled. All eight scenarios
    pass, including verifier_failure, which is new on main: 603 checks passed, 101 N/A, zero failures, and all eight
    artifact gates fulfilled.

At be384a24d, 1868 focused tests pass locally (adapter, session contract, public API, Responses types, vllm_model).
pre-commit run --files <changed files> and DCO sign-off pass. CI for this head was started with /ok to test.

Real-model smoke (November 3)

All three attempts ran before the bash-only runtime in 1f7c89bb5.

  • Model: nvidia/nemotron-3.5-super-vl-120b-a12b on NVIDIA NIM (integrate.api.nvidia.com), through Gym's vLLM Model
    Server (Chat Completions). Temperature 1.0, top-p 0.95 and max_tokens 32768 are set on the Model Server.
  • Copilot 1.0.103, with context_window 131072, max_output_tokens 32768 and timeout 900.
  • Docker provider on a Linux host, with Resources-owned task sandboxes and single_agent_turn (resources_tool_transports: []).
    Model-call capture is enabled.
  • The five TB2.1 tasks from the October smoke, at task source 7131e4375048a0e408a8fb404b5f499d726b695b, with rows
    byte-identical to that run: regex-log, cancel-async-tasks, db-wal-recovery, fix-code-vulnerability and
    git-multibranch.
  • No --allow-unsupported-pairing was needed, because this branch declares Copilot.
Attempt / source Reward Model calls Health Strict evidence (--require-sandbox)
1 / tree of 70af8e1b0 4/5 84, all HTTP 200 5 healthy, 0 unhealthy, 0 unobserved fulfilled 5/5
2 / tree of 70af8e1b0, two tasks 2/2 8, all HTTP 200 2 healthy fulfilled 2/2
3 / 7482fbc28 3/5 87, all HTTP 200 5 passed, 0 flagged, 0 unobserved fulfilled 5/5
  • All rows: every row has evaluation_completed: true and mask_sample: false, and the failures sidecar is empty.
    Response usage equals the summed model-call captures on every row, and strict profiling covers every row.
  • Zero grades: each is a verifier-graded task failure. In attempt 1, cancel-async-tasks failed
    test_tasks_cancel_above_max_concurrent. In attempt 3, db-wal-recovery failed 2 of 7 tests and
    fix-code-vulnerability failed test_cwe_id.
  • Masking: attempts 1–2 found the defect. In attempt 2, regex-log had 24 masked spans across response.output,
    ng_trajectory and ng_agent_observations, and cancel-async-tasks lost tool timing. Attempt 3 has no masked spans,
    apart from a tool output in which the agent printed Copilot's own environment, and no tool_timing_unavailable gaps.
  • Close before verify: recorded Docker events show Copilot's session-directory removal, which ends agent close,
    finishing 0.56–0.89 s before the verifier uploads /tests and runs test.sh. Resources then kills and removes the
    container. This is measured for every sandbox in attempts 2–3 and three of five in attempt 1, where the daemon's
    event buffer dropped the first two. Every owned sandbox was removed.

Commands: gym env resolve, gym env validate, gym env start, then
gym eval run --no-serve --config run.yaml --input tasks.jsonl --output rollouts.jsonl --limit 5 --num-repeats 1 --concurrency 1.
After collection: gym eval health-check <run-dir> --model-call-capture-dir <run-dir>/model-calls,
scripts/inspect_harness_conformance.py --bundle <rollouts.jsonl> --capture-dir <model-calls> --output <evidence> --require-sandbox
and gym eval profile.

Limits and remaining work

  • Unsupported: host execution, Resources tool grants and training-token capture.
  • Documented gaps: subagent hierarchy, native compaction observations (so the P1 context_compaction checks fail), and aggregate usage after observed compaction.
    Timed-out tools keep an incomplete status and can have no output; the retained-artifact checker now accepts that representation. Other unavailable evidence remains explicit.
  • The only full TB2.1 run is the October single-repeat run below (53/89, source 475b7c902). The add-harness full
    evaluation (all tasks × 8 repeats) has not been run on this head.
  • The real-model runs below predate the bash-only runtime; the November 5 Linux smoke at 1f7c89bb5 (above) covers it.
    Alpine/BusyBox images are still untested.
  • The sandbox still downloads Copilot from npm, so networks that block the registry cannot install it. Rollout stop and
    ContextCompactionObservation records are not supported.
  • Benchmark-owner review of the TB2.1 and SWE-bench Pro allowed_agents additions is still pending.
Evidence at earlier heads (October 26–27; not rerun)

Validation at earlier heads

Current source: e9a1e9cfe48ef465f6d359c0da54aa25d728ade7. It merges current main into 709cbc7077625ca14e4a74fce4523bf6205fc912 and adds the review fixes below. The full benchmark is pinned to 475b7c902a6e3394e32f0d841597432bbe4aa997; later commits repair compaction usage reporting, startup diagnostics, and leading-dash prompt argument handling, and declare tested pairings. The original benchmark artifacts remain unchanged, and final-source diagnostic runs are reported separately. The real-model evidence below predates the review fixes and was not rerun.

Review fixes at e9a1e9cfe

  • Merge with main: fix(agents): hide the sandbox supervisor and runners from pkill python #4805 renamed the uploaded supervisor, which broke 17 Copilot tests. The runner now uploads as RUNNER_FILE with stdlib_runner=True, so a task's pkill python3 cannot stop it.
  • Legacy relay migration: test_add_legacy_agent_environment_servers.py::test_repository_configs failed on copilot_agent.yaml. Copilot is now exempt, like Stirrup, with a composition regression test.
  • Response status: only errors that end Copilot's own run fail the response, matching 1.0.103's exit rule (pyo() in cli-main.js). Sub-agent errors, hook errors, and a model_call error followed by a root assistant message no longer do.
  • Usage coverage: usage stays unknown (model_usage_spans_missing) when an event's response ID has no chat span. Model-call references are the union of span and event IDs, and span-only background calls still count.
  • Annotations on replay: annotations: [] is now dropped like null; non-empty annotations still fail validation.
  • Usage gaps:
    • Compaction alone no longer adds a false partial_model_usage_unavailable.
    • native_compaction_state_unavailable is renamed compaction_state_unavailable.
  • Docs:
    • TB2.1 lists Copilot in its intro and cap notes. Its context_window example is now 24576, because Copilot's setting is a prompt limit and needs room for 8192 output tokens.
    • The harness table says training-token capture is not wired up.

Checks at e9a1e9cfe

  • CI copilot conformance probes: all seven scenarios exercised; 535 checks passed, 74 N/A, zero failures, including main's structured model-failure outcome check. The job's 434 adapter and shared tests passed.
  • CI lint, DCO, copyright, guardwords, secret scan, and Server suite shards 0-7 pass. The core Unit tests / Test job was still running when this section was updated. The non-blocking Kilocode probe and conformance Publish check also fail on main (20be8ee8d).
  • Local offline runs (macOS) passed:
    • Copilot tests: 72 passed
    • tests/unit_tests/test_openai_utils.py: 335 passed
    • tests/unit_tests/test_add_legacy_agent_environment_servers.py: 62 passed
  • Local full tests/unit_tests: no new failures. All 50 local failures (macOS environment and optional packages) also fail on a clean main worktree.
  • Each new regression failed before its fix and passed after it: runner opt-in, session-error filtering, missing spans, compaction gaps, and empty annotations.
  • pre-commit run on the changed files and DCO sign-off: passed.

Earlier checks at 709cbc707

  • Linux gym env test +entrypoint=responses_api_agents/copilot_agent +skip_venv_if_present=true: 62 passed, one dependency warning.
  • Fresh Linux python scripts/run_harness_conformance.py --harness copilot --output <new-dir> after the final prompt fix: all seven scenarios exercised and fulfilled; 535 checks passed, 74 N/A, zero failures. No checker was weakened.
  • Shared schema, base Model Server, vLLM, and Copilot regression suite at 6ef8717dd: 819 passed, one dependency warning.
  • Session-contract/harness-capability/conformance-registration checks: 286 passed; config/checkpoint/episode checks: 328 passed.
  • pre-commit run --all-files, diff checks, and DCO sign-off passed. Fern check: zero errors, one warning.
  • Controlled native compaction probe: reproduced a missing 137 input / 17 output tokens before repair. After repair, all four calls remain captured, the strict sandbox artifact check is fulfilled, and health reports zero unhealthy / one unobserved aggregate. This explicitly documents the native telemetry limit; it does not claim exact native totals.

Real-model evidence at earlier heads

Nemotron 3.5 Super GA, context 262144, per-call output limit 32768, temperature 1.0, top-p 0.95. Gym Environment Server coordinates Resources-owned OpenSandbox task containers. Model-call capture is enabled. Typed task identities, original prompts, and stock verifiers are retained.

Full sandboxed TB2.1: 53/89 successful tasks (59.55%), from 53 passes, 35 stock zero grades, and one unavailable grade. All 89 original task/rollout identities were attempted once and audited; 88 graded rows are completed/unmasked, with zero identity errors. The graded-only rate is 53/88 (60.23%), which is not the headline denominator.

The unavailable task, pytorch-model-recovery, exited before any model call because of the leading-dash CLI parsing bug. After repair, a separate final-source sandbox run passes all five stock verifier tests: reward 1, nine successful model calls, nine tools, healthy, strict artifact/profile checks passed. This diagnostic is excluded from the original 89-task score.

Full-run model capture contains 2,780 HTTP-200 calls and two deadline cancellations. All 137 requests carrying the background-tool client marker succeeded. Original rollout health: 78 healthy / 7 unhealthy / 3 unobserved. Five unhealthy rows have exact compaction-token deficits covered by the reporting fix; two end on cancelled model calls. Three interrupted rows retain unknown aggregate usage. Original artifacts are unchanged.

The strict retained-artifact audit is not fulfilled on 8/88 rows: six have interrupted native tools with no terminal result (tools.status, tools.output), and two cancelled calls have no policy response/HTTP status (steps.attempt_accounting). The checker exempts unbound HTTP errors with status >=400, but not these cancelled attempts. No result, turn, or status was fabricated and no checker was weakened. Strict full-coverage profiling also fails because the startup failure has no grade; a separately labeled partial profile covers 88/89. These limits are separate from the passing seven-scenario scripted conformance suite.

All 12 exact full-run sandbox scopes were re-listed empty; the owned model allocation is stopped and temporary task credential copies are removed. The earlier interrupted 17-task attempt is retained separately and excluded. A 16-task group hit a port collision before collection; startup-only recovery used identical source/input/budgets/identities and preserved concurrency, with no duplicate task attempts. Failed source-staging/import checks also occurred before any model attempt and are retained separately.

Completed pairing / source Result Evidence
TB2.1 final-source regression, pytorch-model-recovery / 709cbc707 1/1; all 5 stock tests passed 9 model calls, 9 tools; healthy; strict artifact/profile passed; isolated source/venv verified; cleanup complete
TB2.1 deployment smoke, regex-log / 475b7c902 1/1, completed and unmasked Healthy; strict sandbox artifact check fulfilled; strict profile passed; cleanup completed
SWE-bench Pro Ansible / 243cf625d 1/1; all 175 required tests passed 57 model calls, 72 tools; healthy; strict sandbox artifact check fulfilled; configuration-only benchmark swap; cleanup completed

Pinned TB task source: 7131e4375048a0e408a8fb404b5f499d726b695b. SWE-Pro dataset: 7ab5114912baf22bb098818e604c02fe7ad2c11f; evaluator: ca10a60a5fcae51e6948ffe1485d4153d421e6c5; task image digest: sha256:a2ea931d3b4a4ca9d19cf4577f1f97b970553f459fedb13a18ed01c804d88ace.

Pairing commands exercised: gym env resolve, gym env validate, gym env start, gym eval run --no-serve ... --allow-unsupported-pairing, gym eval health-check <run-dir>, and scripts/inspect_harness_conformance.py --bundle <rollouts.jsonl> --capture-dir <model-calls> --output <evidence> --require-sandbox. Full-run resources use Gym defaults of 4 CPUs, 16 GiB RAM, and 30 GiB storage; this is not a claim that every optional task-specific resource hint is matched.

Host execution, Resources tool grants, and training-token capture are unsupported. Subagent hierarchy, native compaction observations, and aggregate usage after observed compaction remain documented gaps. The full run's original compaction health findings are preserved separately from stock verifier grades. Timed-out tools retain incomplete status and absent native results; those partial rollouts can be graded but do not fulfill the strict tool-evidence checks.

🤖 Generated with Claude Code

Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 26, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@svcnvidia-nemo-ci svcnvidia-nemo-ci added area:agent Agent harnesses and Responses API agent behavior feature New capabilities, enhancements, or enablement work labels Oct 26, 2026
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
@yaoyu-33
yaoyu-33 requested a review from a team October 26, 2026 20:27
@yaoyu-33
yaoyu-33 marked this pull request as ready for review October 27, 2026 17:56
@svcnvidia-nemo-ci svcnvidia-nemo-ci added the needs-review PR is ready for code review and waiting on a reviewer label Oct 27, 2026
yaoyu-33 and others added 3 commits October 27, 2026 14:01
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Main now runs the shared supervisor as gym-supervisor from a file
without a .py suffix (#4805), and the Copilot test fake still matched
process_supervisor.py, so 17 tests failed after merging main.

Opt the Copilot runner in the same way as Pi, Codex, OpenCode and
OpenClaw: upload it as sandbox_runner and set stdlib_runner, so a task
agent's pkill -f python3, pkill python3 or killall python3 cannot stop
the runner and end the episode. The post-run compaction probe uses the
same file. The session fake now asserts the runner launches as
bin/gym-runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Aggregate usage was summed over Copilot's OpenTelemetry chat spans
alone, and model-call references came from the spans whenever any
existed. If the file exporter lost a span, for example when Copilot
stopped before flushing, the response published a subtotal as the
total and dropped that call's reference without a gap.

Treat any response ID from Copilot's events that has no chat span as
missing coverage: usage stays unknown with a model_usage_spans_missing
gap, and model-call references are the spans' IDs plus any event-only
IDs. The provider-error test now carries the span for its first,
successful call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>

@svcnvidia-nemo-ci svcnvidia-nemo-ci left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SHIP WITH CARE — one RISK: partially retained native telemetry can be published as complete token accounting and discard observed model-call references.

Reviewed all 23 changed files and their directly affected lifecycle, model-request, observation, and conformance paths. The sandbox ownership, request-rejection, runtime-installation, and shared-schema changes otherwise showed no qualifying issues. The documented compaction and interruption limits are explicit; the finding below concerns additional evidence loss despite response IDs already being retained.

Static review only. Tests and native CLI probes were not executed, and the PR’s reported real-model results were not independently reproduced.

Review generated by codex. This was a full review. Request a full review with /review reset=true.

yaoyu-33 and others added 6 commits October 27, 2026 14:22
copilot_agent.yaml binds resources_server: null and Copilot has no
compatibility /run, but the migration script did not know the agent
type, so `--check` reported a legacy relay to add and
test_repository_configs failed.

Exempt Copilot the same way as Stirrup, and add a regression test that
the default config composes with exactly one session Environment Server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Every session.error became the response error, so a run whose root
agent finished with a final message came back failed, and the default
outcome policy retried or failed it. Copilot 1.0.103's own exit status
ignores errors from sub-agents (agentId, data.agentId or
data.parentToolCallId), hook errors, and a model_call error that a
later root assistant message recovers from (cli-main.js pyo() and its
session status tracker). Apply the same rule; an unrecovered root
model_call error still fails and stays classified.

Also correct two usage gaps:
- Observed or unreadable compaction no longer adds
  partial_model_usage_unavailable ("a model call reported no usage"),
  which was false when every chat span reported usage.
- Rename native_compaction_state_unavailable to
  compaction_state_unavailable, following the AGENTS.md naming rule
  before the code reaches retained rollouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
The replay normalizer dropped assistant annotations only when null. The
openai SDK types Chat Completion annotations as an optional list, and
the OpenAI Model Server passes the upstream message through, so a
provider that returns "annotations": [] made Copilot's next request
fail strict validation with a 422. An empty list carries no citation, so
drop it too; non-empty annotations still fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
- TB2.1: list Copilot in the intro and in the per-call cap and
  request-level max_output_tokens sentences, both of which apply to it.
- TB2.1: Copilot's context_window is a prompt-token limit, so the 32k
  smoke example now leaves room for max_output_tokens (24576 + 8192).
  The adapter README says how to choose it.
- Integrate Existing Agents: training-token capture is not wired up for
  Copilot, matching the other adapters' wording and its README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
The runner drains Copilot's stdout after Copilot exits without waiting
for EOF, because a tool that starts a service can inherit the pipe. Lock
that in with real processes: a fake Copilot leaves a sleeping child that
holds stdout and ends with an event that has no trailing newline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Usage coverage requires a span for every response that Copilot's events
report, not equal ID sets. Lock in that background calls, which have
chat spans but no assistant event, still add their counts and model-call
references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
@yaoyu-33

Copy link
Copy Markdown
Contributor Author

/ok to test e9a1e9c

@nemo-automation-bot
nemo-automation-bot Bot requested review from a team October 27, 2026 19:13
@@ -0,0 +1,168 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Install the pinned Copilot CLI binary inside a task sandbox, outside the task repository.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a way we can do this install without relying on Python? Not all task sandboxes come with Python. For SWE-Together I cached the harness from Gym side and then transferred it to a shared storage that the task mounted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 1f7c89b: the sandbox no longer needs Python. The Agent Server probes the OS, CPU and C library with one shell command, picks the npm platform package and reads its tarball URL and sha512 from the registry; install_copilot_runtime.sh then downloads and checks it with curl or wget (installing bash or curl only as root with apk or apt-get), and Copilot runs through the shared harness_runner.sh. install_copilot_runtime.py and sandbox_runner.py are gone.

One difference from your SWE-Together setup: the sandbox still fetches the package from npm itself. Fetching it on the Gym side and uploading it (or mounting a shared cache) would remove that network dependency; I would leave that for a follow-up.

yaoyu-33 and others added 3 commits November 4, 2026 19:12
Resolves the conflict in scripts/harness_conformance/ci.py: keep main's locked
`uv sync` install from #4837 and keep Copilot in the harnesses that provision
their runtime in the task sandbox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
…uv.lock

#4837 replaced server requirements.txt files with committed uv projects and
forbids requirements.txt. Copilot's requirement was the same as Pi's
(nemo-gym[dev,sandbox] from the repository), so its pyproject.toml mirrors Pi's
and its lock is Pi's with only the project name changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Main moved typed_exceptions into nemo_gym.core, which exports NgFailureEvent
from its public API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
@yaoyu-33
yaoyu-33 requested a review from a team as a code owner November 5, 2026 03:37
@yaoyu-33

yaoyu-33 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test ab16997

Copilot required the task image's Python for its installer, its runner and
its compaction probe, which the harness contract rules out for a CLI harness.
Install and launch it the way the other CLI adapters do:

- Bootstrap only bash, as root with apk or apt-get, or refuse clearly.
- Probe the OS, CPU and C library with one shell command and select the npm
  platform package on the Agent Server. A non-Linux sandbox, another CPU or
  glibc older than 2.28 is refused at seed (422); other probe output and
  registry failures stay errors to retry (500).
- Read the package's tarball URL and sha512 from the registry on the Agent
  Server, once per registry, package and version.
- Install with install_copilot_runtime.sh: flock when available, reuse only a
  runtime with its ready marker that passes a health check, download with
  curl or wget, check the sha512, unpack the binary with a private HOME, and
  publish the staged directory atomically.
- Launch Copilot through the shared harness_runner.sh with params.sh, and
  read the persisted session events for compaction on the Agent Server.
- Remove sandbox_runner.py, install_copilot_runtime.py and their tests.

Also:
- Bound the whole seed by sandbox_install_timeout_seconds, so the owned
  sandbox's TTL holds.
- Fail setup with the installer's output when it prints no runtime record.
- Treat context_window as the total window: Copilot's prompt limit is
  context_window minus max_output_tokens, which must be smaller.
- Keep aggregate usage unknown when the telemetry file has an unreadable
  line, with a model_usage_telemetry_malformed gap.
- Reject a prompt that cannot be one command-line argument (NUL, 128 KiB).
- Drop the unused --usage-output-file.
- Declare Copilot in the Terminal-Bench 2.1 benchmark config, add it to the
  conformance compaction settings, and update the READMEs.

Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaoyu-33

yaoyu-33 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 1f7c89b

…ance scenario

The previous commit gave Copilot the 32k compaction window in the
conformance episode. Copilot then compacts for real: it sends its summary
request in the background, concurrently with the policy loop, and the
scripted conformance model answers strictly in sequence, so it refuses
those requests and the whole context_compaction scenario fails (71 P1
checks instead of the 3 known compaction-record gaps). Restore Copilot's
default window there until the scripted model can serve concurrent
background compaction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
@yaoyu-33

yaoyu-33 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 6c9a967

Comment thread scripts/harness_conformance/episode.py Resolved

@giuliolovisotto giuliolovisotto left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two failure-evidence follow-ups below, separate from the existing conformance and benchmark-qualification discussion. Recovered errors should remain observable without failing a successful result; cleanup should preserve the original failure. An extracted-parser probe reproduced recovered-error loss; the cleanup finding is from source inspection. No new native Copilot rollout or adapter test-suite run was performed.

— @codex

Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>

This branch was previously deployed

1 inactive (outdated) deployment
public — 6c9a967b Deployed Nov 5, 2026 by copy-pr-bot[bot] via release / finalize / notify #10446
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent Agent harnesses and Responses API agent behavior feature New capabilities, enhancements, or enablement work needs-review PR is ready for code review and waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants