Skip to content

Comments

Python: Restructure Python samples: progressive learning path (01→05)#3764

Closed
eavanvalkenburg wants to merge 7 commits intomicrosoft:mainfrom
eavanvalkenburg:restructure/python-samples
Closed

Python: Restructure Python samples: progressive learning path (01→05)#3764
eavanvalkenburg wants to merge 7 commits intomicrosoft:mainfrom
eavanvalkenburg:restructure/python-samples

Conversation

@eavanvalkenburg
Copy link
Member

Summary

Restructures the Python samples into a clear progressive learning path with 5 sections:

  • 01-get-started/ — 6 numbered steps (hello agent → hosting), each adding one concept
  • 02-agents/ — Deep-dive concept samples: tools/, middleware/, conversations/, providers/
  • 03-workflows/ — One folder per workflow pattern (sequential, concurrent, branching, HITL, etc.)
  • 04-hosting/ — Multi-file projects: a2a, azure-functions, durable-tasks
  • 05-end-to-end/ — Complete apps: hosted-agents, m365-agent, workflow-evaluation, evaluation

Key design decisions

  • One concept per file — each .py demonstrates a single topic
  • Snippet tags — all samples include # <name> / # </name> tags for docs :::code references
  • Explicit env varsapi_key=os.environ.get("OPENAI_API_KEY") instead of implicit detection
  • Default provider — OpenAI Responses via OpenAIResponsesClient
  • Single-file for 01-03 — only 04/05 use multi-file projects
  • AGENTS.md — documents structure, conventions, and file→docs mapping for future maintainers

What changed

  • ~70 new sample files created across 5 sections
  • ~486 old files moved to _to_delete/ for reviewer inspection (not deleted)
  • autogen-migration/ and semantic-kernel-migration/ preserved at root
  • Updated SAMPLE_GUIDELINES.md TODOs addressed by new structure

Related PRs

  • .NET samples: (separate PR on restructure/dotnet-samples)
  • Docs: (draft PR on semantic-kernel-pr repo)

@eavanvalkenburg eavanvalkenburg requested a review from a team as a code owner February 9, 2026 16:04
Copilot AI review requested due to automatic review settings February 9, 2026 16:04
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation python labels Feb 9, 2026
@github-actions github-actions bot changed the title Restructure Python samples: progressive learning path (01→05) Python: Restructure Python samples: progressive learning path (01→05) Feb 9, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restructures the Python samples into a 5-part progressive learning path and adds/updates sample content + maintainers’ guidance to support docs integration and long-term upkeep.

Changes:

  • Introduces new 01-get-started05-end-to-end sample layout with section READMEs.
  • Adds concept-focused samples for agents, tools, middleware, conversations, and workflows.
  • Moves legacy samples into python/samples/_to_delete/ for review (not deleted) and adds python/samples/AGENTS.md conventions/mapping.

Reviewed changes

