Python: Fix PropertySchema.to_json_schema() not recursing into nested array items / object properties#7200
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request addresses a Python bug in PropertySchema.to_json_schema() where nested schemas (array items, nested object properties) were not normalized (kind→type, empty enum removal), producing JSON Schema that structured-output providers reject. The change set also introduces a sizeable set of new “research” docs and a new .NET learning/sandbox project (dotnet/learn/AgentLearn), plus repo-level editor/gitignore tweaks.
Changes:
- Python: add recursive schema normalization for nested
items/properties, and add regression tests. - Add
dotnet/learn/AgentLearnsample app + integration tests for learning framework workflows/HITL/OTel. - Add
research/documentation and VS Code / gitignore convenience updates.
Reviewed changes
Copilot reviewed 40 out of 41 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| research/README.md | Adds a top-level README describing the research/ folder. |
| research/python/agentic-capabilities.md | Adds Python agentic capabilities research document. |
| research/dotnet/agentic-capabilities.md | Adds .NET agentic capabilities research document. |
| research/agentic-capabilities-overview.md | Adds cross-language agentic capabilities overview research document. |
| python/packages/declarative/tests/test_declarative_models.py | Adds regression tests for nested schema normalization. |
| python/packages/declarative/agent_framework_declarative/_models.py | Implements recursive nested schema normalization in to_json_schema(). |
| dotnet/samples/run.bash | Adds helper script to run a .NET sample with .env variables loaded. |
| dotnet/learn/README.md | Adds documentation for the new AgentLearn project. |
| dotnet/learn/Directory.Packages.props | Disables central package management within dotnet/learn. |
| dotnet/learn/Directory.Build.targets | Isolates learn projects from parent build targets. |
| dotnet/learn/Directory.Build.props | Isolates learn projects from parent build props. |
| dotnet/learn/CLAUDE.md | Adds project guidance/conventions for dotnet/learn. |
| dotnet/learn/AgentLearn/tests/integration/StoryGeneratorWorkflowTests.cs | Adds HITL workflow integration tests. |
| dotnet/learn/AgentLearn/tests/integration/MockChatClientHelper.cs | Adds shared mock IChatClient helper for integration tests. |
| dotnet/learn/AgentLearn/tests/integration/JokeWriterWorkflowTests.cs | Adds workflow integration tests for single/sequential/concurrent joke flows. |
| dotnet/learn/AgentLearn/tests/integration/AgentLearn.IntegrationTests.csproj | Adds integration test project definition. |
| dotnet/learn/AgentLearn/TaskKinds/StoryGenerator/StoryGenerator.http | Adds REST client requests for StoryGenerator. |
| dotnet/learn/AgentLearn/TaskKinds/StoryGenerator/StoryGenerator.cs | Adds StoryGenerator task kind (models/executors/agent/workflow/handler/DI). |
| dotnet/learn/AgentLearn/TaskKinds/JokeWriter/JokeWriter.http | Adds REST client requests for JokeWriter. |
| dotnet/learn/AgentLearn/TaskKinds/JokeWriter/JokeWriter.cs | Adds JokeWriter task kind (models/executors/agents/workflows/handler/DI). |
| dotnet/learn/AgentLearn/Services/ITaskHandler.cs | Adds task-handler abstraction for dispatching requests by kind. |
| dotnet/learn/AgentLearn/Services/ChatClientFactory.cs | Adds multi-provider IChatClient factory + mock client. |
| dotnet/learn/AgentLearn/run.sh | Adds dev runner that starts Jaeger and runs AgentLearn. |
| dotnet/learn/AgentLearn/Properties/launchSettings.json | Adds local launch profiles for AgentLearn. |
| dotnet/learn/AgentLearn/Program.cs | Wires DI, OpenTelemetry, DevUI, OpenAI-compatible endpoints, and controllers. |
| dotnet/learn/AgentLearn/Models/TaskResponse.cs | Adds /task response DTO. |
| dotnet/learn/AgentLearn/Models/TaskRequest.cs | Adds /task request DTO. |
| dotnet/learn/AgentLearn/Models/TaskKind.cs | Adds task-kind enum for dispatch. |
| dotnet/learn/AgentLearn/Models/LlmOptions.cs | Adds configuration model for LLM provider selection. |
| dotnet/learn/AgentLearn/Models/AgentMode.cs | Adds workflow mode enum. |
| dotnet/learn/AgentLearn/Extensions/AIAgentBuilderExtensions.cs | Adds tool-invocation logging middleware extension. |
| dotnet/learn/AgentLearn/Controllers/TaskController.cs | Adds /task controller that routes to ITaskHandlers. |
| dotnet/learn/AgentLearn/CLAUDE.md | Adds AgentLearn-specific contributor guidance. |
| dotnet/learn/AgentLearn/appsettings.json | Adds default configuration for AgentLearn. |
| dotnet/learn/AgentLearn/appsettings.Development.json | Adds dev configuration (incl. debug logging). |
| dotnet/learn/AgentLearn/AgentLearn.csproj | Adds AgentLearn project definition and package references. |
| dotnet/learn/AgentLearn.sln | Adds solution file for AgentLearn. |
| dotnet/learn/.gitignore | Adds ignore rules for local .env variants. |
| CLAUDE.md | Adds/updates repo-level contributor guidance for Claude. |
| .vscode/settings.json | Sets VS Code dotnet.defaultSolution. |
| .gitignore | Ignores .workspaces/ directory. |
… schemas
Nested array 'items' and object 'properties' kept the declarative 'kind'
key and empty 'enum' placeholders, producing JSON Schema OpenAI rejects
('schema must have a type key'). Recursively apply the same conversion the
top-level properties loop performs, including the serialized named-list
properties shape and nested required arrays.
Fixes microsoft#7198
(cherry picked from commit c156ffd)
c156ffd to
53784b0
Compare
…ial conversion Review feedback: the list-shaped properties branch popped name/required from each element and returned on the first unexpected one, leaving earlier elements half-converted. Validate the whole list first so an unexpected shape leaves the node fully untouched.
|
Note for reviewers: the other review threads (research/, dotnet/learn/, .vscode/settings.json) referenced unrelated files that were accidentally included from a stale fork base — the branch has been rebuilt as a single commit on top of main and those files are no longer part of this PR (now 2 files: |
|
@microsoft-github-policy-service agree |
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||
| node["properties"] = new_props | ||
| if required_fields: | ||
| node["required"] = required_fields | ||
| elif isinstance(props, dict): |
There was a problem hiding this comment.
This branch looks unreachable via to_json_schema : ObjectProperty.properties is always stored/serialized as a named list, so nested properties is a list here, never a dict.
|
@exp-ouroborous thank you for authoring this fix. Can you please take a look at the comment and the Pyright type-check error failures. |
Motivation and Context
PropertySchema.to_json_schema()renameskind→type(and drops emptyenumplaceholders) only in its top-level properties loop. Nested schemas — arrayitems, nested objectproperties(which serialize in the named-list shape) — keepkindand emptyenum, producing JSON Schema that OpenAI rejects ("schema must have a 'type' key"). Reproduced on 1.0.0rc2.Description
_normalize_nested_schemas/_normalize_schema_node: recursively applies the same conversion the top-level loop performs —kind→type, empty-enumremoval, named-listproperties→ dict with arequiredarray — at every depth."items": {"type": "string"}instead of"items": {"kind": "string", "enum": []}.Contribution Checklist
test_declarative_models.py: 98 passed)