Skip to content

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

Open
matteolibrizzi-scale wants to merge 2 commits into
nextfrom
feat/expose-data-converter-kwarg
Open

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

Conversation

@matteolibrizzi-scale
Copy link
Copy Markdown

@matteolibrizzi-scale matteolibrizzi-scale commented May 27, 2026

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

from temporalio.converter import DataConverter
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, OpenAIPayloadConverter

worker = 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 all five public surfaces (AgentexWorker, TemporalClient, TemporalACP, TemporalACPConfig, FastACP) to let callers compose OpenAIAgentsPlugin with a payload codec by pre-building a fully-configured DataConverter and passing it directly, bypassing the conflict that previously blocked this combination.

  • New ambiguity guard in both get_temporal_client implementations rejects payload_codec + data_converter together; the existing OpenAI-plugin silent-drop guard is tightened to fire only when payload_codec is the standalone kwarg (not when a full DataConverter is supplied).
  • TemporalACPConfig gains a model_validator that enforces mutual exclusion at config construction time, consistent with its existing eager-validation pattern for plugins and interceptors.
  • New test cases cover pass-through, ambiguity errors, and construction defaults on all five surfaces; plugin transformer behaviour is not exercised end-to-end because Client.connect is mocked.

Confidence Score: 4/5

Safe to merge for callers who follow the documented usage; the new data_converter path works correctly when the caller supplies a properly-constructed DataConverter.

The change is well-scoped and backwards-compatible. All existing callers are unaffected. The one gap worth noting is that AgentexWorker.__init__ accepts incompatible payload_codec + data_converter combinations silently, only surfacing the error later in run() after partial startup steps (health check server, agent registration) have already executed — whereas TemporalACPConfig enforces the same constraint eagerly at construction.

src/agentex/lib/core/temporal/workers/worker.py — AgentexWorker.__init__ does not validate the mutual exclusion that get_temporal_client enforces, so misconfigured workers start partially before failing.

Important Files Changed

Filename Overview
src/agentex/lib/core/clients/temporal/utils.py Adds data_converter kwarg with ambiguity guard and refined OpenAI-plugin guard; passes converter directly to Client.connect when supplied.
src/agentex/lib/core/temporal/workers/worker.py Mirrors utils.py changes for the worker path; AgentexWorker.__init__ stores data_converter but skips the mutual-exclusion check that TemporalACPConfig enforces at construction.
src/agentex/lib/core/clients/temporal/temporal_client.py Adds data_converter to TemporalClient.__init__ and create; correctly threads it through to get_temporal_client.
src/agentex/lib/types/fastacp.py Adds data_converter field to TemporalACPConfig with a model_validator enforcing mutual exclusion with payload_codec at construction time.
src/agentex/lib/sdk/fastacp/impl/temporal_acp.py Adds data_converter to TemporalACP.__init__ and create, correctly forwarded to TemporalClient.create.
src/agentex/lib/sdk/fastacp/fastacp.py Forwards data_converter from config to implementation_class.create using the same hasattr pattern as payload_codec.
tests/lib/test_payload_codec.py New tests cover pass-through, mutual-exclusion, and construction defaults for all five public surfaces; data_converter + OpenAI-plugin tests mock Client.connect so plugin transformer behavior is not exercised end-to-end.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant AgentexWorker
    participant TemporalACP
    participant TemporalClient
    participant get_temporal_client
    participant Client.connect

    Caller->>AgentexWorker: "__init__(data_converter=dc)"
    note over AgentexWorker: stores dc, no early validation
    Caller->>AgentexWorker: "run(activities, workflow=...)"
    AgentexWorker->>get_temporal_client: "(data_converter=dc, plugins=...)"
    get_temporal_client->>get_temporal_client: guard: payload_codec+data_converter → ValueError
    get_temporal_client->>get_temporal_client: guard: has_openai_plugin+payload_codec → ValueError
    get_temporal_client->>Client.connect: "data_converter=dc (passed through)"

    Caller->>TemporalACP: "create(data_converter=dc)"
    TemporalACP->>TemporalClient: "create(data_converter=dc)"
    TemporalClient->>get_temporal_client: "(data_converter=dc)"
    get_temporal_client->>Client.connect: "data_converter=dc"

    Caller->>TemporalACPConfig: "(payload_codec=x, data_converter=dc)"
    TemporalACPConfig->>TemporalACPConfig: model_validator → ValueError (eager)
Loading

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/agentex/lib/core/temporal/workers/worker.py:147-173
**`AgentexWorker` defers mutual-exclusion validation until `run()`**

`TemporalACPConfig` now validates `payload_codec` + `data_converter` mutual exclusion eagerly via `model_validator`, but `AgentexWorker.__init__` stores both values without any guard. The ambiguity check is only triggered inside `get_temporal_client` when `.run()` is called — which happens after `start_health_check_server()` and `_register_agent()` have already executed. A misconfigured worker therefore completes partial startup before raising, leaving a registered-but-non-functional agent in the system. Adding the same `ValueError` guard in `__init__` (mirroring the pattern in `TemporalACPConfig`) would surface the error immediately at construction, consistent with the fast-fail behaviour now enforced elsewhere.

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

…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>
Comment thread src/agentex/lib/core/clients/temporal/utils.py
Comment thread src/agentex/lib/types/fastacp.py
- 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>
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.

2 participants