mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
Close 3 integration gaps between the ported Sandbox system and Agent V2: 1. Fix _invoke_tool_in_sandbox to use SandboxBashSession context manager API correctly (keyword args, bash_tool, ToolReference), with graceful fallback to direct invocation when DifyCli binary is unavailable. 2. Inject sandbox into run_context via _resolve_sandbox_context() in WorkflowBasedAppRunner — automatically creates a sandbox when a tenant has an active sandbox provider configured. 3. Register SandboxLayer in both advanced_chat and workflow app runners for proper sandbox lifecycle cleanup on graph end. Also: make SkillInitializer non-fatal when no skill bundle exists, add node_id to ExecutionContext for sandbox session scoping. Made-with: Cursor
174 lines
4.3 KiB
Python
174 lines
4.3 KiB
Python
import uuid
|
|
from collections.abc import Mapping
|
|
from enum import StrEnum
|
|
from typing import Any, Union
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolProviderType
|
|
|
|
|
|
class AgentToolEntity(BaseModel):
|
|
"""
|
|
Agent Tool Entity.
|
|
"""
|
|
|
|
provider_type: ToolProviderType
|
|
provider_id: str
|
|
tool_name: str
|
|
tool_parameters: dict[str, Any] = Field(default_factory=dict)
|
|
plugin_unique_identifier: str | None = None
|
|
credential_id: str | None = None
|
|
|
|
|
|
class AgentPromptEntity(BaseModel):
|
|
"""
|
|
Agent Prompt Entity.
|
|
"""
|
|
|
|
first_prompt: str
|
|
next_iteration: str
|
|
|
|
|
|
class AgentScratchpadUnit(BaseModel):
|
|
"""
|
|
Agent First Prompt Entity.
|
|
"""
|
|
|
|
class Action(BaseModel):
|
|
"""
|
|
Action Entity.
|
|
"""
|
|
|
|
action_name: str
|
|
action_input: Union[dict, str]
|
|
|
|
def to_dict(self):
|
|
"""
|
|
Convert to dictionary.
|
|
"""
|
|
return {
|
|
"action": self.action_name,
|
|
"action_input": self.action_input,
|
|
}
|
|
|
|
agent_response: str | None = None
|
|
thought: str | None = None
|
|
action_str: str | None = None
|
|
observation: str | None = None
|
|
action: Action | None = None
|
|
|
|
def is_final(self) -> bool:
|
|
"""
|
|
Check if the scratchpad unit is final.
|
|
"""
|
|
return self.action is None or (
|
|
"final" in self.action.action_name.lower() and "answer" in self.action.action_name.lower()
|
|
)
|
|
|
|
|
|
class AgentEntity(BaseModel):
|
|
"""
|
|
Agent Entity.
|
|
"""
|
|
|
|
class Strategy(StrEnum):
|
|
"""
|
|
Agent Strategy.
|
|
"""
|
|
|
|
CHAIN_OF_THOUGHT = "chain-of-thought"
|
|
FUNCTION_CALLING = "function-calling"
|
|
|
|
provider: str
|
|
model: str
|
|
strategy: Strategy
|
|
prompt: AgentPromptEntity | None = None
|
|
tools: list[AgentToolEntity] | None = None
|
|
max_iteration: int = 10
|
|
|
|
|
|
class AgentInvokeMessage(ToolInvokeMessage):
|
|
"""
|
|
Agent Invoke Message.
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
class ExecutionContext(BaseModel):
|
|
"""Execution context containing trace and audit information.
|
|
|
|
Carries IDs and metadata needed for tracing, auditing, and correlation
|
|
but not part of the core business logic.
|
|
"""
|
|
|
|
user_id: str | None = None
|
|
app_id: str | None = None
|
|
conversation_id: str | None = None
|
|
message_id: str | None = None
|
|
tenant_id: str | None = None
|
|
node_id: str | None = None
|
|
|
|
@classmethod
|
|
def create_minimal(cls, user_id: str | None = None) -> "ExecutionContext":
|
|
return cls(user_id=user_id)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"user_id": self.user_id,
|
|
"app_id": self.app_id,
|
|
"conversation_id": self.conversation_id,
|
|
"message_id": self.message_id,
|
|
"tenant_id": self.tenant_id,
|
|
}
|
|
|
|
def with_updates(self, **kwargs) -> "ExecutionContext":
|
|
data = self.to_dict()
|
|
data.update(kwargs)
|
|
return ExecutionContext(**{k: v for k, v in data.items() if k in ExecutionContext.model_fields})
|
|
|
|
|
|
class AgentLog(BaseModel):
|
|
"""Structured log entry for agent execution tracing."""
|
|
|
|
class LogType(StrEnum):
|
|
ROUND = "round"
|
|
THOUGHT = "thought"
|
|
TOOL_CALL = "tool_call"
|
|
|
|
class LogMetadata(StrEnum):
|
|
STARTED_AT = "started_at"
|
|
FINISHED_AT = "finished_at"
|
|
ELAPSED_TIME = "elapsed_time"
|
|
TOTAL_PRICE = "total_price"
|
|
TOTAL_TOKENS = "total_tokens"
|
|
PROVIDER = "provider"
|
|
CURRENCY = "currency"
|
|
LLM_USAGE = "llm_usage"
|
|
ICON = "icon"
|
|
ICON_DARK = "icon_dark"
|
|
|
|
class LogStatus(StrEnum):
|
|
START = "start"
|
|
ERROR = "error"
|
|
SUCCESS = "success"
|
|
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
label: str = Field(...)
|
|
log_type: LogType = Field(...)
|
|
parent_id: str | None = Field(default=None)
|
|
error: str | None = Field(default=None)
|
|
status: LogStatus = Field(...)
|
|
data: Mapping[str, Any] = Field(...)
|
|
metadata: Mapping[LogMetadata, Any] = Field(default={})
|
|
|
|
|
|
class AgentResult(BaseModel):
|
|
"""Agent execution result."""
|
|
|
|
text: str = Field(default="")
|
|
files: list[Any] = Field(default_factory=list)
|
|
usage: Any | None = Field(default=None)
|
|
finish_reason: str | None = Field(default=None)
|