Skip to content
Closed
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
7 changes: 5 additions & 2 deletions python/samples/01-get-started/01_hello_agent.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import os

from dotenv import load_dotenv
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
Expand All @@ -15,12 +17,13 @@
There are XML tags in all of the get started samples, those are used to display the same code in the docs repo.
"""

load_dotenv() # Load environment variables from .env file

async def main() -> None:
# <create_agent>
client = FoundryChatClient(
project_endpoint="https://your-project.services.ai.azure.com",
model="gpt-4o",
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)

Expand Down
9 changes: 7 additions & 2 deletions python/samples/01-get-started/02_add_tools.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import os
from random import randint
from typing import Annotated

from dotenv import load_dotenv

from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
Expand All @@ -16,6 +19,8 @@
and wire it into an agent so the model can call it.
"""

load_dotenv() # Load environment variables from .env file


# <define_tool>
# NOTE: approval_mode="never_require" is for sample brevity.
Expand All @@ -34,8 +39,8 @@ def get_weather(

async def main() -> None:
client = FoundryChatClient(
project_endpoint="https://your-project.services.ai.azure.com",
model="gpt-4o",
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)

Expand Down
9 changes: 7 additions & 2 deletions python/samples/01-get-started/03_multi_turn.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import os

from dotenv import load_dotenv

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
Expand All @@ -13,12 +16,14 @@
by reusing the same session object.
"""

load_dotenv() # Load environment variables from .env file


async def main() -> None:
# <create_agent>
client = FoundryChatClient(
project_endpoint="https://your-project.services.ai.azure.com",
model="gpt-4o",
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)

Expand Down
9 changes: 7 additions & 2 deletions python/samples/01-get-started/04_memory.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import os
from typing import Any

from dotenv import load_dotenv

from agent_framework import Agent, AgentSession, ContextProvider, SessionContext
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
Expand All @@ -15,6 +18,8 @@
responses — the name persists across turns via the session.
"""

load_dotenv() # Load environment variables from .env file


# <context_provider>
class UserMemoryProvider(ContextProvider):
Expand Down Expand Up @@ -67,8 +72,8 @@ async def after_run(
async def main() -> None:
# <create_agent>
client = FoundryChatClient(
project_endpoint="https://your-project.services.ai.azure.com",
model="gpt-4o",
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ async def poem_workflow(topic: str) -> str:


async def main() -> None:
workflow_instance = poem_workflow.build()
result = await workflow_instance.run("a cat learning to code")
poem = poem_workflow.build()
result = await poem.run("a cat learning to code")
print(result.get_outputs()[0])


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ async def text_workflow(text: str) -> str:

async def main() -> None:
# <run_workflow>
workflow_instance = text_workflow.build()
result = await workflow_instance.run("hello world")
pipeline = text_workflow.build()
result = await pipeline.run("hello world")
print(f"Output: {result.get_outputs()}")
print(f"Final state: {result.get_final_state()}")
# </run_workflow>
Expand Down
68 changes: 65 additions & 3 deletions python/samples/01-get-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,75 @@ pip install agent-framework-foundry

Sample 08 additionally requires `agent-framework-azurefunctions --pre`.

Set the required environment variables:
### 1. Configure environment variables

The samples read connection settings from environment variables (or a local
`.env` file loaded via `python-dotenv`). The project endpoint has the shape
`https://<account>.services.ai.azure.com/api/projects/<project>` and must
point at a Foundry **project**, not the account root.

```bash
export FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
export FOUNDRY_MODEL="<your-deployment-name>" # required; must match a deployment on the account
```

Or drop the same keys into `python/samples/.env`:

```dotenv
FOUNDRY_PROJECT_ENDPOINT=https://<account>.services.ai.azure.com/api/projects/<project>
FOUNDRY_MODEL=<your-deployment-name>
```

> `load_dotenv()` walks upward and loads the **first** `.env` it finds, so a
> `python/samples/.env` next to the samples shadows a `python/.env` higher up.
> If a value looks wrong at runtime, edit the nearest `.env` on the path.
> Also note that already-set shell env vars take precedence over `.env` unless
> you pass `load_dotenv(override=True)`.

### 2. Sign in and grant data-plane access

The samples authenticate with `AzureCliCredential`, so first run:

```bash
export FOUNDRY_PROJECT_ENDPOINT="https://your-project-endpoint"
export FOUNDRY_MODEL="gpt-4o" # optional, defaults to gpt-4o
az login
```

Calling the Foundry project's inference endpoints (Responses, Chat
Completions, etc. under `/api/projects/<project>/openai/v1/...`) requires a
data-plane role on the AI Services account (or the project sub-resource).
The Responses path is served by the **AIServices** RBAC namespace, so the
`Azure AI Developer` role — which does not include
`Microsoft.CognitiveServices/accounts/AIServices/responses/*` — is **not**
sufficient on its own.

Assign one of the following to your user/service principal on the account
`Microsoft.CognitiveServices/accounts/<account>` (or the child
`.../projects/<project>` scope):

| Role | Grants | Notes |
|------|--------|-------|
| `Foundry Project Runtime User` | `Microsoft.CognitiveServices/accounts/AIServices/responses/*` | Minimal role for the Responses API. |
| `Foundry User` | `Microsoft.CognitiveServices/*` | Broader; covers all Foundry data-plane calls. |

Example (account scope, broad role):

```bash
az role assignment create \
--assignee "<your-object-id>" \
--role "Foundry User" \
--scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>"
```

Role propagation can take up to a few minutes. Symptoms of missing/insufficient
roles:

- `401 Unauthorized` — token audience wrong or no role at all.
- `403 PermissionDenied` on the project URL — a role is assigned but its
`dataActions` don't cover `AIServices/responses/*`.
- `404 DeploymentNotFound` — auth is OK but `FOUNDRY_MODEL` doesn't match any
deployment on the account. Verify with
`az cognitiveservices account deployment list -g <rg> -n <account>`.

## Samples

| # | File | What you'll learn |
Expand Down
Loading