Copilot reviewed 76 out of 607 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
python/samples/_to_delete/getting_started/agents/a2a/README.md Added legacy A2A sample README retained under _to_delete/.
python/samples/_to_delete/demos/workflow_evaluation/run_evaluation.py Added legacy workflow evaluation runner retained under _to_delete/.
python/samples/_to_delete/demos/workflow_evaluation/create_workflow.py Added legacy multi-agent workflow creation + tracking code retained under _to_delete/.
python/samples/_to_delete/demos/workflow_evaluation/README.md Added legacy workflow evaluation documentation retained under _to_delete/.
python/samples/_to_delete/demos/workflow_evaluation/.env.example Added example env file for legacy workflow evaluation demo.
python/samples/_to_delete/demos/m365-agent/m365_agent_demo/app.py Added legacy M365 agent demo app retained under _to_delete/.
python/samples/_to_delete/demos/m365-agent/README.md Added legacy M365 demo documentation retained under _to_delete/.
python/samples/_to_delete/demos/m365-agent/.env.example Added example env file for legacy M365 demo.
python/samples/_to_delete/demos/hosted_agents/agents_in_workflow/requirements.txt Added legacy hosted agent requirements retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agents_in_workflow/main.py Added legacy hosted agent workflow demo retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agents_in_workflow/agent.yaml Added legacy hosted agent manifest retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agents_in_workflow/Dockerfile Added legacy hosted agent Dockerfile retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_text_search_rag/requirements.txt Added legacy hosted agent requirements retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_text_search_rag/main.py Added legacy text-search RAG hosted agent demo retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_text_search_rag/agent.yaml Added legacy hosted agent manifest retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_text_search_rag/Dockerfile Added legacy hosted agent Dockerfile retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_hosted_mcp/requirements.txt Added legacy hosted agent requirements retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_hosted_mcp/main.py Added legacy hosted MCP agent demo retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_hosted_mcp/agent.yaml Added legacy hosted agent manifest retained under _to_delete/.
python/samples/_to_delete/demos/hosted_agents/agent_with_hosted_mcp/Dockerfile Added legacy hosted agent Dockerfile retained under _to_delete/.
python/samples/AGENTS.md New maintainer guide documenting sample structure, conventions, and docs mapping.
python/samples/05-end-to-end/README.md New section README for end-to-end samples.
python/samples/04-hosting/a2a/agent_with_a2a.py New A2A protocol hosting sample with snippet tags.
python/samples/04-hosting/README.md New section README for hosting/protocol samples.
python/samples/03-workflows/visualization/visualization.py New workflow visualization pattern sample.
python/samples/03-workflows/state-management/state_management.py New workflow state management pattern sample.
python/samples/03-workflows/sequential/sequential.py New sequential workflow pattern sample.
python/samples/03-workflows/human-in-the-loop/human_in_the_loop.py New human-in-the-loop workflow pattern sample.
python/samples/03-workflows/declarative/declarative.py New declarative workflow (YAML) sample.
python/samples/03-workflows/concurrent/concurrent.py New concurrent (fan-out/fan-in) workflow pattern sample.
python/samples/03-workflows/checkpoints/checkpoints.py New checkpoint/resume workflow sample.
python/samples/03-workflows/branching/branching.py New branching/conditional routing workflow sample.
python/samples/03-workflows/agents-in-workflows/agents_in_workflows.py New sample using agents directly as workflow steps.
python/samples/03-workflows/README.md New section README indexing workflow patterns.
python/samples/02-agents/typed_options.py New typed options deep-dive sample.
python/samples/02-agents/tools/web_search.py New web search tool sample.
python/samples/02-agents/tools/tool_approval.py New tool approval (HITL) sample.
python/samples/02-agents/tools/local_mcp_tools.py New local MCP tool sample (streamable HTTP transport).
python/samples/02-agents/tools/hosted_mcp_tools.py New hosted MCP tool sample (provider-managed).
python/samples/02-agents/tools/function_tools.py New advanced function tools sample (kwargs injection).
python/samples/02-agents/tools/file_search.py New hosted file search tool sample (vector stores).
python/samples/02-agents/tools/code_interpreter.py New hosted code interpreter tool sample.
python/samples/02-agents/structured_output.py New structured output sample using Pydantic.
python/samples/02-agents/response_stream.py New deep-dive sample explaining ResponseStream.
python/samples/02-agents/rag.py New RAG sample using a ContextProvider.
python/samples/02-agents/providers/openai_provider.py New OpenAI provider “hello world” sample.
python/samples/02-agents/providers/ollama_provider.py New Ollama provider “hello world” sample.
python/samples/02-agents/providers/github_copilot.py New GitHub Copilot provider “hello world” sample.
python/samples/02-agents/providers/custom_provider.py New custom provider (BaseAgent) “hello world” sample.
python/samples/02-agents/providers/copilot_studio.py New Copilot Studio provider “hello world” sample.
python/samples/02-agents/providers/azure_openai.py New Azure OpenAI provider “hello world” sample.
python/samples/02-agents/providers/azure_ai_foundry.py New Azure AI Foundry provider “hello world” sample.
python/samples/02-agents/providers/anthropic_provider.py New Anthropic provider “hello world” sample.
python/samples/02-agents/observability.py New OpenTelemetry observability/tracing sample.
python/samples/02-agents/middleware/thread_tracking.py New middleware sample demonstrating thread behavior visibility.
python/samples/02-agents/middleware/termination.py New middleware termination sample.
python/samples/02-agents/middleware/shared_state.py New middleware sample demonstrating shared state patterns.
python/samples/02-agents/middleware/runtime_context.py New middleware sample demonstrating runtime context delegation patterns.
python/samples/02-agents/middleware/override_result.py New middleware sample overriding results (streaming + non-streaming).
python/samples/02-agents/middleware/exception_handling.py New middleware sample for centralized exception handling.
python/samples/02-agents/middleware/defining_middleware.py New middleware sample showing class/function/decorator forms.
python/samples/02-agents/middleware/chat_middleware.py New chat middleware sample (observe/modify/override).
python/samples/02-agents/middleware/agent_vs_run_middleware.py New sample contrasting agent-level vs run-level middleware.
python/samples/02-agents/declarative_agents.py New sample for declarative agent creation from YAML.
python/samples/02-agents/conversations/suspend_resume.py New sample for suspend/resume via thread serialize/deserialize.
python/samples/02-agents/conversations/redis_storage.py New sample for Redis-backed conversation persistence.
python/samples/02-agents/conversations/persistent_conversation.py New sample implementing a custom message store.
python/samples/02-agents/README.md New section README indexing advanced single-agent samples.
python/samples/01-get-started/README.md New section README for progressive “get started” steps.
python/samples/01-get-started/06_host_your_agent.py New step 6 sample: connect/invoke via A2A protocol.
python/samples/01-get-started/05_first_workflow.py New step 5 sample: build a simple sequential workflow.
python/samples/01-get-started/04_memory.py New step 4 sample: context provider “memory” injection.
python/samples/01-get-started/03_multi_turn.py New step 3 sample: multi-turn using AgentThread.
python/samples/01-get-started/02_add_tools.py New step 2 sample: define and use tools.
python/samples/01-get-started/01_hello_agent.py New step 1 sample: minimal agent run + streaming.

