Skip to content

fix(runners): observe cancellation after completion callbacks - #2591

Merged
HAYDEN-OAI merged 3 commits into
mainfrom
codex/runner-after-completion-abort
Sep 4, 2026
Merged

fix(runners): observe cancellation after completion callbacks#2591
HAYDEN-OAI merged 3 commits into
mainfrom
codex/runner-after-completion-abort

Conversation

@HAYDEN-OAI

@HAYDEN-OAI HAYDEN-OAI commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Cancelling a tool runner during its final afterCompletion callback could be reported as success: done() resolved and successful final events were emitted even though the runner controller was aborted.

This PR observes callback cancellation at the existing post-callback boundary and again at successful final settlement:

  • Continue awaiting the configured callback at all three exit sites: a final response, a forced function call, and the completion limit.
  • Retain the early cancellation check before another request, and use one final-settlement check to cover later fulfillment reactions on a callback's returned promise.
  • Preserve the runner signal's reason by identity on APIUserAbortError.cause.
  • Preserve completed tool results and the original error when the callback itself rejects.

The final-settlement check is gated by a private flag set only when afterCompletion is actually invoked. Omitted/null callbacks, configured-but-never-invoked callbacks, and unrelated ChatCompletionStream behavior remain unchanged.

Scope

Only handwritten src/lib/AbstractChatCompletionRunner.ts, its existing cancellation test, and docs/helpers.md change. No generated files, dependencies, exported types, or general EventStream machinery change.

#2607 owns the broader external-signal reason forwarding and five preexisting tool checkpoints. Those changes are not duplicated here. This PR preserves the reason already present on the runner's signal at the new callback boundaries and composes with that separate forwarding fix.

Verification

  • Fail-before regressions cover callback/external cancellation, cause identity, and the late-promise-reaction race across JSON/SSE and every exit route. The final settlement addition made eight previously failing late-reaction cases pass while preserving 34 controls.
  • 118 related tests pass on Node 22.22.2 and 24.19.0, including callback-error-precedence and no-callback controls.
  • 474 final built CJS/ESM checks pass across exact Node 22.0.0, 24.19.0, and 26.7.0: a 324-case runner matrix plus 150 independent compatibility checks. These verify cause identity/descriptors, arbitrary/falsy reasons, late reactions, one request, retained history, lifecycle counts, omitted/null callbacks, never-invoked callbacks, and bare streams.
  • tsc --noEmit, canonical ./scripts/build, pinned Oxfmt 0.62.0, available cached Oxlint 1.76.0, and git diff --check pass. Emitted CJS/ESM runner declarations remain byte-identical.
  • Full handwritten unit suite on the final revision: 7,450 passed, 1 failed. The sole oxlint-config package-command dependency-verification failure reproduces identically on the clean dde19c5c base.
  • Repeated independent adversarial review covered security, compatibility, callback/error precedence, final-settlement ordering, and regression gaps. No blocking implementation findings remain within this callback scope.

Review follow-ups

  • 718da1c6 adds cause preservation at the new checkpoint.
  • 4ae4ac34 closes the late-promise-reaction gap with the callback-scoped settlement guard.

Local tooling limitation

Fresh frozen installation remains blocked by missing publication-time metadata for qs@6.16.0 in the configured registry. Local checks use available cached Vitest 4.1.10 and Oxlint 1.76.0 rather than pinned 4.1.11 and 1.79.0; TypeScript 6.0.3 and Oxfmt 0.62.0 match their pins. Fresh CI validates the new head with the pinned toolchain. No lockfile, registry configuration, or supply-chain safeguards were changed.

@HAYDEN-OAI
HAYDEN-OAI requested a review from a team as a code owner September 4, 2026 00:58
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T17:21:54.978047Z 4ae4ac3 New commits
🔒 Security Review Completed 2026-09-04T17:21:49.695276Z 4ae4ac3 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@openai-sdks

