feat(api): Agent App type S1 — AppMode.AGENT + create flow + binding (#36829)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
zyssyz123
2026-06-02 03:50:10 +00:00
committed by GitHub
co-authored by Claude Opus 4.7 autofix-ci[bot]
parent e530e84772
commit e35d23c3cb
62 changed files with 3702 additions and 347 deletions
+25
View File
@@ -366,6 +366,10 @@ class AppMode(StrEnum):
CHAT = "chat"
ADVANCED_CHAT = "advanced-chat"
AGENT_CHAT = "agent-chat"
# New Agent App type backed by the Dify Agent runtime (distinct from the
# legacy ``agent-chat`` ReAct app). The app is bound 1:1 to a roster Agent
# via ``Agent.app_id``; its configuration lives in the Agent Soul snapshot.
AGENT = "agent"
CHANNEL = "channel"
RAG_PIPELINE = "rag-pipeline"
@@ -458,6 +462,27 @@ class App(Base):
return None
@property
def bound_agent_id(self) -> str | None:
"""For an Agent App (mode=agent), the roster Agent it is backed by.
Resolved via ``Agent.app_id`` so the console can open the Composer in
roster-detail mode from the app id. ``None`` for non-agent apps.
"""
if self.mode != AppMode.AGENT:
return None
from .agent import Agent, AgentScope, AgentSource, AgentStatus
agent = db.session.scalar(
select(Agent).where(
Agent.app_id == self.id,
Agent.scope == AgentScope.ROSTER,
Agent.source == AgentSource.AGENT_APP,
Agent.status == AgentStatus.ACTIVE,
)
)
return agent.id if agent else None
@property
def api_base_url(self) -> str:
base = dify_config.SERVICE_API_URL or request.host_url.rstrip("/")