Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
140 lines (125 loc) · 5.2 KB
/
Copy pathpyproject.toml
File metadata and controls
140 lines (125 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# uv's own build backend, because this is a uv project. `src/seahaven` is what it
# packages -- `module-root` defaults to `src`, and the module is the project name
# normalised -- and every file under that directory travels, not only the `.py`
# ones, which is what carries `docs/` and `cli/templates/` into the wheel.
[build-system]
requires = ["uv_build>=0.8.17,<0.9.0"]
build-backend = "uv_build"
[project]
name = "seahaven"
version = "0.5.0"
description = "Synthetic world framework for agent evals and RL."
readme = "README.md"
requires-python = ">=3.14"
license = "MIT"
license-files = ["LICENSE"]
authors = [{ name = "Steve Cosman" }]
keywords = ["ai", "agents", "rl", "evaluation", "environments", "simulation"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
# Lower bounds are the versions this project is known to work on, not the
# oldest that might: each is the release `uv.lock` resolves, verified green on
# CPython 3.14.0 -- spelled as the lock spells it, except `apsw`, which the lock
# holds as the equal `3.53.4.0`. Raise one when a newer version is verified; do
# not lower one without running the suites against it.
dependencies = [
"apsw>=3.53.4",
"pydantic>=2.13.5,<3",
"pyyaml>=6.0.3",
]
[project.optional-dependencies]
serve = ["openenv>=0.5.0,<0.6"]
mcp = ["mcp>=2.2,<3"]
[project.scripts]
seahaven = "seahaven.cli:main"
# Installing `seahaven` activates its pytest plugin: a world's tests use the
# `world` and `instance` fixtures by name, with nothing in a `conftest.py`.
[project.entry-points.pytest11]
seahaven = "seahaven.pytest_plugin"
[project.urls]
Homepage = "https://github.com/Kiln-AI/Seahaven"
[dependency-groups]
# `projecttracker` is the reference world and `seahaven-xmlrpc` the example
# extension, both in this repository and developed with the framework. They are
# dev dependencies of `seahaven` and never runtime ones: the dependency runs the
# other way, and Seahaven imports neither.
dev = [
# `tests/state_v1.schema.json` is the published shape of the built-in state
# documents, and this is what asserts a document against it.
"jsonschema>=4",
"packaging>=24",
"projecttracker",
"pytest>=8",
"ruff>=0.14",
"seahaven-xmlrpc",
"ty>=0.0.1a21",
]
# `serve` and `mcp` cannot be installed together, and saying so here is what
# keeps `uv lock` solvable. `openenv` requires `fastmcp>=3,<4`, every `fastmcp`
# 3.x requires `mcp>=1.24,<2`, and `seahaven.mcp` is written against the 2.x
# lower-level server API, which 1.x does not have. Declaring the conflict locks
# both majors -- 1.30 under `serve`, 2.2 under `mcp` -- and refuses a sync that
# asks for both. The conflict dissolves when an `openenv` release accepts
# `fastmcp` 4.x, which is the first to take `mcp` 2.x; the extras can then be
# synced together again and this table goes.
[tool.uv]
conflicts = [[{ extra = "serve" }, { extra = "mcp" }]]
[tool.uv.workspace]
members = ["worlds/*", "extensions/*"]
[tool.uv.sources]
projecttracker = { workspace = true }
seahaven-xmlrpc = { workspace = true }
[tool.ruff]
line-length = 100
src = [
"src",
"tests",
".",
"worlds/projecttracker/src",
"worlds/projecttracker/tests",
"extensions/seahaven-xmlrpc/src",
"extensions/seahaven-xmlrpc/tests",
]
# The specs are documents. Their code blocks are sketches, not code that runs.
extend-exclude = ["specs"]
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
# The MCP test modules import the SDK after `tests/conftest.py`'s `mcp_sdk()`,
# which skips them where the `mcp` extra is not installed -- the environment
# synced for `serve` has the wrong major, so the guard has to run before the
# import rather than beside it. Ruff exempts a literal `pytest.importorskip`
# from E402 and not a call that wraps one, and one guard in one place is worth
# more than the exemption.
[tool.ruff.lint.per-file-ignores]
"tests/test_mcp_server.py" = ["E402"]
"tests/test_mcp_process.py" = ["E402"]
[tool.ty.src]
include = ["src", "tests", "tools", "worlds", "extensions"]
# The composite worlds of `tests/worlds/README.md` are packages that import one
# another, because that is how a host world reaches a world it adds. Nothing
# installs them -- `tests/conftest.py` puts them on `sys.path` for the same
# reason -- so ty is told where they are the same way.
[tool.ty.environment]
extra-paths = [
"tests/worlds/payments/src",
"tests/worlds/shop/src",
"tests/worlds/emporium/src",
"tests/worlds/ledger/src",
"tests/worlds/bazaar/src",
"tests/worlds/unsealed/src",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q"
# An exception on a thread a test started is otherwise a warning printed beside
# a passing test, which is no way to test a lock.
filterwarnings = ["error::pytest.PytestUnhandledThreadExceptionWarning"]
# `slow` is the 500-session smoke test and anything else that is measured in
# tens of seconds: always run in CI, deselectable with `-m "not slow"` locally.
markers = ["slow: takes tens of seconds; deselect with -m 'not slow'"]