mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-15 00:16:46 +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
@@ -1,4 +1,4 @@
|
||||
"""Tests for application/api/user/agents/folders.py.
|
||||
"""Tests for docsgpt/api/user/agents/folders.py.
|
||||
|
||||
Uses the ephemeral ``pg_conn`` fixture to exercise real PG repository code.
|
||||
"""
|
||||
@@ -22,22 +22,22 @@ def _patch_folders_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.folders.db_session", _yield
|
||||
"docsgpt.api.user.agents.folders.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.folders.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.folders.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def _seed_folder(pg_conn, user, name="F", parent_id=None):
|
||||
from application.storage.db.repositories.agent_folders import (
|
||||
from docsgpt.storage.db.repositories.agent_folders import (
|
||||
AgentFoldersRepository,
|
||||
)
|
||||
return AgentFoldersRepository(pg_conn).create(user, name, parent_id=parent_id)
|
||||
|
||||
|
||||
def _seed_agent(pg_conn, user, folder_id=None):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
repo = AgentsRepository(pg_conn)
|
||||
agent = repo.create(user, "test-agent", "published", description="x")
|
||||
if folder_id:
|
||||
@@ -47,7 +47,7 @@ def _seed_agent(pg_conn, user, folder_id=None):
|
||||
|
||||
class TestAgentFoldersGet:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
with app.test_request_context("/api/agents/folders/"):
|
||||
from flask import request
|
||||
@@ -56,7 +56,7 @@ class TestAgentFoldersGet:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_folders_list(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
user = "u-folders-list"
|
||||
_seed_folder(pg_conn, user, name="A")
|
||||
@@ -75,7 +75,7 @@ class TestAgentFoldersGet:
|
||||
|
||||
class TestAgentFoldersPost:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/", method="POST", json={"name": "F"}
|
||||
@@ -86,7 +86,7 @@ class TestAgentFoldersPost:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_name(self, app):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/", method="POST", json={}
|
||||
@@ -97,7 +97,7 @@ class TestAgentFoldersPost:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_creates_folder_at_root(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/", method="POST",
|
||||
@@ -111,7 +111,7 @@ class TestAgentFoldersPost:
|
||||
assert response.json["parent_id"] is None
|
||||
|
||||
def test_creates_nested_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
user = "u-nested"
|
||||
parent = _seed_folder(pg_conn, user, name="parent")
|
||||
@@ -127,7 +127,7 @@ class TestAgentFoldersPost:
|
||||
assert response.json["parent_id"] == str(parent["id"])
|
||||
|
||||
def test_returns_404_for_missing_parent(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolders
|
||||
from docsgpt.api.user.agents.folders import AgentFolders
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/", method="POST",
|
||||
@@ -144,7 +144,7 @@ class TestAgentFoldersPost:
|
||||
|
||||
class TestAgentFolderGet:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with app.test_request_context("/api/agents/folders/abc"):
|
||||
from flask import request
|
||||
@@ -153,7 +153,7 @@ class TestAgentFolderGet:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_404_missing_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/00000000-0000-0000-0000-000000000000"
|
||||
@@ -166,7 +166,7 @@ class TestAgentFolderGet:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_returns_folder_with_agents_and_subfolders(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-folder-detail"
|
||||
parent = _seed_folder(pg_conn, user, name="parent")
|
||||
@@ -188,7 +188,7 @@ class TestAgentFolderGet:
|
||||
|
||||
class TestAgentFolderPut:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/abc", method="PUT", json={"name": "new"}
|
||||
@@ -199,7 +199,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_404_missing_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/00000000-0000-0000-0000-000000000000",
|
||||
@@ -214,7 +214,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_renames_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-rename"
|
||||
folder = _seed_folder(pg_conn, user, name="old")
|
||||
@@ -230,7 +230,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_prevents_setting_self_as_parent(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-self-parent"
|
||||
folder = _seed_folder(pg_conn, user, name="f1")
|
||||
@@ -246,7 +246,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_sets_parent_to_other_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-moveparent"
|
||||
f1 = _seed_folder(pg_conn, user, name="f1")
|
||||
@@ -263,7 +263,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_returns_404_for_missing_parent(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-missingparent"
|
||||
folder = _seed_folder(pg_conn, user, name="f")
|
||||
@@ -279,7 +279,7 @@ class TestAgentFolderPut:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_clears_parent_id_when_null(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-clear"
|
||||
parent = _seed_folder(pg_conn, user, name="p")
|
||||
@@ -300,7 +300,7 @@ class TestAgentFolderPut:
|
||||
|
||||
class TestAgentFolderDelete:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/abc", method="DELETE"
|
||||
@@ -311,7 +311,7 @@ class TestAgentFolderDelete:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_404_missing_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/00000000-0000-0000-0000-000000000000",
|
||||
@@ -325,7 +325,7 @@ class TestAgentFolderDelete:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_deletes_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import AgentFolder
|
||||
from docsgpt.api.user.agents.folders import AgentFolder
|
||||
|
||||
user = "u-del"
|
||||
folder = _seed_folder(pg_conn, user, name="tbd")
|
||||
@@ -341,7 +341,7 @@ class TestAgentFolderDelete:
|
||||
|
||||
class TestMoveAgentToFolder:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/move_agent",
|
||||
@@ -354,7 +354,7 @@ class TestMoveAgentToFolder:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_agent_id(self, app):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/move_agent",
|
||||
@@ -367,7 +367,7 @@ class TestMoveAgentToFolder:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_404_agent_not_found(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/move_agent",
|
||||
@@ -380,7 +380,7 @@ class TestMoveAgentToFolder:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_moves_agent_into_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
user = "u-move"
|
||||
folder = _seed_folder(pg_conn, user, name="target")
|
||||
@@ -400,7 +400,7 @@ class TestMoveAgentToFolder:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_returns_404_folder_not_found(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
user = "u-move-nofolder"
|
||||
agent = _seed_agent(pg_conn, user)
|
||||
@@ -419,7 +419,7 @@ class TestMoveAgentToFolder:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_removes_agent_from_folder(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import MoveAgentToFolder
|
||||
from docsgpt.api.user.agents.folders import MoveAgentToFolder
|
||||
|
||||
user = "u-remove"
|
||||
folder = _seed_folder(pg_conn, user, name="target")
|
||||
@@ -438,7 +438,7 @@ class TestMoveAgentToFolder:
|
||||
|
||||
class TestBulkMoveAgents:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.folders import BulkMoveAgents
|
||||
from docsgpt.api.user.agents.folders import BulkMoveAgents
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/bulk_move",
|
||||
@@ -451,7 +451,7 @@ class TestBulkMoveAgents:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_agent_ids(self, app):
|
||||
from application.api.user.agents.folders import BulkMoveAgents
|
||||
from docsgpt.api.user.agents.folders import BulkMoveAgents
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/agents/folders/bulk_move",
|
||||
@@ -464,7 +464,7 @@ class TestBulkMoveAgents:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_bulk_moves_agents(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import BulkMoveAgents
|
||||
from docsgpt.api.user.agents.folders import BulkMoveAgents
|
||||
|
||||
user = "u-bulk"
|
||||
folder = _seed_folder(pg_conn, user, name="dest")
|
||||
@@ -485,7 +485,7 @@ class TestBulkMoveAgents:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_returns_404_when_folder_not_found(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import BulkMoveAgents
|
||||
from docsgpt.api.user.agents.folders import BulkMoveAgents
|
||||
|
||||
with _patch_folders_db(pg_conn), app.test_request_context(
|
||||
"/api/agents/folders/bulk_move",
|
||||
@@ -501,7 +501,7 @@ class TestBulkMoveAgents:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_bulk_move_tolerates_missing_agents(self, app, pg_conn):
|
||||
from application.api.user.agents.folders import BulkMoveAgents
|
||||
from docsgpt.api.user.agents.folders import BulkMoveAgents
|
||||
|
||||
user = "u-bulk-partial"
|
||||
folder = _seed_folder(pg_conn, user, name="f")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for application/api/user/agents/guardrails.py and config validation.
|
||||
"""Tests for docsgpt/api/user/agents/guardrails.py and config validation.
|
||||
|
||||
Uses the ephemeral ``pg_conn`` fixture so the repository code is real.
|
||||
"""
|
||||
@@ -22,13 +22,13 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.guardrails.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.guardrails.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def _seed_agent(pg_conn, user="u-gr"):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
return AgentsRepository(pg_conn).create(user, "guarded", "published")
|
||||
|
||||
@@ -41,7 +41,7 @@ def _seed_agent(pg_conn, user="u-gr"):
|
||||
@pytest.mark.unit
|
||||
class TestNormalizeAgentConfig:
|
||||
def _norm(self, raw):
|
||||
from application.api.user.agents.routes import normalize_agent_config
|
||||
from docsgpt.api.user.agents.routes import normalize_agent_config
|
||||
|
||||
return normalize_agent_config(raw)
|
||||
|
||||
@@ -140,7 +140,7 @@ class TestNormalizeAgentConfig:
|
||||
@pytest.mark.unit
|
||||
class TestCatalogRoute:
|
||||
def _get(self, app, decoded_token={"sub": "u-gr"}):
|
||||
from application.api.user.agents.guardrails import GuardrailCatalog
|
||||
from docsgpt.api.user.agents.guardrails import GuardrailCatalog
|
||||
|
||||
with app.test_request_context("/api/guardrails/catalog"):
|
||||
from flask import request
|
||||
@@ -183,7 +183,7 @@ class TestCatalogRoute:
|
||||
def test_reports_the_instance_floor(self, app, monkeypatch):
|
||||
import json
|
||||
|
||||
from application.core.settings import settings
|
||||
from docsgpt.core.settings import settings
|
||||
|
||||
monkeypatch.setattr(
|
||||
settings,
|
||||
@@ -199,7 +199,7 @@ class TestCatalogRoute:
|
||||
def test_floor_is_null_when_unset(self, app, monkeypatch):
|
||||
import json
|
||||
|
||||
from application.core.settings import settings
|
||||
from docsgpt.core.settings import settings
|
||||
|
||||
monkeypatch.setattr(settings, "GUARDRAILS_FLOOR", {})
|
||||
payload = json.loads(self._get(app).get_data(as_text=True))
|
||||
@@ -214,7 +214,7 @@ class TestCatalogRoute:
|
||||
@pytest.mark.unit
|
||||
class TestEventsRoute:
|
||||
def _get(self, app, pg_conn, args="", decoded_token={"sub": "u-gr"}):
|
||||
from application.api.user.agents.guardrails import GuardrailEvents
|
||||
from docsgpt.api.user.agents.guardrails import GuardrailEvents
|
||||
|
||||
with app.test_request_context(f"/api/guardrails/events{args}"):
|
||||
from flask import request
|
||||
@@ -248,7 +248,7 @@ class TestEventsRoute:
|
||||
def test_returns_recorded_events(self, app, pg_conn):
|
||||
import json
|
||||
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -277,7 +277,7 @@ class TestEventsRoute:
|
||||
@pytest.mark.unit
|
||||
class TestSummaryRoute:
|
||||
def _get(self, app, pg_conn, args="", decoded_token={"sub": "u-gr"}):
|
||||
from application.api.user.agents.guardrails import GuardrailSummary
|
||||
from docsgpt.api.user.agents.guardrails import GuardrailSummary
|
||||
|
||||
with app.test_request_context(f"/api/guardrails/summary{args}"):
|
||||
from flask import request
|
||||
@@ -293,7 +293,7 @@ class TestSummaryRoute:
|
||||
def test_splits_blocked_from_flagged_from_unevaluated(self, app, pg_conn):
|
||||
import json
|
||||
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -331,7 +331,7 @@ class TestSummaryAgentScoping:
|
||||
"""The agent-logs panel needs per-agent aggregates, not per-user ones."""
|
||||
|
||||
def _get(self, app, pg_conn, args="", decoded_token={"sub": "u-gr"}):
|
||||
from application.api.user.agents.guardrails import GuardrailSummary
|
||||
from docsgpt.api.user.agents.guardrails import GuardrailSummary
|
||||
|
||||
with app.test_request_context(f"/api/guardrails/summary{args}"):
|
||||
from flask import request
|
||||
@@ -341,8 +341,8 @@ class TestSummaryAgentScoping:
|
||||
return GuardrailSummary().get()
|
||||
|
||||
def _seed(self, pg_conn):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -400,7 +400,7 @@ class TestConfigRejectionDoesNotLeakInternals:
|
||||
"""
|
||||
|
||||
def test_the_static_message_is_not_derived_from_the_exception(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
INVALID_CONFIG_MESSAGE,
|
||||
normalize_agent_config,
|
||||
)
|
||||
@@ -415,7 +415,7 @@ class TestConfigRejectionDoesNotLeakInternals:
|
||||
assert INVALID_CONFIG_MESSAGE not in detail
|
||||
|
||||
def test_internal_validator_text_still_names_the_field(self):
|
||||
from application.api.user.agents.routes import normalize_agent_config
|
||||
from docsgpt.api.user.agents.routes import normalize_agent_config
|
||||
|
||||
with pytest.raises(ValueError, match="timeout_ms"):
|
||||
normalize_agent_config({"guardrails": {"timeout_ms": 5}})
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Gap-coverage tests for application.api.user.agents.routes.
|
||||
"""Gap-coverage tests for docsgpt.api.user.agents.routes.
|
||||
|
||||
No bson/ObjectId imports. The routes internally use ObjectId (patched where
|
||||
needed) and Mongo collections (mocked). Repository assertions use
|
||||
@@ -37,35 +37,35 @@ class TestNormalizeWorkflowReferenceGaps:
|
||||
pass
|
||||
|
||||
def test_handles_integer_zero(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
assert normalize_workflow_reference(0) == "0"
|
||||
|
||||
def test_handles_list_converts_to_str(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
result = normalize_workflow_reference([1, 2])
|
||||
assert isinstance(result, str)
|
||||
|
||||
def test_json_string_with_underscore_id(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
result = normalize_workflow_reference('{"_id": "abc"}')
|
||||
assert result == "abc"
|
||||
|
||||
def test_json_string_with_workflow_id_key(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
result = normalize_workflow_reference('{"workflow_id": "wf99"}')
|
||||
assert result == "wf99"
|
||||
|
||||
def test_whitespace_only_string_returns_empty(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
assert normalize_workflow_reference(" \t ") == ""
|
||||
|
||||
def test_dict_missing_all_id_keys_returns_none(self):
|
||||
from application.api.user.agents.routes import normalize_workflow_reference
|
||||
from docsgpt.api.user.agents.routes import normalize_workflow_reference
|
||||
|
||||
result = normalize_workflow_reference({"other_key": "value"})
|
||||
assert result is None
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Happy-path tests for application/api/user/agents/routes.py.
|
||||
"""Happy-path tests for docsgpt/api/user/agents/routes.py.
|
||||
|
||||
Exercises each endpoint with the ephemeral ``pg_conn`` fixture and real
|
||||
repository classes so the route bodies run end-to-end.
|
||||
@@ -23,9 +23,9 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _yield
|
||||
"docsgpt.api.user.agents.routes.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.routes.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.routes.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
@@ -34,12 +34,12 @@ def _seed_agent(
|
||||
pg_conn, user="u", *, name="A", status="published", with_source=True,
|
||||
retriever="classic", **extra,
|
||||
):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
repo = AgentsRepository(pg_conn)
|
||||
kwargs = {"description": "d", "retriever": retriever, **extra}
|
||||
if with_source:
|
||||
# Sources have a UUID FK; seed one
|
||||
from application.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
src = SourcesRepository(pg_conn).create("src", user_id=user)
|
||||
kwargs["source_id"] = str(src["id"])
|
||||
return repo.create(user, name, status, **kwargs)
|
||||
@@ -47,7 +47,7 @@ def _seed_agent(
|
||||
|
||||
class TestGetAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import GetAgent
|
||||
from docsgpt.api.user.agents.routes import GetAgent
|
||||
|
||||
with app.test_request_context("/api/get_agent?id=x"):
|
||||
from flask import request
|
||||
@@ -59,7 +59,7 @@ class TestGetAgent:
|
||||
assert status == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.routes import GetAgent
|
||||
from docsgpt.api.user.agents.routes import GetAgent
|
||||
|
||||
with app.test_request_context("/api/get_agent"):
|
||||
from flask import request
|
||||
@@ -71,7 +71,7 @@ class TestGetAgent:
|
||||
assert status == 400
|
||||
|
||||
def test_returns_404_when_missing(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import GetAgent
|
||||
from docsgpt.api.user.agents.routes import GetAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/get_agent?id=00000000-0000-0000-0000-000000000000"
|
||||
@@ -85,7 +85,7 @@ class TestGetAgent:
|
||||
assert status == 404
|
||||
|
||||
def test_returns_agent_by_id(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import GetAgent
|
||||
from docsgpt.api.user.agents.routes import GetAgent
|
||||
|
||||
user = "u-getA"
|
||||
agent = _seed_agent(pg_conn, user=user, name="Al")
|
||||
@@ -102,7 +102,7 @@ class TestGetAgent:
|
||||
|
||||
class TestGetAgents:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import GetAgents
|
||||
from docsgpt.api.user.agents.routes import GetAgents
|
||||
|
||||
with app.test_request_context("/api/get_agents"):
|
||||
from flask import request
|
||||
@@ -114,7 +114,7 @@ class TestGetAgents:
|
||||
assert status == 401
|
||||
|
||||
def test_returns_list_for_user(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import GetAgents
|
||||
from docsgpt.api.user.agents.routes import GetAgents
|
||||
|
||||
user = "u-list-agents"
|
||||
_seed_agent(pg_conn, user=user, name="B1")
|
||||
@@ -129,7 +129,7 @@ class TestGetAgents:
|
||||
assert "B1" in names and "B2" in names
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.routes import GetAgents
|
||||
from docsgpt.api.user.agents.routes import GetAgents
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -137,7 +137,7 @@ class TestGetAgents:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context("/api/get_agents"):
|
||||
from flask import request
|
||||
request.decoded_token = {"sub": "u"}
|
||||
@@ -147,7 +147,7 @@ class TestGetAgents:
|
||||
|
||||
class TestDeleteAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/delete_agent?id=x", method="DELETE"
|
||||
@@ -158,7 +158,7 @@ class TestDeleteAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/delete_agent", method="DELETE"
|
||||
@@ -169,7 +169,7 @@ class TestDeleteAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_404_missing_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/delete_agent?id=00000000-0000-0000-0000-000000000000",
|
||||
@@ -181,8 +181,8 @@ class TestDeleteAgent:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_deletes_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-delagent"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -199,7 +199,7 @@ class TestDeleteAgent:
|
||||
|
||||
class TestPinnedAgents:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import PinnedAgents
|
||||
from docsgpt.api.user.agents.routes import PinnedAgents
|
||||
|
||||
with app.test_request_context("/api/pinned_agents"):
|
||||
from flask import request
|
||||
@@ -208,7 +208,7 @@ class TestPinnedAgents:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_empty_list_for_new_user(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import PinnedAgents
|
||||
from docsgpt.api.user.agents.routes import PinnedAgents
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context("/api/pinned_agents"):
|
||||
from flask import request
|
||||
@@ -220,7 +220,7 @@ class TestPinnedAgents:
|
||||
|
||||
class TestPinAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import PinAgent
|
||||
from docsgpt.api.user.agents.routes import PinAgent
|
||||
|
||||
with app.test_request_context("/api/pin_agent?id=x", method="POST"):
|
||||
from flask import request
|
||||
@@ -229,7 +229,7 @@ class TestPinAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.routes import PinAgent
|
||||
from docsgpt.api.user.agents.routes import PinAgent
|
||||
|
||||
with app.test_request_context("/api/pin_agent", method="POST"):
|
||||
from flask import request
|
||||
@@ -238,7 +238,7 @@ class TestPinAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_pins_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import PinAgent
|
||||
from docsgpt.api.user.agents.routes import PinAgent
|
||||
|
||||
user = "u-pin"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -254,7 +254,7 @@ class TestPinAgent:
|
||||
|
||||
class TestGetTemplateAgents:
|
||||
def test_returns_empty_without_templates(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import GetTemplateAgents
|
||||
from docsgpt.api.user.agents.routes import GetTemplateAgents
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/template_agents"
|
||||
@@ -266,8 +266,8 @@ class TestGetTemplateAgents:
|
||||
assert response.json == []
|
||||
|
||||
def test_returns_templates(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import GetTemplateAgents
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import GetTemplateAgents
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
AgentsRepository(pg_conn).create(
|
||||
"__system__", "Template One", "template",
|
||||
@@ -286,7 +286,7 @@ class TestGetTemplateAgents:
|
||||
|
||||
class TestAdoptAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/adopt_agent?id=x", method="POST"
|
||||
@@ -297,7 +297,7 @@ class TestAdoptAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/adopt_agent", method="POST"
|
||||
@@ -310,7 +310,7 @@ class TestAdoptAgent:
|
||||
|
||||
class TestRemoveSharedAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import RemoveSharedAgent
|
||||
from docsgpt.api.user.agents.routes import RemoveSharedAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/remove_shared_agent?id=x", method="POST"
|
||||
@@ -321,7 +321,7 @@ class TestRemoveSharedAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.routes import RemoveSharedAgent
|
||||
from docsgpt.api.user.agents.routes import RemoveSharedAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/remove_shared_agent", method="POST"
|
||||
@@ -332,9 +332,9 @@ class TestRemoveSharedAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_removes_shared_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import RemoveSharedAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.users import UsersRepository
|
||||
from docsgpt.api.user.agents.routes import RemoveSharedAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository
|
||||
|
||||
owner = "owner-user"
|
||||
viewer = "u-rm-shared"
|
||||
@@ -357,7 +357,7 @@ class TestRemoveSharedAgent:
|
||||
|
||||
class TestCreateAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/create_agent",
|
||||
@@ -373,7 +373,7 @@ class TestCreateAgent:
|
||||
assert status == 401
|
||||
|
||||
def test_returns_400_missing_required_draft(self, app):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/create_agent",
|
||||
@@ -386,8 +386,8 @@ class TestCreateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_creates_draft_classic_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-create-A"
|
||||
|
||||
@@ -417,7 +417,7 @@ class TestCreateAgent:
|
||||
|
||||
class TestUpdateAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/update_agent/abc", method="PUT",
|
||||
@@ -429,7 +429,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_404_agent_not_found(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/update_agent/00000000-0000-0000-0000-000000000000",
|
||||
@@ -444,8 +444,8 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_updates_simple_fields(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-upd-simple"
|
||||
agent = _seed_agent(pg_conn, user=user, name="orig")
|
||||
@@ -466,8 +466,8 @@ class TestUpdateAgent:
|
||||
assert got["name"] == "new name"
|
||||
|
||||
def test_ignores_client_supplied_image_path(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-upd-image-path"
|
||||
agent = _seed_agent(
|
||||
@@ -488,7 +488,7 @@ class TestUpdateAgent:
|
||||
assert got["image"] is None
|
||||
|
||||
def test_invalid_status_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-upd-status"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -503,7 +503,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_invalid_source_uuid_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-upd-src"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -521,7 +521,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_source_default_clears(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-src-default"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -539,7 +539,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_invalid_sources_item_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-sources"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -583,7 +583,7 @@ class TestUpdateAgent:
|
||||
"""
|
||||
import logging
|
||||
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = f"u-log-{field}"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -607,7 +607,7 @@ class TestUpdateAgent:
|
||||
), f"no WARN naming field={field!r} and user={user!r}; got {warnings!r}"
|
||||
|
||||
def test_invalid_chunks_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-upd-chunks"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -625,7 +625,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_negative_chunks_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-neg-chunks"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -643,7 +643,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_tools_must_be_list(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-tools"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -661,7 +661,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_limited_token_mode_requires_limit(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-limit"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -679,7 +679,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_limited_request_mode_requires_limit(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-req-limit"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -697,7 +697,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_token_limit_without_mode_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-token-mode"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -715,7 +715,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_invalid_prompt_id_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-upd-prompt"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -733,7 +733,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_prompt_id_default_clears(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-pid-default"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -751,7 +751,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_empty_name_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-empty-name"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -766,7 +766,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_publish_classic_missing_fields_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-publish-missing"
|
||||
agent = _seed_agent(pg_conn, user=user, with_source=False)
|
||||
@@ -789,9 +789,9 @@ class TestUpdateAgent:
|
||||
``Missing or invalid required fields: Source``. The retriever
|
||||
carries the runtime identity, so the gate now accepts it.
|
||||
"""
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.prompts import PromptsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.prompts import PromptsRepository
|
||||
|
||||
user = "u-publish-default"
|
||||
# Draft agent with retriever='classic', no source_id, prompt + chunks set.
|
||||
@@ -832,9 +832,9 @@ class TestUpdateAgent:
|
||||
):
|
||||
"""If neither a source nor a retriever is configured, the gate
|
||||
still trips — the agent has no way to retrieve anything."""
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.prompts import PromptsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.prompts import PromptsRepository
|
||||
|
||||
user = "u-publish-no-retriever"
|
||||
agent = _seed_agent(
|
||||
@@ -868,15 +868,15 @@ class TestUpdateAgent:
|
||||
assert "Source or retriever" in response.json.get("message", "")
|
||||
|
||||
def test_publishing_generates_api_key(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-publish-key"
|
||||
agent = _seed_agent(
|
||||
pg_conn, user=user, status="draft", retriever="classic",
|
||||
)
|
||||
# Seed a prompt so published path validates
|
||||
from application.storage.db.repositories.prompts import PromptsRepository
|
||||
from docsgpt.storage.db.repositories.prompts import PromptsRepository
|
||||
prompt = PromptsRepository(pg_conn).create(user, "p", "c")
|
||||
AgentsRepository(pg_conn).update(
|
||||
str(agent["id"]), user,
|
||||
@@ -901,7 +901,7 @@ class TestUpdateAgent:
|
||||
assert "key" in response.json
|
||||
|
||||
def test_invalid_json_in_form_field_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-bad-json"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -922,7 +922,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_empty_update_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-empty-upd"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -937,7 +937,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_db_error_returns_500(self, app):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -945,7 +945,7 @@ class TestUpdateAgent:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/update_agent/abc", method="PUT",
|
||||
json={"name": "n", "description": "d", "status": "draft"},
|
||||
@@ -956,7 +956,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 500
|
||||
|
||||
def test_allow_system_prompt_override(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-override"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -974,7 +974,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_folder_id_null_clears(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-folder-null"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -992,7 +992,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_publish_workflow_without_workflow_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-wf-publish"
|
||||
agent = _seed_agent(pg_conn, user=user, with_source=False)
|
||||
@@ -1012,7 +1012,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_invalid_json_schema_returns_400(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-bad-schema"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -1033,7 +1033,7 @@ class TestUpdateAgent:
|
||||
assert response.status_code in (200, 400)
|
||||
|
||||
def test_json_schema_empty_becomes_none(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
|
||||
user = "u-schema-empty"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -1061,7 +1061,7 @@ class TestUpdateAgent:
|
||||
|
||||
class TestCreateAgentMore:
|
||||
def test_invalid_status_returns_400(self, app):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/create_agent", method="POST",
|
||||
@@ -1076,7 +1076,7 @@ class TestCreateAgentMore:
|
||||
assert status == 400
|
||||
|
||||
def test_publish_classic_without_source_returns_400(self, app):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/create_agent", method="POST",
|
||||
@@ -1096,7 +1096,7 @@ class TestCreateAgentMore:
|
||||
assert status == 400
|
||||
|
||||
def test_unknown_agent_type_falls_back_classic(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
user = "u-unknown-type"
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
@@ -1117,7 +1117,7 @@ class TestCreateAgentMore:
|
||||
assert status == 201
|
||||
|
||||
def test_create_form_invalid_json_fields(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
# Invalid JSON strings in form fields are coerced to []/None (no 400)
|
||||
user = "u-form-json"
|
||||
@@ -1145,7 +1145,7 @@ class TestCreateAgentMore:
|
||||
def test_create_published_workflow_without_workflow_returns_400(
|
||||
self, app, pg_conn,
|
||||
):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
user = "u-wf-no-wf"
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
@@ -1166,8 +1166,8 @@ class TestCreateAgentMore:
|
||||
assert status == 400
|
||||
|
||||
def test_create_with_sources_list(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from application.storage.db.repositories.sources import (
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.storage.db.repositories.sources import (
|
||||
SourcesRepository,
|
||||
)
|
||||
|
||||
@@ -1194,7 +1194,7 @@ class TestCreateAgentMore:
|
||||
assert status == 201
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -1202,7 +1202,7 @@ class TestCreateAgentMore:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/create_agent", method="POST",
|
||||
json={
|
||||
@@ -1226,8 +1226,8 @@ class TestCreateAgentMore:
|
||||
|
||||
class TestAdoptAgentMore:
|
||||
def test_adopts_template_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
repo = AgentsRepository(pg_conn)
|
||||
template = repo.create("__system__", "Template X", "template")
|
||||
@@ -1247,10 +1247,10 @@ class TestAdoptAgentMore:
|
||||
import io
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.core.settings import settings
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.utils import (
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.core.settings import settings
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.utils import (
|
||||
is_safe_agent_image_path,
|
||||
safe_user_storage_component,
|
||||
)
|
||||
@@ -1268,7 +1268,7 @@ class TestAdoptAgentMore:
|
||||
storage.save_file.side_effect = lambda data, path, **kw: {"path": path}
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.routes.storage", storage
|
||||
"docsgpt.api.user.agents.routes.storage", storage
|
||||
), app.test_request_context(
|
||||
f"/api/adopt_agent?id={template['id']}", method="POST"
|
||||
):
|
||||
@@ -1292,8 +1292,8 @@ class TestAdoptAgentMore:
|
||||
def test_adopt_drops_image_when_copy_fails(self, app, pg_conn):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
repo = AgentsRepository(pg_conn)
|
||||
template = repo.create(
|
||||
@@ -1307,7 +1307,7 @@ class TestAdoptAgentMore:
|
||||
storage.get_file.side_effect = FileNotFoundError("missing")
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.routes.storage", storage
|
||||
"docsgpt.api.user.agents.routes.storage", storage
|
||||
), app.test_request_context(
|
||||
f"/api/adopt_agent?id={template['id']}", method="POST"
|
||||
):
|
||||
@@ -1326,8 +1326,8 @@ class TestAdoptAgentMore:
|
||||
def test_adopt_keeps_external_image_url(self, app, pg_conn):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
repo = AgentsRepository(pg_conn)
|
||||
template = repo.create(
|
||||
@@ -1340,7 +1340,7 @@ class TestAdoptAgentMore:
|
||||
storage = MagicMock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.routes.storage", storage
|
||||
"docsgpt.api.user.agents.routes.storage", storage
|
||||
), app.test_request_context(
|
||||
f"/api/adopt_agent?id={template['id']}", method="POST"
|
||||
):
|
||||
@@ -1358,7 +1358,7 @@ class TestAdoptAgentMore:
|
||||
storage.get_file.assert_not_called()
|
||||
|
||||
def test_adopt_template_missing_returns_404(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/adopt_agent?id=00000000-0000-0000-0000-000000000000",
|
||||
@@ -1370,7 +1370,7 @@ class TestAdoptAgentMore:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -1378,7 +1378,7 @@ class TestAdoptAgentMore:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/adopt_agent?id=abc", method="POST"
|
||||
):
|
||||
@@ -1391,8 +1391,8 @@ class TestAdoptAgentMore:
|
||||
class TestPinAgentMore:
|
||||
def test_toggle_pin(self, app, pg_conn):
|
||||
"""PinAgent is a toggle — second call unpins."""
|
||||
from application.api.user.agents.routes import PinAgent
|
||||
from application.storage.db.repositories.users import UsersRepository
|
||||
from docsgpt.api.user.agents.routes import PinAgent
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository
|
||||
|
||||
user = "u-pin-toggle"
|
||||
agent = _seed_agent(pg_conn, user=user)
|
||||
@@ -1420,7 +1420,7 @@ class TestPinAgentMore:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_pin_db_error_returns_500(self, app):
|
||||
from application.api.user.agents.routes import PinAgent
|
||||
from docsgpt.api.user.agents.routes import PinAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -1428,7 +1428,7 @@ class TestPinAgentMore:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/pin_agent?id=abc", method="POST"
|
||||
):
|
||||
@@ -1440,14 +1440,14 @@ class TestPinAgentMore:
|
||||
|
||||
class TestRegenerateAgentKey:
|
||||
def _seed_published_with_key(self, pg_conn, user, key):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent = _seed_agent(pg_conn, user=user, status="published")
|
||||
AgentsRepository(pg_conn).update(str(agent["id"]), user, {"key": key})
|
||||
return agent
|
||||
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/regenerate_agent_key/abc", method="POST"
|
||||
@@ -1461,7 +1461,7 @@ class TestRegenerateAgentKey:
|
||||
assert status == 401
|
||||
|
||||
def test_returns_404_when_missing(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/regenerate_agent_key/00000000-0000-0000-0000-000000000000",
|
||||
@@ -1476,7 +1476,7 @@ class TestRegenerateAgentKey:
|
||||
|
||||
def test_returns_404_for_non_owner(self, app, pg_conn):
|
||||
"""Owner-only: another user cannot rotate someone else's key."""
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
|
||||
owner = "u-owner-key"
|
||||
agent = self._seed_published_with_key(pg_conn, owner, "owner-old-key")
|
||||
@@ -1490,7 +1490,7 @@ class TestRegenerateAgentKey:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_returns_400_for_draft_without_key(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
|
||||
user = "u-draft-key"
|
||||
agent = _seed_agent(pg_conn, user=user, status="draft")
|
||||
@@ -1504,8 +1504,8 @@ class TestRegenerateAgentKey:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_regenerates_key_and_invalidates_old(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-regen"
|
||||
old_key = "regen-old-key"
|
||||
@@ -1536,17 +1536,17 @@ class TestRegenerateAgentKey:
|
||||
not owner-scoped, and the conversation is created with api_key set but
|
||||
agent_id NULL to prove the api_key-only path is covered.
|
||||
"""
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.shared_conversations import (
|
||||
from docsgpt.storage.db.repositories.shared_conversations import (
|
||||
SharedConversationsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.stack_logs import (
|
||||
from docsgpt.storage.db.repositories.stack_logs import (
|
||||
StackLogsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.token_usage import (
|
||||
from docsgpt.storage.db.repositories.token_usage import (
|
||||
TokenUsageRepository,
|
||||
)
|
||||
|
||||
@@ -1601,7 +1601,7 @@ class TestRegenerateAgentKey:
|
||||
assert _count("shared_conversations", new_key) == 1
|
||||
|
||||
def test_db_error_returns_500(self, app):
|
||||
from application.api.user.agents.routes import RegenerateAgentKey
|
||||
from docsgpt.api.user.agents.routes import RegenerateAgentKey
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -1609,7 +1609,7 @@ class TestRegenerateAgentKey:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/regenerate_agent_key/abc", method="POST"
|
||||
):
|
||||
@@ -1621,7 +1621,7 @@ class TestRegenerateAgentKey:
|
||||
|
||||
class TestPinnedAgentsListing:
|
||||
def test_returns_pinned_after_pinning(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import PinAgent, PinnedAgents
|
||||
from docsgpt.api.user.agents.routes import PinAgent, PinnedAgents
|
||||
|
||||
user = "u-pinned-list"
|
||||
agent = _seed_agent(pg_conn, user=user, retriever="classic")
|
||||
@@ -1646,7 +1646,7 @@ class TestPinnedAgentsListing:
|
||||
assert response.json[0]["pinned"] is True
|
||||
|
||||
def test_pinned_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.routes import PinnedAgents
|
||||
from docsgpt.api.user.agents.routes import PinnedAgents
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -1654,7 +1654,7 @@ class TestPinnedAgentsListing:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _broken
|
||||
"docsgpt.api.user.agents.routes.db_session", _broken
|
||||
), app.test_request_context("/api/pinned_agents"):
|
||||
from flask import request
|
||||
request.decoded_token = {"sub": "u"}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for helper functions in application/api/user/agents/routes.py."""
|
||||
"""Tests for helper functions in docsgpt/api/user/agents/routes.py."""
|
||||
|
||||
import json
|
||||
from contextlib import contextmanager
|
||||
@@ -20,28 +20,28 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _yield
|
||||
"docsgpt.api.user.agents.routes.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.routes.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.routes.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
class TestNormalizeWorkflowReference:
|
||||
def test_none_returns_none(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference(None) is None
|
||||
|
||||
def test_dict_returns_id_field(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference({"id": "w1"}) == "w1"
|
||||
|
||||
def test_dict_returns_workflow_id_field(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert (
|
||||
@@ -49,25 +49,25 @@ class TestNormalizeWorkflowReference:
|
||||
)
|
||||
|
||||
def test_dict_with_underscore_id(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference({"_id": "wf-2"}) == "wf-2"
|
||||
|
||||
def test_empty_string_returns_empty(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference("") == ""
|
||||
|
||||
def test_plain_string_returned(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference("wf-123") == "wf-123"
|
||||
|
||||
def test_json_string_dict(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert (
|
||||
@@ -75,19 +75,19 @@ class TestNormalizeWorkflowReference:
|
||||
)
|
||||
|
||||
def test_json_string_as_string(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference('"wf-str"') == "wf-str"
|
||||
|
||||
def test_invalid_json_returns_original(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference("not-json-wf") == "not-json-wf"
|
||||
|
||||
def test_non_string_non_dict_coerced(self):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
normalize_workflow_reference,
|
||||
)
|
||||
assert normalize_workflow_reference(42) == "42"
|
||||
@@ -95,14 +95,14 @@ class TestNormalizeWorkflowReference:
|
||||
|
||||
class TestResolveWorkflowForUser:
|
||||
def test_none_workflow_returns_none(self, pg_conn):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
_resolve_workflow_for_user,
|
||||
)
|
||||
pg_id, err = _resolve_workflow_for_user(pg_conn, None, "u")
|
||||
assert pg_id is None and err is None
|
||||
|
||||
def test_not_found_returns_error(self, pg_conn, app):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
_resolve_workflow_for_user,
|
||||
)
|
||||
with app.app_context():
|
||||
@@ -116,10 +116,10 @@ class TestResolveWorkflowForUser:
|
||||
assert err.status_code == 404
|
||||
|
||||
def test_resolves_owned_workflow(self, pg_conn, app):
|
||||
from application.api.user.agents.routes import (
|
||||
from docsgpt.api.user.agents.routes import (
|
||||
_resolve_workflow_for_user,
|
||||
)
|
||||
from application.storage.db.repositories.workflows import (
|
||||
from docsgpt.storage.db.repositories.workflows import (
|
||||
WorkflowsRepository,
|
||||
)
|
||||
|
||||
@@ -135,13 +135,13 @@ class TestResolveWorkflowForUser:
|
||||
|
||||
class TestResolveFolderId:
|
||||
def test_none_returns_none(self, pg_conn):
|
||||
from application.api.user.agents.routes import _resolve_folder_id
|
||||
from docsgpt.api.user.agents.routes import _resolve_folder_id
|
||||
pg_id, err = _resolve_folder_id(pg_conn, None, "u")
|
||||
assert pg_id is None
|
||||
assert err is None
|
||||
|
||||
def test_not_found_returns_error(self, pg_conn, app):
|
||||
from application.api.user.agents.routes import _resolve_folder_id
|
||||
from docsgpt.api.user.agents.routes import _resolve_folder_id
|
||||
|
||||
with app.app_context():
|
||||
pg_id, err = _resolve_folder_id(
|
||||
@@ -151,8 +151,8 @@ class TestResolveFolderId:
|
||||
assert err.status_code == 404
|
||||
|
||||
def test_resolves_owned_folder(self, pg_conn, app):
|
||||
from application.api.user.agents.routes import _resolve_folder_id
|
||||
from application.storage.db.repositories.agent_folders import (
|
||||
from docsgpt.api.user.agents.routes import _resolve_folder_id
|
||||
from docsgpt.storage.db.repositories.agent_folders import (
|
||||
AgentFoldersRepository,
|
||||
)
|
||||
|
||||
@@ -166,7 +166,7 @@ class TestResolveFolderId:
|
||||
|
||||
class TestFormatAgentOutput:
|
||||
def test_basic_shape(self):
|
||||
from application.api.user.agents.routes import _format_agent_output
|
||||
from docsgpt.api.user.agents.routes import _format_agent_output
|
||||
|
||||
agent = {
|
||||
"id": "agent-1",
|
||||
@@ -191,21 +191,21 @@ class TestFormatAgentOutput:
|
||||
assert out["key"].startswith("secr") and out["key"].endswith("long")
|
||||
|
||||
def test_no_key_masking(self):
|
||||
from application.api.user.agents.routes import _format_agent_output
|
||||
from docsgpt.api.user.agents.routes import _format_agent_output
|
||||
|
||||
agent = {"id": "a", "name": "n", "chunks": None}
|
||||
out = _format_agent_output(agent, include_key_masked=False)
|
||||
assert "key" not in out
|
||||
|
||||
def test_empty_key_returns_empty_string(self):
|
||||
from application.api.user.agents.routes import _format_agent_output
|
||||
from docsgpt.api.user.agents.routes import _format_agent_output
|
||||
|
||||
agent = {"id": "a", "name": "n", "key": ""}
|
||||
out = _format_agent_output(agent)
|
||||
assert out["key"] == ""
|
||||
|
||||
def test_with_folder_and_workflow(self):
|
||||
from application.api.user.agents.routes import _format_agent_output
|
||||
from docsgpt.api.user.agents.routes import _format_agent_output
|
||||
|
||||
agent = {
|
||||
"id": "a", "name": "n",
|
||||
@@ -218,7 +218,7 @@ class TestFormatAgentOutput:
|
||||
|
||||
class TestBuildCreateKwargs:
|
||||
def test_classic_kwargs(self):
|
||||
from application.api.user.agents.routes import _build_create_kwargs
|
||||
from docsgpt.api.user.agents.routes import _build_create_kwargs
|
||||
|
||||
data = {
|
||||
"description": "d",
|
||||
@@ -233,7 +233,7 @@ class TestBuildCreateKwargs:
|
||||
assert out["chunks"] == 3
|
||||
|
||||
def test_invalid_chunks_skipped(self, app):
|
||||
from application.api.user.agents.routes import _build_create_kwargs
|
||||
from docsgpt.api.user.agents.routes import _build_create_kwargs
|
||||
|
||||
data = {"chunks": "abc"}
|
||||
with app.app_context():
|
||||
@@ -243,7 +243,7 @@ class TestBuildCreateKwargs:
|
||||
assert "chunks" not in out
|
||||
|
||||
def test_prompt_id_default_not_set(self):
|
||||
from application.api.user.agents.routes import _build_create_kwargs
|
||||
from docsgpt.api.user.agents.routes import _build_create_kwargs
|
||||
|
||||
data = {"prompt_id": "default"}
|
||||
out = _build_create_kwargs(
|
||||
@@ -252,7 +252,7 @@ class TestBuildCreateKwargs:
|
||||
assert "prompt_id" not in out
|
||||
|
||||
def test_image_url_used_when_provided(self):
|
||||
from application.api.user.agents.routes import _build_create_kwargs
|
||||
from docsgpt.api.user.agents.routes import _build_create_kwargs
|
||||
|
||||
out = _build_create_kwargs(
|
||||
{}, image_url="/upload/img.png", agent_type="classic",
|
||||
@@ -260,7 +260,7 @@ class TestBuildCreateKwargs:
|
||||
assert out.get("image") == "/upload/img.png"
|
||||
|
||||
def test_client_image_path_is_never_persisted(self):
|
||||
from application.api.user.agents.routes import _build_create_kwargs
|
||||
from docsgpt.api.user.agents.routes import _build_create_kwargs
|
||||
|
||||
out = _build_create_kwargs(
|
||||
{"image": ".env"}, image_url="", agent_type="classic",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for application/api/user/agents/sharing.py.
|
||||
"""Tests for docsgpt/api/user/agents/sharing.py.
|
||||
|
||||
Uses the ephemeral ``pg_conn`` fixture to exercise the real PG repository
|
||||
code paths (agents, users).
|
||||
@@ -23,15 +23,15 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.sharing.db_session", _yield
|
||||
"docsgpt.api.user.agents.sharing.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.sharing.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.sharing.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def _make_agent(pg_conn, user_id="owner", *, shared=False, shared_token=None):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
agent = AgentsRepository(pg_conn).create(
|
||||
user_id,
|
||||
"Agent",
|
||||
@@ -49,7 +49,7 @@ def _make_agent(pg_conn, user_id="owner", *, shared=False, shared_token=None):
|
||||
|
||||
class TestSharedAgentGet:
|
||||
def test_returns_400_missing_token(self, app):
|
||||
from application.api.user.agents.sharing import SharedAgent
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent
|
||||
|
||||
with app.test_request_context("/api/shared_agent"):
|
||||
from flask import request
|
||||
@@ -58,7 +58,7 @@ class TestSharedAgentGet:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_404_for_unknown_token(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import SharedAgent
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/shared_agent?token=unknown"
|
||||
@@ -69,7 +69,7 @@ class TestSharedAgentGet:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_returns_agent_for_known_token(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import SharedAgent
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent
|
||||
|
||||
_make_agent(pg_conn, shared=True, shared_token="abc123")
|
||||
|
||||
@@ -85,7 +85,7 @@ class TestSharedAgentGet:
|
||||
assert data["shared"] is True
|
||||
|
||||
def test_records_shared_with_different_user(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import SharedAgent
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent
|
||||
|
||||
_make_agent(pg_conn, user_id="owner", shared=True, shared_token="tk1")
|
||||
|
||||
@@ -98,7 +98,7 @@ class TestSharedAgentGet:
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.sharing import SharedAgent
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -106,7 +106,7 @@ class TestSharedAgentGet:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.sharing.db_readonly", _broken
|
||||
"docsgpt.api.user.agents.sharing.db_readonly", _broken
|
||||
), app.test_request_context("/api/shared_agent?token=x"):
|
||||
from flask import request
|
||||
request.decoded_token = None
|
||||
@@ -116,7 +116,7 @@ class TestSharedAgentGet:
|
||||
|
||||
class TestSharedAgents:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.sharing import SharedAgents
|
||||
from docsgpt.api.user.agents.sharing import SharedAgents
|
||||
|
||||
with app.test_request_context("/api/shared_agents"):
|
||||
from flask import request
|
||||
@@ -125,7 +125,7 @@ class TestSharedAgents:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_empty_list_for_new_user(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import SharedAgents
|
||||
from docsgpt.api.user.agents.sharing import SharedAgents
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/shared_agents"
|
||||
@@ -139,7 +139,7 @@ class TestSharedAgents:
|
||||
def test_returns_shared_agents_for_user(self, app, pg_conn):
|
||||
"""After SharedAgent adds an agent to the user's shared_with_me, it
|
||||
should appear in SharedAgents."""
|
||||
from application.api.user.agents.sharing import SharedAgent, SharedAgents
|
||||
from docsgpt.api.user.agents.sharing import SharedAgent, SharedAgents
|
||||
|
||||
_make_agent(pg_conn, user_id="owner", shared=True, shared_token="tk2")
|
||||
|
||||
@@ -162,7 +162,7 @@ class TestSharedAgents:
|
||||
assert response.json[0]["shared"] is True
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.sharing import SharedAgents
|
||||
from docsgpt.api.user.agents.sharing import SharedAgents
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -170,7 +170,7 @@ class TestSharedAgents:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.sharing.db_session", _broken
|
||||
"docsgpt.api.user.agents.sharing.db_session", _broken
|
||||
), app.test_request_context("/api/shared_agents"):
|
||||
from flask import request
|
||||
request.decoded_token = {"sub": "u"}
|
||||
@@ -180,7 +180,7 @@ class TestSharedAgents:
|
||||
|
||||
class TestShareAgent:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/share_agent", method="PUT", json={"id": "x", "shared": True}
|
||||
@@ -191,7 +191,7 @@ class TestShareAgent:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/share_agent", method="PUT", json={"shared": True}
|
||||
@@ -202,7 +202,7 @@ class TestShareAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_400_missing_shared(self, app):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/share_agent", method="PUT", json={"id": "x"}
|
||||
@@ -213,7 +213,7 @@ class TestShareAgent:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_404_agent_not_found(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
|
||||
with _patch_db(pg_conn), app.test_request_context(
|
||||
"/api/share_agent",
|
||||
@@ -226,8 +226,8 @@ class TestShareAgent:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_shares_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent = _make_agent(pg_conn, user_id="owner")
|
||||
agent_id = str(agent["id"])
|
||||
@@ -250,8 +250,8 @@ class TestShareAgent:
|
||||
assert got["shared_metadata"]["shared_by"] == "alice"
|
||||
|
||||
def test_unshares_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent = _make_agent(pg_conn, user_id="owner", shared=True, shared_token="tk")
|
||||
agent_id = str(agent["id"])
|
||||
@@ -270,7 +270,7 @@ class TestShareAgent:
|
||||
assert got["shared_token"] is None
|
||||
|
||||
def test_db_error_returns_400(self, app):
|
||||
from application.api.user.agents.sharing import ShareAgent
|
||||
from docsgpt.api.user.agents.sharing import ShareAgent
|
||||
|
||||
@contextmanager
|
||||
def _broken():
|
||||
@@ -278,7 +278,7 @@ class TestShareAgent:
|
||||
yield
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.sharing.db_session", _broken
|
||||
"docsgpt.api.user.agents.sharing.db_session", _broken
|
||||
), app.test_request_context(
|
||||
"/api/share_agent",
|
||||
method="PUT",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Gap-coverage tests for application.api.user.agents.webhooks.
|
||||
"""Gap-coverage tests for docsgpt.api.user.agents.webhooks.
|
||||
|
||||
These tests use only stdlib IDs (uuid / hex strings) — no bson/ObjectId.
|
||||
The agent routes still read from Mongo collections internally; we mock
|
||||
@@ -47,13 +47,13 @@ class TestAgentWebhookListenerGaps:
|
||||
|
||||
def test_post_empty_payload_still_enqueues(self, app):
|
||||
"""Empty dict payload does not block task enqueue (warning only)."""
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
mock_task = Mock()
|
||||
mock_task.id = "task_empty"
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook"
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook"
|
||||
) as mock_process:
|
||||
mock_process.apply_async.return_value = mock_task
|
||||
with app.test_request_context(
|
||||
@@ -69,13 +69,13 @@ class TestAgentWebhookListenerGaps:
|
||||
|
||||
def test_get_empty_query_string(self, app):
|
||||
"""GET request with no query params produces an empty payload dict."""
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
mock_task = Mock()
|
||||
mock_task.id = "task_noqs"
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook"
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook"
|
||||
) as mock_process:
|
||||
mock_process.apply_async.return_value = mock_task
|
||||
with app.test_request_context(
|
||||
@@ -96,13 +96,13 @@ class TestAgentWebhookListenerGaps:
|
||||
|
||||
def test_enqueue_returns_task_id_in_response(self, app):
|
||||
"""Success response body includes task_id from the Celery task."""
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
mock_task = Mock()
|
||||
mock_task.id = "celery-task-99"
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook"
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook"
|
||||
) as mock_process:
|
||||
mock_process.apply_async.return_value = mock_task
|
||||
with app.test_request_context(
|
||||
@@ -118,10 +118,10 @@ class TestAgentWebhookListenerGaps:
|
||||
|
||||
def test_enqueue_error_returns_500_with_message(self, app):
|
||||
"""Queue failure returns 500 with a human-readable message."""
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook"
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook"
|
||||
) as mock_process:
|
||||
mock_process.apply_async.side_effect = RuntimeError("celery is down")
|
||||
with app.test_request_context(
|
||||
@@ -149,9 +149,9 @@ def _patch_webhooks_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.db_session", _yield
|
||||
"docsgpt.api.user.agents.webhooks.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.webhooks.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.webhooks.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
@@ -163,16 +163,16 @@ def _patch_base_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.base.db_readonly", _yield
|
||||
"docsgpt.api.user.base.db_readonly", _yield
|
||||
), patch(
|
||||
"application.api.user.base.db_session", _yield
|
||||
"docsgpt.api.user.base.db_session", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
class TestAgentWebhookGet:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.agents.webhooks import AgentWebhook
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhook
|
||||
|
||||
with app.test_request_context("/api/agent_webhook?id=x"):
|
||||
from flask import request
|
||||
@@ -181,7 +181,7 @@ class TestAgentWebhookGet:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_id(self, app):
|
||||
from application.api.user.agents.webhooks import AgentWebhook
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhook
|
||||
|
||||
with app.test_request_context("/api/agent_webhook"):
|
||||
from flask import request
|
||||
@@ -190,7 +190,7 @@ class TestAgentWebhookGet:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_returns_404_missing_agent(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhook
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhook
|
||||
|
||||
with _patch_webhooks_db(pg_conn), app.test_request_context(
|
||||
"/api/agent_webhook?id=00000000-0000-0000-0000-000000000000"
|
||||
@@ -201,14 +201,14 @@ class TestAgentWebhookGet:
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_generates_webhook_url(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhook
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhook
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-wh"
|
||||
agent = AgentsRepository(pg_conn).create(user, "a", "published")
|
||||
|
||||
with _patch_webhooks_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.settings.API_URL",
|
||||
"docsgpt.api.user.agents.webhooks.settings.API_URL",
|
||||
"https://api.test",
|
||||
), app.test_request_context(
|
||||
f"/api/agent_webhook?id={agent['id']}"
|
||||
@@ -222,8 +222,8 @@ class TestAgentWebhookGet:
|
||||
)
|
||||
|
||||
def test_reuses_existing_webhook_token(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhook
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhook
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-wh-reuse"
|
||||
agent = AgentsRepository(pg_conn).create(
|
||||
@@ -231,7 +231,7 @@ class TestAgentWebhookGet:
|
||||
)
|
||||
|
||||
with _patch_webhooks_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.settings.API_URL",
|
||||
"docsgpt.api.user.agents.webhooks.settings.API_URL",
|
||||
"https://api.test",
|
||||
), app.test_request_context(
|
||||
f"/api/agent_webhook?id={agent['id']}"
|
||||
@@ -244,8 +244,8 @@ class TestAgentWebhookGet:
|
||||
|
||||
class TestAgentWebhookListener:
|
||||
def test_post_valid_enqueues_task(self, app, pg_conn):
|
||||
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
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
user = "u-wh-enq"
|
||||
@@ -255,7 +255,7 @@ class TestAgentWebhookListener:
|
||||
fake_task = MagicMock(id="task-post")
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
return_value=fake_task,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-enq", method="POST",
|
||||
@@ -272,8 +272,8 @@ class TestAgentWebhookListener:
|
||||
assert response.json["task_id"] == "task-post"
|
||||
|
||||
def test_get_collects_query_params(self, app, pg_conn):
|
||||
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
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
user = "u-wh-get"
|
||||
@@ -283,7 +283,7 @@ class TestAgentWebhookListener:
|
||||
fake_task = MagicMock(id="task-get")
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
return_value=fake_task,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-get?foo=bar&baz=42"
|
||||
|
||||
@@ -19,15 +19,15 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.db_session", _yield
|
||||
"docsgpt.api.user.agents.webhooks.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.webhooks.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.webhooks.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def _seed_agent(pg_conn, user="u", token="tk", **kw):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
return AgentsRepository(pg_conn).create(
|
||||
user, "a", "published", incoming_webhook_token=token, **kw,
|
||||
)
|
||||
@@ -42,13 +42,13 @@ def _apply_async_mock():
|
||||
|
||||
class TestWebhookIdempotency:
|
||||
def test_no_header_enqueues_normally(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-noh", token="tk-noh")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-noh", method="POST",
|
||||
@@ -66,13 +66,13 @@ class TestWebhookIdempotency:
|
||||
def test_header_first_post_records_row(self, app, pg_conn):
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-first", token="tk-first")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-first", method="POST",
|
||||
@@ -105,13 +105,13 @@ class TestWebhookIdempotency:
|
||||
"""The Celery task body needs the key so ``with_idempotency`` can
|
||||
record terminal status and ``_derive_source_id`` can pick it up.
|
||||
"""
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-fwd", token="tk-fwd")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-fwd", method="POST",
|
||||
@@ -133,13 +133,13 @@ class TestWebhookIdempotency:
|
||||
)
|
||||
|
||||
def test_same_header_second_post_returns_cached(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-rep", token="tk-rep")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
):
|
||||
with app.test_request_context(
|
||||
@@ -179,8 +179,8 @@ class TestWebhookIdempotency:
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from contextlib import contextmanager
|
||||
|
||||
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
|
||||
|
||||
with pg_engine.begin() as conn:
|
||||
agent = AgentsRepository(conn).create(
|
||||
@@ -218,13 +218,13 @@ class TestWebhookIdempotency:
|
||||
# module-attribute patches once before fanning out so every
|
||||
# thread sees the mock instead of racing on save/restore.
|
||||
with patch(
|
||||
"application.api.user.agents.webhooks.db_session",
|
||||
"docsgpt.api.user.agents.webhooks.db_session",
|
||||
_engine_session,
|
||||
), patch(
|
||||
"application.api.user.agents.webhooks.db_readonly",
|
||||
"docsgpt.api.user.agents.webhooks.db_readonly",
|
||||
_engine_readonly,
|
||||
), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), ThreadPoolExecutor(max_workers=8) as ex:
|
||||
responses = list(ex.map(fire, range(8)))
|
||||
@@ -243,14 +243,14 @@ class TestWebhookIdempotency:
|
||||
"""
|
||||
from sqlalchemy import text as sql_text
|
||||
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent_a = _seed_agent(pg_conn, user="u-a", token="tk-a")
|
||||
agent_b = _seed_agent(pg_conn, user="u-b", token="tk-b")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
):
|
||||
with app.test_request_context(
|
||||
@@ -296,13 +296,13 @@ class TestWebhookIdempotency:
|
||||
def test_empty_header_treated_as_absent(self, app, pg_conn):
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-empty", token="tk-empty")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-empty", method="POST",
|
||||
@@ -323,13 +323,13 @@ class TestWebhookIdempotency:
|
||||
assert count == 0
|
||||
|
||||
def test_oversized_header_rejected_with_400(self, app, pg_conn):
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-big", token="tk-big")
|
||||
oversized = "x" * 257
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
) as mock_apply, app.test_request_context(
|
||||
"/api/webhooks/agents/tk-big", method="POST",
|
||||
json={"event": "x"},
|
||||
@@ -351,14 +351,14 @@ class TestWebhookIdempotency:
|
||||
"""
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.api.user.agents.webhooks import AgentWebhookListener
|
||||
from docsgpt.api.user.agents.webhooks import AgentWebhookListener
|
||||
|
||||
agent = _seed_agent(pg_conn, user="u-stale", token="tk-stale")
|
||||
apply_mock = _apply_async_mock()
|
||||
|
||||
# First POST creates a dedup row.
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-stale", method="POST",
|
||||
@@ -388,7 +388,7 @@ class TestWebhookIdempotency:
|
||||
|
||||
# Second POST with the same key must enqueue again, not silently dedup.
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
"docsgpt.api.user.agents.webhooks.process_agent_webhook.apply_async",
|
||||
apply_mock,
|
||||
), app.test_request_context(
|
||||
"/api/webhooks/agents/tk-stale", method="POST",
|
||||
|
||||
@@ -26,22 +26,22 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.agents.routes.db_session", _yield
|
||||
"docsgpt.api.user.agents.routes.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.agents.routes.db_readonly", _yield
|
||||
"docsgpt.api.user.agents.routes.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def _seed_workflow(pg_conn, user, *, name="WF"):
|
||||
"""Create a start → agent → end workflow; returns (workflow, nodes, edges)."""
|
||||
from application.storage.db.repositories.workflow_edges import (
|
||||
from docsgpt.storage.db.repositories.workflow_edges import (
|
||||
WorkflowEdgesRepository,
|
||||
)
|
||||
from application.storage.db.repositories.workflow_nodes import (
|
||||
from docsgpt.storage.db.repositories.workflow_nodes import (
|
||||
WorkflowNodesRepository,
|
||||
)
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf = WorkflowsRepository(pg_conn).create(user, name, description="d")
|
||||
wf_id = str(wf["id"])
|
||||
@@ -80,10 +80,10 @@ def _seed_workflow(pg_conn, user, *, name="WF"):
|
||||
|
||||
|
||||
def _graph(pg_conn, workflow_id, version=1):
|
||||
from application.storage.db.repositories.workflow_edges import (
|
||||
from docsgpt.storage.db.repositories.workflow_edges import (
|
||||
WorkflowEdgesRepository,
|
||||
)
|
||||
from application.storage.db.repositories.workflow_nodes import (
|
||||
from docsgpt.storage.db.repositories.workflow_nodes import (
|
||||
WorkflowNodesRepository,
|
||||
)
|
||||
|
||||
@@ -94,7 +94,7 @@ def _graph(pg_conn, workflow_id, version=1):
|
||||
|
||||
class TestCloneToUser:
|
||||
def test_clones_graph_for_new_owner(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "owner-a", name="Source WF")
|
||||
clone = WorkflowsRepository(pg_conn).clone_to_user(
|
||||
@@ -122,7 +122,7 @@ class TestCloneToUser:
|
||||
assert len(src_nodes) == 3 and len(src_edges) == 2
|
||||
|
||||
def test_wrong_owner_returns_none(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "owner-a")
|
||||
assert (
|
||||
@@ -133,7 +133,7 @@ class TestCloneToUser:
|
||||
)
|
||||
|
||||
def test_missing_workflow_returns_none(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
assert (
|
||||
WorkflowsRepository(pg_conn).clone_to_user(
|
||||
@@ -145,9 +145,9 @@ class TestCloneToUser:
|
||||
|
||||
class TestAdoptWorkflowAgent:
|
||||
def test_adopt_clones_the_graph(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "__system__", name="Template WF")
|
||||
repo = AgentsRepository(pg_conn)
|
||||
@@ -187,8 +187,8 @@ class TestAdoptWorkflowAgent:
|
||||
Publishing the agent anyway would hand the adopter a workflow agent
|
||||
with no graph — permanently unrunnable — so the adopt fails instead.
|
||||
"""
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "someone-else")
|
||||
repo = AgentsRepository(pg_conn)
|
||||
@@ -219,16 +219,16 @@ class TestAdoptWorkflowAgent:
|
||||
|
||||
def test_adopt_strips_foreign_node_refs(self, app, pg_conn):
|
||||
"""Cloned agent nodes keep builtin tool ids but shed the owner's refs."""
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from application.api.user.agents.routes import AdoptAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.user_tools import (
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
from docsgpt.api.user.agents.routes import AdoptAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.user_tools import (
|
||||
UserToolsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.workflow_nodes import (
|
||||
from docsgpt.storage.db.repositories.workflow_nodes import (
|
||||
WorkflowNodesRepository,
|
||||
)
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
owner_tool = UserToolsRepository(pg_conn).create(
|
||||
"__system__", "brave", config={}, display_name="Brave"
|
||||
@@ -291,9 +291,9 @@ class TestAdoptWorkflowAgent:
|
||||
|
||||
class TestDeleteWorkflowAgent:
|
||||
def test_delete_removes_owned_workflow(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
user = "u-wf-del"
|
||||
wf, _, _ = _seed_workflow(pg_conn, user)
|
||||
@@ -319,9 +319,9 @@ class TestDeleteWorkflowAgent:
|
||||
"""Regression: deleting an agent whose ``workflow_id`` points at another
|
||||
user's workflow (the pre-clone adopted shape) must not touch that graph.
|
||||
The old explicit node/edge cleanup was not owner-scoped and gutted it."""
|
||||
from application.api.user.agents.routes import DeleteAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.api.user.agents.routes import DeleteAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "__system__", name="Shared Template WF")
|
||||
repo = AgentsRepository(pg_conn)
|
||||
@@ -350,8 +350,8 @@ class TestDeleteWorkflowAgent:
|
||||
|
||||
class TestCreateWorkflowAgent:
|
||||
def test_create_published_with_owned_workflow(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-wf-create"
|
||||
wf, _, _ = _seed_workflow(pg_conn, user)
|
||||
@@ -381,7 +381,7 @@ class TestCreateWorkflowAgent:
|
||||
assert agent["status"] == "published"
|
||||
|
||||
def test_create_published_with_unowned_workflow_returns_404(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import CreateAgent
|
||||
from docsgpt.api.user.agents.routes import CreateAgent
|
||||
|
||||
wf, _, _ = _seed_workflow(pg_conn, "someone-else")
|
||||
|
||||
@@ -405,8 +405,8 @@ class TestCreateWorkflowAgent:
|
||||
|
||||
class TestUpdateWorkflowAgent:
|
||||
def test_update_sets_and_clears_workflow(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-wf-update"
|
||||
wf, _, _ = _seed_workflow(pg_conn, user)
|
||||
@@ -440,8 +440,8 @@ class TestUpdateWorkflowAgent:
|
||||
assert repo.get(agent_id, user)["workflow_id"] is None
|
||||
|
||||
def test_publish_without_workflow_is_rejected(self, app, pg_conn):
|
||||
from application.api.user.agents.routes import UpdateAgent
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.api.user.agents.routes import UpdateAgent
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
user = "u-wf-update2"
|
||||
agent = AgentsRepository(pg_conn).create(
|
||||
|
||||
Reference in new issue
Block a user