[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "openjiuwen"
version = "0.1.14"
description = "openJiuwen agent-core is a feature-rich AI agent SDK for developing, running, tuning, and improving your AI agents."
readme = "README.md"
requires-python = ">=3.11,<3.14"
classifiers = [
    'Development Status :: 4 - Beta',
    'Programming Language :: Python',
    'Programming Language :: Python :: Implementation :: CPython',
    'Programming Language :: Python :: 3',
    'Programming Language :: Python :: 3 :: Only',
    'Programming Language :: Python :: 3.11',
    'Programming Language :: Python :: 3.12',
    'Programming Language :: Python :: 3.13',
]
dependencies = [
    # HTTP clients
    "aiohttp>=3.11.12",
    "requests>=2.32.3",
    # Date & time
    "python-dateutil>=2.9.0.post0",
    # File & locking
    "filelock>=3.20.1",
    "portalocker>=3.2.0",
    "aiofiles>=25.1.0",
    # Database ORM
    "sqlalchemy>=2.0.41",
    "sqlmodel>=0.0.37",
    # AI/LLM
    "openai>=1.108.0",
    "transformers>=4.52.4",
    "tiktoken>=0.12.0",
    "dashscope>=1.25.6",
    # Vector database (2.6.10 changed interface)
    "pymilvus>=2.6.2,<2.6.10",
    # MCP server
    "fastmcp>=2.14.2,<3.0",
    "mcp>=1.26.0",
    # Document processing
    "beautifulsoup4>=4.12.0",
    "docx2txt>=0.8",
    "python-docx>=1.2.0",
    "pdfplumber>=0.11.8",
    "openpyxl>=3.1.0",
    # Utilities
    "numpy!=2.4.0",
    "cacheout>=0.16.0",
    "mermaid-py>=0.8.0,<0.9",
    "pycryptodome>=3.23.0",
    "charset-normalizer>=3.4.4",
    "pysbd>=0.3.4",
    "oauthlib>=3.3.1",
    "python-dotenv>=1.2.1",
    "json-repair>=0.55.0",
    "tenacity>=9.1.2",
    "alembic>=1.13.1",
    "anyio>=4.0.0",
    "loguru>=0.7.3",
]

# A2A: required for `openjiuwen.remote_clients` / `openjiuwen.server_adapters` A2A entry
# points (`pip install "openjiuwen[all-a2a]"` — entry points do not auto-install deps).
[project.optional-dependencies]
# Parallel to `all-mq` / `all-storage` / `all-vector` (integration bundle name).
all-a2a = ["a2a-sdk[http-server]==1.0.0"]
pulsar = ["pulsar-client>=3.5.0"]
elasticsearch = ["elasticsearch[async]>=8.0.0"]
redis = ["redis>=7.1.0"]
sqlite = ["aiosqlite>=0.22.1", "greenlet>=3.1.1"]
postgres = ["asyncpg>=0.30.0"]
mysql = ["aiomysql>=0.3.2"]
gaussdb = ["async-gaussdb~=0.30.0", "asyncpg>=0.29.0"]
pgvector = ["pgvector>=0.2.0"]
gaussvector = ["psycopg2-binary>=2.9.10"]
chromadb = ["chromadb>=1.5.4", "opentelemetry-proto>=1.33.0", "protobuf>=5.0,<7.0"]
obs = ["aioboto3>=11.0.0"]
zmq = ["pyzmq>=26.0.0", "tornado>=6.1"]
sandbox = ["agent-sandbox>=0.0.26"]
mem0 = ["mem0ai>=1.0.0"]
agentarts = ["agentarts-sdk>=0.1.2,<0.2"]
mobile-gui = [
    # Install: pip install 'openjiuwen[mobile-gui]'
    "uiautomator2>=3.2.0",
    "pillow>=10.0.0",
]

online-rl = [
    "fastapi>=0.100",
    "uvicorn[standard]",
    "httpx>=0.24",
    "pandas",
    "pyarrow",
    "omegaconf>=2.3.0",
]

all-mq = ["openjiuwen[pulsar]"]
all-storage = ["openjiuwen[sqlite,postgres,mysql,gaussdb,redis,elasticsearch,obs]"]
all-vector = ["openjiuwen[pgvector,chromadb,gaussvector]"]

cli = ["click>=8.0", "rich>=13.0", "prompt-toolkit>=3.0"]

default = []
# Includes A2A SDK so the A2A remote/server plugins work when using `openjiuwen[all]`.
all = ["openjiuwen[all-mq,all-storage,all-vector,all-a2a]"]

[dependency-groups]
# Testing
test = [
    "pytest>=8.3.5",
    "pytest-asyncio>=1.0.0",
    "pytest-html>=4.1.1",
    "pytest-mock>=3.14.0",
    "pytest-cov>=7.0.0",
    "coverage>=7.7.1",
    "fastapi>=0.115.0",
    "uvicorn>=0.32.0",
    "sse-starlette>=2.1.3",
    "a2a-sdk[http-server]==1.0.0",
]

# Linting & formatting
lint = [
    "ruff>=0.11.2",
    "pylint>=3.0.0",
    "mypy>=1.12.0",
    "codespell>=2.2.4",
    "httpx>=0.28.1",
]
# Documentation
docs = [
    "autodoc-pydantic>=2.2.0",
]

dev = [{ include-group = "test" }, { include-group = "lint" }, { include-group = "docs" }]

# IntelliRouter
intelli-router = ["intelli-router @ git+https://gitcode.com/openJiuwen/agent-protocol.git@feature/intelliRouter#subdirectory=intelli_router"]

[project.entry-points."openjiuwen.remote_clients"]
A2A = "openjiuwen.extensions.a2a.a2a_remote_client:A2ARemoteClient"

[project.entry-points."openjiuwen.server_adapters"]
A2A = "openjiuwen.extensions.a2a.a2a_server_adapter:A2AServerAdapter"

[project.scripts]
openjiuwen = "openjiuwen.harness.cli.cli:cli"
team-member = "openjiuwen.agent_teams.skill.cli:run"
openjiuwen-team-mcp = "openjiuwen.agent_teams.mcp.server:main"

[project.urls]
Homepage = "https://openjiuwen.com"
Documentation = "https://openjiuwen.com/docs-page"
Repository = "https://gitcode.com/openJiuwen/agent-core.git"
Changelog = "https://gitcode.com/openJiuwen/agent-core/releases"

[tool.uv]
default-groups = ['dev']

[[tool.uv.index]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple"
default = true

[tool.setuptools.packages.find]
include = ["openjiuwen*"]

[tool.setuptools.package-data]
openjiuwen = [
    "**/prompts/**/*.md",
    "**/locales/**/*.md",
    "**/auto_harness/resources/*.yaml",
    "**/auto_harness/skills/**/*.md",
]

[tool.coverage.run]
omit = ["tests/*"]

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"
testpaths = ["tests"]
pythonpath = ["jiuwen"]
addopts = ["-v", "--html=report/index.html", "--self-contained-html"]

# Formatting & Linting
[tool.ruff]
line-length = 120
target-version = "py311"

[tool.ruff.lint]
# E203 (whitespace before ':') intentionally allowed everywhere: ``ruff
# format`` (Black style) inserts a space before ``:`` in slices that contain
# non-trivial expressions (e.g. ``s[len(prefix) :]``), and Black's official
# guidance is to disable E203 in any companion linter so the formatter and
# the linter agree. Ruff itself does not raise E203 in the stable rule set,
# but this entry makes the project intent explicit for downstream tools that
# read ``pyproject.toml``.
extend-ignore = ["E203"]

[tool.ruff.format]
# Respect magic trailing commas: when a call/signature/collection ends with `,`,
# keep it multi-line even if it fits within line-length. This is the team's
# explicit "force multi-line" signal.
skip-magic-trailing-comma = false
quote-style = "double"
indent-style = "space"
line-ending = "auto"
# Format code blocks inside docstrings (```python ... ```); length inherits line-length.
docstring-code-format = true
docstring-code-line-length = "dynamic"

[tool.pylint.MAIN]
ignore-paths = ["^(examples|tests)/.*"]
load-plugins = ["pylint.extensions.bad_builtin"]
py-version = "3.11"

[tool.pylint."DEPRECATED BUILTINS"]
bad-functions = ["print"]

[tool.pylint.FORMAT]
max-line-length = 120

[tool.pylint.DESIGN]
max-return = 5
max-args = 10
max-locals = 15
max-branches = 25

[tool.pylint."MESSAGES CONTROL"]
disable = [
    "import-outside-toplevel",
    "missing-module-docstring",
    "too-few-public-methods",
    "use-dict-literal",
    "use-list-literal",
    "unused-argument",
    "too-many-nested-blocks",
    "too-many-positional-arguments",
    "too-many-instance-attributes",
    "too-many-ancestors",
    "broad-exception-caught",
    "broad-exception-raised",
    "missing-timeout",
]

# Type Checking
[tool.mypy]
python_version = "3.11"

# Required to catch inconsistent return types
check_untyped_defs = true

# Ignore certain issues to stay minimal
disable_error_code = ["index"]
disallow_untyped_defs = false
disallow_any_unimported = false
disallow_any_expr = false
disallow_any_decorated = false
warn_unused_ignores = false
warn_return_any = false
ignore_missing_imports = true

# No constraints on optional
no_implicit_optional = false
strict_optional = false

# Show errors
show_error_codes = true