refactor: type high-value module contracts

This commit is contained in:
jxxghp
2026-08-24 01:03:57 +08:00
parent bec64887d6
commit b0c4809d1a
4 changed files with 210 additions and 92 deletions
+140 -91
View File
@@ -3772,48 +3772,57 @@
"version": 1
},
"download_discord_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_feishu_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_feishu_image_to_data_url": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageImageDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"image_ref",
"source"
],
"result_contract": "str | None",
"result_shape": "string",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
@@ -3839,176 +3848,208 @@
"version": 1
},
"download_qq_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_slack_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_slack_file_to_data_url": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_url",
"source"
],
"result_contract": "str | None",
"result_shape": "string",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_synologychat_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_telegram_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_id",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_telegram_file_to_base64": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_id",
"source"
],
"result_contract": "str | None",
"result_shape": "string",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_vocechat_file_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageFileDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"file_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_vocechat_image_to_data_url": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageImageDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"image_ref",
"source"
],
"result_contract": "str | None",
"result_shape": "string",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_wechat_image_to_data_url": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageImageDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"image_ref",
"source"
],
"result_contract": "str | None",
"result_shape": "string",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"download_wechat_media_bytes": {
"aggregation": "legacy",
"aggregation": "first_non_empty",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"family": "messaging",
"input_contract": "MessageMediaDownloadRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"media_ref",
"source"
],
"result_contract": "bytes | None",
"result_shape": "bytes",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
"version": 1
},
"downloader_info": {
"aggregation": "legacy",
"aggregation": "ordered_list_merge",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"input_contract": "DownloaderInfoRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"downloader"
],
"result_contract": "list[DownloaderInfo]",
"result_shape": "list",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
@@ -4188,16 +4229,21 @@
"version": 1
},
"list_torrents": {
"aggregation": "legacy",
"aggregation": "ordered_list_merge",
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"input_contract": "TorrentListRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"result_shape": "any",
"required_parameters": [
"downloader",
"hashs",
"include_all_tags",
"status"
],
"result_contract": "list[DownloaderTorrent]",
"result_shape": "list",
"supports_async": true,
"supports_sync": true,
"timeout_policy": "caller_budget",
@@ -5576,11 +5622,14 @@
"error_policy": "isolate_provider",
"execution": "sync_or_async",
"family": "downloader",
"input_contract": "DownloaderKeywordArguments",
"input_contract": "TorrentFilesRequest",
"plugin_short_circuit": true,
"public_to_plugins": true,
"required_parameters": [],
"result_contract": "DownloaderProviderResult",
"required_parameters": [
"downloader",
"tid"
],
"result_contract": "DownloaderFileCollection | None",
"result_shape": "any",
"supports_async": true,
"supports_sync": true,
+47
View File
@@ -134,6 +134,53 @@ def test_result_diagnostics_check_only_enabled_basic_shapes() -> None:
)
def test_message_attachment_contracts_use_messaging_family() -> None:
"""消息附件下载能力不得因 download 前缀误归入下载器能力族。"""
expected_parameters = {
"download_telegram_file_bytes": ("file_id", "source"),
"download_wechat_media_bytes": ("media_ref", "source"),
"download_slack_file_to_data_url": ("file_url", "source"),
"download_feishu_image_to_data_url": ("image_ref", "source"),
}
for method, parameters in expected_parameters.items():
contract = get_module_method_contract(method)
assert contract.family == "messaging"
assert contract.aggregation is ModuleResultAggregation.FIRST_NON_EMPTY
assert contract.required_parameters == parameters
def test_downloader_query_contracts_merge_provider_lists() -> None:
"""下载器查询能力应显式合并各 provider 的有序列表结果。"""
for method in ("list_torrents", "downloader_info"):
contract = get_module_method_contract(method)
assert contract.family == "downloader"
assert contract.aggregation is ModuleResultAggregation.ORDERED_LIST_MERGE
assert contract.result_shape is ModuleResultShape.LIST
def test_heterogeneous_torrent_files_result_remains_legacy_compatible() -> None:
"""下载器文件集合尚未归一前不得声明虚假的列表聚合语义。"""
contract = get_module_method_contract("torrent_files")
assert contract.required_parameters == ("tid", "downloader")
assert contract.result_contract == "DownloaderFileCollection | None"
assert contract.aggregation is ModuleResultAggregation.LEGACY
assert contract.result_shape is ModuleResultShape.ANY
def test_attachment_result_diagnostics_distinguish_bytes_and_strings() -> None:
"""附件契约应区分二进制内容和可展示字符串,偏差仍仅供诊断。"""
assert diagnose_module_result("download_qq_file_bytes", b"content") == ()
assert diagnose_module_result("download_qq_file_bytes", "content") == (
"unexpected-result:bytes:str",
)
assert diagnose_module_result(
"download_wechat_image_to_data_url",
"data:image/png;base64,AA==",
) == ()
def test_unknown_plugin_result_keeps_unchecked_legacy_compatibility() -> None:
"""未知第三方方法的任意返回值继续不做结果形状诊断。"""
assert diagnose_module_result("third_party_custom_method", object()) == ()