Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions infra/ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ deployments:
name: gpt-4o
sku:
name: "GlobalStandard"
capacity: 80
capacity: 150
- name: gpt-4-evals
model:
format: OpenAI
name: gpt-4o-mini
sku:
name: "GlobalStandard"
capacity: 80
capacity: 150
13 changes: 7 additions & 6 deletions src/api/agents/researcher/researcher.prompty
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ Return the results as a list of JSON objects with the following structure:
- It's important that you only return the json object, nothing else!! Do not return any additional text.
- Make sure to return at least 4 articles, but no more than 5.

# Feedback
Use this feedback to help you refine your queries and responses - if there is any feedback:

{{feedback}}

# Market Codes
The following are the market codes for the countries and regions that are supported by
the Microsoft Bing API and should be used when formulating your queries. Use the language
Expand All @@ -127,5 +122,11 @@ Swedish, sv-SE
Turkish, tr-TR
English, en-US

assistant:
# Feedback
Use this feedback to help you refine your queries and responses - if there is any feedback:

{{feedback}}

user:
{{instructions}}
{{instructions}}
197 changes: 111 additions & 86 deletions src/api/agents/researcher/researcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,106 +19,131 @@
# At the moment, it should be in the format "<HostName>;<AzureSubscriptionId>;<ResourceGroup>;<HubName>"
# Customer needs to login to Azure subscription via Azure CLI and set the environment variables


@trace
def execute_research(instructions: str, feedback: str = "No feedback"):

ai_project_conn_str = os.getenv("AZURE_LOCATION")+".api.azureml.ms;"+os.getenv("AZURE_SUBSCRIPTION_ID")+";"+os.getenv("AZURE_RESOURCE_GROUP")+";"+os.getenv("AZURE_AI_PROJECT_NAME")

