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

@@ -1,5 +1,5 @@
"""Streaming-heartbeat liveness for reasoning models that "think" before
answering (``complete_stream`` in ``application/api/answer/routes/base.py``).
answering (``complete_stream`` in ``docsgpt/api/answer/routes/base.py``).
Background
----------
@@ -42,10 +42,10 @@ from typing import Any, Dict, List, Optional
import pytest
from sqlalchemy import text
from application.api.answer.routes.base import BaseAnswerResource
from application.api.answer.services.conversation_service import ConversationService
from application.storage.db.repositories.conversations import ConversationsRepository
from application.storage.db.repositories.reconciliation import (
from docsgpt.api.answer.routes.base import BaseAnswerResource
from docsgpt.api.answer.services.conversation_service import ConversationService
from docsgpt.storage.db.repositories.conversations import ConversationsRepository
from docsgpt.storage.db.repositories.reconciliation import (
ReconciliationRepository,
)
@@ -152,9 +152,9 @@ def _wire_db(engine, monkeypatch):
the journal writer for a no-op. Mirrors the helper in
``test_v1_tool_pause_finalization.py``.
"""
from application.api.answer.services import conversation_service as conv_mod
from application.api.answer.services import continuation_service as cont_mod
from application.api.answer.routes import base as base_mod
from docsgpt.api.answer.services import conversation_service as conv_mod
from docsgpt.api.answer.services import continuation_service as cont_mod
from docsgpt.api.answer.routes import base as base_mod
@contextmanager
def _session():
@@ -237,7 +237,7 @@ class TestHeartbeatPumpsDuringReasoning:
def test_thought_only_stream_heartbeats_while_pending(
self, pg_engine, monkeypatch
):
from application.api.answer.routes import base as base_mod
from docsgpt.api.answer.routes import base as base_mod
user_id = f"user-{uuid.uuid4().hex[:8]}"
with pg_engine.begin() as conn:
@@ -312,7 +312,7 @@ class TestHeartbeatPumpsDuringReasoning:
``last_heartbeat_at`` already stamped (seed-at-start), and a subsequent
``thought`` must bump it further — all before any ``answer``.
"""
from application.api.answer.routes import base as base_mod
from docsgpt.api.answer.routes import base as base_mod
user_id = f"user-{uuid.uuid4().hex[:8]}"
with pg_engine.begin() as conn:
@@ -540,7 +540,7 @@ class TestNormalAnswerTurnUnchanged:
def test_answer_turn_marks_streaming_and_finalizes_complete(
self, pg_engine, monkeypatch
):
from application.api.answer.routes import base as base_mod
from docsgpt.api.answer.routes import base as base_mod
user_id = f"user-{uuid.uuid4().hex[:8]}"
with pg_engine.begin() as conn:
+51 -51
View File
@@ -1,4 +1,4 @@
"""Extended unit tests for application/api/v1/routes.py.
"""Extended unit tests for docsgpt/api/v1/routes.py.
Covers:
- _extract_bearer_token helper
@@ -18,7 +18,7 @@ from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from application.api.v1.routes import (
from docsgpt.api.v1.routes import (
_extract_bearer_token,
_get_model_name,
v1_bp,
@@ -130,8 +130,8 @@ class TestChatCompletions:
def _patch_mongo(self, monkeypatch, mongo=None):
if mongo is None:
mongo = self._make_mongo()
monkeypatch.setattr("application.api.v1.routes.MongoDB.get_client", lambda: mongo)
monkeypatch.setattr("application.api.v1.routes.settings.MONGO_DB_NAME", "testdb")
monkeypatch.setattr("docsgpt.api.v1.routes.MongoDB.get_client", lambda: mongo)
monkeypatch.setattr("docsgpt.api.v1.routes.settings.MONGO_DB_NAME", "testdb")
def test_missing_auth_returns_401(self):
app = _build_app()
@@ -181,7 +181,7 @@ class TestListModelsExtra:
@contextmanager
def _patch_v1_db(conn):
from application.storage.db.repositories.agents import AgentsRepository
from docsgpt.storage.db.repositories.agents import AgentsRepository
if AgentsRepository(conn).find_by_key("x") is None:
AgentsRepository(conn).create("u-test", "Test Agent", "published", key="x")
@@ -190,7 +190,7 @@ def _patch_v1_db(conn):
def _yield():
yield conn
with patch("application.api.v1.routes.db_readonly", _yield):
with patch("docsgpt.api.v1.routes.db_readonly", _yield):
yield
@@ -198,7 +198,7 @@ def _patch_v1_db(conn):
def test_response_usage_reports_cumulative_turn_totals():
from types import SimpleNamespace
from application.api.v1.routes import _response_usage
from docsgpt.api.v1.routes import _response_usage
# Multi-round tool turns must report the accumulator's turn total,
# not the final round's provider snapshot.
@@ -222,8 +222,8 @@ def test_response_usage_reports_cumulative_turn_totals():
@pytest.mark.unit
class TestLookupAgentHappy:
def test_returns_agent_for_valid_key(self, pg_conn):
from application.api.v1.routes import _lookup_agent
from application.storage.db.repositories.agents import AgentsRepository
from docsgpt.api.v1.routes import _lookup_agent
from docsgpt.storage.db.repositories.agents import AgentsRepository
AgentsRepository(pg_conn).create("u1", "Test", "published", key="k-ok")
@@ -233,21 +233,21 @@ class TestLookupAgentHappy:
assert got["key"] == "k-ok"
def test_returns_none_when_not_found(self, pg_conn):
from application.api.v1.routes import _lookup_agent
from docsgpt.api.v1.routes import _lookup_agent
with _patch_v1_db(pg_conn):
got = _lookup_agent("nope")
assert got is None
def test_returns_none_on_exception(self):
from application.api.v1.routes import _lookup_agent
from docsgpt.api.v1.routes import _lookup_agent
@contextmanager
def _broken():
raise RuntimeError("db down")
yield
with patch("application.api.v1.routes.db_readonly", _broken):
with patch("docsgpt.api.v1.routes.db_readonly", _broken):
got = _lookup_agent("k")
assert got is None
@@ -264,7 +264,7 @@ class TestListModelsPgConn:
assert resp.status_code == 401
def test_returns_agent_for_valid_key(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
from docsgpt.storage.db.repositories.agents import AgentsRepository
app = _build_app()
repo = AgentsRepository(pg_conn)
@@ -291,7 +291,7 @@ class TestListModelsPgConn:
raise RuntimeError("boom")
yield
with patch("application.api.v1.routes.db_readonly", _broken):
with patch("docsgpt.api.v1.routes.db_readonly", _broken):
with app.test_client() as c:
resp = c.get(
"/v1/models",
@@ -348,10 +348,10 @@ class TestChatCompletionsHappyPath:
"extra": {},
}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
):
with app.test_client() as c:
@@ -368,7 +368,7 @@ class TestChatCompletionsHappyPath:
def test_null_n_is_treated_as_default(self, pg_conn):
app = _build_app()
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=ValueError("reached translator"),
):
with app.test_client() as c:
@@ -400,8 +400,8 @@ class TestChatCompletionsHappyPath:
assert resp.get_json()["error"]["type"] == "invalid_request_error"
def test_conversation_id_must_belong_to_authenticated_agent(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
from application.storage.db.repositories.conversations import (
from docsgpt.storage.db.repositories.agents import AgentsRepository
from docsgpt.storage.db.repositories.conversations import (
ConversationsRepository,
)
@@ -447,18 +447,18 @@ class TestChatCompletionsHappyPath:
"extra": {},
}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.load_conversation",
"docsgpt.api.v1.routes.load_conversation",
return_value="deleted-conversation",
), patch(
"application.api.v1.routes._conversation_belongs_to_agent",
"docsgpt.api.v1.routes._conversation_belongs_to_agent",
return_value=False,
), patch(
"application.api.v1.routes.delete_conversation",
"docsgpt.api.v1.routes.delete_conversation",
) as delete_mapping, patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
):
with app.test_client() as c:
@@ -474,7 +474,7 @@ class TestChatCompletionsHappyPath:
delete_mapping.assert_called_once()
def test_duplicate_resume_returns_conflict(self, pg_conn):
from application.api.answer.services.continuation_service import (
from docsgpt.api.answer.services.continuation_service import (
ResumeInProgressError,
)
@@ -482,20 +482,20 @@ class TestChatCompletionsHappyPath:
fake_processor = MagicMock()
fake_processor.decoded_token = {"sub": "u-test"}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
return_value={
"conversation_id": "conv-1",
"tool_actions": [{"call_id": "call-1", "result": "ok"}],
"messages": [],
},
), patch(
"application.api.v1.routes._conversation_belongs_to_agent",
"docsgpt.api.v1.routes._conversation_belongs_to_agent",
return_value=True,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes.ContinuationService.claim_state",
"docsgpt.api.v1.routes.ContinuationService.claim_state",
side_effect=ResumeInProgressError("Resume already in progress"),
):
with app.test_client() as c:
@@ -530,7 +530,7 @@ class TestChatCompletionsHappyPath:
def test_translate_error_returns_400(self, pg_conn):
app = _build_app()
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=ValueError("bad"),
):
with app.test_client() as c:
@@ -552,10 +552,10 @@ class TestChatCompletionsHappyPath:
}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=MagicMock(decoded_token={"sub": "u"}),
):
with app.test_client() as c:
@@ -576,10 +576,10 @@ class TestChatCompletionsHappyPath:
fake_processor.build_agent.side_effect = ValueError("boom")
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
):
with app.test_client() as c:
@@ -600,10 +600,10 @@ class TestChatCompletionsHappyPath:
fake_processor.build_agent.side_effect = RuntimeError("boom")
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
):
with app.test_client() as c:
@@ -645,16 +645,16 @@ class TestChatCompletionsHappyPath:
}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
), patch(
"application.api.v1.routes.translate_response",
"docsgpt.api.v1.routes.translate_response",
return_value={"id": "x", "choices": []},
):
with app.test_client() as c:
@@ -691,13 +691,13 @@ class TestChatCompletionsHappyPath:
}
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
):
with app.test_client() as c:
@@ -730,16 +730,16 @@ class TestChatCompletionsHappyPath:
fake_helper.complete_stream.side_effect = _fake_helper_complete_stream
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
), patch(
"application.api.v1.routes.translate_stream_event",
"docsgpt.api.v1.routes.translate_stream_event",
return_value=["data: chunk\n\n"],
):
with app.test_client() as c:
@@ -793,16 +793,16 @@ class TestChatCompletionsHappyPath:
fake_helper.complete_stream.side_effect = _fake_helper_complete_stream
with _patch_v1_db(pg_conn), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
), patch(
"application.api.v1.routes.translate_stream_event",
"docsgpt.api.v1.routes.translate_stream_event",
side_effect=_fake_translate_stream_event,
):
with app.test_client() as c:
+4 -4
View File
@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
import pytest
from application.api.v1.session_store import (
from docsgpt.api.v1.session_store import (
delete_conversation,
identify_session,
load_conversation,
@@ -52,10 +52,10 @@ def test_save_and_load_use_bounded_redis_ttl(monkeypatch):
redis = MagicMock()
redis.get.return_value = b"conv-1"
monkeypatch.setattr(
"application.api.v1.session_store.get_redis_instance", lambda: redis
"docsgpt.api.v1.session_store.get_redis_instance", lambda: redis
)
monkeypatch.setattr(
"application.api.v1.session_store.settings.V1_SESSION_TTL_SECONDS", 123
"docsgpt.api.v1.session_store.settings.V1_SESSION_TTL_SECONDS", 123
)
session = identify_session({"X-Session-ID": "s"}, {"messages": []}, "a")
save_conversation(session, "conv-1")
@@ -67,7 +67,7 @@ def test_save_and_load_use_bounded_redis_ttl(monkeypatch):
def test_delete_conversation_invalidates_stale_mapping(monkeypatch):
redis = MagicMock()
monkeypatch.setattr(
"application.api.v1.session_store.get_redis_instance", lambda: redis
"docsgpt.api.v1.session_store.get_redis_instance", lambda: redis
)
session = identify_session({"X-Session-ID": "s"}, {"messages": []}, "a")
delete_conversation(session)
@@ -16,10 +16,10 @@ import pytest
from flask import Flask
from sqlalchemy import text
from application.api.answer.services import stream_processor as sp_mod
from application.api.v1.routes import v1_bp
from application.storage.db.repositories.agents import AgentsRepository
from application.storage.db.repositories.conversations import ConversationsRepository
from docsgpt.api.answer.services import stream_processor as sp_mod
from docsgpt.api.v1.routes import v1_bp
from docsgpt.storage.db.repositories.agents import AgentsRepository
from docsgpt.storage.db.repositories.conversations import ConversationsRepository
# Reuse the route-level DB wiring + seed helpers from the tool-pause suite.
from tests.api.v1.test_v1_tool_pause_finalization import (
+8 -8
View File
@@ -8,7 +8,7 @@ honors a client-supplied ``Idempotency-Key`` header: a retry returns the
These tests pin both layers against an ephemeral Postgres (``pg_engine``):
- the ``application.api.v1.idempotency`` helper contract directly
- the ``docsgpt.api.v1.idempotency`` helper contract directly
(completed → cached, fresh-pending → 409, stale-pending → re-claim,
non-2xx → not cached); and
- the real ``/v1/chat/completions`` route end-to-end: the same key twice
@@ -28,8 +28,8 @@ import pytest
from flask import Flask
from sqlalchemy import text
from application.api.v1 import idempotency as v1_idem
from application.api.v1.idempotency import (
from docsgpt.api.v1 import idempotency as v1_idem
from docsgpt.api.v1.idempotency import (
STALE_PENDING_SECONDS,
TASK_NAME,
claim_or_replay,
@@ -37,7 +37,7 @@ from application.api.v1.idempotency import (
release,
scoped_key,
)
from application.api.v1.routes import v1_bp
from docsgpt.api.v1.routes import v1_bp
# Reuse the route-level DB wiring + fake answering agent from the tool-pause
# suite so a real two-POST round-trip runs against the ephemeral Postgres.
@@ -294,7 +294,7 @@ class TestV1IdempotencyRoute:
_CountingAnswerAgent.gen_calls = 0
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
self._fake_build_agent,
):
@@ -332,7 +332,7 @@ class TestV1IdempotencyRoute:
_CountingAnswerAgent.gen_calls = 0
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
self._fake_build_agent,
):
@@ -359,7 +359,7 @@ class TestV1IdempotencyRoute:
_CountingAnswerAgent.gen_calls = 0
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
self._fake_build_agent,
):
@@ -399,7 +399,7 @@ class TestV1IdempotencyRoute:
_CountingAnswerAgent.gen_calls = 0
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
_build,
):
+27 -27
View File
@@ -51,9 +51,9 @@ from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from application.api.answer.routes.base import BaseAnswerResource
from application.api.answer.services.conversation_service import ConversationService
from application.api.v1.routes import v1_bp
from docsgpt.api.answer.routes.base import BaseAnswerResource
from docsgpt.api.answer.services.conversation_service import ConversationService
from docsgpt.api.v1.routes import v1_bp
# ---------------------------------------------------------------------------
@@ -215,9 +215,9 @@ def _wire_db(engine, monkeypatch):
so we hand out fresh connections from the same ephemeral engine and
swap the journal writer for a no-op.
"""
from application.api.answer.services import conversation_service as conv_mod
from application.api.answer.services import continuation_service as cont_mod
from application.api.answer.routes import base as base_mod
from docsgpt.api.answer.services import conversation_service as conv_mod
from docsgpt.api.answer.services import continuation_service as cont_mod
from docsgpt.api.answer.routes import base as base_mod
@contextmanager
def _session():
@@ -658,28 +658,28 @@ class TestV1ContinuationRoutesStatelessly:
yield MagicMock()
with patch(
"application.api.v1.routes._lookup_agent",
"docsgpt.api.v1.routes._lookup_agent",
return_value={"id": "agent-1", "name": "Agent", "user_id": "owner"},
), patch(
"application.api.v1.routes.ContinuationService.claim_state",
"docsgpt.api.v1.routes.ContinuationService.claim_state",
return_value=None,
), patch(
"application.api.v1.routes._conversation_belongs_to_agent",
"docsgpt.api.v1.routes._conversation_belongs_to_agent",
return_value=True,
), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
), patch(
"application.api.v1.routes.db_readonly",
"docsgpt.api.v1.routes.db_readonly",
_yield_conn,
), patch(
"application.api.v1.routes.translate_response",
"docsgpt.api.v1.routes.translate_response",
return_value={"id": "x", "choices": []},
):
with app.test_client() as c:
@@ -767,22 +767,22 @@ class TestV1ContinuationRoutesStatelessly:
yield MagicMock()
with patch(
"application.api.v1.routes._lookup_agent",
"docsgpt.api.v1.routes._lookup_agent",
return_value={"id": "agent-1", "name": "Agent", "user_id": "owner"},
), patch(
"application.api.v1.routes.translate_request",
"docsgpt.api.v1.routes.translate_request",
side_effect=_fake_translate,
), patch(
"application.api.v1.routes.StreamProcessor",
"docsgpt.api.v1.routes.StreamProcessor",
return_value=fake_processor,
), patch(
"application.api.v1.routes._V1AnswerHelper",
"docsgpt.api.v1.routes._V1AnswerHelper",
return_value=fake_helper,
), patch(
"application.api.v1.routes.db_readonly",
"docsgpt.api.v1.routes.db_readonly",
_yield_conn,
), patch(
"application.api.v1.routes.translate_response",
"docsgpt.api.v1.routes.translate_response",
return_value={"id": "x", "choices": []},
):
with app.test_client() as c:
@@ -888,7 +888,7 @@ class _PauseThenAnswerAgent:
def _seed_agent(conn, user_id: str, key: str) -> None:
from application.storage.db.repositories.agents import AgentsRepository
from docsgpt.storage.db.repositories.agents import AgentsRepository
AgentsRepository(conn).create(user_id, "Weather Agent", "published", key=key)
@@ -902,8 +902,8 @@ def _wire_v1_route_db(engine, monkeypatch):
title-gen ``LLMCreator`` on the base module, so a real two-POST round-trip
runs entirely against the ephemeral Postgres with no live LLM/provider.
"""
from application.api.v1 import routes as v1_routes_mod
from application.api.answer.routes import base as base_mod
from docsgpt.api.v1 import routes as v1_routes_mod
from docsgpt.api.answer.routes import base as base_mod
@contextmanager
def _readonly():
@@ -1007,11 +1007,11 @@ class TestV1ToolRoundTripEndToEnd:
# ---- POST #1: user question -> agent pauses for the client tool ----
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
_fake_build_agent,
), patch(
"application.api.v1.routes._conversation_belongs_to_agent",
"docsgpt.api.v1.routes._conversation_belongs_to_agent",
return_value=True,
):
with app.test_client() as c:
@@ -1049,11 +1049,11 @@ class TestV1ToolRoundTripEndToEnd:
# ---- POST #2: tool result + conversation_id -> agent answers ----
with _wire_v1_route_db(pg_engine, monkeypatch), patch(
"application.api.answer.services.stream_processor.StreamProcessor"
"docsgpt.api.answer.services.stream_processor.StreamProcessor"
".build_agent",
_fake_build_agent,
), patch(
"application.api.v1.routes._conversation_belongs_to_agent",
"docsgpt.api.v1.routes._conversation_belongs_to_agent",
return_value=True,
):
with app.test_client() as c: