Feat: More APIs for compiler list and deletion of compilation result. (#17425)

### Summary

 More APIs for comliler list and deletion of compilation result.
This commit is contained in:
Kevin Hu
2026-07-27 20:11:18 +08:00
committed by GitHub
parent f73f4cb720
commit f9e47ae0b9
7 changed files with 208 additions and 7 deletions

View File

@@ -671,6 +671,12 @@ def prompts():
)
# Synthetic ``canvas_category`` the frontend passes to list compilation template
# groups through the merged /agents endpoint. Also the ``type`` discriminator
# stamped on group items in the merged response.
_COMPILATION_TEMPLATE_GROUP_CATEGORY = "compilation_template_group"
@manager.route("/agents", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
@@ -702,6 +708,75 @@ def list_agents(tenant_id):
else:
effective_owner_ids = list(authorized_owner_ids)
# Groups-only: an explicit ``compilation_template_group`` category returns
# just the caller's template groups (no agents) via list_saved, so the
# frontend can render a dedicated tab. list_saved paginates in Python.
if canvas_category == _COMPILATION_TEMPLATE_GROUP_CATEGORY:
from api.db.services.compilation_template_group_service import CompilationTemplateGroupService
try:
groups = CompilationTemplateGroupService.list_saved(tenant_id, keywords, "", order_by, desc)
except Exception:
logging.exception("list_agents: compilation template group list failed for tenant=%s", tenant_id)
groups = []
for group in groups:
group["type"] = _COMPILATION_TEMPLATE_GROUP_CATEGORY
total = len(groups)
if page_number and items_per_page:
start = (page_number - 1) * items_per_page
groups = groups[start : start + items_per_page]
return get_json_result(data={"canvas": groups, "total": total})
# Merge mode: with no ``canvas_category`` (and no agent-only filters), list
# the caller's compilation template groups alongside agents, interleaved by
# ``update_time``. ``canvas_type`` / ``tags`` are agent-only concepts, so
# their presence keeps the response agent-only.
merge_groups = not canvas_category and not canvas_type and not tags
if merge_groups:
from api.db.services.compilation_template_group_service import CompilationTemplateGroupService
# Fetch every matching agent (page_number=0 disables SQL pagination) so
# the two sources can be globally ordered before we page in Python.
agents, _ = UserCanvasService.get_by_tenant_ids(
effective_owner_ids,
tenant_id,
0,
0,
order_by,
desc,
keywords,
None,
tags,
canvas_type,
)
# Groups are owner-only (no team sharing), so they're scoped to the
# caller. Keyword filters the group name; scope is left unfiltered.
try:
groups = CompilationTemplateGroupService.list_saved(tenant_id, keywords, "", order_by, desc)
except Exception:
logging.exception("list_agents: compilation template group merge failed for tenant=%s", tenant_id)
groups = []
items: list[dict] = []
for agent in agents:
agent["type"] = "agent"
items.append(agent)
for group in groups:
group["type"] = _COMPILATION_TEMPLATE_GROUP_CATEGORY
group["title"] = group["name"]
items.append(group)
# Interleave by update_time (the requested merge key); items missing the
# field sort as oldest.
items.sort(key=lambda item: item.get("update_time") or 0, reverse=desc)
total = len(items)
if page_number and items_per_page:
start = (page_number - 1) * items_per_page
items = items[start : start + items_per_page]
return get_json_result(data={"canvas": items, "total": total})
canvas, total = UserCanvasService.get_by_tenant_ids(
effective_owner_ids,
tenant_id,

View File

@@ -747,6 +747,47 @@ async def get_dataset_structure(tenant_id, dataset_id):
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/artifacts_structure", methods=["DELETE"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs
def delete_dataset_structure(tenant_id, dataset_id):
"""Delete the dataset-scope (KB-wide) structure graph for one kind.
DELETE /api/v1/datasets/<dataset_id>/artifacts_structure?kind=<kind>
Optional query param: wipe=false cancels the task without deleting stored rows.
"""
kind = request.args.get("kind", "")
if isinstance(kind, str):
kind = kind.strip()
if not kind:
return get_error_data_result(
message="`kind` is required (one of: graph, mindmap, timeline, session_essence, session_graph).",
code=RetCode.ARGUMENT_ERROR,
)
if dataset_api_service._resolve_dataset_structure_kind(kind) is None:
return get_error_data_result(
message=f"Unsupported structure kind: {kind!r}. Expected one of: graph, mindmap, timeline, session_essence, session_graph.",
code=RetCode.ARGUMENT_ERROR,
)
wipe_arg = (request.args.get("wipe", "true") or "true").strip().lower()
wipe = wipe_arg not in ("false", "0", "no", "off")
try:
success, result = dataset_api_service.delete_dataset_structure(
dataset_id,
tenant_id,
kind,
wipe=wipe,
)
if success:
return get_result(data=result)
if result == "No authorization.":
return get_result(data=False, message=result, code=RetCode.AUTHENTICATION_ERROR)
return get_error_data_result(message=result)
except Exception as e:
logging.exception(e)
return get_error_data_result(message="Internal server error")
@manager.route("/datasets/<dataset_id>/artifacts/alteration", methods=["GET"]) # noqa: F821
@login_required
@add_tenant_id_to_kwargs

View File

@@ -1721,6 +1721,13 @@ _DATASET_STRUCTURE_KIND_ALIASES = {
"session_essence": "session_essence",
"session_graph": "session_graph",
}
_DATASET_STRUCTURE_KIND_TO_INDEX_TYPE = {
"knowledge_graph": "structure_graph",
"mind_map": "structure_mindmap",
"timeline": "timeline",
"session_essence": "session_essence",
"session_graph": "session_graph",
}
def _resolve_dataset_structure_kind(kind) -> str | None:
@@ -1730,6 +1737,15 @@ def _resolve_dataset_structure_kind(kind) -> str | None:
return _DATASET_STRUCTURE_KIND_ALIASES.get(kind.strip().lower().replace("-", "_"))
def delete_dataset_structure(dataset_id: str, tenant_id: str, kind: str, wipe: bool = True):
"""Delete the merged KB-wide structure rows for one artifacts_structure kind."""
resolved_kind = _resolve_dataset_structure_kind(kind)
if not resolved_kind:
return False, f"Unsupported structure kind: {kind!r}. Expected one of: graph, mindmap, timeline, session_essence, session_graph."
index_type = _DATASET_STRUCTURE_KIND_TO_INDEX_TYPE[resolved_kind]
return delete_index(dataset_id, tenant_id, index_type, wipe=wipe)
async def get_dataset_structure(dataset_id: str, tenant_id: str, kind: str, keywords: str = ""):
"""Load the dataset-scope (KB-wide) structure graph for one ``kind``.