Skip to content

feat(lib): expose data_converter kwarg on AgentexWorker and Temporal client APIs - #372

Merged
matteolibrizzi-scale merged 2 commits into
nextfrom
feat/expose-data-converter-kwarg
May 29, 2026
Merged

feat(lib): expose data_converter kwarg on AgentexWorker and Temporal client APIs#372
matteolibrizzi-scale merged 2 commits into
nextfrom
feat/expose-data-converter-kwarg

Conversation

@matteolibrizzi-scale

@matteolibrizzi-scalematteolibrizzi-scale commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a data_converter kwarg to the AgentexWorker / TemporalClient / TemporalACP API surface so callers can compose OpenAIAgentsPlugin with a payload codec (e.g. AES-GCM at-rest encryption).

Why

Today, passing payload_codec=... to AgentexWorker(...) together with OpenAIAgentsPlugin raises with a hard guard. That guard is correct for the API surface currently exposed: without it, the plugin's _data_converter(None) transformer builds a fresh DataConverter and the user's codec is silently dropped — payloads land in Temporal in plain text.

But the composition does work if you pre-build a DataConverter with both payload_converter_class=OpenAIPayloadConverter AND payload_codec=... and pass it via Client.connect(data_converter=...). The plugin's transformer has a fourth branch that passes through any DataConverter whose payload converter is an OpenAIPayloadConverter instance (or subclass) unchanged. This PR exposes that working path through the agentex API.

The first downstream user is the Emu Deep Research agent, which needs both OpenAIAgentsPlugin (to dispatch model calls as invoke_model_activity under Temporal) and the shared emu_shared.encryption.codec.get_payload_codec() already used by OneEdge / FDD / VDR.

What changed

New data_converter kwarg on:

  • agentex.lib.core.temporal.workers.worker.get_temporal_client and AgentexWorker.__init__ (worker side)
  • agentex.lib.core.clients.temporal.utils.get_temporal_client (client side)
  • TemporalClient.__init__ / TemporalClient.create
  • TemporalACP.__init__ / TemporalACP.create
  • TemporalACPConfig (forwarded by FastACP.create_async_acp)

Guards in both get_temporal_client implementations:

  1. Ambiguitypayload_codec AND data_converter together raise ValueError (the codec belongs inside the data converter).
  2. Silent-drop guard refined — fires only when OpenAIAgentsPlugin is present AND payload_codec is the standalone kwarg AND no data_converter was supplied. The error message now points callers at the working composition path (DataConverter(payload_converter_class=OpenAIPayloadConverter, payload_codec=...)).

No behavior change for existing callers — none currently pass data_converter.

Usage

fromtemporalio.converterimportDataConverterfromtemporalio.contrib.openai_agentsimportOpenAIAgentsPlugin, OpenAIPayloadConverterworker=AgentexWorker(
task_queue=...,
plugins=[OpenAIAgentsPlugin(...)],
data_converter=DataConverter(
payload_converter_class=OpenAIPayloadConverter,
payload_codec=my_aes_gcm_codec,
),
)

Test plan

  • All 355 existing tests in tests/lib/ pass
  • New tests added in tests/lib/test_payload_codec.py for both get_temporal_client paths:
    • data_converter pass-through with OpenAIAgentsPlugin
    • data_converter pass-through without plugin
    • payload_codec + data_converter together raises ambiguity error
    • Silent-drop guard error message references data_converter
  • New tests for AgentexWorker, TemporalClient, TemporalACP, TemporalACPConfig, FastACP storing/forwarding data_converter
  • Signature smoke check confirms data_converter appears on all five public surfaces

🤖 Generated with Claude Code

Greptile Summary

This PR exposes a data_converter kwarg across the full Agentex worker/client API surface (AgentexWorker, TemporalClient, TemporalACP, TemporalACPConfig, FastACP) so callers can compose OpenAIAgentsPlugin with an encryption codec by pre-building a DataConverter(payload_converter_class=OpenAIPayloadConverter, payload_codec=...) and passing it directly, bypassing the silent-drop guard that blocked this pattern before.

  • New data_converter parameter added to all five public surfaces, forwarded through to Client.connect; the existing payload_codec standalone path is preserved unchanged.
  • Two mutual-exclusivity guards added in both get_temporal_client implementations: one raising immediately if both payload_codec and data_converter are provided, and one refining the existing guard to fire only when payload_codec is the standalone kwarg with OpenAIAgentsPlugin present (not when data_converter is supplied).
  • TemporalACPConfig gains a model_validator mirroring the runtime guard so misconfiguration is caught at Pydantic construction time; new tests cover all five surfaces.

Confidence Score: 5/5

Safe to merge — the change is purely additive, all existing callers are unaffected, and the two new guards prevent the same silent-drop failure mode the original guard was added for.

All five public surfaces are updated consistently, the mutual-exclusivity guards fire before any connection attempt, and the TemporalACPConfig model validator catches misconfiguration at object construction time. The lazy-validation pattern in AgentexWorker and TemporalACP is deliberate and consistent with how interceptors are validated in the same classes. No existing behavior is changed for callers who don't pass data_converter.

No files require special attention.

Important Files Changed

