mirror of
https://github.com/langgenius/dify.git
synced 2026-05-31 06:06:20 +08:00
Compare commits
5 Commits
deploy/ent
...
chore/keep
| Author | SHA1 | Date | |
|---|---|---|---|
| 52cdaa20d7 | |||
| ac4e117a2a | |||
| 418ee7398e | |||
| 78f40c0d25 | |||
| 2cc567c6a3 |
@ -1,9 +1,17 @@
|
||||
from flask_restx import Resource
|
||||
|
||||
from controllers.common.schema import register_schema_models
|
||||
from controllers.common.schema import register_response_schema_models, register_schema_models
|
||||
from controllers.console import console_ns
|
||||
from controllers.console.app.wraps import get_app_model
|
||||
from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required
|
||||
from fields.agent_fields import (
|
||||
AgentAppComposerResponse,
|
||||
AgentComposerCandidatesResponse,
|
||||
AgentComposerImpactResponse,
|
||||
AgentComposerValidateResponse,
|
||||
WorkflowAgentComposerResponse,
|
||||
)
|
||||
from libs.helper import dump_response
|
||||
from libs.login import current_account_with_tenant, login_required
|
||||
from models.model import App, AppMode
|
||||
from services.agent.composer_service import AgentComposerService
|
||||
@ -11,23 +19,40 @@ from services.agent.composer_validator import ComposerConfigValidator
|
||||
from services.entities.agent_entities import ComposerSavePayload
|
||||
|
||||
register_schema_models(console_ns, ComposerSavePayload)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
AgentAppComposerResponse,
|
||||
AgentComposerCandidatesResponse,
|
||||
AgentComposerImpactResponse,
|
||||
AgentComposerValidateResponse,
|
||||
WorkflowAgentComposerResponse,
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/agent-composer")
|
||||
class WorkflowAgentComposerApi(Resource):
|
||||
@console_ns.response(
|
||||
200, "Workflow agent composer state", console_ns.models[WorkflowAgentComposerResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@get_app_model(mode=[AppMode.WORKFLOW, AppMode.ADVANCED_CHAT])
|
||||
def get(self, app_model: App, node_id: str):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
return AgentComposerService.load_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
return dump_response(
|
||||
WorkflowAgentComposerResponse,
|
||||
AgentComposerService.load_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
),
|
||||
)
|
||||
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(
|
||||
200, "Workflow agent composer saved", console_ns.models[WorkflowAgentComposerResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -36,18 +61,24 @@ class WorkflowAgentComposerApi(Resource):
|
||||
def put(self, app_model: App, node_id: str):
|
||||
account, tenant_id = current_account_with_tenant()
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
return AgentComposerService.save_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
return dump_response(
|
||||
WorkflowAgentComposerResponse,
|
||||
AgentComposerService.save_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/agent-composer/validate")
|
||||
class WorkflowAgentComposerValidateApi(Resource):
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(
|
||||
200, "Workflow agent composer validation result", console_ns.models[AgentComposerValidateResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -55,21 +86,29 @@ class WorkflowAgentComposerValidateApi(Resource):
|
||||
def post(self, app_model: App, node_id: str):
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
ComposerConfigValidator.validate_save_payload(payload)
|
||||
return {"result": "success", "errors": []}
|
||||
return dump_response(AgentComposerValidateResponse, {"result": "success", "errors": []})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/agent-composer/candidates")
|
||||
class WorkflowAgentComposerCandidatesApi(Resource):
|
||||
@console_ns.response(
|
||||
200, "Workflow agent composer candidates", console_ns.models[AgentComposerCandidatesResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@get_app_model(mode=[AppMode.WORKFLOW, AppMode.ADVANCED_CHAT])
|
||||
def get(self, app_model: App, node_id: str):
|
||||
return AgentComposerService.get_workflow_candidates(app_id=app_model.id)
|
||||
return dump_response(
|
||||
AgentComposerCandidatesResponse,
|
||||
AgentComposerService.get_workflow_candidates(app_id=app_model.id),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/agent-composer/impact")
|
||||
class WorkflowAgentComposerImpactApi(Resource):
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(200, "Workflow agent composer impact", console_ns.models[AgentComposerImpactResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -79,13 +118,21 @@ class WorkflowAgentComposerImpactApi(Resource):
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
current_snapshot_id = payload.binding.current_snapshot_id if payload.binding else None
|
||||
if not current_snapshot_id:
|
||||
return {"current_snapshot_id": None, "workflow_node_count": 0, "bindings": []}
|
||||
return AgentComposerService.calculate_impact(tenant_id=tenant_id, current_snapshot_id=current_snapshot_id)
|
||||
return dump_response(
|
||||
AgentComposerImpactResponse, {"current_snapshot_id": None, "workflow_node_count": 0, "bindings": []}
|
||||
)
|
||||
return dump_response(
|
||||
AgentComposerImpactResponse,
|
||||
AgentComposerService.calculate_impact(tenant_id=tenant_id, current_snapshot_id=current_snapshot_id),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/agent-composer/save-to-roster")
|
||||
class WorkflowAgentComposerSaveToRosterApi(Resource):
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(
|
||||
200, "Workflow agent composer saved to roster", console_ns.models[WorkflowAgentComposerResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -94,26 +141,34 @@ class WorkflowAgentComposerSaveToRosterApi(Resource):
|
||||
def post(self, app_model: App, node_id: str):
|
||||
account, tenant_id = current_account_with_tenant()
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
return AgentComposerService.save_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
return dump_response(
|
||||
WorkflowAgentComposerResponse,
|
||||
AgentComposerService.save_workflow_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
node_id=node_id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/agent-composer")
|
||||
class AgentAppComposerApi(Resource):
|
||||
@console_ns.response(200, "Agent app composer state", console_ns.models[AgentAppComposerResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@get_app_model()
|
||||
def get(self, app_model: App):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
return AgentComposerService.load_agent_app_composer(tenant_id=tenant_id, app_id=app_model.id)
|
||||
return dump_response(
|
||||
AgentAppComposerResponse,
|
||||
AgentComposerService.load_agent_app_composer(tenant_id=tenant_id, app_id=app_model.id),
|
||||
)
|
||||
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(200, "Agent app composer saved", console_ns.models[AgentAppComposerResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -122,17 +177,23 @@ class AgentAppComposerApi(Resource):
|
||||
def put(self, app_model: App):
|
||||
account, tenant_id = current_account_with_tenant()
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
return AgentComposerService.save_agent_app_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
return dump_response(
|
||||
AgentAppComposerResponse,
|
||||
AgentComposerService.save_agent_app_composer(
|
||||
tenant_id=tenant_id,
|
||||
app_id=app_model.id,
|
||||
account_id=account.id,
|
||||
payload=payload,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/agent-composer/validate")
|
||||
class AgentAppComposerValidateApi(Resource):
|
||||
@console_ns.expect(console_ns.models[ComposerSavePayload.__name__])
|
||||
@console_ns.response(
|
||||
200, "Agent app composer validation result", console_ns.models[AgentComposerValidateResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -140,14 +201,20 @@ class AgentAppComposerValidateApi(Resource):
|
||||
def post(self, app_model: App):
|
||||
payload = ComposerSavePayload.model_validate(console_ns.payload or {})
|
||||
ComposerConfigValidator.validate_save_payload(payload)
|
||||
return {"result": "success", "errors": []}
|
||||
return dump_response(AgentComposerValidateResponse, {"result": "success", "errors": []})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/agent-composer/candidates")
|
||||
class AgentAppComposerCandidatesApi(Resource):
|
||||
@console_ns.response(
|
||||
200, "Agent app composer candidates", console_ns.models[AgentComposerCandidatesResponse.__name__]
|
||||
)
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@get_app_model()
|
||||
def get(self, app_model: App):
|
||||
return AgentComposerService.get_agent_app_candidates(app_id=app_model.id)
|
||||
return dump_response(
|
||||
AgentComposerCandidatesResponse,
|
||||
AgentComposerService.get_agent_app_candidates(app_id=app_model.id),
|
||||
)
|
||||
|
||||
@ -4,10 +4,18 @@ from flask import request
|
||||
from flask_restx import Resource
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from controllers.common.schema import register_schema_models
|
||||
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
|
||||
from controllers.console import console_ns
|
||||
from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required
|
||||
from extensions.ext_database import db
|
||||
from fields.agent_fields import (
|
||||
AgentConfigSnapshotDetailResponse,
|
||||
AgentConfigSnapshotListResponse,
|
||||
AgentInviteOptionsResponse,
|
||||
AgentRosterListResponse,
|
||||
AgentRosterResponse,
|
||||
)
|
||||
from libs.helper import dump_response
|
||||
from libs.login import current_account_with_tenant, login_required
|
||||
from services.agent.roster_service import AgentRosterService
|
||||
from services.entities.agent_entities import RosterAgentCreatePayload, RosterAgentUpdatePayload, RosterListQuery
|
||||
@ -29,6 +37,14 @@ register_schema_models(
|
||||
RosterAgentUpdatePayload,
|
||||
RosterListQuery,
|
||||
)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
AgentConfigSnapshotDetailResponse,
|
||||
AgentConfigSnapshotListResponse,
|
||||
AgentInviteOptionsResponse,
|
||||
AgentRosterListResponse,
|
||||
AgentRosterResponse,
|
||||
)
|
||||
|
||||
|
||||
def _agent_roster_service() -> AgentRosterService:
|
||||
@ -37,17 +53,23 @@ def _agent_roster_service() -> AgentRosterService:
|
||||
|
||||
@console_ns.route("/agents")
|
||||
class AgentRosterListApi(Resource):
|
||||
@console_ns.doc(params=query_params_from_model(RosterListQuery))
|
||||
@console_ns.response(200, "Agent roster list", console_ns.models[AgentRosterListResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def get(self):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
query = RosterListQuery.model_validate(request.args.to_dict(flat=True))
|
||||
return _agent_roster_service().list_roster_agents(
|
||||
tenant_id=tenant_id, page=query.page, limit=query.limit, keyword=query.keyword
|
||||
return dump_response(
|
||||
AgentRosterListResponse,
|
||||
_agent_roster_service().list_roster_agents(
|
||||
tenant_id=tenant_id, page=query.page, limit=query.limit, keyword=query.keyword
|
||||
),
|
||||
)
|
||||
|
||||
@console_ns.expect(console_ns.models[RosterAgentCreatePayload.__name__])
|
||||
@console_ns.response(201, "Agent created", console_ns.models[AgentRosterResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -57,36 +79,49 @@ class AgentRosterListApi(Resource):
|
||||
payload = RosterAgentCreatePayload.model_validate(console_ns.payload or {})
|
||||
service = _agent_roster_service()
|
||||
agent = service.create_roster_agent(tenant_id=tenant_id, account_id=account.id, payload=payload)
|
||||
return service.get_roster_agent_detail(tenant_id=tenant_id, agent_id=agent.id), 201
|
||||
return dump_response(
|
||||
AgentRosterResponse,
|
||||
service.get_roster_agent_detail(tenant_id=tenant_id, agent_id=agent.id),
|
||||
), 201
|
||||
|
||||
|
||||
@console_ns.route("/agents/invite-options")
|
||||
class AgentInviteOptionsApi(Resource):
|
||||
@console_ns.doc(params=query_params_from_model(AgentInviteOptionsQuery))
|
||||
@console_ns.response(200, "Agent invite options", console_ns.models[AgentInviteOptionsResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def get(self):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
query = AgentInviteOptionsQuery.model_validate(request.args.to_dict(flat=True))
|
||||
return _agent_roster_service().list_invite_options(
|
||||
tenant_id=tenant_id,
|
||||
page=query.page,
|
||||
limit=query.limit,
|
||||
keyword=query.keyword,
|
||||
app_id=query.app_id,
|
||||
return dump_response(
|
||||
AgentInviteOptionsResponse,
|
||||
_agent_roster_service().list_invite_options(
|
||||
tenant_id=tenant_id,
|
||||
page=query.page,
|
||||
limit=query.limit,
|
||||
keyword=query.keyword,
|
||||
app_id=query.app_id,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/agents/<uuid:agent_id>")
|
||||
class AgentRosterDetailApi(Resource):
|
||||
@console_ns.response(200, "Agent detail", console_ns.models[AgentRosterResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def get(self, agent_id: UUID):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
return _agent_roster_service().get_roster_agent_detail(tenant_id=tenant_id, agent_id=str(agent_id))
|
||||
return dump_response(
|
||||
AgentRosterResponse,
|
||||
_agent_roster_service().get_roster_agent_detail(tenant_id=tenant_id, agent_id=str(agent_id)),
|
||||
)
|
||||
|
||||
@console_ns.expect(console_ns.models[RosterAgentUpdatePayload.__name__])
|
||||
@console_ns.response(200, "Agent updated", console_ns.models[AgentRosterResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -94,10 +129,14 @@ class AgentRosterDetailApi(Resource):
|
||||
def patch(self, agent_id: UUID):
|
||||
account, tenant_id = current_account_with_tenant()
|
||||
payload = RosterAgentUpdatePayload.model_validate(console_ns.payload or {})
|
||||
return _agent_roster_service().update_roster_agent(
|
||||
tenant_id=tenant_id, agent_id=str(agent_id), account_id=account.id, payload=payload
|
||||
return dump_response(
|
||||
AgentRosterResponse,
|
||||
_agent_roster_service().update_roster_agent(
|
||||
tenant_id=tenant_id, agent_id=str(agent_id), account_id=account.id, payload=payload
|
||||
),
|
||||
)
|
||||
|
||||
@console_ns.response(204, "Agent archived")
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -110,23 +149,31 @@ class AgentRosterDetailApi(Resource):
|
||||
|
||||
@console_ns.route("/agents/<uuid:agent_id>/versions")
|
||||
class AgentRosterVersionsApi(Resource):
|
||||
@console_ns.response(200, "Agent versions", console_ns.models[AgentConfigSnapshotListResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def get(self, agent_id: UUID):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
return {"data": _agent_roster_service().list_agent_versions(tenant_id=tenant_id, agent_id=str(agent_id))}
|
||||
return dump_response(
|
||||
AgentConfigSnapshotListResponse,
|
||||
{"data": _agent_roster_service().list_agent_versions(tenant_id=tenant_id, agent_id=str(agent_id))},
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/agents/<uuid:agent_id>/versions/<uuid:version_id>")
|
||||
class AgentRosterVersionDetailApi(Resource):
|
||||
@console_ns.response(200, "Agent version detail", console_ns.models[AgentConfigSnapshotDetailResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def get(self, agent_id: UUID, version_id: UUID):
|
||||
_, tenant_id = current_account_with_tenant()
|
||||
return _agent_roster_service().get_agent_version_detail(
|
||||
tenant_id=tenant_id,
|
||||
agent_id=str(agent_id),
|
||||
version_id=str(version_id),
|
||||
return dump_response(
|
||||
AgentConfigSnapshotDetailResponse,
|
||||
_agent_roster_service().get_agent_version_detail(
|
||||
tenant_id=tenant_id,
|
||||
agent_id=str(agent_id),
|
||||
version_id=str(version_id),
|
||||
),
|
||||
)
|
||||
|
||||
192
api/fields/agent_fields.py
Normal file
192
api/fields/agent_fields.py
Normal file
@ -0,0 +1,192 @@
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from fields.base import ResponseModel
|
||||
from models.agent import (
|
||||
AgentConfigRevisionOperation,
|
||||
AgentIconType,
|
||||
AgentKind,
|
||||
AgentScope,
|
||||
AgentSource,
|
||||
AgentStatus,
|
||||
WorkflowAgentBindingType,
|
||||
)
|
||||
from models.agent_config_entities import (
|
||||
AgentSoulConfig,
|
||||
DeclaredOutputConfig,
|
||||
DeclaredOutputType,
|
||||
WorkflowNodeJobConfig,
|
||||
)
|
||||
from services.entities.agent_entities import (
|
||||
ComposerCandidateCapabilities,
|
||||
ComposerSaveStrategy,
|
||||
ComposerVariant,
|
||||
)
|
||||
|
||||
|
||||
class AgentConfigSnapshotSummaryResponse(ResponseModel):
|
||||
id: str
|
||||
agent_id: str | None = None
|
||||
version: int
|
||||
summary: str | None = None
|
||||
version_note: str | None = None
|
||||
created_by: str | None = None
|
||||
created_at: str | None = None
|
||||
|
||||
|
||||
class AgentRosterResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
icon_type: AgentIconType | None = None
|
||||
icon: str | None = None
|
||||
icon_background: str | None = None
|
||||
agent_kind: AgentKind
|
||||
scope: AgentScope
|
||||
source: AgentSource
|
||||
app_id: str | None = None
|
||||
workflow_id: str | None = None
|
||||
workflow_node_id: str | None = None
|
||||
active_config_snapshot_id: str | None = None
|
||||
active_config_snapshot: AgentConfigSnapshotSummaryResponse | None = None
|
||||
status: AgentStatus
|
||||
created_by: str | None = None
|
||||
updated_by: str | None = None
|
||||
archived_by: str | None = None
|
||||
archived_at: str | None = None
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
class AgentInviteOptionResponse(AgentRosterResponse):
|
||||
is_in_current_workflow: bool = False
|
||||
in_current_workflow_count: int = 0
|
||||
existing_node_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentRosterListResponse(ResponseModel):
|
||||
data: list[AgentRosterResponse]
|
||||
page: int
|
||||
limit: int
|
||||
total: int
|
||||
has_more: bool
|
||||
|
||||
|
||||
class AgentInviteOptionsResponse(ResponseModel):
|
||||
data: list[AgentInviteOptionResponse]
|
||||
page: int
|
||||
limit: int
|
||||
total: int
|
||||
has_more: bool
|
||||
|
||||
|
||||
class AgentConfigRevisionResponse(ResponseModel):
|
||||
id: str
|
||||
previous_snapshot_id: str | None = None
|
||||
current_snapshot_id: str
|
||||
revision: int
|
||||
operation: AgentConfigRevisionOperation
|
||||
summary: str | None = None
|
||||
version_note: str | None = None
|
||||
created_by: str | None = None
|
||||
created_at: str | None = None
|
||||
|
||||
|
||||
class AgentConfigSnapshotDetailResponse(AgentConfigSnapshotSummaryResponse):
|
||||
config_snapshot: AgentSoulConfig
|
||||
revisions: list[AgentConfigRevisionResponse] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentConfigSnapshotListResponse(ResponseModel):
|
||||
data: list[AgentConfigSnapshotSummaryResponse]
|
||||
|
||||
|
||||
class AgentComposerAgentResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
scope: AgentScope
|
||||
status: AgentStatus
|
||||
active_config_snapshot_id: str | None = None
|
||||
|
||||
|
||||
class AgentComposerBindingResponse(ResponseModel):
|
||||
id: str
|
||||
binding_type: WorkflowAgentBindingType
|
||||
agent_id: str | None = None
|
||||
current_snapshot_id: str | None = None
|
||||
workflow_id: str
|
||||
node_id: str
|
||||
|
||||
|
||||
class AgentComposerSoulLockResponse(ResponseModel):
|
||||
locked: bool
|
||||
can_unlock: bool = False
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
class AgentComposerImpactBindingResponse(ResponseModel):
|
||||
app_id: str
|
||||
workflow_id: str
|
||||
node_id: str
|
||||
|
||||
|
||||
class AgentComposerImpactResponse(ResponseModel):
|
||||
current_snapshot_id: str | None = None
|
||||
workflow_node_count: int
|
||||
bindings: list[AgentComposerImpactBindingResponse] = Field(default_factory=list)
|
||||
|
||||
|
||||
class WorkflowAgentComposerResponse(ResponseModel):
|
||||
variant: Literal[ComposerVariant.WORKFLOW]
|
||||
agent: AgentComposerAgentResponse | None = None
|
||||
active_config_snapshot: AgentConfigSnapshotSummaryResponse | None = None
|
||||
binding: AgentComposerBindingResponse | None = None
|
||||
soul_lock: AgentComposerSoulLockResponse
|
||||
agent_soul: AgentSoulConfig
|
||||
node_job: WorkflowNodeJobConfig
|
||||
effective_declared_outputs: list[DeclaredOutputConfig] = Field(default_factory=list)
|
||||
save_options: list[ComposerSaveStrategy]
|
||||
impact_summary: AgentComposerImpactResponse | None = None
|
||||
app_id: str | None = None
|
||||
workflow_id: str | None = None
|
||||
node_id: str | None = None
|
||||
|
||||
|
||||
class AgentAppComposerResponse(ResponseModel):
|
||||
variant: Literal[ComposerVariant.AGENT_APP]
|
||||
agent: AgentComposerAgentResponse
|
||||
active_config_snapshot: AgentConfigSnapshotSummaryResponse
|
||||
agent_soul: AgentSoulConfig
|
||||
save_options: list[ComposerSaveStrategy]
|
||||
|
||||
|
||||
class AgentComposerValidateResponse(ResponseModel):
|
||||
result: Literal["success"]
|
||||
errors: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentComposerNodeJobCandidatesResponse(ResponseModel):
|
||||
previous_node_outputs: list[dict[str, Any]] = Field(default_factory=list)
|
||||
declare_output_types: list[DeclaredOutputType] = Field(default_factory=list)
|
||||
human_contacts: list[dict[str, Any]] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentComposerSoulCandidatesResponse(ResponseModel):
|
||||
skills_files: list[dict[str, Any]] = Field(default_factory=list)
|
||||
dify_tools: list[dict[str, Any]] = Field(default_factory=list)
|
||||
cli_tools: list[dict[str, Any]] = Field(default_factory=list)
|
||||
knowledge_datasets: list[dict[str, Any]] = Field(default_factory=list)
|
||||
human_contacts: list[dict[str, Any]] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentComposerCandidatesResponse(ResponseModel):
|
||||
variant: ComposerVariant
|
||||
allowed_node_job_candidates: AgentComposerNodeJobCandidatesResponse = Field(
|
||||
default_factory=AgentComposerNodeJobCandidatesResponse
|
||||
)
|
||||
allowed_soul_candidates: AgentComposerSoulCandidatesResponse = Field(
|
||||
default_factory=AgentComposerSoulCandidatesResponse
|
||||
)
|
||||
capabilities: ComposerCandidateCapabilities = Field(default_factory=ComposerCandidateCapabilities)
|
||||
@ -343,11 +343,19 @@ Check if activation token is valid
|
||||
### /agents
|
||||
|
||||
#### GET
|
||||
##### Parameters
|
||||
|
||||
| Name | Located in | Description | Required | Schema |
|
||||
| ---- | ---------- | ----------- | -------- | ------ |
|
||||
| keyword | query | | No | string |
|
||||
| limit | query | | No | integer |
|
||||
| page | query | | No | integer |
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent roster list | [AgentRosterListResponse](#agentrosterlistresponse) |
|
||||
|
||||
#### POST
|
||||
##### Parameters
|
||||
@ -358,18 +366,27 @@ Check if activation token is valid
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 201 | Agent created | [AgentRosterResponse](#agentrosterresponse) |
|
||||
|
||||
### /agents/invite-options
|
||||
|
||||
#### GET
|
||||
##### Parameters
|
||||
|
||||
| Name | Located in | Description | Required | Schema |
|
||||
| ---- | ---------- | ----------- | -------- | ------ |
|
||||
| app_id | query | Workflow app id for in-current-workflow markers | No | string |
|
||||
| keyword | query | | No | string |
|
||||
| limit | query | | No | integer |
|
||||
| page | query | | No | integer |
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent invite options | [AgentInviteOptionsResponse](#agentinviteoptionsresponse) |
|
||||
|
||||
### /agents/{agent_id}
|
||||
|
||||
@ -384,7 +401,7 @@ Check if activation token is valid
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| 204 | Agent archived |
|
||||
|
||||
#### GET
|
||||
##### Parameters
|
||||
@ -395,9 +412,9 @@ Check if activation token is valid
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent detail | [AgentRosterResponse](#agentrosterresponse) |
|
||||
|
||||
#### PATCH
|
||||
##### Parameters
|
||||
@ -409,9 +426,9 @@ Check if activation token is valid
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent updated | [AgentRosterResponse](#agentrosterresponse) |
|
||||
|
||||
### /agents/{agent_id}/versions
|
||||
|
||||
@ -424,9 +441,9 @@ Check if activation token is valid
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent versions | [AgentConfigSnapshotListResponse](#agentconfigsnapshotlistresponse) |
|
||||
|
||||
### /agents/{agent_id}/versions/{version_id}
|
||||
|
||||
@ -440,9 +457,9 @@ Check if activation token is valid
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent version detail | [AgentConfigSnapshotDetailResponse](#agentconfigsnapshotdetailresponse) |
|
||||
|
||||
### /all-workspaces
|
||||
|
||||
@ -978,9 +995,9 @@ Run draft workflow for advanced chat application
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent app composer state | [AgentAppComposerResponse](#agentappcomposerresponse) |
|
||||
|
||||
#### PUT
|
||||
##### Parameters
|
||||
@ -992,9 +1009,9 @@ Run draft workflow for advanced chat application
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent app composer saved | [AgentAppComposerResponse](#agentappcomposerresponse) |
|
||||
|
||||
### /apps/{app_id}/agent-composer/candidates
|
||||
|
||||
@ -1007,9 +1024,9 @@ Run draft workflow for advanced chat application
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent app composer candidates | [AgentComposerCandidatesResponse](#agentcomposercandidatesresponse) |
|
||||
|
||||
### /apps/{app_id}/agent-composer/validate
|
||||
|
||||
@ -1023,9 +1040,9 @@ Run draft workflow for advanced chat application
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Agent app composer validation result | [AgentComposerValidateResponse](#agentcomposervalidateresponse) |
|
||||
|
||||
### /apps/{app_id}/agent/logs
|
||||
|
||||
@ -3224,9 +3241,9 @@ Run draft workflow loop node
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer state | [WorkflowAgentComposerResponse](#workflowagentcomposerresponse) |
|
||||
|
||||
#### PUT
|
||||
##### Parameters
|
||||
@ -3239,9 +3256,9 @@ Run draft workflow loop node
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer saved | [WorkflowAgentComposerResponse](#workflowagentcomposerresponse) |
|
||||
|
||||
### /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer/candidates
|
||||
|
||||
@ -3255,9 +3272,9 @@ Run draft workflow loop node
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer candidates | [AgentComposerCandidatesResponse](#agentcomposercandidatesresponse) |
|
||||
|
||||
### /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer/impact
|
||||
|
||||
@ -3268,12 +3285,13 @@ Run draft workflow loop node
|
||||
| ---- | ---------- | ----------- | -------- | ------ |
|
||||
| app_id | path | | Yes | string |
|
||||
| node_id | path | | Yes | string |
|
||||
| payload | body | | Yes | [ComposerSavePayload](#composersavepayload) |
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer impact | [AgentComposerImpactResponse](#agentcomposerimpactresponse) |
|
||||
|
||||
### /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer/save-to-roster
|
||||
|
||||
@ -3288,9 +3306,9 @@ Run draft workflow loop node
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer saved to roster | [WorkflowAgentComposerResponse](#workflowagentcomposerresponse) |
|
||||
|
||||
### /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer/validate
|
||||
|
||||
@ -3305,9 +3323,9 @@ Run draft workflow loop node
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Success |
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Workflow agent composer validation result | [AgentComposerValidateResponse](#agentcomposervalidateresponse) |
|
||||
|
||||
### /apps/{app_id}/workflows/draft/nodes/{node_id}/last-run
|
||||
|
||||
@ -10651,6 +10669,150 @@ Get banner list
|
||||
| model_mode | string | Model mode | Yes |
|
||||
| model_name | string | Model name | Yes |
|
||||
|
||||
#### AgentAppComposerResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| active_config_snapshot | [AgentConfigSnapshotSummaryResponse](#agentconfigsnapshotsummaryresponse) | | Yes |
|
||||
| agent | [AgentComposerAgentResponse](#agentcomposeragentresponse) | | Yes |
|
||||
| agent_soul | [AgentSoulConfig](#agentsoulconfig) | | Yes |
|
||||
| save_options | [ [ComposerSaveStrategy](#composersavestrategy) ] | | Yes |
|
||||
| variant | string | | Yes |
|
||||
|
||||
#### AgentComposerAgentResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| active_config_snapshot_id | string | | No |
|
||||
| description | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
| scope | [AgentScope](#agentscope) | | Yes |
|
||||
| status | [AgentStatus](#agentstatus) | | Yes |
|
||||
|
||||
#### AgentComposerBindingResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_id | string | | No |
|
||||
| binding_type | [WorkflowAgentBindingType](#workflowagentbindingtype) | | Yes |
|
||||
| current_snapshot_id | string | | No |
|
||||
| id | string | | Yes |
|
||||
| node_id | string | | Yes |
|
||||
| workflow_id | string | | Yes |
|
||||
|
||||
#### AgentComposerCandidatesResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| allowed_node_job_candidates | [AgentComposerNodeJobCandidatesResponse](#agentcomposernodejobcandidatesresponse) | | No |
|
||||
| allowed_soul_candidates | [AgentComposerSoulCandidatesResponse](#agentcomposersoulcandidatesresponse) | | No |
|
||||
| capabilities | [ComposerCandidateCapabilities](#composercandidatecapabilities) | | No |
|
||||
| variant | [ComposerVariant](#composervariant) | | Yes |
|
||||
|
||||
#### AgentComposerImpactBindingResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| app_id | string | | Yes |
|
||||
| node_id | string | | Yes |
|
||||
| workflow_id | string | | Yes |
|
||||
|
||||
#### AgentComposerImpactResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| bindings | [ [AgentComposerImpactBindingResponse](#agentcomposerimpactbindingresponse) ] | | No |
|
||||
| current_snapshot_id | string | | No |
|
||||
| workflow_node_count | integer | | Yes |
|
||||
|
||||
#### AgentComposerNodeJobCandidatesResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| declare_output_types | [ [DeclaredOutputType](#declaredoutputtype) ] | | No |
|
||||
| human_contacts | [ object ] | | No |
|
||||
| previous_node_outputs | [ object ] | | No |
|
||||
|
||||
#### AgentComposerSoulCandidatesResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| cli_tools | [ object ] | | No |
|
||||
| dify_tools | [ object ] | | No |
|
||||
| human_contacts | [ object ] | | No |
|
||||
| knowledge_datasets | [ object ] | | No |
|
||||
| skills_files | [ object ] | | No |
|
||||
|
||||
#### AgentComposerSoulLockResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| can_unlock | boolean | | No |
|
||||
| locked | boolean | | Yes |
|
||||
| reason | string | | No |
|
||||
|
||||
#### AgentComposerValidateResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| errors | [ string ] | | No |
|
||||
| result | string | | Yes |
|
||||
|
||||
#### AgentConfigRevisionOperation
|
||||
|
||||
Audit operation recorded for Agent Soul version/revision changes.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| AgentConfigRevisionOperation | string | Audit operation recorded for Agent Soul version/revision changes. | |
|
||||
|
||||
#### AgentConfigRevisionResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | string | | No |
|
||||
| created_by | string | | No |
|
||||
| current_snapshot_id | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| operation | [AgentConfigRevisionOperation](#agentconfigrevisionoperation) | | Yes |
|
||||
| previous_snapshot_id | string | | No |
|
||||
| revision | integer | | Yes |
|
||||
| summary | string | | No |
|
||||
| version_note | string | | No |
|
||||
|
||||
#### AgentConfigSnapshotDetailResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_id | string | | No |
|
||||
| config_snapshot | [AgentSoulConfig](#agentsoulconfig) | | Yes |
|
||||
| created_at | string | | No |
|
||||
| created_by | string | | No |
|
||||
| id | string | | Yes |
|
||||
| revisions | [ [AgentConfigRevisionResponse](#agentconfigrevisionresponse) ] | | No |
|
||||
| summary | string | | No |
|
||||
| version | integer | | Yes |
|
||||
| version_note | string | | No |
|
||||
|
||||
#### AgentConfigSnapshotListResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [AgentConfigSnapshotSummaryResponse](#agentconfigsnapshotsummaryresponse) ] | | Yes |
|
||||
|
||||
#### AgentConfigSnapshotSummaryResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_id | string | | No |
|
||||
| created_at | string | | No |
|
||||
| created_by | string | | No |
|
||||
| id | string | | Yes |
|
||||
| summary | string | | No |
|
||||
| version | integer | | Yes |
|
||||
| version_note | string | | No |
|
||||
|
||||
#### AgentIconType
|
||||
|
||||
Supported icon storage formats for Agent roster entries.
|
||||
@ -10665,6 +10827,35 @@ Supported icon storage formats for Agent roster entries.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_id | string | | Yes |
|
||||
|
||||
#### AgentInviteOptionResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| active_config_snapshot | [AgentConfigSnapshotSummaryResponse](#agentconfigsnapshotsummaryresponse) | | No |
|
||||
| active_config_snapshot_id | string | | No |
|
||||
| agent_kind | [AgentKind](#agentkind) | | Yes |
|
||||
| app_id | string | | No |
|
||||
| archived_at | string | | No |
|
||||
| archived_by | string | | No |
|
||||
| created_at | string | | No |
|
||||
| created_by | string | | No |
|
||||
| description | string | | Yes |
|
||||
| existing_node_ids | [ string ] | | No |
|
||||
| icon | string | | No |
|
||||
| icon_background | string | | No |
|
||||
| icon_type | [AgentIconType](#agenticontype) | | No |
|
||||
| id | string | | Yes |
|
||||
| in_current_workflow_count | integer | | No |
|
||||
| is_in_current_workflow | boolean | | No |
|
||||
| name | string | | Yes |
|
||||
| scope | [AgentScope](#agentscope) | | Yes |
|
||||
| source | [AgentSource](#agentsource) | | Yes |
|
||||
| status | [AgentStatus](#agentstatus) | | Yes |
|
||||
| updated_at | string | | No |
|
||||
| updated_by | string | | No |
|
||||
| workflow_id | string | | No |
|
||||
| workflow_node_id | string | | No |
|
||||
|
||||
#### AgentInviteOptionsQuery
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -10674,6 +10865,27 @@ Supported icon storage formats for Agent roster entries.
|
||||
| limit | integer | | No |
|
||||
| page | integer | | No |
|
||||
|
||||
#### AgentInviteOptionsResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [AgentInviteOptionResponse](#agentinviteoptionresponse) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### AgentKind
|
||||
|
||||
Agent implementation family.
|
||||
|
||||
This leaves room for future non-Dify agent implementations while keeping
|
||||
the current roster/workflow APIs scoped to Dify Agent.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| AgentKind | string | Agent implementation family. This leaves room for future non-Dify agent implementations while keeping the current roster/workflow APIs scoped to Dify Agent. | |
|
||||
|
||||
#### AgentKnowledgeQueryMode
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -10687,6 +10899,50 @@ Supported icon storage formats for Agent roster entries.
|
||||
| conversation_id | string | Conversation UUID | Yes |
|
||||
| message_id | string | Message UUID | Yes |
|
||||
|
||||
#### AgentRosterListResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [AgentRosterResponse](#agentrosterresponse) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### AgentRosterResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| active_config_snapshot | [AgentConfigSnapshotSummaryResponse](#agentconfigsnapshotsummaryresponse) | | No |
|
||||
| active_config_snapshot_id | string | | No |
|
||||
| agent_kind | [AgentKind](#agentkind) | | Yes |
|
||||
| app_id | string | | No |
|
||||
| archived_at | string | | No |
|
||||
| archived_by | string | | No |
|
||||
| created_at | string | | No |
|
||||
| created_by | string | | No |
|
||||
| description | string | | Yes |
|
||||
| icon | string | | No |
|
||||
| icon_background | string | | No |
|
||||
| icon_type | [AgentIconType](#agenticontype) | | No |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
| scope | [AgentScope](#agentscope) | | Yes |
|
||||
| source | [AgentSource](#agentsource) | | Yes |
|
||||
| status | [AgentStatus](#agentstatus) | | Yes |
|
||||
| updated_at | string | | No |
|
||||
| updated_by | string | | No |
|
||||
| workflow_id | string | | No |
|
||||
| workflow_node_id | string | | No |
|
||||
|
||||
#### AgentScope
|
||||
|
||||
Visibility and lifecycle scope of an Agent record.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| AgentScope | string | Visibility and lifecycle scope of an Agent record. | |
|
||||
|
||||
#### AgentSoulConfig
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -10821,6 +11077,22 @@ Reference to model credentials resolved only at runtime.
|
||||
| cli_tools | [ object ] | | No |
|
||||
| dify_tools | [ [AgentSoulDifyToolConfig](#agentsouldifytoolconfig) ] | | No |
|
||||
|
||||
#### AgentSource
|
||||
|
||||
Origin that created or imported the Agent.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| AgentSource | string | Origin that created or imported the Agent. | |
|
||||
|
||||
#### AgentStatus
|
||||
|
||||
Soft lifecycle state for Agent records.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| AgentStatus | string | Soft lifecycle state for Agent records. | |
|
||||
|
||||
#### AgentThought
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -11528,6 +11800,12 @@ Button styles for user actions.
|
||||
| binding_type | string | *Enum:* `"inline_agent"`, `"roster_agent"` | Yes |
|
||||
| current_snapshot_id | string | | No |
|
||||
|
||||
#### ComposerCandidateCapabilities
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| human_roster_available | boolean | | No |
|
||||
|
||||
#### ComposerSavePayload
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -15369,6 +15647,32 @@ in form definiton, or a variable while the workflow is running.
|
||||
| embedding_provider_name | string | | Yes |
|
||||
| vector_weight | number | | Yes |
|
||||
|
||||
#### WorkflowAgentBindingType
|
||||
|
||||
How a workflow node is bound to an Agent.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| WorkflowAgentBindingType | string | How a workflow node is bound to an Agent. | |
|
||||
|
||||
#### WorkflowAgentComposerResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| active_config_snapshot | [AgentConfigSnapshotSummaryResponse](#agentconfigsnapshotsummaryresponse) | | No |
|
||||
| agent | [AgentComposerAgentResponse](#agentcomposeragentresponse) | | No |
|
||||
| agent_soul | [AgentSoulConfig](#agentsoulconfig) | | Yes |
|
||||
| app_id | string | | No |
|
||||
| binding | [AgentComposerBindingResponse](#agentcomposerbindingresponse) | | No |
|
||||
| effective_declared_outputs | [ [DeclaredOutputConfig](#declaredoutputconfig) ] | | No |
|
||||
| impact_summary | [AgentComposerImpactResponse](#agentcomposerimpactresponse) | | No |
|
||||
| node_id | string | | No |
|
||||
| node_job | [WorkflowNodeJobConfig](#workflownodejobconfig) | | Yes |
|
||||
| save_options | [ [ComposerSaveStrategy](#composersavestrategy) ] | | Yes |
|
||||
| soul_lock | [AgentComposerSoulLockResponse](#agentcomposersoullockresponse) | | Yes |
|
||||
| variant | string | | Yes |
|
||||
| workflow_id | string | | No |
|
||||
|
||||
#### WorkflowAppLogPaginationResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|
||||
@ -30,6 +30,90 @@ def _unwrap(method):
|
||||
return method
|
||||
|
||||
|
||||
def _agent_response(agent_id: str = "agent-1") -> dict:
|
||||
return {
|
||||
"id": agent_id,
|
||||
"name": "Analyst",
|
||||
"description": "",
|
||||
"icon_type": None,
|
||||
"icon": None,
|
||||
"icon_background": None,
|
||||
"agent_kind": "dify_agent",
|
||||
"scope": "roster",
|
||||
"source": "agent_app",
|
||||
"app_id": None,
|
||||
"workflow_id": None,
|
||||
"workflow_node_id": None,
|
||||
"active_config_snapshot_id": "version-1",
|
||||
"active_config_snapshot": _version_response(),
|
||||
"status": "active",
|
||||
"created_by": "account-1",
|
||||
"updated_by": "account-1",
|
||||
"archived_by": None,
|
||||
"archived_at": None,
|
||||
"created_at": None,
|
||||
"updated_at": None,
|
||||
}
|
||||
|
||||
|
||||
def _version_response(version_id: str = "version-1") -> dict:
|
||||
return {
|
||||
"id": version_id,
|
||||
"agent_id": "agent-1",
|
||||
"version": 1,
|
||||
"summary": None,
|
||||
"version_note": None,
|
||||
"created_by": "account-1",
|
||||
"created_at": None,
|
||||
}
|
||||
|
||||
|
||||
def _workflow_composer_response(**overrides) -> dict:
|
||||
response = {
|
||||
"variant": "workflow",
|
||||
"agent": None,
|
||||
"active_config_snapshot": None,
|
||||
"binding": None,
|
||||
"soul_lock": {"locked": False, "can_unlock": False, "reason": "workflow_only_empty"},
|
||||
"agent_soul": {},
|
||||
"node_job": {},
|
||||
"effective_declared_outputs": [],
|
||||
"save_options": ["node_job_only"],
|
||||
"impact_summary": None,
|
||||
"app_id": "app-1",
|
||||
"workflow_id": "workflow-1",
|
||||
"node_id": "node-1",
|
||||
}
|
||||
response.update(overrides)
|
||||
return response
|
||||
|
||||
|
||||
def _agent_app_composer_response() -> dict:
|
||||
return {
|
||||
"variant": "agent_app",
|
||||
"agent": {
|
||||
"id": "agent-1",
|
||||
"name": "Analyst",
|
||||
"description": "",
|
||||
"scope": "roster",
|
||||
"status": "active",
|
||||
"active_config_snapshot_id": "version-1",
|
||||
},
|
||||
"active_config_snapshot": _version_response(),
|
||||
"agent_soul": {},
|
||||
"save_options": ["save_to_current_version", "save_as_new_version"],
|
||||
}
|
||||
|
||||
|
||||
def _candidates_response(variant: str) -> dict:
|
||||
return {
|
||||
"variant": variant,
|
||||
"allowed_node_job_candidates": {},
|
||||
"allowed_soul_candidates": {},
|
||||
"capabilities": {"human_roster_available": False},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def account():
|
||||
return SimpleNamespace(id="account-1")
|
||||
@ -67,14 +151,15 @@ def test_roster_list_post_creates_agent_and_returns_detail(app, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
"get_roster_agent_detail",
|
||||
lambda _self, **kwargs: {"id": kwargs["agent_id"], "tenant_id": kwargs["tenant_id"]},
|
||||
lambda _self, **kwargs: _agent_response(kwargs["agent_id"]),
|
||||
)
|
||||
|
||||
with app.test_request_context(json={"name": "Analyst", "agent_soul": {"prompt": {"system_prompt": "x"}}}):
|
||||
result, status = _unwrap(AgentRosterListApi.post)(AgentRosterListApi())
|
||||
|
||||
assert status == 201
|
||||
assert result == {"id": "agent-1", "tenant_id": "tenant-1"}
|
||||
assert result["id"] == "agent-1"
|
||||
assert result["agent_kind"] == "dify_agent"
|
||||
|
||||
|
||||
def test_invite_options_get_parses_app_id(app, monkeypatch):
|
||||
@ -82,14 +167,14 @@ def test_invite_options_get_parses_app_id(app, monkeypatch):
|
||||
|
||||
def list_invite_options(_self, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return {"data": []}
|
||||
return {"data": [], "page": kwargs["page"], "limit": kwargs["limit"], "total": 0, "has_more": False}
|
||||
|
||||
monkeypatch.setattr(roster_controller.AgentRosterService, "list_invite_options", list_invite_options)
|
||||
|
||||
with app.test_request_context("/console/api/agents/invite-options?page=1&limit=10&app_id=app-1"):
|
||||
result = _unwrap(AgentInviteOptionsApi.get)(AgentInviteOptionsApi())
|
||||
|
||||
assert result == {"data": []}
|
||||
assert result == {"data": [], "page": 1, "limit": 10, "total": 0, "has_more": False}
|
||||
assert captured == {"tenant_id": "tenant-1", "page": 1, "limit": 10, "keyword": None, "app_id": "app-1"}
|
||||
|
||||
|
||||
@ -100,12 +185,12 @@ def test_roster_detail_patch_delete_and_versions_call_services(app, monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
"get_roster_agent_detail",
|
||||
lambda _self, **kwargs: {"id": kwargs["agent_id"]},
|
||||
lambda _self, **kwargs: _agent_response(kwargs["agent_id"]),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
"update_roster_agent",
|
||||
lambda _self, **kwargs: {"id": kwargs["agent_id"], "description": kwargs["payload"].description},
|
||||
lambda _self, **kwargs: {**_agent_response(kwargs["agent_id"]), "description": kwargs["payload"].description},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
@ -115,12 +200,29 @@ def test_roster_detail_patch_delete_and_versions_call_services(app, monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
"list_agent_versions",
|
||||
lambda _self, **kwargs: [{"id": "version-1"}],
|
||||
lambda _self, **kwargs: [_version_response()],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
roster_controller.AgentRosterService,
|
||||
"get_agent_version_detail",
|
||||
lambda _self, **kwargs: {"id": kwargs["version_id"], "agent_id": kwargs["agent_id"]},
|
||||
lambda _self, **kwargs: {
|
||||
**_version_response(kwargs["version_id"]),
|
||||
"agent_id": kwargs["agent_id"],
|
||||
"config_snapshot": {},
|
||||
"revisions": [
|
||||
{
|
||||
"id": "revision-1",
|
||||
"previous_snapshot_id": None,
|
||||
"current_snapshot_id": kwargs["version_id"],
|
||||
"revision": 1,
|
||||
"operation": "create_version",
|
||||
"summary": None,
|
||||
"version_note": None,
|
||||
"created_by": "account-1",
|
||||
"created_at": None,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
assert _unwrap(AgentRosterDetailApi.get)(AgentRosterDetailApi(), agent_id)["id"] == agent_id
|
||||
@ -128,11 +230,10 @@ def test_roster_detail_patch_delete_and_versions_call_services(app, monkeypatch)
|
||||
assert _unwrap(AgentRosterDetailApi.patch)(AgentRosterDetailApi(), agent_id)["description"] == "updated"
|
||||
assert _unwrap(AgentRosterDetailApi.delete)(AgentRosterDetailApi(), agent_id) == ("", 204)
|
||||
assert archived["account_id"] == "account-1"
|
||||
assert _unwrap(AgentRosterVersionsApi.get)(AgentRosterVersionsApi(), agent_id) == {"data": [{"id": "version-1"}]}
|
||||
assert _unwrap(AgentRosterVersionDetailApi.get)(AgentRosterVersionDetailApi(), agent_id, version_id) == {
|
||||
"id": version_id,
|
||||
"agent_id": agent_id,
|
||||
}
|
||||
assert _unwrap(AgentRosterVersionsApi.get)(AgentRosterVersionsApi(), agent_id)["data"][0]["id"] == "version-1"
|
||||
version_detail = _unwrap(AgentRosterVersionDetailApi.get)(AgentRosterVersionDetailApi(), agent_id, version_id)
|
||||
assert version_detail["id"] == version_id
|
||||
assert version_detail["agent_id"] == agent_id
|
||||
|
||||
|
||||
def test_workflow_composer_get_put_validate_candidates_impact_and_save(app, monkeypatch):
|
||||
@ -145,50 +246,52 @@ def test_workflow_composer_get_put_validate_candidates_impact_and_save(app, monk
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"load_workflow_composer",
|
||||
lambda **kwargs: {"node_id": kwargs["node_id"]},
|
||||
lambda **kwargs: _workflow_composer_response(node_id=kwargs["node_id"]),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"save_workflow_composer",
|
||||
lambda **kwargs: {"saved": kwargs["payload"].save_strategy.value, "account_id": kwargs["account_id"]},
|
||||
lambda **kwargs: _workflow_composer_response(save_options=[kwargs["payload"].save_strategy.value]),
|
||||
)
|
||||
monkeypatch.setattr(composer_controller.ComposerConfigValidator, "validate_save_payload", lambda payload: None)
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"get_workflow_candidates",
|
||||
lambda **kwargs: {"data": []},
|
||||
lambda **kwargs: _candidates_response("workflow"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"calculate_impact",
|
||||
lambda **kwargs: {"current_snapshot_id": kwargs["current_snapshot_id"], "workflow_node_count": 1},
|
||||
lambda **kwargs: {
|
||||
"current_snapshot_id": kwargs["current_snapshot_id"],
|
||||
"workflow_node_count": 1,
|
||||
"bindings": [],
|
||||
},
|
||||
)
|
||||
|
||||
assert _unwrap(WorkflowAgentComposerApi.get)(WorkflowAgentComposerApi(), app_model, "node-1") == {
|
||||
"node_id": "node-1"
|
||||
}
|
||||
workflow_state = _unwrap(WorkflowAgentComposerApi.get)(WorkflowAgentComposerApi(), app_model, "node-1")
|
||||
assert workflow_state["node_id"] == "node-1"
|
||||
with app.test_request_context(json=payload):
|
||||
assert _unwrap(WorkflowAgentComposerApi.put)(WorkflowAgentComposerApi(), app_model, "node-1") == {
|
||||
"saved": "node_job_only",
|
||||
"account_id": "account-1",
|
||||
}
|
||||
saved_state = _unwrap(WorkflowAgentComposerApi.put)(WorkflowAgentComposerApi(), app_model, "node-1")
|
||||
assert saved_state["save_options"] == ["node_job_only"]
|
||||
assert _unwrap(WorkflowAgentComposerValidateApi.post)(
|
||||
WorkflowAgentComposerValidateApi(), app_model, "node-1"
|
||||
) == {"result": "success", "errors": []}
|
||||
assert _unwrap(WorkflowAgentComposerCandidatesApi.get)(
|
||||
WorkflowAgentComposerCandidatesApi(), app_model, "node-1"
|
||||
) == {"data": []}
|
||||
assert (
|
||||
_unwrap(WorkflowAgentComposerCandidatesApi.get)(WorkflowAgentComposerCandidatesApi(), app_model, "node-1")[
|
||||
"variant"
|
||||
]
|
||||
== "workflow"
|
||||
)
|
||||
with app.test_request_context(json=payload):
|
||||
assert _unwrap(WorkflowAgentComposerImpactApi.post)(WorkflowAgentComposerImpactApi(), app_model, "node-1") == {
|
||||
"current_snapshot_id": "version-1",
|
||||
"workflow_node_count": 1,
|
||||
"bindings": [],
|
||||
}
|
||||
assert (
|
||||
_unwrap(WorkflowAgentComposerSaveToRosterApi.post)(
|
||||
WorkflowAgentComposerSaveToRosterApi(), app_model, "node-1"
|
||||
)["saved"]
|
||||
== "node_job_only"
|
||||
)
|
||||
assert _unwrap(WorkflowAgentComposerSaveToRosterApi.post)(
|
||||
WorkflowAgentComposerSaveToRosterApi(), app_model, "node-1"
|
||||
)["save_options"] == ["node_job_only"]
|
||||
|
||||
|
||||
def test_workflow_impact_returns_empty_without_version(app):
|
||||
@ -212,28 +315,26 @@ def test_agent_app_composer_get_put_validate_and_candidates(app, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"load_agent_app_composer",
|
||||
lambda **kwargs: {"loaded": True},
|
||||
lambda **kwargs: _agent_app_composer_response(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"save_agent_app_composer",
|
||||
lambda **kwargs: {"saved": kwargs["payload"].variant.value, "account_id": kwargs["account_id"]},
|
||||
lambda **kwargs: _agent_app_composer_response(),
|
||||
)
|
||||
monkeypatch.setattr(composer_controller.ComposerConfigValidator, "validate_save_payload", lambda payload: None)
|
||||
monkeypatch.setattr(
|
||||
composer_controller.AgentComposerService,
|
||||
"get_agent_app_candidates",
|
||||
lambda **kwargs: {"data": []},
|
||||
lambda **kwargs: _candidates_response("agent_app"),
|
||||
)
|
||||
|
||||
assert _unwrap(AgentAppComposerApi.get)(AgentAppComposerApi(), app_model) == {"loaded": True}
|
||||
assert _unwrap(AgentAppComposerApi.get)(AgentAppComposerApi(), app_model)["variant"] == "agent_app"
|
||||
with app.test_request_context(json=payload):
|
||||
assert _unwrap(AgentAppComposerApi.put)(AgentAppComposerApi(), app_model) == {
|
||||
"saved": "agent_app",
|
||||
"account_id": "account-1",
|
||||
}
|
||||
assert _unwrap(AgentAppComposerApi.put)(AgentAppComposerApi(), app_model)["variant"] == "agent_app"
|
||||
assert _unwrap(AgentAppComposerValidateApi.post)(AgentAppComposerValidateApi(), app_model) == {
|
||||
"result": "success",
|
||||
"errors": [],
|
||||
}
|
||||
assert _unwrap(AgentAppComposerCandidatesApi.get)(AgentAppComposerCandidatesApi(), app_model) == {"data": []}
|
||||
agent_app_candidates = _unwrap(AgentAppComposerCandidatesApi.get)(AgentAppComposerCandidatesApi(), app_model)
|
||||
assert agent_app_candidates["variant"] == "agent_app"
|
||||
|
||||
@ -40,7 +40,7 @@ export type PollSuccess = {
|
||||
subject_type?: string
|
||||
subject_email?: string
|
||||
subject_issuer?: string
|
||||
account?: PollAccount | null
|
||||
account?: PollAccount
|
||||
workspaces?: readonly PollWorkspace[]
|
||||
default_workspace_id?: string
|
||||
token_id?: string
|
||||
|
||||
@ -99,9 +99,8 @@ function renderCodePrompt(w: NodeJS.WritableStream, cs: ReturnType<typeof colorS
|
||||
|
||||
function renderLoggedIn(w: NodeJS.WritableStream, cs: ReturnType<typeof colorScheme>, host: string, s: PollSuccess): void {
|
||||
const display = bareHost(host)
|
||||
const account = s.account ?? undefined
|
||||
if (account !== undefined && account.email !== '') {
|
||||
w.write(`${cs.successIcon()} Logged in to ${display} as ${cs.bold(account.email)} (${account.name})\n`)
|
||||
if (s.account !== undefined && s.account.email !== '') {
|
||||
w.write(`${cs.successIcon()} Logged in to ${display} as ${cs.bold(s.account.email)} (${s.account.name})\n`)
|
||||
const ws = findDefaultWorkspace(s)
|
||||
if (ws !== undefined)
|
||||
w.write(` Workspace: ${ws.name}\n`)
|
||||
@ -140,12 +139,11 @@ function bundleFromSuccess(host: string, s: PollSuccess, mode: StorageMode): Hos
|
||||
token_id: s.token_id,
|
||||
tokens: { bearer: s.token },
|
||||
}
|
||||
const account = s.account ?? undefined
|
||||
if (account !== undefined) {
|
||||
bundle.account = { id: account.id, email: account.email, name: account.name }
|
||||
if (s.account !== undefined) {
|
||||
bundle.account = { id: s.account.id, email: s.account.email, name: s.account.name }
|
||||
}
|
||||
if (s.subject_email !== undefined && s.subject_email !== ''
|
||||
&& (account === undefined || account.id === '')) {
|
||||
&& (s.account === undefined || s.account.id === '')) {
|
||||
bundle.external_subject = {
|
||||
email: s.subject_email,
|
||||
issuer: s.subject_issuer ?? '',
|
||||
|
||||
@ -44,7 +44,7 @@ abstract class FileBasedStore implements Store {
|
||||
flush(): void {
|
||||
fs.mkdirSync(dirname(this.filePath), { recursive: true, mode: DIR_PERM })
|
||||
|
||||
// we don't handle A-B-A scenario,
|
||||
// we don't handle A-B-A scenario,
|
||||
// which is not likely to happen in cli
|
||||
if (!this.dirty) {
|
||||
return
|
||||
|
||||
3
cli/test/fixtures/dify-mock/server.ts
vendored
3
cli/test/fixtures/dify-mock/server.ts
vendored
@ -356,9 +356,6 @@ export function buildApp(getScenario: () => Scenario, state?: MockState): Hono {
|
||||
subject_type: 'external_sso',
|
||||
subject_email: 'sso@dify.ai',
|
||||
subject_issuer: 'https://issuer.example',
|
||||
account: null,
|
||||
workspaces: [],
|
||||
default_workspace_id: null,
|
||||
token_id: 'tok-sso-1',
|
||||
})
|
||||
}
|
||||
|
||||
@ -12,7 +12,9 @@ import {
|
||||
zGetAgentsByAgentIdVersionsByVersionIdResponse,
|
||||
zGetAgentsByAgentIdVersionsPath,
|
||||
zGetAgentsByAgentIdVersionsResponse,
|
||||
zGetAgentsInviteOptionsQuery,
|
||||
zGetAgentsInviteOptionsResponse,
|
||||
zGetAgentsQuery,
|
||||
zGetAgentsResponse,
|
||||
zPatchAgentsByAgentIdBody,
|
||||
zPatchAgentsByAgentIdPath,
|
||||
@ -21,22 +23,15 @@ import {
|
||||
zPostAgentsResponse,
|
||||
} from './zod.gen'
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const get = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'GET',
|
||||
operationId: 'getAgentsInviteOptions',
|
||||
path: '/agents/invite-options',
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(z.object({ query: zGetAgentsInviteOptionsQuery.optional() }))
|
||||
.output(zGetAgentsInviteOptionsResponse)
|
||||
|
||||
export const inviteOptions = {
|
||||
@ -66,16 +61,8 @@ export const byVersionId = {
|
||||
get: get2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const get3 = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'GET',
|
||||
operationId: 'getAgentsByAgentIdVersions',
|
||||
@ -90,35 +77,20 @@ export const versions = {
|
||||
byVersionId,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const delete_ = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'DELETE',
|
||||
operationId: 'deleteAgentsByAgentId',
|
||||
path: '/agents/{agent_id}',
|
||||
successStatus: 204,
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(z.object({ params: zDeleteAgentsByAgentIdPath }))
|
||||
.output(zDeleteAgentsByAgentIdResponse)
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const get4 = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'GET',
|
||||
operationId: 'getAgentsByAgentId',
|
||||
@ -128,16 +100,8 @@ export const get4 = oc
|
||||
.input(z.object({ params: zGetAgentsByAgentIdPath }))
|
||||
.output(zGetAgentsByAgentIdResponse)
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const patch = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'PATCH',
|
||||
operationId: 'patchAgentsByAgentId',
|
||||
@ -154,22 +118,15 @@ export const byAgentId = {
|
||||
versions,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const get5 = oc
|
||||
.route({
|
||||
deprecated: true,
|
||||
description:
|
||||
'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
|
||||
inputStructure: 'detailed',
|
||||
method: 'GET',
|
||||
operationId: 'getAgents',
|
||||
path: '/agents',
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(z.object({ query: zGetAgentsQuery.optional() }))
|
||||
.output(zGetAgentsResponse)
|
||||
|
||||
/**
|
||||
@ -186,6 +143,7 @@ export const post = oc
|
||||
method: 'POST',
|
||||
operationId: 'postAgents',
|
||||
path: '/agents',
|
||||
successStatus: 201,
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(z.object({ body: zPostAgentsBody }))
|
||||
|
||||
@ -4,6 +4,14 @@ export type ClientOptions = {
|
||||
baseUrl: `${string}://${string}/console/api` | (string & {})
|
||||
}
|
||||
|
||||
export type AgentRosterListResponse = {
|
||||
data: Array<AgentRosterResponse>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type RosterAgentCreatePayload = {
|
||||
agent_soul?: AgentSoulConfig
|
||||
description?: string
|
||||
@ -14,6 +22,38 @@ export type RosterAgentCreatePayload = {
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AgentRosterResponse = {
|
||||
active_config_snapshot?: AgentConfigSnapshotSummaryResponse
|
||||
active_config_snapshot_id?: string | null
|
||||
agent_kind: AgentKind
|
||||
app_id?: string | null
|
||||
archived_at?: string | null
|
||||
archived_by?: string | null
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
description: string
|
||||
icon?: string | null
|
||||
icon_background?: string | null
|
||||
icon_type?: AgentIconType
|
||||
id: string
|
||||
name: string
|
||||
scope: AgentScope
|
||||
source: AgentSource
|
||||
status: AgentStatus
|
||||
updated_at?: string | null
|
||||
updated_by?: string | null
|
||||
workflow_id?: string | null
|
||||
workflow_node_id?: string | null
|
||||
}
|
||||
|
||||
export type AgentInviteOptionsResponse = {
|
||||
data: Array<AgentInviteOptionResponse>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type RosterAgentUpdatePayload = {
|
||||
description?: string | null
|
||||
icon?: string | null
|
||||
@ -22,6 +62,22 @@ export type RosterAgentUpdatePayload = {
|
||||
name?: string | null
|
||||
}
|
||||
|
||||
export type AgentConfigSnapshotListResponse = {
|
||||
data: Array<AgentConfigSnapshotSummaryResponse>
|
||||
}
|
||||
|
||||
export type AgentConfigSnapshotDetailResponse = {
|
||||
agent_id?: string | null
|
||||
config_snapshot: AgentSoulConfig
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
id: string
|
||||
revisions?: Array<AgentConfigRevisionResponse>
|
||||
summary?: string | null
|
||||
version: number
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AgentSoulConfig = {
|
||||
app_features?: {
|
||||
[key: string]: unknown
|
||||
@ -44,6 +100,63 @@ export type AgentSoulConfig = {
|
||||
|
||||
export type AgentIconType = 'emoji' | 'image' | 'link'
|
||||
|
||||
export type AgentConfigSnapshotSummaryResponse = {
|
||||
agent_id?: string | null
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
id: string
|
||||
summary?: string | null
|
||||
version: number
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AgentKind = 'dify_agent'
|
||||
|
||||
export type AgentScope = 'roster' | 'workflow_only'
|
||||
|
||||
export type AgentSource = 'agent_app' | 'imported' | 'system' | 'workflow'
|
||||
|
||||
export type AgentStatus = 'active' | 'archived'
|
||||
|
||||
export type AgentInviteOptionResponse = {
|
||||
active_config_snapshot?: AgentConfigSnapshotSummaryResponse
|
||||
active_config_snapshot_id?: string | null
|
||||
agent_kind: AgentKind
|
||||
app_id?: string | null
|
||||
archived_at?: string | null
|
||||
archived_by?: string | null
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
description: string
|
||||
existing_node_ids?: Array<string>
|
||||
icon?: string | null
|
||||
icon_background?: string | null
|
||||
icon_type?: AgentIconType
|
||||
id: string
|
||||
in_current_workflow_count?: number
|
||||
is_in_current_workflow?: boolean
|
||||
name: string
|
||||
scope: AgentScope
|
||||
source: AgentSource
|
||||
status: AgentStatus
|
||||
updated_at?: string | null
|
||||
updated_by?: string | null
|
||||
workflow_id?: string | null
|
||||
workflow_node_id?: string | null
|
||||
}
|
||||
|
||||
export type AgentConfigRevisionResponse = {
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
current_snapshot_id: string
|
||||
id: string
|
||||
operation: AgentConfigRevisionOperation
|
||||
previous_snapshot_id?: string | null
|
||||
revision: number
|
||||
summary?: string | null
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AppVariableConfig = {
|
||||
default?: unknown
|
||||
name: string
|
||||
@ -124,6 +237,13 @@ export type AgentSoulToolsConfig = {
|
||||
dify_tools?: Array<AgentSoulDifyToolConfig>
|
||||
}
|
||||
|
||||
export type AgentConfigRevisionOperation
|
||||
= | 'create_version'
|
||||
| 'save_current_version'
|
||||
| 'save_new_agent'
|
||||
| 'save_new_version'
|
||||
| 'save_to_roster'
|
||||
|
||||
export type AgentKnowledgeQueryMode = 'generated_query' | 'user_query'
|
||||
|
||||
export type AgentSoulModelCredentialRef = {
|
||||
@ -157,14 +277,16 @@ export type AgentSoulDifyToolCredentialRef = {
|
||||
export type GetAgentsData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query?: never
|
||||
query?: {
|
||||
keyword?: string
|
||||
limit?: number
|
||||
page?: number
|
||||
}
|
||||
url: '/agents'
|
||||
}
|
||||
|
||||
export type GetAgentsResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentRosterListResponse
|
||||
}
|
||||
|
||||
export type GetAgentsResponse = GetAgentsResponses[keyof GetAgentsResponses]
|
||||
@ -177,9 +299,7 @@ export type PostAgentsData = {
|
||||
}
|
||||
|
||||
export type PostAgentsResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
201: AgentRosterResponse
|
||||
}
|
||||
|
||||
export type PostAgentsResponse = PostAgentsResponses[keyof PostAgentsResponses]
|
||||
@ -187,14 +307,17 @@ export type PostAgentsResponse = PostAgentsResponses[keyof PostAgentsResponses]
|
||||
export type GetAgentsInviteOptionsData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query?: never
|
||||
query?: {
|
||||
app_id?: string
|
||||
keyword?: string
|
||||
limit?: number
|
||||
page?: number
|
||||
}
|
||||
url: '/agents/invite-options'
|
||||
}
|
||||
|
||||
export type GetAgentsInviteOptionsResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentInviteOptionsResponse
|
||||
}
|
||||
|
||||
export type GetAgentsInviteOptionsResponse
|
||||
@ -210,8 +333,8 @@ export type DeleteAgentsByAgentIdData = {
|
||||
}
|
||||
|
||||
export type DeleteAgentsByAgentIdResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
204: {
|
||||
[key: string]: never
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +351,7 @@ export type GetAgentsByAgentIdData = {
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentRosterResponse
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdResponse
|
||||
@ -246,9 +367,7 @@ export type PatchAgentsByAgentIdData = {
|
||||
}
|
||||
|
||||
export type PatchAgentsByAgentIdResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentRosterResponse
|
||||
}
|
||||
|
||||
export type PatchAgentsByAgentIdResponse
|
||||
@ -264,9 +383,7 @@ export type GetAgentsByAgentIdVersionsData = {
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdVersionsResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentConfigSnapshotListResponse
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdVersionsResponse
|
||||
@ -283,9 +400,7 @@ export type GetAgentsByAgentIdVersionsByVersionIdData = {
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdVersionsByVersionIdResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentConfigSnapshotDetailResponse
|
||||
}
|
||||
|
||||
export type GetAgentsByAgentIdVersionsByVersionIdResponse
|
||||
|
||||
@ -20,6 +20,136 @@ export const zRosterAgentUpdatePayload = z.object({
|
||||
name: z.string().min(1).max(255).nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentConfigSnapshotSummaryResponse
|
||||
*/
|
||||
export const zAgentConfigSnapshotSummaryResponse = z.object({
|
||||
agent_id: z.string().nullish(),
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
id: z.string(),
|
||||
summary: z.string().nullish(),
|
||||
version: z.int(),
|
||||
version_note: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentConfigSnapshotListResponse
|
||||
*/
|
||||
export const zAgentConfigSnapshotListResponse = z.object({
|
||||
data: z.array(zAgentConfigSnapshotSummaryResponse),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentKind
|
||||
*
|
||||
* Agent implementation family.
|
||||
*
|
||||
* This leaves room for future non-Dify agent implementations while keeping
|
||||
* the current roster/workflow APIs scoped to Dify Agent.
|
||||
*/
|
||||
export const zAgentKind = z.enum(['dify_agent'])
|
||||
|
||||
/**
|
||||
* AgentScope
|
||||
*
|
||||
* Visibility and lifecycle scope of an Agent record.
|
||||
*/
|
||||
export const zAgentScope = z.enum(['roster', 'workflow_only'])
|
||||
|
||||
/**
|
||||
* AgentSource
|
||||
*
|
||||
* Origin that created or imported the Agent.
|
||||
*/
|
||||
export const zAgentSource = z.enum(['agent_app', 'imported', 'system', 'workflow'])
|
||||
|
||||
/**
|
||||
* AgentStatus
|
||||
*
|
||||
* Soft lifecycle state for Agent records.
|
||||
*/
|
||||
export const zAgentStatus = z.enum(['active', 'archived'])
|
||||
|
||||
/**
|
||||
* AgentRosterResponse
|
||||
*/
|
||||
export const zAgentRosterResponse = z.object({
|
||||
active_config_snapshot: zAgentConfigSnapshotSummaryResponse.optional(),
|
||||
active_config_snapshot_id: z.string().nullish(),
|
||||
agent_kind: zAgentKind,
|
||||
app_id: z.string().nullish(),
|
||||
archived_at: z.string().nullish(),
|
||||
archived_by: z.string().nullish(),
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
description: z.string(),
|
||||
icon: z.string().nullish(),
|
||||
icon_background: z.string().nullish(),
|
||||
icon_type: zAgentIconType.optional(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
scope: zAgentScope,
|
||||
source: zAgentSource,
|
||||
status: zAgentStatus,
|
||||
updated_at: z.string().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
workflow_id: z.string().nullish(),
|
||||
workflow_node_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentRosterListResponse
|
||||
*/
|
||||
export const zAgentRosterListResponse = z.object({
|
||||
data: z.array(zAgentRosterResponse),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentInviteOptionResponse
|
||||
*/
|
||||
export const zAgentInviteOptionResponse = z.object({
|
||||
active_config_snapshot: zAgentConfigSnapshotSummaryResponse.optional(),
|
||||
active_config_snapshot_id: z.string().nullish(),
|
||||
agent_kind: zAgentKind,
|
||||
app_id: z.string().nullish(),
|
||||
archived_at: z.string().nullish(),
|
||||
archived_by: z.string().nullish(),
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
description: z.string(),
|
||||
existing_node_ids: z.array(z.string()).optional(),
|
||||
icon: z.string().nullish(),
|
||||
icon_background: z.string().nullish(),
|
||||
icon_type: zAgentIconType.optional(),
|
||||
id: z.string(),
|
||||
in_current_workflow_count: z.int().optional().default(0),
|
||||
is_in_current_workflow: z.boolean().optional().default(false),
|
||||
name: z.string(),
|
||||
scope: zAgentScope,
|
||||
source: zAgentSource,
|
||||
status: zAgentStatus,
|
||||
updated_at: z.string().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
workflow_id: z.string().nullish(),
|
||||
workflow_node_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentInviteOptionsResponse
|
||||
*/
|
||||
export const zAgentInviteOptionsResponse = z.object({
|
||||
data: z.array(zAgentInviteOptionResponse),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AppVariableConfig
|
||||
*/
|
||||
@ -78,6 +208,34 @@ export const zAgentSoulSkillsFilesConfig = z.object({
|
||||
skills: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentConfigRevisionOperation
|
||||
*
|
||||
* Audit operation recorded for Agent Soul version/revision changes.
|
||||
*/
|
||||
export const zAgentConfigRevisionOperation = z.enum([
|
||||
'create_version',
|
||||
'save_current_version',
|
||||
'save_new_agent',
|
||||
'save_new_version',
|
||||
'save_to_roster',
|
||||
])
|
||||
|
||||
/**
|
||||
* AgentConfigRevisionResponse
|
||||
*/
|
||||
export const zAgentConfigRevisionResponse = z.object({
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
current_snapshot_id: z.string(),
|
||||
id: z.string(),
|
||||
operation: zAgentConfigRevisionOperation,
|
||||
previous_snapshot_id: z.string().nullish(),
|
||||
revision: z.int(),
|
||||
summary: z.string().nullish(),
|
||||
version_note: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentKnowledgeQueryMode
|
||||
*/
|
||||
@ -196,39 +354,67 @@ export const zRosterAgentCreatePayload = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* AgentConfigSnapshotDetailResponse
|
||||
*/
|
||||
export const zGetAgentsResponse = z.record(z.string(), z.unknown())
|
||||
export const zAgentConfigSnapshotDetailResponse = z.object({
|
||||
agent_id: z.string().nullish(),
|
||||
config_snapshot: zAgentSoulConfig,
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
id: z.string(),
|
||||
revisions: z.array(zAgentConfigRevisionResponse).optional(),
|
||||
summary: z.string().nullish(),
|
||||
version: z.int(),
|
||||
version_note: z.string().nullish(),
|
||||
})
|
||||
|
||||
export const zGetAgentsQuery = z.object({
|
||||
keyword: z.string().optional(),
|
||||
limit: z.int().gte(1).lte(100).optional().default(20),
|
||||
page: z.int().gte(1).optional().default(1),
|
||||
})
|
||||
|
||||
/**
|
||||
* Agent roster list
|
||||
*/
|
||||
export const zGetAgentsResponse = zAgentRosterListResponse
|
||||
|
||||
export const zPostAgentsBody = zRosterAgentCreatePayload
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent created
|
||||
*/
|
||||
export const zPostAgentsResponse = z.record(z.string(), z.unknown())
|
||||
export const zPostAgentsResponse = zAgentRosterResponse
|
||||
|
||||
export const zGetAgentsInviteOptionsQuery = z.object({
|
||||
app_id: z.string().optional(),
|
||||
keyword: z.string().optional(),
|
||||
limit: z.int().gte(1).lte(100).optional().default(20),
|
||||
page: z.int().gte(1).optional().default(1),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent invite options
|
||||
*/
|
||||
export const zGetAgentsInviteOptionsResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAgentsInviteOptionsResponse = zAgentInviteOptionsResponse
|
||||
|
||||
export const zDeleteAgentsByAgentIdPath = z.object({
|
||||
agent_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent archived
|
||||
*/
|
||||
export const zDeleteAgentsByAgentIdResponse = z.record(z.string(), z.unknown())
|
||||
export const zDeleteAgentsByAgentIdResponse = z.record(z.string(), z.never())
|
||||
|
||||
export const zGetAgentsByAgentIdPath = z.object({
|
||||
agent_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent detail
|
||||
*/
|
||||
export const zGetAgentsByAgentIdResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAgentsByAgentIdResponse = zAgentRosterResponse
|
||||
|
||||
export const zPatchAgentsByAgentIdBody = zRosterAgentUpdatePayload
|
||||
|
||||
@ -237,18 +423,18 @@ export const zPatchAgentsByAgentIdPath = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent updated
|
||||
*/
|
||||
export const zPatchAgentsByAgentIdResponse = z.record(z.string(), z.unknown())
|
||||
export const zPatchAgentsByAgentIdResponse = zAgentRosterResponse
|
||||
|
||||
export const zGetAgentsByAgentIdVersionsPath = z.object({
|
||||
agent_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent versions
|
||||
*/
|
||||
export const zGetAgentsByAgentIdVersionsResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAgentsByAgentIdVersionsResponse = zAgentConfigSnapshotListResponse
|
||||
|
||||
export const zGetAgentsByAgentIdVersionsByVersionIdPath = z.object({
|
||||
agent_id: z.string(),
|
||||
@ -256,6 +442,6 @@ export const zGetAgentsByAgentIdVersionsByVersionIdPath = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent version detail
|
||||
*/
|
||||
export const zGetAgentsByAgentIdVersionsByVersionIdResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAgentsByAgentIdVersionsByVersionIdResponse = zAgentConfigSnapshotDetailResponse
|
||||
|
||||
@ -352,6 +352,7 @@ import {
|
||||
zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunBody,
|
||||
zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunPath,
|
||||
zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponse,
|
||||
zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactBody,
|
||||
zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactPath,
|
||||
zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse,
|
||||
zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterBody,
|
||||
@ -3516,7 +3517,12 @@ export const post47 = oc
|
||||
path: '/apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer/impact',
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(z.object({ params: zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactPath }))
|
||||
.input(
|
||||
z.object({
|
||||
body: zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactBody,
|
||||
params: zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactPath,
|
||||
}),
|
||||
)
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse)
|
||||
|
||||
export const impact = {
|
||||
|
||||
@ -167,6 +167,14 @@ export type AdvancedChatWorkflowRunPayload = {
|
||||
query?: string
|
||||
}
|
||||
|
||||
export type AgentAppComposerResponse = {
|
||||
active_config_snapshot: AgentConfigSnapshotSummaryResponse
|
||||
agent: AgentComposerAgentResponse
|
||||
agent_soul: AgentSoulConfig
|
||||
save_options: Array<ComposerSaveStrategy>
|
||||
variant: string
|
||||
}
|
||||
|
||||
export type ComposerSavePayload = {
|
||||
agent_soul?: AgentSoulConfig
|
||||
binding?: ComposerBindingPayload
|
||||
@ -180,6 +188,18 @@ export type ComposerSavePayload = {
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AgentComposerCandidatesResponse = {
|
||||
allowed_node_job_candidates?: AgentComposerNodeJobCandidatesResponse
|
||||
allowed_soul_candidates?: AgentComposerSoulCandidatesResponse
|
||||
capabilities?: ComposerCandidateCapabilities
|
||||
variant: ComposerVariant
|
||||
}
|
||||
|
||||
export type AgentComposerValidateResponse = {
|
||||
errors?: Array<string>
|
||||
result: string
|
||||
}
|
||||
|
||||
export type AnnotationReplyPayload = {
|
||||
embedding_model_name: string
|
||||
embedding_provider_name: string
|
||||
@ -736,6 +756,28 @@ export type HumanInputDeliveryTestPayload = {
|
||||
}
|
||||
}
|
||||
|
||||
export type WorkflowAgentComposerResponse = {
|
||||
active_config_snapshot?: AgentConfigSnapshotSummaryResponse
|
||||
agent?: AgentComposerAgentResponse
|
||||
agent_soul: AgentSoulConfig
|
||||
app_id?: string | null
|
||||
binding?: AgentComposerBindingResponse
|
||||
effective_declared_outputs?: Array<DeclaredOutputConfig>
|
||||
impact_summary?: AgentComposerImpactResponse
|
||||
node_id?: string | null
|
||||
node_job: WorkflowNodeJobConfig
|
||||
save_options: Array<ComposerSaveStrategy>
|
||||
soul_lock: AgentComposerSoulLockResponse
|
||||
variant: string
|
||||
workflow_id?: string | null
|
||||
}
|
||||
|
||||
export type AgentComposerImpactResponse = {
|
||||
bindings?: Array<AgentComposerImpactBindingResponse>
|
||||
current_snapshot_id?: string | null
|
||||
workflow_node_count: number
|
||||
}
|
||||
|
||||
export type WorkflowRunNodeExecutionResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount
|
||||
@ -961,6 +1003,25 @@ export type AdvancedChatWorkflowRunForListResponse = {
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type AgentConfigSnapshotSummaryResponse = {
|
||||
agent_id?: string | null
|
||||
created_at?: string | null
|
||||
created_by?: string | null
|
||||
id: string
|
||||
summary?: string | null
|
||||
version: number
|
||||
version_note?: string | null
|
||||
}
|
||||
|
||||
export type AgentComposerAgentResponse = {
|
||||
active_config_snapshot_id?: string | null
|
||||
description: string
|
||||
id: string
|
||||
name: string
|
||||
scope: AgentScope
|
||||
status: AgentStatus
|
||||
}
|
||||
|
||||
export type AgentSoulConfig = {
|
||||
app_features?: {
|
||||
[key: string]: unknown
|
||||
@ -981,6 +1042,13 @@ export type AgentSoulConfig = {
|
||||
tools?: AgentSoulToolsConfig
|
||||
}
|
||||
|
||||
export type ComposerSaveStrategy
|
||||
= | 'node_job_only'
|
||||
| 'save_as_new_agent'
|
||||
| 'save_as_new_version'
|
||||
| 'save_to_current_version'
|
||||
| 'save_to_roster'
|
||||
|
||||
export type ComposerBindingPayload = {
|
||||
agent_id?: string | null
|
||||
binding_type: 'inline_agent' | 'roster_agent'
|
||||
@ -1003,13 +1071,6 @@ export type WorkflowNodeJobConfig = {
|
||||
workflow_prompt?: string
|
||||
}
|
||||
|
||||
export type ComposerSaveStrategy
|
||||
= | 'node_job_only'
|
||||
| 'save_as_new_agent'
|
||||
| 'save_as_new_version'
|
||||
| 'save_to_current_version'
|
||||
| 'save_to_roster'
|
||||
|
||||
export type ComposerSoulLockPayload = {
|
||||
locked?: boolean
|
||||
unlocked_from_version_id?: string | null
|
||||
@ -1017,6 +1078,38 @@ export type ComposerSoulLockPayload = {
|
||||
|
||||
export type ComposerVariant = 'agent_app' | 'workflow'
|
||||
|
||||
export type AgentComposerNodeJobCandidatesResponse = {
|
||||
declare_output_types?: Array<DeclaredOutputType>
|
||||
human_contacts?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
previous_node_outputs?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
}
|
||||
|
||||
export type AgentComposerSoulCandidatesResponse = {
|
||||
cli_tools?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
dify_tools?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
human_contacts?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
knowledge_datasets?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
skills_files?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
}
|
||||
|
||||
export type ComposerCandidateCapabilities = {
|
||||
human_roster_available?: boolean
|
||||
}
|
||||
|
||||
export type AnnotationHitHistory = {
|
||||
annotation_content?: string | null
|
||||
annotation_question?: string | null
|
||||
@ -1305,6 +1398,39 @@ export type PipelineVariableResponse = {
|
||||
variable: string
|
||||
}
|
||||
|
||||
export type AgentComposerBindingResponse = {
|
||||
agent_id?: string | null
|
||||
binding_type: WorkflowAgentBindingType
|
||||
current_snapshot_id?: string | null
|
||||
id: string
|
||||
node_id: string
|
||||
workflow_id: string
|
||||
}
|
||||
|
||||
export type DeclaredOutputConfig = {
|
||||
array_item?: DeclaredArrayItem
|
||||
check?: DeclaredOutputCheckConfig
|
||||
description?: string | null
|
||||
failure_strategy?: DeclaredOutputFailureStrategy
|
||||
file?: DeclaredOutputFileConfig
|
||||
id?: string | null
|
||||
name: string
|
||||
required?: boolean
|
||||
type: DeclaredOutputType
|
||||
}
|
||||
|
||||
export type AgentComposerSoulLockResponse = {
|
||||
can_unlock?: boolean
|
||||
locked: boolean
|
||||
reason?: string | null
|
||||
}
|
||||
|
||||
export type AgentComposerImpactBindingResponse = {
|
||||
app_id: string
|
||||
node_id: string
|
||||
workflow_id: string
|
||||
}
|
||||
|
||||
export type WorkflowDraftVariableWithoutValue = {
|
||||
description?: string
|
||||
edited?: boolean
|
||||
@ -1353,6 +1479,10 @@ export type WorkflowOnlineUser = {
|
||||
username: string
|
||||
}
|
||||
|
||||
export type AgentScope = 'roster' | 'workflow_only'
|
||||
|
||||
export type AgentStatus = 'active' | 'archived'
|
||||
|
||||
export type AppVariableConfig = {
|
||||
default?: unknown
|
||||
name: string
|
||||
@ -1433,20 +1563,10 @@ export type AgentSoulToolsConfig = {
|
||||
dify_tools?: Array<AgentSoulDifyToolConfig>
|
||||
}
|
||||
|
||||
export type DeclaredOutputConfig = {
|
||||
array_item?: DeclaredArrayItem
|
||||
check?: DeclaredOutputCheckConfig
|
||||
description?: string | null
|
||||
failure_strategy?: DeclaredOutputFailureStrategy
|
||||
file?: DeclaredOutputFileConfig
|
||||
id?: string | null
|
||||
name: string
|
||||
required?: boolean
|
||||
type: DeclaredOutputType
|
||||
}
|
||||
|
||||
export type WorkflowNodeJobMode = 'let_agent_figure_it_out' | 'tell_agent_what_to_do'
|
||||
|
||||
export type DeclaredOutputType = 'array' | 'boolean' | 'file' | 'number' | 'object' | 'string'
|
||||
|
||||
export type SimpleModelConfig = {
|
||||
model_dict?: JsonValue
|
||||
pre_prompt?: string | null
|
||||
@ -1515,29 +1635,7 @@ export type WorkflowRunForArchivedLogResponse = {
|
||||
triggered_from?: string | null
|
||||
}
|
||||
|
||||
export type AgentKnowledgeQueryMode = 'generated_query' | 'user_query'
|
||||
|
||||
export type AgentSoulModelCredentialRef = {
|
||||
id?: string | null
|
||||
provider?: string | null
|
||||
type: string
|
||||
}
|
||||
|
||||
export type AgentSoulDifyToolConfig = {
|
||||
credential_ref?: AgentSoulDifyToolCredentialRef
|
||||
credential_type?: 'api-key' | 'oauth2' | 'unauthorized'
|
||||
description?: string | null
|
||||
enabled?: boolean
|
||||
name?: string | null
|
||||
plugin_id?: string | null
|
||||
provider?: string | null
|
||||
provider_id?: string | null
|
||||
provider_type?: string
|
||||
runtime_parameters?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
tool_name: string
|
||||
}
|
||||
export type WorkflowAgentBindingType = 'inline_agent' | 'roster_agent'
|
||||
|
||||
export type DeclaredArrayItem = {
|
||||
description?: string | null
|
||||
@ -1566,7 +1664,29 @@ export type DeclaredOutputFileConfig = {
|
||||
mime_types?: Array<string>
|
||||
}
|
||||
|
||||
export type DeclaredOutputType = 'array' | 'boolean' | 'file' | 'number' | 'object' | 'string'
|
||||
export type AgentKnowledgeQueryMode = 'generated_query' | 'user_query'
|
||||
|
||||
export type AgentSoulModelCredentialRef = {
|
||||
id?: string | null
|
||||
provider?: string | null
|
||||
type: string
|
||||
}
|
||||
|
||||
export type AgentSoulDifyToolConfig = {
|
||||
credential_ref?: AgentSoulDifyToolCredentialRef
|
||||
credential_type?: 'api-key' | 'oauth2' | 'unauthorized'
|
||||
description?: string | null
|
||||
enabled?: boolean
|
||||
name?: string | null
|
||||
plugin_id?: string | null
|
||||
provider?: string | null
|
||||
provider_id?: string | null
|
||||
provider_type?: string
|
||||
runtime_parameters?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
tool_name: string
|
||||
}
|
||||
|
||||
export type UserActionConfig = {
|
||||
button_style?: ButtonStyle
|
||||
@ -1576,12 +1696,6 @@ export type UserActionConfig = {
|
||||
|
||||
export type FormInputConfig = unknown
|
||||
|
||||
export type AgentSoulDifyToolCredentialRef = {
|
||||
id?: string | null
|
||||
provider?: string | null
|
||||
type?: 'provider' | 'tool'
|
||||
}
|
||||
|
||||
export type OutputErrorStrategy = 'default_value' | 'fail_branch' | 'stop'
|
||||
|
||||
export type DeclaredOutputRetryConfig = {
|
||||
@ -1590,6 +1704,12 @@ export type DeclaredOutputRetryConfig = {
|
||||
retry_interval_ms?: number
|
||||
}
|
||||
|
||||
export type AgentSoulDifyToolCredentialRef = {
|
||||
id?: string | null
|
||||
provider?: string | null
|
||||
type?: 'provider' | 'tool'
|
||||
}
|
||||
|
||||
export type ButtonStyle = 'accent' | 'default' | 'ghost' | 'primary'
|
||||
|
||||
export type ParagraphInputConfig = {
|
||||
@ -2062,9 +2182,7 @@ export type GetAppsByAppIdAgentComposerData = {
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAgentComposerResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentAppComposerResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAgentComposerResponse
|
||||
@ -2080,9 +2198,7 @@ export type PutAppsByAppIdAgentComposerData = {
|
||||
}
|
||||
|
||||
export type PutAppsByAppIdAgentComposerResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentAppComposerResponse
|
||||
}
|
||||
|
||||
export type PutAppsByAppIdAgentComposerResponse
|
||||
@ -2098,9 +2214,7 @@ export type GetAppsByAppIdAgentComposerCandidatesData = {
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAgentComposerCandidatesResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentComposerCandidatesResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAgentComposerCandidatesResponse
|
||||
@ -2116,9 +2230,7 @@ export type PostAppsByAppIdAgentComposerValidateData = {
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdAgentComposerValidateResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentComposerValidateResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdAgentComposerValidateResponse
|
||||
@ -4515,9 +4627,7 @@ export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerData = {
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: WorkflowAgentComposerResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse
|
||||
@ -4534,9 +4644,7 @@ export type PutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerData = {
|
||||
}
|
||||
|
||||
export type PutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: WorkflowAgentComposerResponse
|
||||
}
|
||||
|
||||
export type PutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse
|
||||
@ -4553,16 +4661,14 @@ export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesData
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentComposerCandidatesResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponse
|
||||
= GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponses[keyof GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponses]
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactData = {
|
||||
body?: never
|
||||
body: ComposerSavePayload
|
||||
path: {
|
||||
app_id: string
|
||||
node_id: string
|
||||
@ -4572,9 +4678,7 @@ export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactData =
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentComposerImpactResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse
|
||||
@ -4591,9 +4695,7 @@ export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterD
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: WorkflowAgentComposerResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterResponse
|
||||
@ -4610,9 +4712,7 @@ export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateData
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateResponses = {
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
200: AgentComposerValidateResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateResponse
|
||||
|
||||
@ -77,6 +77,14 @@ export const zAdvancedChatWorkflowRunPayload = z.object({
|
||||
query: z.string().optional().default(''),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentComposerValidateResponse
|
||||
*/
|
||||
export const zAgentComposerValidateResponse = z.object({
|
||||
errors: z.array(z.string()).optional(),
|
||||
result: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationReplyPayload
|
||||
*/
|
||||
@ -730,12 +738,16 @@ export const zSite = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* ComposerBindingPayload
|
||||
* AgentConfigSnapshotSummaryResponse
|
||||
*/
|
||||
export const zComposerBindingPayload = z.object({
|
||||
export const zAgentConfigSnapshotSummaryResponse = z.object({
|
||||
agent_id: z.string().nullish(),
|
||||
binding_type: z.enum(['inline_agent', 'roster_agent']),
|
||||
current_snapshot_id: z.string().nullish(),
|
||||
created_at: z.string().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
id: z.string(),
|
||||
summary: z.string().nullish(),
|
||||
version: z.int(),
|
||||
version_note: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -749,6 +761,15 @@ export const zComposerSaveStrategy = z.enum([
|
||||
'save_to_roster',
|
||||
])
|
||||
|
||||
/**
|
||||
* ComposerBindingPayload
|
||||
*/
|
||||
export const zComposerBindingPayload = z.object({
|
||||
agent_id: z.string().nullish(),
|
||||
binding_type: z.enum(['inline_agent', 'roster_agent']),
|
||||
current_snapshot_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ComposerSoulLockPayload
|
||||
*/
|
||||
@ -762,6 +783,24 @@ export const zComposerSoulLockPayload = z.object({
|
||||
*/
|
||||
export const zComposerVariant = z.enum(['agent_app', 'workflow'])
|
||||
|
||||
/**
|
||||
* AgentComposerSoulCandidatesResponse
|
||||
*/
|
||||
export const zAgentComposerSoulCandidatesResponse = z.object({
|
||||
cli_tools: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
dify_tools: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
human_contacts: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
knowledge_datasets: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
skills_files: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ComposerCandidateCapabilities
|
||||
*/
|
||||
export const zComposerCandidateCapabilities = z.object({
|
||||
human_roster_available: z.boolean().optional().default(false),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationHitHistory
|
||||
*/
|
||||
@ -1235,6 +1274,33 @@ export const zWorkflowPaginationResponse = z.object({
|
||||
page: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentComposerSoulLockResponse
|
||||
*/
|
||||
export const zAgentComposerSoulLockResponse = z.object({
|
||||
can_unlock: z.boolean().optional().default(false),
|
||||
locked: z.boolean(),
|
||||
reason: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentComposerImpactBindingResponse
|
||||
*/
|
||||
export const zAgentComposerImpactBindingResponse = z.object({
|
||||
app_id: z.string(),
|
||||
node_id: z.string(),
|
||||
workflow_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentComposerImpactResponse
|
||||
*/
|
||||
export const zAgentComposerImpactResponse = z.object({
|
||||
bindings: z.array(zAgentComposerImpactBindingResponse).optional(),
|
||||
current_snapshot_id: z.string().nullish(),
|
||||
workflow_node_count: z.int(),
|
||||
})
|
||||
|
||||
export const zWorkflowDraftVariableWithoutValue = z.object({
|
||||
description: z.string().optional(),
|
||||
edited: z.boolean().optional(),
|
||||
@ -1475,6 +1541,32 @@ export const zWorkflowOnlineUsersResponse = z.object({
|
||||
data: z.array(zWorkflowOnlineUsersByApp),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentScope
|
||||
*
|
||||
* Visibility and lifecycle scope of an Agent record.
|
||||
*/
|
||||
export const zAgentScope = z.enum(['roster', 'workflow_only'])
|
||||
|
||||
/**
|
||||
* AgentStatus
|
||||
*
|
||||
* Soft lifecycle state for Agent records.
|
||||
*/
|
||||
export const zAgentStatus = z.enum(['active', 'archived'])
|
||||
|
||||
/**
|
||||
* AgentComposerAgentResponse
|
||||
*/
|
||||
export const zAgentComposerAgentResponse = z.object({
|
||||
active_config_snapshot_id: z.string().nullish(),
|
||||
description: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
scope: zAgentScope,
|
||||
status: zAgentStatus,
|
||||
})
|
||||
|
||||
/**
|
||||
* AppVariableConfig
|
||||
*/
|
||||
@ -1538,6 +1630,37 @@ export const zAgentSoulSkillsFilesConfig = z.object({
|
||||
*/
|
||||
export const zWorkflowNodeJobMode = z.enum(['let_agent_figure_it_out', 'tell_agent_what_to_do'])
|
||||
|
||||
/**
|
||||
* DeclaredOutputType
|
||||
*/
|
||||
export const zDeclaredOutputType = z.enum([
|
||||
'array',
|
||||
'boolean',
|
||||
'file',
|
||||
'number',
|
||||
'object',
|
||||
'string',
|
||||
])
|
||||
|
||||
/**
|
||||
* AgentComposerNodeJobCandidatesResponse
|
||||
*/
|
||||
export const zAgentComposerNodeJobCandidatesResponse = z.object({
|
||||
declare_output_types: z.array(zDeclaredOutputType).optional(),
|
||||
human_contacts: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
previous_node_outputs: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentComposerCandidatesResponse
|
||||
*/
|
||||
export const zAgentComposerCandidatesResponse = z.object({
|
||||
allowed_node_job_candidates: zAgentComposerNodeJobCandidatesResponse.optional(),
|
||||
allowed_soul_candidates: zAgentComposerSoulCandidatesResponse.optional(),
|
||||
capabilities: zComposerCandidateCapabilities.optional(),
|
||||
variant: zComposerVariant,
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleModelConfig
|
||||
*/
|
||||
@ -1725,6 +1848,63 @@ export const zWorkflowArchivedLogPaginationResponse = z.object({
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* WorkflowAgentBindingType
|
||||
*
|
||||
* How a workflow node is bound to an Agent.
|
||||
*/
|
||||
export const zWorkflowAgentBindingType = z.enum(['inline_agent', 'roster_agent'])
|
||||
|
||||
/**
|
||||
* AgentComposerBindingResponse
|
||||
*/
|
||||
export const zAgentComposerBindingResponse = z.object({
|
||||
agent_id: z.string().nullish(),
|
||||
binding_type: zWorkflowAgentBindingType,
|
||||
current_snapshot_id: z.string().nullish(),
|
||||
id: z.string(),
|
||||
node_id: z.string(),
|
||||
workflow_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredArrayItem
|
||||
*
|
||||
* Per-item shape for an ``array``-typed declared output.
|
||||
*
|
||||
* PRD §OUTPUT 配置框 keeps arrays one level deep on first version; nested arrays
|
||||
* are rejected so the runtime type checker and JSON Schema stay easy to reason
|
||||
* about. Stage 4 §4.2.
|
||||
*/
|
||||
export const zDeclaredArrayItem = z.object({
|
||||
description: z.string().nullish(),
|
||||
type: zDeclaredOutputType,
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredOutputCheckConfig
|
||||
*
|
||||
* File-output content check via a model-based comparison against a benchmark file.
|
||||
*
|
||||
* Per PRD §OUTPUT 配置框, output check is **file-only** and optional. Stage 4 §4.3.
|
||||
*/
|
||||
export const zDeclaredOutputCheckConfig = z.object({
|
||||
benchmark_file_ref: z.record(z.string(), z.unknown()).nullish(),
|
||||
enabled: z.boolean().optional().default(false),
|
||||
model_ref: z.record(z.string(), z.unknown()).nullish(),
|
||||
prompt: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredOutputFileConfig
|
||||
*
|
||||
* File-type output metadata. Both lists empty means "any file accepted".
|
||||
*/
|
||||
export const zDeclaredOutputFileConfig = z.object({
|
||||
extensions: z.array(z.string()).optional(),
|
||||
mime_types: z.array(z.string()).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentKnowledgeQueryMode
|
||||
*/
|
||||
@ -1763,124 +1943,8 @@ export const zAgentSoulModelConfig = z.object({
|
||||
plugin_id: z.string().min(1).max(255),
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredOutputCheckConfig
|
||||
*
|
||||
* File-output content check via a model-based comparison against a benchmark file.
|
||||
*
|
||||
* Per PRD §OUTPUT 配置框, output check is **file-only** and optional. Stage 4 §4.3.
|
||||
*/
|
||||
export const zDeclaredOutputCheckConfig = z.object({
|
||||
benchmark_file_ref: z.record(z.string(), z.unknown()).nullish(),
|
||||
enabled: z.boolean().optional().default(false),
|
||||
model_ref: z.record(z.string(), z.unknown()).nullish(),
|
||||
prompt: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredOutputFileConfig
|
||||
*
|
||||
* File-type output metadata. Both lists empty means "any file accepted".
|
||||
*/
|
||||
export const zDeclaredOutputFileConfig = z.object({
|
||||
extensions: z.array(z.string()).optional(),
|
||||
mime_types: z.array(z.string()).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* DeclaredOutputType
|
||||
*/
|
||||
export const zDeclaredOutputType = z.enum([
|
||||
'array',
|
||||
'boolean',
|
||||
'file',
|
||||
'number',
|
||||
'object',
|
||||
'string',
|
||||
])
|
||||
|
||||
/**
|
||||
* DeclaredArrayItem
|
||||
*
|
||||
* Per-item shape for an ``array``-typed declared output.
|
||||
*
|
||||
* PRD §OUTPUT 配置框 keeps arrays one level deep on first version; nested arrays
|
||||
* are rejected so the runtime type checker and JSON Schema stay easy to reason
|
||||
* about. Stage 4 §4.2.
|
||||
*/
|
||||
export const zDeclaredArrayItem = z.object({
|
||||
description: z.string().nullish(),
|
||||
type: zDeclaredOutputType,
|
||||
})
|
||||
|
||||
export const zFormInputConfig = z.unknown()
|
||||
|
||||
/**
|
||||
* AgentSoulDifyToolCredentialRef
|
||||
*
|
||||
* Reference to a stored Dify Plugin Tool credential.
|
||||
*
|
||||
* Secret values are resolved only at runtime. The legacy ``credential_id``
|
||||
* field is accepted by :class:`AgentSoulDifyToolConfig` and normalized here so
|
||||
* old Agent tool payloads can be read while new payloads stay explicit.
|
||||
*/
|
||||
export const zAgentSoulDifyToolCredentialRef = z.object({
|
||||
id: z.string().max(255).nullish(),
|
||||
provider: z.string().max(255).nullish(),
|
||||
type: z.enum(['provider', 'tool']).optional().default('tool'),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulDifyToolConfig
|
||||
*
|
||||
* One Dify Plugin Tool configured on Agent Soul.
|
||||
*
|
||||
* The API backend prepares this persisted product shape into
|
||||
* ``DifyPluginToolConfig`` before sending a run request to Agent backend.
|
||||
* ``provider_id`` keeps compatibility with existing Agent tool config payloads;
|
||||
* new callers should send ``plugin_id`` + ``provider`` when available.
|
||||
*/
|
||||
export const zAgentSoulDifyToolConfig = z.object({
|
||||
credential_ref: zAgentSoulDifyToolCredentialRef.optional(),
|
||||
credential_type: z.enum(['api-key', 'oauth2', 'unauthorized']).optional().default('api-key'),
|
||||
description: z.string().nullish(),
|
||||
enabled: z.boolean().optional().default(true),
|
||||
name: z.string().max(255).nullish(),
|
||||
plugin_id: z.string().max(255).nullish(),
|
||||
provider: z.string().max(255).nullish(),
|
||||
provider_id: z.string().max(255).nullish(),
|
||||
provider_type: z.string().optional().default('plugin'),
|
||||
runtime_parameters: z.record(z.string(), z.unknown()).optional(),
|
||||
tool_name: z.string().min(1).max(255),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulToolsConfig
|
||||
*/
|
||||
export const zAgentSoulToolsConfig = z.object({
|
||||
cli_tools: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
dify_tools: z.array(zAgentSoulDifyToolConfig).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulConfig
|
||||
*/
|
||||
export const zAgentSoulConfig = z.object({
|
||||
app_features: z.record(z.string(), z.unknown()).optional(),
|
||||
app_variables: z.array(zAppVariableConfig).optional(),
|
||||
env: zAgentSoulEnvConfig.optional(),
|
||||
human: zAgentSoulHumanConfig.optional(),
|
||||
knowledge: zAgentSoulKnowledgeConfig.optional(),
|
||||
memory: zAgentSoulMemoryConfig.optional(),
|
||||
misc_legacy: z.record(z.string(), z.unknown()).optional(),
|
||||
model: zAgentSoulModelConfig.optional(),
|
||||
prompt: zAgentSoulPromptConfig.optional(),
|
||||
sandbox: zAgentSoulSandboxConfig.optional(),
|
||||
schema_version: z.int().optional().default(1),
|
||||
skills_files: zAgentSoulSkillsFilesConfig.optional(),
|
||||
tools: zAgentSoulToolsConfig.optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* OutputErrorStrategy
|
||||
*
|
||||
@ -1951,6 +2015,83 @@ export const zWorkflowNodeJobConfig = z.object({
|
||||
workflow_prompt: z.string().optional().default(''),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulDifyToolCredentialRef
|
||||
*
|
||||
* Reference to a stored Dify Plugin Tool credential.
|
||||
*
|
||||
* Secret values are resolved only at runtime. The legacy ``credential_id``
|
||||
* field is accepted by :class:`AgentSoulDifyToolConfig` and normalized here so
|
||||
* old Agent tool payloads can be read while new payloads stay explicit.
|
||||
*/
|
||||
export const zAgentSoulDifyToolCredentialRef = z.object({
|
||||
id: z.string().max(255).nullish(),
|
||||
provider: z.string().max(255).nullish(),
|
||||
type: z.enum(['provider', 'tool']).optional().default('tool'),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulDifyToolConfig
|
||||
*
|
||||
* One Dify Plugin Tool configured on Agent Soul.
|
||||
*
|
||||
* The API backend prepares this persisted product shape into
|
||||
* ``DifyPluginToolConfig`` before sending a run request to Agent backend.
|
||||
* ``provider_id`` keeps compatibility with existing Agent tool config payloads;
|
||||
* new callers should send ``plugin_id`` + ``provider`` when available.
|
||||
*/
|
||||
export const zAgentSoulDifyToolConfig = z.object({
|
||||
credential_ref: zAgentSoulDifyToolCredentialRef.optional(),
|
||||
credential_type: z.enum(['api-key', 'oauth2', 'unauthorized']).optional().default('api-key'),
|
||||
description: z.string().nullish(),
|
||||
enabled: z.boolean().optional().default(true),
|
||||
name: z.string().max(255).nullish(),
|
||||
plugin_id: z.string().max(255).nullish(),
|
||||
provider: z.string().max(255).nullish(),
|
||||
provider_id: z.string().max(255).nullish(),
|
||||
provider_type: z.string().optional().default('plugin'),
|
||||
runtime_parameters: z.record(z.string(), z.unknown()).optional(),
|
||||
tool_name: z.string().min(1).max(255),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulToolsConfig
|
||||
*/
|
||||
export const zAgentSoulToolsConfig = z.object({
|
||||
cli_tools: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
dify_tools: z.array(zAgentSoulDifyToolConfig).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentSoulConfig
|
||||
*/
|
||||
export const zAgentSoulConfig = z.object({
|
||||
app_features: z.record(z.string(), z.unknown()).optional(),
|
||||
app_variables: z.array(zAppVariableConfig).optional(),
|
||||
env: zAgentSoulEnvConfig.optional(),
|
||||
human: zAgentSoulHumanConfig.optional(),
|
||||
knowledge: zAgentSoulKnowledgeConfig.optional(),
|
||||
memory: zAgentSoulMemoryConfig.optional(),
|
||||
misc_legacy: z.record(z.string(), z.unknown()).optional(),
|
||||
model: zAgentSoulModelConfig.optional(),
|
||||
prompt: zAgentSoulPromptConfig.optional(),
|
||||
sandbox: zAgentSoulSandboxConfig.optional(),
|
||||
schema_version: z.int().optional().default(1),
|
||||
skills_files: zAgentSoulSkillsFilesConfig.optional(),
|
||||
tools: zAgentSoulToolsConfig.optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AgentAppComposerResponse
|
||||
*/
|
||||
export const zAgentAppComposerResponse = z.object({
|
||||
active_config_snapshot: zAgentConfigSnapshotSummaryResponse,
|
||||
agent: zAgentComposerAgentResponse,
|
||||
agent_soul: zAgentSoulConfig,
|
||||
save_options: z.array(zComposerSaveStrategy),
|
||||
variant: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ComposerSavePayload
|
||||
*/
|
||||
@ -1967,6 +2108,25 @@ export const zComposerSavePayload = z.object({
|
||||
version_note: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* WorkflowAgentComposerResponse
|
||||
*/
|
||||
export const zWorkflowAgentComposerResponse = z.object({
|
||||
active_config_snapshot: zAgentConfigSnapshotSummaryResponse.optional(),
|
||||
agent: zAgentComposerAgentResponse.optional(),
|
||||
agent_soul: zAgentSoulConfig,
|
||||
app_id: z.string().nullish(),
|
||||
binding: zAgentComposerBindingResponse.optional(),
|
||||
effective_declared_outputs: z.array(zDeclaredOutputConfig).optional(),
|
||||
impact_summary: zAgentComposerImpactResponse.optional(),
|
||||
node_id: z.string().nullish(),
|
||||
node_job: zWorkflowNodeJobConfig,
|
||||
save_options: z.array(zComposerSaveStrategy),
|
||||
soul_lock: zAgentComposerSoulLockResponse,
|
||||
variant: z.string(),
|
||||
workflow_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ButtonStyle
|
||||
*
|
||||
@ -2412,9 +2572,9 @@ export const zGetAppsByAppIdAgentComposerPath = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent app composer state
|
||||
*/
|
||||
export const zGetAppsByAppIdAgentComposerResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAppsByAppIdAgentComposerResponse = zAgentAppComposerResponse
|
||||
|
||||
export const zPutAppsByAppIdAgentComposerBody = zComposerSavePayload
|
||||
|
||||
@ -2423,18 +2583,18 @@ export const zPutAppsByAppIdAgentComposerPath = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent app composer saved
|
||||
*/
|
||||
export const zPutAppsByAppIdAgentComposerResponse = z.record(z.string(), z.unknown())
|
||||
export const zPutAppsByAppIdAgentComposerResponse = zAgentAppComposerResponse
|
||||
|
||||
export const zGetAppsByAppIdAgentComposerCandidatesPath = z.object({
|
||||
app_id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent app composer candidates
|
||||
*/
|
||||
export const zGetAppsByAppIdAgentComposerCandidatesResponse = z.record(z.string(), z.unknown())
|
||||
export const zGetAppsByAppIdAgentComposerCandidatesResponse = zAgentComposerCandidatesResponse
|
||||
|
||||
export const zPostAppsByAppIdAgentComposerValidateBody = zComposerSavePayload
|
||||
|
||||
@ -2443,9 +2603,9 @@ export const zPostAppsByAppIdAgentComposerValidatePath = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Agent app composer validation result
|
||||
*/
|
||||
export const zPostAppsByAppIdAgentComposerValidateResponse = z.record(z.string(), z.unknown())
|
||||
export const zPostAppsByAppIdAgentComposerValidateResponse = zAgentComposerValidateResponse
|
||||
|
||||
export const zGetAppsByAppIdAgentLogsPath = z.object({
|
||||
app_id: z.string(),
|
||||
@ -3723,12 +3883,10 @@ export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerPath = z.obj
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer state
|
||||
*/
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse = z.record(
|
||||
z.string(),
|
||||
z.unknown(),
|
||||
)
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse
|
||||
= zWorkflowAgentComposerResponse
|
||||
|
||||
export const zPutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerBody = zComposerSavePayload
|
||||
|
||||
@ -3738,12 +3896,10 @@ export const zPutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerPath = z.obj
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer saved
|
||||
*/
|
||||
export const zPutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse = z.record(
|
||||
z.string(),
|
||||
z.unknown(),
|
||||
)
|
||||
export const zPutAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse
|
||||
= zWorkflowAgentComposerResponse
|
||||
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesPath = z.object({
|
||||
app_id: z.string(),
|
||||
@ -3751,12 +3907,13 @@ export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesPa
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer candidates
|
||||
*/
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponse = z.record(
|
||||
z.string(),
|
||||
z.unknown(),
|
||||
)
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidatesResponse
|
||||
= zAgentComposerCandidatesResponse
|
||||
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactBody
|
||||
= zComposerSavePayload
|
||||
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactPath = z.object({
|
||||
app_id: z.string(),
|
||||
@ -3764,12 +3921,10 @@ export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactPath
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer impact
|
||||
*/
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse = z.record(
|
||||
z.string(),
|
||||
z.unknown(),
|
||||
)
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse
|
||||
= zAgentComposerImpactResponse
|
||||
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterBody
|
||||
= zComposerSavePayload
|
||||
@ -3780,10 +3935,10 @@ export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRoste
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer saved to roster
|
||||
*/
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterResponse
|
||||
= z.record(z.string(), z.unknown())
|
||||
= zWorkflowAgentComposerResponse
|
||||
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateBody
|
||||
= zComposerSavePayload
|
||||
@ -3794,12 +3949,10 @@ export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidatePat
|
||||
})
|
||||
|
||||
/**
|
||||
* Success
|
||||
* Workflow agent composer validation result
|
||||
*/
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateResponse = z.record(
|
||||
z.string(),
|
||||
z.unknown(),
|
||||
)
|
||||
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateResponse
|
||||
= zAgentComposerValidateResponse
|
||||
|
||||
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdLastRunPath = z.object({
|
||||
app_id: z.string(),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { act, fireEvent, screen } from '@testing-library/react'
|
||||
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import { createSystemFeaturesWrapper } from '@/__tests__/utils/mock-system-features'
|
||||
import { renderWithNuqs } from '@/test/nuqs-testing'
|
||||
@ -13,9 +13,11 @@ const mockUseWorkflowOnlineUsers = vi.hoisted(() => vi.fn((_options: unknown) =>
|
||||
|
||||
const mockReplace = vi.fn()
|
||||
const mockRouter = { replace: mockReplace }
|
||||
let mockSearchParams = new URLSearchParams('')
|
||||
vi.mock('@/next/navigation', () => ({
|
||||
useRouter: () => mockRouter,
|
||||
useSearchParams: () => new URLSearchParams(''),
|
||||
usePathname: () => '/apps',
|
||||
useSearchParams: () => mockSearchParams,
|
||||
}))
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
@ -49,12 +51,10 @@ vi.mock('@/context/app-context', () => ({
|
||||
}))
|
||||
|
||||
const mockSetKeywords = vi.fn()
|
||||
const mockSetTagIDs = vi.fn()
|
||||
const mockSetIsCreatedByMe = vi.fn()
|
||||
const mockSetCategory = vi.fn()
|
||||
const mockQueryState = {
|
||||
category: 'all',
|
||||
tagIDs: [] as string[],
|
||||
keywords: '',
|
||||
isCreatedByMe: false,
|
||||
}
|
||||
@ -64,11 +64,20 @@ vi.mock('../hooks/use-apps-query-state', () => ({
|
||||
query: mockQueryState,
|
||||
setCategory: mockSetCategory,
|
||||
setKeywords: mockSetKeywords,
|
||||
setTagIDs: mockSetTagIDs,
|
||||
setIsCreatedByMe: mockSetIsCreatedByMe,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/features/tag-management/components/tag-filter', () => ({
|
||||
TagFilter: ({ value, onChange, onOpenTagManagement }: { value: string[], onChange: (value: string[]) => void, onOpenTagManagement: () => void }) => (
|
||||
<div>
|
||||
<button type="button" onClick={() => onChange(['tag-1'])}>common.tag.placeholder</button>
|
||||
<span data-testid="tag-filter-value">{value.join(',')}</span>
|
||||
<button type="button" onClick={onOpenTagManagement}>Manage tags</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
let mockOnDSLFileDropped: ((file: File) => void) | null = null
|
||||
let mockDragging = false
|
||||
vi.mock('../hooks/use-dsl-drag-drop', () => ({
|
||||
@ -190,9 +199,9 @@ vi.mock('../app-card', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('../new-app-card', () => ({
|
||||
default: React.forwardRef((_props: unknown, _ref: React.ForwardedRef<unknown>) => {
|
||||
default: (_props: { ref?: React.Ref<unknown> }) => {
|
||||
return React.createElement('div', { 'data-testid': 'new-app-card', 'role': 'button' }, 'New App Card')
|
||||
}),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('../empty', () => ({
|
||||
@ -230,6 +239,7 @@ beforeAll(() => {
|
||||
// Render helper wrapping with shared nuqs testing helper plus a seeded
|
||||
// systemFeatures cache so List can resolve its useSuspenseQuery.
|
||||
const renderList = (searchParams = '') => {
|
||||
mockSearchParams = new URLSearchParams(searchParams)
|
||||
const { wrapper: SystemFeaturesWrapper } = createSystemFeaturesWrapper({
|
||||
systemFeatures: { branding: { enabled: false } },
|
||||
})
|
||||
@ -253,7 +263,6 @@ describe('List', () => {
|
||||
mockServiceState.isLoading = false
|
||||
mockServiceState.isFetchingNextPage = false
|
||||
mockQueryState.category = 'all'
|
||||
mockQueryState.tagIDs = []
|
||||
mockQueryState.keywords = ''
|
||||
mockQueryState.isCreatedByMe = false
|
||||
mockUseWorkflowOnlineUsers.mockClear()
|
||||
@ -375,12 +384,12 @@ describe('List', () => {
|
||||
|
||||
describe('App List Query', () => {
|
||||
it('should build paged query input from active filters', () => {
|
||||
mockQueryState.tagIDs = ['tag-1']
|
||||
mockQueryState.keywords = 'sales'
|
||||
mockQueryState.isCreatedByMe = true
|
||||
mockQueryState.category = AppModeEnum.WORKFLOW
|
||||
|
||||
renderList()
|
||||
fireEvent.click(screen.getByText('common.tag.placeholder'))
|
||||
|
||||
const options = mockAppListInfiniteOptions.mock.calls.at(-1)?.[0] as AppListInfiniteOptions
|
||||
|
||||
@ -397,6 +406,17 @@ describe('List', () => {
|
||||
expect(options.getNextPageParam({ has_more: true, page: 2 })).toBe(3)
|
||||
expect(options.getNextPageParam({ has_more: false, page: 2 })).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should remove legacy tagIDs from URL while preserving other filters', async () => {
|
||||
renderList('?category=workflow&tagIDs=tag-1;tag-2&keywords=sales&isCreatedByMe=true')
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockReplace).toHaveBeenCalledWith(
|
||||
'/apps?category=workflow&keywords=sales&isCreatedByMe=true',
|
||||
{ scroll: false },
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Tag Filter', () => {
|
||||
|
||||
@ -5,6 +5,7 @@ import { APP_LIST_SEARCH_DEBOUNCE_MS } from '../../constants'
|
||||
import { useAppsQueryState } from '../use-apps-query-state'
|
||||
|
||||
const renderWithAdapter = (searchParams = '') => {
|
||||
// eslint-disable-next-line react/use-state -- renderHook executes a custom hook, not React.useState
|
||||
return renderHookWithNuqs(() => useAppsQueryState(), { searchParams })
|
||||
}
|
||||
|
||||
@ -18,13 +19,11 @@ describe('useAppsQueryState', () => {
|
||||
|
||||
expect(result.current.query).toEqual({
|
||||
category: 'all',
|
||||
tagIDs: [],
|
||||
keywords: '',
|
||||
isCreatedByMe: false,
|
||||
})
|
||||
expect(typeof result.current.setCategory).toBe('function')
|
||||
expect(typeof result.current.setKeywords).toBe('function')
|
||||
expect(typeof result.current.setTagIDs).toBe('function')
|
||||
expect(typeof result.current.setIsCreatedByMe).toBe('function')
|
||||
})
|
||||
|
||||
@ -35,7 +34,6 @@ describe('useAppsQueryState', () => {
|
||||
|
||||
expect(result.current.query).toEqual({
|
||||
category: AppModeEnum.WORKFLOW,
|
||||
tagIDs: ['tag1', 'tag2'],
|
||||
keywords: 'search term',
|
||||
isCreatedByMe: true,
|
||||
})
|
||||
@ -117,33 +115,6 @@ describe('useAppsQueryState', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should update tag filter URL state', async () => {
|
||||
const { result, onUrlUpdate } = renderWithAdapter()
|
||||
|
||||
act(() => {
|
||||
result.current.setTagIDs(['tag1', 'tag2'])
|
||||
})
|
||||
|
||||
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
||||
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
||||
expect(result.current.query.tagIDs).toEqual(['tag1', 'tag2'])
|
||||
expect(update.searchParams.get('tagIDs')).toBe('tag1;tag2')
|
||||
expect(update.options.history).toBe('push')
|
||||
})
|
||||
|
||||
it('should remove tagIDs from URL when empty', async () => {
|
||||
const { result, onUrlUpdate } = renderWithAdapter('?tagIDs=tag1;tag2')
|
||||
|
||||
act(() => {
|
||||
result.current.setTagIDs([])
|
||||
})
|
||||
|
||||
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
||||
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
||||
expect(result.current.query.tagIDs).toEqual([])
|
||||
expect(update.searchParams.has('tagIDs')).toBe(false)
|
||||
})
|
||||
|
||||
it('should update created-by-me URL state', async () => {
|
||||
const { result, onUrlUpdate } = renderWithAdapter()
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { debounce, parseAsArrayOf, parseAsBoolean, parseAsString, parseAsStringLiteral, useQueryStates } from 'nuqs'
|
||||
import { debounce, parseAsBoolean, parseAsString, parseAsStringLiteral, useQueryStates } from 'nuqs'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { AppModes } from '@/types/app'
|
||||
import { APP_LIST_SEARCH_DEBOUNCE_MS } from '../constants'
|
||||
@ -16,9 +16,6 @@ const appListQueryParsers = {
|
||||
category: parseAsStringLiteral(APP_LIST_CATEGORY_VALUES)
|
||||
.withDefault('all')
|
||||
.withOptions({ history: 'push' }),
|
||||
tagIDs: parseAsArrayOf(parseAsString, ';')
|
||||
.withDefault([])
|
||||
.withOptions({ history: 'push' }),
|
||||
keywords: parseAsString.withDefault('').withOptions({
|
||||
limitUrlUpdates: debounce(APP_LIST_SEARCH_DEBOUNCE_MS),
|
||||
}),
|
||||
@ -38,10 +35,6 @@ export function useAppsQueryState() {
|
||||
setQuery({ keywords })
|
||||
}, [setQuery])
|
||||
|
||||
const setTagIDs = useCallback((tagIDs: string[]) => {
|
||||
setQuery({ tagIDs })
|
||||
}, [setQuery])
|
||||
|
||||
const setIsCreatedByMe = useCallback((isCreatedByMe: boolean) => {
|
||||
setQuery({ isCreatedByMe })
|
||||
}, [setQuery])
|
||||
@ -50,7 +43,6 @@ export function useAppsQueryState() {
|
||||
query,
|
||||
setCategory,
|
||||
setKeywords,
|
||||
setTagIDs,
|
||||
setIsCreatedByMe,
|
||||
}), [query, setCategory, setKeywords, setTagIDs, setIsCreatedByMe])
|
||||
}), [query, setCategory, setKeywords, setIsCreatedByMe])
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import { useAppContext } from '@/context/app-context'
|
||||
import { TagFilter } from '@/features/tag-management/components/tag-filter'
|
||||
import { CheckModal } from '@/hooks/use-pay'
|
||||
import dynamic from '@/next/dynamic'
|
||||
import { usePathname, useRouter, useSearchParams } from '@/next/navigation'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { systemFeaturesQueryOptions } from '@/service/system-features'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
@ -44,15 +45,18 @@ const List: FC<Props> = ({
|
||||
const { t } = useTranslation()
|
||||
const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions())
|
||||
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator, isLoadingCurrentWorkspace } = useAppContext()
|
||||
const searchParams = useSearchParams()
|
||||
const pathname = usePathname()
|
||||
const { replace } = useRouter()
|
||||
|
||||
// eslint-disable-next-line react/use-state -- custom URL query hook, not React.useState
|
||||
const {
|
||||
query: { category, tagIDs, keywords, isCreatedByMe },
|
||||
query: { category, keywords, isCreatedByMe },
|
||||
setCategory,
|
||||
setKeywords,
|
||||
setTagIDs,
|
||||
setIsCreatedByMe,
|
||||
} = useAppsQueryState()
|
||||
const [tagIDs, setTagIDs] = useState<string[]>([])
|
||||
const debouncedKeywords = useDebounce(keywords, { wait: APP_LIST_SEARCH_DEBOUNCE_MS })
|
||||
const newAppCardRef = useRef<HTMLDivElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
@ -71,6 +75,16 @@ const List: FC<Props> = ({
|
||||
enabled: isCurrentWorkspaceEditor,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchParams.has('tagIDs'))
|
||||
return
|
||||
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
params.delete('tagIDs')
|
||||
const query = params.toString()
|
||||
replace(query ? `${pathname}?${query}` : pathname, { scroll: false })
|
||||
}, [pathname, replace, searchParams])
|
||||
|
||||
const appListQuery = useMemo<AppListQuery>(() => ({
|
||||
page: 1,
|
||||
limit: 30,
|
||||
|
||||
@ -3,6 +3,12 @@ import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { PluginSource, TaskStatus } from '@/app/components/plugins/types'
|
||||
import PluginItem from '../plugin-item'
|
||||
|
||||
vi.mock('@/app/components/base/icons/src/vender/solid/mediaAndDevices', () => ({
|
||||
MagicBox: ({ className }: { className?: string }) => (
|
||||
<svg data-testid="magic-box-icon" className={className} />
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/plugins/card/base/card-icon', () => ({
|
||||
default: ({ src, size }: { src: string, size: string }) => (
|
||||
<div data-testid="card-icon" data-src={src} data-size={size} />
|
||||
@ -108,6 +114,23 @@ describe('PluginItem', () => {
|
||||
expect(cardIcon).toHaveAttribute('data-src', 'https://example.com/icons/my-icon.svg')
|
||||
expect(cardIcon).toHaveAttribute('data-size', 'small')
|
||||
})
|
||||
|
||||
it('should show default tool icon when plugin icon is empty', () => {
|
||||
const { container } = render(
|
||||
<PluginItem
|
||||
plugin={createPlugin({ icon: '' })}
|
||||
getIconUrl={mockGetIconUrl}
|
||||
language="en_US"
|
||||
statusIcon={<span data-testid="status-icon" />}
|
||||
statusText="status"
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(mockGetIconUrl).not.toHaveBeenCalled()
|
||||
expect(screen.queryByTestId('card-icon')).not.toBeInTheDocument()
|
||||
expect(container.querySelector('[data-testid="magic-box-icon"]')).toHaveClass('size-8', 'text-text-tertiary')
|
||||
expect(screen.getByTestId('status-icon').parentElement).toHaveClass('absolute', '-bottom-0.5', '-right-0.5', 'z-10')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Props', () => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import type { PluginStatus } from '@/app/components/plugins/types'
|
||||
import type { Locale } from '@/i18n-config'
|
||||
import { MagicBox } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
||||
import CardIcon from '@/app/components/plugins/card/base/card-icon'
|
||||
|
||||
type PluginItemProps = {
|
||||
@ -24,13 +25,20 @@ const PluginItem: FC<PluginItemProps> = ({
|
||||
action,
|
||||
onClear,
|
||||
}) => {
|
||||
const hasPluginIcon = !!plugin.icon
|
||||
|
||||
return (
|
||||
<div className="group/item flex gap-1 rounded-lg p-2 hover:bg-state-base-hover">
|
||||
<div className="relative shrink-0 self-start">
|
||||
<CardIcon
|
||||
size="small"
|
||||
src={getIconUrl(plugin.icon)}
|
||||
/>
|
||||
{hasPluginIcon
|
||||
? (
|
||||
<CardIcon
|
||||
size="small"
|
||||
src={getIconUrl(plugin.icon)}
|
||||
/>
|
||||
)
|
||||
// eslint-disable-next-line hyoban/prefer-tailwind-icons -- Reuse the same MagicBox component as the marketplace install button.
|
||||
: <MagicBox className="size-8 text-text-tertiary" />}
|
||||
<div className="absolute -right-0.5 -bottom-0.5 z-10">
|
||||
{statusIcon}
|
||||
</div>
|
||||
|
||||
@ -6,10 +6,9 @@ import DevicePage from '../page'
|
||||
const mockPush = vi.fn()
|
||||
const mockReplace = vi.fn()
|
||||
const mockDeviceLookup = vi.fn()
|
||||
let mockSearchParams: Record<string, string | null> = {}
|
||||
|
||||
vi.mock('@/next/navigation', () => ({
|
||||
useSearchParams: () => ({ get: (key: string) => mockSearchParams[key] ?? null }),
|
||||
useSearchParams: () => ({ get: () => null }),
|
||||
useRouter: () => ({ push: mockPush, replace: mockReplace }),
|
||||
usePathname: () => '/device',
|
||||
}))
|
||||
@ -54,12 +53,6 @@ let MockDeviceFlowError: MockDeviceFlowErrorCtor
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
mockSearchParams = {}
|
||||
// router.replace(pathname) in the real app drops the query string; mirror
|
||||
// that so useSearchParams reflects the cleared URL on the next render.
|
||||
mockReplace.mockImplementation(() => {
|
||||
mockSearchParams = {}
|
||||
})
|
||||
mockUseQuery.mockReturnValue({ data: undefined, isError: false } as ReturnType<typeof useQuery>)
|
||||
const mod = await import('@/service/device-flow') as { DeviceFlowError: MockDeviceFlowErrorCtor }
|
||||
MockDeviceFlowError = mod.DeviceFlowError
|
||||
@ -117,41 +110,3 @@ describe('error_lookup_failed terminal state', () => {
|
||||
expect(screen.queryByText('Could not verify the code')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('sso_error inline banner on the code-entry page', () => {
|
||||
const SSO_BANNER_COPY = /identity is linked to a Dify account/i
|
||||
|
||||
it('shows the error banner with friendly copy when sso_error is present', async () => {
|
||||
mockSearchParams = { sso_error: 'email_belongs_to_dify_account' }
|
||||
render(<DevicePage />)
|
||||
expect(await screen.findByText(SSO_BANNER_COPY)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('keeps the code-entry screen visible (error on main page, not a separate view)', async () => {
|
||||
mockSearchParams = { sso_error: 'email_belongs_to_dify_account' }
|
||||
render(<DevicePage />)
|
||||
await screen.findByText(SSO_BANNER_COPY)
|
||||
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: /Continue/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not surface the raw backend error code', async () => {
|
||||
mockSearchParams = { sso_error: 'email_belongs_to_dify_account' }
|
||||
render(<DevicePage />)
|
||||
await screen.findByText(SSO_BANNER_COPY)
|
||||
expect(screen.queryByText('email_belongs_to_dify_account')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not scrub the param on mount (regression: error was wiped by router.replace)', async () => {
|
||||
mockSearchParams = { sso_error: 'email_belongs_to_dify_account' }
|
||||
render(<DevicePage />)
|
||||
await screen.findByText(SSO_BANNER_COPY)
|
||||
expect(mockReplace).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shows no banner when sso_error is absent', () => {
|
||||
render(<DevicePage />)
|
||||
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
||||
expect(screen.queryByText(SSO_BANNER_COPY)).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -14,7 +14,7 @@ import AuthorizeAccount from './components/authorize-account'
|
||||
import AuthorizeSSO from './components/authorize-sso'
|
||||
import Chooser from './components/chooser'
|
||||
import CodeInput from './components/code-input'
|
||||
import { classifyLookupError, ssoErrorCopy } from './utils/error-copy'
|
||||
import { classifyLookupError } from './utils/error-copy'
|
||||
import { isValidUserCode } from './utils/user-code'
|
||||
|
||||
type View
|
||||
@ -33,7 +33,6 @@ export default function DevicePage() {
|
||||
const pathname = usePathname()
|
||||
const urlUserCode = (searchParams.get('user_code') || '').trim().toUpperCase()
|
||||
const ssoVerified = searchParams.get('sso_verified') === '1'
|
||||
const ssoError = searchParams.get('sso_error') || ''
|
||||
|
||||
const [typed, setTyped] = useState('')
|
||||
const [view, setView] = useState<View>({ kind: 'code_entry' })
|
||||
@ -126,12 +125,6 @@ export default function DevicePage() {
|
||||
<>
|
||||
{view.kind === 'code_entry' && (
|
||||
<div className="flex flex-col gap-5">
|
||||
{ssoError && (
|
||||
<div className="flex items-start gap-2 rounded-lg bg-state-destructive-hover p-3">
|
||||
<span className="mt-0.5 i-ri-close-circle-line h-4 w-4 shrink-0 text-util-colors-red-red-600" />
|
||||
<p className="text-sm text-text-destructive">{ssoErrorCopy(ssoError)}</p>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-text-primary">Authorize Dify CLI</h1>
|
||||
<p className="mt-2 text-sm text-text-secondary">
|
||||
|
||||
@ -30,18 +30,6 @@ export function approveErrorCopy(err: unknown): string {
|
||||
return DEFAULT_MESSAGE
|
||||
}
|
||||
|
||||
// SSO-branch failures arrive as a `sso_error` query param set by the backend
|
||||
// (oauth_device_sso sso-complete) when it redirects back to /device.
|
||||
const SSO_ERROR_COPY: Record<string, string> = {
|
||||
email_belongs_to_dify_account: 'This identity is linked to a Dify account. Use “Sign in with Dify account” instead.',
|
||||
}
|
||||
|
||||
const DEFAULT_SSO_ERROR_MESSAGE = 'Single sign-on could not be completed. Try again.'
|
||||
|
||||
export function ssoErrorCopy(code: string): string {
|
||||
return SSO_ERROR_COPY[code] ?? DEFAULT_SSO_ERROR_MESSAGE
|
||||
}
|
||||
|
||||
export type LookupOutcome = 'expired' | 'rate_limited' | 'failed'
|
||||
|
||||
export function classifyLookupError(err: unknown): LookupOutcome {
|
||||
|
||||
@ -18,6 +18,10 @@ vi.mock('@/next/navigation', () => ({
|
||||
useSearchParams: vi.fn(() => new URLSearchParams()),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/billing/pricing', () => ({
|
||||
default: () => <div>billing.plansCommon.mostPopular</div>,
|
||||
}))
|
||||
|
||||
const mockUseProviderContext = vi.fn()
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
useProviderContext: () => mockUseProviderContext(),
|
||||
|
||||
Reference in New Issue
Block a user