mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-15 20:15:30 +00:00
feat: better artefact in convo UI
This commit is contained in:
1 parent
e0649d25cf
commit
132a2de3bf
6 files changed
+183
-22
No files matched your search
@@ -944,6 +944,33 @@ class ToolExecutor:
|
||||
artifact_id = str(artifact_id).strip() if artifact_id is not None else ""
|
||||
if artifact_id:
|
||||
tool_call_data["artifact_id"] = artifact_id
|
||||
|
||||
# A single call can produce several files (``run_code`` writing more
|
||||
# than one). ``artifact_id`` names only the first, which left the rest
|
||||
# with no way into the UI, so report the full set with display names.
|
||||
get_artifacts = (
|
||||
getattr(tool, "get_artifacts", None)
|
||||
if tool_data["name"] != "api_tool"
|
||||
else None
|
||||
)
|
||||
if callable(get_artifacts):
|
||||
artifacts = []
|
||||
try:
|
||||
# Normalize inside the guard: a tool returning an unexpected
|
||||
# shape must not break the call it just completed.
|
||||
artifacts = [
|
||||
{"id": str(a["id"]).strip(), "filename": a.get("filename")}
|
||||
for a in (get_artifacts(action_name, **parameters) or [])
|
||||
if isinstance(a, dict) and a.get("id")
|
||||
]
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Failed to extract artifacts from tool %s for action %s",
|
||||
tool_data["name"],
|
||||
action_name,
|
||||
)
|
||||
if artifacts:
|
||||
tool_call_data["artifacts"] = artifacts
|
||||
result_full = bound_result_full(str(result))
|
||||
tool_call_data["resolved_arguments"] = resolved_arguments
|
||||
tool_call_data["result_full"] = result_full
|
||||
|
||||
@@ -435,6 +435,7 @@ class ArtifactGeneratorTool(Tool):
|
||||
self.workflow_run_id: Optional[str] = self.config.get("workflow_run_id")
|
||||
self.message_id: Optional[str] = self.config.get("message_id")
|
||||
self._last_artifact_id: Optional[str] = None
|
||||
self._last_filename: Optional[str] = None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Tool ABC
|
||||
@@ -536,12 +537,19 @@ class ArtifactGeneratorTool(Tool):
|
||||
"""Return the produced artifact id so the UI artifact rail lights up."""
|
||||
return self._last_artifact_id
|
||||
|
||||
def get_artifacts(self, action_name: str, **kwargs: Any) -> List[Dict[str, Any]]:
|
||||
"""Return the produced artifact with its filename, for UI labelling."""
|
||||
if not self._last_artifact_id:
|
||||
return []
|
||||
return [{"id": self._last_artifact_id, "filename": self._last_filename}]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Dispatch
|
||||
# ------------------------------------------------------------------
|
||||
def execute_action(self, action_name: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
"""Dispatch a create/edit/rewrite action."""
|
||||
self._last_artifact_id = None
|
||||
self._last_filename = None
|
||||
if not self.user_id:
|
||||
return {"status": "error", "error": "artifact_generator requires a valid user_id."}
|
||||
if self.conversation_id is None and self.workflow_run_id is None:
|
||||
@@ -595,6 +603,7 @@ class ArtifactGeneratorTool(Tool):
|
||||
if ref is None:
|
||||
return {"status": "error", "error": "failed to persist artifact."}
|
||||
self._last_artifact_id = ref["artifact_id"]
|
||||
self._last_filename = ref.get("filename")
|
||||
return {"status": "ok", **ref}
|
||||
|
||||
def _edit(self, **kwargs: Any) -> Dict[str, Any]:
|
||||
@@ -661,6 +670,7 @@ class ArtifactGeneratorTool(Tool):
|
||||
if ref is None:
|
||||
return {"status": "error", "error": "failed to persist artifact version."}
|
||||
self._last_artifact_id = ref["artifact_id"]
|
||||
self._last_filename = ref.get("filename")
|
||||
return {"status": "ok", **ref}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@@ -73,6 +73,7 @@ class CodeExecutorTool(Tool):
|
||||
# Static, deployment-level approval gate (mirrors the action metadata flag).
|
||||
self._require_approval: bool = bool(self.config.get("require_approval", False))
|
||||
self._last_artifact_id: Optional[str] = None
|
||||
self._last_artifacts: List[Dict[str, Any]] = []
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Tool ABC
|
||||
@@ -181,6 +182,15 @@ class CodeExecutorTool(Tool):
|
||||
"""Return the primary produced artifact id so the UI artifact rail lights up."""
|
||||
return self._last_artifact_id
|
||||
|
||||
def get_artifacts(self, action_name: str, **kwargs: Any) -> List[Dict[str, Any]]:
|
||||
"""Return every artifact this call produced, with display names.
|
||||
|
||||
A single ``run_code`` can write several files. Reporting only the first
|
||||
left the others reachable by API but invisible in the UI, and gave the
|
||||
one button the tool's name rather than the file's.
|
||||
"""
|
||||
return list(self._last_artifacts)
|
||||
|
||||
def preview_decision(self, action_name: str, params: dict) -> Tuple[bool, bool]:
|
||||
"""Return ``(requires_approval, denylist_forced)`` for the approval gate; never denylist-forced here."""
|
||||
if action_name != "run_code":
|
||||
@@ -195,6 +205,7 @@ class CodeExecutorTool(Tool):
|
||||
if action_name != "run_code":
|
||||
return {"status": "error", "error": f"unknown action: {action_name}"}
|
||||
self._last_artifact_id = None
|
||||
self._last_artifacts = []
|
||||
return self._run_code(**kwargs)
|
||||
|
||||
def _run_code(self, **kwargs: Any) -> Dict[str, Any]:
|
||||
@@ -404,6 +415,11 @@ class CodeExecutorTool(Tool):
|
||||
)
|
||||
if captured:
|
||||
self._last_artifact_id = captured[0]["artifact_id"]
|
||||
self._last_artifacts = [
|
||||
{"id": a["artifact_id"], "filename": a.get("filename")}
|
||||
for a in captured
|
||||
if a.get("artifact_id")
|
||||
]
|
||||
return captured
|
||||
|
||||
def _shape_payload(
|
||||
|
||||
Reference in new issue
Block a user