mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
d5c07f2623
* feat(foundry): add experimental to_prompt_agent converter Adds `to_prompt_agent(agent)`, an experimental converter (`ExperimentalFeature.TO_PROMPT_AGENT`) that turns an Agent Framework `Agent` into a Foundry `PromptAgentDefinition` ready to publish via `AIProjectClient.agents.create_version(...)`. Behaviour: * `agent.client` must be a `FoundryChatClient` (or subclass); otherwise `TypeError` is raised. The model deployment name is lifted from the bound client so the same Agent definition used for local runs can be published as a hosted prompt agent without restating the model. * Foundry SDK tool instances (from `FoundryChatClient.get_*_tool()`) are passed through unchanged. AF `FunctionTool`s (and `@tool`-decorated callables) are emitted as Foundry `FunctionTool` declarations. * Local AF MCP tools cannot be expressed in a `PromptAgentDefinition`; the converter raises `ValueError` and points at `FoundryChatClient.get_mcp_tool()` for hosted MCP servers. * The converter walks both `agent.default_options["tools"]` and `agent.mcp_tools` because `normalize_tools()` splits local MCP off into its own list. Re-exported through the `agent_framework.foundry` lazy-loading namespace (updates both `__init__.py` and the `__init__.pyi` type stub). Adds a portable-agent sample showing the same `Agent` driven through both `agent.run(...)` and `to_prompt_agent(agent)`, and a README section covering the new converter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): remove snippet tags from portable agent sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): inline FoundryChatClient and enable prompt-agent publish Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): drop async credential context manager Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): trim README to_prompt_agent example to publish-only flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): note FoundryAgent runs @tool callables for deployed prompt agents Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): address review comments on to_prompt_agent converter * Construct `PromptAgentDefinition` `Tool` from a dict via `**tool_item` unpacking rather than the positional Mapping constructor \u2014 cleaner and matches the typical Pydantic / Azure SDK pattern. * Drop the redundant `isinstance(mcp_tool, MCPTool)` guard in `_convert_tools`; the parameter is already typed `Iterable[MCPTool]` so the second `raise` was unreachable. The remaining single `raise` fires for every entry as intended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): match Agent.__init__ model resolution in to_prompt_agent * Read the model from `agent.default_options.get("model")` first, falling back to `agent.client.model`. This mirrors the order `Agent.__init__` uses (`_agents.py:740`) when assembling default_options, so the model the agent runs with is the same model the converter publishes \u2014 e.g. when the caller passes `default_options={"model": "..."}` to override the bound client. * Updated the missing-model error message to point at both the client and the default_options paths. * Added tests: * tool-only agent with no `instructions` produces a definition where `instructions` is `None` and is omitted from the dict payload (`Agent.__init__` strips None values from default_options before storing them). * `default_options['model']` wins over the bound client's model. * Fallback to client.model when default_options has no model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry): add deploy_as_prompt_agent helper + samples Adds `deploy_as_prompt_agent(agent)`, a convenience wrapper around `to_prompt_agent` that reuses the bound FoundryChatClient's project client to call `project_client.agents.create_version(...)`. Defaults `agent_name` / `description` from `agent.name` / `agent.description` so the Agent stays the single source of truth. * Exposed from `agent_framework_foundry` and the lazy-loading `agent_framework.foundry` namespace (including the .pyi stub). * Marked experimental with the existing `ExperimentalFeature.TO_PROMPT_AGENT` tag. * Tests cover the happy path, name/description defaulting, explicit override, no-name error, metadata + description forwarding, extra kwargs passthrough, and the experimental metadata. Samples: * Renamed the existing sample to `creating_prompt_agents.py`, drops 'portable' wording, presents `deploy_as_prompt_agent` first as the recommended path and `to_prompt_agent` + `AIProjectClient` as the two-step alternative, and adds a cleanup step that deletes the published agent so re-runs stay idempotent. * New `using_prompt_agents.py` shows the end-to-end loop: deploy the agent, connect to it with `FoundryAgent` passing the same local `@tool` callable, run a query against the deployed prompt agent, then clean up. README updated to introduce `deploy_as_prompt_agent` as the recommended path and link to both runnable samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): restore missing-model ValueError in to_prompt_agent The check was accidentally dropped while reworking docstrings in the previous commit. Test `test_to_prompt_agent_rejects_missing_model` exercises this path and was failing on CI as a result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): rename deploy_as_prompt_agent -> create_prompt_agent Renames the helper across the foundry package, core lazy-loader stubs, tests, README and samples. The new name better matches the action performed (a prompt-agent definition is created in Foundry) and is consistent with the surrounding ''create_*'' API surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): drop create_prompt_agent, enrich to_prompt_agent params Remove the create_prompt_agent helper and consolidate on to_prompt_agent. Expose every PromptAgentDefinition parameter that has either an Agent Framework equivalent (sourced from default_options) or no equivalent (accepted as a keyword argument). * default_options-sourced (with kwarg overrides): temperature, top_p, string tool_choice * kwarg-only Foundry knobs: reasoning, text, structured_inputs, rai_config, ToolChoiceParam tool_choice Precedence is always: explicit keyword > default_options entry > unset. Tests cover every path (defaults, default_options, kwargs, kwarg override). Samples and README rewritten around the enriched to_prompt_agent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): single source of truth for prompt-agent options Stop duplicating the generation-parameter surface between FoundryChatOptions and to_prompt_agent. Translate every field with an Agent Framework equivalent (temperature, top_p, tool_choice, reasoning, response_format/text/verbosity) from agent.default_options via a new RawFoundryChatClient helper _prepare_prompt_agent_options. Only Foundry-specific fields with no AF equivalent — structured_inputs and rai_config — remain as keyword arguments on to_prompt_agent. - tool_choice is dropped when there are no tools (mirrors _prepare_options semantics and avoids polluting tool-less prompt agents with Agent.__init__'s 'auto' default). - response_format Pydantic models route through openai.lib._parsing._responses.type_to_text_format_param; dict shapes go through the existing _prepare_response_and_text_format helper. - default_options is not mutated; text dict is defensively copied. Tests, README, and creating_prompt_agents.py sample updated to reflect the new single-source model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): consolidate prompt-agent sample Drop creating_prompt_agents.py (the publish-only variant) and rename using_prompt_agents.py to foundry_prompt_agents.py so the single sample covers the full convert -> publish -> connect -> run loop. Update the README link list accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): run local Agent + deployed agent in same sample Add an agent.run() call against the local Agent before publishing, then run the deployed prompt agent on the same query. Expand the docstring with a compare-and-contrast covering runtime/latency, configurability, and persistence/sharing differences between the two execution paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(foundry): cover conflicting response_format + text.format in to_prompt_agent Exercises the ValueError path when a Pydantic response_format would overwrite an explicit text.format mapping with a different shape. Lifts _chat_client.py coverage from 89% to 90%. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): move _prepare_prompt_agent_options into _to_prompt_agent Lift the translation helper off RawFoundryChatClient and into the _to_prompt_agent module as a module-private function that takes the client as its first argument. The chat client no longer needs to carry a method whose only consumer is the prompt-agent converter, while still serving as the source of the request-path helper (_prepare_response_and_text_format) that the converter reuses for dict-shaped response_format values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(python): codify GA terminology + post-run docs review Add two pieces of guidance to python/AGENTS.md: * Terminology - reserve 'GA' for hosted services; use 'released' or 'stable' for Agent Framework code/features to match the feature-lifecycle stages. * Maintaining Documentation - review AGENTS.md and skills at the end of every run and update any guidance the conversation made stale; before adding a new principle, ask the user to confirm it should be captured. Also pulls in a docstring fix in foundry_prompt_agents.py that swaps the stray 'GA' for 'released', applying the new terminology rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review: strict=True default, Tool._deserialize dispatch, sample cleanup safety - FunctionTool published as strict=True so the server-side schema validation matches what the local FoundryAgent(tools=[same_callable]) dispatcher enforces. AF FunctionTool has no 'strict' attribute, so the safer default is used uniformly instead of silently downgrading to a permissive contract. - _validate_mapping_tool now dispatches through ProjectsTool._deserialize so dict-shaped tools rehydrate to the concrete subclass (FunctionTool, WebSearchTool, ...) via the 'type' discriminator instead of returning a generic Tool. Added a test that asserts isinstance(WebSearchTool) and a new test for the function-typed dict path. - foundry_prompt_agents.py sample now wraps credential + project client in async with and the create_version / run flow in try/finally so a failure on connect or run still deletes the published prompt agent rather than leaving an orphaned, billable resource in the user's Foundry project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): correct linkspector ignorePattern typo (./pulls -> ./pull) GitHub PR URLs use the singular segment /pull/N (compare to /issues/N for issues). The existing './pulls' ignore pattern never matched anything as a result, so legitimately stale PR links (e.g. PRs deleted from forks) surface as linkspector failures on unrelated PRs. This is the same convention the './issues' rule above already follows. Fixes the markdown-link-check failure on a dangling link in dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
112 lines
5.5 KiB
Markdown
112 lines
5.5 KiB
Markdown
# AGENTS.md
|
|
|
|
Instructions for AI coding agents working in the Python codebase.
|
|
|
|
**Key Documentation:**
|
|
- [DEV_SETUP.md](DEV_SETUP.md) - Development environment setup and available poe tasks
|
|
- [CODING_STANDARD.md](CODING_STANDARD.md) - Coding standards, docstring format, and performance guidelines
|
|
- [samples/SAMPLE_GUIDELINES.md](samples/SAMPLE_GUIDELINES.md) - Sample structure and guidelines
|
|
|
|
**Agent Skills** (`.github/skills/`) — detailed, task-specific instructions loaded on demand:
|
|
- `python-development` — coding standards, type annotations, docstrings, logging, performance
|
|
- `python-testing` — test structure, fixtures, async mode, running tests
|
|
- `python-code-quality` — linting, formatting, type checking, prek hooks, CI workflow
|
|
- `python-feature-lifecycle` — package vs feature lifecycle stages, decorators, enums, and promotion guidance
|
|
- `python-package-management` — monorepo structure, lazy loading, versioning, new packages
|
|
- `python-samples` — sample file structure, PEP 723, documentation guidelines
|
|
|
|
## Maintaining Documentation
|
|
|
|
When making changes to a package, check if the following need updates:
|
|
- The package's `AGENTS.md` file (adding/removing/renaming public APIs, architecture changes, import path changes)
|
|
- The agent skills in `.github/skills/` if conventions, commands, or workflows change
|
|
|
|
At the end of every run, re-read `AGENTS.md` and the relevant skill files and
|
|
update any guidance that the conversation revealed to be out of date,
|
|
incomplete, or misleading (renamed files, changed commands, new conventions
|
|
the user confirmed, etc.). **Before adding a new principle or rule, ask the
|
|
user whether they want it captured as a durable principle** — do not invent
|
|
team norms from a single conversation without explicit confirmation.
|
|
|
|
## Terminology
|
|
|
|
- **Avoid "GA" for Agent Framework code.** Reserve *GA* for hosted services
|
|
(e.g. "the Foundry service is GA"). For Agent Framework packages, features,
|
|
and APIs use **"released"** or **"stable"** depending on context — these
|
|
match the feature-lifecycle stages documented in the
|
|
`python-feature-lifecycle` skill.
|
|
|
|
## Pull Request Description Guidance
|
|
|
|
When preparing a PR description:
|
|
- Follow the repository PR template at `.github/pull_request_template.md` and keep its structure/headings.
|
|
- Describe the net change relative to `main` (this is implied; do not call it out explicitly as "vs main").
|
|
- Do not add ad-hoc validation sections (for example, "Validation" or "Tests run"); CI/CD and the template checklist cover validation status.
|
|
|
|
## Quick Reference
|
|
|
|
Run `uv run poe` from the `python/` directory to see available commands. See [DEV_SETUP.md](DEV_SETUP.md) for detailed usage.
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
python/
|
|
├── packages/
|
|
│ ├── core/ # agent-framework-core (main package)
|
|
│ │ ├── agent_framework/ # Public API exports
|
|
│ │ └── tests/
|
|
│ ├── foundry/ # agent-framework-foundry
|
|
│ ├── anthropic/ # agent-framework-anthropic
|
|
│ ├── ollama/ # agent-framework-ollama
|
|
│ └── ... # Other provider packages
|
|
├── samples/ # Sample code and examples
|
|
├── .github/skills/ # Agent skills for Copilot
|
|
└── tests/ # Integration tests
|
|
```
|
|
|
|
### Package Relationships
|
|
|
|
- `agent-framework-core` contains core abstractions and OpenAI/Azure OpenAI built-in
|
|
- Provider packages (`foundry`, `anthropic`, etc.) extend core with specific integrations
|
|
- Core uses lazy loading via `__getattr__` in provider folders (e.g., `agent_framework/azure/`)
|
|
|
|
## Package Documentation
|
|
|
|
### Core
|
|
- [core](packages/core/AGENTS.md) - Core abstractions, types, and built-in OpenAI/Azure OpenAI support
|
|
|
|
### LLM Providers
|
|
- [anthropic](packages/anthropic/AGENTS.md) - Anthropic Claude API
|
|
- [bedrock](packages/bedrock/AGENTS.md) - AWS Bedrock
|
|
- [claude](packages/claude/AGENTS.md) - Claude Agent SDK
|
|
- [foundry_local](packages/foundry_local/AGENTS.md) - Azure AI Foundry Local
|
|
- [ollama](packages/ollama/AGENTS.md) - Local Ollama inference
|
|
|
|
### Azure Integrations
|
|
- [foundry](packages/foundry/README.md) - Microsoft Foundry chat, agent, memory, and embedding integrations
|
|
- [azure-contentunderstanding](packages/azure-contentunderstanding/AGENTS.md) - Azure Content Understanding context provider
|
|
- [azure-ai-search](packages/azure-ai-search/AGENTS.md) - Azure AI Search RAG
|
|
- [azure-cosmos](packages/azure-cosmos/AGENTS.md) - Azure Cosmos DB-backed history provider
|
|
- [azurefunctions](packages/azurefunctions/AGENTS.md) - Azure Functions hosting
|
|
|
|
### Protocols & UI
|
|
- [a2a](packages/a2a/AGENTS.md) - Agent-to-Agent protocol
|
|
- [ag-ui](packages/ag-ui/AGENTS.md) - AG-UI protocol
|
|
- [chatkit](packages/chatkit/AGENTS.md) - OpenAI ChatKit integration
|
|
- [devui](packages/devui/AGENTS.md) - Developer UI for testing
|
|
|
|
### Storage & Memory
|
|
- [mem0](packages/mem0/AGENTS.md) - Mem0 memory integration
|
|
- [redis](packages/redis/AGENTS.md) - Redis storage
|
|
|
|
### Infrastructure
|
|
- [copilotstudio](packages/copilotstudio/AGENTS.md) - Microsoft Copilot Studio
|
|
- [declarative](packages/declarative/AGENTS.md) - YAML/JSON agent definitions
|
|
- [durabletask](packages/durabletask/AGENTS.md) - Durable execution
|
|
- [github_copilot](packages/github_copilot/AGENTS.md) - GitHub Copilot extensions
|
|
- [purview](packages/purview/AGENTS.md) - Data governance
|
|
|
|
### Experimental
|
|
- [lab](packages/lab/AGENTS.md) - Experimental features
|
|
- [monty](packages/monty/AGENTS.md) - Monty-backed CodeAct integrations (alpha)
|