agent_service.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import threading
  2. from typing import Optional
  3. import pytz
  4. from flask_login import current_user # type: ignore
  5. import contexts
  6. from core.app.app_config.easy_ui_based_app.agent.manager import AgentConfigManager
  7. from core.plugin.manager.agent import PluginAgentManager
  8. from core.plugin.manager.exc import PluginDaemonClientSideError
  9. from core.tools.tool_manager import ToolManager
  10. from extensions.ext_database import db
  11. from models.account import Account
  12. from models.model import App, Conversation, EndUser, Message, MessageAgentThought
  13. class AgentService:
  14. @classmethod
  15. def get_agent_logs(cls, app_model: App, conversation_id: str, message_id: str) -> dict:
  16. """
  17. Service to get agent logs
  18. """
  19. contexts.plugin_tool_providers.set({})
  20. contexts.plugin_tool_providers_lock.set(threading.Lock())
  21. conversation: Conversation | None = (
  22. db.session.query(Conversation)
  23. .filter(
  24. Conversation.id == conversation_id,
  25. Conversation.app_id == app_model.id,
  26. )
  27. .first()
  28. )
  29. if not conversation:
  30. raise ValueError(f"Conversation not found: {conversation_id}")
  31. message: Optional[Message] = (
  32. db.session.query(Message)
  33. .filter(
  34. Message.id == message_id,
  35. Message.conversation_id == conversation_id,
  36. )
  37. .first()
  38. )
  39. if not message:
  40. raise ValueError(f"Message not found: {message_id}")
  41. agent_thoughts: list[MessageAgentThought] = message.agent_thoughts
  42. if conversation.from_end_user_id:
  43. # only select name field
  44. executor = (
  45. db.session.query(EndUser, EndUser.name).filter(EndUser.id == conversation.from_end_user_id).first()
  46. )
  47. else:
  48. executor = (
  49. db.session.query(Account, Account.name).filter(Account.id == conversation.from_account_id).first()
  50. )
  51. if executor:
  52. executor = executor.name
  53. else:
  54. executor = "Unknown"
  55. timezone = pytz.timezone(current_user.timezone)
  56. app_model_config = app_model.app_model_config
  57. if not app_model_config:
  58. raise ValueError("App model config not found")
  59. result = {
  60. "meta": {
  61. "status": "success",
  62. "executor": executor,
  63. "start_time": message.created_at.astimezone(timezone).isoformat(),
  64. "elapsed_time": message.provider_response_latency,
  65. "total_tokens": message.answer_tokens + message.message_tokens,
  66. "agent_mode": app_model_config.agent_mode_dict.get("strategy", "react"),
  67. "iterations": len(agent_thoughts),
  68. },
  69. "iterations": [],
  70. "files": message.message_files,
  71. }
  72. agent_config = AgentConfigManager.convert(app_model_config.to_dict())
  73. if not agent_config:
  74. raise ValueError("Agent config not found")
  75. agent_tools = agent_config.tools or []
  76. def find_agent_tool(tool_name: str):
  77. for agent_tool in agent_tools:
  78. if agent_tool.tool_name == tool_name:
  79. return agent_tool
  80. for agent_thought in agent_thoughts:
  81. tools = agent_thought.tools
  82. tool_labels = agent_thought.tool_labels
  83. tool_meta = agent_thought.tool_meta
  84. tool_inputs = agent_thought.tool_inputs_dict
  85. tool_outputs = agent_thought.tool_outputs_dict or {}
  86. tool_calls = []
  87. for tool in tools:
  88. tool_name = tool
  89. tool_label = tool_labels.get(tool_name, tool_name)
  90. tool_input = tool_inputs.get(tool_name, {})
  91. tool_output = tool_outputs.get(tool_name, {})
  92. tool_meta_data = tool_meta.get(tool_name, {})
  93. tool_config = tool_meta_data.get("tool_config", {})
  94. if tool_config.get("tool_provider_type", "") != "dataset-retrieval":
  95. tool_icon = ToolManager.get_tool_icon(
  96. tenant_id=app_model.tenant_id,
  97. provider_type=tool_config.get("tool_provider_type", ""),
  98. provider_id=tool_config.get("tool_provider", ""),
  99. )
  100. if not tool_icon:
  101. tool_entity = find_agent_tool(tool_name)
  102. if tool_entity:
  103. tool_icon = ToolManager.get_tool_icon(
  104. tenant_id=app_model.tenant_id,
  105. provider_type=tool_entity.provider_type,
  106. provider_id=tool_entity.provider_id,
  107. )
  108. else:
  109. tool_icon = ""
  110. tool_calls.append(
  111. {
  112. "status": "success" if not tool_meta_data.get("error") else "error",
  113. "error": tool_meta_data.get("error"),
  114. "time_cost": tool_meta_data.get("time_cost", 0),
  115. "tool_name": tool_name,
  116. "tool_label": tool_label,
  117. "tool_input": tool_input,
  118. "tool_output": tool_output,
  119. "tool_parameters": tool_meta_data.get("tool_parameters", {}),
  120. "tool_icon": tool_icon,
  121. }
  122. )
  123. result["iterations"].append(
  124. {
  125. "tokens": agent_thought.tokens,
  126. "tool_calls": tool_calls,
  127. "tool_raw": {
  128. "inputs": agent_thought.tool_input,
  129. "outputs": agent_thought.observation,
  130. },
  131. "thought": agent_thought.thought,
  132. "created_at": agent_thought.created_at.isoformat(),
  133. "files": agent_thought.files,
  134. }
  135. )
  136. return result
  137. @classmethod
  138. def list_agent_providers(cls, user_id: str, tenant_id: str):
  139. """
  140. List agent providers
  141. """
  142. manager = PluginAgentManager()
  143. return manager.fetch_agent_strategy_providers(tenant_id)
  144. @classmethod
  145. def get_agent_provider(cls, user_id: str, tenant_id: str, provider_name: str):
  146. """
  147. Get agent provider
  148. """
  149. manager = PluginAgentManager()
  150. try:
  151. return manager.fetch_agent_strategy_provider(tenant_id, provider_name)
  152. except PluginDaemonClientSideError as e:
  153. raise ValueError(str(e)) from e