def on_unidentified_dialogue(self, msg: AgentMessage) -> None: """ React to an unidentified dialogue. :param msg: agent message :return: None """ logger.debug("[{}]: Unidentified dialogue.".format(self.agent_name)) result = ByteMessage( msg.msg_id + 1, msg.dialogue_id, msg.destination, b'This message belongs to an unidentified dialogue.', Context()) self.out_box.out_queue.put(result)
def on_decline(self, msg_id: int, dialogue_id: int, origin: str, target: int) -> None: """ Handle a Decline. :param msg_id: the message id :param dialogue_id: the dialogue id :param origin: the public key of the sending agent :param target: the message id targetted by this message :return: None """ self.in_queue.put( Decline(msg_id, dialogue_id, origin, target, Context()))
def on_message(self, msg_id: int, dialogue_id: int, origin: str, content: bytes) -> None: """ Handle a message. :param msg_id: the message id :param dialogue_id: the dialogue id :param origin: the public key of the sending agent :param content: the message body :return: None """ self.in_queue.put( ByteMessage(msg_id, dialogue_id, origin, content, Context()))
def on_propose(self, msg_id: int, dialogue_id: int, origin: str, target: int, proposals: PROPOSE_TYPES) -> None: """ Handle a Propose. :param msg_id: the message id :param dialogue_id: the dialogue id :param origin: the public key of the sending agent :param target: the message id targetted by this message :param proposals: the proposals :return: None """ self.in_queue.put( Propose(msg_id, dialogue_id, origin, target, proposals, Context()))
def on_cfp(self, msg_id: int, dialogue_id: int, origin: str, target: int, query: CFP_TYPES) -> None: """ Handle a CFP. :param msg_id: the message id :param dialogue_id: the dialogue id :param origin: the public key of the sending agent :param target: the message id targetted by this message :param query: the query :return: None """ self.in_queue.put( CFP(msg_id, dialogue_id, origin, target, query, Context()))
def _on_services_search_result(self, agent_pbks: List[str], is_searching_for_sellers: bool) -> None: """ Process the search result for services. :param agent_pbks: the agent public keys matching the search query :param is_searching_for_sellers: whether it is searching for sellers or not :return: None """ agent_pbks_set = set(agent_pbks) if self.crypto.public_key in agent_pbks_set: agent_pbks_set.remove(self.crypto.public_key) agent_pbks = list(agent_pbks_set) searched_for = 'sellers' if is_searching_for_sellers else 'buyers' logger.debug("[{}]: Found potential {}: {}".format( self.agent_name, searched_for, agent_pbks)) query = self.game_instance.build_services_query( is_searching_for_sellers) if query is None: response = 'demanding' if is_searching_for_sellers else 'supplying' logger.debug("[{}]: No longer {} any goods...".format( self.agent_name, response)) return for agent_pbk in agent_pbks: dialogue = self.game_instance.dialogues.create_self_initiated( agent_pbk, self.crypto.public_key, not is_searching_for_sellers) cfp = CFP(STARTING_MESSAGE_ID, dialogue.dialogue_label.dialogue_id, agent_pbk, STARTING_MESSAGE_TARGET, query, Context()) logger.debug( "[{}]: send_cfp_as_{}: msg_id={}, dialogue_id={}, destination={}, target={}, query={}" .format(self.agent_name, dialogue.role, cfp.msg_id, cfp.dialogue_id, cfp.destination, cfp.target, query)) dialogue.outgoing_extend([cfp]) self.out_box.out_queue.put(cfp)
def on_cfp(self, cfp: CFP, dialogue: Dialogue) -> Union[Propose, Decline]: """ Handle a CFP. :param cfp: the CFP :param dialogue: the dialogue :return: a Propose or a Decline """ goods_description = self.game_instance.get_service_description(is_supply=dialogue.is_seller) new_msg_id = cfp.msg_id + 1 if not cfp.query.check(goods_description): logger.debug("[{}]: Current holdings do not satisfy CFP query.".format(self.agent_name)) logger.debug("[{}]: sending to {} a Decline{}".format(self.agent_name, cfp.destination, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.dialogue_id, "origin": cfp.destination, "target": cfp.msg_id }))) response = Decline(new_msg_id, cfp.dialogue_id, cfp.destination, cfp.msg_id, Context()) self.game_instance.stats_manager.add_dialogue_endstate(EndState.DECLINED_CFP, dialogue.is_self_initiated) else: proposals = [random.choice(self.game_instance.get_proposals(cfp.query, dialogue.is_seller))] self.game_instance.lock_manager.store_proposals(proposals, new_msg_id, dialogue, cfp.destination, dialogue.is_seller, self.crypto) logger.debug("[{}]: sending to {} a Propose{}".format(self.agent_name, cfp.destination, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.dialogue_id, "origin": cfp.destination, "target": cfp.msg_id, "propose": proposals[0].values # TODO fix if more than one proposal! }))) response = Propose(new_msg_id, cfp.dialogue_id, cfp.destination, cfp.msg_id, proposals, Context()) return response
def _on_initial_accept(self, accept: Accept, dialogue: Dialogue) -> Union[List[Decline], List[Union[OutContainer, Accept]]]: """ Handle an initial Accept. :param accept: the accept :param dialogue: the dialogue :return: a Deline or an Accept and a Transaction (in OutContainer """ transaction = self.game_instance.lock_manager.pop_pending_proposal(dialogue, accept.target) new_msg_id = accept.msg_id + 1 results = [] if self._is_profitable_transaction(transaction, dialogue): if self.game_instance.strategy.is_world_modeling: self.game_instance.world_state.update_on_initial_accept(transaction) logger.debug("[{}]: Locking the current state (as {}).".format(self.agent_name, dialogue.role)) self.game_instance.lock_manager.add_lock(transaction, as_seller=dialogue.is_seller) results.append(OutContainer(message=transaction.serialize(), message_id=STARTING_MESSAGE_ID, dialogue_id=accept.dialogue_id, destination=self.game_instance.controller_pbk)) results.append(Accept(new_msg_id, accept.dialogue_id, accept.destination, accept.msg_id, Context())) else: logger.debug("[{}]: Decline the accept (as {}).".format(self.agent_name, dialogue.role)) results.append(Decline(new_msg_id, accept.dialogue_id, accept.destination, accept.msg_id, Context())) self.game_instance.stats_manager.add_dialogue_endstate(EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) return results
def on_propose(self, propose: Propose, dialogue: Dialogue) -> Union[Accept, Decline]: """ Handle a Propose. :param propose: the Propose :param dialogue: the dialogue :return: an Accept or a Decline """ logger.debug("[{}]: on propose as {}.".format(self.agent_name, dialogue.role)) proposal = propose.proposals[0] transaction_id = generate_transaction_id(self.crypto.public_key, propose.destination, dialogue.dialogue_label, dialogue.is_seller) transaction = Transaction.from_proposal(proposal, transaction_id, is_sender_buyer=not dialogue.is_seller, counterparty=propose.destination, sender=self.crypto.public_key, crypto=self.crypto) new_msg_id = propose.msg_id + 1 if self._is_profitable_transaction(transaction, dialogue): logger.debug("[{}]: Accepting propose (as {}).".format(self.agent_name, dialogue.role)) self.game_instance.lock_manager.add_lock(transaction, as_seller=dialogue.is_seller) self.game_instance.lock_manager.add_pending_initial_acceptance(dialogue, new_msg_id, transaction) result = Accept(new_msg_id, propose.dialogue_id, propose.destination, propose.msg_id, Context()) else: logger.debug("[{}]: Declining propose (as {})".format(self.agent_name, dialogue.role)) result = Decline(new_msg_id, propose.dialogue_id, propose.destination, propose.msg_id, Context()) self.game_instance.stats_manager.add_dialogue_endstate(EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) return result