Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ FOUNDRY_PROJECT_ENDPOINT="..."
AZURE_AI_MODEL_DEPLOYMENT_NAME="..."
# Comma-separated list of Foundry skill names to download at startup.
SKILL_NAMES="support-style,escalation-policy"
# Optional writable directory for downloaded skills. Defaults to the system temp directory.
# DOWNLOADED_SKILLS_DIR="/tmp/maf_downloaded_skills"
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ Each `SKILL.md` includes a unique `*-CANARY-*` token that the model is asked to

### Downloading skills at agent startup

[`main.py`](main.py) reads the comma-separated `SKILL_NAMES` env var, opens an `AIProjectClient` (also with `allow_preview=True`), and for each skill name streams the ZIP archive from `beta.skills.download(name)` and unpacks it into a **separate runtime directory** at `downloaded_skills/<name>/` (kept distinct from the static `skills/` source folder so the two never get confused — `skills/` is the input to `provision_skills.py`, `downloaded_skills/` is the output of `main.py`'s bootstrap step).
[`main.py`](main.py) reads the comma-separated `SKILL_NAMES` env var, opens an `AIProjectClient` (also with `allow_preview=True`), and for each skill name streams the ZIP archive from `beta.skills.download(name)` and unpacks it into a **separate writable runtime directory**. By default this directory is created under the system temp folder as `maf_downloaded_skills/<name>/`, which works in hosted containers where the application directory may be read-only. Set `DOWNLOADED_SKILLS_DIR` to override the location.

A [`SkillsProvider`](../../../../../packages/core/agent_framework/_skills.py) is then built over `downloaded_skills/` and attached to the `Agent` as a context provider. The provider follows the [Agent Skills](https://agentskills.io/) progressive-disclosure pattern:
A [`SkillsProvider`](../../../../../packages/core/agent_framework/_skills.py) is then built over the downloaded skills directory and attached to the `Agent` as a context provider. The provider follows the [Agent Skills](https://agentskills.io/) progressive-disclosure pattern:

1. **Advertise** — skill names and descriptions are injected into the system prompt at session start (~100 tokens per skill).
2. **Load** — the model calls the `load_skill` tool when it decides a skill is relevant to the user's turn, and the full `SKILL.md` body is returned.
Expand Down Expand Up @@ -100,7 +100,9 @@ Downloading skill 'support-style' from Foundry...
Downloading skill 'escalation-policy' from Foundry...
```

The downloaded `SKILL.md` files land under `downloaded_skills/<name>/SKILL.md` next to `main.py`. This directory is recreated from scratch on every run, so deleting it manually is never necessary.
The downloaded `SKILL.md` files land under `DOWNLOADED_SKILLS_DIR/<name>/SKILL.md`. The directory is recreated from scratch on every run, so deleting it manually is never necessary.

By default, the sample uses the system temp directory, for example `/tmp/maf_downloaded_skills` on Linux. To choose a different writable location, set `DOWNLOADED_SKILLS_DIR` before startup.

## Interacting with the agent

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

At startup, this agent downloads each Foundry Skill named in
``SKILL_NAMES`` from the project's ``beta.skills`` API, unpacks each
one into a separate runtime directory under ``downloaded_skills/``, and wires
one into a separate writable runtime directory and wires
that directory into a :class:`SkillsProvider` so the agent advertises the
skills to the model and loads them on demand (progressive disclosure).

Expand All @@ -17,6 +17,7 @@
import logging
import os
import shutil
import tempfile
import zipfile
from pathlib import Path
from typing import Final
Expand All @@ -34,7 +35,11 @@
# Kept separate from the static ``skills/`` source folder so the two never
# get confused: the source folder is the input to ``provision_skills.py``
# and the runtime folder is the output of this script's bootstrap step.
DOWNLOADED_SKILLS_DIR: Final = Path(__file__).parent / "downloaded_skills"
# Defaults to a system temp location because hosted containers may mount the
# application directory read-only. Set DOWNLOADED_SKILLS_DIR to override it.
_DEFAULT_DOWNLOADED_SKILLS_DIR: Final = Path(tempfile.gettempdir()) / "maf_downloaded_skills"
_DOWNLOADED_SKILLS_DIR_ENV = os.environ.get("DOWNLOADED_SKILLS_DIR")
DOWNLOADED_SKILLS_DIR: Final = Path((_DOWNLOADED_SKILLS_DIR_ENV or "").strip() or _DEFAULT_DOWNLOADED_SKILLS_DIR)

logger = logging.getLogger(__name__)

Expand Down
Loading