openai-sdks Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 10.601s for Node SDK PR #2591.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 180ms
tests/chat-completions-create.test.ts ✅ Passed 259ms
tests/chat-completions-stream.test.ts ✅ Passed 236ms
tests/files-content-binary.test.ts ✅ Passed 215ms
tests/files-create-multipart.test.ts ✅ Passed 152ms
tests/files-list-pagination.test.ts ✅ Passed 142ms
tests/initialize-config.test.ts ✅ Passed 174ms
tests/instance-isolation.test.ts ✅ Passed 120ms
tests/models-list.test.ts ✅ Passed 151ms
tests/responses-background-lifecycle.test.ts ✅ Passed 233ms
tests/responses-body-method-errors.test.ts ✅ Passed 316ms
tests/responses-cancel-timeout.test.ts ✅ Passed 209ms
tests/responses-cancel.test.ts ✅ Passed 198ms
tests/responses-compact-retries.test.ts ✅ Passed 258ms
tests/responses-compact.test.ts ✅ Passed 200ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 139ms
tests/responses-create-advanced.test.ts ✅ Passed 157ms
tests/responses-create-disconnect.test.ts ✅ Passed 1.207s
tests/responses-create-errors.test.ts ✅ Passed 198ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 206ms
tests/responses-create-retries.test.ts ✅ Passed 307ms
tests/responses-create-stream-failures.test.ts ✅ Passed 199ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 2.156s
tests/responses-create-stream-wire.test.ts ✅ Passed 2.615s
tests/responses-create-stream.test.ts ✅ Passed 85ms
tests/responses-create-terminal-states.test.ts ✅ Passed 238ms
tests/responses-create-timeout.test.ts ✅ Passed 241ms
tests/responses-create.test.ts ✅ Passed 191ms
tests/responses-delete.test.ts ✅ Passed 266ms
tests/responses-input-items-errors.test.ts ✅ Passed 249ms
tests/responses-input-items-list.test.ts ✅ Passed 183ms
tests/responses-input-items-options.test.ts ✅ Passed 112ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 229ms
tests/responses-input-tokens-count.test.ts ✅ Passed 221ms
tests/responses-malformed-inputs.test.ts ✅ Passed 2.202s
tests/responses-not-found-errors.test.ts ✅ Passed 251ms
tests/responses-parse.test.ts ✅ Passed 166ms
tests/responses-retrieve-retries.test.ts ✅ Passed 231ms
tests/responses-retrieve.test.ts ✅ Passed 222ms
tests/responses-stored-method-errors.test.ts ✅ Passed 580ms
tests/retry-behavior.test.ts ✅ Passed 2.981s
tests/sdk-error-shape.test.ts ✅ Passed 281ms

View OkTest run #33899977811

SDK merge (96844e40671b) · head (4ae4ac34612f) · base (dde19c5c7228) · OkTest (2b1bdfd25e98)

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

32 mixed files remain; 0 existing customizations changed.

Compared dde19c5c72284ae4ac34612f. Generated baselines verified.

32 existing customizations unchanged
  • api.md
  • scripts/castiron/README.md
  • scripts/castiron/custom_code_report.py
  • scripts/castiron/test_custom_code_report.py
  • src/client.ts
  • src/resources/audio/transcriptions.ts
  • src/resources/audio/translations.ts
  • src/resources/beta/assistants.ts
  • src/resources/beta/beta.ts
  • src/resources/beta/index.ts
  • src/resources/beta/responses/internal-base.ts
  • src/resources/beta/responses/responses.ts
  • src/resources/beta/threads/index.ts
  • src/resources/beta/threads/runs/index.ts
  • src/resources/beta/threads/runs/runs.ts
  • src/resources/beta/threads/threads.ts
  • src/resources/chat/completions/completions.ts
  • src/resources/chat/completions/index.ts
  • src/resources/conversations/index.ts
  • src/resources/embeddings.ts
  • src/resources/files.ts
  • src/resources/fine-tuning/checkpoints/permissions.ts
  • src/resources/images.ts
  • src/resources/responses/internal-base.ts
  • src/resources/responses/responses.ts
  • src/resources/skills/skills.ts
  • src/resources/skills/versions/versions.ts
  • src/resources/vector-stores/file-batches.ts
  • src/resources/vector-stores/files.ts
  • src/resources/webhooks/index.ts
  • src/resources/webhooks/webhooks.ts
  • tests/lib/data-residency.test.ts

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 33900061440 --repo openai/openai-node \
  --name castiron-custom-code-33900061440-1 --dir /tmp/castiron-custom-code-33900061440-1
git apply --stat /tmp/castiron-custom-code-33900061440-1/custom-code.patch
cat /tmp/castiron-custom-code-33900061440-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin dde19c5c72280516fdfd4e0f4fe987fd1a3eced1 4ae4ac34612f2b0813d86de029726c0c86bcdff4
python3 scripts/castiron/custom_code_report.py report \
  --base dde19c5c72280516fdfd4e0f4fe987fd1a3eced1 \
  --head 4ae4ac34612f2b0813d86de029726c0c86bcdff4 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-4ae4ac34612f
cat /tmp/castiron-custom-code-4ae4ac34612f/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

sylvesterkaczmarek pushed a commit to sylvesterkaczmarek/openai-node that referenced this pull request Sep 4, 2026
## Summary

Correct three tokens in the handwritten Chat Streaming guide:

- The optional `stream` flag accepted by `chat.completions.stream()` is
`true`, not `false`.
- The helper returns `ChatCompletionStream`, not
`ChatCompletionStreamingRunner` (which is used for streaming tool
runners).

The current documented `stream: false` call fails type checking with
TS2322. The public helper always enables streaming. No SDK
implementation, generated files, public declarations, dependencies, or
lockfiles change. `docs/helpers.md` is absent from the pinned Castiron
generated snapshot. I checked open PRs; openai#2591 edits an unrelated
`afterCompletion` section of the same guide and does not address this
issue.

## Validation

- Compiler reproduction through the public `OpenAI` export: `stream:
false` is rejected; omitted `stream` and `stream: true` are accepted.
- Public `.stream()` smoke test with synthetic SSE: exact
`ChatCompletionStream` prototype, not a `ChatCompletionStreamingRunner`,
serialized `stream: true`, successful completion, no live API calls.
- `./scripts/test tests/lib/ChatCompletionStream.test.ts`: **40 passed**
on Node 22.22.2 and **40 passed** on Node 24.19.0.
- Pinned Oxfmt 0.62.0 check and `git diff --check` passed.
- Local focused tests used available cached Vitest 4.1.10; the
repository pins 4.1.11. A fresh frozen install remains blocked by
missing publication-time metadata for `qs@6.16.0` in the configured
registry; no installation safeguards or configuration were changed.

## Adversarial self-review

Reviewed public types, actual return identity, optional/explicit stream
behavior, compatibility, and security implications. Independent review
found no actionable issues. This is a documentation-only correction;
compiler/runtime verification and the existing stream suite are
proportionate, without adding a Markdown-parsing test harness for three
tokens.

@markstuart-oai markstuart-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the cancellation boundary at all three tool-runner exit paths and the callback-error precedence. The shared helper keeps the check localized, and the focused streaming/non-streaming matrix covers final responses, forced tools, and completion limits.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi, the new post-callback abort path throws a fresh APIUserAbortError() and drops the abort signal's reason. An external controller.abort(reason) therefore loses the cause here even though other client cancellation paths preserve it. Could this construct the abort error from this.controller.signal.reason and add a cause assertion?

Copy link
Copy Markdown
Contributor Author

Addressed the post-callback cause feedback in 718da1c. The new checkpoint now attaches the runner signal's reason by identity to APIUserAbortError.cause. The extended matrix failed 24 cause assertions before the fix; 108 related tests and 276 built CJS/ESM checks pass afterward. This deliberately covers only the newly introduced afterCompletion boundary; #2607 remains responsible for external-signal forwarding and the five preexisting checkpoints, so the changes compose without duplication.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 718da1c604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/AbstractChatCompletionRunner.ts Outdated
Comment thread src/lib/AbstractChatCompletionRunner.ts Outdated
@HAYDEN-OAI
HAYDEN-OAI added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 27f5c6a Sep 4, 2026
49 checks passed
@HAYDEN-OAI
HAYDEN-OAI deleted the codex/runner-after-completion-abort branch September 4, 2026 20:26
@openai-sdks openai-sdks Bot mentioned this pull request Sep 4, 2026
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.

3 participants