Skip to content
This repository was archived by the owner on Mar 5, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion functions_to_format/functions/activity_report_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,18 @@ class FunctionCallActivityRecord(FunctionStrategy):
"""Strategy for function-call activity event UI."""

def build_widget_inputs(self, context):
context.logger_context.logger.debug(
"function_call_activity_record_building_widget_inputs",
)
data = FunctionCallBackendOutput(
function_name=context.backend_output.get("function_name", ""),
arguments=context.backend_output.get("arguments", {}),
)
context.logger_context.logger.debug(
"function_call_activity_record_parsed_data",
function_name=data.function_name,
arguments=data.arguments,
)
return {
build_function_call_activity_widget: WidgetInput(
widget=Widget(
Expand Down Expand Up @@ -163,10 +171,17 @@ class FunctionResponseActivityRecord(FunctionStrategy):
"""

def build_widget_inputs(self, context):
context.logger_context.logger.debug(
"function_response_activity_record_building_widget_inputs",
)
data = FunctionResponseBackendOutput(
function_name=context.backend_output.get("function_name", ""),
response=context.backend_output.get("response", {}),
)
context.logger_context.logger.debug(
"function_response_activity_record_parsed_data",
function_name=data.function_name,
)
return {
build_function_response_activity_widget: WidgetInput(
widget=Widget(
Expand All @@ -186,17 +201,36 @@ def build_widget_inputs(self, context):
}

def execute(self, context):
context.logger_context.logger.info(
"function_response_activity_record_execute_started",
)
data = FunctionResponseBackendOutput(
function_name=context.backend_output.get("function_name", ""),
response=context.backend_output.get("response", {}),
)
context.logger_context.logger.debug(
"function_response_activity_record_trying_embedded_ui",
function_name=data.function_name,
)
embedded = _try_build_embedded_ui(
function_name=data.function_name,
response=data.response,
parent_context=context,
)
context.logger_context.logger.debug(
"function_response_activity_record_embedded_ui_result",
has_embedded=embedded is not None,
embedded_count=len(embedded) if embedded else 0,
)
widget_inputs = self.build_widget_inputs(context)
return self._build_and_save(context, widget_inputs, extra_widget_dicts=embedded)
result = self._build_and_save(
context, widget_inputs, extra_widget_dicts=embedded
)
context.logger_context.logger.info(
"function_response_activity_record_execute_completed",
widgets_count=result.widgets_count,
)
return result


function_response_activity_record = FunctionResponseActivityRecord()
68 changes: 45 additions & 23 deletions functions_to_format/functions/buttons.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pydivkit as dv
from pydivkit.core import Expr
import json
import uuid
from typing import List, Optional

# Import smarty_ui components
Expand Down Expand Up @@ -34,46 +35,61 @@
def build_buttons_row(
button_texts: list,
language: str = "ru",
include_feedback: bool = True,
include_feedback: bool = False,
):
"""
Build a row of buttons with optional feedback handling using smarty_ui smarty_button component.

Args:
button_texts: List of button text labels
language: Language code for feedback text (ru, en, uz)
include_feedback: Whether to include success/error feedback containers
include_feedback: Whether to include success/error feedback containers (default: False)

Returns:
DivContainer with buttons and optional feedback
"""
# Generate unique ID for this button row instance to avoid variable conflicts
btn_row_uuid = str(uuid.uuid4())[:8]

feedback_texts = BUTTON_FEEDBACK_TEXTS.get(language, BUTTON_FEEDBACK_TEXTS["en"])

# Unique variable names for this button row instance
success_var = f"btn_row_{btn_row_uuid}_success_visible"
error_var = f"btn_row_{btn_row_uuid}_error_visible"

# Build button items using smarty_ui smarty_button
button_items = []
for txt in button_texts:
# Create smarty_button with action_url for the main action
action_url = f"div-action://button/{txt.lower().replace(' ', '_')}"
btn = smarty_button(text=txt, action_url=action_url)

# Add custom actions including feedback action
btn.actions = [
# Add custom actions (feedback action only if include_feedback is True)
actions = [
dv.DivAction(
log_id=f"btn-{txt.lower().replace(' ', '_')}",
log_id=f"btn-{txt.lower().replace(' ', '_')}-{btn_row_uuid}",
url=action_url,
payload={"button_text": txt, "action": txt.lower()},
),
# Success feedback action
dv.DivAction(
log_id=f"btn-{txt.lower().replace(' ', '_')}-success",
url="div-action://set_variable?name=simple_btn_success_visible&value=1",
),
]

if include_feedback:
# Success feedback action
actions.append(
dv.DivAction(
log_id=f"btn-{txt.lower().replace(' ', '_')}-success-{btn_row_uuid}",
url=f"div-action://set_variable?name={success_var}&value=1",
)
)

btn.actions = actions
btn.margins = dv.DivEdgeInsets(right=8)
button_items.append(btn)

if not include_feedback:
return HStack(button_items)
# Return simple HStack without feedback containers and without variables
buttons_row = HStack(button_items)
return dv.make_div(buttons_row)

# Success feedback container using smarty_ui
success_icon = caption_1("✅")
Expand All @@ -88,8 +104,8 @@ def build_buttons_row(
dismiss_success.paddings = dv.DivEdgeInsets(left=8)
dismiss_success.actions = [
dv.DivAction(
log_id="dismiss-simple-btn-success",
url="div-action://set_variable?name=simple_btn_success_visible&value=0",
log_id=f"dismiss-btn-success-{btn_row_uuid}",
url=f"div-action://set_variable?name={success_var}&value=0",
)
]

Expand All @@ -100,9 +116,9 @@ def build_buttons_row(
corner_radius=8,
width=dv.DivMatchParentSize(),
)
success_container.id = "simple-btn-success"
success_container.id = f"btn-success-{btn_row_uuid}"
success_container.visibility = Expr(
"@{simple_btn_success_visible == 1 ? 'visible' : 'gone'}"
f"@{{{success_var} == 1 ? 'visible' : 'gone'}}"
)
success_container.margins = dv.DivEdgeInsets(top=8)
success_container.border = dv.DivBorder(
Expand All @@ -122,8 +138,8 @@ def build_buttons_row(
dismiss_error.paddings = dv.DivEdgeInsets(left=8)
dismiss_error.actions = [
dv.DivAction(
log_id="dismiss-simple-btn-error",
url="div-action://set_variable?name=simple_btn_error_visible&value=0",
log_id=f"dismiss-btn-error-{btn_row_uuid}",
url=f"div-action://set_variable?name={error_var}&value=0",
)
]

Expand All @@ -134,9 +150,9 @@ def build_buttons_row(
corner_radius=8,
width=dv.DivMatchParentSize(),
)
error_container.id = "simple-btn-error"
error_container.id = f"btn-error-{btn_row_uuid}"
error_container.visibility = Expr(
"@{simple_btn_error_visible == 1 ? 'visible' : 'gone'}"
f"@{{{error_var} == 1 ? 'visible' : 'gone'}}"
)
error_container.margins = dv.DivEdgeInsets(top=8)
error_container.border = dv.DivBorder(
Expand All @@ -146,18 +162,24 @@ def build_buttons_row(
# Buttons row using HStack
buttons_row = HStack(button_items)

# Main container using VStack
# Main container using VStack with scoped variables
main_container = VStack([buttons_row, success_container, error_container])
main_container.variables = [
dv.IntegerVariable(name="simple_btn_success_visible", value=0),
dv.IntegerVariable(name="simple_btn_error_visible", value=0),
dv.IntegerVariable(name=success_var, value=0),
dv.IntegerVariable(name=error_var, value=0),
]

return dv.make_div(main_container)


if __name__ == "__main__":
buttons = ["submit", "cancel"]
# Test without feedback (default)
buttons_widget = build_buttons_row(buttons)
with open("logs/json/buttons.json", "w") as f:
json.dump(dv.make_div(buttons_widget), f, indent=2, ensure_ascii=False)
json.dump(buttons_widget, f, indent=2, ensure_ascii=False)

# Test with feedback
buttons_widget_with_feedback = build_buttons_row(buttons, include_feedback=True)
with open("logs/json/buttons_with_feedback.json", "w") as f:
json.dump(buttons_widget_with_feedback, f, indent=2, ensure_ascii=False)
58 changes: 57 additions & 1 deletion functions_to_format/functions/chatbot_answer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
from typing import Any, Dict, List

from smarty_ui.blocks import contacts_list
from tool_call_models.smartbazar import SearchProductsResponse

from .human_approval import (
HumanApprovalRequestEvent,
human_approval_ui,
)

from .products import build_products_list_widget
from .general import (
Widget,
ButtonsWidget,
Expand Down Expand Up @@ -52,7 +60,55 @@ class ChatbotAnswer(FunctionStrategy):

def build_widget_inputs(self, context):
text_builder, text_input = self.make_text_input(context.llm_output)
return {text_builder: text_input}

# # add products list widget as well

return {
# build_products_list_widget: WidgetInput(
# widget=Widget(
# name="products_list_widget",
# type="products_list_widget",
# order=1,
# layout="vertical",
# fields=["products", "title"],
# ),
# args={
# "products_list_input": SearchProductsResponse(
# **json.load(
# open(
# "../consultant_ai_golang_backend/playground/fixture/smartbazar_search_products.json"
# )
# )["backend_output"]
# ).products[:1],
# "language": context.language,
# "chat_id": context.logger_context.chat_id,
# "api_key": context.api_key,
# },
# ), # USED FOR TESTING
# human_approval_ui: WidgetInput(
# widget=Widget(
# order=2,
# type="approval_widget",
# name="approval_widget",
# layout="vertical",
# fields=["approval_widget"],
# values=[context.backend_output],
# ),
# args={
# "human_approval_input": HumanApprovalRequestEvent.model_validate(
# json.load(
# open(
# "../consultant_ai_golang_backend/playground/fixture/human_approval.json"
# )
# )["backend_output"]["human_approval_event"]
# ),
# "language": context.language,
# "api_key": context.api_key,
# "text": context.llm_output,
# },
# ), # USED FOR TESTING
text_builder: text_input,
}


chatbot_answer = ChatbotAnswer()
Expand Down
Loading
Loading