mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 10:15:21 +00:00
refactor: rename the application package to docsgpt
The backend import package is now docsgpt, the name it will carry on PyPI; application was far too generic to install into anyone's site-packages. git mv plus a mechanical rewrite of every import, dotted string and path reference: 734 Python files, the compose files, Dockerfile, workflows, docs, setup scripts, devcontainer, k8s manifests, vscode config, pytest and coverage config, .gitignore. Behaviour is unchanged. Kept for one release: - A top-level application package whose meta-path finder resolves application.x.y to the already-imported docsgpt.x.y object, so old imports and entry points (celery -A application.app.celery, uvicorn application.asgi:asgi_app) keep working with a FutureWarning. - Celery registers every application.* task name as an alias of its docsgpt.* task on start-up, so messages queued by the previous release still run. The redbeat key prefix moves to redbeat:docsgpt:v2: so schedule entries the previous release wrote are left unread instead of firing twice. The backend image builds from the repository root (docker build -f docsgpt/Dockerfile .) so it can ship the alias package; a root .dockerignore allow-lists docsgpt/ and application/ and keeps caches, local data, .env files, the sample index files and the Dockerfile out. Compose and the image workflows point at the new context.
This commit is contained in:
1 parent
3e7f1f91b4
commit
574f96341e
984 files changed
+9847
-9682
No files matched your search
@@ -18,7 +18,7 @@ Then set in .env::
|
||||
DAYTONA_SNAPSHOT=docsgpt-artifacts-py312
|
||||
|
||||
Keep the pins in sync with the backend venv (python-pptx / openpyxl / lxml /
|
||||
pillow are in application/requirements.txt; python-docx and reportlab arrive
|
||||
pillow are in docsgpt/requirements.txt; python-docx and reportlab arrive
|
||||
transitively) so the Daytona render output matches the Jupyter-backend output.
|
||||
"""
|
||||
|
||||
@@ -57,7 +57,7 @@ def main(argv: list[str]) -> int:
|
||||
"""Build (or skip) the snapshot and print the value to set as DAYTONA_SNAPSHOT."""
|
||||
args = _parse_args(argv)
|
||||
|
||||
from application.core.settings import settings
|
||||
from docsgpt.core.settings import settings
|
||||
|
||||
if not settings.DAYTONA_API_KEY:
|
||||
print("DAYTONA_API_KEY is not set (check .env).", file=sys.stderr)
|
||||
|
||||
@@ -14,7 +14,7 @@ only knobs operators need. This script discovers what's available from
|
||||
the :data:`BACKFILLERS` registry and runs whichever tables were asked for.
|
||||
|
||||
This script imports ``pymongo`` directly. ``pymongo`` is not part of the
|
||||
base ``application/requirements.txt`` post-migration — install it
|
||||
base ``docsgpt/requirements.txt`` post-migration — install it
|
||||
directly before running::
|
||||
|
||||
pip install 'pymongo>=4.6'
|
||||
@@ -49,13 +49,13 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from sqlalchemy import Connection, text # noqa: E402
|
||||
|
||||
from application.core.settings import settings # noqa: E402
|
||||
from application.storage.db.engine import get_engine # noqa: E402
|
||||
from docsgpt.core.settings import settings # noqa: E402
|
||||
from docsgpt.storage.db.engine import get_engine # noqa: E402
|
||||
|
||||
|
||||
# The backfill tool is the one remaining consumer of MongoDB in this repo.
|
||||
# It reads from Mongo and writes to Postgres, so it keeps its own client
|
||||
# rather than going through the (now-deleted) ``application.core.mongo_db``
|
||||
# rather than going through the (now-deleted) ``docsgpt.core.mongo_db``
|
||||
# wrapper. The DB name is hard-coded to ``docsgpt`` — historically surfaced
|
||||
# as ``settings.MONGO_DB_NAME`` but that setting has been removed post-cutover.
|
||||
_MONGO_DB_NAME = "docsgpt"
|
||||
@@ -889,7 +889,7 @@ def _rename_faiss_indexes(
|
||||
)
|
||||
return stats
|
||||
|
||||
from application.storage.storage_creator import StorageCreator
|
||||
from docsgpt.storage.storage_creator import StorageCreator
|
||||
|
||||
storage = StorageCreator.get_storage()
|
||||
storage_type = getattr(storage, "__class__", type(storage)).__name__
|
||||
@@ -1302,14 +1302,14 @@ def _backfill_memories(
|
||||
Mongo memory docs don't carry the body inline — ``content`` lives on
|
||||
disk at ``doc["storage_path"]`` (e.g.
|
||||
``inputs/local/memories/<oid>/memory.txt``) and is accessed through
|
||||
:class:`application.storage.storage_creator.StorageCreator`. We read
|
||||
:class:`docsgpt.storage.storage_creator.StorageCreator`. We read
|
||||
the file lazily here so the PG ``content`` column gets the actual
|
||||
memory text rather than an empty string. Missing/unreadable files are
|
||||
logged and fall back to an empty ``content`` so one bad row doesn't
|
||||
abort the whole batch. Import is lazy (matches ``_rename_faiss_indexes``)
|
||||
so ``storage`` / backend creds aren't required to import this module.
|
||||
"""
|
||||
from application.storage.storage_creator import StorageCreator
|
||||
from docsgpt.storage.storage_creator import StorageCreator
|
||||
|
||||
storage = StorageCreator.get_storage()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Backfill ``token_usage.model_id`` for rows written before the column.
|
||||
|
||||
New rows get ``model_id`` stamped at write time (see
|
||||
``application.llm.llm_creator`` / ``application.usage``). This script
|
||||
``docsgpt.llm.llm_creator`` / ``docsgpt.usage``). This script
|
||||
fills the historical NULLs by deriving the model from data we already
|
||||
trust, in priority order. A row is only ever filled by the
|
||||
highest-priority tier that matches it; tiers run in one transaction so
|
||||
@@ -60,7 +60,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from sqlalchemy import text # noqa: E402
|
||||
|
||||
from application.storage.db.engine import get_engine # noqa: E402
|
||||
from docsgpt.storage.db.engine import get_engine # noqa: E402
|
||||
|
||||
|
||||
# Tier 1: same request -> same model, primary (agent_stream) rows only.
|
||||
|
||||
@@ -40,7 +40,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from sqlalchemy import text # noqa: E402
|
||||
|
||||
from application.storage.db.engine import get_engine # noqa: E402
|
||||
from docsgpt.storage.db.engine import get_engine # noqa: E402
|
||||
|
||||
|
||||
# Tier 1: parent message → user, conversation → agent.
|
||||
|
||||
@@ -13,7 +13,7 @@ Intended use:
|
||||
|
||||
This script is a thin wrapper around ``alembic upgrade head``. It exists
|
||||
separately so the same command is discoverable from the repo root without
|
||||
remembering the ``-c application/alembic.ini`` invocation.
|
||||
remembering the ``-c docsgpt/alembic.ini`` invocation.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -25,7 +25,7 @@ from alembic import command
|
||||
from alembic.config import Config
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
ALEMBIC_INI = REPO_ROOT / "application" / "alembic.ini"
|
||||
ALEMBIC_INI = REPO_ROOT / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Rewrite stored model IDs across active config tables.
|
||||
|
||||
Run this when a provider renames or deprecates a model ID. The catalog
|
||||
in ``application/core/models/<provider>.yaml`` is updated to the new ID,
|
||||
in ``docsgpt/core/models/<provider>.yaml`` is updated to the new ID,
|
||||
but existing agents and schedules still reference the old one and will
|
||||
fail on the next call. This script rewrites every active config row
|
||||
in-place inside a single transaction.
|
||||
@@ -51,7 +51,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from sqlalchemy import text # noqa: E402
|
||||
|
||||
from application.storage.db.session import db_session # noqa: E402
|
||||
from docsgpt.storage.db.session import db_session # noqa: E402
|
||||
|
||||
|
||||
# Built-in mapping reflects the 2026-05-25 Google preview -> GA swap.
|
||||
|
||||
@@ -28,7 +28,7 @@ verbatim as the conversation's prompt). See
|
||||
|
||||
Run standalone (does NOT import anything from ``application/``). Python 3.11+.
|
||||
Flask is the only non-stdlib dependency and is already in
|
||||
``application/requirements.txt``.
|
||||
``docsgpt/requirements.txt``.
|
||||
|
||||
Usage::
|
||||
|
||||
@@ -482,7 +482,7 @@ def _stream_chat_response(
|
||||
if tool_calls and toolcall_arg_mode:
|
||||
# Frame-split mode: the call's ``arguments`` are spread over several
|
||||
# deltas that all share one ``index``, which is what the client-side
|
||||
# merge in application/llm/handlers/base.py reassembles.
|
||||
# merge in docsgpt/llm/handlers/base.py reassembles.
|
||||
call = tool_calls[0]
|
||||
frames = _toolcall_arg_frames(call["function"]["arguments"], toolcall_arg_mode)
|
||||
for position, piece in enumerate(frames):
|
||||
|
||||
@@ -20,7 +20,7 @@ comes from ``MOCK_OIDC_GROUPS`` (comma-separated).
|
||||
|
||||
Run standalone (does NOT import anything from ``application/``). Dependencies
|
||||
(flask, python-jose, cryptography, requests) are all in
|
||||
``application/requirements.txt``.
|
||||
``docsgpt/requirements.txt``.
|
||||
|
||||
Usage::
|
||||
|
||||
|
||||
+4
-4
@@ -255,7 +255,7 @@ FLASK_PID="$PIDDIR/flask.pid"
|
||||
log "starting Flask on 127.0.0.1:$FLASK_PORT"
|
||||
(
|
||||
cd "$E2E_TMP"
|
||||
PYTHONUNBUFFERED=1 nohup "$FLASK_BIN" --app ../application/app.py run \
|
||||
PYTHONUNBUFFERED=1 nohup "$FLASK_BIN" --app ../docsgpt/app.py run \
|
||||
--host 127.0.0.1 --port "$FLASK_PORT" \
|
||||
>"$FLASK_LOG" 2>&1 &
|
||||
echo $! > "$FLASK_PID"
|
||||
@@ -275,7 +275,7 @@ log "starting Celery worker (solo pool)"
|
||||
cd "$E2E_TMP"
|
||||
PYTHONPATH="$REPO_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
nohup "$PY_BIN" -m celery -A application.app.celery worker \
|
||||
nohup "$PY_BIN" -m celery -A docsgpt.app.celery worker \
|
||||
-l INFO --pool=solo -Q docsgpt,parsing \
|
||||
--without-gossip --without-mingle --without-heartbeat \
|
||||
>"$CELERY_LOG" 2>&1 &
|
||||
@@ -290,7 +290,7 @@ if ! wait_for_log "celery 'celery@'" 30 "$CELERY_LOG" "celery@"; then
|
||||
fi
|
||||
|
||||
# Ready check via `celery inspect ping`. We can't grep the log for 'ready'
|
||||
# because application/core/logging_config.py calls dictConfig with the default
|
||||
# because docsgpt/core/logging_config.py calls dictConfig with the default
|
||||
# disable_existing_loggers=True, which silences celery.worker's ready banner.
|
||||
# `inspect ping` queries the worker over the broker — it's the canonical
|
||||
# responsiveness check and doesn't depend on log output.
|
||||
@@ -301,7 +301,7 @@ while (( elapsed < CELERY_INSPECT_TIMEOUT )); do
|
||||
if ( cd "$E2E_TMP" && \
|
||||
PYTHONPATH="$REPO_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
"$PY_BIN" -m celery -A application.app.celery inspect ping \
|
||||
"$PY_BIN" -m celery -A docsgpt.app.celery inspect ping \
|
||||
--timeout 2 >/dev/null 2>&1 ); then
|
||||
ping_ok=1
|
||||
log " -> celery inspect ping OK after ${elapsed}s"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# bash scripts/export_requirements.sh
|
||||
#
|
||||
# Each exported file is a complete environment (core plus the named extra),
|
||||
# so `pip install -r application/requirements-docling.txt` on its own works,
|
||||
# so `pip install -r docsgpt/requirements-docling.txt` on its own works,
|
||||
# and installing it on top of requirements.txt only adds the extra's packages.
|
||||
set -euo pipefail
|
||||
|
||||
@@ -40,18 +40,18 @@ export_file() {
|
||||
echo "wrote $out ($(grep -cE '^[A-Za-z0-9]' "$out") packages)"
|
||||
}
|
||||
|
||||
export_file application/requirements.txt \
|
||||
export_file docsgpt/requirements.txt \
|
||||
"Core runtime. Optional extras live in requirements-<extra>.txt:
|
||||
docling DOC_PARSER_ENGINE=docling, docling OCR backend, read_document structured output
|
||||
milvus VECTOR_STORE=milvus"
|
||||
|
||||
INDEX_URL=https://download.pytorch.org/whl/cpu export_file application/requirements-docling.txt \
|
||||
INDEX_URL=https://download.pytorch.org/whl/cpu export_file docsgpt/requirements-docling.txt \
|
||||
"Core runtime plus the docling extra: DOC_PARSER_ENGINE=docling, the docling
|
||||
OCR backend (layout-model hybrid OCR, ocrmac/rapidocr engines), .adoc/.vtt/.xml
|
||||
attachment parsing, and read_document's 'structured' output. The default
|
||||
anydoc engine needs none of this, and OCR itself does not either:
|
||||
OCR_ENABLED=true with the tesseract binary (or a DeepSeek-OCR endpoint) runs
|
||||
through application/parser/file/ocr_parser.py.
|
||||
through docsgpt/parser/file/ocr_parser.py.
|
||||
On Linux torch comes from the CPU-only PyTorch index (no CUDA stack); a GPU
|
||||
deployment can reinstall torch from PyPI on top.
|
||||
pip resolves the extra index as expected. uv only takes a package from the
|
||||
@@ -61,7 +61,7 @@ pins the index per package) or set UV_INDEX_STRATEGY=unsafe-best-match.
|
||||
Docker: --build-arg EXTRAS=docling" \
|
||||
--extra docling
|
||||
|
||||
export_file application/requirements-milvus.txt \
|
||||
export_file docsgpt/requirements-milvus.txt \
|
||||
"Core runtime plus the milvus extra (VECTOR_STORE=milvus): pymilvus and the
|
||||
embedded milvus-lite server, which pulls pyarrow.
|
||||
Docker: --build-arg EXTRAS=milvus" \
|
||||
|
||||
@@ -33,10 +33,10 @@ import dotenv # noqa: E402
|
||||
|
||||
dotenv.load_dotenv()
|
||||
|
||||
from application.storage.db.repositories.auth_events import AuthEventsRepository # noqa: E402
|
||||
from application.storage.db.repositories.user_roles import UserRolesRepository # noqa: E402
|
||||
from application.storage.db.repositories.users import UsersRepository # noqa: E402
|
||||
from application.storage.db.session import db_readonly, db_session # noqa: E402
|
||||
from docsgpt.storage.db.repositories.auth_events import AuthEventsRepository # noqa: E402
|
||||
from docsgpt.storage.db.repositories.user_roles import UserRolesRepository # noqa: E402
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository # noqa: E402
|
||||
from docsgpt.storage.db.session import db_readonly, db_session # noqa: E402
|
||||
|
||||
logging.basicConfig(level=logging.WARNING, format="%(levelname)s %(message)s")
|
||||
logger = logging.getLogger("grant_admin")
|
||||
|
||||
@@ -52,8 +52,8 @@ def migrate_faiss_to_v1_vectorstore():
|
||||
|
||||
vectors = list(vectors_collection.find())
|
||||
for vector in tqdm(vectors, desc="Migrating FAISS vectors"):
|
||||
old_path = f"./application/indexes/{vector['user']}/{vector['name']}"
|
||||
new_path = f"./application/indexes/{vector['_id']}"
|
||||
old_path = f"./docsgpt/indexes/{vector['user']}/{vector['name']}"
|
||||
new_path = f"./docsgpt/indexes/{vector['_id']}"
|
||||
try:
|
||||
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
||||
shutil.move(old_path, new_path)
|
||||
|
||||
@@ -54,7 +54,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bootstrap: import application/* and connect to the configured Postgres.
|
||||
# Bootstrap: import docsgpt/* and connect to the configured Postgres.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
@@ -84,9 +84,9 @@ UNIQUE = f"qa_e2e_{int(time.time())}_{uuid.uuid4().hex[:6]}"
|
||||
|
||||
# Quiet noisy library loggers so the script's own output stays readable.
|
||||
for name in (
|
||||
"application", "application.api", "application.storage",
|
||||
"application.usage", "application.parser",
|
||||
"application.api.user.reconciliation",
|
||||
"application", "docsgpt.api", "docsgpt.storage",
|
||||
"docsgpt.usage", "docsgpt.parser",
|
||||
"docsgpt.api.user.reconciliation",
|
||||
):
|
||||
logging.getLogger(name).setLevel(logging.ERROR)
|
||||
|
||||
@@ -260,11 +260,11 @@ def s1_wal_and_reconciler() -> None:
|
||||
a stuck pending row to ``failed`` after 3 attempts and emits a
|
||||
structured alert."""
|
||||
|
||||
from application.api.answer.services.conversation_service import (
|
||||
from docsgpt.api.answer.services.conversation_service import (
|
||||
ConversationService,
|
||||
TERMINATED_RESPONSE_PLACEHOLDER,
|
||||
)
|
||||
from application.api.user.reconciliation import run_reconciliation
|
||||
from docsgpt.api.user.reconciliation import run_reconciliation
|
||||
|
||||
user = f"{UNIQUE}-s1"
|
||||
with ENGINE.begin() as c:
|
||||
@@ -273,7 +273,7 @@ def s1_wal_and_reconciler() -> None:
|
||||
{"u": user},
|
||||
)
|
||||
|
||||
with patch_db_session("application.api.answer.services.conversation_service"):
|
||||
with patch_db_session("docsgpt.api.answer.services.conversation_service"):
|
||||
res = ConversationService().save_user_question(
|
||||
conversation_id=None,
|
||||
question=f"{UNIQUE} s1 stuck WAL",
|
||||
@@ -348,8 +348,8 @@ def s2_webhook_idempotency_and_scoping() -> None:
|
||||
|
||||
from flask import Flask
|
||||
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user_a = f"{UNIQUE}-s2a"
|
||||
user_b = f"{UNIQUE}-s2b"
|
||||
@@ -382,8 +382,8 @@ def s2_webhook_idempotency_and_scoping() -> None:
|
||||
raw_key = f"{UNIQUE}-key-1"
|
||||
|
||||
# Sequential dedup: same key twice → same task_id, single apply_async call.
|
||||
with patch_db_session("application.api.user.agents.webhooks"), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
with patch_db_session("docsgpt.api.user.agents.webhooks"), patch(
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
):
|
||||
for _ in range(2):
|
||||
@@ -410,8 +410,8 @@ def s2_webhook_idempotency_and_scoping() -> None:
|
||||
apply_mock.reset_mock()
|
||||
apply_calls.clear()
|
||||
cross_key = f"{UNIQUE}-cross"
|
||||
with patch_db_session("application.api.user.agents.webhooks"), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
with patch_db_session("docsgpt.api.user.agents.webhooks"), patch(
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
):
|
||||
for ag in (agent_a, agent_b):
|
||||
@@ -453,11 +453,11 @@ def s3_ingest_deterministic_and_resume() -> None:
|
||||
"""Deterministic source_id is stable; chunk-progress checkpoint
|
||||
resumes from the next un-embedded chunk."""
|
||||
|
||||
from application.parser.embedding_pipeline import _read_resume_index
|
||||
from application.storage.db.repositories.ingest_chunk_progress import (
|
||||
from docsgpt.parser.embedding_pipeline import _read_resume_index
|
||||
from docsgpt.storage.db.repositories.ingest_chunk_progress import (
|
||||
IngestChunkProgressRepository,
|
||||
)
|
||||
from application.worker import _derive_source_id
|
||||
from docsgpt.worker import _derive_source_id
|
||||
|
||||
# Same scoped key → same uuid5; different scope → different uuid5.
|
||||
a = _derive_source_id("alice:UPLOAD-1")
|
||||
@@ -475,7 +475,7 @@ def s3_ingest_deterministic_and_resume() -> None:
|
||||
|
||||
# Checkpoint primitive: seed progress, observe resume index.
|
||||
src_id = uuid.uuid4()
|
||||
with patch_db_session("application.parser.embedding_pipeline"):
|
||||
with patch_db_session("docsgpt.parser.embedding_pipeline"):
|
||||
with ENGINE.begin() as conn:
|
||||
repo = IngestChunkProgressRepository(conn)
|
||||
repo.init_progress(str(src_id), total_chunks=10)
|
||||
@@ -497,11 +497,11 @@ def s4_token_usage_atomic_rollback() -> None:
|
||||
insert; the surrounding transaction must roll back so no orphan
|
||||
token_usage row survives."""
|
||||
|
||||
from application.api.answer.services.conversation_service import (
|
||||
from docsgpt.api.answer.services.conversation_service import (
|
||||
ConversationService,
|
||||
)
|
||||
from application.storage.db.repositories import conversations as conv_mod
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories import conversations as conv_mod
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
|
||||
@@ -531,8 +531,8 @@ def s4_token_usage_atomic_rollback() -> None:
|
||||
try:
|
||||
conv_mod.ConversationsRepository.update_message_by_id = explode
|
||||
with patch_db_session(
|
||||
"application.api.answer.services.conversation_service",
|
||||
), suppress_logging("application.api.answer.services.conversation_service"):
|
||||
"docsgpt.api.answer.services.conversation_service",
|
||||
), suppress_logging("docsgpt.api.answer.services.conversation_service"):
|
||||
try:
|
||||
ConversationService().finalize_message(
|
||||
mid,
|
||||
@@ -577,7 +577,7 @@ def s5_reconciler_tool_call_sweeps() -> None:
|
||||
flips proposed→failed and executed→failed (or compensated when the
|
||||
tool exposes a working compensate)."""
|
||||
|
||||
from application.api.user.reconciliation import run_reconciliation
|
||||
from docsgpt.api.user.reconciliation import run_reconciliation
|
||||
|
||||
user = f"{UNIQUE}-s5"
|
||||
with ENGINE.begin() as c:
|
||||
@@ -687,7 +687,7 @@ def s6_resume_janitor() -> None:
|
||||
)
|
||||
info(f"seeded pending_tool_state in 'resuming' (resumed_at=-11m) for conv={cid}")
|
||||
|
||||
from application.api.user.tasks import cleanup_pending_tool_state
|
||||
from docsgpt.api.user.tasks import cleanup_pending_tool_state
|
||||
|
||||
res = cleanup_pending_tool_state.run()
|
||||
info(f"janitor result: {res}")
|
||||
@@ -712,13 +712,13 @@ def s7_token_usage_attribution() -> None:
|
||||
``_persist_token_usage_inline`` self-write a row; the canary fires
|
||||
when ``status='complete'`` arrives with zero counts."""
|
||||
|
||||
from application.api.answer.services.conversation_service import (
|
||||
from docsgpt.api.answer.services.conversation_service import (
|
||||
ConversationService,
|
||||
)
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
from application.usage import _maybe_persist_inline
|
||||
from docsgpt.usage import _maybe_persist_inline
|
||||
|
||||
user = f"{UNIQUE}-s7"
|
||||
with ENGINE.begin() as c:
|
||||
@@ -747,7 +747,7 @@ def s7_token_usage_attribution() -> None:
|
||||
mid_zero = str(msg2["id"])
|
||||
|
||||
# 1. Real counts → row written, source='agent_stream'.
|
||||
with patch_db_session("application.api.answer.services.conversation_service"):
|
||||
with patch_db_session("docsgpt.api.answer.services.conversation_service"):
|
||||
ok = ConversationService().finalize_message(
|
||||
mid_real,
|
||||
"answer",
|
||||
@@ -771,7 +771,7 @@ def s7_token_usage_attribution() -> None:
|
||||
|
||||
# 2. Zero-count complete fires the canary alert.
|
||||
canary_logger = logging.getLogger(
|
||||
"application.api.answer.services.conversation_service"
|
||||
"docsgpt.api.answer.services.conversation_service"
|
||||
)
|
||||
seen: list[logging.LogRecord] = []
|
||||
|
||||
@@ -787,7 +787,7 @@ def s7_token_usage_attribution() -> None:
|
||||
canary_logger.setLevel(logging.WARNING)
|
||||
try:
|
||||
with patch_db_session(
|
||||
"application.api.answer.services.conversation_service",
|
||||
"docsgpt.api.answer.services.conversation_service",
|
||||
):
|
||||
ConversationService().finalize_message(
|
||||
mid_zero,
|
||||
@@ -817,7 +817,7 @@ def s7_token_usage_attribution() -> None:
|
||||
_persist_token_usage_inline = True
|
||||
_token_usage_source = "compression"
|
||||
|
||||
with patch_db_session("application.usage"):
|
||||
with patch_db_session("docsgpt.usage"):
|
||||
_maybe_persist_inline(
|
||||
_SideLLM(),
|
||||
{"prompt_tokens": 250, "generated_tokens": 80},
|
||||
@@ -839,10 +839,10 @@ def s8_regenerate_replaces() -> None:
|
||||
position N before reserving the placeholder, so the new row lands at
|
||||
position=N (replacing the old) rather than appending at the end."""
|
||||
|
||||
from application.api.answer.services.conversation_service import (
|
||||
from docsgpt.api.answer.services.conversation_service import (
|
||||
ConversationService,
|
||||
)
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
|
||||
@@ -871,7 +871,7 @@ def s8_regenerate_replaces() -> None:
|
||||
assert before == [0, 1, 2, 3, 4], f"seed wrong: {before}"
|
||||
info(f"seeded conv={cid} positions={before}")
|
||||
|
||||
with patch_db_session("application.api.answer.services.conversation_service"):
|
||||
with patch_db_session("docsgpt.api.answer.services.conversation_service"):
|
||||
result = ConversationService().save_user_question(
|
||||
conversation_id=cid,
|
||||
question=f"{UNIQUE}-regen",
|
||||
@@ -899,7 +899,7 @@ def s9_idempotency_concurrent_claim() -> None:
|
||||
Confirms the ON CONFLICT DO NOTHING race semantics for the HTTP
|
||||
claim-first pattern."""
|
||||
|
||||
from application.storage.db.repositories.idempotency import (
|
||||
from docsgpt.storage.db.repositories.idempotency import (
|
||||
IdempotencyRepository,
|
||||
)
|
||||
|
||||
@@ -1033,7 +1033,7 @@ def _build_openai_llm():
|
||||
"""Construct an OpenAI-provider LLM pointing at the mock LLM. Skips
|
||||
the BYOM resolution path that LLMCreator usually goes through, since
|
||||
we just want a direct openai-client wrapper for the mock."""
|
||||
from application.llm.openai import OpenAILLM
|
||||
from docsgpt.llm.openai import OpenAILLM
|
||||
|
||||
return OpenAILLM(
|
||||
api_key="mock-key",
|
||||
@@ -1061,7 +1061,7 @@ def s11_live_llm_stream_through_wal() -> None:
|
||||
streamed response captured.
|
||||
"""
|
||||
|
||||
from application.api.answer.services.conversation_service import (
|
||||
from docsgpt.api.answer.services.conversation_service import (
|
||||
ConversationService,
|
||||
)
|
||||
|
||||
@@ -1072,7 +1072,7 @@ def s11_live_llm_stream_through_wal() -> None:
|
||||
{"u": user},
|
||||
)
|
||||
|
||||
with patch_db_session("application.api.answer.services.conversation_service"):
|
||||
with patch_db_session("docsgpt.api.answer.services.conversation_service"):
|
||||
res = ConversationService().save_user_question(
|
||||
conversation_id=None,
|
||||
question=f"{UNIQUE} say hello",
|
||||
@@ -1105,7 +1105,7 @@ def s11_live_llm_stream_through_wal() -> None:
|
||||
f"response[:40]={response_text[:40]!r}"
|
||||
)
|
||||
|
||||
with patch_db_session("application.api.answer.services.conversation_service"):
|
||||
with patch_db_session("docsgpt.api.answer.services.conversation_service"):
|
||||
ok = ConversationService().finalize_message(
|
||||
mid,
|
||||
response_text,
|
||||
@@ -1162,7 +1162,7 @@ def s12_full_embedding_loop() -> None:
|
||||
is just a regular Python function; ``self`` is a MagicMock with the
|
||||
minimum attrs the worker reads."""
|
||||
|
||||
from application.core.settings import settings
|
||||
from docsgpt.core.settings import settings
|
||||
|
||||
user = f"{UNIQUE}-s12"
|
||||
with ENGINE.begin() as c:
|
||||
@@ -1227,7 +1227,7 @@ def s12_full_embedding_loop() -> None:
|
||||
settings.VECTOR_STORE = "faiss"
|
||||
|
||||
idempotency_key = f"{user}:{UNIQUE}-s12-key"
|
||||
from application.worker import _derive_source_id
|
||||
from docsgpt.worker import _derive_source_id
|
||||
|
||||
expected_source_id = str(_derive_source_id(idempotency_key))
|
||||
|
||||
@@ -1250,11 +1250,11 @@ def s12_full_embedding_loop() -> None:
|
||||
|
||||
try:
|
||||
with patch_db_session(
|
||||
"application.parser.embedding_pipeline",
|
||||
"application.worker",
|
||||
"application.api.answer.services.conversation_service",
|
||||
), patch("application.worker.upload_index", _fake_upload_index):
|
||||
from application.worker import ingest_worker
|
||||
"docsgpt.parser.embedding_pipeline",
|
||||
"docsgpt.worker",
|
||||
"docsgpt.api.answer.services.conversation_service",
|
||||
), patch("docsgpt.worker.upload_index", _fake_upload_index):
|
||||
from docsgpt.worker import ingest_worker
|
||||
|
||||
resp = ingest_worker(
|
||||
fake_self,
|
||||
@@ -1347,7 +1347,7 @@ class CeleryWorkerService:
|
||||
self._proc = subprocess.Popen( # noqa: S603
|
||||
[
|
||||
sys.executable, "-m", "celery",
|
||||
"-A", "application.app.celery", "worker",
|
||||
"-A", "docsgpt.app.celery", "worker",
|
||||
"-l", "INFO", "--pool=solo",
|
||||
"-Q", self._queue,
|
||||
"-n", f"qa-{UNIQUE}@%h",
|
||||
@@ -1508,7 +1508,7 @@ def s13_sigkill_redelivers_via_acks_late() -> None:
|
||||
|
||||
# Dispatch via celery's send_task using the same broker URL the worker
|
||||
# listens on. The DocsGPT celery instance has already loaded
|
||||
# ``application.celeryconfig`` (broker = production .env DB 0); since
|
||||
# ``docsgpt.celeryconfig`` (broker = production .env DB 0); since
|
||||
# Celery's conf re-reads ``CELERY_BROKER_URL`` from the env at publish
|
||||
# time, we override the env for the *whole* dispatch + wait block.
|
||||
from celery import Celery
|
||||
@@ -1536,7 +1536,7 @@ def s13_sigkill_redelivers_via_acks_late() -> None:
|
||||
task_id = str(uuid.uuid4())
|
||||
info(f"dispatching task_id={task_id} key={idempotency_key}")
|
||||
chaos_app.send_task(
|
||||
"application.api.user.tasks.process_agent_webhook",
|
||||
"docsgpt.api.user.tasks.process_agent_webhook",
|
||||
kwargs={
|
||||
"agent_id": agent_id,
|
||||
"payload": {"event": f"{UNIQUE}-s13"},
|
||||
@@ -1636,7 +1636,7 @@ def s10_celery_default_queue() -> None:
|
||||
"""Sanity: the broker queue is project-scoped so a sibling worker on
|
||||
the same Redis can't grab DocsGPT tasks."""
|
||||
|
||||
from application import celeryconfig
|
||||
from docsgpt import celeryconfig
|
||||
|
||||
assert celeryconfig.task_default_queue == "docsgpt", (
|
||||
f"expected default queue 'docsgpt'; got {celeryconfig.task_default_queue!r}"
|
||||
|
||||
Reference in new issue
Block a user