Skip to content

Commit 7b600bd

Browse files
authored
Merge pull request #95 from ks6088ts-labs/feature/issue-94_azure-ai-foundry
add Azure AI Foundry operator
2 parents 46cdc7e + 12759e2 commit 7b600bd

File tree

6 files changed

+447
-0
lines changed

6 files changed

+447
-0
lines changed

.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ AZURE_OPENAI_MODEL_CHAT="gpt-5"
2020
AZURE_OPENAI_MODEL_EMBEDDING="text-embedding-3-small"
2121
AZURE_OPENAI_MODEL_REASONING="o4-mini"
2222

23+
## Azure AI Foundry
24+
AZURE_AI_FOUNDRY_INFERENCE_ENDPOINT="https://xxx.services.ai.azure.com/api/projects/xxx"
25+
AZURE_AI_FOUNDRY_INFERENCE_API_VERSION="2025-04-01-preview"
26+
AZURE_AI_FOUNDRY_INFERENCE_MODEL_CHAT="gpt-5"
27+
2328
## Ollama Settings
2429
OLLAMA_MODEL_CHAT="gemma3:270m"
2530

docs/references.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
- [Azure Cosmos DB No SQL](https://python.langchain.com/docs/integrations/vectorstores/azure_cosmos_db_no_sql/)
3030
- [Azure AI Search](https://python.langchain.com/docs/integrations/vectorstores/azuresearch/)
3131

32+
### Azure AI Foundry
33+
34+
- [Quickstart: Get started with Azure AI Foundry](https://learn.microsoft.com/azure/ai-foundry/quickstarts/get-started-code?tabs=python&pivots=fdp-project)
35+
- [azure-rest-api-specs/specification/ai/data-plane/Azure.AI.Agents](https://github.com/Azure/azure-rest-api-specs/tree/main/specification/ai/data-plane/Azure.AI.Agents)
36+
3237
### Services
3338

3439
- [FastAPI](https://fastapi.tiangolo.com/)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ description = "A GitHub template repository for Python"
55
readme = "README.md"
66
requires-python = ">=3.10"
77
dependencies = [
8+
"azure-ai-projects>=1.0.0",
89
"azure-cosmos>=4.9.0",
910
"azure-identity>=1.23.1",
1011
"azure-search-documents>=11.5.3",
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
import logging
2+
3+
import typer
4+
from dotenv import load_dotenv
5+
6+
from template_langgraph.llms.azure_ai_foundrys import AzureAiFoundryWrapper
7+
from template_langgraph.loggers import get_logger
8+
9+
# Initialize the Typer application
10+
app = typer.Typer(
11+
add_completion=False,
12+
help="Azure AI Foundry operator CLI",
13+
)
14+
15+
# Set up logging
16+
logger = get_logger(__name__)
17+
18+
19+
@app.command()
20+
def chat(
21+
query: str = typer.Option(
22+
"Hello",
23+
"--query",
24+
"-q",
25+
help="The query to send to the AI",
26+
),
27+
verbose: bool = typer.Option(
28+
False,
29+
"--verbose",
30+
"-v",
31+
help="Enable verbose output",
32+
),
33+
):
34+
# Set up logging
35+
if verbose:
36+
logger.setLevel(logging.DEBUG)
37+
38+
logger.info("Running Azure AI Foundry chat...")
39+
40+
wrapper = AzureAiFoundryWrapper()
41+
42+
openai_client = wrapper.get_openai_client()
43+
44+
response = openai_client.chat.completions.create(
45+
model=wrapper.settings.azure_ai_foundry_inference_model_chat,
46+
messages=[
47+
{"role": "user", "content": query},
48+
],
49+
)
50+
logger.info(response.choices[0].message.content)
51+
52+
53+
@app.command()
54+
def create_agent(
55+
name: str = typer.Option(
56+
"MyAgent",
57+
"--name",
58+
"-n",
59+
help="The name of the agent",
60+
),
61+
instructions: str = typer.Option(
62+
"This is my agent",
63+
"--instructions",
64+
"-i",
65+
help="The instructions for the agent",
66+
),
67+
verbose: bool = typer.Option(
68+
False,
69+
"--verbose",
70+
"-v",
71+
help="Enable verbose output",
72+
),
73+
):
74+
# Set up logging
75+
if verbose:
76+
logger.setLevel(logging.DEBUG)
77+
78+
logger.info("Creating agent...")
79+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
80+
with project_client.agents as agents_client:
81+
# Create a new agent
82+
agent = agents_client.create_agent(
83+
name=name,
84+
instructions=instructions,
85+
model=AzureAiFoundryWrapper().settings.azure_ai_foundry_inference_model_chat,
86+
)
87+
logger.info(f"Created agent: {agent.as_dict()}")
88+
89+
90+
@app.command()
91+
def delete_agent(
92+
agent_id: str = typer.Option(
93+
"asst_xxx",
94+
"--agent-id",
95+
"-a",
96+
help="The ID of the agent to delete",
97+
),
98+
verbose: bool = typer.Option(
99+
False,
100+
"--verbose",
101+
"-v",
102+
help="Enable verbose output",
103+
),
104+
):
105+
# Set up logging
106+
if verbose:
107+
logger.setLevel(logging.DEBUG)
108+
109+
logger.info("Deleting agent...")
110+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
111+
with project_client.agents as agents_client:
112+
agents_client.delete_agent(agent_id=agent_id)
113+
114+
115+
@app.command()
116+
def list_agents(
117+
verbose: bool = typer.Option(
118+
False,
119+
"--verbose",
120+
"-v",
121+
help="Enable verbose output",
122+
),
123+
):
124+
# Set up logging
125+
if verbose:
126+
logger.setLevel(logging.DEBUG)
127+
128+
logger.info("Listing agents...")
129+
130+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
131+
with project_client.agents as agents_client:
132+
agents = agents_client.list_agents()
133+
for agent in agents:
134+
logger.info(f"Agent ID: {agent.id}, Name: {agent.name}")
135+
136+
137+
@app.command()
138+
def create_thread(
139+
verbose: bool = typer.Option(
140+
False,
141+
"--verbose",
142+
"-v",
143+
help="Enable verbose output",
144+
),
145+
):
146+
# Set up logging
147+
if verbose:
148+
logger.setLevel(logging.DEBUG)
149+
150+
logger.info("Creating thread...")
151+
152+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
153+
thread = project_client.agents.threads.create()
154+
logger.info(thread.as_dict())
155+
156+
157+
@app.command()
158+
def delete_thread(
159+
thread_id: str = typer.Option(
160+
"thread_xxx",
161+
"--thread-id",
162+
"-t",
163+
help="The ID of the thread to delete",
164+
),
165+
verbose: bool = typer.Option(
166+
False,
167+
"--verbose",
168+
"-v",
169+
help="Enable verbose output",
170+
),
171+
):
172+
# Set up logging
173+
if verbose:
174+
logger.setLevel(logging.DEBUG)
175+
176+
logger.info("Deleting thread...")
177+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
178+
project_client.agents.threads.delete(thread_id=thread_id)
179+
180+
181+
@app.command()
182+
def list_threads(
183+
verbose: bool = typer.Option(
184+
False,
185+
"--verbose",
186+
"-v",
187+
help="Enable verbose output",
188+
),
189+
):
190+
# Set up logging
191+
if verbose:
192+
logger.setLevel(logging.DEBUG)
193+
194+
logger.info("Listing threads...")
195+
196+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
197+
threads = project_client.agents.threads.list()
198+
for thread in threads:
199+
logger.info(thread.as_dict())
200+
201+
202+
@app.command()
203+
def create_message(
204+
role: str = typer.Option(
205+
"user",
206+
"--role",
207+
"-r",
208+
help="The role of the message sender",
209+
),
210+
content: str = typer.Option(
211+
"Hello, world!",
212+
"--content",
213+
"-c",
214+
help="The content of the message",
215+
),
216+
thread_id: str = typer.Option(
217+
"thread_xxx",
218+
"--thread-id",
219+
"-t",
220+
help="The ID of the thread to list messages from",
221+
),
222+
verbose: bool = typer.Option(
223+
False,
224+
"--verbose",
225+
"-v",
226+
help="Enable verbose output",
227+
),
228+
):
229+
# Set up logging
230+
if verbose:
231+
logger.setLevel(logging.DEBUG)
232+
233+
logger.info("Creating message...")
234+
235+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
236+
message = project_client.agents.messages.create(
237+
thread_id=thread_id,
238+
role=role,
239+
content=content,
240+
)
241+
logger.info(message.as_dict())
242+
243+
244+
@app.command()
245+
def list_messages(
246+
thread_id: str = typer.Option(
247+
"thread_xxx",
248+
"--thread-id",
249+
"-t",
250+
help="The ID of the thread to list messages from",
251+
),
252+
verbose: bool = typer.Option(
253+
False,
254+
"--verbose",
255+
"-v",
256+
help="Enable verbose output",
257+
),
258+
):
259+
# Set up logging
260+
if verbose:
261+
logger.setLevel(logging.DEBUG)
262+
263+
logger.info("Listing messages...")
264+
265+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
266+
messages = project_client.agents.messages.list(thread_id=thread_id)
267+
for message in messages:
268+
logger.info(message.as_dict())
269+
270+
271+
@app.command()
272+
def run_thread(
273+
agent_id: str = typer.Option(
274+
"agent_xxx",
275+
"--agent-id",
276+
"-a",
277+
help="The ID of the agent to run",
278+
),
279+
thread_id: str = typer.Option(
280+
"thread_xxx",
281+
"--thread-id",
282+
"-t",
283+
help="The ID of the thread to run",
284+
),
285+
verbose: bool = typer.Option(
286+
False,
287+
"--verbose",
288+
"-v",
289+
help="Enable verbose output",
290+
),
291+
):
292+
# Set up logging
293+
if verbose:
294+
logger.setLevel(logging.DEBUG)
295+
296+
logger.info("Running thread...")
297+
298+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
299+
run = project_client.agents.runs.create(
300+
thread_id=thread_id,
301+
agent_id=agent_id,
302+
)
303+
304+
logger.info(f"Run created: {run.as_dict()}")
305+
306+
307+
@app.command()
308+
def get_run(
309+
thread_id: str = typer.Option(
310+
"thread_xxx",
311+
"--thread-id",
312+
"-t",
313+
help="The ID of the thread to run",
314+
),
315+
run_id: str = typer.Option(
316+
"run_xxx",
317+
"--run-id",
318+
"-r",
319+
help="The ID of the run to retrieve",
320+
),
321+
verbose: bool = typer.Option(
322+
False,
323+
"--verbose",
324+
"-v",
325+
help="Enable verbose output",
326+
),
327+
):
328+
# Set up logging
329+
if verbose:
330+
logger.setLevel(logging.DEBUG)
331+
332+
logger.info("Getting run...")
333+
334+
project_client = AzureAiFoundryWrapper().get_ai_project_client()
335+
run = project_client.agents.runs.get(
336+
thread_id=thread_id,
337+
run_id=run_id,
338+
)
339+
logger.info(run.as_dict())
340+
341+
342+
if __name__ == "__main__":
343+
load_dotenv(
344+
override=True,
345+
verbose=True,
346+
)
347+
app()

0 commit comments

Comments
 (0)