From 4b7a3256a9390fc94d5c9b94150a5c1118587883 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Mon, 6 Jan 2025 15:23:51 +0000 Subject: [PATCH 1/4] Add pagination to treasury app --- .../app_nft_treasury_game.py | 49 ++++++++++++++++--- .../db/agent_communication.py | 3 +- .../db/long_term_memory_table_handler.py | 2 + prediction_market_agent/db/sql_handler.py | 3 ++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py index 1c70cb67..5e7993a6 100644 --- a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py @@ -37,7 +37,10 @@ ReceiveMessage, SendPaidMessageToAnotherAgent, ) -from prediction_market_agent.db.agent_communication import fetch_unseen_transactions +from prediction_market_agent.db.agent_communication import ( + fetch_count_unprocessed_transactions, + fetch_unseen_transactions, +) from prediction_market_agent.db.long_term_memory_table_handler import ( LongTermMemories, LongTermMemoryTableHandler, @@ -178,12 +181,39 @@ def customized_chat_message( st.markdown(parsed_function_output_body) -@st.fragment(run_every=timedelta(seconds=5)) def show_function_calls_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> None: st.markdown(f"""### Agent's actions""") + messages_per_page = 50 + if "page_number" not in st.session_state: + st.session_state.page_number = 0 + + col1, col2, col3 = st.columns(3) + with col1: + if st.button("Previous page", disabled=st.session_state.page_number == 0): + st.session_state.page_number -= 1 + with col2: + if st.button("Next page"): + st.session_state.page_number += 1 + with col3: + st.write(f"Current page {st.session_state.page_number + 1}") + + show_function_calls_part_messages( + nft_agent, messages_per_page, st.session_state.page_number + ) + + +@st.fragment(run_every=timedelta(seconds=10)) +def show_function_calls_part_messages( + nft_agent: type[DeployableAgentNFTGameAbstract], + messages_per_page: int, + page_number: int, +) -> None: with st.spinner("Loading agent's actions..."): - calls = long_term_memory_table_handler(nft_agent.identifier).search() + calls = long_term_memory_table_handler(nft_agent.identifier).search( + offset=page_number * messages_per_page, + limit=messages_per_page, + ) if not calls: st.markdown("No actions yet.") @@ -205,7 +235,7 @@ def show_function_calls_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> customized_chat_message(function_call, function_output) -@st.fragment(run_every=timedelta(seconds=5)) +@st.fragment(run_every=timedelta(seconds=10)) def show_about_agent_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> None: system_prompt = ( system_prompt_from_db.prompt @@ -240,7 +270,9 @@ def show_about_agent_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> No ) st.markdown("---") with st.popover("Show unprocessed incoming messages"): - messages = fetch_unseen_transactions(nft_agent.wallet_address) + show_n = 10 + n_messages = fetch_count_unprocessed_transactions(nft_agent.wallet_address) + messages = fetch_unseen_transactions(nft_agent.wallet_address, n=show_n) if not messages: st.info("No unprocessed messages") @@ -248,15 +280,18 @@ def show_about_agent_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> No for message in messages: st.markdown( f""" - **From:** {message.sender} + **From:** {message.sender} **Message:** {unzip_message_else_do_nothing(message.message.hex())} **Value:** {wei_to_xdai(message.value)} xDai """ ) st.divider() + if n_messages > show_n: + st.write(f"... and another {n_messages - show_n} unprocessed messages.") + -@st.fragment(run_every=timedelta(seconds=5)) +@st.fragment(run_every=timedelta(seconds=10)) def show_treasury_part() -> None: treasury_xdai_balance = get_balances(TREASURY_SAFE_ADDRESS).xdai st.markdown( diff --git a/prediction_market_agent/db/agent_communication.py b/prediction_market_agent/db/agent_communication.py index 326eb2e7..36ebd65e 100644 --- a/prediction_market_agent/db/agent_communication.py +++ b/prediction_market_agent/db/agent_communication.py @@ -12,13 +12,14 @@ def fetch_unseen_transactions( consumer_address: ChecksumAddress, + n: int | None = None, ) -> list[MessageContainer]: agent_comm_contract = AgentCommunicationContract() count_unseen_messages = fetch_count_unprocessed_transactions(consumer_address) message_containers = par_map( - items=list(range(count_unseen_messages)), + items=list(range(n or count_unseen_messages)), func=lambda idx: agent_comm_contract.get_at_index( agent_address=consumer_address, idx=idx ), diff --git a/prediction_market_agent/db/long_term_memory_table_handler.py b/prediction_market_agent/db/long_term_memory_table_handler.py index 463f2054..3846746d 100644 --- a/prediction_market_agent/db/long_term_memory_table_handler.py +++ b/prediction_market_agent/db/long_term_memory_table_handler.py @@ -48,6 +48,7 @@ def search( self, from_: DatetimeUTC | None = None, to_: DatetimeUTC | None = None, + offset: int = 0, limit: int | None = None, ) -> list[LongTermMemories]: """Searches the LongTermMemoryTableHandler for entries within a specified datetime range that match @@ -64,5 +65,6 @@ def search( query_filters=query_filters, order_by_column_name=LongTermMemories.datetime_.key, # type: ignore[attr-defined] order_desc=True, + offset=offset, limit=limit, ) diff --git a/prediction_market_agent/db/sql_handler.py b/prediction_market_agent/db/sql_handler.py index 48094d14..40a8f5ba 100644 --- a/prediction_market_agent/db/sql_handler.py +++ b/prediction_market_agent/db/sql_handler.py @@ -34,6 +34,7 @@ def get_with_filter_and_order( query_filters: t.Sequence[ColumnElement[bool] | BinaryExpression[bool]] = (), order_by_column_name: str | None = None, order_desc: bool = True, + offset: int = 0, limit: int | None = None, ) -> list[SQLModelType]: with self.db_manager.get_session() as session: @@ -47,6 +48,8 @@ def get_with_filter_and_order( if order_desc else asc(order_by_column_name) ) + if offset: + query = query.offset(offset) if limit: query = query.limit(limit) results = query.all() From 503b7cf7cc330c8a28be4f45762e3b24a54ccbec Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Mon, 6 Jan 2025 15:27:33 +0000 Subject: [PATCH 2/4] formating --- .../microchain_agent/nft_treasury_game/app_nft_treasury_game.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py index 5e7993a6..ad96df7e 100644 --- a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py @@ -280,7 +280,7 @@ def show_about_agent_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> No for message in messages: st.markdown( f""" - **From:** {message.sender} + **From:** {message.sender} **Message:** {unzip_message_else_do_nothing(message.message.hex())} **Value:** {wei_to_xdai(message.value)} xDai """ From d795348b2e9c73b5e953ae512322d24c0aa49df5 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Tue, 7 Jan 2025 09:28:50 +0000 Subject: [PATCH 3/4] disable next page --- .../app_nft_treasury_game.py | 7 ++++- .../db/long_term_memory_table_handler.py | 26 +++++++++++++------ prediction_market_agent/db/sql_handler.py | 10 +++++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py index ad96df7e..74412fea 100644 --- a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py @@ -184,6 +184,7 @@ def customized_chat_message( def show_function_calls_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> None: st.markdown(f"""### Agent's actions""") + n_total_messages = long_term_memory_table_handler(nft_agent.identifier).count() messages_per_page = 50 if "page_number" not in st.session_state: st.session_state.page_number = 0 @@ -193,7 +194,11 @@ def show_function_calls_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> if st.button("Previous page", disabled=st.session_state.page_number == 0): st.session_state.page_number -= 1 with col2: - if st.button("Next page"): + if st.button( + "Next page", + disabled=st.session_state.page_number + == n_total_messages // messages_per_page, + ): st.session_state.page_number += 1 with col3: st.write(f"Current page {st.session_state.page_number + 1}") diff --git a/prediction_market_agent/db/long_term_memory_table_handler.py b/prediction_market_agent/db/long_term_memory_table_handler.py index 3846746d..595e7d68 100644 --- a/prediction_market_agent/db/long_term_memory_table_handler.py +++ b/prediction_market_agent/db/long_term_memory_table_handler.py @@ -2,6 +2,7 @@ import typing as t from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow +from sqlalchemy.sql.elements import ColumnElement from sqlmodel import col from prediction_market_agent.agents.identifiers import AgentIdentifier @@ -44,6 +45,18 @@ def save_answer_with_scenario( ) -> None: return self.save_history([answer_with_scenario.model_dump()]) + def _get_query_filters( + self, from_: DatetimeUTC | None, to_: DatetimeUTC | None + ) -> list[ColumnElement[bool]]: + query_filters = [ + col(LongTermMemories.task_description) == self.task_description + ] + if from_ is not None: + query_filters.append(col(LongTermMemories.datetime_) >= from_) + if to_ is not None: + query_filters.append(col(LongTermMemories.datetime_) <= to_) + return query_filters + def search( self, from_: DatetimeUTC | None = None, @@ -53,14 +66,7 @@ def search( ) -> list[LongTermMemories]: """Searches the LongTermMemoryTableHandler for entries within a specified datetime range that match self.task_description.""" - query_filters = [ - col(LongTermMemories.task_description) == self.task_description - ] - if from_ is not None: - query_filters.append(col(LongTermMemories.datetime_) >= from_) - if to_ is not None: - query_filters.append(col(LongTermMemories.datetime_) <= to_) - + query_filters = self._get_query_filters(from_, to_) return self.sql_handler.get_with_filter_and_order( query_filters=query_filters, order_by_column_name=LongTermMemories.datetime_.key, # type: ignore[attr-defined] @@ -68,3 +74,7 @@ def search( offset=offset, limit=limit, ) + + def count(self) -> int: + query_filters = self._get_query_filters(None, None) + return self.sql_handler.count(query_filters=query_filters) diff --git a/prediction_market_agent/db/sql_handler.py b/prediction_market_agent/db/sql_handler.py index 40a8f5ba..3288a25f 100644 --- a/prediction_market_agent/db/sql_handler.py +++ b/prediction_market_agent/db/sql_handler.py @@ -54,3 +54,13 @@ def get_with_filter_and_order( query = query.limit(limit) results = query.all() return results + + def count( + self, + query_filters: t.Sequence[ColumnElement[bool] | BinaryExpression[bool]] = (), + ) -> int: + with self.db_manager.get_session() as session: + query = session.query(self.table) + for exp in query_filters: + query = query.where(exp) + return query.count() From 8bbdb1d1b3c553ad8dc45467e4ec94e5bedff37b Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Tue, 7 Jan 2025 12:10:14 +0000 Subject: [PATCH 4/4] small fix --- prediction_market_agent/db/agent_communication.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/prediction_market_agent/db/agent_communication.py b/prediction_market_agent/db/agent_communication.py index 36ebd65e..9a5d74d6 100644 --- a/prediction_market_agent/db/agent_communication.py +++ b/prediction_market_agent/db/agent_communication.py @@ -19,7 +19,13 @@ def fetch_unseen_transactions( count_unseen_messages = fetch_count_unprocessed_transactions(consumer_address) message_containers = par_map( - items=list(range(n or count_unseen_messages)), + items=list( + range( + min(n, count_unseen_messages) + if n is not None + else count_unseen_messages + ) + ), func=lambda idx: agent_comm_contract.get_at_index( agent_address=consumer_address, idx=idx ),