Skip to content

fix: make every LLM operation cancellable - #1764

Open
kang-heewon wants to merge 1 commit into
trunkfrom
fix/1711-cancellable-llm-operations
Open

fix: make every LLM operation cancellable#1764
kang-heewon wants to merge 1 commit into
trunkfrom
fix/1711-cancellable-llm-operations

Conversation

@kang-heewon

Copy link
Copy Markdown
Member

Outcome

All public LLM generation, streaming, structured generation, tool, and embedding operations now accept a shared optional AbortSignal and forward it through LlmService, model implementations, and the OpenAI transport.

Pre-abort and mid-flight cancellation produce stable Croco Problems. Cancelled work emits no completion or usage-success event, including the race after an OpenAI stream yields its final usage chunk. The @Llm decorator forwards per-call cancellation through its optional second argument.

Fixes #1711

Reviewer context

Completion-event publication is the terminal success commit point: cancellation is checked synchronously immediately before publication, and a later abort cannot retract an event already being delivered.

The API documentation generator found existing tracked drift in other public surfaces. Those deterministic generated files are included because docs:api:check compares the complete generated tree and passes only with the full synchronized output.

Verification

  • pnpm --filter @croco/llm-core test — 151 passed
  • pnpm --filter @croco/llm-openai test — 36 passed, 1 live test skipped
  • affected package lint, typecheck, and build commands — passed
  • pnpm public-api:check — 115 package snapshots match
  • pnpm problem-registry:check — 577/577 codes match
  • pnpm docs:api:check — generated API docs match
  • pnpm changeset-required:check -- --base origin/trunk --head HEAD — passed
  • pnpm check — passed (24/25; one not applicable)
  • pre-push full test — 234/234 tasks passed
  • pre-push full typecheck — 233/233 tasks passed

Review gates

  • Correctness and regression — PASS. Parameterized coverage proves all six service operations reject pre-abort; OpenAI coverage proves all five non-stream operations forward active aborts; stream coverage proves mid-flight cancellation, completion-event suppression, and no usage telemetry after final-chunk cancellation. Deferred event-bus tests define the atomic success boundary.
  • API, security, compatibility, and release — PASS. Cancellation fields and decorator invocation options are additive and optional; stable Problem exports, public API snapshots, Problem registry, generated docs, and changesets for @croco/llm-core, @croco/llm-openai, and @croco/problems-core are synchronized. Dependencies and lockfile are unchanged.
  • Maintainability and minimality — PASS. The implementation reuses existing request parameter, Problem, model, transport, telemetry, and event boundaries without changing retry or billing policy. Generated churn is limited to the deterministic full-tree synchronization required by the passing docs gate.
  • Independent adversarial review — PASS after fixes. Completion-publication races, final-stream-usage telemetry, the decorator entrypoint, and shared-type documentation findings were corrected; re-review found no remaining actionable findings.

Residual risk

Outbound cancellation remains transport-dependent by contract; the OpenAI transport forwards the caller signal directly. No model retry or billing policy changed.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 110 files, which is 10 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6f77dac4-7bec-4c8b-9cc7-3c1e62d93c8c

📥 Commits

