| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- class QueryCustomsDeclarationFilesTool:
- name = 'query_customs_declaration_files'
- route_path = '/mcp/tools/queryCustomsDeclarationFiles'
- MAX_NUMBERS = 100
- def __init__(self, api_client=None):
- self.api_client = api_client
- def metadata(self):
- number_item = {
- 'type': 'string',
- 'minLength': 1,
- 'maxLength': 100,
- }
- return {
- 'name': self.name,
- 'description': (
- '使用场景:用户明确要查看或下载报关资料文件和文件链接时,批量查询订单'
- '的报关资料文件链接。用户明确说“订单号”时使用'
- '订单号数组;用户明确说“排舱单号”时使用排舱单号数组。'
- '这里的订单号是后台订单列表及排舱详情“订单号”列显示的号码,'
- '不是系统单号、数据库 order_id/id、客户参考号、快递单号或排舱单号。'
- '一次调用只能选择一种号码,单个号码也必须放入数组。'
- '如果用户没有明确说明是订单号还是排舱单号,必须先提问,'
- '让用户选择“订单号”或“排舱单号”,确认前不得调用工具。'
- '用户只说“单号”时必须先追问是订单号还是排舱单号。'
- '用户说“系统单号”时也不得当作订单号;必须先确认并取得订单号。'
- '号码类型不明确时必须先询问用户。禁止使用:用户要查看完整排舱详情时'
- '应使用 query_outbound_detail,不得用本工具替代;本工具也不返回订单资料、'
- '排舱列表、物流轨迹或导出文件。不得根据号码格式猜测。'
- '查询无结果后不得切换号码类型,不得跨字段重试,'
- '不得跨字段或跨工具试查。'
- '参数名仅用于工具调用;向用户回答时只能使用中文业务名称,'
- '不得展示内部参数名。'
- ),
- 'input_schema': {
- 'type': 'object',
- 'properties': {
- 'outbound_numbers': {
- 'type': 'array',
- 'items': dict(number_item),
- 'minItems': 1,
- 'maxItems': self.MAX_NUMBERS,
- 'description': (
- '多个排舱单号。仅当用户明确说“排舱单号”时使用;'
- '不是订单号、客户参考号或快递单号。'
- ),
- 'examples': [['PC202607150001', 'PC202607150002']],
- },
- 'order_numbers': {
- 'type': 'array',
- 'items': dict(number_item),
- 'minItems': 1,
- 'maxItems': self.MAX_NUMBERS,
- 'description': (
- '多个订单号,对应后台订单列表及排舱详情“订单号”列的值。'
- '仅当用户明确说“订单号”时使用;不是系统单号或数据库'
- ' order_id/id,也不是客户参考号、快递单号或排舱单号。'
- '用户提供“系统单号”时不得填入此字段,必须先追问取得订单号。'
- ),
- 'examples': [['ORD202607150001', 'ORD202607150002']],
- },
- 'page': {
- 'type': 'integer',
- 'minimum': 1,
- 'maximum': 100,
- 'default': 1,
- 'description': '页码,从 1 开始,最大 100。',
- },
- 'limit': {
- 'type': 'integer',
- 'minimum': 1,
- 'maximum': 100,
- 'default': 20,
- 'description': '每页订单数量,范围 1 到 100。',
- },
- },
- 'oneOf': [
- {'required': ['outbound_numbers']},
- {'required': ['order_numbers']},
- ],
- 'additionalProperties': False,
- },
- }
- def call(
- self,
- outbound_numbers=None,
- order_numbers=None,
- page=1,
- limit=20,
- request_id='rq_query_customs_declaration_files',
- ):
- if self.api_client is None:
- raise RuntimeError(
- 'api client is required for query_customs_declaration_files'
- )
- has_outbound = outbound_numbers is not None
- has_order = order_numbers is not None
- if has_outbound == has_order:
- raise ValueError(
- 'provide outbound_numbers or order_numbers'
- )
- field = 'outbound_numbers' if has_outbound else 'order_numbers'
- values = outbound_numbers if has_outbound else order_numbers
- numbers = self._normalize_numbers(values, field)
- page = self._bounded_integer(page, 'page', 100)
- limit = self._bounded_integer(limit, 'limit', 100)
- return self.api_client.call_tool(
- self.name,
- self.route_path,
- {
- field: numbers,
- 'page': page,
- 'limit': limit,
- },
- request_id,
- )
- @classmethod
- def _normalize_numbers(cls, values, field):
- if not isinstance(values, list):
- raise ValueError('{0} must be an array'.format(field))
- if len(values) > cls.MAX_NUMBERS:
- raise ValueError('{0} must contain 1 to 100 values'.format(field))
- numbers = []
- for value in values:
- if not isinstance(value, str):
- raise ValueError('{0} must contain strings'.format(field))
- value = value.strip()
- if not value:
- continue
- if len(value) > 100:
- raise ValueError('{0} contains an invalid number'.format(field))
- if value not in numbers:
- numbers.append(value)
- if not numbers:
- raise ValueError('{0} must contain 1 to 100 values'.format(field))
- return numbers
- @staticmethod
- def _bounded_integer(value, field, maximum):
- if isinstance(value, bool):
- raise ValueError('{0} must be between 1 and {1}'.format(field, maximum))
- try:
- value = int(value)
- except (TypeError, ValueError):
- raise ValueError('{0} must be between 1 and {1}'.format(field, maximum))
- if value < 1 or value > maximum:
- raise ValueError('{0} must be between 1 and {1}'.format(field, maximum))
- return value
|