-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
291 lines (264 loc) · 10.6 KB
/
pyproject.toml
File metadata and controls
291 lines (264 loc) · 10.6 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
[project]
name = "kosmos"
version = "0.1.0"
description = "Conversational multi-agent platform for Korean public APIs"
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.12"
authors = [{ name = "umyunsang" }]
dependencies = [
"httpx>=0.27",
"pydantic>=2.13.0",
"pydantic-settings>=2.13.1",
"typer>=0.24.1",
"rich>=13.0",
"prompt-toolkit>=3.0",
"opentelemetry-sdk>=1.25",
"opentelemetry-exporter-otlp-proto-http>=1.25",
"opentelemetry-semantic-conventions>=0.46b0",
"rank-bm25>=0.2.2",
"kiwipiepy>=0.17",
"openai>=2.32.0",
"presidio-analyzer>=2.2",
"sentence-transformers>=3.0", # spec 026 — retrieval dense backend
"numpy>=1.26", # spec 026 — retrieval dense backend
# torch pinned to CPU-only wheel via [tool.uv.sources] below — sentence-transformers
# pulls torch transitively; declaring it explicitly here lets tool.uv.sources route
# the resolver to download.pytorch.org/whl/cpu instead of the GPU-by-default pypi.
"torch>=2.5",
# spec 026 — PyYAML is loaded at module import time by prompt_loader,
# session_compact, and tools/release_manifest/render. The Docker runtime
# stage (`uv sync --frozen --no-dev`) and the release-manifest workflow
# (`uv sync --frozen`) do not install dev/extras groups, so yaml MUST be
# a core runtime dependency or those entrypoints crash at import.
"pyyaml>=6.0.3",
]
[project.scripts]
kosmos = "kosmos.cli.app:main"
# kosmos-permissions = "kosmos.permissions.cli:main" — removed Epic δ #2295 (Codex P1).
# The KOSMOS-invented Spec 033 permission CLI (mode/rules/killswitch ops) is
# deleted alongside its module. Spec 035 receipt-ledger verification has its
# own console-script-free workflow via `python -m kosmos.permissions.ledger_verify`
# or programmatic `kosmos.permissions.ledger_verify.verify_ledger(...)` callers.
kosmos-plugin-init = "kosmos.plugins.cli_init:main"
kosmos-plugin-validate = "kosmos.plugins.checks.framework:_cli_main"
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=1.3.0",
"pytest-benchmark>=5.2.3",
"pytest-cov>=7.1.0",
"pytest-xdist>=3.5",
"respx>=0.23.1",
"hypothesis[pydantic]>=6.100",
"mypy>=1.20.0",
"ruff>=0.5",
"pre-commit>=3.7",
"pip-audit>=2.10.0",
"vulture>=2.16",
"pip-licenses>=5.0",
# Spec 2521 — TUI Layer 5 (asciinema cast → per-frame text snapshot).
# Dev-only: replays asciicast v2/v3 byte streams through a real VT-100
# emulator so LLM agents can grep deterministic cell-grid text frames
# instead of OCR'ing PNG keyframes. See AGENTS.md § TUI verification.
"pyte>=0.8.2",
]
# spec 026 FR-C09 — Langfuse Prompt Management is an OPT-IN integration.
# It must never be a core runtime dependency (AGENTS.md hard rule: no new
# core runtime deps without a spec-driven PR; this extras-only form is the
# spec-driven carve-out). Install with: `uv sync --extra langfuse`.
langfuse = [
"langfuse>=2.60",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/kosmos"]
# spec 026 — bundle the repo-root prompts/ directory into the wheel as
# `kosmos/prompts/` so that PromptLoader can resolve manifest.yaml via
# importlib.resources when KOSMOS is installed as a wheel (the default
# packages= only ships src/kosmos; without this include the Docker
# runtime stage cannot find prompts/manifest.yaml at startup).
[tool.hatch.build.targets.wheel.force-include]
"prompts" = "kosmos/prompts"
# Spec 1636 P5 / Sec H-1 (review re-eval): bundle the canonical PIPA
# §26 acknowledgment markdown so canonical_acknowledgment.py can read
# it via importlib.resources when KOSMOS is installed as a wheel
# (default packages= only ships src/kosmos; without this include the
# kosmos.plugins import fails at module load).
"docs/plugins/security-review.md" = "kosmos/_canonical/security-review.md"
# Bundle the 50-item validation checklist YAML so kosmos-plugin-validate
# CLI can find it without depending on the source-tree layout.
"tests/fixtures/plugin_validation/checklist_manifest.yaml" = "kosmos/_canonical/checklist_manifest.yaml"
[tool.pytest.ini_options]
# Spec 1636 P5 — plugin in-tree tests live alongside the plugin module
# at src/kosmos/plugins/tests/ so they ship with the wheel and exercise
# package-private helpers. Both roots must be in testpaths so CI's
# `pytest -n auto --cov=src/kosmos` sees plugin tests AND records
# coverage on the plugin sources they exercise.
testpaths = ["tests", "src/kosmos/plugins/tests"]
asyncio_mode = "auto"
# -p no:unraisableexception disables pytest's unraisable-exception plugin
# which in 8.4+ wraps late-gc ResourceWarnings (unclosed sockets, event
# loops from other tests that finalise out of order on Python 3.13) into
# an ExceptionGroup and fails an unrelated test. These resources are
# already released by the time the warning fires; filterwarnings-based
# ignore does not always reach the plugin's warn_explicit call site on
# 3.13. Disabling the plugin reverts to Python's default behaviour of
# logging to stderr — visible in CI output but not failure-inducing.
addopts = "--strict-markers -q --tb=short -p no:unraisableexception"
markers = [
"live: hits real data.go.kr APIs — skipped in CI (deselect with -m 'not live')",
"performance: timing assertions against perf budgets — opt-out via KOSMOS_SKIP_PERF=1",
"live_embedder: downloads HF model weights — skipped in CI (run locally with -m live_embedder)",
"integration: cross-spec integration tests (no live APIs; mocked WS dependencies)",
]
filterwarnings = [
"error",
"ignore::pytest_benchmark.logger.PytestBenchmarkWarning",
# Python 3.13 changed gc finalisation timing, which surfaces
# unraisable exceptions (e.g., late-finalised httpx/OTel resources)
# that were previously silently swallowed. These do not affect test
# correctness; the underlying resources are already released by the
# time the warning fires. Filtering here keeps filterwarnings=error
# strict for code-visible warnings without flaking on 3.13-specific
# shutdown-order noise.
"ignore::pytest.PytestUnraisableExceptionWarning",
]
[tool.coverage.run]
source = ["src/kosmos"]
parallel = true
omit = ["tests/*"]
[tool.coverage.report]
fail_under = 80
show_missing = true
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
]
[tool.ruff]
line-length = 100
target-version = "py312"
src = ["src", "tests"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"W", # pycodestyle warnings
"I", # isort (import sorting)
"N", # pep8-naming
"UP", # pyupgrade
"S", # flake8-bandit (security)
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"T20", # flake8-print (catches print() calls)
"SIM", # flake8-simplify
"C90", # mccabe complexity
]
ignore = [
"S101", # allow assert in tests
]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101", "S105", "S106"] # allow assert and hardcoded test passwords/tokens in tests
# S603/S607 (subprocess security) suppressed only in the file that invokes docker CLI
"tests/infra/test_docker_compose_dev.py" = ["S101", "S106", "S603", "S607"]
"src/kosmos/cli/**" = ["T20"] # allow print() in CLI layer only
# Spec 1636 P5 — these modules ship CLI entry-points (kosmos-plugin-init,
# kosmos-plugin-validate) declared in [project.scripts]. They print to
# stdout/stderr by design; T20 is correctly enforced everywhere else.
"src/kosmos/plugins/cli_init.py" = ["T20"]
"src/kosmos/plugins/checks/framework.py" = ["T20"]
# Plugin test suite mirrors `tests/**` permissions — assert + subprocess
# (multi-process flock race tests) are intentional.
"src/kosmos/plugins/tests/**" = ["S101", "S105", "S106", "S603", "S607"]
[tool.ruff.lint.mccabe]
max-complexity = 10
[tool.ruff.lint.isort]
known-first-party = ["kosmos"]
[tool.ruff.format]
quote-style = "double"
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_configs = true
plugins = ["pydantic.mypy"]
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
# Spec 1636: in-tree plugin tests live under src/kosmos/plugins/tests/
# (so they ship with the library and exercise package-private helpers).
# They use **dict[str, object] kwargs against typed PluginManifest /
# CatalogEntry constructors — a common test fixture pattern that strict
# mypy flags. Disable strict checks for test modules; CI's pytest run
# is the actual gate for behaviour.
[[tool.mypy.overrides]]
module = "kosmos.plugins.tests.*"
disallow_untyped_defs = false
disable_error_code = [
"arg-type",
"no-redef",
"no-any-return",
"call-arg",
"operator",
"unused-ignore",
]
# kiwipiepy ships no py.typed stubs (BSD licensed Korean tokenizer used
# by q4 search-hint nouns check) — silence import-untyped for that one
# module without disabling type checking for the file that uses it.
[[tool.mypy.overrides]]
module = "kiwipiepy"
ignore_missing_imports = true
# langfuse extras are opt-in (see [project.optional-dependencies]); they
# are NOT installed in the default --all-extras --dev sync the lint job
# uses. Skip the import check for the optional client.
[[tool.mypy.overrides]]
module = "langfuse"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "langfuse.*"
ignore_missing_imports = true
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
[tool.vulture]
paths = ["src", "vulture_whitelist.py"]
min_confidence = 80
[tool.commitizen]
name = "cz_conventional_commits"
version = "0.1.0"
tag_format = "v$version"
# PyTorch CPU-only wheel for Docker image size discipline (SC-1: ≤ 2 GB).
# sentence-transformers pulls torch; GPU wheels are ~2.5 GB + CUDA runtime layers
# push the final image above the 2 GB SC-1 hard cap. KOSMOS has no GPU workload
# at runtime (embedding inference is CPU-bound, batch-size 1), so CPU wheel is
# functionally identical for our workload.
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.uv.sources]
torch = [{ index = "pytorch-cpu" }]
torchvision = [{ index = "pytorch-cpu" }]
[dependency-groups]
dev = [
"jsonschema>=4.26.0",
"pytest>=9.0.3",
"pytest-asyncio>=1.3.0",
"pytest-benchmark>=5.2.3",
"pytest-cov>=7.1.0",
"pytest-xdist>=3.5",
"respx>=0.23.1",
"hypothesis[pydantic]>=6.100",
"mypy>=1.20.0",
"ruff>=0.5",
"pre-commit>=3.7",
"pip-audit>=2.10.0",
"vulture>=2.16",
"pip-licenses>=5.0",
"types-pyyaml>=6.0.12",
]