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:
Alex committed 2026-09-07 10:20:43 +01:00
1 parent 3e7f1f91b4
commit 574f96341e
984 files changed
+9847 -9682

No files matched your search

+2 -2
View File
@@ -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)
+7 -7
View File
@@ -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()
+2 -2
View File
@@ -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.
+2 -2
View File
@@ -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:
+2 -2
View File
@@ -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.
+2 -2
View File
@@ -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):
+1 -1
View File
@@ -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
View File
@@ -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"
+5 -5
View File
@@ -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" \
+4 -4
View File
@@ -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")
+2 -2
View File
@@ -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)
+50 -50
View File
@@ -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}"