Skip to content

Fix #245 CJS resolution failure #346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 16, 2025

Conversation

seratch
Copy link
Member

@seratch seratch commented Aug 15, 2025

This pull request adds the integration test correction on top of @CharlieGreenman's amazing contribution #258; it resolves #245

You can verify this PR resolves the CJS issue by the following steps:

Step 1: Before merging the changes in this PR; follow the steps at https://github.com/openai/openai-agents-js/blob/main/integration-tests/README.md the test fails this way:

 FAIL  integration-tests/node.test.ts > Node.js > should be able to run using CommonJS
ExecaError: Command failed with exit code 1: npm run 'start:cjs'

(node:67335) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/seratch/code/openai-agents-js/integration-tests/node/node_modules/@openai/agents/dist/index.js:1
import { setDefaultModelProvider } from '@openai/agents-core';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (node:internal/modules/cjs/loader:1472:18)
    at Module._compile (node:internal/modules/cjs/loader:1501:20)
    at Module._extensions..js (node:internal/modules/cjs/loader:1613:10)
    at Module.load (node:internal/modules/cjs/loader:1275:32)
    at Module._load (node:internal/modules/cjs/loader:1096:12)
    at Module.require (node:internal/modules/cjs/loader:1298:19)
    at require (node:internal/modules/helpers:182:18)
    at Object.<anonymous> (/Users/seratch/code/openai-agents-js/integration-tests/node/index.cjs:9:5)
    at Module._compile (node:internal/modules/cjs/loader:1529:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1613:10)

Node.js v20.19.4


> start:cjs
> node --no-experimental-require-module index.cjs

Step 2: With the changes in this PR, all the integration tests pass.

@vrtnis
Copy link
Contributor

vrtnis commented Aug 15, 2025

Quick thought - noticed tsc-multi.json now flips the .js target to CJS and keeps ESM as .mjs. That effectively makes .mjs the public ESM surface for the packages, right?

Just to better understand the trajectory here, would there be breakage we’d expect for projects that: rely on "type":"module" and therefore expect ESM at .js, and/or deep‑import files under dist/*.js (not ideal of course, but we may see it in the wild).

Also re: exports, with .js now CJS and .mjs ESM, will each package’s exports map (incl. subpaths like ./realtime, ./utils, ./_shims/*) be updated to route import -> *.mjs and require -> CJS *.js? And we won’t keep "type":"module" in packages where .js is CJS?

For comparison, counterpart tsc-multi approach in draft #333 keeps ESM as .js in dist/ and adds a CJS dist-cjs/ with exports.import/require wiring, plus the same loadEnv() eval(import.meta) guard.

Apologies for the many questions, I’m happy to rebase #333 as I draft it on top of #346 - just wanted to clarify these tsc-multi specific points.

"scripts": {
"start:cjs": "node index.cjs",
"start:esm": "node index.mjs"
"start:cjs": "node --no-experimental-require-module index.cjs",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this option is necessary to turn the esmodule interop option off

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it! sounds good :)

cwd: './integration-tests/node',
env: {
...process.env,
NODE_OPTIONS: '',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove all the pre-set node options too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, makes sense ..will prevent hidden loader/interop from leaking in

@@ -1,6 +1,6 @@
{
"targets": [
{ "extname": ".js", "module": "es2022", "moduleResolution": "node" },
{ "extname": ".js", "module": "commonjs", "moduleResolution": "node" },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*.js files are CJS compat; *.mjs are ESModule compat

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the .js ---> CJS / .mjs --> ESM flip is clear. wondering if will we align each packages/* exports (incl. subpaths) so import --> *.mjs, require --> *.js, and drop "type":"module" where .js is CJS? If top-level only is intended, all good!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. I've revised package.json files to be simpler and clearer to use "require" and "import". Verified the behavior with the integration tests, plus did additional manual tests with a simple project too.

@@ -1,6 +1,6 @@
{
"targets": [
{ "extname": ".js", "module": "es2022", "moduleResolution": "node" },
{ "extname": ".js", "module": "commonjs", "moduleResolution": "node" },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. I've revised package.json files to be simpler and clearer to use "require" and "import". Verified the behavior with the integration tests, plus did additional manual tests with a simple project too.

@@ -14,67 +14,49 @@
},
"exports": {
".": {
"require": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to repeat types and default under require; simplified much

"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
"require": "./dist/index.js",
"import": "./dist/index.mjs"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"default" works too but "import" works with clearer intention with ESModule

},
"types": "./dist/shims/shims-node.d.ts",
"default": "./dist/shims/shims-node.mjs"
"types": "./dist/shims/shims.d.ts",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shims/shims is just a reference to shims/shims-node, but there is no downside of this change

@seratch
Copy link
Member Author

seratch commented Aug 15, 2025

@vrtnis

Quick thought - noticed tsc-multi.json now flips the .js target to CJS and keeps ESM as .mjs. That effectively makes .mjs the public ESM surface for the packages, right?

Yes, you're right.

Just to better understand the trajectory here, would there be breakage we’d expect for projects that: rely on "type":"module" and therefore expect ESM at .js, and/or deep‑import files under dist/*.js (not ideal of course, but we may see it in the wild).

We basically do not support deep-imports. When a user needs some additional exports, we're happy to add exports of sub directories and/or export those modules under existing exports.

Also re: exports, with .js now CJS and .mjs ESM, will each package’s exports map (incl. subpaths like ./realtime, ./utils, ./_shims/*) be updated to route import -> *.mjs and require -> CJS *.js? And we won’t keep "type":"module" in packages where .js is CJS?

Yes, this is correct.

For comparison, counterpart tsc-multi approach in draft #333 keeps ESM as .js in dist/ and adds a CJS dist-cjs/ with exports.import/require wiring, plus the same loadEnv() eval(import.meta) guard.

I don't see the necessity to have dist and dist-cjs. However, if there is anything to add on top of this PR, I am happy to check your PRs!

@vrtnis
Copy link
Contributor

vrtnis commented Aug 15, 2025

@seratch --thanks so much for the detailed explanation and context here, all sounds great :)

Copy link

changeset-bot bot commented Aug 16, 2025

⚠️ No Changeset found

Latest commit: c894a8e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@seratch
Copy link
Member Author

seratch commented Aug 16, 2025

Did more tests and this should work well for both CJS and ESModule projects

@seratch seratch merged commit 8c4e116 into main Aug 16, 2025
5 checks passed
@seratch seratch deleted the CharlieGreenman-issue-245-branch-commonjs-interop branch August 16, 2025 00:33
seratch added a commit that referenced this pull request Aug 16, 2025
@seratch seratch mentioned this pull request Aug 16, 2025
seratch added a commit that referenced this pull request Aug 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Runtime SyntaxError for typescript 5.8.3 with openai/agents v0.0.12 at agents-core with node v22 locally and AWS lambda
3 participants