-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpyproject.toml
More file actions
160 lines (149 loc) · 6.55 KB
/
Copy pathpyproject.toml
File metadata and controls
160 lines (149 loc) · 6.55 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
[project]
name = "corlinman"
version = "1.56.5"
description = "Python AI plane for corlinman (LLM providers, agent reasoning)"
requires-python = ">=3.12"
readme = "README.md"
license = { text = "MIT" }
authors = [{ name = "corlinman contributors" }]
# Meta-package: depends on every workspace member so `uv sync` installs them
# all into the virtualenv for development. Individual publishing happens
# per-package.
dependencies = [
"corlinman-grpc",
"corlinman-providers",
"corlinman-agent",
"corlinman-server",
"corlinman-tagmemo",
"corlinman-evolution-engine",
"corlinman-user-model",
"corlinman-persona",
"corlinman-episodes",
"corlinman-goals",
"corlinman-agent-brain",
"corlinman-memory-kernel",
"corlinman-content-policy",
"corlinman-runtime",
]
[project.optional-dependencies]
# Re-exported from corlinman-agent so `uv sync --extra voice` works from the
# workspace root. Without this the extra is only reachable as
# `uv sync --package corlinman-agent --extra voice`, which is not what the
# docs (or anyone's muscle memory) reach for.
voice = ["corlinman-agent[voice]"]
[tool.uv.sources]
corlinman-grpc = { workspace = true }
corlinman-providers = { workspace = true }
corlinman-agent = { workspace = true }
corlinman-server = { workspace = true }
corlinman-tagmemo = { workspace = true }
corlinman-evolution-engine = { workspace = true }
corlinman-user-model = { workspace = true }
corlinman-persona = { workspace = true }
corlinman-episodes = { workspace = true }
corlinman-goals = { workspace = true }
corlinman-agent-brain = { workspace = true }
corlinman-memory-kernel = { workspace = true }
corlinman-content-policy = { workspace = true }
corlinman-runtime = { workspace = true }
[tool.uv.workspace]
members = ["python/packages/*"]
exclude = ["python/packages/corlinman-embedding"]
[tool.uv]
managed = true
[dependency-groups]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.25",
"pytest-cov>=5.0",
"pytest-timeout>=2.3",
"hypothesis>=6.0",
# In-memory Redis double for the Redis journal backend tests
# (``test_agent_journal_redis.py``) — CI has no live Redis service,
# and unlike pytest-postgresql this needs no external binary, so the
# tests actually RUN in CI instead of skipping. Pulls redis-py as a
# transitive dep, which is also what the real backend drives.
"fakeredis>=2.26",
"respx>=0.21",
"syrupy>=4.1",
"ruff>=0.8",
"mypy>=1.11",
# Pin exact versions so `scripts/gen-proto.sh` produces byte-identical stubs
# across dev machines and CI. Drift in either of these breaks the
# `proto-sync` CI job. Bump together and regenerate stubs in the same PR.
"grpcio-tools==1.80.0",
"protobuf==6.33.6",
"import-linter>=2.0",
]
[tool.ruff]
line-length = 100
target-version = "py312"
# Generated protobuf stubs are never linted; they are regenerated from .proto
# by `scripts/gen-proto.sh` and formatted with `ruff format`, but the shape
# of grpcio-tools' output trips many style rules.
extend-exclude = ["**/_generated/**", "audit/**"]
[tool.ruff.lint]
external = ["BLE001","PLC0415","E402","N818","ARG002","ARG001","SLF001","D401","A001","A002","A004","N801","N802","PLW0603","B017","S101","S105","S603","C901","ANN001","ANN002","ANN003"]
# Enforce the bug-catching families. `N` (pep8-naming) and `SIM` (flake8-simplify)
# were selected but never enforced (150+ standing violations of the codebase's
# deliberate domain naming + explicit-control-flow style) — dropped so the gate
# reflects what is actually enforced rather than aspirational style.
select = ["E", "F", "I", "UP", "B", "A", "C4", "RUF"]
ignore = [
"E501", # line length — the formatter owns wrapping
"E402", # module-import-not-at-top: the gateway uses intentional lazy/conditional imports
"RUF001", "RUF002", "RUF003", # ambiguous-unicode: false positives on legitimate CJK prompt/doc content
"A002", "A004", # builtin shadowing on params/imports (id/type/input/format) — common, intentional API naming
"B008", # function-call-in-default: the FastAPI Depends()/Query()/Path() dependency-injection pattern
"B017", # pytest.raises(Exception): test-only, team-accepted (also in `external`)
"UP042", # str-enum->StrEnum: behavior-changing (str(member) value vs repr) — not worth the modernization risk
"UP046", "UP047", # PEP-695 generic syntax: optional modernization; the module-level TypeVar pattern is valid
]
[tool.ruff.lint.per-file-ignores]
# Prompts and test fixtures legitimately contain CJK punctuation
# (FULLWIDTH COMMA / COLON / EN DASH etc.); RUF001 flags these as
# "ambiguous" but here they're part of the natural-language content.
"python/packages/corlinman-user-model/src/corlinman_user_model/distiller.py" = ["RUF001"]
"python/packages/corlinman-user-model/tests/test_distiller.py" = ["RUF001"]
[tool.mypy]
python_version = "3.12"
# Start lenient so CI can go green while the Python plane is still landing;
# individual packages can opt into strict mode via their own mypy overrides.
# TODO(M7): flip back to `strict = true` once all packages pass.
strict = false
ignore_missing_imports = true
explicit_package_bases = true
warn_return_any = true
warn_unused_configs = true
exclude = [
"^python/packages/[^/]+/tests/",
"_generated/",
]
[tool.pytest.ini_options]
asyncio_mode = "auto"
# Use importlib so duplicate module names (e.g. ``tests/``) across uv workspace
# members don't collide in ``sys.modules``.
addopts = "--import-mode=importlib"
# Per-test watchdog — a hung test must FAIL, not wedge the suite.
#
# ``thread`` was the original choice because it fires even when the event
# loop is blocked, but it cannot *interrupt* the test: it dumps stacks and
# then kills the interpreter. So one hung test took down the whole py-test
# job with no failing-test attribution — the run just ended at exit code 1
# and every other test went unreported. That is the "py-test hangs in CI"
# symptom operators kept re-running.
#
# ``signal`` raises inside the hung test instead (SIGALRM; both CI and dev
# are Unix), so it fails with a normal traceback pointing at the blocking
# line and the remaining tests still run. An event loop parked in
# ``selector.poll()`` is interruptible this way — that is a plain syscall,
# not a GIL-holding C call.
timeout = 180
timeout_method = "signal"
consider_namespace_packages = true
markers = [
"live_llm: tests that hit real LLM APIs (cost money)",
"live_transport: tests that need real channel endpoints",
"integration: tests that spin real in-process gRPC servers",
"slow: tests that take noticeable wall-clock (e.g. multi-DB E2E)",
]