Reviewing files that changed from the base of the PR and between cfe0d14 and 9adc41c.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (110)
  • .changeset/cancellable-llm-operations.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/diagnostics-core/src/classes/InvalidDiagnosticsTimeoutProblem.md
  • packages/docs/src/content/docs/api/diagnostics-core/src/variables/MAX_DIAGNOSTICS_TIMEOUT_MS.md
  • packages/docs/src/content/docs/api/events-inmemory/src/classes/InvalidEventBusConfigurationProblem.md
  • packages/docs/src/content/docs/api/events-inmemory/src/type-aliases/InMemoryEventBusOptions.md
  • packages/docs/src/content/docs/api/events-inmemory/src/variables/MAX_EVENT_BUS_CONCURRENCY.md
  • packages/docs/src/content/docs/api/events-inmemory/src/variables/MAX_EVENT_BUS_TIMEOUT_MS.md
  • packages/docs/src/content/docs/api/framework-context/src/interfaces/RuntimeContext.md
  • packages/docs/src/content/docs/api/frontend-cloudflare/src/type-aliases/SsrFailureCode.md
  • packages/docs/src/content/docs/api/frontend-cloudflare/src/type-aliases/SsrFailureReport.md
  • packages/docs/src/content/docs/api/frontend-cloudflare/src/type-aliases/SsrHandlerOptions.md
  • packages/docs/src/content/docs/api/frontend-cloudflare/src/variables/SSR_FAILURE_CODES.md
  • packages/docs/src/content/docs/api/health-core/src/classes/InvalidHealthCheckTimeoutProblem.md
  • packages/docs/src/content/docs/api/health-core/src/variables/MAX_HEALTH_CHECK_TIMEOUT_MS.md
  • packages/docs/src/content/docs/api/llm-core/src/classes/InMemoryLlmModel.md
  • packages/docs/src/content/docs/api/llm-core/src/classes/LlmModel.md
  • packages/docs/src/content/docs/api/llm-core/src/classes/LlmOperationAbortedProblem.md
  • packages/docs/src/content/docs/api/llm-core/src/classes/LlmService.md
  • packages/docs/src/content/docs/api/llm-core/src/functions/Llm.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/CancellableRequestOptions.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/EmbedManyParams.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/EmbedParams.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/GenerateParams.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/LlmInvocationOptions.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/StreamParams.md
  • packages/docs/src/content/docs/api/llm-core/src/type-aliases/ToolCallParams.md
  • packages/docs/src/content/docs/api/llm-openai/src/classes/OpenAiLlmModel.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/api/protocols-core/src/interfaces/ParamIR.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/BoundDesktopContract.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/BoundDesktopGrant.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopAppContractMetadata.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopContractDefinition.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopContractMemberMetadata.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopContractMetadata.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopContractOptions.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopDirectoryGrantOptions.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopFileGrantOptions.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopGrantDefinition.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopGrantMetadata.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopGrantReference.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/InferDesktopContractCommands.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/InferDesktopContractEvents.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/InferDesktopContractGrants.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/KeyedDesktopGrant.md
  • packages/docs/src/content/docs/api/protocols-desktop/src/variables/desktop.md
  • packages/docs/src/content/docs/api/protocols-graphql/src/classes/GraphQLRolesGuard.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/DistributedRateLimitStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/FixedWindowInMemoryStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/FixedWindowStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/RateLimitPruneIntervalProblem.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/RateLimitStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/SlidingWindowInMemoryStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/SlidingWindowStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/TokenBucketInMemoryStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/classes/TokenBucketStore.md
  • packages/docs/src/content/docs/api/ratelimit-core/src/type-aliases/InMemoryRateLimitStoreOptions.md
  • packages/docs/src/content/docs/api/ratelimit-upstash/src/classes/UpstashFixedWindowStore.md
  • packages/docs/src/content/docs/api/ratelimit-upstash/src/classes/UpstashSlidingWindowStore.md
  • packages/docs/src/content/docs/api/ratelimit-upstash/src/classes/UpstashTokenBucketStore.md
  • packages/docs/src/content/docs/api/repository-core/src/classes/BatchLoadDuplicateResultKeyProblem.md
  • packages/docs/src/content/docs/api/repository-core/src/classes/BatchLoadResultIdentityMismatchProblem.md
  • packages/docs/src/content/docs/api/repository-core/src/classes/BatchLoadUnexpectedResultKeyProblem.md
  • packages/docs/src/content/docs/api/repository-core/src/classes/BatchLoadUnkeyedResultProblem.md
  • packages/docs/src/content/docs/api/repository-core/src/interfaces/ReadRepository.md
  • packages/docs/src/content/docs/api/repository-core/src/interfaces/Repository.md
  • packages/docs/src/content/docs/api/repository-core/src/type-aliases/KeyedRepositoryResult.md
  • packages/docs/src/content/docs/api/tasks-core/src/classes/TaskRunner.md
  • packages/docs/src/content/docs/api/tasks-core/src/interfaces/TaskRunnerRuntime.md
  • packages/docs/src/content/docs/api/tasks-core/src/type-aliases/RegisteredTask.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestClock.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestEnvironment.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestIdSource.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestKernel.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestKernelLeakProblem.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestKernelOutboundCallProblem.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestRandomSource.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestRuntime.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestRuntimeConfigurationProblem.md
  • packages/docs/src/content/docs/api/testing/src/classes/TestRuntimeDrainProblem.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/BillingProviderConformanceCapabilityEvidence.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/BillingProviderConformanceManifest.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/BillingProviderConformanceOptions.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/BillingProviderConformanceSuite.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelBootstrapContext.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelLeak.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/TestReplayMetadata.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/TestRuntimeOptions.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/TestScheduledWork.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/UsageBillingConformanceFixtures.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/UsageBillingFailureScenario.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/UsageBillingGatewayConformanceOptions.md
  • packages/docs/src/content/docs/api/testing/src/type-aliases/UsageBillingLiveSmokeGate.md
  • packages/docs/src/content/docs/api/transports-graphql/src/type-aliases/SchemaCompileOptions.md
  • packages/docs/src/content/docs/api/tx-drizzle/src/classes/AbstractDrizzleRepository.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/llm-core/src/index.ts
  • packages/llm-core/src/libs/InMemoryLlmModel.ts
  • packages/llm-core/src/libs/LlmService.ts
  • packages/llm-core/src/libs/decorators/Llm.ts
  • packages/llm-core/src/libs/problems/LlmProblems.ts
  • packages/llm-core/src/libs/types.ts
  • packages/llm-core/src/tests/LlmService.spec.ts
  • packages/llm-core/src/tests/decorators/Llm.spec.ts
  • packages/llm-core/src/tests/problems/LlmProblems.spec.ts
  • packages/llm-openai/src/libs/OpenAiLlmModel.ts
  • packages/llm-openai/src/tests/OpenAiLlmModel.spec.ts
  • public-api-surface.snapshot.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

