Spaces:
Running
Running
import json | |
import uuid | |
from toolformers.base import Toolformer | |
from utils import extract_substring | |
NEGOTIATION_RULES = ''' | |
Here are some rules (that should also be explained to the other GPT): | |
- You can assume that the protocol has a sender and a receiver. Do not worry about how the messages will be delivered, focus only on the content of the messages. | |
- Keep the protocol short and simple. It should be easy to understand and implement. | |
- The protocol must specify the exact format of what is sent and received. Do not leave it open to interpretation. | |
- The implementation will be written by a programmer that does not have access to the negotiation process, so make sure the protocol is clear and unambiguous. | |
- The implementation will receive a string and return a string, so structure your protocol accordingly. | |
- The other party might have a different internal data schema or set of tools, so make sure that the protocol is flexible enough to accommodate that. | |
- There will only be one message sent by the sender and one message sent by the receiver. Design the protocol accordingly. | |
- Keep the negotiation short: no need to repeat the same things over and over. | |
- If the other party has proposed a protocol and you're good with it, there's no reason to keep negotiating or to repeat the protocol to the other party. | |
- Do not restate parts of the protocols that have already been agreed upon. | |
And remember: keep the protocol as simple and unequivocal as necessary. The programmer that will implement the protocol can code, but they are not a mind reader. | |
''' | |
TASK_NEGOTIATOR_PROMPT = f''' | |
You are ProtocolNegotiatorGPT. Your task is to negotiate a protocol that can be used to query a service. | |
You will receive a JSON schema of the task that the service must perform. Negotiate with the service to determine a protocol that can be used to query it. | |
To do so, you will chat with another GPT (role: user) that will negotiate on behalf of the service. | |
{NEGOTIATION_RULES} | |
Once you are ready to save the protocol, reply wrapping the final version of the protocol, as agreed in your negotiation, between the tags <FINALPROTOCOL> and </FINALPROTOCOL>. | |
Within the body of the tag, add the tags <NAME></NAME> and <DESCRIPTION></DESCRIPTION> to specify the name and description of the protocol. | |
Remember that the <FINALPROTOCOL></FINALPROTOCOL> tags should also contain the protocol itself. Nothing outside such tags will be stored. | |
''' | |
class SenderNegotiator: | |
def __init__(self, toolformer : Toolformer): | |
self.toolformer = toolformer | |
def negotiate_protocol_for_task(self, task_schema, callback_fn, final_message_callback_fn=None): | |
found_protocol = None | |
prompt = TASK_NEGOTIATOR_PROMPT + '\nThe JSON schema of the task is the following:\n\n' + json.dumps(task_schema, indent=2) | |
conversation = self.toolformer.new_conversation(prompt, [], category='negotiation') | |
other_message = 'Hello! How may I help you?' | |
conversation_id = None | |
for i in range(10): | |
print('===NegotiatorGPT===') | |
message = conversation.chat(other_message, print_output=True) | |
print('Checking if we can extract from:', message) | |
print('---------') | |
protocol = extract_substring(message, '<FINALPROTOCOL>', '</FINALPROTOCOL>') | |
if protocol is None: | |
print('Could not extract') | |
other_message = callback_fn(message) | |
print() | |
print('===Other GPT===') | |
print(other_message) | |
print() | |
else: | |
if final_message_callback_fn: | |
rest_of_message = message.split('<FINALPROTOCOL>')[0] | |
final_message_callback_fn(rest_of_message) | |
name = extract_substring(protocol, '<NAME>', '</NAME>') | |
description = extract_substring(protocol, '<DESCRIPTION>', '</DESCRIPTION>') | |
if name is None: | |
name = 'Unnamed protocol' | |
if description is None: | |
description = 'No description provided' | |
found_protocol = { | |
'name': name, | |
'description': description, | |
'protocol': protocol | |
} | |
break | |
return found_protocol | |
TOOLS_NEGOTIATOR_PROMPT = f''' | |
You are ProtocolNegotiatorGPT. You are negotiating a protocol on behalf of a web service that can perform a task. | |
The other party is a GPT that is negotiating on behalf of the user. Your goal is to negotiate a protocol that is simple and clear, \ | |
but also expressive enough to allow the service to perform the task. A protocol is sufficiently expressive if you could write code \ | |
that, given the query formatted according to the protocol and the tools at the service's disposal, can parse the query according to \ | |
the protocol's specification, perform the task (if any) and send a reply. | |
{NEGOTIATION_RULES} | |
You will receive a list of tools that are available to the programmer that will implement the protocol. | |
When you are okay with the protocol, don't further repeat everything, just tell to the other party that you are done. | |
''' | |
class ReceiverNegotiator: | |
def __init__(self, toolformer : Toolformer, tools, additional_info): | |
prompt = TOOLS_NEGOTIATOR_PROMPT | |
prompt += '\n\n' + additional_info | |
prompt += '\n\nThe tools that the implementer will have access to are:\n\n' | |
if len(tools) == 0: | |
prompt += 'No additional tools provided' | |
else: | |
for tool in tools: | |
prompt += tool.as_documented_python() + '\n\n' | |
print('Prompt:', prompt) | |
self.conversation = toolformer.new_conversation(prompt, tools, category='negotiation') | |
def handle_negotiation(self, message): | |
reply = self.conversation.chat(message, print_output=True) | |
return reply |