[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "cxas-scrapi"
version = "1.8.0"
description = "A high level scripting API for CX Agent Studio developers."
readme = "README.md"
authors = [
  { name = "Patrick Marlow", email = "pmarlow@google.com" },
]
license = { text = "Apache-2.0" }
classifiers = [
  "Development Status :: 4 - Beta",
  "Intended Audience :: Developers",
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
  "Topic :: Communications :: Chat",
  "Topic :: Software Development",
  "Programming Language :: Python :: 3",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
  "Programming Language :: Python :: 3.13",
  "Programming Language :: Python :: 3.14",
]
keywords = ["ces", "google", "bot", "chatbot", "agent", "scrapi"]
requires-python = ">=3.10, <4"
dependencies = [
  "absl-py",
  "google-cloud-ces",
  "google-auth",
  "requests",
  "protobuf",
  "google-cloud-secret-manager",
  "pydantic",
  "jsonpath-ng",
  "pandas",
  "gspread",
  "gspread-dataframe",
  "ipython",
  "PyYAML",
  "google-genai",
  "pandas-gbq",
  "google-cloud-bigquery",
  "pytest",
  "google-cloud-texttospeech",
  "websocket-client",
  "certifi",
  "json5",
  "graphviz",
  "rich",
  "google-cloud-dialogflow-cx",
  "google-cloud-storage",
  "google-cloud-logging",
  "nest_asyncio",
  "jinja2",
  "scikit-learn",
  # InquirerPy powers the cxas-agent-foundry configure wizard and the
  # structural-consolidation grouping review TUI at
  # cxas_scrapi.migration.grouping_review. Imported lazily — only
  # callers that explicitly opt into the TUI pay the cost; the CLI's
  # `cxas migrate dfcx` interactive dashboard and `cxas migrate dfcx-cxas`
  # subcommands do NOT pull it in.
  "InquirerPy",
  "ratelimit",
  "pydub",
  "audioop-lts; python_version >= '3.13'",
]

[project.optional-dependencies]
dev = [
  "pytest-asyncio",
  "pytest-xdist",
  "pytest-cov",
  "ruff",
  "twine",
  "pre-commit",
  "mdformat>=0.7.21",
  "mdformat-gfm",
  "mdformat-frontmatter",
  "mdformat-gfm-alerts",
  "google-antigravity>=0.1.0",
  "markdown",
]
docs = [
  "mkdocs-material[imaging]>=9.5",
  "mkdocstrings[python]>=0.27",
  "mkdocs-git-revision-date-localized-plugin>=1.2",
  "mkdocs-minify-plugin>=0.8",
  "mike>=2.0",
]

[project.scripts]
cxas = "cxas_scrapi.cli.main:main"

[tool.hatch.build.targets.wheel.shared-data]
".agents" = "share/cxas-scrapi/skills/.agents"
".claude" = "share/cxas-scrapi/skills/.claude"
".gemini" = "share/cxas-scrapi/skills/.gemini"
"AGENTS.md" = "share/cxas-scrapi/skills/AGENTS.md"
"examples/cxaslint.yaml" = "share/cxas-scrapi/skills/examples/cxaslint.yaml"

[tool.hatch.build.targets.wheel]
packages = ["src/cxas_scrapi"]

[tool.ruff]
line-length = 80
target-version = "py310"
extend-exclude = ["*.ipynb", ".agents/skills/cxas-agent-foundry/assets/project-template/", ".agents/skills/cxas-agent-foundry/scripts", ".agents/skills/cxas-sim-eval/scripts", ".agents/skills/cxas-cuj-report-generator/", ".agents/skills/cxas-insights-sim-eval/scripts", "examples/", "skill_eval/scratch/"]

[tool.ruff.lint]
select = [
    "E",  # pycodestyle errors
    "W",  # pycodestyle warnings
    "F",  # pyflakes
    "I",  # isort
    "B",  # flake8-bugbear
    "PL", # pylint
    "RUF", # Ruff rules
    "UP",  # pyupgrade rules
    "ANN", # flake8-annotations
    "TCH", # flake8-type-checking
    "SIM", # flake8-simplify
    "PT",  # flake8-pytest-style
]
ignore = [
    "E203",  # extend-ignore = E203 from flake8
    # Add common PL ignores based on standard Google pylint defaults if Ruff implements them
    "PLR0913", # too-many-arguments
    "PLR0912", # too-many-branches
    "PLR0915", # too-many-statements
    "PLR0911", # too-many-return-statements
    "PLR0914", # too-many-locals
    "PLR2004", # magic-value-comparison
    "PLW0108", # unnecessary-lambda
    "RUF001",  # ambiguous unicode characters (allow emojis in visualizers)
    "RUF006",  # allow fire-and-forget create_task
    "RUF100",  # preserve unused noqa comments for external linter compatibility
    "RUF012",  # mutable class attributes (constants are fine)
    "ANN401",  # dynamically typed Any

    "ANN204",  # missing return type for __init__
]

[tool.ruff.lint.per-file-ignores]
"src/cxas_scrapi/cli/**" = ["PLC0415", "E501"]
"src/cxas_scrapi/migration/prompts.py" = ["E501"]
"src/cxas_scrapi/prompts/llm_lint_prompts.py" = ["E501"]
# html_preview is dominated by HTML/CSS template strings; wrapping them would
# hurt readability of the templates themselves. The Python code in this file
# is line-length compliant; only template strings exceed.
"src/cxas_scrapi/migration/html_preview.py" = ["E501"]
# Skill-local visualizer is a thin re-export shim over html_preview; the same
# exemption applies in case of any inline overrides.
".agents/skills/cxas-dfcx-migration/scripts/_visualizer.py" = ["E501"]
# Audio-analysis prompts are verbatim text intended for Gemini and must not be
# reflowed; line-length doesn't apply to prompt content.
"src/cxas_scrapi/utils/tracing/audio_analysis.py" = ["E501"]
# Benchmark orchestrator, reports generator, and scenarios contain multi-line HTML templates
# and long prompts that cannot be reflowed without breaking layout.
"skill_eval/**/*.py" = ["E501"]
"src/cxas_scrapi/utils/insights_analytics.py" = ["E501"]
"src/cxas_scrapi/utils/insights_utils.py" = ["E501"]
"examples/bella_notte/run_insights_demo.py" = ["E501"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"

[[tool.uv.index]]
url = "https://pypi.org/simple"
default = true
