Skip to content

Agent coding integration - #295

Open
guillaume-byte wants to merge 10 commits into
devfrom
agent-coding-integration
Open

Agent coding integration#295
guillaume-byte wants to merge 10 commits into
devfrom
agent-coding-integration

Conversation

@guillaume-byte

@guillaume-byte guillaume-byte commented Aug 14, 2026

Copy link
Copy Markdown
Member

Change the OpenRouter agent to OpenCode. Now, both the SDK and UI run OpenCode on the same server.

  • On the backend side, more flexibility in terms of model (still OpenRouter, but also ChatGPT, Gemini, and Claude API also).
  • On the UI side, the agent is directly included on the landing page, meaning that the user can start working from the workspace directly, then continue interacting during the experiment with the agent and schedule monitoring tasks also.

Still ongoing tasks:

  • Optimize token management
  • Default OpenCode settings ensure best token management and WeightsLab instructions
  • OpenCode session allow agent to work on task in background for main prompt?

guillaume-byte and others added 10 commits August 5, 2026 14:53
…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>
Copilot AI lite review requested due to automatic review settings August 14, 2026 14:14

Copilot AI 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.

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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants