Repository navigation
Conversation
convertAgent runs a clone of each agent, and the clone has its own event emitter, so listeners on the caller's agent never heard agent_start, agent_end, agent_handoff, agent_tool_start or agent_tool_end. Each clone now re-emits them on the original agent, with agent arguments mapped back to the caller's agents. A listener that writes the run context runs in Workflow code and can change the commands that follow, so the forwarding is behind the openai-agents.forward-agent-hooks patch: runs recorded before it keep skipping the hooks on replay.
This was referenced Oct 27, 2026
Closed
Contributor
Author
|
Replaced by #270. It runs agents as written instead of cloning them, so agent.on(...) listeners fire without the forwarding code here. This PR's Worker test is carried over there and passes. |
campoy
deleted the
fix/openai-agents-typescript-agent-hooks-never-fire
branch
October 29, 2026 15:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was changed
agent.on(...)lifecycle hooks now run when an agent goes throughTemporalOpenAIRunner.run, as they do with the upstreamRunner.convertAgentruns a clone of each agent (to swap in the Activity-backed model), and the clone has its own event emitter. With the new internalforwardHooksflag, each clone re-emitsagent_start,agent_end,agent_handoff,agent_tool_startandagent_tool_endon the original agent. Agent arguments are mapped back to the caller's agents, soagent_startgets the caller's agent andagent_handoffthe caller's handoff target. Handoff targets are converted the same way, so their listeners run too.TemporalOpenAIRunner.runsets that flag frompatched('openai-agents.forward-agent-hooks').API change: none.
convertAgentis not exported, and no option or signature of the public API changes.Replay and rollback: a listener that writes the run context runs in Workflow code and can change the commands that follow, so the forwarding is behind a
patched()gate. Runs recorded before this change keep skipping the hooks on replay. The gate can't be narrowed to agents that have listeners: in the Workflow bundle the agent's emitter is the framework's browser emitter, which keeps its listeners in private fields and whoseemitalways returnstrue. So new runs record the marker on their firstrun()call, and an earlier plugin version can't replay them ([TMPRL1100]on the marker). To roll back, keep this version and decline the patch with the Worker'spatchActivationCallback(experimental in SDK 1.24), or use Worker Versioning.Why?
See #235.
agent.clone()gives the clone a new event emitter, and the run loop emits lifecycle events on the running agent, the clone, so listeners on the caller's agent never heard them. Nothing failed or warned. A listener that writes the run context, which the upstream context guide allows, silently never ran, so later model requests and the next turn didn't see the value, and the result could differ from the same code outside Temporal.Checklist
Closes [Bug] openai-agents (TypeScript): agent.on(...) lifecycle hooks never run through TemporalOpenAIRunner #235
How was this tested:
src/__tests__/convert-agent.test.ts: withforwardHooks, events emitted on the clones reach listeners on the caller's agents, with the caller's agent inagent_startand the caller's handoff target inagent_handoff; without it, they don't.agent.on listeners run and their context writes reach later turnsinsrc/__tests__/test-openai-agents.ts. Its Workflow has anactivityAsTooltool and three listeners; the tool-end listener writes the tool result into the run context, the instructions show the context, and a second turn runs only when the listener wrote it.agent.on listeners stay off when replaying a run recorded before they were forwarded. It replays a History of that Workflow recorded onmain(src/__tests__/histories/agent-hooks-before-forwarding.json), where no listener ran and the run ended after one turn.mainwith only the new integration tests copied in, the listener test fails:result.eventsis[]instead of the five events. The replay test passes there too.[TMPRL1100] Nondeterminism error: Activity machine does not handle this event: HistoryEvent(id: 23, WorkflowExecutionCompleted): the listener writes the context, so the Workflow starts a second turn where the old run ended.src/__tests__/agent-tools.test.tsfake the Workflow activator to callrun(); the fake now haspatchInternal.make sync,make lint(8 existing warnings, none in files this PR touches),make test(211 tests),make build,scripts/ci/check_npm_package.py,node ../_shared/smoke.mjsandscripts/ci/check_conventions.pypass, and Prettier with the SDK settings reports the changed files clean.mainatc664a34, and 0 on this branch.mainand from this branch, with and without listeners, finished and still waiting:main's, its own, and the runs carried across versions.main's waiting runs finish on this branch with the old behavior: no listener events, no marker, 0 failed Workflow Tasks.patchActivationCallbackdeclining the patch): this branch's waiting runs finish with the listeners still on (the second turn runs), 0 failed Workflow Tasks; a new run takes the old path and records no marker.mainreplays the 7 histories without the marker and fails the 6 with it with[TMPRL1100] Nondeterminism error: Non-deprecated patch marker encountered for change openai-agents.forward-agent-hooks, as expected forpatched().main's finished run with listeners fails with[TMPRL1100]; its other 3 histories replay.fetchValueActivity in a history fails with[TMPRL1100] Nondeterminism error: Activity type of scheduled event 'fetchRenamed' does not match activity type of activity command 'fetchValue'.CI covers the other Node versions and platforms. Not run against a real model provider.
Any docs updates needed?
The README row, included here. Release notes should say that
agent.on(...)listeners now run in new runs, in Workflow code, and that runs started on this version can't be replayed by an earlier one.Not covered:
runner.on(...)):TemporalOpenAIRunnerkeeps its innerRunnerprivate, so there is nothing to register them on.Related: the other open drafts for this plugin (#209, #210, #215, #216, #217, #218) also add tests at the end of
src/__tests__/test-openai-agents.tsandsrc/__tests__/workflows/openai-agents.tsand edit the README, so whichever merges later may need a small rebase there. None of them touchesconvert-agent.tsor theconvertAgentcall inrunner.ts.Open questions:
run()call even without listeners, and rolling back to an earlier version needspatchActivationCallback(experimental) or Worker Versioning. An opt-in option would avoid the marker for others, but it would be a public API addition and leave listeners silently skipped by default.Runner) or the clone the plugin runs?Draft while these questions are open.