-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(sdk): add AI SDK 7 support #3833
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
Open
ericallam
wants to merge
2
commits into
main
Choose a base branch
from
feat/ai-sdk-7-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@trigger.dev/sdk": patch | ||
| --- | ||
|
|
||
| Adds AI SDK 7 support. The `ai` peer range now includes v7, and the `chat.agent` / chat surfaces work against v7's ESM-only build. On v7, install `@ai-sdk/otel` alongside `ai` and the SDK registers it for you so `experimental_telemetry` spans keep flowing into your run traces (v7 stopped emitting them from `ai` core). v5 and v6 keep working unchanged. | ||
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| // Typechecks core's src against AI SDK 7 (the `ai-v7` aliased devDep). Core's | ||
| // `ai` surface is small (ChatSnapshotV1's UIMessage constraint, ToolTaskParameters' | ||
| // Schema), but it ships in the public type surface, so it gets the same v7 gate | ||
| // as the SDK. See packages/trigger-sdk/tsconfig.ai-v7.json for the `paths` | ||
| // file-direct rationale. | ||
| "extends": "./tsconfig.src.json", | ||
| "compilerOptions": { | ||
| "baseUrl": ".", | ||
| "paths": { | ||
| "ai": ["./node_modules/ai-v7/dist/index.d.ts"] | ||
| } | ||
| } | ||
| } |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // CJS variant of ./ai-runtime.ts — tshy swaps this in for the CommonJS build. | ||
| // `require("ai")` of an ESM-only package is supported on Node >=20.19 / >=22.12. | ||
|
|
||
| // @ts-ignore | ||
| const ai = require("ai"); | ||
|
|
||
| // @ts-ignore | ||
| module.exports.convertToModelMessages = ai.convertToModelMessages; | ||
| // @ts-ignore | ||
| module.exports.dynamicTool = ai.dynamicTool; | ||
| // @ts-ignore | ||
| module.exports.generateId = ai.generateId; | ||
| // @ts-ignore | ||
| module.exports.getToolName = ai.getToolName; | ||
| // @ts-ignore | ||
| module.exports.isToolUIPart = ai.isToolUIPart; | ||
| // @ts-ignore | ||
| module.exports.jsonSchema = ai.jsonSchema; | ||
| // @ts-ignore | ||
| module.exports.readUIMessageStream = ai.readUIMessageStream; | ||
| // @ts-ignore | ||
| module.exports.stepCountIs = ai.stepCountIs; | ||
| // @ts-ignore | ||
| module.exports.tool = ai.tool; | ||
| // @ts-ignore | ||
| module.exports.zodSchema = ai.zodSchema; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Runtime VALUE imports from `ai`, isolated behind a paired ESM/CJS shim. | ||
| // | ||
| // `ai@7` is ESM-only (no `require` export). Under NodeNext + TS < 5.8 a value | ||
| // import of an ESM-only package emitted to a CJS file raises TS1479, which | ||
| // would break the SDK's CommonJS build. tshy maps `ai-runtime-cjs.cts` -> the | ||
| // CJS build and this `.ts` -> the ESM build, so each dialect gets the right | ||
| // form. `require(esm)` is stable on Node >=20.19 / >=22.12 (both our targets), | ||
| // so the CJS variant works at runtime. Mirrors `imports/uncrypto{,-cjs.cts}`. | ||
| // | ||
| // VALUES only — type-only imports from `ai` erase and don't trip TS1479, so | ||
| // they stay as direct `import type { … } from "ai"` at their use sites. | ||
|
|
||
| // @ts-ignore | ||
| import { | ||
| convertToModelMessages, | ||
| dynamicTool, | ||
| generateId, | ||
| getToolName, | ||
| isToolUIPart, | ||
| jsonSchema, | ||
| readUIMessageStream, | ||
| stepCountIs, | ||
| tool, | ||
| zodSchema, | ||
| } from "ai"; | ||
|
|
||
| // @ts-ignore | ||
| export { | ||
| convertToModelMessages, | ||
| dynamicTool, | ||
| generateId, | ||
| getToolName, | ||
| isToolUIPart, | ||
| jsonSchema, | ||
| readUIMessageStream, | ||
| stepCountIs, | ||
| tool, | ||
| zodSchema, | ||
| }; |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| /** | ||
| * Auto-register `@ai-sdk/otel` so AI SDK 7 emits OpenTelemetry spans into the | ||
| * Trigger.dev run trace with no customer setup. | ||
| * | ||
| * AI SDK 6 emitted spans from `ai` core, so `experimental_telemetry` (set by | ||
| * `chat.toStreamTextOptions({ telemetry })`) was enough. v7 moved span emission | ||
| * into the separate `@ai-sdk/otel` adapter, so on v7 `experimental_telemetry` | ||
| * alone produces nothing until an integration is registered. We register it once | ||
| * per worker process at chat.agent run boot. `@ai-sdk/otel` writes to the global | ||
| * OpenTelemetry tracer, which is the same provider the Trigger worker installs | ||
| * (the `@opentelemetry/api` global is a `globalThis` singleton keyed by major | ||
| * version, so the separate copies still share it), so spans land in the trace. | ||
| * | ||
| * Fully guarded and best-effort — telemetry must never break a run: | ||
| * - `registerTelemetry` only exists in v7 `ai` (no-op on v5/v6). | ||
| * - `@ai-sdk/otel` is an OPTIONAL peer. The specifier is computed so the task | ||
| * bundler doesn't hard-require it (v5/v6 users never install it). | ||
| * - We detect an already-registered `@ai-sdk/otel` integration and skip, so a | ||
| * customer (or a library they import) that registers it themselves doesn't | ||
| * get duplicate spans. `registerTelemetry` is append-only, so without this | ||
| * guard a second integration would double every span. | ||
| * - To disable our auto-register entirely (e.g. you register `@ai-sdk/otel` | ||
| * yourself after this boot, or via a custom integration our detection can't | ||
| * see), set the env var `TRIGGER_AI_SDK_OTEL_AUTOREGISTER=0`. | ||
| */ | ||
| let registration: Promise<void> | null = null; | ||
|
|
||
| /** Registers the AI SDK OTel integration once per process. Safe to call on every run. */ | ||
| export function ensureAiSdkTelemetry(): Promise<void> { | ||
| if (!registration) { | ||
| registration = register(); | ||
| } | ||
| return registration; | ||
| } | ||
|
|
||
| async function register(): Promise<void> { | ||
| try { | ||
| if (isAutoRegisterDisabled()) { | ||
| return; // opted out via TRIGGER_AI_SDK_OTEL_AUTOREGISTER | ||
| } | ||
| const aiMod: any = await import("ai"); | ||
| if (typeof aiMod.registerTelemetry !== "function") { | ||
| return; // v5 / v6 — `ai` core emits spans itself, nothing to wire. | ||
| } | ||
| // Computed specifier keeps the optional peer out of static bundler | ||
| // resolution; resolves at runtime only when the customer installed it. | ||
| const otelSpecifier = ["@ai-sdk", "otel"].join("/"); | ||
| const otelMod: any = await import(otelSpecifier).catch(() => null); | ||
| if (typeof otelMod?.OpenTelemetry !== "function") { | ||
| return; // optional peer not installed | ||
| } | ||
| if (hasAiSdkOtelIntegration(otelMod.OpenTelemetry)) { | ||
| return; // already registered by the customer or a library they import | ||
| } | ||
| aiMod.registerTelemetry(new otelMod.OpenTelemetry()); | ||
| } catch { | ||
| // never throw from telemetry setup | ||
| } | ||
| } | ||
|
|
||
| function isAutoRegisterDisabled(): boolean { | ||
| const value = process.env.TRIGGER_AI_SDK_OTEL_AUTOREGISTER?.toLowerCase(); | ||
| return value === "0" || value === "false"; | ||
| } | ||
|
|
||
| /** | ||
| * True if an `@ai-sdk/otel` integration is already in v7's global telemetry | ||
| * registry (`globalThis.AI_SDK_TELEMETRY_INTEGRATIONS`, a documented public | ||
| * global that `registerTelemetry` appends to). `instanceof` matches a same-copy | ||
| * registration; the constructor-name fallback catches a separate copy of | ||
| * `@ai-sdk/otel`. | ||
| */ | ||
| function hasAiSdkOtelIntegration(OpenTelemetry: any): boolean { | ||
| const integrations = (globalThis as any).AI_SDK_TELEMETRY_INTEGRATIONS; | ||
| if (!Array.isArray(integrations)) { | ||
| return false; | ||
| } | ||
| return integrations.some( | ||
| (integration: any) => | ||
| (typeof OpenTelemetry === "function" && integration instanceof OpenTelemetry) || | ||
| integration?.constructor?.name === "OpenTelemetry" | ||
| ); | ||
|
ericallam marked this conversation as resolved.
|
||
| } | ||
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.