project_client = AIProjectClient.from_connection_string(
credential=DefaultAzureCredential(),
conn_str=ai_project_conn_str,
ai_project_conn_str = os.getenv("AZURE_LOCATION")+".api.azureml.ms;"+os.getenv("AZURE_SUBSCRIPTION_ID")+";"+os.getenv("AZURE_RESOURCE_GROUP")+";"+os.getenv("AZURE_AI_PROJECT_NAME")
print(f"Connection string: {ai_project_conn_str}")

project_client = AIProjectClient.from_connection_string(
credential=DefaultAzureCredential(),
conn_str=ai_project_conn_str,
)
print(f"Project client created: {project_client}")

prompt_template = PromptTemplate.from_prompty(file_path="researcher.prompty")

bing_connection = project_client.connections.get(
connection_name='bing-connection'
)
conn_id = bing_connection.id

# Initialize agent bing tool and add the connection id
bing = BingGroundingTool(connection_id=conn_id)

# Extract instructions from system message in Prompty template
messages = prompt_template.create_messages(instructions='', feedback='')
system_messages = [m for m in messages if m['role'] == 'system']
agent_system_instructions = system_messages[0]['content']

AGENT_NAME = "contoso-creative-writer"
found_agent = None
all_agents_list = project_client.agents.list_agents().data
for a in all_agents_list:
if a.name == AGENT_NAME:
found_agent = a
break

model_name = "gpt-4"
if found_agent:
# Update the existing agent to use new tools
agent = project_client.agents.update_agent(
assistant_id=found_agent.id,
model=model_name,
instructions=agent_system_instructions,
tools=bing.definitions,
)

prompt_template = PromptTemplate.from_prompty(file_path="researcher.prompty")


instructions = instructions
feedback= feedback
messages = prompt_template.create_messages(instructions=instructions, feedback=feedback)

bing_connection = project_client.connections.get(
connection_name='bing-connection'
print(f"reusing agent > {agent.name} (id: {agent.id})")
else:
agent = project_client.agents.create_agent(
model=model_name,
name=AGENT_NAME,
instructions=agent_system_instructions,
tools=bing.definitions,
)
conn_id = bing_connection.id

# Initialize agent bing tool and add the connection id
bing = BingGroundingTool(connection_id=conn_id)
print(f"creating agent > {agent.name} (id: {agent.id})")

prompt_template = PromptTemplate.from_prompty(file_path="researcher.prompty")
@trace
def execute_research(instructions: str, feedback: str = None):

# Create agent with the bing tool and process assistant run
with project_client:
agent = project_client.agents.create_agent(
model="gpt-4",
name="my-assistant",
instructions=messages[0]['content'],
tools=bing.definitions,
)
if not feedback:
feedback = "No feedback"

print(f"Created agent, ID: {agent.id}")
# Create thread for communication
thread = project_client.agents.create_thread()
print(f"Created thread, ID: {thread.id}")

# Create thread for communication
thread = project_client.agents.create_thread()
print(f"Created thread, ID: {thread.id}")
# Create assistant and user messages from Prompty template
messages = prompt_template.create_messages(instructions=instructions, feedback=feedback)
thread_messages = [m for m in messages if m['role'] in ['assistant', 'user']]
for message in thread_messages:
content = message['content']
role = message['role']

# Create message to thread
message = project_client.agents.create_message(
thread_id=thread.id,
role="user",
content=instructions,
)
print(f"Created message, ID: {message.id}")

# # Create and process agent run in thread with tools
# run = project_client.agents.create_stream(thread_id=thread.id, assistant_id=agent.id)
def is_rate_limited(run):
# Check if the run failed due to rate limit
if run.status == "failed" and run.last_error and run.last_error.get('code') == 'rate_limit_exceeded':
print(f"Run failed: {run.last_error}")
return True # Indicates Tenacity should retry
return False # No retry needed

@retry(
retry=retry_if_result(is_rate_limited),
wait=wait_exponential(multiplier=1, min=4, max=60),
stop=stop_after_attempt(6)
role=role,
content=content,
)
def run_agent():
# Create and process agent run in thread with tools
run = project_client.agents.create_and_process_run(thread_id=thread.id, assistant_id=agent.id)
print(f"Run finished with status: {run.status}")
return run

run = run_agent()
# Retrieve run step details to get Bing Search query link
# To render the webpage, we recommend you replace the endpoint of Bing search query URLs with `www.bing.com` and your Bing search query URL would look like "https://www.bing.com/search?q={search query}"
run_steps = project_client.agents.list_run_steps(run_id=run.id, thread_id=thread.id)
run_steps_data = run_steps['data']

print(f"Agent created and now researching...")
print('')

# Delete the assistant when done
project_client.agents.delete_agent(agent.id)

# Fetch and log all messages
messages = project_client.agents.list_messages(thread_id=thread.id)
# print(f"Messages: {messages}")
print(f"Created {role} message, ID: {message.id}")

# Create and process agent run in thread with tools
# run = project_client.agents.create_stream(thread_id=thread.id, assistant_id=agent.id)
def is_rate_limited(run):
# Check if the run failed due to rate limit
if run.status == "failed" and run.last_error and run.last_error.get('code') == 'rate_limit_exceeded':
print(f"Run failed: {run.last_error}")
return True # Indicates Tenacity should retry
return False # No retry needed

@retry(
retry=retry_if_result(is_rate_limited),
wait=wait_exponential(multiplier=1, min=4, max=60),
stop=stop_after_attempt(6)
)
def run_agent():
# Create and process agent run in thread with tools
run = project_client.agents.create_and_process_run(thread_id=thread.id, assistant_id=agent.id)
print(f"Run finished with status: {run.status}")
return run

run = run_agent()
# Retrieve run step details to get Bing Search query link
# To render the webpage, we recommend you replace the endpoint of Bing search query URLs with `www.bing.com` and your Bing search query URL would look like "https://www.bing.com/search?q={search query}"
run_steps = project_client.agents.list_run_steps(run_id=run.id, thread_id=thread.id)
run_steps_data = run_steps['data']

print(f"Agent created and now researching...")
print('')

# Delete the assistant when done
#project_client.agents.delete_agent(agent.id)

# Fetch and log all messages
messages = project_client.agents.list_messages(thread_id=thread.id)
# print(f"Messages: {messages}")
research_response = messages.data[0]['content'][0]['text']['value']
try:
json_r = json.loads(research_response)
except:
print('retrying')
research_response = messages.data[0]['content'][0]['text']['value']
try:
json_r = json.loads(research_response)
except:
print('retrying')
research_response = messages.data[0]['content'][0]['text']['value']
json_r = json.loads(research_response)
research = json_r['web']
print('research succesfully completed')
return research
json_r = json.loads(research_response)
research = json_r['web']
print('research succesfully completed')
return research

@trace
def research(instructions: str, feedback: str = "No feedback"):
r = execute_research(instructions=instructions)
def research(instructions: str, feedback: str = None):
r = execute_research(instructions=instructions, feedback=feedback)
research = {
"web": r,
"entities": [],
Expand Down
12 changes: 2 additions & 10 deletions src/api/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from agents.researcher import researcher
from agents.product import product
from agents.writer import writer
# from agents.designer import designer
from agents.editor import editor
from evaluate.evaluators import evaluate_article_in_background
from prompty.tracer import trace, Tracer, console_tracer, PromptyTracer
Expand Down Expand Up @@ -68,12 +67,10 @@ def building_agents_message():
@trace
def create(research_context, product_context, assignment_context, evaluate=False):

feedback = "No Feedback"

yield building_agents_message()

yield start_message("researcher")
research_result = researcher.research(research_context, feedback)
research_result = researcher.research(research_context)
yield complete_message("researcher", research_result)

yield start_message("marketing")
Expand All @@ -88,7 +85,7 @@ def create(research_context, product_context, assignment_context, evaluate=False
product_context,
product_result,
assignment_context,
feedback,
feedback = "No Feedback",
)

full_result = " "
Expand All @@ -98,11 +95,6 @@ def create(research_context, product_context, assignment_context, evaluate=False

processed_writer_result = writer.process(full_result)

# send article to the designer, to generate an image for the blog
# yield start_message("designer")
# designer_response = designer.design(processed_writer_result['article'])
# yield complete_message("designer", [f"Image stored in {designer_response}"])

# Then send it to the editor, to decide if it's good or not
yield start_message("editor")
editor_response = editor.edit(processed_writer_result['article'], processed_writer_result["feedback"])
Expand Down
2 changes: 1 addition & 1 deletion src/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev": "vite --host",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
Expand Down