|
| 1 | +# Contributing to Bayesian-Agent |
| 2 | + |
| 3 | +Thanks for helping improve Bayesian-Agent. |
| 4 | + |
| 5 | +Bayesian-Agent is not meant to become a monolithic agent runtime. Its core value is a Bayesian Skill/SOP evolution layer that can work with many execution harnesses. Contributions should preserve that boundary. |
| 6 | + |
| 7 | +## Project Principles |
| 8 | + |
| 9 | +- **Keep the core harness-agnostic**: `bayesian_agent/core/` must not import GenericAgent, browser runtimes, model SDKs, benchmark runners, or framework-specific code. |
| 10 | +- **Do not vendor external agents**: integrations should point to local checkouts, packages, APIs, or commands. Do not copy another agent framework into this repository. |
| 11 | +- **Evidence first**: adapter outputs should be convertible into verified `TrajectoryEvidence`. |
| 12 | +- **Small interfaces over large abstractions**: prefer one clear adapter boundary over a deep plugin hierarchy. |
| 13 | +- **Standard-library-first**: avoid runtime dependencies unless there is a strong reason. |
| 14 | +- **Tests before confidence**: every adapter contribution should include focused tests that run with `python3 -m unittest discover -v`. |
| 15 | + |
| 16 | +## Repository Map |
| 17 | + |
| 18 | +```text |
| 19 | +bayesian_agent/ |
| 20 | + core/ # Framework-agnostic evidence, beliefs, registry, policy, context, repair |
| 21 | + adapters/ # Adapter protocol and optional external harness boundaries |
| 22 | +schemas/ # Portable JSON schemas for trajectories and Skill beliefs |
| 23 | +artifacts/ # Experiment result artifacts |
| 24 | +docs/ # Documentation site content |
| 25 | +tests/ # unittest test suite |
| 26 | +``` |
| 27 | + |
| 28 | +## Adding a New Adapter |
| 29 | + |
| 30 | +Adapters are how Bayesian-Agent connects to external agent frameworks. |
| 31 | + |
| 32 | +The rule is simple: |
| 33 | + |
| 34 | +```text |
| 35 | +External Harness Run -> trajectory-like mapping -> TrajectoryEvidence -> Bayesian Skill Registry |
| 36 | +Bayesian Skill Context -> Adapter -> External Harness Next Run |
| 37 | +``` |
| 38 | + |
| 39 | +An adapter should execute one task with posterior-weighted Skill context and return a trajectory-like mapping that Bayesian-Agent can normalize. |
| 40 | + |
| 41 | +### 1. Start From the Protocol |
| 42 | + |
| 43 | +All adapters should satisfy `AgentAdapter`: |
| 44 | + |
| 45 | +```python |
| 46 | +from typing import Any, Mapping, Protocol, runtime_checkable |
| 47 | + |
| 48 | +@runtime_checkable |
| 49 | +class AgentAdapter(Protocol): |
| 50 | + def run(self, task: Mapping[str, Any], skill_context: str) -> Mapping[str, Any]: |
| 51 | + """Run one task with Bayesian Skill context and return a trajectory-like mapping.""" |
| 52 | + ... |
| 53 | +``` |
| 54 | + |
| 55 | +The adapter receives: |
| 56 | + |
| 57 | +- `task`: a benchmark or application task mapping |
| 58 | +- `skill_context`: posterior-weighted Skill/SOP context rendered by Bayesian-Agent |
| 59 | + |
| 60 | +The adapter returns a mapping with enough information to build `TrajectoryEvidence`. |
| 61 | + |
| 62 | +### 2. Create an Adapter Module |
| 63 | + |
| 64 | +Create a focused file under `bayesian_agent/adapters/`. |
| 65 | + |
| 66 | +Example: |
| 67 | + |
| 68 | +```text |
| 69 | +bayesian_agent/adapters/my_harness.py |
| 70 | +``` |
| 71 | + |
| 72 | +Skeleton: |
| 73 | + |
| 74 | +```python |
| 75 | +"""Optional MyHarness integration boundary. |
| 76 | +
|
| 77 | +This module should not vendor MyHarness or import heavy dependencies eagerly. |
| 78 | +""" |
| 79 | + |
| 80 | +from __future__ import annotations |
| 81 | + |
| 82 | +from dataclasses import dataclass |
| 83 | +from typing import Any, Mapping |
| 84 | + |
| 85 | + |
| 86 | +@dataclass |
| 87 | +class MyHarnessAdapter: |
| 88 | + """Adapter for a local or installed MyHarness runner.""" |
| 89 | + |
| 90 | + root: str |
| 91 | + |
| 92 | + def integration_note(self) -> str: |
| 93 | + return ( |
| 94 | + "MyHarness integration is optional. Set root to a local MyHarness checkout; " |
| 95 | + "Bayesian-Agent does not copy or vendor MyHarness code." |
| 96 | + ) |
| 97 | + |
| 98 | + def run(self, task: Mapping[str, Any], skill_context: str) -> Mapping[str, Any]: |
| 99 | + """Run one task and return a trajectory-like result. |
| 100 | +
|
| 101 | + Keep this method as a thin boundary around the external harness. |
| 102 | + """ |
| 103 | + raise NotImplementedError( |
| 104 | + "Wire this method to your local MyHarness runner." |
| 105 | + ) |
| 106 | +``` |
| 107 | + |
| 108 | +If the external harness has expensive imports, import them inside `run()` or behind a helper so `import bayesian_agent` remains lightweight. |
| 109 | + |
| 110 | +### 3. Return a Trajectory-Like Mapping |
| 111 | + |
| 112 | +The returned mapping should include fields compatible with `TrajectoryEvidence.from_run(...)`. |
| 113 | + |
| 114 | +Minimum useful shape: |
| 115 | + |
| 116 | +```python |
| 117 | +{ |
| 118 | + "task_id": "sop_12", |
| 119 | + "success": False, |
| 120 | + "input_tokens": 70123, |
| 121 | + "output_tokens": 4242, |
| 122 | + "total_tokens": 74365, |
| 123 | + "turns": 8, |
| 124 | + "elapsed_seconds": 31.5, |
| 125 | + "failure_mode": "xml_wrapped_answer", |
| 126 | + "summary": "The model wrapped the final answer in XML.", |
| 127 | + "metadata": { |
| 128 | + "harness": "my_harness", |
| 129 | + "model": "deepseek-v4-flash" |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +Bayesian-Agent will attach `skill_id` and `context` when converting benchmark results into evidence, or your integration can construct `TrajectoryEvidence` directly. |
| 135 | + |
| 136 | +The portable schema is documented in: |
| 137 | + |
| 138 | +```text |
| 139 | +schemas/trajectory.schema.json |
| 140 | +``` |
| 141 | + |
| 142 | +### 4. Preserve the Harness Boundary |
| 143 | + |
| 144 | +Good adapter behavior: |
| 145 | + |
| 146 | +- calls an installed package, local checkout, CLI command, API, or user-provided callable |
| 147 | +- returns normalized trajectory data |
| 148 | +- keeps harness-specific logs in `metadata` |
| 149 | +- fails with a clear error when the external harness is not configured |
| 150 | + |
| 151 | +Avoid: |
| 152 | + |
| 153 | +- copying external framework source code into `bayesian_agent/adapters/` |
| 154 | +- importing a large framework at module import time |
| 155 | +- hiding benchmark graders inside the adapter |
| 156 | +- returning only free-form text without token usage or success signal |
| 157 | +- changing `bayesian_agent/core/` to fit one harness |
| 158 | + |
| 159 | +### 5. Add Tests |
| 160 | + |
| 161 | +Add tests under `tests/`. |
| 162 | + |
| 163 | +For a lightweight boundary adapter, test that it: |
| 164 | + |
| 165 | +- satisfies `AgentAdapter` |
| 166 | +- does not eagerly import the external framework |
| 167 | +- preserves constructor configuration |
| 168 | +- returns or documents a clear integration error |
| 169 | + |
| 170 | +Example: |
| 171 | + |
| 172 | +```python |
| 173 | +import unittest |
| 174 | + |
| 175 | +from bayesian_agent.adapters.base import AgentAdapter |
| 176 | +from bayesian_agent.adapters.my_harness import MyHarnessAdapter |
| 177 | + |
| 178 | + |
| 179 | +class MyHarnessAdapterTests(unittest.TestCase): |
| 180 | + def test_adapter_is_runtime_checkable(self): |
| 181 | + adapter = MyHarnessAdapter(root="/tmp/my-harness") |
| 182 | + self.assertIsInstance(adapter, AgentAdapter) |
| 183 | + |
| 184 | + def test_adapter_does_not_vendor_harness(self): |
| 185 | + adapter = MyHarnessAdapter(root="/tmp/not-installed") |
| 186 | + self.assertIn("does not copy or vendor", adapter.integration_note()) |
| 187 | + |
| 188 | + |
| 189 | +if __name__ == "__main__": |
| 190 | + unittest.main() |
| 191 | +``` |
| 192 | + |
| 193 | +Run: |
| 194 | + |
| 195 | +```bash |
| 196 | +python3 -m unittest discover -v |
| 197 | +python3 -m compileall bayesian_agent |
| 198 | +``` |
| 199 | + |
| 200 | +### 6. Document the Adapter |
| 201 | + |
| 202 | +Update docs when the adapter is user-visible: |
| 203 | + |
| 204 | +- `docs/adapters.md`: explain setup and usage |
| 205 | +- `docs/quick-start.md`: add a short example if the adapter is ready for users |
| 206 | +- `README.md` / `README_ZH.md`: mention only mature integrations |
| 207 | + |
| 208 | +If the adapter is only a boundary placeholder, say so clearly. |
| 209 | + |
| 210 | +### 7. Adapter PR Checklist |
| 211 | + |
| 212 | +Before opening a PR, make sure: |
| 213 | + |
| 214 | +- [ ] The adapter does not vendor or copy external framework code. |
| 215 | +- [ ] The adapter does not import heavy external dependencies at module import time. |
| 216 | +- [ ] The adapter returns a trajectory-like mapping or documents how it emits `TrajectoryEvidence`. |
| 217 | +- [ ] Harness-specific diagnostics go into `metadata`. |
| 218 | +- [ ] Tests pass with `python3 -m unittest discover -v`. |
| 219 | +- [ ] Compilation passes with `python3 -m compileall bayesian_agent`. |
| 220 | +- [ ] Documentation explains setup, expected inputs, and returned evidence. |
| 221 | + |
| 222 | +## General Development Workflow |
| 223 | + |
| 224 | +1. Create a small branch. |
| 225 | +2. Keep changes scoped to one concern. |
| 226 | +3. Add or update tests. |
| 227 | +4. Run verification: |
| 228 | + |
| 229 | +```bash |
| 230 | +python3 -m unittest discover -v |
| 231 | +python3 -m compileall bayesian_agent |
| 232 | +git diff --check |
| 233 | +``` |
| 234 | + |
| 235 | +5. If docs changed, run: |
| 236 | + |
| 237 | +```bash |
| 238 | +uv run --with mkdocs-material mkdocs build --strict |
| 239 | +``` |
| 240 | + |
| 241 | +6. Open a PR with: |
| 242 | + |
| 243 | +- what changed |
| 244 | +- why it matters |
| 245 | +- how it was tested |
| 246 | +- any remaining limitations |
| 247 | + |
| 248 | +## Commit Style |
| 249 | + |
| 250 | +Use short, descriptive commit messages: |
| 251 | + |
| 252 | +```text |
| 253 | +feat: add my-harness adapter boundary |
| 254 | +test: cover my-harness adapter protocol |
| 255 | +docs: document adapter contribution workflow |
| 256 | +``` |
| 257 | + |
| 258 | +## Questions |
| 259 | + |
| 260 | +If you are unsure whether an integration belongs in core or adapters, put it in adapters. The core package should remain portable, evidence-first, and harness-agnostic. |
0 commit comments