datachat-agent 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datachat_agent-0.1.0/.env.example +73 -0
- datachat_agent-0.1.0/.github/workflows/ci.yml +95 -0
- datachat_agent-0.1.0/.github/workflows/release.yml +104 -0
- datachat_agent-0.1.0/.gitignore +30 -0
- datachat_agent-0.1.0/Dockerfile +11 -0
- datachat_agent-0.1.0/LICENSE +21 -0
- datachat_agent-0.1.0/PKG-INFO +353 -0
- datachat_agent-0.1.0/README.md +304 -0
- datachat_agent-0.1.0/docker-compose.yml +77 -0
- datachat_agent-0.1.0/docs/CHECKLIST.md +122 -0
- datachat_agent-0.1.0/docs/RELEASING.md +51 -0
- datachat_agent-0.1.0/eval/datasets/erp_demo.py +350 -0
- datachat_agent-0.1.0/eval/datasets/make_pdfs.py +212 -0
- datachat_agent-0.1.0/packages/datachat_agent/__init__.py +17 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/answer.py +162 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/answer_plan.py +186 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/cited_answer.py +156 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/doc_planner.py +47 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/graph.py +227 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/knowledge.py +61 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/router.py +46 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/service.py +61 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/sessions.py +52 -0
- datachat_agent-0.1.0/packages/datachat_agent/agent/tools.py +229 -0
- datachat_agent-0.1.0/packages/datachat_agent/cli.py +279 -0
- datachat_agent-0.1.0/packages/datachat_agent/client.py +413 -0
- datachat_agent-0.1.0/packages/datachat_agent/config.py +84 -0
- datachat_agent-0.1.0/packages/datachat_agent/core/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/core/embeddings.py +124 -0
- datachat_agent-0.1.0/packages/datachat_agent/core/llm.py +85 -0
- datachat_agent-0.1.0/packages/datachat_agent/core/pii.py +99 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/chunker.py +89 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/extract.py +93 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/ingest.py +132 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/items.py +192 -0
- datachat_agent-0.1.0/packages/datachat_agent/docs/search.py +140 -0
- datachat_agent-0.1.0/packages/datachat_agent/mcp_server.py +170 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/env.py +30 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/script.py.mako +25 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/versions/0001_initial_schema.py +268 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/versions/0002_agent_sessions_glossary_examples.py +112 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/versions/0003_document_heading_date.py +26 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/versions/0004_limits_feedback.py +30 -0
- datachat_agent-0.1.0/packages/datachat_agent/migrations/versions/0005_publishable_keys.py +38 -0
- datachat_agent-0.1.0/packages/datachat_agent/security.py +74 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/app.py +85 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/auth.py +88 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/db.py +52 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/jobs.py +86 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/limits.py +101 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/models.py +277 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/ask.py +395 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/connections.py +287 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/documents.py +231 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/feedback.py +54 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/health.py +10 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/keys.py +113 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/knowledge.py +238 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/schema_items.py +74 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/routes/usage.py +50 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/services.py +54 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/static/widget.js +62 -0
- datachat_agent-0.1.0/packages/datachat_agent/server/worker.py +44 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/__init__.py +0 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/connector.py +161 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/executor.py +110 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/generator.py +111 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/pipeline.py +120 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/schema_scanner.py +143 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/schema_store.py +270 -0
- datachat_agent-0.1.0/packages/datachat_agent/sql/validator.py +292 -0
- datachat_agent-0.1.0/pyproject.toml +78 -0
- datachat_agent-0.1.0/sdk-js/README.md +45 -0
- datachat_agent-0.1.0/sdk-js/package-lock.json +394 -0
- datachat_agent-0.1.0/sdk-js/package.json +30 -0
- datachat_agent-0.1.0/sdk-js/src/index.ts +245 -0
- datachat_agent-0.1.0/sdk-js/test/client.test.js +126 -0
- datachat_agent-0.1.0/sdk-js/tsconfig.json +14 -0
- datachat_agent-0.1.0/tests/__init__.py +0 -0
- datachat_agent-0.1.0/tests/conftest.py +31 -0
- datachat_agent-0.1.0/tests/fakes.py +64 -0
- datachat_agent-0.1.0/tests/integration/__init__.py +0 -0
- datachat_agent-0.1.0/tests/integration/conftest.py +156 -0
- datachat_agent-0.1.0/tests/integration/test_ask.py +415 -0
- datachat_agent-0.1.0/tests/integration/test_connections.py +175 -0
- datachat_agent-0.1.0/tests/integration/test_documents.py +443 -0
- datachat_agent-0.1.0/tests/integration/test_library.py +146 -0
- datachat_agent-0.1.0/tests/integration/test_mcp.py +99 -0
- datachat_agent-0.1.0/tests/integration/test_publishable_keys.py +202 -0
- datachat_agent-0.1.0/tests/integration/test_sql_pipeline.py +205 -0
- datachat_agent-0.1.0/tests/integration/test_week5.py +341 -0
- datachat_agent-0.1.0/tests/test_agent_units.py +187 -0
- datachat_agent-0.1.0/tests/test_api.py +48 -0
- datachat_agent-0.1.0/tests/test_llm.py +94 -0
- datachat_agent-0.1.0/tests/test_pii.py +80 -0
- datachat_agent-0.1.0/tests/test_security.py +44 -0
- datachat_agent-0.1.0/tests/test_validator.py +272 -0
- datachat_agent-0.1.0/widget/package-lock.json +2550 -0
- datachat_agent-0.1.0/widget/package.json +22 -0
- datachat_agent-0.1.0/widget/src/Widget.tsx +192 -0
- datachat_agent-0.1.0/widget/src/main.tsx +59 -0
- datachat_agent-0.1.0/widget/src/styles.ts +58 -0
- datachat_agent-0.1.0/widget/test/widget.test.tsx +131 -0
- datachat_agent-0.1.0/widget/tsconfig.json +14 -0
- datachat_agent-0.1.0/widget/vite.config.ts +27 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Copy this file to .env and fill in YOUR OWN values.
|
|
2
|
+
# .env is git-ignored: your keys never leave your machine.
|
|
3
|
+
|
|
4
|
+
# --- DataChat's own Postgres (needs the pgvector extension) ---
|
|
5
|
+
DATABASE_URL=postgresql://datachat:datachat@localhost:5432/datachat
|
|
6
|
+
REDIS_URL=redis://localhost:6379/0
|
|
7
|
+
|
|
8
|
+
# Encrypts stored database passwords and LLM keys. Generate with: datachat-agent gen-secret
|
|
9
|
+
SECRET_KEY=
|
|
10
|
+
|
|
11
|
+
# --- LLM: bring your own key ---
|
|
12
|
+
# Any OpenAI-compatible endpoint works. Pick ONE block and uncomment it.
|
|
13
|
+
LLM_PROVIDER=openai_compatible
|
|
14
|
+
|
|
15
|
+
# Groq (free tier): https://console.groq.com/keys
|
|
16
|
+
# LLM_BASE_URL=https://api.groq.com/openai/v1
|
|
17
|
+
# LLM_MODEL=llama-3.3-70b-versatile
|
|
18
|
+
|
|
19
|
+
# Google Gemini (free tier): https://aistudio.google.com/apikey
|
|
20
|
+
# LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
|
|
21
|
+
# LLM_MODEL=gemini-3.6-flash (names change often; check the models list in AI Studio)
|
|
22
|
+
|
|
23
|
+
# OpenRouter (models ending in :free): https://openrouter.ai/keys
|
|
24
|
+
# LLM_BASE_URL=https://openrouter.ai/api/v1
|
|
25
|
+
# LLM_MODEL=qwen/qwen-2.5-coder-32b-instruct:free
|
|
26
|
+
|
|
27
|
+
# Ollama (local, no key): https://ollama.com then: ollama pull qwen2.5-coder:7b
|
|
28
|
+
# LLM_BASE_URL=http://localhost:11434/v1
|
|
29
|
+
# LLM_MODEL=qwen2.5-coder:7b
|
|
30
|
+
|
|
31
|
+
# Claude: set LLM_PROVIDER=anthropic, leave LLM_BASE_URL empty
|
|
32
|
+
# LLM_MODEL=claude-sonnet-5-5
|
|
33
|
+
|
|
34
|
+
LLM_BASE_URL=
|
|
35
|
+
LLM_MODEL=
|
|
36
|
+
LLM_API_KEY=
|
|
37
|
+
# Free tiers get overloaded: list backup models (same provider and key) to try in order.
|
|
38
|
+
# LLM_FALLBACK_MODELS=gemini-3.5-flash,gemini-3.5-flash-lite
|
|
39
|
+
# Thinking models (Gemini 3.x) are faster and use fewer tokens with less reasoning:
|
|
40
|
+
# LLM_REASONING_EFFORT=low
|
|
41
|
+
# LLM_TIMEOUT_SECONDS=30
|
|
42
|
+
# LLM_MAX_RETRIES=1
|
|
43
|
+
|
|
44
|
+
# --- Embeddings (local and free by default) ---
|
|
45
|
+
# local: runs on your CPU, downloads ~70 MB once. openai_compatible: uses EMBED_BASE_URL/EMBED_API_KEY
|
|
46
|
+
# (falls back to the LLM settings).
|
|
47
|
+
EMBED_PROVIDER=local
|
|
48
|
+
EMBED_MODEL=BAAI/bge-small-en-v1.5
|
|
49
|
+
# Must match the model's vector size. Changing it later means re-creating the vector tables.
|
|
50
|
+
EMBED_DIM=384
|
|
51
|
+
# EMBED_BASE_URL=
|
|
52
|
+
# EMBED_API_KEY=
|
|
53
|
+
|
|
54
|
+
# --- Documents and background work ---
|
|
55
|
+
# MAX_PDF_MB=20
|
|
56
|
+
# sync: process uploads inside the request · inline: in the background of the API process (default)
|
|
57
|
+
# arq: in a separate `datachat-agent worker` process via Redis (what docker-compose uses)
|
|
58
|
+
# JOBS_BACKEND=inline
|
|
59
|
+
|
|
60
|
+
# --- Abuse and cost limits ---
|
|
61
|
+
# memory: per server process · redis: shared by all servers (use with several API servers)
|
|
62
|
+
# RATE_LIMIT_BACKEND=memory
|
|
63
|
+
# DEFAULT_RATE_LIMIT_PER_MINUTE=60
|
|
64
|
+
# DEFAULT_MONTHLY_TOKEN_LIMIT= (empty = no cap; per-tenant limits override it)
|
|
65
|
+
|
|
66
|
+
# Replace emails, phone numbers, card, Aadhaar and PAN numbers with placeholders before data
|
|
67
|
+
# is sent to the model; real values are put back into the answer.
|
|
68
|
+
# MASK_PII=false
|
|
69
|
+
|
|
70
|
+
# --- Limits on every query against a customer database ---
|
|
71
|
+
# SQL_TIMEOUT_SECONDS=10
|
|
72
|
+
# SQL_MAX_ROWS=500
|
|
73
|
+
# SQL_MAX_RESPONSE_BYTES=5000000
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12"]
|
|
14
|
+
services:
|
|
15
|
+
postgres:
|
|
16
|
+
image: pgvector/pgvector:pg17
|
|
17
|
+
env:
|
|
18
|
+
POSTGRES_USER: datachat
|
|
19
|
+
POSTGRES_PASSWORD: datachat
|
|
20
|
+
POSTGRES_DB: datachat
|
|
21
|
+
ports: ["5432:5432"]
|
|
22
|
+
options: >-
|
|
23
|
+
--health-cmd "pg_isready -U datachat"
|
|
24
|
+
--health-interval 5s --health-timeout 5s --health-retries 10
|
|
25
|
+
redis:
|
|
26
|
+
image: redis:7-alpine
|
|
27
|
+
ports: ["6379:6379"]
|
|
28
|
+
mysql:
|
|
29
|
+
image: mysql:8.4
|
|
30
|
+
env:
|
|
31
|
+
MYSQL_ROOT_PASSWORD: rootpass
|
|
32
|
+
ports: ["3307:3306"]
|
|
33
|
+
options: >-
|
|
34
|
+
--health-cmd "mysqladmin ping -h 127.0.0.1 -uroot -prootpass --silent"
|
|
35
|
+
--health-interval 5s --health-timeout 5s --health-retries 20
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python-version }}
|
|
41
|
+
cache: pip
|
|
42
|
+
- name: Install
|
|
43
|
+
run: pip install -e ".[dev]"
|
|
44
|
+
- name: Lint
|
|
45
|
+
run: |
|
|
46
|
+
ruff check .
|
|
47
|
+
ruff format --check .
|
|
48
|
+
- name: Tests (unit + integration against Postgres and MySQL)
|
|
49
|
+
run: pytest -q -rs
|
|
50
|
+
|
|
51
|
+
docker:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
- name: Build the self-host image
|
|
56
|
+
run: docker build -t datachat-agent:ci .
|
|
57
|
+
- name: CLI starts inside the image
|
|
58
|
+
run: docker run --rm datachat-agent:ci datachat-agent --help
|
|
59
|
+
|
|
60
|
+
js:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
- uses: actions/setup-node@v4
|
|
65
|
+
with:
|
|
66
|
+
node-version: 22
|
|
67
|
+
- name: SDK (sdk-js)
|
|
68
|
+
working-directory: sdk-js
|
|
69
|
+
run: |
|
|
70
|
+
npm ci
|
|
71
|
+
npm test
|
|
72
|
+
- name: Widget (widget)
|
|
73
|
+
working-directory: widget
|
|
74
|
+
run: |
|
|
75
|
+
npm ci
|
|
76
|
+
npx tsc -p tsconfig.json
|
|
77
|
+
npm test
|
|
78
|
+
npm run build
|
|
79
|
+
- name: The widget served by the API is the freshly built one
|
|
80
|
+
run: cmp widget/dist/widget.js packages/datachat_agent/server/static/widget.js
|
|
81
|
+
|
|
82
|
+
package:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
- uses: astral-sh/setup-uv@v6
|
|
87
|
+
- name: Build wheel and sdist
|
|
88
|
+
run: uv build
|
|
89
|
+
- name: Check package metadata
|
|
90
|
+
run: uvx twine check dist/*
|
|
91
|
+
- name: Wheel installs and starts
|
|
92
|
+
run: |
|
|
93
|
+
python -m venv /tmp/v && /tmp/v/bin/pip install dist/*.whl
|
|
94
|
+
/tmp/v/bin/datachat-agent --help
|
|
95
|
+
/tmp/v/bin/python -c "import datachat_agent, importlib.resources as r; assert r.files('datachat_agent').joinpath('server/static/widget.js').is_file()"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Push a tag like v0.1.0 to publish. The tag must match the version in pyproject.toml and
|
|
4
|
+
# sdk-js/package.json. See docs/RELEASING.md for the one-time PyPI and npm setup.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
verify:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
outputs:
|
|
13
|
+
version: ${{ steps.v.outputs.version }}
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- id: v
|
|
17
|
+
name: Tag, Python and npm versions agree
|
|
18
|
+
run: |
|
|
19
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
20
|
+
py=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
21
|
+
js=$(node -p "require('./sdk-js/package.json').version")
|
|
22
|
+
echo "tag=$tag python=$py npm=$js"
|
|
23
|
+
[ "$tag" = "$py" ] && [ "$tag" = "$js" ] || { echo "Versions differ"; exit 1; }
|
|
24
|
+
echo "version=$tag" >> "$GITHUB_OUTPUT"
|
|
25
|
+
|
|
26
|
+
pypi:
|
|
27
|
+
needs: verify
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
environment: pypi
|
|
30
|
+
permissions:
|
|
31
|
+
id-token: write # trusted publishing: no PyPI password stored in GitHub
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
- uses: astral-sh/setup-uv@v6
|
|
35
|
+
- run: uv build
|
|
36
|
+
- run: uvx twine check dist/*
|
|
37
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
38
|
+
|
|
39
|
+
npm:
|
|
40
|
+
needs: verify
|
|
41
|
+
# Off until npm is set up: Settings -> Secrets and variables -> Actions -> Variables ->
|
|
42
|
+
# PUBLISH_NPM = true (see docs/RELEASING.md).
|
|
43
|
+
if: vars.PUBLISH_NPM == 'true'
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment: npm
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write # trusted publishing and provenance
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
- uses: actions/setup-node@v4
|
|
51
|
+
with:
|
|
52
|
+
node-version: 22
|
|
53
|
+
registry-url: https://registry.npmjs.org
|
|
54
|
+
- run: npm install -g npm@latest # trusted publishing needs npm 11.5+
|
|
55
|
+
- working-directory: sdk-js
|
|
56
|
+
run: |
|
|
57
|
+
npm ci
|
|
58
|
+
npm test
|
|
59
|
+
npm publish --provenance --access public
|
|
60
|
+
|
|
61
|
+
docker:
|
|
62
|
+
needs: verify
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
contents: read
|
|
66
|
+
packages: write
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
- uses: docker/login-action@v3
|
|
70
|
+
with:
|
|
71
|
+
registry: ghcr.io
|
|
72
|
+
username: ${{ github.actor }}
|
|
73
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
74
|
+
- id: meta
|
|
75
|
+
uses: docker/metadata-action@v5
|
|
76
|
+
with:
|
|
77
|
+
images: ghcr.io/${{ github.repository_owner }}/datachat-agent
|
|
78
|
+
tags: |
|
|
79
|
+
type=semver,pattern={{version}}
|
|
80
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
81
|
+
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }}
|
|
82
|
+
- uses: docker/build-push-action@v6
|
|
83
|
+
with:
|
|
84
|
+
context: .
|
|
85
|
+
push: true
|
|
86
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
87
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
88
|
+
|
|
89
|
+
github-release:
|
|
90
|
+
needs: [pypi, npm, docker]
|
|
91
|
+
# A skipped npm job (not set up yet) must not block the release; a failed one does.
|
|
92
|
+
if: >-
|
|
93
|
+
!cancelled() && needs.pypi.result == 'success' && needs.docker.result == 'success'
|
|
94
|
+
&& needs.npm.result != 'failure'
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
permissions:
|
|
97
|
+
contents: write
|
|
98
|
+
steps:
|
|
99
|
+
- uses: actions/checkout@v4
|
|
100
|
+
- uses: softprops/action-gh-release@v2
|
|
101
|
+
with:
|
|
102
|
+
generate_release_notes: true
|
|
103
|
+
prerelease: ${{ contains(github.ref_name, '-') || startsWith(github.ref_name, 'v0.') }}
|
|
104
|
+
files: packages/datachat_agent/server/static/widget.js
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Secrets: never commit real keys, even free ones
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
|
|
6
|
+
# Python
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
|
|
19
|
+
# Node (sdk-js, widget, console)
|
|
20
|
+
node_modules/
|
|
21
|
+
|
|
22
|
+
# Editors / OS
|
|
23
|
+
.vscode/
|
|
24
|
+
.idea/
|
|
25
|
+
.DS_Store
|
|
26
|
+
Thumbs.db
|
|
27
|
+
|
|
28
|
+
# Local data
|
|
29
|
+
*.sqlite3
|
|
30
|
+
uploads/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
|
|
5
|
+
|
|
6
|
+
COPY pyproject.toml README.md ./
|
|
7
|
+
COPY packages ./packages
|
|
8
|
+
RUN pip install --no-cache-dir .
|
|
9
|
+
|
|
10
|
+
EXPOSE 8000
|
|
11
|
+
CMD ["sh", "-c", "datachat-agent init-db && datachat-agent serve --host 0.0.0.0 --port 8000"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DataChat contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: datachat-agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Open-source AI agent that answers questions from your SQL database and PDFs
|
|
5
|
+
Project-URL: Homepage, https://github.com/Ashish-devl/Data-chat-agent
|
|
6
|
+
Project-URL: Issues, https://github.com/Ashish-devl/Data-chat-agent/issues
|
|
7
|
+
Author: DataChat Agent contributors
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,fastapi,llm,mcp,pdf,rag,text-to-sql
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: alembic>=1.13
|
|
22
|
+
Requires-Dist: arq>=0.26
|
|
23
|
+
Requires-Dist: asyncpg>=0.29
|
|
24
|
+
Requires-Dist: cryptography>=43
|
|
25
|
+
Requires-Dist: fastapi>=0.115
|
|
26
|
+
Requires-Dist: fastembed>=0.4
|
|
27
|
+
Requires-Dist: langchain-anthropic>=0.2
|
|
28
|
+
Requires-Dist: langchain-openai>=0.2
|
|
29
|
+
Requires-Dist: langgraph>=1.0
|
|
30
|
+
Requires-Dist: mcp>=2.3
|
|
31
|
+
Requires-Dist: pdfplumber>=0.11
|
|
32
|
+
Requires-Dist: pgvector>=0.3
|
|
33
|
+
Requires-Dist: psycopg[binary]>=3.2
|
|
34
|
+
Requires-Dist: pydantic-settings>=2.4
|
|
35
|
+
Requires-Dist: pydantic>=2.7
|
|
36
|
+
Requires-Dist: pymysql>=1.1
|
|
37
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
38
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.30
|
|
39
|
+
Requires-Dist: sqlglot>=25
|
|
40
|
+
Requires-Dist: typer>=0.12
|
|
41
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
46
|
+
Requires-Dist: reportlab>=4; extra == 'dev'
|
|
47
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# DataChat Agent
|
|
51
|
+
|
|
52
|
+
An open-source AI agent that answers plain-English questions from your SQL database and your PDFs, and shows the SQL or page each answer came from.
|
|
53
|
+
|
|
54
|
+
> Status: preview release 0.1.0 (week 6 of 8 toward v1.0). Not ready for production use yet.
|
|
55
|
+
|
|
56
|
+
## Bring your own model key
|
|
57
|
+
|
|
58
|
+
DataChat Agent never ships with an LLM key. You use your own, from any OpenAI-compatible provider or Claude:
|
|
59
|
+
|
|
60
|
+
| Provider | Cost | Get a key |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| Groq | Free tier | https://console.groq.com/keys |
|
|
63
|
+
| Google Gemini | Free tier | https://aistudio.google.com/apikey |
|
|
64
|
+
| OpenRouter (`:free` models) | Free | https://openrouter.ai/keys |
|
|
65
|
+
| Ollama | Free, runs locally | https://ollama.com |
|
|
66
|
+
| OpenAI, Claude | Paid | Their consoles |
|
|
67
|
+
|
|
68
|
+
## Quickstart
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/Ashish-devl/Data-chat-agent.git
|
|
72
|
+
cd Data-chat-agent
|
|
73
|
+
cp .env.example .env # then fill in your LLM settings
|
|
74
|
+
pip install -e ".[dev]"
|
|
75
|
+
datachat-agent gen-secret # paste the output into SECRET_KEY in .env
|
|
76
|
+
datachat-agent check-llm # confirms your model key works
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Start Postgres (with pgvector) and Redis, then the API:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
docker compose up -d db redis
|
|
83
|
+
datachat-agent init-db
|
|
84
|
+
datachat-agent create-tenant "My company" # prints an admin API key, once
|
|
85
|
+
datachat-agent serve
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Or run everything in Docker: `docker compose up --build`.
|
|
89
|
+
|
|
90
|
+
API docs: http://localhost:8000/docs
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
curl http://localhost:8000/v1/keys -H "Authorization: Bearer dc_live_..."
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Connect a database
|
|
97
|
+
|
|
98
|
+
DataChat Agent only ever reads. Create a database user that can `SELECT` and nothing else; the
|
|
99
|
+
connection test refuses users that can write.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
KEY="Authorization: Bearer dc_live_..."
|
|
103
|
+
curl -X POST localhost:8000/v1/connections -H "$KEY" -H "Content-Type: application/json" -d '{"name": "erp", "dsn": "postgresql://readonly:pass@host:5432/erp"}'
|
|
104
|
+
curl -X POST localhost:8000/v1/connections/<id>/test -H "$KEY" # must say "ok"
|
|
105
|
+
curl -X POST localhost:8000/v1/connections/<id>/scan -H "$KEY" # reads tables and columns
|
|
106
|
+
curl localhost:8000/v1/connections/<id>/schema -H "$KEY"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Describe or hide columns (hidden columns can never be queried):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
curl -X PATCH localhost:8000/v1/schema-items/<item id> -H "$KEY" -H "Content-Type: application/json" -d '{"hidden": true}'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Teach it your business language and give it worked examples:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
curl -X POST localhost:8000/v1/connections/<id>/terms -H "$KEY" -H "Content-Type: application/json" -d '{"term": "open PO", "definition": "a purchase order whose status is Open or Partially Received"}'
|
|
119
|
+
curl -X POST localhost:8000/v1/connections/<id>/examples -H "$KEY" -H "Content-Type: application/json" -d '{"question": "Suppliers in Ludhiana", "sql": "SELECT name FROM suppliers WHERE city = '"'"'Ludhiana'"'"'"}'
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Ask questions
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
curl -X POST localhost:8000/v1/ask -H "$KEY" -H "Content-Type: application/json" -d '{"question": "Which production orders are delayed?", "session_id": "chat-1"}'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"answer": "There are 13 delayed production orders in total ...",
|
|
131
|
+
"route": "database",
|
|
132
|
+
"sql": "SELECT ... LIMIT 500",
|
|
133
|
+
"columns": ["style_no", "qty_behind"],
|
|
134
|
+
"rows": [{"style_no": "26C1740", "qty_behind": 1390}],
|
|
135
|
+
"chart": {"type": "bar", "x": "style_no", "y": "qty_behind"},
|
|
136
|
+
"session_id": "chat-1",
|
|
137
|
+
"latency_ms": 7126
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Send the same `session_id` for follow-ups ("which buyers are those for?"); read a conversation
|
|
142
|
+
with `GET /v1/sessions/chat-1`. Pass `connection_id` when you have more than one database, and
|
|
143
|
+
`user_context` (e.g. `{"user_company": 7}`) when the connection uses row filters. Keys need the
|
|
144
|
+
`ask` scope.
|
|
145
|
+
|
|
146
|
+
### Streaming
|
|
147
|
+
|
|
148
|
+
`POST /v1/ask/stream` takes the same body and answers as Server-Sent Events, so a chat window can
|
|
149
|
+
show the answer while it is being written:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
event: meta data: {"session_id": "chat-1", "route": "database"}
|
|
153
|
+
event: data data: {"sql": "SELECT ...", "rows": [...], "row_count": 13}
|
|
154
|
+
event: token data: {"text": "There are 13 "}
|
|
155
|
+
event: token data: {"text": "delayed orders ..."}
|
|
156
|
+
event: done data: { ...the same body /v1/ask returns... }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Feedback
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
curl -X POST localhost:8000/v1/feedback -H "$KEY" -H "Content-Type: application/json" -d '{"query_id": "<from the answer>", "rating": "wrong", "comment": "Should include line 7"}'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Limits and privacy
|
|
166
|
+
|
|
167
|
+
- Each API key may make `DEFAULT_RATE_LIMIT_PER_MINUTE` requests a minute (60 by default; 429 with
|
|
168
|
+
`Retry-After` beyond that). Use `RATE_LIMIT_BACKEND=redis` when several servers share the load.
|
|
169
|
+
- `DEFAULT_MONTHLY_TOKEN_LIMIT` caps model tokens per account per month. Operators set per-account
|
|
170
|
+
limits with `datachat-agent set-limits <tenant id> --per-minute 30 --monthly-tokens 500000` and
|
|
171
|
+
see them with `datachat-agent list-tenants`. `GET /v1/usage` shows an account its own use.
|
|
172
|
+
- `MASK_PII=true` replaces emails, phone numbers, card, Aadhaar and PAN numbers with placeholders
|
|
173
|
+
before anything reaches the model; the real values are put back into the answer.
|
|
174
|
+
|
|
175
|
+
## Upload PDFs
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
curl -X POST localhost:8000/v1/documents -H "$KEY" -F "file=@invoice.pdf;type=application/pdf"
|
|
179
|
+
curl localhost:8000/v1/documents -H "$KEY" # status: queued → ready
|
|
180
|
+
curl localhost:8000/v1/documents/<id>/items -H "$KEY" # line items from its tables
|
|
181
|
+
curl -o original.pdf localhost:8000/v1/documents/<id>/file -H "$KEY"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
PDFs with a text layer up to 20 MB; the same file uploaded twice is stored once. Text is split
|
|
185
|
+
into passages per page and searched by meaning and by keyword; tables become line items (item,
|
|
186
|
+
qty, unit, rate, amount). Answers from documents cite the file and page:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"answer": "The grand total of invoice KE/26-27/8231 is INR 773,550.00 [1].",
|
|
191
|
+
"route": "documents",
|
|
192
|
+
"citations": [{"ref": 1, "filename": "invoice_KE-26-27-8231.pdf", "page": 1,
|
|
193
|
+
"url": "/v1/documents/<id>/file#page=1"}]
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
One question can use both sources ("Which orders are delayed, and what carton weight does the
|
|
198
|
+
manual allow?"). Uploads need a key with the `docs` scope. Scanned PDFs without a text layer are
|
|
199
|
+
not supported yet. Generate made-up sample PDFs with `python eval/datasets/make_pdfs.py out/`.
|
|
200
|
+
|
|
201
|
+
Processing runs in the background of the API by default. With Docker, a separate `worker`
|
|
202
|
+
service does it (`JOBS_BACKEND=arq`), and it also re-scans every database schema nightly.
|
|
203
|
+
|
|
204
|
+
Try the SQL step alone from the command line:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
datachat-agent ask-sql <connection id> "Which production orders are delayed?"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Safety: three separate layers
|
|
211
|
+
|
|
212
|
+
1. The database user must be read-only (checked on test and before every scan).
|
|
213
|
+
2. Every query is parsed: one `SELECT` only, allowed tables only, no hidden columns, no admin
|
|
214
|
+
functions, `LIMIT 500` at most.
|
|
215
|
+
3. Queries run in a read-only transaction with a 10-second timeout.
|
|
216
|
+
|
|
217
|
+
Per-user row filters (`"row_filters": {"orders": "company_id = :user_company"}`) are wrapped around
|
|
218
|
+
every use of the table; a question without the user's context is refused.
|
|
219
|
+
|
|
220
|
+
## Five ways to use it
|
|
221
|
+
|
|
222
|
+
### 1. Python library (no server)
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pip install datachat-agent
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from datachat_agent import DataChat
|
|
230
|
+
|
|
231
|
+
with DataChat("postgresql://readonly:secret@host/erp") as dc:
|
|
232
|
+
dc.scan_schema() # refuses a user that can write
|
|
233
|
+
dc.hide("employees", "salary") # never shown to the model, never queryable
|
|
234
|
+
dc.add_term("open PO", "status is Open or Partially Received")
|
|
235
|
+
dc.add_pdf("invoice_8231.pdf")
|
|
236
|
+
print(dc.ask("What is the total of invoice KE/26-27/8231?").answer)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
It stores what it learns in its own Postgres with pgvector (`DATABASE_URL`, or
|
|
240
|
+
`DataChat(..., storage_url=...)`). `ask` returns `answer`, `sql`, `rows`, `citations` and `chart`;
|
|
241
|
+
`aask`, `ascan_schema` and `aadd_pdf` are the async versions.
|
|
242
|
+
|
|
243
|
+
### 2. Inside your FastAPI app
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from datachat_agent import mount
|
|
247
|
+
|
|
248
|
+
mount(app, prefix="/ai") # serves /ai/v1/ask, /ai/v1/documents, ... and /ai/widget.js
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Run `datachat-agent init-db` once to create its tables.
|
|
252
|
+
|
|
253
|
+
### 3. Self-hosted server (Docker)
|
|
254
|
+
|
|
255
|
+
`docker compose up --build` starts the API, a background worker, Postgres with pgvector and
|
|
256
|
+
Redis. Configure it with `.env`.
|
|
257
|
+
|
|
258
|
+
### 4. HTTP API, JavaScript SDK and chat widget
|
|
259
|
+
|
|
260
|
+
The API is described above and at `/docs` on a running server. From JavaScript:
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
import { DataChatClient } from "datachat-agent"; // npm install datachat-agent
|
|
264
|
+
const dc = new DataChatClient({ baseUrl: "https://api.example.com", apiKey: "dc_live_..." });
|
|
265
|
+
const a = await dc.ask("Which production orders are delayed?");
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
For a web page, create a **publishable** key that works only on your websites and can only ask:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
curl -X POST localhost:8000/v1/keys -H "$KEY" -H "Content-Type: application/json" -d '{"name": "website", "type": "publishable", "allowed_domains": ["erp.example.com"]}'
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
then add one line to the page:
|
|
275
|
+
|
|
276
|
+
```html
|
|
277
|
+
<script src="https://your-datachat-server/widget.js" data-key="dc_pub_..."
|
|
278
|
+
data-title="Ask about our data"></script>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Optional: `data-connection`, `data-position="left"`, `data-color="#0f766e"`,
|
|
282
|
+
`data-placeholder`. The widget streams answers, shows a small table and the sources, and has
|
|
283
|
+
Helpful / Wrong buttons. Publishable keys cannot send `user_context`, so a connection with row
|
|
284
|
+
filters refuses widget questions rather than guessing whose rows to show.
|
|
285
|
+
|
|
286
|
+
### 5. MCP server (Claude Desktop, IDEs)
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
datachat-agent mcp --api-key dc_live_...
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Tools: `list_tables`, `describe_table`, `run_sql`, `search_documents`, `get_document_items` and
|
|
293
|
+
`ask`, all read-only. In Claude Desktop's `claude_desktop_config.json`:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"mcpServers": {
|
|
298
|
+
"datachat": {
|
|
299
|
+
"command": "datachat-agent",
|
|
300
|
+
"args": ["mcp"],
|
|
301
|
+
"env": {
|
|
302
|
+
"DATACHAT_API_KEY": "dc_live_...",
|
|
303
|
+
"DATABASE_URL": "postgresql://datachat:datachat@localhost:5432/datachat",
|
|
304
|
+
"SECRET_KEY": "...",
|
|
305
|
+
"LLM_BASE_URL": "...", "LLM_MODEL": "...", "LLM_API_KEY": "..."
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Command line
|
|
313
|
+
|
|
314
|
+
| Command | Does |
|
|
315
|
+
| --- | --- |
|
|
316
|
+
| `datachat-agent serve` / `worker` | API server / background worker |
|
|
317
|
+
| `datachat-agent init-db` | Create or upgrade tables |
|
|
318
|
+
| `datachat-agent create-tenant NAME` | New account and its first admin key |
|
|
319
|
+
| `datachat-agent scan CONNECTION_ID` | Re-read a database schema |
|
|
320
|
+
| `datachat-agent ingest TENANT_ID FILE...` | Upload and process PDFs |
|
|
321
|
+
| `datachat-agent ask-sql CONNECTION_ID "question"` | Try the SQL step |
|
|
322
|
+
| `datachat-agent mcp` | MCP server over stdio |
|
|
323
|
+
| `datachat-agent list-tenants` / `set-limits` | Usage and limits |
|
|
324
|
+
| `datachat-agent check-llm` / `gen-secret` | Test the model / make a SECRET_KEY |
|
|
325
|
+
|
|
326
|
+
## Development
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
docker compose up -d db redis
|
|
330
|
+
docker compose --profile dev up -d mysql # optional: MySQL tests
|
|
331
|
+
pytest # unit + integration tests
|
|
332
|
+
ruff check . && ruff format --check .
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Integration tests create a throwaway `datachat_test` database and load `erp_demo`, a made-up
|
|
336
|
+
garment-factory ERP (`eval/datasets/erp_demo.py`), into Postgres and MySQL. They are skipped when
|
|
337
|
+
the databases are not running. Load the sample yourself to try the API:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
python eval/datasets/erp_demo.py postgresql://datachat:datachat@localhost:5432/postgres
|
|
341
|
+
# then connect with: postgresql://erp_readonly:erp_readonly@localhost:5432/erp_demo
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
After changing `server/models.py`, generate a migration with
|
|
345
|
+
`datachat-agent make-migration "what changed"`.
|
|
346
|
+
|
|
347
|
+
JavaScript parts: `cd sdk-js && npm ci && npm test`; `cd widget && npm ci && npm test && npm run build`,
|
|
348
|
+
then copy `widget/dist/widget.js` to `packages/datachat_agent/server/static/` (CI checks they
|
|
349
|
+
match). Releases: see [docs/RELEASING.md](docs/RELEASING.md).
|
|
350
|
+
|
|
351
|
+
## Licence
|
|
352
|
+
|
|
353
|
+
MIT
|