Skip to content

feat(sdk): make the chat.agent system prompt cacheable#3952

Merged
ericallam merged 3 commits into
mainfrom
feat/chat-system-prompt-caching
Jun 15, 2026
Merged

feat(sdk): make the chat.agent system prompt cacheable#3952
ericallam merged 3 commits into
mainfrom
feat/chat-system-prompt-caching

Conversation

@ericallam

Copy link
Copy Markdown
Member

Summary

chat.agent's system prompt (the chat.prompt text plus any skills preamble) could not carry a provider cache breakpoint, so the largest and most stable part of the prompt re-paid full input price on every turn. chat.toStreamTextOptions() now emits the system prompt as a structured message carrying providerOptions when you opt in, so a provider can cache the system block. Without an option, system stays a plain string, so existing behavior is unchanged.

API

Three ways to opt in (most specific wins, no deep merge):

// Anthropic sugar
chat.toStreamTextOptions({ cacheControl: { type: "ephemeral" } });
// provider-agnostic (also covers Amazon Bedrock's cachePoint)
chat.toStreamTextOptions({ systemProviderOptions: { anthropic: { cacheControl: { type: "ephemeral" } } } });
// at the definition site
chat.prompt.set(SYSTEM_PROMPT, { providerOptions: { anthropic: { cacheControl: { type: "ephemeral" } } } });

The cacheControl shorthand is Anthropic-only; systemProviderOptions is the general form. Pairs with a prepareMessages cache breakpoint to cache the conversation prefix too.

Docs guide: #3951

chat.toStreamTextOptions() can now emit the system prompt as a structured message carrying providerOptions, so a provider can cache the system block. Opt in three ways (most specific wins): cacheControl sugar or systemProviderOptions on toStreamTextOptions(), or providerOptions on chat.prompt.set(). Without an option, system stays a plain string.
@changeset-bot

changeset-bot Bot commented Jun 15, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 981d9bd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 25 packages
Name Type
@trigger.dev/sdk Patch
@trigger.dev/python Patch
@internal/sdk-compat-tests Patch
@trigger.dev/build Patch
@trigger.dev/core Patch
@trigger.dev/plugins Patch
@trigger.dev/react-hooks Patch
@trigger.dev/redis-worker Patch
@trigger.dev/rsc Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch
@trigger.dev/rbac Patch
trigger.dev Patch
@internal/cache Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/tsql Patch
@internal/zod-worker Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e9b146a7-262b-4378-9296-c9cb29db7e2c

📥 Commits

Reviewing files that changed from the base of the PR and between 0d5a1d8 and 981d9bd.

📒 Files selected for processing (2)
  • packages/trigger-sdk/src/v3/ai.ts
  • packages/trigger-sdk/test/promptCaching.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/trigger-sdk/test/promptCaching.test.ts
  • packages/trigger-sdk/src/v3/ai.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (33)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (3, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (4, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (10, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (9, 10)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (11, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 10)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (7, 10)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: internal / 🧪 Unit Tests: Internal (12, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (9, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (7, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (10, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (2, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 10)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (6, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (3, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (1, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (1, 10)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (8, 12)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (4, 12)
  • GitHub Check: internal / 🧪 Unit Tests: Internal (5, 12)
  • GitHub Check: packages / 🧪 Unit Tests: Packages (3, 3)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: packages / 🧪 Unit Tests: Packages (2, 3)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: packages / 🧪 Unit Tests: Packages (1, 3)
  • GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp
  • GitHub Check: Build and publish previews

Walkthrough

This patch introduces opt-in Anthropic prompt caching for the chat agent's system prompt in @trigger.dev/sdk. A new SetChatPromptOptions type allows chat.prompt.set() to accept a providerOptions argument, which is stored in task locals under a new chatPromptProviderOptionsKey. ToStreamTextOptionsOptions gains two new fields—systemProviderOptions and cacheControl (typed by the new SystemCacheControl)—that toStreamTextOptions() uses to resolve provider options with explicit precedence: call-site systemProviderOptions overrides cacheControl sugar, which overrides options stored via chat.prompt.set(). When resolved options are present, the method emits a structured system message object with providerOptions instead of a plain string. A new test file validates all five code paths, and a patch changeset documents the behavior.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description provides a comprehensive summary, clear API documentation with three opt-in methods, and context about the feature's purpose, but does not follow the repository's template structure. Consider restructuring the description to match the repository template: include 'Closes #', a completed checklist, 'Testing' section, and 'Changelog' section for consistency.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(sdk): make the chat.agent system prompt cacheable' clearly and concisely describes the main feature addition: enabling caching for the chat.agent system prompt.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chat-system-prompt-caching

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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 and usage tips.

…roviderOptions

ai re-exports ProviderMetadata (same Record<string, Record<string, JSONValue>> shape) but not ProviderOptions, so importing the latter failed the SDK build with TS2459. The public option names are unchanged.
coderabbitai[bot]

This comment was marked as resolved.

@pkg-pr-new

pkg-pr-new Bot commented Jun 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@trigger.dev/build

npm i https://pkg.pr.new/@trigger.dev/build@981d9bd

trigger.dev

npm i https://pkg.pr.new/trigger.dev@981d9bd

@trigger.dev/core

npm i https://pkg.pr.new/@trigger.dev/core@981d9bd

@trigger.dev/python

npm i https://pkg.pr.new/@trigger.dev/python@981d9bd

@trigger.dev/react-hooks

npm i https://pkg.pr.new/@trigger.dev/react-hooks@981d9bd

@trigger.dev/redis-worker

npm i https://pkg.pr.new/@trigger.dev/redis-worker@981d9bd

@trigger.dev/rsc

npm i https://pkg.pr.new/@trigger.dev/rsc@981d9bd

@trigger.dev/schema-to-json

npm i https://pkg.pr.new/@trigger.dev/schema-to-json@981d9bd

@trigger.dev/sdk

npm i https://pkg.pr.new/@trigger.dev/sdk@981d9bd

commit: 981d9bd

A later chat.prompt.set() with no options left the previous prompt's providerOptions in locals, so toStreamTextOptions() could still cache a prompt that did not opt in. Always overwrite the slot. Also replaces fixed sleeps in the prompt-caching test with a bounded condition wait.
@ericallam ericallam marked this pull request as ready for review June 15, 2026 13:29

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread packages/trigger-sdk/src/v3/ai.ts
@ericallam ericallam merged commit 3b91999 into main Jun 15, 2026
64 checks passed
@ericallam ericallam deleted the feat/chat-system-prompt-caching branch June 15, 2026 14:54
ericallam added a commit that referenced this pull request Jun 15, 2026
…locks (#3954)

## Summary

The script that generates the changeset release PR description was
silently dropping some changelog entries and stripping code examples. In
[#3932](#3932), entry
[#3937](#3937) was
missing entirely from the Improvements list and
[#3952](#3952 code
block was gone, even though both were present in the raw changeset
output.

## Root cause

`parsePrBody` parsed the raw changeset body line by line:

- The dependency-bump filter matched any entry whose text *began* with a
backticked package name, so a real changelog entry like ``
`@trigger.dev/sdk` now bundles... `` got thrown out along with the
genuine version-bump lines.
- Only the first line of each bullet was kept, so fenced code blocks,
sub-bullets, and continuation paragraphs were discarded.

## Fix

Group each top-level bullet with its indented continuation (code blocks,
sub-bullets, paragraphs), dedent it, and re-emit it intact. The
dependency filter is now anchored so it only matches lines that are
*entirely* a package bump, leaving real entries that merely start with a
package name.

Verified by replaying #3932's raw body through the script: #3937 returns
to the list, #3952's code block is preserved, and #3936's sub-bullets
nest correctly under their parent.
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