Files
OpenJarvis/pyproject.toml
T
dfa908c358 Adopt hatch-vcs dynamic versioning (reworks autotag, pypi-publish, desktop) (#538)
* build: adopt hatch-vcs dynamic versioning (#526)

Replace the static `version = "1.0.2"` with `dynamic = ["version"]` and
derive the version from git tags via hatch-vcs, so source and editable
checkouts report their true git describe version (e.g.
1.0.3.dev110+g<sha>) instead of a stale constant.

Config notes:
- Exclude .dev/.rc/desktop-* tags from derivation. setuptools_scm cannot
  bump custom .devN tags, so the base is taken from the latest plain
  release tag (vX.Y.Z) and the dev distance from commit count.
- Add fallback_version so builds without a git checkout (shallow CI
  clones, Docker COPY src/, source-zip installs) resolve to a sentinel
  instead of hard-failing. CI release builds inject the exact version via
  SETUPTOOLS_SCM_PRETEND_VERSION.

* ci(autotag): derive dev base from the latest release tag (#526)

pyproject no longer carries a static version, so read the base from the
latest plain release tag (vX.Y.Z) reachable from HEAD instead of grepping
pyproject. .dev/.rc/desktop-* tags are excluded so they cannot be mistaken
for the release base. The computed tag (vX.Y.Z.devN) is unchanged.

* ci(pypi-publish): pin build version from tag, drop sed injection (#526)

With dynamic versioning there is no static line to sed. Pin the exact
build version from the pushed tag via SETUPTOOLS_SCM_PRETEND_VERSION so
the published version equals the tag. This is required, not cosmetic: a
naive hatch-vcs build emits 1.0.3.devN+g<sha>, and PyPI rejects local
version segments on upload.

Also add a dry_run input that targets TestPyPI instead of PyPI, for
validating the release path without a production upload.

* ci(desktop): derive dispatch-fallback version from release tag (#526)

The workflow_dispatch fallback grepped the now-removed static pyproject
version. Derive its base from the latest release tag instead (matching
autotag), and give the build-and-release checkout full history and tags
so the derivation works.

---------

Co-authored-by: Jon Saad-Falcon <jonsaadfalcon@gmail.com>
2026-06-14 19:35:17 -07:00

230 lines
7.9 KiB
TOML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"
[project]
name = "OpenJarvis"
dynamic = ["version"]
description = "OpenJarvis — modular AI assistant backend with composable intelligence primitives"
readme = "README.md"
# Upper bound: numpy 2.2.x (pinned transitively via datasets/pandas) ships no
# cp314 Windows wheel, so under Python 3.14 uv would compile numpy from source
# (Meson) and fail on Windows boxes without a C toolchain (#350). Cap to the
# range that has prebuilt wheels; matches the classifiers (3.103.13).
requires-python = ">=3.10,<3.14"
license = {text = "Apache-2.0"}
authors = [
{name = "Open Jarvis Contributors"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"click>=8",
"datasets>=4.5.0",
"ddgs>=9.11.4",
"httpx>=0.27",
"openai>=1.30",
"nvidia-ml-py>=12.560.30",
"posthog>=3.0",
"python-telegram-bot>=22.6",
"rich>=13",
"tomli>=2.0; python_version < '3.11'",
"tomlkit>=0.12",
"websockets>=15.0.1",
]
[project.optional-dependencies]
dev = [
"maturin>=1.12.6",
"pytest>=8",
"pytest-asyncio>=0.24",
"pytest-cov>=5",
"respx>=0.22",
"ruff>=0.4",
"pre-commit>=3.0",
]
inference-mlx = ["mlx-lm>=0.31.1; sys_platform == 'darwin'"]
inference-vllm = ["vllm>=0.16.0"]
inference-cloud = [
"openai>=1.30",
"anthropic>=0.30",
]
inference-google = [
"google-genai>=1.0",
]
inference-litellm = ["litellm>=1.40"]
inference-gemma = ["pygemma>=0.1.3"]
tools-search = [
"tavily-python>=0.3",
"ddgs>=9.11.4",
]
memory-faiss = [
"faiss-cpu>=1.7",
"sentence-transformers>=2.2",
"numpy>=1.24",
]
memory-colbert = [
"colbert-ai>=0.2",
"torch>=2.0",
]
memory-pdf = ["pdfplumber>=0.10"]
memory-bm25 = ["rank-bm25>=0.2.2"]
server = [
"fastapi>=0.110",
"uvicorn>=0.30",
"pydantic>=2.0",
"python-multipart>=0.0.9",
]
openhands = ["openhands-sdk>=1.0; python_version >= '3.12'"]
gpu-metrics = ["pynvml>=12.0"]
energy-amd = ["amdsmi>=6.1"]
energy-apple = ["zeus-ml[apple]"]
energy-all = ["pynvml>=12.0", "amdsmi>=6.1", "zeus-ml[apple]"]
orchestrator-training = ["torch>=2.0", "transformers>=4.40"]
learning-dspy = ["dspy>=2.6"]
learning-gepa = ["gepa>=0.1"]
channel-telegram = ["python-telegram-bot>=21.0"]
channel-discord = ["discord.py>=2.3"]
channel-slack = ["slack-sdk>=3.27"]
channel-line = ["line-bot-sdk>=3.0"]
channel-viber = ["viberbot>=1.0"]
channel-messenger = ["pymessenger>=0.0.7"]
channel-reddit = ["praw>=7.0"]
channel-mastodon = ["Mastodon.py>=1.8"]
channel-xmpp = ["slixmpp>=1.8"]
channel-rocketchat = ["rocketchat-API>=1.30"]
channel-zulip = ["zulip>=0.9"]
channel-twitter = ["httpx>=0.27"]
channel-twitch = ["twitchio>=2.6"]
channel-nostr = ["pynostr>=0.6"]
channel-twilio = ["twilio>=9.0"]
channel-gmail = [
"google-api-python-client>=2.0",
"google-auth-oauthlib>=1.0",
"google-auth-httplib2>=0.2",
]
browser = ["playwright>=1.40"]
media = ["openai>=1.30"]
mining-pearl-vllm = ["docker>=7.0", "httpx>=0.27"]
pdf = ["pdfplumber>=0.10"]
scheduler = ["croniter>=2.0"]
security-signing = ["cryptography>=43"]
sandbox-wasm = ["wasmtime>=25"]
sandbox-docker = ["docker>=7.0"]
dashboard = ["textual>=0.80"]
speech = ["faster-whisper>=1.0"]
speech-deepgram = ["deepgram-sdk>=3.0"]
eval-wandb = ["wandb>=0.17"]
eval-sheets = ["gspread>=6.0", "google-auth>=2.0"]
mining-pearl-cpu = [
# Pearl Python packages (py-pearl-mining, miner-base, pearl-gateway) are
# not on PyPI yet. They are installed at first `mine init` via the
# build-from-pin path in src/openjarvis/mining/_install.py:build_from_pin().
# When Pearl publishes wheels, replace the line below with version pins.
#
# The extra remains as a feature-flag namespace so users can run
# `uv sync --extra mining-pearl-cpu` to opt-in (it succeeds with no
# additional resolution today; the actual install happens on demand).
]
framework-comparison = ["polars>=1.0"]
docs = [
"mkdocs>=1.6",
"mkdocs-material>=9.5",
"mkdocstrings[python]>=0.25",
"mkdocs-gen-files>=0.5",
"mkdocs-literate-nav>=0.6",
]
[project.urls]
Homepage = "https://github.com/open-jarvis/OpenJarvis"
Documentation = "https://open-jarvis.github.io/OpenJarvis/"
Repository = "https://github.com/open-jarvis/OpenJarvis"
Issues = "https://github.com/open-jarvis/OpenJarvis/issues"
[project.scripts]
jarvis = "openjarvis.cli:main"
openjarvis-eval = "openjarvis.evals.cli:main"
# Version is derived from git tags by hatch-vcs (see #526). For source/editable
# checkouts this yields the true `git describe` version (e.g. 1.0.3.dev109+g<sha>)
# rather than a stale static string. CI release builds override this with
# SETUPTOOLS_SCM_PRETEND_VERSION so the published version equals the pushed tag.
#
# setuptools_scm cannot bump custom `.devN` tags (only `.dev0`), so the autotag
# `vX.Y.Z.devN` tags are deliberately EXCLUDED from version derivation here; the
# base is taken from the latest plain release tag (vX.Y.Z) and the dev distance
# is computed from commit count since that release.
[tool.hatch.version]
source = "vcs"
[tool.hatch.version.raw-options]
tag_regex = '^v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)$'
git_describe_command = [
"git", "describe", "--dirty", "--tags", "--long",
"--match", "v[0-9]*", "--exclude", "*dev*", "--exclude", "*rc*", "--exclude", "desktop-*",
]
# Builds without a git checkout (e.g. the `COPY src/ src/` Docker stages, which
# never include .git) can't run `git describe`. Without a fallback that would
# hard-fail the build. Mirror the runtime sentinel in src/openjarvis/__init__.py.
# Such builds can inject the real version via SETUPTOOLS_SCM_PRETEND_VERSION.
fallback_version = "0.0.0+unknown"
[tool.hatch.build.targets.wheel]
packages = ["src/openjarvis"]
[tool.hatch.build.targets.wheel.force-include]
"src/openjarvis/agents/claude_code_runner" = "_node_modules/claude_code_runner"
"src/openjarvis/channels/whatsapp_baileys_bridge" = "_node_modules/whatsapp_baileys_bridge"
"scripts/install" = "_install_scripts"
"deploy/windows" = "_deploy/windows"
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
"amd: requires AMD GPU",
"apple: requires Apple Silicon",
"cloud: requires cloud API keys",
"docker: requires a working Docker daemon (no GPU required)",
"live: requires running inference engine",
"macos15: requires macOS 15+ (Sequoia) for Apple FM",
"live_channel: requires real channel credentials (env vars)",
"nvidia: requires NVIDIA GPU",
"slow: long-running test",
"hub: downloads real datasets from the HuggingFace Hub at runtime; excluded from the default CI lane (run with -m hub)",
"live_external: requires HERMES_AGENT_PATH and OPENCLAW_PATH; spawns real foreign-framework subprocesses",
"modal: requires Modal token + network; runs real swebench harness on Modal",
]
[tool.ruff]
target-version = "py310"
src = ["src", "tests"]
[tool.ruff.lint]
select = ["E", "F", "I", "W"]
[tool.ruff.lint.per-file-ignores]
"src/openjarvis/evals/datasets/*.py" = ["E501"]
"src/openjarvis/evals/scorers/*.py" = ["E501"]
# hybrid/ is research code with long prompt strings and paradigm-specific
# config dicts — same relaxation as evals research code above. The ``**`` glob
# also covers subpackages (e.g. hybrid/skillorchestra/), which the prior
# ``hybrid/*.py`` glob missed.
"src/openjarvis/agents/hybrid/**/*.py" = ["E501"]
# research_loop.py carries long prompt strings too (documented in CLAUDE.md);
# the ignore was missing here.
"src/openjarvis/agents/research_loop.py" = ["E501"]
[dependency-groups]
dev = [
"maturin>=1.12.6",
]