fix(agent): add agent app duplicate endpoint (#37571)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
zyssyz123 2026-06-17 16:09:47 +08:00 committed by GitHub
parent 872b5a081f
commit 912c0fa8d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 610 additions and 17 deletions

View File

@ -12,6 +12,7 @@ from controllers.console.app.app import (
AppListQuery,
AppPagination,
AppPartial,
CopyAppPayload,
UpdateAppPayload,
_normalize_app_list_query_args,
)
@ -134,6 +135,7 @@ register_schema_models(
console_ns,
AgentAppCreatePayload,
AgentAppUpdatePayload,
CopyAppPayload,
AgentInviteOptionsQuery,
AgentLogsQuery,
AgentStatisticsQuery,
@ -348,6 +350,34 @@ class AgentAppApi(Resource):
return "", 204
@console_ns.route("/agent/<uuid:agent_id>/copy")
class AgentAppCopyApi(Resource):
@console_ns.expect(console_ns.models[CopyAppPayload.__name__])
@console_ns.response(201, "Agent app copied successfully", console_ns.models[AppDetailWithSite.__name__])
@console_ns.response(403, "Insufficient permissions")
@console_ns.response(400, "Invalid request parameters")
@setup_required
@login_required
@account_initialization_required
@cloud_edition_billing_resource_check("apps")
@edit_permission_required
@with_current_user
@with_current_tenant_id
def post(self, tenant_id: str, current_user: Account, agent_id: UUID):
args = CopyAppPayload.model_validate(console_ns.payload or {})
copied_app = _agent_roster_service().duplicate_agent_app(
tenant_id=tenant_id,
agent_id=str(agent_id),
account=current_user,
name=args.name,
description=args.description,
icon_type=args.icon_type,
icon=args.icon,
icon_background=args.icon_background,
)
return _serialize_agent_app_detail(copied_app), 201
@console_ns.route("/agent/invite-options")
class AgentInviteOptionsApi(Resource):
@console_ns.doc(params=query_params_from_model(AgentInviteOptionsQuery))

View File

@ -508,6 +508,27 @@ Stop a running Agent App chat message generation
| ---- | ----------- | ------ |
| 200 | Agent app composer validation result | **application/json**: [AgentComposerValidateResponse](#agentcomposervalidateresponse)<br> |
### [POST] /agent/{agent_id}/copy
#### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ------ |
| agent_id | path | | Yes | string |
#### Request Body
| Required | Schema |
| -------- | ------ |
| Yes | **application/json**: [CopyAppPayload](#copyapppayload)<br> |
#### Responses
| Code | Description | Schema |
| ---- | ----------- | ------ |
| 201 | Agent app copied successfully | **application/json**: [AppDetailWithSite](#appdetailwithsite)<br> |
| 400 | Invalid request parameters | |
| 403 | Insufficient permissions | |
### [GET] /agent/{agent_id}/drive/files
List agent drive entries for an Agent App

View File

@ -19,7 +19,7 @@ from models.agent import (
)
from models.agent_config_entities import AgentSoulConfig
from models.enums import AppStatus
from models.model import App, AppMode
from models.model import App, AppMode, IconType
from models.workflow import Workflow
from services.agent.agent_soul_state import agent_soul_has_model
from services.agent.composer_validator import ComposerConfigValidator
@ -29,7 +29,10 @@ from services.agent.errors import (
AgentNotFoundError,
AgentVersionNotFoundError,
)
from services.app_service import AppService, CreateAppParams
from services.enterprise.enterprise_service import EnterpriseService
from services.entities.agent_entities import RosterAgentCreatePayload, RosterAgentUpdatePayload
from services.feature_service import FeatureService
class AgentReferencingWorkflow(TypedDict):
@ -48,6 +51,28 @@ class AgentReferencingWorkflow(TypedDict):
class AgentRosterService:
_APP_MODEL_CONFIG_COPY_FIELDS = (
"opening_statement",
"suggested_questions",
"suggested_questions_after_answer",
"speech_to_text",
"text_to_speech",
"more_like_this",
"model",
"user_input_form",
"dataset_query_variable",
"pre_prompt",
"agent_mode",
"sensitive_word_avoidance",
"retriever_resource",
"prompt_type",
"chat_prompt_config",
"completion_prompt_config",
"dataset_configs",
"external_data_tools",
"file_upload",
)
def __init__(self, session: Any):
self._session = session
@ -418,6 +443,142 @@ class AgentRosterService:
raise AgentNotFoundError()
return app
def duplicate_agent_app(
self,
*,
tenant_id: str,
agent_id: str,
account: Any,
name: str | None = None,
description: str | None = None,
icon_type: Any = None,
icon: str | None = None,
icon_background: str | None = None,
) -> App:
source_app = self.get_agent_app_model(tenant_id=tenant_id, agent_id=agent_id)
source_agent = self.get_app_backing_agent(tenant_id=tenant_id, app_id=source_app.id)
if source_agent is None:
raise AgentNotFoundError()
copied_name = name or self._next_duplicate_agent_name(tenant_id=tenant_id, base_name=source_app.name)
copied_description = description if description is not None else source_app.description
copied_icon_type = icon_type if icon_type is not None else source_app.icon_type
copied_icon = icon if icon is not None else source_app.icon
copied_icon_background = icon_background if icon_background is not None else source_app.icon_background
target_app = AppService().create_app(
tenant_id,
CreateAppParams(
name=copied_name,
description=copied_description,
mode="agent",
agent_role=source_agent.role or "",
icon_type=self._normalize_app_icon_type(copied_icon_type),
icon=copied_icon,
icon_background=copied_icon_background,
api_rph=source_app.api_rph or 0,
api_rpm=source_app.api_rpm or 0,
max_active_requests=source_app.max_active_requests,
),
account,
)
target_app.enable_site = source_app.enable_site
target_app.enable_api = source_app.enable_api
target_app.use_icon_as_answer_icon = source_app.use_icon_as_answer_icon
target_app.tracing = source_app.tracing
self._copy_app_model_config(source_app=source_app, target_app=target_app, account_id=account.id)
self._copy_agent_active_snapshot(
tenant_id=tenant_id,
source_agent=source_agent,
target_app_id=target_app.id,
account_id=account.id,
)
self._session.commit()
if FeatureService.get_system_features().webapp_auth.enabled:
try:
original_settings = EnterpriseService.WebAppAuth.get_app_access_mode_by_id(source_app.id)
access_mode = original_settings.access_mode
except Exception:
access_mode = "public"
EnterpriseService.WebAppAuth.update_app_access_mode(target_app.id, access_mode)
return target_app
@staticmethod
def _normalize_app_icon_type(icon_type: IconType | str | None) -> str | None:
if icon_type is None:
return None
if isinstance(icon_type, IconType):
return icon_type.value
return icon_type
def _copy_app_model_config(self, *, source_app: App, target_app: App, account_id: str) -> None:
source_config = source_app.app_model_config
target_config = target_app.app_model_config
if source_config is None or target_config is None:
return
for field_name in self._APP_MODEL_CONFIG_COPY_FIELDS:
setattr(target_config, field_name, getattr(source_config, field_name))
target_config.updated_by = account_id
def _copy_agent_active_snapshot(
self,
*,
tenant_id: str,
source_agent: Agent,
target_app_id: str,
account_id: str,
) -> None:
target_agent = self.get_app_backing_agent(tenant_id=tenant_id, app_id=target_app_id)
if target_agent is None:
raise AgentNotFoundError()
source_version = self._get_version(
tenant_id=tenant_id,
agent_id=source_agent.id,
version_id=source_agent.active_config_snapshot_id,
)
target_version = self._get_version(
tenant_id=tenant_id,
agent_id=target_agent.id,
version_id=target_agent.active_config_snapshot_id,
)
target_version.config_snapshot = AgentSoulConfig.model_validate(source_version.config_snapshot_dict)
target_version.summary = source_version.summary
target_version.version_note = source_version.version_note
target_version.created_by = account_id
target_agent.active_config_has_model = agent_soul_has_model(target_version.config_snapshot)
target_agent.updated_by = account_id
def _next_duplicate_agent_name(self, *, tenant_id: str, base_name: str) -> str:
suffix = " copy"
max_base_len = 255 - len(suffix)
first_candidate = f"{base_name[:max_base_len]}{suffix}"
candidates = [first_candidate]
for index in range(2, 100):
numbered_suffix = f" copy {index}"
candidates.append(f"{base_name[: 255 - len(numbered_suffix)]}{numbered_suffix}")
existing_names = set(
self._session.scalars(
select(Agent.name).where(
Agent.tenant_id == tenant_id,
Agent.scope == AgentScope.ROSTER,
Agent.status == AgentStatus.ACTIVE,
Agent.name.in_(candidates),
)
).all()
)
for candidate in candidates:
if candidate not in existing_names:
return candidate
return f"{base_name[:245]} copy {int(naive_utc_now().timestamp())}"
def list_workflows_referencing_app_agent(self, *, tenant_id: str, app_id: str) -> list[AgentReferencingWorkflow]:
"""List the workflow apps that reference this Agent App's bound Agent.

View File

@ -21,6 +21,7 @@ from controllers.console.agent.composer import (
)
from controllers.console.agent.roster import (
AgentAppApi,
AgentAppCopyApi,
AgentAppListApi,
AgentInviteOptionsApi,
AgentLogsApi,
@ -140,6 +141,7 @@ def test_agent_v2_console_routes_are_agent_id_first() -> None:
"/agent/<uuid:agent_id>/composer/validate",
"/agent/<uuid:agent_id>/composer/candidates",
"/agent/<uuid:agent_id>/features",
"/agent/<uuid:agent_id>/copy",
"/agent/<uuid:agent_id>/referencing-workflows",
"/agent/<uuid:agent_id>/drive/files",
"/agent/<uuid:agent_id>/sandbox/files",
@ -347,6 +349,52 @@ def test_agent_app_detail_update_delete_resolve_app_from_agent_id(
assert captured["delete"] is app_model
def test_agent_app_copy_uses_agent_id_and_returns_agent_detail(
app: Flask, monkeypatch: pytest.MonkeyPatch, account_id: str
) -> None:
agent_id = "00000000-0000-0000-0000-000000000001"
current_user = SimpleNamespace(id=account_id)
copied_app = _app_detail_obj(id="copied-app", bound_agent_id="copied-agent")
captured: dict[str, object] = {}
class FakeRosterService:
def duplicate_agent_app(self, **kwargs: object) -> object:
captured.update(kwargs)
return copied_app
monkeypatch.setattr(roster_controller, "_agent_roster_service", lambda: FakeRosterService())
monkeypatch.setattr(
roster_controller,
"_serialize_agent_app_detail",
lambda app_model: {"id": "copied-agent", "app_id": app_model.id, "name": app_model.name},
)
with app.test_request_context(
"/console/api/agent/00000000-0000-0000-0000-000000000001/copy",
json={
"name": "Iris copy",
"description": "Copied",
"icon_type": "emoji",
"icon": "sparkles",
"icon_background": "#fff",
},
):
copied, status = unwrap(AgentAppCopyApi.post)(AgentAppCopyApi(), "tenant-1", current_user, agent_id)
assert status == 201
assert copied == {"id": "copied-agent", "app_id": "copied-app", "name": "Iris"}
assert captured == {
"tenant_id": "tenant-1",
"agent_id": agent_id,
"account": current_user,
"name": "Iris copy",
"description": "Copied",
"icon_type": "emoji",
"icon": "sparkles",
"icon_background": "#fff",
}
def test_invite_options_get_parses_app_id(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
captured: dict[str, object] = {}

View File

@ -23,6 +23,7 @@ from models.agent_config_entities import (
DeclaredOutputType,
WorkflowNodeJobConfig,
)
from models.model import IconType
from models.workflow import Workflow
from services.agent import composer_service, roster_service
from services.agent.agent_soul_state import agent_soul_has_model
@ -1309,6 +1310,267 @@ class TestAgentAppBackingAgent:
with pytest.raises(roster_service.AgentNotFoundError):
service.get_agent_app_model(tenant_id="tenant-1", agent_id="agent-x")
def test_duplicate_agent_app_copies_app_config_and_active_soul(self, monkeypatch):
source_config = SimpleNamespace(
opening_statement="hello",
suggested_questions='["q1"]',
suggested_questions_after_answer='{"enabled": true}',
speech_to_text='{"enabled": false}',
text_to_speech='{"enabled": false}',
more_like_this='{"enabled": false}',
model=None,
user_input_form=None,
dataset_query_variable=None,
pre_prompt=None,
agent_mode=None,
sensitive_word_avoidance=None,
retriever_resource='{"enabled": true}',
prompt_type="simple",
chat_prompt_config=None,
completion_prompt_config=None,
dataset_configs=None,
external_data_tools=None,
file_upload='{"image": {"enabled": true}}',
)
target_config = SimpleNamespace(**dict.fromkeys(AgentRosterService._APP_MODEL_CONFIG_COPY_FIELDS))
source_app = SimpleNamespace(
id="source-app",
tenant_id="tenant-1",
name="Iris",
description="source desc",
icon_type="emoji",
icon="robot",
icon_background="#fff",
api_rph=1,
api_rpm=2,
max_active_requests=3,
enable_site=False,
enable_api=True,
use_icon_as_answer_icon=True,
tracing="{}",
app_model_config=source_config,
)
target_app = SimpleNamespace(
id="target-app",
app_model_config=target_config,
enable_site=True,
enable_api=True,
use_icon_as_answer_icon=False,
tracing=None,
)
source_agent = Agent(
id="source-agent",
tenant_id="tenant-1",
name="Iris",
description="source desc",
role="Analyst",
agent_kind=AgentKind.DIFY_AGENT,
scope=AgentScope.ROSTER,
source=AgentSource.AGENT_APP,
status=AgentStatus.ACTIVE,
app_id="source-app",
active_config_snapshot_id="source-version",
active_config_has_model=True,
)
target_agent = Agent(
id="target-agent",
tenant_id="tenant-1",
name="Iris copy",
description="source desc",
role="Analyst",
agent_kind=AgentKind.DIFY_AGENT,
scope=AgentScope.ROSTER,
source=AgentSource.AGENT_APP,
status=AgentStatus.ACTIVE,
app_id="target-app",
active_config_snapshot_id="target-version",
)
source_version = AgentConfigSnapshot(
id="source-version",
tenant_id="tenant-1",
agent_id="source-agent",
version=1,
config_snapshot=_agent_soul_with_model(),
summary="configured",
version_note="v1",
created_by="account-1",
)
target_version = AgentConfigSnapshot(
id="target-version",
tenant_id="tenant-1",
agent_id="target-agent",
version=1,
config_snapshot=AgentSoulConfig(),
created_by="account-1",
)
session = FakeSession(
scalar=[source_agent, source_app, source_agent, target_agent, source_version, target_version],
scalars=[[]],
)
captured: dict[str, object] = {}
class FakeAppService:
def create_app(self, tenant_id: str, params, account: object) -> object:
captured["tenant_id"] = tenant_id
captured["params"] = params
captured["account"] = account
return target_app
monkeypatch.setattr(roster_service, "AppService", FakeAppService)
monkeypatch.setattr(
roster_service.FeatureService,
"get_system_features",
lambda: SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)),
)
account = SimpleNamespace(id="account-1")
duplicated = AgentRosterService(session).duplicate_agent_app(
tenant_id="tenant-1",
agent_id="source-agent",
account=account,
)
assert duplicated is target_app
params = captured["params"]
assert params.name == "Iris copy"
assert params.mode == "agent"
assert params.agent_role == "Analyst"
assert target_app.enable_site is False
assert target_app.enable_api is True
assert target_app.use_icon_as_answer_icon is True
assert target_app.tracing == "{}"
assert target_config.opening_statement == "hello"
assert target_config.file_upload == '{"image": {"enabled": true}}'
assert target_config.updated_by == "account-1"
assert target_version.config_snapshot.model.model == "gpt-4o"
assert target_version.summary == "configured"
assert target_version.version_note == "v1"
assert target_agent.active_config_has_model is True
assert target_agent.updated_by == "account-1"
assert session.commits == 1
def test_duplicate_agent_app_inherits_webapp_access_mode(self, monkeypatch):
source_app = SimpleNamespace(
id="source-app",
tenant_id="tenant-1",
name="Iris",
description="source desc",
icon_type=None,
icon="robot",
icon_background="#fff",
api_rph=1,
api_rpm=2,
max_active_requests=3,
enable_site=True,
enable_api=True,
use_icon_as_answer_icon=False,
tracing=None,
)
source_agent = SimpleNamespace(id="source-agent", role="Analyst")
target_app = SimpleNamespace(id="target-app")
session = FakeSession()
service = AgentRosterService(session)
monkeypatch.setattr(service, "get_agent_app_model", lambda **_: source_app)
monkeypatch.setattr(service, "get_app_backing_agent", lambda **_: source_agent)
monkeypatch.setattr(service, "_copy_app_model_config", lambda **_: None)
monkeypatch.setattr(service, "_copy_agent_active_snapshot", lambda **_: None)
monkeypatch.setattr(service, "_next_duplicate_agent_name", lambda **_: "Iris copy")
class FakeAppService:
def create_app(self, tenant_id: str, params, account: object) -> object:
return target_app
access_mode_updates = []
class FakeWebAppAuth:
@classmethod
def get_app_access_mode_by_id(cls, app_id: str) -> object:
return SimpleNamespace(access_mode="private")
@classmethod
def update_app_access_mode(cls, app_id: str, access_mode: str) -> None:
access_mode_updates.append((app_id, access_mode))
monkeypatch.setattr(roster_service, "AppService", FakeAppService)
monkeypatch.setattr(
roster_service.FeatureService,
"get_system_features",
lambda: SimpleNamespace(webapp_auth=SimpleNamespace(enabled=True)),
)
monkeypatch.setattr(roster_service.EnterpriseService, "WebAppAuth", FakeWebAppAuth)
duplicated = service.duplicate_agent_app(
tenant_id="tenant-1",
agent_id="source-agent",
account=SimpleNamespace(id="account-1"),
)
assert duplicated is target_app
assert access_mode_updates == [("target-app", "private")]
def test_duplicate_agent_app_falls_back_to_public_access_mode(self, monkeypatch):
source_app = SimpleNamespace(
id="source-app",
tenant_id="tenant-1",
name="Iris",
description="source desc",
icon_type=IconType.EMOJI,
icon="robot",
icon_background="#fff",
api_rph=1,
api_rpm=2,
max_active_requests=3,
enable_site=True,
enable_api=True,
use_icon_as_answer_icon=False,
tracing=None,
)
source_agent = SimpleNamespace(id="source-agent", role="Analyst")
target_app = SimpleNamespace(id="target-app")
session = FakeSession()
service = AgentRosterService(session)
monkeypatch.setattr(service, "get_agent_app_model", lambda **_: source_app)
monkeypatch.setattr(service, "get_app_backing_agent", lambda **_: source_agent)
monkeypatch.setattr(service, "_copy_app_model_config", lambda **_: None)
monkeypatch.setattr(service, "_copy_agent_active_snapshot", lambda **_: None)
monkeypatch.setattr(service, "_next_duplicate_agent_name", lambda **_: "Iris copy")
class FakeAppService:
def create_app(self, tenant_id: str, params, account: object) -> object:
return target_app
access_mode_updates = []
class FakeWebAppAuth:
@classmethod
def get_app_access_mode_by_id(cls, app_id: str) -> object:
raise ValueError("not found")
@classmethod
def update_app_access_mode(cls, app_id: str, access_mode: str) -> None:
access_mode_updates.append((app_id, access_mode))
monkeypatch.setattr(roster_service, "AppService", FakeAppService)
monkeypatch.setattr(
roster_service.FeatureService,
"get_system_features",
lambda: SimpleNamespace(webapp_auth=SimpleNamespace(enabled=True)),
)
monkeypatch.setattr(roster_service.EnterpriseService, "WebAppAuth", FakeWebAppAuth)
service.duplicate_agent_app(
tenant_id="tenant-1",
agent_id="source-agent",
account=SimpleNamespace(id="account-1"),
)
assert access_mode_updates == [("target-app", "public")]
def test_normalize_app_icon_type(self):
assert AgentRosterService._normalize_app_icon_type(None) is None
assert AgentRosterService._normalize_app_icon_type(IconType.EMOJI) == "emoji"
assert AgentRosterService._normalize_app_icon_type("image") == "image"
class TestListWorkflowsReferencingAppAgent:
def test_groups_bindings_by_workflow_app_and_sorts_by_name(self):

View File

@ -61,6 +61,9 @@ import {
zPostAgentByAgentIdComposerValidateBody,
zPostAgentByAgentIdComposerValidatePath,
zPostAgentByAgentIdComposerValidateResponse,
zPostAgentByAgentIdCopyBody,
zPostAgentByAgentIdCopyPath,
zPostAgentByAgentIdCopyResponse,
zPostAgentByAgentIdFeaturesBody,
zPostAgentByAgentIdFeaturesPath,
zPostAgentByAgentIdFeaturesResponse,
@ -239,6 +242,22 @@ export const composer = {
validate,
}
export const post3 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postAgentByAgentIdCopy',
path: '/agent/{agent_id}/copy',
successStatus: 201,
tags: ['console'],
})
.input(z.object({ body: zPostAgentByAgentIdCopyBody, params: zPostAgentByAgentIdCopyPath }))
.output(zPostAgentByAgentIdCopyResponse)
export const copy = {
post: post3,
}
/**
* Time-limited external signed URL for one Agent App drive value
*/
@ -320,7 +339,7 @@ export const drive = {
/**
* Update an Agent App's presentation features (opener, follow-up, citations, ...)
*/
export const post3 = oc
export const post4 = oc
.route({
description: 'Update an Agent App\'s presentation features (opener, follow-up, citations, ...)',
inputStructure: 'detailed',
@ -335,13 +354,13 @@ export const post3 = oc
.output(zPostAgentByAgentIdFeaturesResponse)
export const features = {
post: post3,
post: post4,
}
/**
* Create or update Agent App message feedback
*/
export const post4 = oc
export const post5 = oc
.route({
description: 'Create or update Agent App message feedback',
inputStructure: 'detailed',
@ -356,7 +375,7 @@ export const post4 = oc
.output(zPostAgentByAgentIdFeedbacksResponse)
export const feedbacks = {
post: post4,
post: post5,
}
/**
@ -379,7 +398,7 @@ export const delete_ = oc
/**
* Commit an uploaded file into the Agent App drive under files/<name>
*/
export const post5 = oc
export const post6 = oc
.route({
description: 'Commit an uploaded file into the Agent App drive under files/<name>',
inputStructure: 'detailed',
@ -394,7 +413,7 @@ export const post5 = oc
export const files2 = {
delete: delete_,
post: post5,
post: post6,
}
export const get9 = oc
@ -483,7 +502,7 @@ export const read = {
/**
* Upload one Agent App sandbox file as a Dify ToolFile mapping
*/
export const post6 = oc
export const post7 = oc
.route({
description: 'Upload one Agent App sandbox file as a Dify ToolFile mapping',
inputStructure: 'detailed',
@ -501,7 +520,7 @@ export const post6 = oc
.output(zPostAgentByAgentIdSandboxFilesUploadResponse)
export const upload = {
post: post6,
post: post7,
}
/**
@ -537,7 +556,7 @@ export const sandbox = {
/**
* Validate + standardize a Skill into an Agent App drive
*/
export const post7 = oc
export const post8 = oc
.route({
description: 'Validate + standardize a Skill into an Agent App drive',
inputStructure: 'detailed',
@ -551,13 +570,13 @@ export const post7 = oc
.output(zPostAgentByAgentIdSkillsStandardizeResponse)
export const standardize = {
post: post7,
post: post8,
}
/**
* Upload + validate a Skill package for an Agent App
*/
export const post8 = oc
export const post9 = oc
.route({
description: 'Upload + validate a Skill package for an Agent App',
inputStructure: 'detailed',
@ -571,13 +590,13 @@ export const post8 = oc
.output(zPostAgentByAgentIdSkillsUploadResponse)
export const upload2 = {
post: post8,
post: post9,
}
/**
* Infer CLI tool + ENV suggestions from a standardized Agent App skill
*/
export const post9 = oc
export const post10 = oc
.route({
description: 'Infer CLI tool + ENV suggestions from a standardized Agent App skill',
inputStructure: 'detailed',
@ -590,7 +609,7 @@ export const post9 = oc
.output(zPostAgentByAgentIdSkillsBySlugInferToolsResponse)
export const inferTools = {
post: post9,
post: post10,
}
/**
@ -714,6 +733,7 @@ export const byAgentId = {
put: put2,
chatMessages,
composer,
copy,
drive,
features,
feedbacks,
@ -738,7 +758,7 @@ export const get18 = oc
.input(z.object({ query: zGetAgentQuery.optional() }))
.output(zGetAgentResponse)
export const post10 = oc
export const post11 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -752,7 +772,7 @@ export const post10 = oc
export const agent = {
get: get18,
post: post10,
post: post11,
inviteOptions,
byAgentId,
}

View File

@ -122,6 +122,14 @@ export type AgentComposerValidateResponse = {
warnings?: Array<ComposerValidationWarningResponse>
}
export type CopyAppPayload = {
description?: string | null
icon?: string | null
icon_background?: string | null
icon_type?: IconType | null
name?: string | null
}
export type AgentDriveListResponse = {
items?: Array<AgentDriveItemResponse>
}
@ -1703,6 +1711,27 @@ export type PostAgentByAgentIdComposerValidateResponses = {
export type PostAgentByAgentIdComposerValidateResponse
= PostAgentByAgentIdComposerValidateResponses[keyof PostAgentByAgentIdComposerValidateResponses]
export type PostAgentByAgentIdCopyData = {
body: CopyAppPayload
path: {
agent_id: string
}
query?: never
url: '/agent/{agent_id}/copy'
}
export type PostAgentByAgentIdCopyErrors = {
400: unknown
403: unknown
}
export type PostAgentByAgentIdCopyResponses = {
201: AppDetailWithSite
}
export type PostAgentByAgentIdCopyResponse
= PostAgentByAgentIdCopyResponses[keyof PostAgentByAgentIdCopyResponses]
export type GetAgentByAgentIdDriveFilesData = {
body?: never
path: {

View File

@ -109,6 +109,17 @@ export const zAgentAppUpdatePayload = z.object({
use_icon_as_answer_icon: z.boolean().nullish(),
})
/**
* CopyAppPayload
*/
export const zCopyAppPayload = z.object({
description: z.string().max(400).nullish(),
icon: z.string().nullish(),
icon_background: z.string().nullish(),
icon_type: zIconType.nullish(),
name: z.string().nullish(),
})
/**
* DeletedTool
*/
@ -2180,6 +2191,17 @@ export const zPostAgentByAgentIdComposerValidatePath = z.object({
*/
export const zPostAgentByAgentIdComposerValidateResponse = zAgentComposerValidateResponse
export const zPostAgentByAgentIdCopyBody = zCopyAppPayload
export const zPostAgentByAgentIdCopyPath = z.object({
agent_id: z.string(),
})
/**
* Agent app copied successfully
*/
export const zPostAgentByAgentIdCopyResponse = zAppDetailWithSite
export const zGetAgentByAgentIdDriveFilesPath = z.object({
agent_id: z.string(),
})