Comment on lines +354 to +365
async for event in events:
if event.type == "output":
workflow_output = event.data
# Handle Unicode characters that may not be displayable in Windows console
try:
print(f"\nWorkflow Output: {event.data}\n")
except UnicodeEncodeError:
output_str = str(event.data).encode("ascii", "replace").decode("ascii")
print(f"\nWorkflow Output: {output_str}\n")

elif event.type == "output" and isinstance(event.data, AgentResponseUpdate):
_track_agent_ids(event, event.executor_id, response_ids, conversation_ids)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The elif event.type == \"output\" and isinstance(event.data, AgentResponseUpdate) branch is unreachable because the preceding if event.type == \"output\" matches first. As written, _track_agent_ids(...) will never run, so response/conversation IDs won’t be tracked. Reorder the checks (handle AgentResponseUpdate first) or use the correct event type for updates vs final outputs so both tracking and workflow output capture work.

Copilot uses AI. Check for mistakes.

def condition(message: Any) -> bool:
if not isinstance(message, DetectionResult):
return True
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-DetectionResult messages, this condition currently returns True, which can cause unintended edge traversal (including multiple conditional edges evaluating to true for unexpected message types). Return False when the message type doesn’t match so routing only occurs when DetectionResult is present.

Suggested change
return True
return False

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +56
"Request Timeout: The data service is taking longer than expected to respond.",
"Respond with message - 'Sorry for the inconvenience, please try again later.'",
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In function middleware, context.result should be set to the tool’s expected return type (here the tool returns str). Assigning a tuple of strings risks serialization/type errors downstream. Set context.result to a single string message (or whatever return type the tool contract requires).

Suggested change
"Request Timeout: The data service is taking longer than expected to respond.",
"Respond with message - 'Sorry for the inconvenience, please try again later.'",
"Request Timeout: The data service is taking longer than expected to respond. "
"Sorry for the inconvenience, please try again later."

