From 54be507723c96b6c815d40e7ff3791376a094ac1 Mon Sep 17 00:00:00 2001 From: aslon Date: Wed, 11 Feb 2026 14:58:30 +0500 Subject: [PATCH] added special UI generation for pay home utility function on human approval --- functions_to_format/functions/functions.py | 1 + .../functions/human_approval.py | 330 ++++++++++++++++-- pyproject.toml | 3 +- uv.lock | 69 +++- 4 files changed, 378 insertions(+), 25 deletions(-) diff --git a/functions_to_format/functions/functions.py b/functions_to_format/functions/functions.py index 938420d..ccdc880 100644 --- a/functions_to_format/functions/functions.py +++ b/functions_to_format/functions/functions.py @@ -74,6 +74,7 @@ "get_suppliers_by_category": get_suppliers_by_category, "start_page_widget": start_page_widget, "send_money_to_someone_via_card": send_money_to_someone_via_card, + "send_money_to_someone_via_card_wrapper": send_money_to_someone_via_card, "get_home_balances": get_home_balances, "build_contacts_list": build_contacts_list, "pay_for_home_utility": pay_for_home_utility, diff --git a/functions_to_format/functions/human_approval.py b/functions_to_format/functions/human_approval.py index 5c37a05..9d0e9e6 100644 --- a/functions_to_format/functions/human_approval.py +++ b/functions_to_format/functions/human_approval.py @@ -1,5 +1,6 @@ from typing import Any +from pydantic import BaseModel from pydivkit.core import Expr from functions_to_format.functions.buttons import build_buttons_row from .general import ( @@ -13,6 +14,7 @@ LanguageOptions, WidgetMargins, ) +from tool_call_models.paynet import PaymentManagerCheckUpResponse import structlog from models.context import Context import pydivkit as dv @@ -32,10 +34,83 @@ ) logger: structlog.stdlib.BoundLogger = structlog.get_logger(__name__) +from datetime import datetime + + +class EventBase(BaseModel): + tool_call_id: str + user_id: str + session_id: str + app_name: str + # created_at: Any + + +class HumanApprovalRequestEvent(EventBase): + approve_link: str + reject_link: str + arguments: dict[str, Any] | None = None + tool_name: str | None = None + + +class PayForHomeUtilityArguments(BaseModel): + amount: int + category_id: str + supplier_id: str + region_id: str | None = None + payment_no: str + payment_no1: str | None = None + payment_no2: str | None = None + payment_no3: str | None = None + payment_no4: str | None = None + supplierName: str + homeImage: str + homeName: str + supplierImage: str + checkUp: PaymentManagerCheckUpResponse + + +def _mask_pii(value: str) -> str: + """Mask PII (e.g. full name) for display: E****ROV J****SHID style.""" + if not value or len(value.strip()) < 4: + return "****" + parts = value.strip().split() + masked = [] + for part in parts: + if len(part) <= 2: + masked.append("*" * len(part)) + else: + masked.append(part[0] + "****" + part[-1].upper()) + return " ".join(masked) + + +def _account_detail_row( + label: str, + value: str, + mask_value: bool = False, +) -> dv.DivBase: + """One receipt-style row: label (left), dotted line, value (right).""" + display_value = _mask_pii(value) if mask_value else value + label_view = caption_2(label, color="#6B7280") + label_view.width = dv.DivWrapContentSize() + + # Dotted filler: middle dots so label and value align like the reference + dots = text_1(" · " * 24, color="#D1D5DB") + dots.font_size = 10 + dots.width = dv.DivMatchParentSize(weight=1) + dots.text_alignment_horizontal = dv.DivAlignmentHorizontal.LEFT + + value_view = text_1(display_value, color="#111827") + value_view.font_weight = dv.DivFontWeight.REGULAR + value_view.width = dv.DivWrapContentSize() + value_view.text_alignment_horizontal = dv.DivAlignmentHorizontal.RIGHT + + row = HStack([label_view, dots, value_view]) + row.margins = dv.DivEdgeInsets(top=10, bottom=10) + return row def human_approval_ui( - human_approval_input: dict[str, Any], + human_approval_input: HumanApprovalRequestEvent, language: LanguageOptions = LanguageOptions.UZBEK, text: str = "", api_key: str = "", @@ -55,6 +130,15 @@ def human_approval_ui( "date": "O'tkazish vaqti:", "sender": "Jo'natuvchi:", "receiver": "Qabul qiluvchi:", + "approval_title_generic": "Iltimos, amalni tasdiqlang.", + "approval_title_utility": "Kommunal to'lovni tasdiqlang.", + "account_details_title": "Hisob tafsilotlari", + "current_balance": "Joriy balans", + "account_number": "Shaxsiy hisob", + "region": "Hudud", + "full_name": "F.I.O.", + "address": "Manzil", + "meter_reading": "Hisoblagich ko'rsatkichlari", }, LanguageOptions.RUSSIAN: { "payment_status": "Сумма платежа", @@ -64,6 +148,15 @@ def human_approval_ui( "date": "Время перевода:", "sender": "Отправитель:", "receiver": "Получатель:", + "approval_title_generic": "Пожалуйста, подтвердите действие.", + "approval_title_utility": "Подтвердите коммунальный платёж.", + "account_details_title": "Детали счета", + "current_balance": "Текущий баланс", + "account_number": "Лицевой счет", + "region": "Регион", + "full_name": "ФИО", + "address": "Адрес", + "meter_reading": "Показания счетчика", }, LanguageOptions.ENGLISH: { "payment_status": "Payment amount", @@ -73,12 +166,21 @@ def human_approval_ui( "date": "Transfer time:", "sender": "Sender:", "receiver": "Receiver:", + "approval_title_generic": "Please approve this action.", + "approval_title_utility": "Please confirm the utility payment.", + "account_details_title": "Account details", + "current_balance": "Current balance", + "account_number": "Account number", + "region": "Region", + "full_name": "Full name", + "address": "Address", + "meter_reading": "Meter reading", }, } try: - approve_link = human_approval_input["human_approval_event"]["approve_link"] - reject_link = human_approval_input["human_approval_event"]["reject_link"] + approve_link = human_approval_input.approve_link + reject_link = human_approval_input.reject_link logger.info( "Generated approval links", @@ -86,20 +188,17 @@ def human_approval_ui( reject_link_length=len(reject_link), ) - # Build approval info text using smarty_ui - info_text = text_1( - "Please approve the action. \n" - + "user_id: " - + human_approval_input["human_approval_event"]["user_id"] - + "\n" - + "session_id: " - + human_approval_input["human_approval_event"]["session_id"] - + "\n" - + "app_name: " - + human_approval_input["human_approval_event"]["app_name"] - + "\n", - color="#111133", - ) + # Build approval info text using smarty_ui (do not expose IDs) + localized_texts = texts_map.get(language, texts_map[LanguageOptions.ENGLISH]) + + if human_approval_input.tool_name == "pay_for_home_utility_wrapper": + header_text = localized_texts.get( + "approval_title_utility", localized_texts["approval_title_generic"] + ) + else: + header_text = localized_texts["approval_title_generic"] + + info_text = text_1(header_text, color="#111133") info_text.font_weight = dv.DivFontWeight.LIGHT info_text.line_height = 22 info_text.text_alignment_horizontal = dv.DivAlignmentHorizontal.LEFT @@ -126,6 +225,186 @@ def human_approval_ui( dv.StringVariable(name="error_text", value=""), ] + # Optional details container for specific tools (e.g. pay_for_home_utility_wrapper) + utility_details_container = None + + if ( + human_approval_input.tool_name == "pay_for_home_utility_wrapper" + and human_approval_input.arguments + ): + try: + arguments = PayForHomeUtilityArguments.model_validate( + human_approval_input.arguments + ) + except Exception as e: + logger.warning( + "PayForHomeUtilityArguments validation failed, skipping account-details view", + error=str(e), + ) + arguments = None + + if arguments is not None: + # Localized labels for account-details view (receipt style) + account_detail_labels = { + LanguageOptions.UZBEK: { + "title": "Hisob tafsilotlari", + "current_balance": "Joriy balans", + "account_number": "Shaxsiy hisob", + "supplier": "Ta'minotchi", + "service": "Xizmat", + "region": "Hudud", + "address": "Manzil", + "meter_reading": "Hisoblagich", + }, + LanguageOptions.RUSSIAN: { + "title": "Детали счета", + "current_balance": "Текущий баланс", + "account_number": "Лицевой счет", + "supplier": "Поставщик", + "service": "Услуга", + "region": "Регион", + "address": "Адрес", + "meter_reading": "Показания счетчика", + }, + LanguageOptions.ENGLISH: { + "title": "Account details", + "current_balance": "Current balance", + "account_number": "Account number", + "supplier": "Supplier", + "service": "Service", + "region": "Region", + "address": "Address", + "meter_reading": "Meter reading", + }, + } + ad_labels = account_detail_labels.get( + language, account_detail_labels[LanguageOptions.ENGLISH] + ) + currency = localized_texts.get( + "currency", texts_map[LanguageOptions.ENGLISH]["currency"] + ) + details_children: list[dv.DivBase] = [] + + # Handle bar (swipe hint) + handle = text_1("\u2007", color="#E5E7EB") + handle.width = dv.DivFixedSize(value=36) + handle.height = dv.DivFixedSize(value=4) + handle.background = [dv.DivSolidBackground(color="#E5E7EB")] + handle.border = dv.DivBorder(corner_radius=2) + handle.margins = dv.DivEdgeInsets(bottom=16) + details_children.append(handle) + + # Title: "Детали счета" + details_title = title_2(ad_labels["title"], color="#111827") + details_title.font_weight = dv.DivFontWeight.BOLD + details_title.margins = dv.DivEdgeInsets(bottom=4) + details_children.append(details_title) + + checkup_data = arguments.checkUp.data + response_by_name: dict[str, str] = { + item.name.strip().lower(): item.value + for item in checkup_data.response + } + shown_keys = set(response_by_name.keys()) + + def _should_mask(name: str, type_str: str) -> bool: + n = (name or "").strip().lower() + t = (type_str or "").strip().lower() + return ( + "фио" in n + or "fio" in n + or "full name" in n + or "full_name" in n + or "name" in t + or "full_name" in t + or "fio" in t + ) + + # 1) Current balance (from checkup balance or payment amount) + # balance_value = str( + # (checkup_data.balance if checkup_data.balance is not None else "0") + # ) + # balance_str = balance_value + # details_children.append( + # _account_detail_row( + # ad_labels["current_balance"], + # f"{balance_str} {currency}", + # mask_value=False, + # ) + # ) + + # 2) Rows from checkup response (sorted by order) + for item in sorted(checkup_data.response, key=lambda x: x.order): + if not item.value: + continue + mask = _should_mask(item.name, item.type) + details_children.append( + _account_detail_row( + item.name, + item.value, + mask_value=mask, + ) + ) + + # 3) Supplemental from arguments if not already in checkup response + def _add_supplement(label_key: str, value: str | None): + if not value: + return + details_children.append( + _account_detail_row( + ad_labels[label_key], + str(value), + mask_value=False, + ) + ) + + def _response_has(fragments: list[str]) -> bool: + return any(f in shown_keys for f in fragments) + + # Account number (payment_no) - often shown with copy in reference + if not _response_has( + [ + "лицевой счет", + "account number", + "shaxsiy hisob", + "номер платежа", + "to'lov raqami", + ] + ): + _add_supplement("account_number", arguments.payment_no) + if not _response_has(["поставщик", "supplier", "ta'minotchi"]): + _add_supplement("supplier", arguments.supplierName) + if arguments.region_id and not _response_has( + ["регион", "region", "hudud"] + ): + _add_supplement("region", arguments.region_id) + if arguments.homeName: + svc_label = ad_labels.get("service", "Service") + details_children.append( + _account_detail_row( + svc_label, arguments.homeName, mask_value=False + ) + ) + + if details_children: + utility_details_container = VStack( + details_children, + padding=20, + background="#FFFFFF", + corner_radius=16, + width=dv.DivMatchParentSize(), + ) + utility_details_container.border = dv.DivBorder( + corner_radius=16, + stroke=dv.DivStroke(color="#E5E7EB", width=1), + ) + utility_details_container.margins = dv.DivEdgeInsets( + top=12, + left=WidgetMargins.LEFT.value, + right=WidgetMargins.RIGHT.value, + bottom=0, + ) + # Success container using smarty_ui success_text = text_1("✅ Action completed successfully!", color="#065F46") success_text.font_weight = dv.DivFontWeight.MEDIUM @@ -270,7 +549,12 @@ def human_approval_ui( buttons_container = HStack([approve_btn, reject_btn]) # Main container using VStack - container = VStack([text_container, buttons_container]) + children = [text_container] + if "utility_details_container" in locals() and utility_details_container: + children.append(utility_details_container) + children.append(buttons_container) + + container = VStack(children) logger.info("Successfully built human approval UI container") return dv.make_div(container) @@ -290,8 +574,12 @@ def human_approval_ui( class HumanApprovalRequests(FunctionStrategy): """Strategy for building human approval UI with fallback.""" - def build_widget_inputs(self, context): + def build_widget_inputs(self, context: Context): """Build the happy-path widget inputs (approval widget).""" + logger.info( + "Context Infor for Human Approval", + backend_output=context.backend_output, + ) return { human_approval_ui: WidgetInput( widget=Widget( @@ -303,7 +591,9 @@ def build_widget_inputs(self, context): values=[context.backend_output], ), args={ - "human_approval_input": context.backend_output, + "human_approval_input": HumanApprovalRequestEvent.model_validate( + context.backend_output["human_approval_event"] + ), "language": context.language, "api_key": context.api_key, "text": context.llm_output, diff --git a/pyproject.toml b/pyproject.toml index 8801441..3c6f058 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "sentry-sdk>=2.44.0", "smarty-ui", "structlog>=25.5.0", - "tool-call-models==0.1.40", + "tool-call-models==0.1.42", ] [tool.uv.sources] @@ -36,6 +36,7 @@ smarty-ui = { path = "smarty_ui" } [dependency-groups] dev = [ + "ipykernel>=7.2.0", "pymongo>=4.15.4", "pyright>=1.1.407", ] diff --git a/uv.lock b/uv.lock index 78fdcee..4126016 100644 --- a/uv.lock +++ b/uv.lock @@ -233,6 +233,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/e2/fc500524cc6f104a9d049abc85a0a8b3f0d14c0a39b9c140511c61e5b40b/debugpy-1.8.20-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:5dff4bb27027821fdfcc9e8f87309a28988231165147c31730128b1c983e282a", size = 2539560, upload-time = "2026-01-29T23:03:48.738Z" }, + { url = "https://files.pythonhosted.org/packages/90/83/fb33dcea789ed6018f8da20c5a9bc9d82adc65c0c990faed43f7c955da46/debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf", size = 4293272, upload-time = "2026-01-29T23:03:50.169Z" }, + { url = "https://files.pythonhosted.org/packages/a6/25/b1e4a01bfb824d79a6af24b99ef291e24189080c93576dfd9b1a2815cd0f/debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393", size = 5331208, upload-time = "2026-01-29T23:03:51.547Z" }, + { url = "https://files.pythonhosted.org/packages/13/f7/a0b368ce54ffff9e9028c098bd2d28cfc5b54f9f6c186929083d4c60ba58/debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7", size = 5372930, upload-time = "2026-01-29T23:03:53.585Z" }, + { url = "https://files.pythonhosted.org/packages/33/2e/f6cb9a8a13f5058f0a20fe09711a7b726232cd5a78c6a7c05b2ec726cff9/debugpy-1.8.20-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:9c74df62fc064cd5e5eaca1353a3ef5a5d50da5eb8058fcef63106f7bebe6173", size = 2538066, upload-time = "2026-01-29T23:03:54.999Z" }, + { url = "https://files.pythonhosted.org/packages/c5/56/6ddca50b53624e1ca3ce1d1e49ff22db46c47ea5fb4c0cc5c9b90a616364/debugpy-1.8.20-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:077a7447589ee9bc1ff0cdf443566d0ecf540ac8aa7333b775ebcb8ce9f4ecad", size = 4269425, upload-time = "2026-01-29T23:03:56.518Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d9/d64199c14a0d4c476df46c82470a3ce45c8d183a6796cfb5e66533b3663c/debugpy-1.8.20-cp314-cp314-win32.whl", hash = "sha256:352036a99dd35053b37b7803f748efc456076f929c6a895556932eaf2d23b07f", size = 5331407, upload-time = "2026-01-29T23:03:58.481Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d9/1f07395b54413432624d61524dfd98c1a7c7827d2abfdb8829ac92638205/debugpy-1.8.20-cp314-cp314-win_amd64.whl", hash = "sha256:a98eec61135465b062846112e5ecf2eebb855305acc1dfbae43b72903b8ab5be", size = 5372521, upload-time = "2026-01-29T23:03:59.864Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, +] + [[package]] name = "decorator" version = "5.2.1" @@ -461,6 +487,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, ] +[[package]] +name = "ipykernel" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046, upload-time = "2026-02-06T16:43:27.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788, upload-time = "2026-02-06T16:43:25.149Z" }, +] + [[package]] name = "ipython" version = "8.12.3" @@ -740,6 +790,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, ] +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -1682,14 +1741,14 @@ wheels = [ [[package]] name = "tool-call-models" -version = "0.1.40" +version = "0.1.42" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/2d/47eb29f0643c0e97d288d3873cd70932f3aeb109d14cfb122da75dfd9369/tool_call_models-0.1.40.tar.gz", hash = "sha256:980df59c360721936559ec4724024d3744b5d4441d5f7b8cad7635b18f0ff340", size = 6476, upload-time = "2025-11-13T06:38:54.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/be/5032aaca6dc901e53881b36e9b6e5777315ef9c960654bb9a62a3bae028f/tool_call_models-0.1.42.tar.gz", hash = "sha256:0fe63a257f0d8448256e8d28ac7c0ffda03b4b3f1d8166a2d5f845893a5511db", size = 6535, upload-time = "2026-02-11T06:16:05.67Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/80/3478db182a1e3f51fe239df4d309a9c47287cd2eb5c4eaa06f13ff995c6f/tool_call_models-0.1.40-py3-none-any.whl", hash = "sha256:31c2bfe5f73670c3ab5315b5fb1391c2021f946e401c847a4a4250f84fece04d", size = 8942, upload-time = "2025-11-13T06:38:52.995Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5b/4e4e0018cfaf802fdf93a1a010bba79952e4bbda5112534c1166f0f8ea06/tool_call_models-0.1.42-py3-none-any.whl", hash = "sha256:286d42a7692da65d37900c27d11e8a1f44d48504b1a922a3a819906339bfff7a", size = 8935, upload-time = "2026-02-11T06:16:04.806Z" }, ] [[package]] @@ -1798,6 +1857,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "ipykernel" }, { name = "pymongo" }, { name = "pyright" }, ] @@ -1827,11 +1887,12 @@ requires-dist = [ { name = "sentry-sdk", specifier = ">=2.44.0" }, { name = "smarty-ui", directory = "smarty_ui" }, { name = "structlog", specifier = ">=25.5.0" }, - { name = "tool-call-models", specifier = "==0.1.40" }, + { name = "tool-call-models", specifier = "==0.1.42" }, ] [package.metadata.requires-dev] dev = [ + { name = "ipykernel", specifier = ">=7.2.0" }, { name = "pymongo", specifier = ">=4.15.4" }, { name = "pyright", specifier = ">=1.1.407" }, ]