mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-15 02:16:08 +00:00
feat(agents): make sources optional and drop the synthetic "Default" source
The sources list used to start with a fake "Default" entry that had no id and, at run time, meant "no source, skip retrieval". The agent form pre-selected it, snapped back to it when the last source was deselected, and refused to publish without it, so a new agent always looked like it had a knowledge base when it had none. Backend - /api/sources returns only ingested sources; no placeholder row. - Publishing an agent no longer requires a source on create or update. The legacy "default" value is still accepted and maps to NULL. Frontend - The agent source picker starts empty, can be cleared, and shows a hint that a source-less agent answers from the model and its tools only. - The picker groups sources into "Your sources" and "Shared with team" when any team-shared source exists, shows "N sources selected" for a multi-selection, and gets the same "Go to Sources" / "Upload new" footer as the chat picker. A source uploaded from the form is selected when it lands. - Source selection serialisation and the picker id live in one helper shared with the chat picker; the four copies in the form are gone. - The client no longer seeds a placeholder source in the store, and the dead auto-select of a "default" document is removed.
This commit is contained in:
1 parent
fb15649a3f
commit
79d418f32a
23 files changed
+532
-365
No files matched your search
@@ -647,9 +647,9 @@ class StreamProcessor:
|
||||
def _configure_source(self):
|
||||
"""Configure the source based on agent data.
|
||||
|
||||
The literal string ``"default"`` is a placeholder meaning "no
|
||||
ingested source" and is normalized to an empty source so that no
|
||||
retrieval is attempted.
|
||||
The literal string ``"default"`` is a legacy placeholder (older
|
||||
clients sent it for "no ingested source") and is normalized to an
|
||||
empty source so that no retrieval is attempted.
|
||||
"""
|
||||
if self._agent_data:
|
||||
agent_data = self._agent_data
|
||||
|
||||
@@ -76,7 +76,8 @@ AGENT_TYPE_SCHEMAS = {
|
||||
# is acceptable and maps to NULL downstream.
|
||||
"validate_published": ["name", "description"],
|
||||
"validate_draft": [],
|
||||
"require_source": True,
|
||||
# No source is required: a source-less agent answers from the model
|
||||
# and its tools, and ``source``/``sources`` map to NULL downstream.
|
||||
"fields": [
|
||||
"name",
|
||||
"description",
|
||||
@@ -661,20 +662,6 @@ class CreateAgent(Resource):
|
||||
if data.get("status") == "published":
|
||||
required_fields = schema["required_published"]
|
||||
validate_fields = schema["validate_published"]
|
||||
if (
|
||||
schema.get("require_source")
|
||||
and not data.get("source")
|
||||
and not data.get("sources")
|
||||
):
|
||||
return make_response(
|
||||
jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "Either 'source' or 'sources' field is required for published agents",
|
||||
}
|
||||
),
|
||||
400,
|
||||
)
|
||||
else:
|
||||
required_fields = schema["required_draft"]
|
||||
validate_fields = schema["validate_draft"]
|
||||
@@ -1190,29 +1177,9 @@ class UpdateAgent(Resource):
|
||||
)
|
||||
if not final_value:
|
||||
missing_published_fields.append(field_label)
|
||||
source_final = update_fields.get(
|
||||
"source_id", existing_agent.get("source_id"),
|
||||
)
|
||||
extra_final = update_fields.get(
|
||||
"extra_source_ids", existing_agent.get("extra_source_ids") or [],
|
||||
)
|
||||
# ``retriever`` carries the runtime identity for
|
||||
# agents that publish against the synthetic
|
||||
# "Default" source (frontend's auto-selected
|
||||
# ``{name: "Default", retriever: "classic"}``
|
||||
# entry has no ``id``, so ``source_id`` ends up
|
||||
# NULL even though the user picked something).
|
||||
# Without this fallback the most common new-agent
|
||||
# publish flow gets a 400.
|
||||
retriever_final = update_fields.get(
|
||||
"retriever", existing_agent.get("retriever"),
|
||||
)
|
||||
if (
|
||||
not source_final
|
||||
and not extra_final
|
||||
and not retriever_final
|
||||
):
|
||||
missing_published_fields.append("Source or retriever")
|
||||
# Sources are optional: a published agent with no
|
||||
# ``source_id`` and no ``extra_source_ids`` skips
|
||||
# retrieval and answers from the model and its tools.
|
||||
if missing_published_fields:
|
||||
return _reject(
|
||||
"Cannot publish agent. Missing or invalid required "
|
||||
|
||||
@@ -73,16 +73,10 @@ class CombinedJson(Resource):
|
||||
if not decoded_token:
|
||||
return make_response(jsonify({"success": False}), 401)
|
||||
user = decoded_token.get("sub")
|
||||
data = [
|
||||
{
|
||||
"name": "Default",
|
||||
"date": "default",
|
||||
"model": settings.EMBEDDINGS_NAME,
|
||||
"location": "remote",
|
||||
"tokens": "",
|
||||
"retriever": "classic",
|
||||
}
|
||||
]
|
||||
# Only ingested sources are listed. There is no synthetic "Default"
|
||||
# entry: "no source" is expressed by an empty selection on the client,
|
||||
# and the answer path treats a missing source as "skip retrieval".
|
||||
data = []
|
||||
|
||||
try:
|
||||
with db_readonly() as conn:
|
||||
|
||||
Reference in new issue
Block a user