fix(api): keep plugin install statuses strictly the enum, and type openapi's task status with it

This commit is contained in:
GareArc
2026-10-10 15:38:27 -07:00
parent 591b03f2cd
commit 769b4df1c3
10 changed files with 33 additions and 47 deletions
+3 -2
View File
@@ -15,6 +15,7 @@ from controllers.common.human_input import HumanInputFormSubmitPayload
from controllers.openapi._i18n import localized
from controllers.openapi._upload import UploadPart, UploadParts
from core.plugin.entities.plugin import PluginCategory
from core.plugin.entities.plugin_daemon import PluginInstallTaskStatus
from core.tools.entities.tool_entities import ToolProviderType
from enums import DeploymentEdition, WebAppAccessMode
from fields.workflow_run_fields import WorkflowRunPaginationResponse
@@ -571,13 +572,13 @@ class PluginTaskStartResponse(Hinted):
class PluginTaskItem(BaseModel):
plugin_id: str
identifier: str
status: str
status: PluginInstallTaskStatus
message: str
class PluginTaskResponse(Hinted):
task_id: str
status: str = Field(description="pending, running, success or failed")
status: PluginInstallTaskStatus
plugins: list[PluginTaskItem]
+2 -2
View File
@@ -268,12 +268,12 @@ class PluginTaskApi(Resource):
hints = []
return PluginTaskResponse(
task_id=task_id,
status=str(task.status),
status=task.status,
plugins=[
PluginTaskItem(
plugin_id=plugin.plugin_id,
identifier=plugin.plugin_unique_identifier,
status=str(plugin.status),
status=plugin.status,
message=plugin.message,
)
for plugin in task.plugins
+2 -2
View File
@@ -194,7 +194,7 @@ class PluginInstallTaskStatus(StrEnum):
class PluginInstallTaskPluginStatus(BaseModel):
plugin_unique_identifier: str = Field(description="The plugin unique identifier of the install task.")
plugin_id: str = Field(description="The plugin ID of the install task.")
status: PluginInstallTaskStatus | str = Field(description="The status of the install task.")
status: PluginInstallTaskStatus = Field(description="The status of the install task.")
message: str = Field(description="The message of the install task.")
icon: str = Field(description="The icon of the plugin.")
labels: I18nObject = Field(description="The labels of the plugin.")
@@ -202,7 +202,7 @@ class PluginInstallTaskPluginStatus(BaseModel):
class PluginInstallTask(BasePluginEntity):
status: PluginInstallTaskStatus | str = Field(description="The status of the install task.")
status: PluginInstallTaskStatus = Field(description="The status of the install task.")
total_plugins: int = Field(description="The total number of plugins to be installed.")
completed_plugins: int = Field(description="The number of plugins that have been installed.")
plugins: list[PluginInstallTaskPluginStatus] = Field(description="The status of the plugins.")
+2 -2
View File
@@ -22021,7 +22021,7 @@ Shared permission levels for resources (datasets, credentials, etc.)
| created_at | dateTime | | Yes |
| id | string | | Yes |
| plugins | [ [PluginInstallTaskPluginStatus](#plugininstalltaskpluginstatus) ] | The status of the plugins. | Yes |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus)<br>string | The status of the install task. | Yes |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | The status of the install task. | Yes |
| total_plugins | integer | The total number of plugins to be installed. | Yes |
| updated_at | dateTime | | Yes |
@@ -22035,7 +22035,7 @@ Shared permission levels for resources (datasets, credentials, etc.)
| plugin_id | string | The plugin ID of the install task. | Yes |
| plugin_unique_identifier | string | The plugin unique identifier of the install task. | Yes |
| source | string | The installation source of the plugin | No |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus)<br>string | The status of the install task. | Yes |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | The status of the install task. | Yes |
#### PluginInstallTaskStartResponse
+8 -2
View File
@@ -2935,6 +2935,12 @@ Strict (extra='forbid').
| ---- | ---- | ----------- | -------- |
| identifiers | [ string ] | Versioned plugin ids such as langgenius/openai:0.2.1@sha256…, from get.marketplace.plugin (identifier) or check.console_app.dependency | Yes |
#### PluginInstallTaskStatus
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| PluginInstallTaskStatus | string | | |
#### PluginListQuery
| Name | Type | Description | Required |
@@ -2975,7 +2981,7 @@ Strict (extra='forbid').
| identifier | string | | Yes |
| message | string | | Yes |
| plugin_id | string | | Yes |
| status | string | | Yes |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | | Yes |
#### PluginTaskResponse
@@ -2983,7 +2989,7 @@ Strict (extra='forbid').
| ---- | ---- | ----------- | -------- |
| hints | [ [Hint](#hint) ] | Next steps the caller can take | No |
| plugins | [ [PluginTaskItem](#plugintaskitem) ] | | Yes |
| status | string | pending, running, success or failed | Yes |
| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | | Yes |
| task_id | string | | Yes |
#### PluginTaskStartResponse
@@ -17,7 +17,7 @@ from core.plugin.entities.parameters import (
cast_parameter_value,
init_frontend_parameter,
)
from core.plugin.entities.plugin_daemon import CredentialType, PluginInstallTask, PluginInstallTaskStatus
from core.plugin.entities.plugin_daemon import CredentialType
from core.plugin.entities.request import (
RequestInvokeLLM,
RequestInvokeSpeech2Text,
@@ -337,34 +337,6 @@ class TestPluginDaemonEntities:
with pytest.raises(ValueError, match="Invalid credential type"):
CredentialType.of("invalid")
@pytest.mark.parametrize(
("raw", "expected"),
[("success", PluginInstallTaskStatus.Success), ("a-status-added-later", "a-status-added-later")],
)
def test_install_task_parses_known_and_unknown_statuses(self, raw, expected):
plugin = {
"plugin_unique_identifier": "langgenius/openai:0.1.0@abc",
"plugin_id": "langgenius/openai",
"status": raw,
"message": "",
"icon": "",
"labels": {"en_US": "OpenAI"},
}
task = PluginInstallTask.model_validate(
{
"id": "task-1",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": raw,
"total_plugins": 1,
"completed_plugins": 0,
"plugins": [plugin],
}
)
assert task.status == expected
assert task.plugins[0].status == expected
class TestPluginRequestEntities:
def test_request_invoke_llm_converts_prompt_messages(self):
@@ -1596,7 +1596,7 @@ export type PluginInstallTask = {
created_at: string
id: string
plugins: Array<PluginInstallTaskPluginStatus>
status: PluginInstallTaskStatus | string
status: PluginInstallTaskStatus
total_plugins: number
updated_at: string
}
@@ -2331,7 +2331,7 @@ export type PluginInstallTaskPluginStatus = {
plugin_id: string
plugin_unique_identifier: string
source?: string | null
status: PluginInstallTaskStatus | string
status: PluginInstallTaskStatus
}
export type PluginInstallTaskStatus = 'failed' | 'pending' | 'running' | 'success'
@@ -2423,7 +2423,7 @@ export const zPluginInstallTaskPluginStatus = z.object({
plugin_id: z.string(),
plugin_unique_identifier: z.string(),
source: z.string().nullish(),
status: z.union([zPluginInstallTaskStatus, z.string()]),
status: zPluginInstallTaskStatus,
})
/**
@@ -2434,7 +2434,7 @@ export const zPluginInstallTask = z.object({
created_at: z.iso.datetime(),
id: z.string(),
plugins: z.array(zPluginInstallTaskPluginStatus),
status: z.union([zPluginInstallTaskStatus, z.string()]),
status: zPluginInstallTaskStatus,
total_plugins: z.int(),
updated_at: z.iso.datetime(),
})
@@ -956,6 +956,8 @@ export type PluginInstallPayload = {
identifiers: Array<string>
}
export type PluginInstallTaskStatus = 'failed' | 'pending' | 'running' | 'success'
export type PluginListQuery = {
category?: PluginCategory | null
}
@@ -985,13 +987,13 @@ export type PluginTaskItem = {
identifier: string
message: string
plugin_id: string
status: string
status: PluginInstallTaskStatus
}
export type PluginTaskResponse = {
hints?: Array<Hint>
plugins: Array<PluginTaskItem>
status: string
status: PluginInstallTaskStatus
task_id: string
}
@@ -1287,6 +1287,11 @@ export const zPluginInstallPayload = z.object({
identifiers: z.array(z.string()).min(1),
})
/**
* PluginInstallTaskStatus
*/
export const zPluginInstallTaskStatus = z.enum(['failed', 'pending', 'running', 'success'])
/**
* PluginListQuery
*/
@@ -1331,7 +1336,7 @@ export const zPluginTaskItem = z.object({
identifier: z.string(),
message: z.string(),
plugin_id: z.string(),
status: z.string(),
status: zPluginInstallTaskStatus,
})
/**
@@ -1340,7 +1345,7 @@ export const zPluginTaskItem = z.object({
export const zPluginTaskResponse = z.object({
hints: z.array(zHint).optional(),
plugins: z.array(zPluginTaskItem),
status: z.string(),
status: zPluginInstallTaskStatus,
task_id: z.string(),
})