Copilot uses AI. Check for mistakes.
agent = client.as_agent(
name="PersonalAssistant",
instructions="You are a helpful personal assistant. Be concise.",
context_providers=preferences,
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses context_providers=preferences, but other samples consistently use context_provider=... for a single provider (e.g., rag.py). If the API expects context_provider (singular), this will raise a TypeError at runtime. Use the correct keyword for a single provider (or pass a list if the API truly supports multiple providers).

Suggested change
context_providers=preferences,
context_provider=preferences,

Copilot uses AI. Check for mistakes.
Comment on lines +102 to +108
last_guess = original_request.prompt.split(": ")[1].split(".")[0]
feedback_text = (
f"Feedback: {reply}. Your last guess was {last_guess}. "
f"Use this feedback to adjust and make your next guess (1-10)."
)
user_msg = ChatMessage("user", text=feedback_text)
await ctx.send_message(AgentExecutorRequest(messages=[user_msg], should_respond=True))
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting last_guess by parsing the human prompt text is brittle (any prompt wording change breaks the split logic). Consider carrying last_guess as a dedicated field on HumanFeedbackRequest (e.g., last_guess: int) so the response handler can reuse it without string parsing.

Copilot uses AI. Check for mistakes.
Step 1: Your First Agent

The simplest possible agent — send a message, get a response.
Uses Azure OpenAI Responses as the default provider.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring says the sample uses 'Azure OpenAI Responses' by default, but the code constructs OpenAIResponsesClient(...), which is the OpenAI provider client. Update the wording to match the actual default provider used in this sample (and optionally clarify how to switch to Azure OpenAI).

Suggested change
Uses Azure OpenAI Responses as the default provider.
Uses OpenAI Responses as the default provider (see below for Azure OpenAI options).

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
agent = ChatAgent(
chat_client=OpenAIResponsesClient(),
instructions="You are a helpful assistant that can search the web for current information.",
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python/samples/AGENTS.md states that canonical samples should use explicit env var wiring (pass api_key= / model_id=) rather than implicit detection. Here OpenAIResponsesClient() is constructed with no explicit parameters. To keep samples consistent with the stated convention, pass api_key=os.environ.get(\"OPENAI_API_KEY\") and model_id=os.environ.get(\"OPENAI_RESPONSES_MODEL_ID\", ...) (and import os).

Copilot uses AI. Check for mistakes.
without exposing them to the model.

For more on tools:
- Basic tools: ../01-get-started/02_add_tools.py
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relative path is incorrect from python/samples/02-agents/tools/ (it would resolve under 02-agents/01-get-started/...). Update it to the correct relative path (e.g. ../../01-get-started/02_add_tools.py) to avoid broken references.

Suggested change
- Basic tools: ../01-get-started/02_add_tools.py
- Basic tools: ../../01-get-started/02_add_tools.py

Copilot uses AI. Check for mistakes.

Environment variables:
- OPENAI_API_KEY: Your OpenAI API key
- OPENAI_RESPONSES_MODEL_ID: Model to use (default: gpt-4.1-mini)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This claims the default model is gpt-4.1-mini, but python/samples/AGENTS.md shows a default of gpt-4o. Align the documented default model across samples/docs (or explicitly state what OpenAIResponsesClient defaults to) to reduce confusion.

Suggested change
- OPENAI_RESPONSES_MODEL_ID: Model to use (default: gpt-4.1-mini)
- OPENAI_RESPONSES_MODEL_ID: Model to use (default: gpt-4o)

Copilot uses AI. Check for mistakes.
…o _to_delete

New structure:
- 01-get-started/ (6 progressive samples)
- 02-agents/ (tools, middleware, conversations, providers)
- 03-workflows/ (9 workflow patterns)
- 04-hosting/ (a2a, azure-functions, durable-tasks)
- 05-end-to-end/ (full apps, evaluation)
- _to_delete/ (old samples for reviewer reference)

Old files preserved in _to_delete/ for review before deletion.
autogen-migration/ and semantic-kernel-migration/ kept as-is.
- 01_hello_agent.py: explicit api_key and model_id from os.environ
- 02_add_tools.py: same pattern
- 03_multi_turn.py: same pattern
- Added env var documentation in docstrings
- Rename next → call_next in all 9 middleware samples (upstream breaking change)
- Add function_tool_explicit_schema.py to 02-agents/tools/ (new upstream sample)
- Add agents_with_declaration_only_tools.py to 03-workflows/human-in-the-loop/ (new upstream sample)
@eavanvalkenburg eavanvalkenburg force-pushed the restructure/python-samples branch from 7e02f41 to 525f2fe Compare February 10, 2026 08:08
…tools.py

- Added Pattern 2: explicit schema via Pydantic model and JSON dict
- Added Pattern 3: declaration-only tool (func=None) with FunctionTool
- Removed standalone function_tool_explicit_schema.py (merged in)
- Declaration-only full workflow demo stays in 03-workflows/human-in-the-loop/
Copy link
Collaborator

@TaoChenOSU TaoChenOSU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of workflow samples are moved to _to_delete. Why is that?

@moonbox3
Copy link
Contributor

We're going to work on workflows samples this week. I'd prefer if the current samples are left alone so we can figure out how we'd like to proceed.

@eavanvalkenburg
Copy link
Member Author

Closing to redo with updated structure — workflows will be handled separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants