Decouple AgentServer responses from generated model internals#47995
Decouple AgentServer responses from generated model internals#47995Shivakishore14 wants to merge 19 commits into
Conversation
Move response contracts to local TypedDict wire payloads and remove runtime reliance on generated model constructors, serialization helpers, and nested generated SDK model paths. Keep validation behind a stable local wrapper and update tests to exercise dict-native payloads instead of generated model runtime callability. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the source-built TypeSpec Python emitter TypedDict output as the model source instead of the localized bridge artifact. Normalize the emitted package into the local AgentServer generated boundary and remove fake model_base/_models compatibility shims. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pin AgentServer TypeSpec generation to the source PR that removes stale OpenAI usage decorators and enables Python TypeDict generation. Replace the old finalization script with a minimal contract extractor, regenerate API docs and model contracts, and remove unused _types.py output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Regenerate AgentServer response TypedDict contracts, validators, and API docs from the current AgentServer service contract path. Point tsp-location.yaml at the fresh spec PR commit and compile from the clean synced Foundry/src root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Inline the single-use wire field mutation helper and remove a thin Foundry serializer wrapper that only delegated to to_wire_dict. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Generate the TypedDict enum fallback at the root _generated package so validators use the same _enums import shape as latest main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Point AgentServer Responses generation metadata at the latest spec PR commit after CI-only validation fixes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Address runtime dict-native response compatibility, static analysis, spelling, and Sphinx documentation failures for the AgentServer Responses package. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Update samples to use TypedDict-safe access and required discriminator fields so package Pyright validation passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
|
Azure Pipelines: Successfully started running 1 pipeline(s). 9 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Migrates AgentServer response contracts from generated runtime model classes to local TypedDict-backed wire dictionaries.
Changes:
- Regenerates contracts and validators from the dependent TypeSpec specification.
- Updates runtime, storage, streaming, samples, and tests for dictionary-native payloads.
- Adds extraction tooling and removes obsolete generated-model shims.
Reviewed changes
Copilot reviewed 95 out of 101 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
type_spec/tsp-location.yaml |
Updates TypeSpec source and commit. |
tests/unit/test_validation.py |
Tests dictionary-native validation errors. |
tests/unit/test_string_content_expansion.py |
Updates content expansion tests. |
tests/unit/test_sse_writer.py |
Uses dictionary SSE events. |
tests/unit/test_session_and_response_id_resolution.py |
Simplifies parsed request fixture. |
tests/unit/test_runtime_state.py |
Uses TypedDict response snapshots. |
tests/unit/test_response_execution.py |
Updates response execution fixture. |
tests/unit/test_response_event_stream_builder.py |
Tests dictionary event streams. |
tests/unit/test_resolve_input_items_for_persistence.py |
Updates persistence fixtures. |
tests/unit/test_input_items_provider_behavior.py |
Uses TypedDict responses. |
tests/unit/test_in_memory_provider_crud.py |
Tests dictionary storage behavior. |
tests/unit/test_id_generator.py |
Tests discriminator-based ID dispatch. |
tests/unit/test_generated_payload_validation.py |
Uses validator wrapper. |
tests/unit/test_foundry_storage_provider.py |
Updates storage payload fixtures. |
tests/unit/test_event_stream_generators.py |
Verifies dictionary events. |
tests/unit/test_emit_return_types.py |
Checks event wire discriminators. |
tests/unit/test_builders.py |
Updates builder assertions. |
tests/interop/test_sdk_round_trip.py |
Uses mapping-style requests. |
tests/interop/test_openai_wire_compliance.py |
Updates wire-contract assertions. |
tests/e2e/test_proxy_e2e.py |
Uses dictionary requests upstream. |
tests/contract/test_stream_provider_fallback.py |
Uses public model exports. |
tests/contract/test_stream_event_lifecycle.py |
Uses public model exports. |
tests/contract/test_response_invariants.py |
Reads dictionary agent references. |
tests/contract/test_bg_isolation_propagation.py |
Uses public model exports. |
samples/sample_16_structured_outputs.py |
Builds structured-output dictionaries. |
samples/sample_15_annotations.py |
Builds annotation dictionaries. |
samples/sample_14_file_inputs.py |
Reads file input mappings. |
samples/sample_13_image_input.py |
Reads image input mappings. |
samples/sample_11_non_streaming_upstream.py |
Forwards dictionary inputs. |
samples/sample_10_streaming_upstream.py |
Builds dictionary snapshots. |
samples/sample_07_customization.py |
Demonstrates mapping access. |
samples/sample_05_conversation_history.py |
Reads dictionary history. |
samples/sample_04_function_calling.py |
Detects calls by discriminator. |
samples/sample_03_full_control.py |
Mutates response mappings. |
pyproject.toml |
Packages generated typing marker. |
Makefile |
Generates and extracts TypedDict contracts. |
cspell.json |
Adds generated terminology. |
streaming/_text_response.py |
Uses public wire types. |
streaming/_state_machine.py |
Uses public enums and mappings. |
streaming/_sse.py |
Encodes mapping-only events. |
streaming/_builders/_reasoning.py |
Returns TypedDict events. |
streaming/_builders/_function.py |
Uses public wire contracts. |
streaming/_builders/_base.py |
Validates dictionary item payloads. |
store/_memory.py |
Persists dictionary snapshots. |
store/_foundry_serializer.py |
Serializes wire dictionaries. |
store/_foundry_provider.py |
Uses public model aliases. |
store/_base.py |
Updates provider protocol types. |
models/runtime.py |
Stores dictionary execution state. |
models/errors.py |
Builds dictionary error envelopes. |
models/_wire.py |
Adds wire normalization helpers. |
models/_validators.py |
Wraps generated validation. |
models/_generated/sdk/models/models/_patch.py |
Removes legacy customizations. |
models/_generated/sdk/models/_types.py |
Removes legacy unions. |
models/_generated/sdk/models/__init__.py |
Removes legacy package surface. |
models/_generated/py.typed |
Marks generated contracts typed. |
models/_generated/models/_patch.py |
Adds generated patch scaffold. |
models/_generated/models/__init__.py |
Initializes patch surface. |
models/_generated/_unions.py |
Adds generated unions. |
models/_generated/_patch.py |
Removes compatibility shim. |
models/_generated/_models.py |
Removes compatibility shim. |
models/_generated/__init__.py |
Exports TypedDicts and enum shims. |
models/__init__.py |
Builds the public model surface. |
hosting/_validation.py |
Validates and returns wire dictionaries. |
hosting/_runtime_state.py |
Copies dictionary snapshots. |
hosting/_routing.py |
Updates handler contract types. |
hosting/_request_parsing.py |
Resolves identity from mappings. |
hosting/_observability.py |
Copies mapping-based tags. |
hosting/_execution_context.py |
Uses public model types. |
hosting/_event_subject.py |
Publishes dictionary events. |
hosting/_endpoint_handler.py |
Normalizes dictionary HTTP payloads. |
_response_context.py |
Resolves dictionary input items. |
_id_generator.py |
Dispatches IDs by wire discriminator. |
api.metadata.yml |
Updates API snapshot metadata. |
_scripts/validator_emitter.py |
Resolves Literal enum values. |
_scripts/validation-overlay.yaml |
Makes function-call IDs optional. |
_scripts/generated_shims/sdk_models__init__.py |
Removes obsolete shim. |
_scripts/generated_shims/models_patch.py |
Removes obsolete customization. |
_scripts/generated_shims/_patch.py |
Removes obsolete patch shim. |
_scripts/generated_shims/_models.py |
Removes obsolete model shim. |
_scripts/generated_shims/_enums.py |
Removes obsolete enum shim. |
_scripts/generated_shims/__init__.py |
Removes obsolete package shim. |
_scripts/extract_model_contracts.py |
Extracts generated TypedDict contracts. |
Comments suppressed due to low confidence (1)
sdk/agentserver/azure-ai-agentserver-responses/azure/ai/agentserver/responses/models/init.py:44
- The new export construction drops the previously public
ResponseIncompleteReasonenum, whileResponseEventStream.emit_incomplete()still documentsazure.ai.agentserver.responses.models.ResponseIncompleteReason. Either restore this hand-written enum in the public model surface or remove/update the stale reference and explicitly account for the breaking API change.
__all__ = [
"ResponseStatus",
"TerminalResponseStatus",
"get_content_expanded",
"get_conversation_expanded",
"get_conversation_id",
"get_input_expanded",
"get_tool_choice_expanded",
*_generated_all,
| assert completed["response"]["status"] == "completed" | ||
| assert completed["response"]["usage"]["total_tokens"] == 3 | ||
| assert isinstance(completed["response"]["completed_at"], int) | ||
| assert completed["response"]["completed_at"] is not None |
Regenerate AgentServer response contracts from the rapida/add-agentserver-view spec branch and restore the SDK TypeSpec pointer layout to the main SDK shape with only the commit updated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
Fix review feedback for dict-native response models by completing ID generation coverage, preserving wire field names, filtering storage-only SSE fields, and restoring ResponseIncompleteReason as a public compatibility enum. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 96 out of 101 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
sdk/agentserver/azure-ai-agentserver-responses/type_spec/tsp-location.yaml:2
- The pinned source does not match this PR's stated dependency. Azure/azure-rest-api-specs#44689 changes
sdk-service-agents-contractsin commit7691586c..., whereas this selects the oldersdk-service-agentserver-contractstree at an unrelated April commit. Regeneration therefore will not consume the contract this PR depends on.
Sanitize generated model docstrings that Sphinx treats as warnings, narrow public model exports to actual generated types, and add package spellcheck words for generated response ID prefixes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 96 out of 101 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
sdk/agentserver/azure-ai-agentserver-responses/tests/unit/test_response_event_stream_builder.py:148
- This weakened assertion hides that
emit_completed()currently returns adatetimeincompleted_at, while the newResponseObjectTypedDict and wire contract require an integer Unix timestamp;created_athas the same mismatch. Because publicemit_*methods now advertise dict-native wire payloads, convert these fields before returning the event and keep the integer assertion.
Avoid using generated enum fallback objects in runtime code by comparing against the stable wire string values directly, and annotate the ID dispatch table for mypy. Regenerate API stubs after the public export cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 96 out of 101 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (2)
sdk/agentserver/azure-ai-agentserver-responses/azure/ai/agentserver/responses/_response_context.py:145
- This now collects
textfrom every content-part discriminator.ReasoningTextContentalso has atextfield, soget_input_text()can expose reasoning text even though its contract says it extracts message input text. Restrict extraction to the intendedinput_text/resolvedoutput_textparts.
if _is_wire_type(item, "message") or _get_field(item, "content") is not None:
for part in _get_field(item, "content") or []:
text = _get_field(part, "text")
if text is not None:
texts.append(text)
sdk/agentserver/azure-ai-agentserver-responses/azure/ai/agentserver/responses/models/init.py:41
models.__all__is now built only from TypedDict/union modules, so generated public compatibility enums such asMessageRole,ToolType, andResponseStreamEventTypedisappear from star imports and fromapi.md, even though they are imported into the module and existing callers use them. Include the generated enum compatibility names when constructing the public export list.
_generated_all = [
name
for module in (_generated_types, _generated_unions)
for name in dir(module)
if not name.startswith("_")
and name not in _TYPE_EXPORT_EXCLUDES
and isinstance(getattr(module, name), type)
]
Handle scale service tier validation, tighten input text extraction, preserve required statuses on search output items, reject output-only item types from input conversion, and keep generated union aliases public without exposing enum literal aliases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 98 out of 103 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
sdk/agentserver/azure-ai-agentserver-responses/tests/unit/test_response_event_stream_builder.py:148
- This relaxed assertion hides a wire-contract regression:
ResponseObject.completed_atisOptional[int], butemit_completed()currently leaves adatetimein the returned dict and only converts it later during SSE/HTTP serialization. Public builder methods now promise dict-native wire payloads, so direct consumers receive a value that contradicts the generated TypedDict. Convert timestamps when constructing the event and retain the integer assertion here.
sdk/agentserver/azure-ai-agentserver-responses/azure/ai/agentserver/responses/models/init.py:48 - The new
__all__only collects TypedDict classes andUnionaliases, so every generated compatibility enum such asMessageRole,ResponseStreamEventType, andServiceTierEnumis omitted. The previous generated__all__exported these names; wildcard imports and API stub generation therefore lose a large part of the public model surface even though_generated.__init__still creates the compatibility enum objects. Include those generated enum exports when building__all__.
_generated_all = [
name
for module in (_generated_types, _generated_unions)
for name in dir(module)
if not name.startswith("_")
and name not in _TYPE_EXPORT_EXCLUDES
and _is_public_generated_export(getattr(module, name))
]
Use a correctly spelled invalid enum member name in the generated enum fallback regression test so CSpell does not flag the test-only typo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 98 out of 103 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
sdk/agentserver/azure-ai-agentserver-responses/tests/unit/test_response_event_stream_builder.py:148
- This weakened assertion hides a wire-contract regression:
ResponseObject.completed_atis typed and documented as a Unixint, butResponseEventStream._set_terminal_fields()now leaves adatetimein the returned dict becausematerialize_wire_payload()does not convert it. SSE encoding happens to convert it later, but callers of the publicemit_completed()API receive a value that violatesResponseCompletedEvent. Keep the integer assertion and convertcreated_at/completed_atwhen constructing the dict-native event payloads.
| "class _EnumMemberFallback(str):\n" | ||
| " @property\n" | ||
| " def value(self) -> str:\n" | ||
| " return str(self)\n\n\n" |
Generate runtime enum classes from literal aliases so enum members preserve isinstance and iteration semantics, and materialize response timestamps as Unix integers in emitted wire payloads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4ead3de5-a3b3-4d3a-bf93-a4ee397d7498
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 98 out of 103 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
sdk/agentserver/azure-ai-agentserver-responses/azure/ai/agentserver/responses/models/init.py:47
- The generated root intentionally rebinds every
Literalalias (for exampleMessageRoleandAnnotationType) to a compatibility enum, but this filter inspects the original value intypes.py, so all of those enums are excluded frommodels.__all__. This breaksfrom azure.ai.agentserver.responses.models import *and removes the enum declarations fromapi.md(onlyResponseIncompleteReasonremains). Inspect the value already imported into this module, or explicitly include the generated enum aliases.
and _is_public_generated_export(getattr(module, name))
| for ev in events: | ||
| copy = deepcopy(ev) | ||
| copy = dict(deepcopy(ev)) | ||
| copy.setdefault("_saved_at", now) |
| # All events must be dict-native ResponseStreamEvent wire payloads. | ||
| for event in events: | ||
| assert isinstance(event, ResponseStreamEvent), f"Expected ResponseStreamEvent, got {type(event)}" | ||
| assert isinstance(events[0], ResponseCreatedEvent) | ||
| assert isinstance(events[1], ResponseInProgressEvent) | ||
| assert isinstance(events[2], ResponseCompletedEvent) | ||
| assert isinstance(event, dict), f"Expected ResponseStreamEvent dict, got {type(event)}" |
Summary
sdk-service-agentserver-contractsTypeSpec path.tsp-location.yamlaligned with the SDK main layout and update only the spec commit to8bfd173c3afb9c85495293bffc04f6dcd4295548fromAzure/azure-rest-api-specsbranchrapida/add-agentserver-view.ResponseIncompleteReasonas a public compatibility enum.Depends on
Azure/azure-rest-api-specsbranchrapida/add-agentserver-viewat commit8bfd173c3afb9c85495293bffc04f6dcd4295548Validation
tsp-client syncmake generate-contracts.venv/bin/azpysdk pyright ..venv/bin/azpysdk apistub ..venv/bin/azpysdk pylint ..venv/bin/python -m black --check azure/ai/agentserver/responses/_id_generator.py azure/ai/agentserver/responses/hosting/_validation.py azure/ai/agentserver/responses/models/__init__.py azure/ai/agentserver/responses/streaming/_sse.py tests/unit/test_id_generator.py tests/unit/test_sse_writer.py.venv/bin/python -m pytest tests/unit/test_id_generator.py tests/unit/test_sse_writer.py tests/e2e/test_sample_e2e.py -q→59 passed, 1 skipped, 1 warning