FilenameOverview
src/agentex/lib/core/clients/temporal/utils.pyAdds data_converter param to get_temporal_client; two guards (ambiguity + OpenAI silent-drop) correctly gate the new path; pass-through branch and default pydantic path are mutually exclusive and correct.
src/agentex/lib/core/temporal/workers/worker.pyMirrors the utils changes: data_converter stored on AgentexWorker and forwarded to the worker-side get_temporal_client; identical guard logic applied; Worker uses the client's data converter so no separate forwarding is needed.
src/agentex/lib/types/fastacp.pyAdds data_converter: Any field to TemporalACPConfig and a model_validator enforcing mutual exclusivity with payload_codec at Pydantic construction time — the only layer with eager validation in this PR.
src/agentex/lib/sdk/fastacp/impl/temporal_acp.pyThreads data_converter through TemporalACP.init, create, and into TemporalClient.create during lifespan; straightforward and consistent with the payload_codec pattern already present.
src/agentex/lib/core/clients/temporal/temporal_client.pyStores data_converter in TemporalClient.init and forwards it via both create() and _get_temporal_client(); the setup() path already delegates to _get_temporal_client so it inherits the forwarding correctly.
src/agentex/lib/sdk/fastacp/fastacp.pyAdds one hasattr forwarding block for data_converter in create_async_acp, consistent with the existing pattern for payload_codec and other temporal-specific fields.
tests/lib/test_payload_codec.pyWell-structured new tests covering pass-through with and without OpenAI plugin, ambiguity error, and forwarding through all five public surfaces; tests mock Client.connect appropriately for the unit-test scope.

Sequence Diagram

sequenceDiagram
participant Caller
participant AgentexWorker / TemporalACP / TemporalClient
participant get_temporal_client
participant Client.connect
Caller->>AgentexWorker / TemporalACP / TemporalClient: __init__(data_converter=dc)
Note over AgentexWorker / TemporalACP / TemporalClient: stores data_converter, no early validation
Caller->>AgentexWorker / TemporalACP / TemporalClient: run() / lifespan / create()
AgentexWorker / TemporalACP / TemporalClient->>get_temporal_client: (plugins, payload_codec, data_converter)
alt "payload_codec != None AND data_converter != None"
get_temporal_client-->>Caller: ValueError (ambiguous)
else "OpenAIAgentsPlugin + payload_codec != None AND data_converter == None"
get_temporal_client-->>Caller: ValueError (silent-drop guard)
else "data_converter != None"
get_temporal_client->>Client.connect: "data_converter=dc (pass-through)"
else not has_openai_plugin
get_temporal_client->>Client.connect: "data_converter=pydantic/custom (optionally +payload_codec)"
else OpenAIAgentsPlugin, no codec
get_temporal_client->>Client.connect: (no data_converter — plugin sets its own)
end
Loading

Reviews (5): Last reviewed commit: "fix(lib): tighten TemporalACPConfig + co..." | Re-trigger Greptile

Comment threadsrc/agentex/lib/core/clients/temporal/utils.py
Comment threadsrc/agentex/lib/types/fastacp.py
@matteolibrizzi-scale
matteolibrizzi-scaleforce-pushed the feat/expose-data-converter-kwarg branch from 55ccc59 to 9eaacd5CompareMay 29, 2026 10:57
@matteolibrizzi-scale
matteolibrizzi-scale enabled auto-merge (squash) May 29, 2026 10:58
matteolibrizzi-scaleand others added 2 commits May 29, 2026 13:31
…client APIs
Adds a `data_converter` kwarg to:
- `AgentexWorker.__init__` and `worker.get_temporal_client`
- `clients.temporal.utils.get_temporal_client`
- `TemporalClient` / `TemporalACP` / `TemporalACPConfig` / `FastACP`
This unlocks composing `OpenAIAgentsPlugin` with a payload codec by passing
a pre-built `DataConverter(payload_converter_class=OpenAIPayloadConverter,
payload_codec=...)`. Previously the plugin would silently drop a standalone
`payload_codec` kwarg because its `_data_converter(None)` transformer builds
a fresh converter without any codec — the existing guard rejected this
combination outright. The guard is refined: it now fires only when both
the plugin is present AND `payload_codec` is the standalone kwarg AND no
`data_converter` was supplied, and the error message points callers at the
working composition path. An additional guard rejects passing `payload_codec`
and `data_converter` together as ambiguous.
No behavior change for existing callers (none currently pass `data_converter`).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add `model_validator(mode="after")` on `TemporalACPConfig` that rejects
setting both `payload_codec` and `data_converter`, mirroring the
`get_temporal_client` ambiguity guard at config-construction time
(consistent with the existing `plugins` / `interceptors` validators).
- Collapse multi-line comments in `worker.py` and `clients/temporal/utils.py`
to single-line context — the PR description carries the long-form rationale.
- Ruff import-order autofixes on touched files (resolves CI lint).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@declan-scale
declan-scaleforce-pushed the feat/expose-data-converter-kwarg branch from 9eaacd5 to 0f4733eCompareMay 29, 2026 17:31
@matteolibrizzi-scale
matteolibrizzi-scale merged commit d04624e into nextMay 29, 2026
37 checks passed
@matteolibrizzi-scale
matteolibrizzi-scale deleted the feat/expose-data-converter-kwarg branch May 29, 2026 17:36
@stainless-appstainless-appBot mentioned this pull request May 29, 2026
@stainless-appstainless-appBot mentioned this pull request May 30, 2026
Sign up for freeto 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.

2 participants

@matteolibrizzi-scale@declan-scale