Skip to content

fix(openai): serialize output schema activity input - #198

Merged
zawadzkidiana merged 5 commits into
cadence-workflow:mainfrom
zawadzkidiana:issue-197-null-output-schema
Oct 15, 2026
Merged

zawadzkidiana merged 5 commits into
cadence-workflow:mainfrom
zawadzkidiana:issue-197-null-output-schema

Conversation

@zawadzkidiana

@zawadzkidiana zawadzkidiana commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Convert OpenAI AgentOutputSchemaBase instances into a concrete, data-conversion-friendly CadenceOutputSchema before scheduling the model Activity.
  • Keep PydanticDataConverter unchanged instead of teaching the generic converter about one framework's abstract class.
  • Preserve the existing 11-argument Activity payload shape while supporting both output_schema=None and non-null structured output.
  • Keep output validation in the Workflow with the original OpenAI Agents schema; the Activity receives only the name, JSON schema, plain-text flag, and strictness needed for the provider request.
  • Avoid repeated failed TypeAdapter construction by removing the converter-level fallback entirely.

Fixes #197.

Validation

  • uv run pytest -q: passed; integration tests skipped unless explicitly enabled.
  • uv run ruff check cadence tests: passed.
  • uv run ruff format --check cadence tests: passed.
  • uv run --all-extras mypy cadence/ tests/: passed.
  • Full 11-argument round trips pass for null and structured output schemas.
  • The actual CadenceModel handoff is tested to send CadenceOutputSchema to the Activity.
  • A credential-free worker-side OpenAIActivities.invoke_model test reconstructs a function tool, carries structured-output metadata, and calls a mocked model.
  • Unsupported non-null arbitrary types still raise PydanticSchemaGenerationError; generic converter strictness is unchanged.
  • Responses API and Chat Completions request formats are identical before and after transport in strict and non-strict modes.
  • OpenAI Agents 0.24.0 passes null, structured-output, and provider-format equivalence checks.
  • A locally built wheel passed all 12 pinned cadence-ai-samples recipe/profile locations: 12/12 passed.
  • The previously failing Recurring AI Watch OpenAI release test passed.
  • The upgraded cadence-samples OpenAI environment compiled, passed Ruff, and passed null and structured-output boundary checks.

Limitations

  • No paid-provider or Windows live matrix was run.
  • This PR does not change downstream pins. A published client release is required before cadence-ai-samples can replace its SHA requirements.

Signed-off-by: zawadzkidiana <dzawa@live.de>
Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
cadence/contrib/openai/cadence_model.py 93.75% <100.00%> (+93.75%) ⬆️
cadence/contrib/openai/cadence_output_schema.py 100.00% <100.00%> (ø)
cadence/contrib/openai/openai_activities.py 100.00% <100.00%> (+100.00%) ⬆️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread cadence/contrib/pydantic/_data_converter.py Outdated
@gitar-bot

gitar-bot Bot commented Oct 15, 2026

Copy link
Copy Markdown

Gitar is not allowed to push to this forked PR. Please enable "Allow edits from maintainers" to allow Gitar to push.

@zawadzkidiana zawadzkidiana self-assigned this Oct 15, 2026
@zawadzkidiana
zawadzkidiana marked this pull request as ready for review October 15, 2026 21:15
Signed-off-by: zawadzkidiana <dzawa@live.de>
Co-authored-by: Cursor <cursoragent@cursor.com>
@zawadzkidiana zawadzkidiana changed the title fix(pydantic): decode null optional unsupported types fix(openai): serialize output schema activity input Oct 15, 2026
@zawadzkidiana
zawadzkidiana marked this pull request as draft October 15, 2026 21:17
zawadzkidiana and others added 2 commits October 15, 2026 14:22
Signed-off-by: zawadzkidiana <dzawa@live.de>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: zawadzkidiana <dzawa@live.de>
Co-authored-by: Cursor <cursoragent@cursor.com>
@zawadzkidiana