📊 Benchmark Results

✅ All benchmarks passed

Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 45.2μs 30.0ms 8.2μs +452.6% -
CrocoApp lambdaHandler (10 controllers) 2.2ms 50.0ms 258.4μs +759.1% -
Lambda cold-start simulation 2.2ms 80.0ms 418.1μs +436.8% -
Lambda cold-start with headers 1.5ms 80.0ms 369.7μs +311.9% -
Lambda cold-start with binary body 1.5ms 80.0ms 339.1μs +344.9% -
Lambda cold-start with query params 1.5ms 80.0ms 301.3μs +393.2% -
Lambda cold-start with authorizer context 1.5ms 80.0ms 299.8μs +398.7% -
Lambda cold-start realistic scenario 1.5ms 80.0ms 299.2μs +389.7% -
EventBusConfig.start (10 handlers) 1.7μs 10.0ms 1.4μs +18.2% -
EventPublisher.publishNow single event 1.9μs 2.0ms 1.7μs +12.5% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.1μs +0.0% -
Container.get singleton (cold) 86.1μs 5.0ms 70.3μs +22.5% -
Container.register × 50 components 3.4ms 10.0ms 3.2ms +4.0% -
Container.validate (50 components) 3.8ms 20.0ms 3.4ms +13.3% -
Container.get singleton (warm) 1.6μs 500.0μs 1.6μs +0.6% -
TelemetryRuntime.init (lambda preset) 2.3μs 200.0ms 1.1ms -99.8% -
lambdaPreset config creation 1.5μs 2.0ms 1.4μs +6.3% -

Updated: 2026-08-05T17:16:23.282Z · Commit: 3c24f59

@kang-heewon

kang-heewon commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

CI evidence note:

  • Optional PR Review Companion fails because verification-manifest.spec.ts cannot resolve @croco/tenant-core/tenant-model from create-croco-app. The identical diagnostic reproduced from a clean detached worktree at exact base cfe0d148f299231aeb4e388222e813e3eb979f1a with pnpm install --frozen-lockfile --ignore-scripts && pnpm check (23/25; only verification contract tests failed; one N/A). This PR changes neither package, and its built current-head checkout passes pnpm check 24/25 with one N/A.

  • Required validate run 31028464216 failed after all six spine-blocking generated-app smoke cases passed. Its matrix reports filteredRun: true and six passing cases, but ci-reports/generated-apps/spine-blocking-journeys was not generated. The verification manifest requires that directory, while writeCanonicalGeneratedSmokeJourneyBundle emits it only for canonical --tier spine-blocking selection (selectedTier === "spine-blocking" with no requested case names). This change-scoped run selected cases by name, so the required artifact could not be produced. Exact-base validate run 31027104975 also failed independently (release metadata), confirming current trunk CI is red, although that full-tier run did emit its journey bundle.

PR #1764 changes only the LLM cancellation surface and generated contract/docs outputs; it does not change the generated-app smoke runner, verification manifest, create-croco-app, tenant-core, or CI workflow. Branch protection requires validate and docs-sync-check, so the PR cannot be merged without fixing this independent CI contract or bypassing protection; no override was attempted.

@kang-heewon
kang-heewon force-pushed the fix/1711-cancellable-llm-operations branch from ebfe595 to 9adc41c Compare August 5, 2026 17:06
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.

[llm-core/llm-openai] Propagate AbortSignal through non-streaming model operations

1 participant