From 48756ff35687557db5dc552dcf41bb0332d92a74 Mon Sep 17 00:00:00 2001 From: Davorin Rusevljan Date: Mon, 7 Oct 2024 08:42:38 +0000 Subject: [PATCH 1/9] limit time in event handlers --- examples/cli/javascript/counter_component.js | 51 ++++++++++++++++++++ fastagency/ui/mesop/base.py | 29 +++++++++-- fastagency/ui/mesop/counter_component.js | 51 ++++++++++++++++++++ fastagency/ui/mesop/main.py | 5 +- fastagency/ui/mesop/mesoptimer.py | 31 ++++++++++++ fastagency/ui/mesop/message.py | 13 ++++- fastagency/ui/mesop/send_prompt.py | 7 +++ 7 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 examples/cli/javascript/counter_component.js create mode 100644 fastagency/ui/mesop/counter_component.js create mode 100644 fastagency/ui/mesop/mesoptimer.py diff --git a/examples/cli/javascript/counter_component.js b/examples/cli/javascript/counter_component.js new file mode 100644 index 00000000..05371feb --- /dev/null +++ b/examples/cli/javascript/counter_component.js @@ -0,0 +1,51 @@ +import { + LitElement, + html, +} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js'; + +class CounterComponent extends LitElement { + static properties = { + value: { type: Number }, + decrementEvent: { type: String }, + }; + + constructor() { + super(); + this.value = 0; + this.decrementEvent = ''; + } + + render() { + return html` +
+ Value: ${this.value} + +
+ `; + } + + _onDecrement() { + this.dispatchEvent( + new MesopEvent(this.decrementEvent, { + value: this.value - 1, + }), + ); + } + + connectedCallback() { + setTimeout( + () => { + this.dispatchEvent( + new MesopEvent(this.decrementEvent, { + value: this.value - 1, + }), + ); + }, + 2000 + ); // Change text after 2 seconds + } +} + +customElements.define('quickstart-counter-component', CounterComponent); diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index fc36ac48..bec461c4 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -1,4 +1,5 @@ import threading +import time from collections.abc import Generator, Iterator from contextlib import contextmanager from dataclasses import dataclass @@ -18,6 +19,7 @@ IOMessageVisitor, MultipleChoice, Runnable, + SystemMessage, TextInput, TextMessage, WorkflowCompleted, @@ -50,6 +52,7 @@ def __init__( *, security_policy: Optional[me.SecurityPolicy] = None, styles: Optional[MesopHomePageStyles] = None, + keep_alive: Optional[bool] = False, ) -> None: """Initialize the console UI object. @@ -57,6 +60,7 @@ def __init__( super_conversation (Optional[MesopUI], optional): The super conversation. Defaults to None. security_policy (Optional[me.SecurityPolicy], optional): The security policy. Defaults to None. styles (Optional[MesopHomePageStyles], optional): The styles. Defaults to None. + keep_alive (Optional[bool]): If keep alive messages should be inserted, defaults to False` """ logger.info(f"Initializing MesopUI: {self}") try: @@ -66,9 +70,13 @@ def __init__( self._in_queue: Optional[Queue[str]] = None self._out_queue: Optional[Queue[MesopMessage]] = None + self._keep_me_alive = keep_alive + self._keep_alive_thread: Optional[threading.Thread] = None if super_conversation is None: self._in_queue = Queue() self._out_queue = Queue() + self.keep_me_alive() + MesopUI.register(self) if MesopUI._me is None: @@ -84,6 +92,20 @@ def __init__( _registry: ClassVar[dict[str, "MesopUI"]] = {} + def keep_me_alive(self) -> None: + def keep_alive_worker() -> None: + msg = SystemMessage(message={"keepAlive": "Stayin' alive"}) + # msg = TextMessage(body="just stayin' alive") + mesop_msg = self._mesop_message(msg) + while self._keep_me_alive: + time.sleep(3) + if self._out_queue: + self._out_queue.put(mesop_msg) + + if self._keep_me_alive and self._keep_alive_thread is None: + self._keep_alive_thread = threading.Thread(target=keep_alive_worker) + self._keep_alive_thread.start() + @classmethod def get_created_instance(cls) -> "MesopUI": created_instance = cls._created_instance @@ -179,7 +201,8 @@ def level(self) -> int: ) def _publish(self, mesop_msg: MesopMessage) -> None: - self.out_queue.put(mesop_msg) + # self.out_queue.put(mesop_msg) + ... def _mesop_message(self, io_message: IOMessage) -> MesopMessage: return MesopMessage( @@ -215,7 +238,7 @@ def create_subconversation(self) -> "MesopUI": return sub_conversation def _is_stream_braker(self, message: IOMessage) -> bool: - return isinstance(message, (AskingMessage, WorkflowCompleted)) + return isinstance(message, (AskingMessage, WorkflowCompleted, SystemMessage)) def respond(self, message: str) -> None: self.in_queue.put(message) @@ -317,7 +340,7 @@ def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: ) return - ui = MesopUI() + ui = MesopUI(keep_alive=True) subconversation = ui.create_subconversation() thread = threading.Thread(target=conversation_worker, args=(ui, subconversation)) thread.start() diff --git a/fastagency/ui/mesop/counter_component.js b/fastagency/ui/mesop/counter_component.js new file mode 100644 index 00000000..05371feb --- /dev/null +++ b/fastagency/ui/mesop/counter_component.js @@ -0,0 +1,51 @@ +import { + LitElement, + html, +} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js'; + +class CounterComponent extends LitElement { + static properties = { + value: { type: Number }, + decrementEvent: { type: String }, + }; + + constructor() { + super(); + this.value = 0; + this.decrementEvent = ''; + } + + render() { + return html` +
+ Value: ${this.value} + +
+ `; + } + + _onDecrement() { + this.dispatchEvent( + new MesopEvent(this.decrementEvent, { + value: this.value - 1, + }), + ); + } + + connectedCallback() { + setTimeout( + () => { + this.dispatchEvent( + new MesopEvent(this.decrementEvent, { + value: this.value - 1, + }), + ); + }, + 2000 + ); // Change text after 2 seconds + } +} + +customElements.define('quickstart-counter-component', CounterComponent); diff --git a/fastagency/ui/mesop/main.py b/fastagency/ui/mesop/main.py index 342f4912..ac839ea4 100644 --- a/fastagency/ui/mesop/main.py +++ b/fastagency/ui/mesop/main.py @@ -22,7 +22,10 @@ DEFAULT_SECURITY_POLICY = me.SecurityPolicy( - allowed_iframe_parents=["https://fastagency.ai"] + allowed_script_srcs=[ + "https://cdn.jsdelivr.net", + ], + allowed_iframe_parents=["https://fastagency.ai"], ) diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/mesoptimer.py new file mode 100644 index 00000000..c1c99db2 --- /dev/null +++ b/fastagency/ui/mesop/mesoptimer.py @@ -0,0 +1,31 @@ +from pathlib import Path +from typing import Any, Callable, Optional + +import mesop.labs as mel + +pp = Path(__file__).parent +# os.path.dirname(__file__) +path_2_js = pp / "counter_component.js" +# path_2_js = os.path.join(pp, "counter_component.js") +# path_2_js = os.path.join(".", "counter_component.js") +# print("dir je:", pp, "u totalu:", path_2_js) + + +# @mel.web_component(path=path_2_js) +@mel.web_component(path="/javascript/counter_component.js") # type: ignore[misc] +def counter_component( + *, + value: int, + on_decrement: Callable[[mel.WebEvent], Any], + key: Optional[str] = None, +) -> mel.WebComponent: + return mel.insert_web_component( + name="quickstart-counter-component", + key=key, + events={ + "decrementEvent": on_decrement, + }, + properties={ + "value": value, + }, + ) diff --git a/fastagency/ui/mesop/message.py b/fastagency/ui/mesop/message.py index 70014201..dd0eeb55 100644 --- a/fastagency/ui/mesop/message.py +++ b/fastagency/ui/mesop/message.py @@ -4,6 +4,7 @@ from uuid import uuid4 import mesop as me +import mesop.labs as mel from fastagency.helpers import jsonify_string @@ -24,7 +25,8 @@ from .base import MesopMessage from .components.inputs import input_text from .data_model import Conversation, ConversationMessage, State -from .send_prompt import send_user_feedback_to_autogen +from .mesoptimer import counter_component +from .send_prompt import get_more_messages, send_user_feedback_to_autogen from .styles import MesopHomePageStyles, MesopMessageStyles logger = get_logger(__name__) @@ -185,6 +187,9 @@ def visit_error(self, message: Error) -> None: ) def visit_system_message(self, message: SystemMessage) -> None: + def on_timer_off(e: mel.WebEvent) -> Iterator[None]: + yield from consume_responses(get_more_messages()) + content = ( f"""#### **{message.message['heading']}** @@ -200,6 +205,12 @@ def visit_system_message(self, message: SystemMessage) -> None: style=self._styles.message.system, scrollable=True, ) + with me.box(style=me.Style(margin=me.Margin.all(15))): + me.text(text="hellooou") + counter_component( + value=17, + on_decrement=on_timer_off, + ) def visit_suggested_function_call(self, message: SuggestedFunctionCall) -> None: content = f"""**function_name**: `{message.function_name}`
diff --git a/fastagency/ui/mesop/send_prompt.py b/fastagency/ui/mesop/send_prompt.py index be22f02e..8f622dd8 100644 --- a/fastagency/ui/mesop/send_prompt.py +++ b/fastagency/ui/mesop/send_prompt.py @@ -22,3 +22,10 @@ def send_user_feedback_to_autogen(user_response: str) -> Iterable[MesopMessage]: mesop_io = MesopUI.get_conversation(mesop_id) mesop_io.respond(user_response) return mesop_io.get_message_stream() + + +def get_more_messages() -> Iterable[MesopMessage]: + state = me.state(State) + mesop_id = state.conversation.fastagency + mesop_io = MesopUI.get_conversation(mesop_id) + return mesop_io.get_message_stream() From ce1ab1388a055c2feb1f0942600c2298b00d4a06 Mon Sep 17 00:00:00 2001 From: Davor Runje Date: Mon, 7 Oct 2024 14:25:25 +0000 Subject: [PATCH 2/9] wip --- fastagency/ui/mesop/base.py | 4 ++ fastagency/ui/mesop/main.py | 1 - fastagency/ui/mesop/mesoptimer.py | 46 ++++++++++++++++++- .../counter_component.js | 0 4 files changed, 48 insertions(+), 3 deletions(-) rename {examples/cli/javascript => javascript}/counter_component.js (100%) diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index bec461c4..30205a52 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -26,6 +26,7 @@ Workflows, ) from ...logging import get_logger +from .mesoptimer import configure_static_file_serving from .styles import MesopHomePageStyles logger = get_logger(__name__) @@ -269,6 +270,9 @@ def handle_wsgi( MesopUI._created_instance = self MesopUI._app = app + if configure_static_file_serving is None: # pragme: no cover + logger.error("configure_static_file_serving is None") + if MesopUI._me is None: logger.error("MesopUI._me is None") raise RuntimeError("MesopUI._me is None") diff --git a/fastagency/ui/mesop/main.py b/fastagency/ui/mesop/main.py index ac839ea4..b72ea8dd 100644 --- a/fastagency/ui/mesop/main.py +++ b/fastagency/ui/mesop/main.py @@ -20,7 +20,6 @@ # Get the logger logger = get_logger(__name__) - DEFAULT_SECURITY_POLICY = me.SecurityPolicy( allowed_script_srcs=[ "https://cdn.jsdelivr.net", diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/mesoptimer.py index c1c99db2..ed9d268b 100644 --- a/fastagency/ui/mesop/mesoptimer.py +++ b/fastagency/ui/mesop/mesoptimer.py @@ -2,6 +2,17 @@ from typing import Any, Callable, Optional import mesop.labs as mel +import mesop.server.static_file_serving +import mesop.server.wsgi_app +from flask import Flask +from mesop.server.static_file_serving import ( + WEB_COMPONENTS_PATH_SEGMENT, + noop, + send_file_compressed, +) +from mesop.server.static_file_serving import ( + configure_static_file_serving as configure_static_file_serving_original, +) pp = Path(__file__).parent # os.path.dirname(__file__) @@ -11,14 +22,45 @@ # print("dir je:", pp, "u totalu:", path_2_js) +def configure_static_file_serving( + app: Flask, + static_file_runfiles_base: str, + livereload_script_url: str | None = None, + preprocess_request: Callable[[], None] = noop, + disable_gzip_cache: bool = False, + default_allowed_iframe_parents: str = "'self'", +): + configure_static_file_serving_original( + app=app, + static_file_runfiles_base=static_file_runfiles_base, + livereload_script_url=livereload_script_url, + preprocess_request=preprocess_request, + disable_gzip_cache=disable_gzip_cache, + default_allowed_iframe_parents=default_allowed_iframe_parents, + ) + + @app.route(f"/{WEB_COMPONENTS_PATH_SEGMENT}/__fast_agency_internal__/") + def serve_web_components_fast_agency(path: str): + root = Path(__file__).parents[3].resolve() + serving_path = f"{root}/{path}" + + return send_file_compressed( + serving_path, + disable_gzip_cache=disable_gzip_cache, + ) + + +mesop.server.wsgi_app.configure_static_file_serving = configure_static_file_serving + + # @mel.web_component(path=path_2_js) -@mel.web_component(path="/javascript/counter_component.js") # type: ignore[misc] +@mel.web_component(path="__fast_agency_internal__/javascript/counter_component.js") # type: ignore[misc] def counter_component( *, value: int, on_decrement: Callable[[mel.WebEvent], Any], key: Optional[str] = None, -) -> mel.WebComponent: +) -> Any: return mel.insert_web_component( name="quickstart-counter-component", key=key, diff --git a/examples/cli/javascript/counter_component.js b/javascript/counter_component.js similarity index 100% rename from examples/cli/javascript/counter_component.js rename to javascript/counter_component.js From cfb0c459e0def0e372f74c3eb25dbeba3cb9e4f9 Mon Sep 17 00:00:00 2001 From: Davor Runje Date: Mon, 7 Oct 2024 14:29:03 +0000 Subject: [PATCH 3/9] wip --- docs/docs/SUMMARY.md | 9 ++++----- .../mesoptimer/configure_static_file_serving.md} | 2 +- .../mesoptimer/counter_component.md} | 2 +- .../send_prompt/get_more_messages.md} | 2 +- fastagency/ui/mesop/main.py | 1 + fastagency/ui/mesop/mesoptimer.py | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) rename docs/docs/en/api/fastagency/ui/{fastapi/base/FastAPIWorkflows.md => mesop/mesoptimer/configure_static_file_serving.md} (62%) rename docs/docs/en/api/fastagency/ui/{fastapi/FastAPIProvider.md => mesop/mesoptimer/counter_component.md} (67%) rename docs/docs/en/api/fastagency/ui/{fastapi/base/FastAPIProvider.md => mesop/send_prompt/get_more_messages.md} (67%) diff --git a/docs/docs/SUMMARY.md b/docs/docs/SUMMARY.md index b598fd18..b4796ac5 100644 --- a/docs/docs/SUMMARY.md +++ b/docs/docs/SUMMARY.md @@ -133,11 +133,6 @@ search: - [ConsoleUI](api/fastagency/ui/console/ConsoleUI.md) - base - [ConsoleUI](api/fastagency/ui/console/base/ConsoleUI.md) - - fastapi - - [FastAPIProvider](api/fastagency/ui/fastapi/FastAPIProvider.md) - - base - - [FastAPIProvider](api/fastagency/ui/fastapi/base/FastAPIProvider.md) - - [FastAPIWorkflows](api/fastagency/ui/fastapi/base/FastAPIWorkflows.md) - mesop - [MesopUI](api/fastagency/ui/mesop/MesopUI.md) - base @@ -157,12 +152,16 @@ search: - [MesopHomePage](api/fastagency/ui/mesop/main/MesopHomePage.md) - [MesopHomePageParams](api/fastagency/ui/mesop/main/MesopHomePageParams.md) - [create_home_page](api/fastagency/ui/mesop/main/create_home_page.md) + - mesoptimer + - [configure_static_file_serving](api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md) + - [counter_component](api/fastagency/ui/mesop/mesoptimer/counter_component.md) - message - [MesopGUIMessageVisitor](api/fastagency/ui/mesop/message/MesopGUIMessageVisitor.md) - [consume_responses](api/fastagency/ui/mesop/message/consume_responses.md) - [handle_message](api/fastagency/ui/mesop/message/handle_message.md) - [message_box](api/fastagency/ui/mesop/message/message_box.md) - send_prompt + - [get_more_messages](api/fastagency/ui/mesop/send_prompt/get_more_messages.md) - [send_prompt_to_autogen](api/fastagency/ui/mesop/send_prompt/send_prompt_to_autogen.md) - [send_user_feedback_to_autogen](api/fastagency/ui/mesop/send_prompt/send_user_feedback_to_autogen.md) - styles diff --git a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md b/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md similarity index 62% rename from docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md rename to docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md index 0ed6b0de..1c2871b1 100644 --- a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIWorkflows.md +++ b/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.fastapi.base.FastAPIWorkflows +::: fastagency.ui.mesop.mesoptimer.configure_static_file_serving diff --git a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md b/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md similarity index 67% rename from docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md rename to docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md index b8b1fee2..d8e68061 100644 --- a/docs/docs/en/api/fastagency/ui/fastapi/FastAPIProvider.md +++ b/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.fastapi.FastAPIProvider +::: fastagency.ui.mesop.mesoptimer.counter_component diff --git a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md b/docs/docs/en/api/fastagency/ui/mesop/send_prompt/get_more_messages.md similarity index 67% rename from docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md rename to docs/docs/en/api/fastagency/ui/mesop/send_prompt/get_more_messages.md index cf91cc6e..4e4bf9ae 100644 --- a/docs/docs/en/api/fastagency/ui/fastapi/base/FastAPIProvider.md +++ b/docs/docs/en/api/fastagency/ui/mesop/send_prompt/get_more_messages.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.fastapi.base.FastAPIProvider +::: fastagency.ui.mesop.send_prompt.get_more_messages diff --git a/fastagency/ui/mesop/main.py b/fastagency/ui/mesop/main.py index b72ea8dd..ac839ea4 100644 --- a/fastagency/ui/mesop/main.py +++ b/fastagency/ui/mesop/main.py @@ -20,6 +20,7 @@ # Get the logger logger = get_logger(__name__) + DEFAULT_SECURITY_POLICY = me.SecurityPolicy( allowed_script_srcs=[ "https://cdn.jsdelivr.net", diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/mesoptimer.py index ed9d268b..430e587c 100644 --- a/fastagency/ui/mesop/mesoptimer.py +++ b/fastagency/ui/mesop/mesoptimer.py @@ -4,7 +4,7 @@ import mesop.labs as mel import mesop.server.static_file_serving import mesop.server.wsgi_app -from flask import Flask +from flask import Flask, Response from mesop.server.static_file_serving import ( WEB_COMPONENTS_PATH_SEGMENT, noop, @@ -25,11 +25,11 @@ def configure_static_file_serving( app: Flask, static_file_runfiles_base: str, - livereload_script_url: str | None = None, + livereload_script_url: Optional[str] = None, preprocess_request: Callable[[], None] = noop, disable_gzip_cache: bool = False, default_allowed_iframe_parents: str = "'self'", -): +) -> None: configure_static_file_serving_original( app=app, static_file_runfiles_base=static_file_runfiles_base, @@ -40,11 +40,11 @@ def configure_static_file_serving( ) @app.route(f"/{WEB_COMPONENTS_PATH_SEGMENT}/__fast_agency_internal__/") - def serve_web_components_fast_agency(path: str): + def serve_web_components_fast_agency(path: str) -> Response: root = Path(__file__).parents[3].resolve() serving_path = f"{root}/{path}" - return send_file_compressed( + return send_file_compressed( # type: ignore[no-any-return] serving_path, disable_gzip_cache=disable_gzip_cache, ) From e3cf183094809bfa01a1995551b50213da1e060c Mon Sep 17 00:00:00 2001 From: Davor Runje Date: Tue, 8 Oct 2024 07:28:49 +0000 Subject: [PATCH 4/9] bug fix: added slash --- fastagency/ui/mesop/mesoptimer.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/mesoptimer.py index 430e587c..0a143a2d 100644 --- a/fastagency/ui/mesop/mesoptimer.py +++ b/fastagency/ui/mesop/mesoptimer.py @@ -14,12 +14,9 @@ configure_static_file_serving as configure_static_file_serving_original, ) -pp = Path(__file__).parent -# os.path.dirname(__file__) -path_2_js = pp / "counter_component.js" -# path_2_js = os.path.join(pp, "counter_component.js") -# path_2_js = os.path.join(".", "counter_component.js") -# print("dir je:", pp, "u totalu:", path_2_js) +from ...logging import get_logger + +logger = get_logger(__name__) def configure_static_file_serving( @@ -30,6 +27,8 @@ def configure_static_file_serving( disable_gzip_cache: bool = False, default_allowed_iframe_parents: str = "'self'", ) -> None: + logger.info("Configuring static file serving with patched method") + configure_static_file_serving_original( app=app, static_file_runfiles_base=static_file_runfiles_base, @@ -41,6 +40,8 @@ def configure_static_file_serving( @app.route(f"/{WEB_COMPONENTS_PATH_SEGMENT}/__fast_agency_internal__/") def serve_web_components_fast_agency(path: str) -> Response: + logger.info(f"Serve web components fast agency: {path}") + root = Path(__file__).parents[3].resolve() serving_path = f"{root}/{path}" @@ -50,11 +51,11 @@ def serve_web_components_fast_agency(path: str) -> Response: ) +logger.info("Patching static file serving in Mesop") mesop.server.wsgi_app.configure_static_file_serving = configure_static_file_serving -# @mel.web_component(path=path_2_js) -@mel.web_component(path="__fast_agency_internal__/javascript/counter_component.js") # type: ignore[misc] +@mel.web_component(path="/__fast_agency_internal__/javascript/counter_component.js") # type: ignore[misc] def counter_component( *, value: int, From 975c4e9a474b6cdf071a890d25203bb3f68aa21f Mon Sep 17 00:00:00 2001 From: Davorin Rusevljan Date: Tue, 8 Oct 2024 08:25:21 +0000 Subject: [PATCH 5/9] added keep alive message --- fastagency/base.py | 10 ++++++++++ fastagency/ui/mesop/base.py | 7 ++++--- fastagency/ui/mesop/message.py | 10 ++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/fastagency/base.py b/fastagency/base.py index 359e4c6b..c2256612 100644 --- a/fastagency/base.py +++ b/fastagency/base.py @@ -29,6 +29,7 @@ "MultipleChoice", "Runnable", "SuggestedFunctionCall", + "KeepAlive", "SystemMessage", "TextInput", "TextMessage", @@ -45,6 +46,7 @@ "text_input", "multiple_choice", "system_message", + "keep_alive", "workflow_completed", "error", ] @@ -77,6 +79,7 @@ def _get_message_class(type: Optional[MessageType]) -> "Type[IOMessage]": "function_call_execution": FunctionCallExecution, "text_input": TextInput, "multiple_choice": MultipleChoice, + "keep_alive": KeepAlive, "system_message": SystemMessage, "workflow_completed": WorkflowCompleted, "error": Error, @@ -171,6 +174,10 @@ class Error(IOMessage): long: Optional[str] = None +@dataclass +class KeepAlive(IOMessage): ... + + class IOMessageVisitor(ABC): def visit(self, message: IOMessage) -> Optional[str]: method_name = f"visit_{message.type}" @@ -202,6 +209,9 @@ def visit_multiple_choice(self, message: MultipleChoice) -> Optional[str]: def visit_system_message(self, message: SystemMessage) -> Optional[str]: return self.visit_default(message) + def visit_keep_alive(self, message: KeepAlive) -> Optional[str]: + return self.visit_default(message) + def visit_workflow_completed(self, message: WorkflowCompleted) -> Optional[str]: return self.visit_default(message) diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index 30205a52..011bad57 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -17,9 +17,9 @@ AskingMessage, IOMessage, IOMessageVisitor, + KeepAlive, MultipleChoice, Runnable, - SystemMessage, TextInput, TextMessage, WorkflowCompleted, @@ -95,7 +95,7 @@ def __init__( def keep_me_alive(self) -> None: def keep_alive_worker() -> None: - msg = SystemMessage(message={"keepAlive": "Stayin' alive"}) + msg = KeepAlive() # msg = TextMessage(body="just stayin' alive") mesop_msg = self._mesop_message(msg) while self._keep_me_alive: @@ -202,6 +202,7 @@ def level(self) -> int: ) def _publish(self, mesop_msg: MesopMessage) -> None: + # todo uncomment this when testing is over # self.out_queue.put(mesop_msg) ... @@ -239,7 +240,7 @@ def create_subconversation(self) -> "MesopUI": return sub_conversation def _is_stream_braker(self, message: IOMessage) -> bool: - return isinstance(message, (AskingMessage, WorkflowCompleted, SystemMessage)) + return isinstance(message, (AskingMessage, WorkflowCompleted, KeepAlive)) def respond(self, message: str) -> None: self.in_queue.put(message) diff --git a/fastagency/ui/mesop/message.py b/fastagency/ui/mesop/message.py index dd0eeb55..6f5f793b 100644 --- a/fastagency/ui/mesop/message.py +++ b/fastagency/ui/mesop/message.py @@ -14,6 +14,7 @@ FunctionCallExecution, IOMessage, IOMessageVisitor, + KeepAlive, MultipleChoice, SuggestedFunctionCall, SystemMessage, @@ -187,9 +188,6 @@ def visit_error(self, message: Error) -> None: ) def visit_system_message(self, message: SystemMessage) -> None: - def on_timer_off(e: mel.WebEvent) -> Iterator[None]: - yield from consume_responses(get_more_messages()) - content = ( f"""#### **{message.message['heading']}** @@ -198,13 +196,17 @@ def on_timer_off(e: mel.WebEvent) -> Iterator[None]: if "heading" in message.message and "body" in message.message else json.dumps(message.message) ) - self.visit_default( message, content=content, style=self._styles.message.system, scrollable=True, ) + + def visit_keep_alive(self, message: KeepAlive) -> None: + def on_timer_off(e: mel.WebEvent) -> Iterator[None]: + yield from consume_responses(get_more_messages()) + with me.box(style=me.Style(margin=me.Margin.all(15))): me.text(text="hellooou") counter_component( From 5b4bec4751bdc652beea0eed657c9ad8522d1834 Mon Sep 17 00:00:00 2001 From: Davorin Rusevljan Date: Tue, 8 Oct 2024 09:34:20 +0000 Subject: [PATCH 6/9] trimming the wakeup component --- fastagency/ui/mesop/base.py | 1 + fastagency/ui/mesop/mesoptimer.py | 15 ++++----- fastagency/ui/mesop/message.py | 17 ++++++----- javascript/counter_component.js | 51 ------------------------------- javascript/wakeup_component.js | 33 ++++++++++++++++++++ 5 files changed, 49 insertions(+), 68 deletions(-) delete mode 100644 javascript/counter_component.js create mode 100644 javascript/wakeup_component.js diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index 011bad57..f3b24ac9 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -101,6 +101,7 @@ def keep_alive_worker() -> None: while self._keep_me_alive: time.sleep(3) if self._out_queue: + print("sending keep alive") self._out_queue.put(mesop_msg) if self._keep_me_alive and self._keep_alive_thread is None: diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/mesoptimer.py index 0a143a2d..9d025564 100644 --- a/fastagency/ui/mesop/mesoptimer.py +++ b/fastagency/ui/mesop/mesoptimer.py @@ -55,20 +55,17 @@ def serve_web_components_fast_agency(path: str) -> Response: mesop.server.wsgi_app.configure_static_file_serving = configure_static_file_serving -@mel.web_component(path="/__fast_agency_internal__/javascript/counter_component.js") # type: ignore[misc] -def counter_component( +@mel.web_component(path="/__fast_agency_internal__/javascript/wakeup_component.js") # type: ignore[misc] +def wakeup_component( *, - value: int, - on_decrement: Callable[[mel.WebEvent], Any], + on_wakeup: Callable[[mel.WebEvent], Any], key: Optional[str] = None, ) -> Any: return mel.insert_web_component( - name="quickstart-counter-component", + name="wakeup-component", key=key, events={ - "decrementEvent": on_decrement, - }, - properties={ - "value": value, + "wakeupEvent": on_wakeup, }, + properties={}, ) diff --git a/fastagency/ui/mesop/message.py b/fastagency/ui/mesop/message.py index 6f5f793b..7f349a1f 100644 --- a/fastagency/ui/mesop/message.py +++ b/fastagency/ui/mesop/message.py @@ -26,7 +26,7 @@ from .base import MesopMessage from .components.inputs import input_text from .data_model import Conversation, ConversationMessage, State -from .mesoptimer import counter_component +from .mesoptimer import wakeup_component from .send_prompt import get_more_messages, send_user_feedback_to_autogen from .styles import MesopHomePageStyles, MesopMessageStyles @@ -204,15 +204,16 @@ def visit_system_message(self, message: SystemMessage) -> None: ) def visit_keep_alive(self, message: KeepAlive) -> None: - def on_timer_off(e: mel.WebEvent) -> Iterator[None]: + def on_wakeup(e: mel.WebEvent) -> Iterator[None]: + logger.info("waking up, after the keep alive") yield from consume_responses(get_more_messages()) - with me.box(style=me.Style(margin=me.Margin.all(15))): - me.text(text="hellooou") - counter_component( - value=17, - on_decrement=on_timer_off, - ) + logger.info("visiting keep alive") + if not self._readonly: + logger.info("setting up wake up") + with me.box(style=me.Style(margin=me.Margin.all(15))): + me.text(text="hellooou") + wakeup_component(on_wakeup=on_wakeup) def visit_suggested_function_call(self, message: SuggestedFunctionCall) -> None: content = f"""**function_name**: `{message.function_name}`
diff --git a/javascript/counter_component.js b/javascript/counter_component.js deleted file mode 100644 index 05371feb..00000000 --- a/javascript/counter_component.js +++ /dev/null @@ -1,51 +0,0 @@ -import { - LitElement, - html, -} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js'; - -class CounterComponent extends LitElement { - static properties = { - value: { type: Number }, - decrementEvent: { type: String }, - }; - - constructor() { - super(); - this.value = 0; - this.decrementEvent = ''; - } - - render() { - return html` -
- Value: ${this.value} - -
- `; - } - - _onDecrement() { - this.dispatchEvent( - new MesopEvent(this.decrementEvent, { - value: this.value - 1, - }), - ); - } - - connectedCallback() { - setTimeout( - () => { - this.dispatchEvent( - new MesopEvent(this.decrementEvent, { - value: this.value - 1, - }), - ); - }, - 2000 - ); // Change text after 2 seconds - } -} - -customElements.define('quickstart-counter-component', CounterComponent); diff --git a/javascript/wakeup_component.js b/javascript/wakeup_component.js new file mode 100644 index 00000000..43d68aa3 --- /dev/null +++ b/javascript/wakeup_component.js @@ -0,0 +1,33 @@ +import { + LitElement, + html, +} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js'; + +class WakeupComponent extends LitElement { + static properties = { + wakeupEvent: { type: String }, + }; + + constructor() { + super(); + this.wakeupEvent = ''; + } + + render() { + return html``; + } + + connectedCallback() { + setTimeout( + () => { + this.dispatchEvent( + new MesopEvent(this.wakeupEvent, { + }), + ); + }, + 100 + ); + } +} + +customElements.define('wakeup-component', WakeupComponent); From a6a731e2c796287a9682bebd2c04a58c2ab7d26d Mon Sep 17 00:00:00 2001 From: Davorin Rusevljan Date: Tue, 8 Oct 2024 11:01:27 +0000 Subject: [PATCH 7/9] stop keep alives when conversation is over --- fastagency/ui/mesop/base.py | 19 +++++++++---------- fastagency/ui/mesop/message.py | 8 +++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index f3b24ac9..6fac7e48 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -95,19 +95,21 @@ def __init__( def keep_me_alive(self) -> None: def keep_alive_worker() -> None: - msg = KeepAlive() - # msg = TextMessage(body="just stayin' alive") - mesop_msg = self._mesop_message(msg) while self._keep_me_alive: time.sleep(3) if self._out_queue: - print("sending keep alive") + msg = KeepAlive() + mesop_msg = self._mesop_message(msg) + logger.info(f"putting keepalive {msg.uuid}") self._out_queue.put(mesop_msg) if self._keep_me_alive and self._keep_alive_thread is None: self._keep_alive_thread = threading.Thread(target=keep_alive_worker) self._keep_alive_thread.start() + def do_not_keep_me_alive(self) -> None: + self._keep_me_alive = False + @classmethod def get_created_instance(cls) -> "MesopUI": created_instance = cls._created_instance @@ -203,9 +205,7 @@ def level(self) -> int: ) def _publish(self, mesop_msg: MesopMessage) -> None: - # todo uncomment this when testing is over - # self.out_queue.put(mesop_msg) - ... + self.out_queue.put(mesop_msg) def _mesop_message(self, io_message: IOMessage) -> MesopMessage: return MesopMessage( @@ -303,7 +303,6 @@ def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: ui=subconversation, # type: ignore[arg-type] initial_message=initial_message, ) - ui.process_message( IOMessage.create( sender="user", @@ -315,7 +314,6 @@ def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: }, ) ) - ui.process_message( IOMessage.create( sender="user", @@ -344,7 +342,8 @@ def conversation_worker(ui: MesopUI, subconversation: MesopUI) -> None: result="Exception raised", ) ) - return + finally: + ui.do_not_keep_me_alive() ui = MesopUI(keep_alive=True) subconversation = ui.create_subconversation() diff --git a/fastagency/ui/mesop/message.py b/fastagency/ui/mesop/message.py index 7f349a1f..e497a01b 100644 --- a/fastagency/ui/mesop/message.py +++ b/fastagency/ui/mesop/message.py @@ -206,13 +206,11 @@ def visit_system_message(self, message: SystemMessage) -> None: def visit_keep_alive(self, message: KeepAlive) -> None: def on_wakeup(e: mel.WebEvent) -> Iterator[None]: logger.info("waking up, after the keep alive") + self._conversation_message.feedback_completed = True yield from consume_responses(get_more_messages()) - logger.info("visiting keep alive") - if not self._readonly: - logger.info("setting up wake up") - with me.box(style=me.Style(margin=me.Margin.all(15))): - me.text(text="hellooou") + with me.box(): + if not (self._readonly or self._conversation_message.feedback_completed): wakeup_component(on_wakeup=on_wakeup) def visit_suggested_function_call(self, message: SuggestedFunctionCall) -> None: From 37c512d8f8324192cf03c6b462f6ce502c729140 Mon Sep 17 00:00:00 2001 From: Davor Runje Date: Tue, 8 Oct 2024 11:58:37 +0000 Subject: [PATCH 8/9] wip --- docs/docs/SUMMARY.md | 7 +-- .../KeepAlive.md} | 2 +- .../configure_static_file_serving.md | 2 +- .../ui/mesop/timer/wakeup_component.md | 11 ++++ fastagency/ui/mesop/base.py | 2 +- fastagency/ui/mesop/counter_component.js | 51 ------------------- fastagency/ui/mesop/message.py | 2 +- .../ui/mesop/{mesoptimer.py => timer.py} | 0 pyproject.toml | 4 +- 9 files changed, 21 insertions(+), 60 deletions(-) rename docs/docs/en/api/fastagency/{ui/mesop/mesoptimer/counter_component.md => base/KeepAlive.md} (67%) rename docs/docs/en/api/fastagency/ui/mesop/{mesoptimer => timer}/configure_static_file_serving.md (62%) create mode 100644 docs/docs/en/api/fastagency/ui/mesop/timer/wakeup_component.md delete mode 100644 fastagency/ui/mesop/counter_component.js rename fastagency/ui/mesop/{mesoptimer.py => timer.py} (100%) diff --git a/docs/docs/SUMMARY.md b/docs/docs/SUMMARY.md index 900b4ae3..aa3cef34 100644 --- a/docs/docs/SUMMARY.md +++ b/docs/docs/SUMMARY.md @@ -62,6 +62,7 @@ search: - [FunctionCallExecution](api/fastagency/base/FunctionCallExecution.md) - [IOMessage](api/fastagency/base/IOMessage.md) - [IOMessageVisitor](api/fastagency/base/IOMessageVisitor.md) + - [KeepAlive](api/fastagency/base/KeepAlive.md) - [MultipleChoice](api/fastagency/base/MultipleChoice.md) - [Runnable](api/fastagency/base/Runnable.md) - [SuggestedFunctionCall](api/fastagency/base/SuggestedFunctionCall.md) @@ -158,9 +159,6 @@ search: - [MesopHomePage](api/fastagency/ui/mesop/main/MesopHomePage.md) - [MesopHomePageParams](api/fastagency/ui/mesop/main/MesopHomePageParams.md) - [create_home_page](api/fastagency/ui/mesop/main/create_home_page.md) - - mesoptimer - - [configure_static_file_serving](api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md) - - [counter_component](api/fastagency/ui/mesop/mesoptimer/counter_component.md) - message - [MesopGUIMessageVisitor](api/fastagency/ui/mesop/message/MesopGUIMessageVisitor.md) - [consume_responses](api/fastagency/ui/mesop/message/consume_responses.md) @@ -177,6 +175,9 @@ search: - [MesopMultipleChoiceInnerStyles](api/fastagency/ui/mesop/styles/MesopMultipleChoiceInnerStyles.md) - [MesopSingleChoiceInnerStyles](api/fastagency/ui/mesop/styles/MesopSingleChoiceInnerStyles.md) - [MesopTextInputInnerStyles](api/fastagency/ui/mesop/styles/MesopTextInputInnerStyles.md) + - timer + - [configure_static_file_serving](api/fastagency/ui/mesop/timer/configure_static_file_serving.md) + - [wakeup_component](api/fastagency/ui/mesop/timer/wakeup_component.md) - nats - [InitiateModel](api/fastagency/ui/nats/InitiateModel.md) - [InputResponseModel](api/fastagency/ui/nats/InputResponseModel.md) diff --git a/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md b/docs/docs/en/api/fastagency/base/KeepAlive.md similarity index 67% rename from docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md rename to docs/docs/en/api/fastagency/base/KeepAlive.md index d8e68061..67bfdd07 100644 --- a/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/counter_component.md +++ b/docs/docs/en/api/fastagency/base/KeepAlive.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.mesop.mesoptimer.counter_component +::: fastagency.base.KeepAlive diff --git a/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md b/docs/docs/en/api/fastagency/ui/mesop/timer/configure_static_file_serving.md similarity index 62% rename from docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md rename to docs/docs/en/api/fastagency/ui/mesop/timer/configure_static_file_serving.md index 1c2871b1..55c9127a 100644 --- a/docs/docs/en/api/fastagency/ui/mesop/mesoptimer/configure_static_file_serving.md +++ b/docs/docs/en/api/fastagency/ui/mesop/timer/configure_static_file_serving.md @@ -8,4 +8,4 @@ search: boost: 0.5 --- -::: fastagency.ui.mesop.mesoptimer.configure_static_file_serving +::: fastagency.ui.mesop.timer.configure_static_file_serving diff --git a/docs/docs/en/api/fastagency/ui/mesop/timer/wakeup_component.md b/docs/docs/en/api/fastagency/ui/mesop/timer/wakeup_component.md new file mode 100644 index 00000000..89b19201 --- /dev/null +++ b/docs/docs/en/api/fastagency/ui/mesop/timer/wakeup_component.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: fastagency.ui.mesop.timer.wakeup_component diff --git a/fastagency/ui/mesop/base.py b/fastagency/ui/mesop/base.py index 6fac7e48..9075a01d 100644 --- a/fastagency/ui/mesop/base.py +++ b/fastagency/ui/mesop/base.py @@ -26,8 +26,8 @@ Workflows, ) from ...logging import get_logger -from .mesoptimer import configure_static_file_serving from .styles import MesopHomePageStyles +from .timer import configure_static_file_serving logger = get_logger(__name__) diff --git a/fastagency/ui/mesop/counter_component.js b/fastagency/ui/mesop/counter_component.js deleted file mode 100644 index 05371feb..00000000 --- a/fastagency/ui/mesop/counter_component.js +++ /dev/null @@ -1,51 +0,0 @@ -import { - LitElement, - html, -} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js'; - -class CounterComponent extends LitElement { - static properties = { - value: { type: Number }, - decrementEvent: { type: String }, - }; - - constructor() { - super(); - this.value = 0; - this.decrementEvent = ''; - } - - render() { - return html` -
- Value: ${this.value} - -
- `; - } - - _onDecrement() { - this.dispatchEvent( - new MesopEvent(this.decrementEvent, { - value: this.value - 1, - }), - ); - } - - connectedCallback() { - setTimeout( - () => { - this.dispatchEvent( - new MesopEvent(this.decrementEvent, { - value: this.value - 1, - }), - ); - }, - 2000 - ); // Change text after 2 seconds - } -} - -customElements.define('quickstart-counter-component', CounterComponent); diff --git a/fastagency/ui/mesop/message.py b/fastagency/ui/mesop/message.py index e497a01b..07e173e5 100644 --- a/fastagency/ui/mesop/message.py +++ b/fastagency/ui/mesop/message.py @@ -26,9 +26,9 @@ from .base import MesopMessage from .components.inputs import input_text from .data_model import Conversation, ConversationMessage, State -from .mesoptimer import wakeup_component from .send_prompt import get_more_messages, send_user_feedback_to_autogen from .styles import MesopHomePageStyles, MesopMessageStyles +from .timer import wakeup_component logger = get_logger(__name__) diff --git a/fastagency/ui/mesop/mesoptimer.py b/fastagency/ui/mesop/timer.py similarity index 100% rename from fastagency/ui/mesop/mesoptimer.py rename to fastagency/ui/mesop/timer.py diff --git a/pyproject.toml b/pyproject.toml index 76a76479..aad4b9e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,11 +174,11 @@ exclude = [ allow-direct-references = true [tool.hatch.build.targets.wheel] -only-include = ["fastagency", "templates"] +only-include = ["fastagency", "templates", "javascript"] [tool.hatch.build.targets.wheel.sources] "src" = "" -"scripts" = "fastagency/templates" +"scripts" = "fastagency/templates, fastagency/javascript" [tool.mypy] From fb10e67beddcce3026de30b3f191293ca1171751 Mon Sep 17 00:00:00 2001 From: Davor Runje Date: Tue, 8 Oct 2024 12:17:06 +0000 Subject: [PATCH 9/9] polishing --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index aad4b9e2..08122870 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,8 +177,8 @@ allow-direct-references = true only-include = ["fastagency", "templates", "javascript"] [tool.hatch.build.targets.wheel.sources] -"src" = "" -"scripts" = "fastagency/templates, fastagency/javascript" +# "src" = "" +# "scripts" = "fastagency/scripts" [tool.mypy]