def on_propose(self, propose: Message, dialogue: Dialogue) -> Envelope: """ Handle a Propose. :param propose: the message containing the Propose :param dialogue: the dialogue :return: an Accept or a Decline """ logger.debug("[{}]: on propose as {}.".format(self.agent_name, dialogue.role)) assert propose.get("performative") == FIPAMessage.Performative.PROPOSE proposal = propose.get("proposal")[0] transaction_id = generate_transaction_id( self.crypto.public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction = Transaction.from_proposal( proposal=proposal, transaction_id=transaction_id, is_sender_buyer=not dialogue.is_seller, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key) new_msg_id = propose.get("id") + 1 is_profitable_transaction, propose_log_msg = self.game_instance.is_profitable_transaction( transaction, dialogue) logger.debug(propose_log_msg) if is_profitable_transaction: logger.debug("[{}]: Accepting propose (as {}).".format( self.agent_name, dialogue.role)) self.game_instance.transaction_manager.add_locked_tx( transaction, as_seller=dialogue.is_seller) self.game_instance.transaction_manager.add_pending_initial_acceptance( dialogue.dialogue_label, new_msg_id, transaction) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.ACCEPT) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) else: logger.debug("[{}]: Declining propose (as {})".format( self.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) return result
def _handle(self, message: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle a message according to the defined behaviour. :param message: the agent message :param dialogue: the dialogue :return: a list of agent messages """ dialogue.incoming_extend([message]) results = [] # type: List[Envelope] performative = message.get("performative") if performative == FIPAMessage.Performative.CFP: result = self.negotiation_behaviour.on_cfp(message, dialogue) results = [result] elif performative == FIPAMessage.Performative.PROPOSE: result = self.negotiation_behaviour.on_propose(message, dialogue) results = [result] elif performative == FIPAMessage.Performative.ACCEPT: results = self.negotiation_behaviour.on_accept(message, dialogue) elif performative == FIPAMessage.Performative.MATCH_ACCEPT: results = self.negotiation_behaviour.on_match_accept( message, dialogue) elif performative == FIPAMessage.Performative.DECLINE: self.negotiation_behaviour.on_decline(message, dialogue) results = [] else: raise ValueError("Performative not supported: {}".format( str(performative))) return results
def on_match_accept(self, match_accept: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle a matching Accept. :param match_accept: the envelope containing the MatchAccept :param dialogue: the dialogue :return: a Transaction """ assert (match_accept.get("performative") == FIPAMessage.Performative.MATCH_ACCEPT and dialogue.dialogue_label in self.game_instance. transaction_manager.pending_initial_acceptances and match_accept.get("target") in self.game_instance.transaction_manager. pending_initial_acceptances[dialogue.dialogue_label]) logger.debug( "[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format( self.agent_name, match_accept.get("id"), match_accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, match_accept.get("target"), )) results = [] transaction = self.game_instance.transaction_manager.pop_pending_initial_acceptance( dialogue.dialogue_label, match_accept.get("target")) tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION, transaction_id=transaction.transaction_id, is_sender_buyer=transaction.is_sender_buyer, counterparty=transaction.counterparty, amount=transaction.amount, quantities_by_good_pbk=transaction.quantities_by_good_pbk, ) dialogue.outgoing_extend([tac_msg]) tac_bytes = TACSerializer().encode(tac_msg) results.append( Envelope( to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, )) return results
def on_cfp(self, cfp: Message, dialogue: Dialogue) -> Envelope: """ Handle a CFP. :param cfp: the message containing the CFP :param dialogue: the dialogue :return: a Propose or a Decline """ assert cfp.get("performative") == FIPAMessage.Performative.CFP goods_description = self.game_instance.get_service_description( is_supply=dialogue.is_seller) new_msg_id = cfp.get("id") + 1 decline = False cfp_services = json.loads(cfp.get("query").decode('utf-8')) if not self.game_instance.is_matching(cfp_services, goods_description): decline = True logger.debug( "[{}]: Current holdings do not satisfy CFP query.".format( self.agent_name)) else: proposal = self.game_instance.generate_proposal( cfp_services, dialogue.is_seller) if proposal is None: decline = True logger.debug( "[{}]: Current strategy does not generate proposal that satisfies CFP query." .format(self.agent_name)) if decline: logger.debug("[{}]: sending to {} a Decline{}".format( self.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("target") }))) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), performative=FIPAMessage.Performative.DECLINE, target=cfp.get("id")) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) response = Envelope( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_CFP, dialogue.is_self_initiated) else: proposal = cast(Description, proposal) transaction_id = generate_transaction_id( self.crypto.public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction = Transaction.from_proposal( proposal=proposal, transaction_id=transaction_id, is_sender_buyer=not dialogue.is_seller, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key) self.game_instance.transaction_manager.add_pending_proposal( dialogue.dialogue_label, new_msg_id, transaction) logger.debug("[{}]: sending to {} a Propose{}".format( self.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("id"), "propose": proposal.values }))) msg = FIPAMessage(performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), target=cfp.get("id"), proposal=[proposal]) dialogue.outgoing_extend([msg]) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) response = Envelope( to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) return response
def on_accept(self, accept: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle an Accept. :param accept: the message containing the Accept :param dialogue: the dialogue :return: a Decline, or an Accept and a Transaction, or a Transaction (in a Message object) """ assert accept.get("performative") == FIPAMessage.Performative.ACCEPT \ and dialogue.dialogue_label in self.game_instance.transaction_manager.pending_proposals \ and accept.get("target") in self.game_instance.transaction_manager.pending_proposals[dialogue.dialogue_label] logger.debug( "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}". format(self.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = accept.get("id") + 1 results = [] transaction = self.game_instance.transaction_manager.pop_pending_proposal( dialogue.dialogue_label, accept.get("target")) is_profitable_transaction, accept_log_msg = self.game_instance.is_profitable_transaction( transaction, dialogue) logger.debug(accept_log_msg) if is_profitable_transaction: 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.transaction_manager.add_locked_tx( transaction, as_seller=dialogue.is_seller) tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION, transaction_id=transaction.transaction_id, is_sender_buyer=transaction.is_sender_buyer, counterparty=transaction.counterparty, amount=transaction.amount, quantities_by_good_pbk=transaction.quantities_by_good_pbk) dialogue.outgoing_extend([tac_msg]) tac_bytes = TACSerializer().encode(tac_msg) results.append( Envelope(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)) msg = FIPAMessage( message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) else: logger.debug("[{}]: Decline the accept (as {}).".format( self.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) return results