[project]
name = "langbot"
version = "4.6.4"
description = "Easy-to-use global IM bot platform designed for LLM era"
readme = "README.md"
license-files = ["LICENSE"]
requires-python = ">=3.11,<4.0"
dependencies = [
    "aiocqhttp>=1.4.4",
    "aiofiles>=24.1.0",
    "aiohttp>=3.11.18",
    "aioshutil>=1.5",
    "aiosqlite>=0.21.0",
    "anthropic>=0.51.0",
    "argon2-cffi>=23.1.0",
    "async-lru>=2.0.5",
    "certifi>=2025.4.26",
    "colorlog~=6.6.0",
    "cryptography>=44.0.3",
    "dashscope>=1.23.2",
    "dingtalk-stream>=0.24.0",
    "discord-py>=2.5.2",
    "pynacl>=1.5.0", # Required for Discord voice support
    "gewechat-client>=0.1.5",
    "lark-oapi>=1.4.15",
    "mcp>=1.8.1",
    "nakuru-project-idk>=0.0.2.1",
    "ollama>=0.4.8",
    "openai>1.0.0",
    "pillow>=11.2.1",
    "psutil>=7.0.0",
    "pycryptodome>=3.22.0",
    "pydantic>2.0",
    "pyjwt>=2.10.1",
    "python-telegram-bot>=22.0",
    "pyyaml>=6.0.2",
    "qq-botpy-rc>=1.2.1.6",
    "quart>=0.20.0",
    "quart-cors>=0.8.0",
    "requests>=2.32.3",
    "slack-sdk>=3.35.0",
    "sqlalchemy[asyncio]>=2.0.40",
    "sqlmodel>=0.0.24",
    "telegramify-markdown>=0.5.1",
    "tiktoken>=0.9.0",
    "urllib3>=2.4.0",
    "websockets>=15.0.1",
    "python-socks>=2.7.1", # dingtalk missing dependency
    "pip>=25.1.1",
    "ruff>=0.11.9",
    "pre-commit>=4.2.0",
    "uv>=0.7.11",
    "mypy>=1.16.0",
    "PyPDF2>=3.0.1",
    "python-docx>=1.1.0",
    "pandas>=2.2.2",
    "chardet>=5.2.0",
    "markdown>=3.6",
    "beautifulsoup4>=4.12.3",
    "ebooklib>=0.18",
    "html2text>=2024.2.26",
    "langchain>=0.2.0",
    "langchain-text-splitters>=0.0.1",
    "chromadb>=0.4.24",
    "qdrant-client (>=1.15.1,<2.0.0)",
    "pyseekdb>=0.1.0",
    "langbot-plugin==0.2.3",
    "asyncpg>=0.30.0",
    "line-bot-sdk>=3.19.0",
    "tboxsdk>=0.0.10",
    "boto3>=1.35.0",
    "pymilvus>=2.6.4",
    "pgvector>=0.4.1",
]
keywords = [
    "bot",
    "agent",
    "telegram",
    "plugins",
    "openai",
    "instant-messaging",
    "wechat",
    "qq",
    "dify",
    "llm",
    "chatgpt",
    "deepseek",
    "onebot",
]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Framework :: AsyncIO",
    "Framework :: Robot Framework",
    "Framework :: Robot Framework :: Library",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Topic :: Communications :: Chat",
]

[project.urls]
Homepage = "https://langbot.app"
Documentation = "https://docs.langbot.app"
Repository = "https://github.com/langbot-app/LangBot"

[project.scripts]
langbot = "langbot.__main__:main"

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
package-data = { "langbot" = ["templates/**", "pkg/provider/modelmgr/requesters/*", "pkg/platform/sources/*", "web/out/**"] }

[dependency-groups]
dev = [
    "pre-commit>=4.2.0",
    "pytest>=8.4.1",
    "pytest-asyncio>=1.0.0",
    "pytest-cov>=7.0.0",
    "ruff>=0.11.9",
]

[tool.ruff]
# Exclude a variety of commonly ignored directories.
exclude = [
    ".bzr",
    ".direnv",
    ".eggs",
    ".git",
    ".git-rewrite",
    ".hg",
    ".ipynb_checkpoints",
    ".mypy_cache",
    ".nox",
    ".pants.d",
    ".pyenv",
    ".pytest_cache",
    ".pytype",
    ".ruff_cache",
    ".svn",
    ".tox",
    ".venv",
    ".vscode",
    "__pypackages__",
    "_build",
    "buck-out",
    "build",
    "dist",
    "node_modules",
    "site-packages",
    "venv",
]

line-length = 120
indent-width = 4

# Assume Python 3.12
target-version = "py312"

[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`)  codes by default.
select = ["E4", "E7", "E9", "F"]
ignore = [
    "E712", # Comparison to true should be 'if cond is true:' or 'if cond:' (E712)
    "F402", # Import `loader` from line 8 shadowed by loop variable
    "F403", # * used, unable to detect undefined names
    "F405", # may be undefined, or defined from star imports
    "E741", # Ambiguous variable name: `l`
    "E722", # bare-except
    "E721", # type-comparison
    "F821", # undefined-all
    "FURB113", # repeated-append
    "FURB152", # math-constant
    "UP007", # non-pep604-annotation
    "UP032", # f-string
    "UP045", # non-pep604-annotation-optional
    "B005", # strip-with-multi-characters
    "B006", # mutable-argument-default
    "B007", # unused-loop-control-variable
    "B026", # star-arg-unpacking-after-keyword-arg
    "B903", # class-as-data-structure
    "B904", # raise-without-from-inside-except
    "B905", # zip-without-explicit-strict
    "N806", # non-lowercase-variable-in-function
    "N815", # mixed-case-variable-in-class-scope
    "PT011", # pytest-raises-too-broad
    "SIM102", # collapsible-if
    "SIM103", # needless-bool
    "SIM105", # suppressible-exception
    "SIM107", # return-in-try-except-finally
    "SIM108", # if-else-block-instead-of-if-exp
    "SIM113", # enumerate-for-loop
    "SIM117", # multiple-with-statements
    "SIM210", # if-expr-with-true-false
]

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "single"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