Copy link
Copy Markdown
Contributor Author

The remaining 3/4 objective is intentionally not implemented as written because it describes the earlier converter-level approach:

Decode a JSON null value for a nullable Activity parameter without constructing a Pydantic schema for the non-null member.

The revised implementation removes AgentOutputSchemaBase | None from the Activity boundary. CadenceModel converts it before scheduling, and OpenAIActivities.invoke_model now receives CadenceOutputSchema | None, a concrete serializable type that Pydantic supports.

As a result:

  • Pydantic successfully constructs and caches the adapter for CadenceOutputSchema | None.
  • A null value is validated normally by that adapter.
  • No PydanticSchemaGenerationError is raised or caught.
  • There is no repeated failed-adapter path to cache.
  • PydanticDataConverter remains generic and unchanged.

So the user-visible outcome is covered, but the literal requirement to avoid constructing a schema is superseded: constructing a valid schema for the concrete transport type is now the intended behavior. The full 11-argument null round trip, non-null structured-output round trip, provider-format equivalence, strict non-null rejection, and credential-free worker-side Activity path are all tested.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: zawadzkidiana <dzawa@live.de>
Co-authored-by: Cursor <cursoragent@cursor.com>
@zawadzkidiana
zawadzkidiana force-pushed the issue-197-null-output-schema branch from 6dfc0b3 to adbe8ce Compare October 15, 2026 21:35
@gitar-bot

gitar-bot Bot commented Oct 15, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟡 Medium risk · Converting OpenAI output schemas into activity-transport metadata could disrupt structured-output model requests if serialization or reconstruction mishandles schema details.

Converts OpenAI AgentOutputSchemaBase into a serializable CadenceOutputSchema before the model Activity is scheduled, keeping PydanticDataConverter unchanged. Failed TypeAdapter builds are no longer cached, so they rerun on each null-schema call. No open issues remain.

✅ 1 closed
✅ Performance: Failed TypeAdapter builds are never cached, so they rerun on every null

📄 cadence/contrib/pydantic/_data_converter.py:41-43 📄 cadence/contrib/pydantic/_data_converter.py:62-68
self._type_adapter is lru_cache(TypeAdapter), and functools.lru_cache does not store results for calls that raise. So when the hint is something like AgentOutputSchemaBase | None, every decode of null (for example output_schema=None on each invoke_model activity call) runs Pydantic schema generation again, raises PydanticSchemaGenerationError, and then catches it. Before this PR that path failed outright. Now it succeeds but repeats the schema-generation cost on every call. A fix is to remember hints that failed (a small set or dict keyed by hint) and skip the adapter build for them when the value is null.

Verification Objectives 3/4 Repos 1 inspected · PRs 1 inspected
Functional validation 3 covered / 4 objectives

#197 3 covered / 4 objectives

Other objectives on this issue, possibly covered elsewhere:

◻️ Decode a JSON null value for a nullable Activity parameter without constructing a Pydantic schema for the non-null member

✅ Add a credential-free mocked model and tool integration check exercising the worker-side Activity boundary
✅ Keep strict validation unchanged for non-null values, so unsupported arbitrary objects are not silently accepted
✅ Round-trip all 11 arguments of OpenAIActivities.invoke_model through PydanticDataConverter with output_schema set to None

Rules No rules evaluated

Broader impact Repos 1 inspected PRs 1 inspected
Cross-repo 1 repository inspected 0 open impacts

cadence-workflow/cadence-samples Inspected

Cross-PR 1 PR inspected 0 open impacts

PR #196: feat!: Standardize Error Handling and Support Custom Error Reasons Inspected

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@shijiesheng

Copy link
Copy Markdown
Member

Good catch!

@zawadzkidiana
zawadzkidiana merged commit c28b21f into cadence-workflow:main Oct 15, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAI model Activity cannot transport output_schema through PydanticDataConverter

2 participants