Agent coding integration - #295
Open
guillaume-byte wants to merge 10 commits into
Open
Conversation
…zily on the first tick) and guarded by a lock, and add message/messages endpoints so a loop's monitoring chat can be read from and written to directly -- backing weights_studio's new per-loop chat tabs, where a running check-in and a manual message must never race on the same session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
signal_history[::step] always starts at index 0, so a fixed-length run (e.g. exactly 10000 steps) lost its last few points once cap-downsampled. Reuse the existing _downsample_uniform helper, which preserves the first and last point, matching the break_by_slices path a few lines above.
Covers 653bc57: a 10000-point history downsampled to max_points=1000 must still include model_age 9999. Verified this test fails against the old signal_history[::step] slice (max 9990) and passes with _downsample_uniform.
… add a data-query bridge endpoint, track detached launches for workspace-lifecycle cleanup, and fix a NB_SEEN double-counting bug - New weightslab/opencode_process.py: a cross-process lock-file handshake (a .wl_opencode.json dropped in the experiment's own workspace directory) so the backend SDK agent (agent.py's DataManipulationAgent, via OpenCodeChat._ensure_reachable) and the UI server's _OpencodeSession converge on ONE OpenCode server regardless of which one needs it first -- previously this required a human to manually export OPENCODE_URL into both processes' environments before starting either. Two separate sessions on that one server, not a merged conversation -- the two sides send incompatible message shapes (structured-JSON/no-tools vs. free-form/full-tools) that would otherwise cross-contaminate context. - New POST /agent-server/data-query: lets the landing-page agent chat perform dataset/model actions (discard, tag, sort, filter, analyze, compute stats, ...) itself, by calling the same ApplyDataQuery RPC the (now-merged, see weights_studio) query bar always used -- same safety guarantees, just a different caller. - New POST /agent-server/track-process + _TrackedProcesses: a DETACHED launch (Start-Process/setsid) has no OS-level tie to this workspace's own process tree -- the intermediate shell that runs Start-Process exits almost immediately afterward, breaking the PID/PPID chain a tree-kill from further up would need to walk. The agent now registers a launched PID directly, killed by this server explicitly (no chain needed) on its own shutdown -- so Ctrl+C on `weightslab start` stops training too, without the agent ever blocking to wait for it. - weightslab/src.py, weightslab/data/dataframe_manager.py: fixed NB_SEEN never actually accumulating across save_group_signals/enqueue_batch calls -- each call built its `updates`/buffered record from scratch, so the existing "0 if not already in updates else +1" logic always read 0. Now reads the running count from the ledger (or an unflushed buffered write, if more recent) before incrementing. Verified: 410/410 passing across tests/ui/, tests/trainer/services/, and three new test files (61 skipped -- gated live-model tests). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… SIGTERM/SIGHUP and Windows console-close/logoff/shutdown events Ctrl+C (SIGINT) was the only termination path weightslab start's cleanup (stopping tracked detached processes, its own OpenCode/Jupyter children, /loop jobs) ever ran on, since Python turns SIGINT into a catchable KeyboardInterrupt automatically but does nothing equivalent for SIGTERM/SIGHUP (a bare `kill`, or closing a POSIX terminal) or Windows' CTRL_CLOSE_EVENT/CTRL_LOGOFF_EVENT/CTRL_SHUTDOWN_EVENT (closing the console window, logging off, a system shutdown) -- confirmed against real platform signal-handling behavior, not assumed. A DETACHED training launch tracked via /agent-server/track-process would have outlived exactly those cases. - SIGTERM/SIGHUP are now re-raised as KeyboardInterrupt, so they run through the exact same try/except/finally serve_ui() already had for Ctrl+C -- no second, duplicate cleanup path. - The three Windows console-control events have no `signal`-module equivalent at all (that only covers CTRL_C_EVENT/CTRL_BREAK_EVENT); a native SetConsoleCtrlHandler registration via ctypes catches them instead, no new dependency needed. - Both installed only for serve_ui(block=True) -- the real interactive CLI path Ctrl+C already covered, not the embedded/background-thread case, which should keep owning its own signal handling. - The four independent shutdown() calls (tracked processes, OpenCode session, loop registry, Jupyter session) are now one shared _run_shutdown_cleanup(), used by both the explicit `finally` block and the new handlers -- previously two of the four only ran via atexit. Verified: 419/419 passing (63 skipped -- gated live-model tests, SIGHUP on Windows where it doesn't exist, and the one SIGTERM end-to-end test that only makes sense on POSIX, where a self-SIGTERM is a real signal rather than Windows' TerminateProcess-mapped emulation). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR switches WeightsLab’s agent backend integration from direct OpenRouter/Ollama-style onboarding to a unified OpenCode-backed architecture, so both the backend SDK agent and the UI/landing-page agent converge on the same local OpenCode server per workspace. It also improves signal-history downsampling correctness and fixes NB_SEEN bookkeeping by incrementing from the ledger rather than resetting each call.
Changes:
- Introduces an OpenCode HTTP+SSE client (
OpenCodeChat) and a shared server discovery/spawn handshake (opencode_process.py) to ensure the SDK agent and UI reuse one OpenCode server per workspace. - Updates proto/API surface and CLI/docs/tests to reflect OpenCode as the only supported agent backend (with legacy enum compatibility retained).
- Fixes logger downsampling to always retain the latest point, and corrects NB_SEEN increments for samples/groups.
Reviewed changes
Copilot reviewed 40 out of 41 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| weightslab/trainer/services/utils/tools.py | Adds provider mapping for PROVIDER_OPENCODE while keeping legacy OpenRouter enum value for wire compatibility. |
| weightslab/trainer/services/experiment_service.py | Replaces fixed-stride downsampling with uniform endpoint-preserving downsampling. |
| weightslab/trainer/services/data_service.py | Updates agent availability docstring to OpenCode. |
| weightslab/trainer/services/agent/opencode_chat.py | New: OpenCode client wrapper (session/message/SSE) with mutating tools disabled for SDK agent calls. |
| weightslab/trainer/services/agent_service.py | Updates onboarding/model docs + adds history/context RPC handlers (and new agent backend expectations). |
| weightslab/src.py | Fixes group NB_SEEN to increment from ledger state instead of resetting. |
| weightslab/proto/experiment_service.proto | Adds OpenCode provider enum + new agent history/context RPCs and response messages. |
| weightslab/opencode_process.py | New: lockfile-based resolve/spawn so UI + backend share one OpenCode server per workspace. |
| weightslab/data/dataframe_manager.py | Adds helpers to read per-sample/per-group column values to support NB_SEEN increments. |
| weightslab/backend/cli.py | Updates CLI agent commands to OpenCode (no API key; model strings now provider/model). |
| weightslab/AGENTS.md | New: ships agent/debugging guide inside the package for workspace seeding and preset prompts. |
| tests/ui/test_server_tracked_processes.py | New: tests tracked detached-process registry + endpoint. |
| tests/ui/test_server_shutdown_signals.py | New: tests termination handler coverage and cleanup behavior. |
| tests/ui/test_server_loop.py | New: tests /loop registry and HTTP endpoints with mocked OpenCode plumbing. |
| tests/ui/test_server_data_query.py | New: tests agent-server data-query endpoint against a real gRPC server. |
| tests/ui/test_server_agent.py | New: tests UI server’s OpenCode supervisor endpoints and AGENTS.md handling. |
| tests/trainer/services/test_trainer_services_unit.py | Adds regression test ensuring downsampling retains the last point. |
| tests/trainer/services/test_opencode_chat.py | New: end-to-end fake-server tests for OpenCodeChat SSE ordering/parsing and usage extraction. |
| tests/trainer/services/test_agent_service_unit.py | Updates agent service tests for OpenCode + new history/context methods. |
| tests/trainer/services/test_agent_prompt_unit.py | Removes OpenRouter/Ollama dependency stubs and updates provider expectations. |
| tests/trainer/services/test_agent_opencode_provider.py | New: tests DataManipulationAgent’s OpenCode provider wiring/config/model/history/context usage. |
| tests/trainer/services/test_agent_model_and_safety_unit.py | Updates safety/auth-failure handling tests for OpenCode-only provider. |
| tests/trainer/services/test_agent_live_prompt_evaluation.py | Switches opt-in live evaluation from OpenRouter-key gating to OpenCode server gating. |
| tests/test_opencode_shared_server_integration.py | New: integration test proving backend+UI converge on one server regardless of start order. |
| tests/test_opencode_process.py | New: unit + real-subprocess tests for env/lockfile/spawn precedence and lockfile behavior. |
| tests/gRPC/test_grpc_user_actions.py | Updates mock agent availability method name. |
| tests/backend/test_cli_additional_unit.py | Updates CLI tests for OpenCode agent init/model behavior. |
| README.md | Adds documentation blurb describing OpenCode-backed agent surfaces and /loop. |
| pyproject.toml | Removes unnecessary LangChain provider deps; ships AGENTS.md as package data. |
| docs/weights_studio.rst | Updates studio agent documentation to OpenCode-only flow. |
| docs/user_commands.rst | Updates CLI examples for OpenCode model strings. |
| docs/usage/parameters.rst | Replaces OpenRouter env vars with OPENCODE_URL/OPENCODE_MODEL documentation. |
| docs/configuration.rst | Updates configuration docs/YAML keys to OpenCode-only backend. |
| docs/agent.rst | Documents two agent surfaces, OpenCode setup, and /loop reference. |
| AGENTS.md | Removes root-level guide (now packaged under weightslab/AGENTS.md). |
| agent_config.yaml | Updates agent config schema to OpenCode URL/model. |
| .gitignore | Fixes typo (launch.json) and ignores OpenCode lockfile .wl_opencode.json. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| cache_read_tokens=usage.get("cache_read_tokens") or 0, | ||
| cache_write_tokens=usage.get("cache_write_tokens") or 0, | ||
| ) | ||
| return pb2.CompactAgentHistoryResponse(success=success, message=message) |
Comment on lines
+43
to
+56
| // Wipe the agent's conversation history (self.history) without touching the | ||
| // provider connection -- distinct from ResetAgent, which drops the connection. | ||
| rpc ClearAgentHistory (Empty) returns (ClearAgentHistoryResponse); | ||
| // Summarize the agent's conversation history via the active model, replacing | ||
| // it with the summary. Distinct from OpenCode's own session compaction (which | ||
| // this does not touch) -- this is the SDK agent's own self.history. | ||
| rpc CompactAgentHistory (Empty) returns (CompactAgentHistoryResponse); | ||
| // Context-window usage breakdown for the active model. A fresh OpenCode | ||
| // session is created per agent call (see opencode_chat.py), so there is no | ||
| // persistent session to total across turns -- this reports the LAST | ||
| // completed call's token usage, which is exactly the size of the context | ||
| // the NEXT call will resend (the full history is baked into the prompt | ||
| // text every time). | ||
| rpc GetAgentContextUsage (Empty) returns (GetAgentContextUsageResponse); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change the OpenRouter agent to OpenCode. Now, both the SDK and UI run OpenCode on the same server.
Still ongoing tasks: