-
-
Notifications
You must be signed in to change notification settings - Fork 636
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
Update realtime docs for streaming and a couple tweaks to the SDK #1486
Conversation
🦋 Changeset detectedLatest commit: 8b68a82 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
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 |
WalkthroughThe changes in this pull request primarily focus on enhancing the functionality of React hooks and related documentation within the Trigger.dev SDK. The modifications allow hooks to directly accept Changes
Suggested reviewers
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
packages/react-hooks/src/hooks/useRun.ts(node:30026) ESLintIgnoreWarning: The ".eslintignore" file is no longer supported. Switch to using the "ignores" property in "eslint.config.js": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files Oops! Something went wrong! :( ESLint: 9.15.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Outside diff range and nitpick comments (20)
.changeset/khaki-ants-yawn.md (1)
6-7
: Consider enhancing the changeset descriptionWhile accurate, the description could be more comprehensive. Consider adding:
- A comma before 'so' for better readability
- Migration guidance for users currently using the Provider
- Examples of the new options usage
-React hooks now all accept accessToken and baseURL options so the use of the Provider is no longer necessary +React hooks now all accept accessToken and baseURL options, so the use of the Provider is no longer necessary. Users can now directly pass these options to individual hooks: + +```jsx +const run = useRealtimeRun(id, { accessToken: "your-token", baseURL: "your-url" }); +``` + +If you're currently using the Provider, you can gradually migrate to the new approach while maintaining backward compatibility.🧰 Tools
🪛 LanguageTool
[uncategorized] ~6-~6: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...l accept accessToken and baseURL options so the use of the Provider is no longer ne...(COMMA_COMPOUND_SENTENCE_2)
packages/react-hooks/src/utils/trigger-swr.ts (2)
11-25
: Add JSDoc comments for authentication and API-related optionsThe type changes look good and align with the goal of eliminating Provider dependency. Consider adding JSDoc comments for the authentication and API-related options to maintain consistency with the existing documentation style.
/** Revalidate the data when the window regains focus. */ revalidateOnFocus?: boolean; - /** Optional access token for authentication */ + /** + * Access token for authentication. When provided, this will override any token + * configured through the Provider. + */ accessToken?: string; - /** Optional base URL for the API endpoints */ + /** + * Base URL for the API endpoints. When provided, this will override any URL + * configured through the Provider. + */ baseURL?: string; - /** Optional additional request configuration */ + /** + * Additional request configuration options that will be passed to all API calls + * made by this hook. + */ requestOptions?: ApiRequestOptions;
11-14
: Consider real-time update strategyThe
refreshInterval
polling option is correctly documented as not recommended in favor of Realtime hooks. However, consider adding a reference to the specific Realtime hooks that should be used instead, making it easier for developers to follow the recommended approach.packages/react-hooks/src/hooks/useRun.ts (1)
Line range hint
7-19
: Enhance JSDoc documentation for better developer experienceConsider improving the documentation by:
- Adding details about available options (refreshInterval, revalidateOnReconnect, revalidateOnFocus, etc.)
- Using TypeScript return type syntax instead of separate @returns for each property
/** * Custom hook to retrieve and manage the state of a run by its ID. * * @template TTask - The type of the task associated with the run. * @param {string} runId - The unique identifier of the run to retrieve. - * @param {CommonTriggerHookOptions} [options] - Optional configuration for the hook's behavior. - * @returns {Object} An object containing the run data, error, loading state, validation state, and error state. - * @returns {RetrieveRunResult<TTask> | undefined} run - The retrieved run data. - * @returns {Error | undefined} error - The error object if an error occurred. - * @returns {boolean} isLoading - Indicates if the run data is currently being loaded. - * @returns {boolean} isValidating - Indicates if the run data is currently being validated. - * @returns {boolean} isError - Indicates if an error occurred during the retrieval of the run data. + * @param {CommonTriggerHookOptions} [options] - Optional configuration: + * - refreshInterval?: number - Interval in milliseconds for data refresh + * - revalidateOnReconnect?: boolean - Whether to revalidate when reconnecting + * - revalidateOnFocus?: boolean - Whether to revalidate when window regains focus + * - accessToken?: string - API access token + * - baseURL?: string - API base URL + * @returns {{ + * run: RetrieveRunResult<TTask> | undefined, + * error: Error | undefined, + * isLoading: boolean, + * isValidating: boolean, + * isError: boolean + * }} */docs/introduction.mdx (1)
15-15
: LGTM, with a style suggestion.The new bullet point effectively introduces the Realtime API feature and includes proper documentation links.
Consider rephrasing to avoid repetitive sentence beginnings. Here's a suggestion:
-- We provide a [Realtime API](/realtime) for monitoring tasks in real-time, along with [React hooks](/frontend/react-hooks#realtime-hooks) for building custom dashboards. ++ Monitor tasks in real-time using our [Realtime API](/realtime), complete with [React hooks](/frontend/react-hooks#realtime-hooks) for building custom dashboards.🧰 Tools
🪛 LanguageTool
[style] ~15-~15: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..., debugging, and managing your tasks. - We provide a Realtime API for...(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
docs/frontend/overview.mdx (3)
11-11
: Consider adding security best practices.While the documentation clearly explains how to create tokens, it would be beneficial to add a note about security best practices, such as:
- Proper storage and transmission of tokens
- Token rotation strategies
- Environment-specific considerations
94-94
: Fix grammatical error in the sentence.Change "which is required" to "which are required" to maintain proper subject-verb agreement.
-You can also specify write scopes, which is required for triggering tasks from your frontend application: +You can also specify write scopes, which are required for triggering tasks from your frontend application:🧰 Tools
🪛 LanguageTool
[uncategorized] ~94-~94: The verb “is” doesn’t seem to fit in this context, “are” is probably more formally correct.
Context: ...ou can also specify write scopes, which is required for triggering tasks from your...(AI_HYDRA_LEO_CPT_IS_ARE)
167-169
: Consider adding a quick example.While linking to the React hooks documentation is good, consider adding a brief inline example to give readers a quick start, such as how to use a token with a basic hook.
docs/runs/metadata.mdx (5)
28-34
: Clarify the difference between metadata.get() and metadata.current()While both methods are shown, it would be helpful to explain the distinction between
metadata.get()
andmetadata.current()
. Consider adding a note explaining when to use each method.
112-112
: Fix typo in metadata update methods description-All metadata update methods (accept for `flush` and `stream`) are synchronous +All metadata update methods (except for `flush` and `stream`) are synchronous🧰 Tools
🪛 LanguageTool
[misspelling] ~112-~112: Did you mean “except”?
Context: ...ur runs.) All metadata update methods (accept forflush
andstream
) are synchrono...(ACCEPT_EXCEPT)
338-357
: Enhance OpenAI streaming example with error handlingThe OpenAI streaming example could be improved by adding error handling and showing how to handle stream interruptions. Consider adding:
- Try-catch block around the API call
- Error handling for stream interruptions
- Cleanup in case of errors
Example enhancement:
export const myTask = task({ id: "my-task", run: async (payload: { prompt: string }) => { + try { const completion = await openai.chat.completions.create({ messages: [{ role: "user", content: payload.prompt }], model: "gpt-3.5-turbo", stream: true, }); const stream = await metadata.stream("openai", completion); let text = ""; for await (const chunk of stream) { logger.log("Received chunk", { chunk }); text += chunk.choices.map((choice) => choice.delta?.content).join(""); } return { text }; + } catch (error) { + logger.error("Error in OpenAI streaming", { error }); + throw error; + } }, });
Line range hint
441-465
: Add performance consideration note for Zod validationThe Zod validation example is good, but consider adding a note about performance implications:
- Mention that validation adds runtime overhead
- Suggest using
.safeParse()
instead of.parse()
in production- Consider recommending validation only in development or at specific checkpoints
🧰 Tools
🪛 LanguageTool
[style] ~56-~56: This phrase is redundant. Consider using “outside”.
Context: ...If you call any of the metadata methods outside of the run function, they will have no eff...(OUTSIDE_OF)
[misspelling] ~112-~112: Did you mean “except”?
Context: ...ur runs.) All metadata update methods (accept forflush
andstream
) are synchrono...(ACCEPT_EXCEPT)
Line range hint
508-508
: Add best practices for handling large metadataConsider adding a section about best practices for handling large metadata:
- How to structure metadata to stay within limits
- Strategies for splitting large data across multiple keys
- When to use external storage instead of metadata
🧰 Tools
🪛 LanguageTool
[style] ~56-~56: This phrase is redundant. Consider using “outside”.
Context: ...If you call any of the metadata methods outside of the run function, they will have no eff...(OUTSIDE_OF)
[misspelling] ~112-~112: Did you mean “except”?
Context: ...ur runs.) All metadata update methods (accept forflush
andstream
) are synchrono...(ACCEPT_EXCEPT)
docs/realtime/streams.mdx (5)
25-27
: Consider consolidating STREAMS type definitionsThe STREAMS type is defined twice with different contents. Consider consolidating these definitions into a single, comprehensive type definition at the beginning of the documentation to avoid confusion.
export type STREAMS = { openai: OpenAI.ChatCompletionChunk; + fetch: string; };
Also applies to: 97-100
127-132
: Consider highlighting stream timeout informationThe note about stream consumption timeout is crucial information that could affect production deployments. Consider moving this information to a more prominent position, perhaps in the "How it works" section, and formatting it as a warning rather than a note.
173-195
: Consider enhancing the React example with error handling and better loading statesThe current example could be improved to better demonstrate production-ready code:
- Add error handling for failed runs
- Implement a proper loading state component
- Add type safety for the streams object
function MyComponent({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) { - const { run, streams } = useRealtimeRunWithStreams<typeof myTask, STREAMS>(runId, { + const { run, streams, error, isLoading } = useRealtimeRunWithStreams<typeof myTask, STREAMS>(runId, { accessToken: publicAccessToken, }); + if (error) { + return <div>Error: {error.message}</div>; + } - if (!run) { + if (isLoading || !run) { - return <div>Loading...</div>; + return <LoadingSpinner />; } return ( <div> <h1>Run ID: {run.id}</h1> <h2>Streams:</h2> <ul> - {Object.entries(streams).map(([key, value]) => ( + {Object.entries(streams ?? {}).map(([key, value]) => ( <li key={key}> <strong>{key}</strong>: {JSON.stringify(value)} </li> ))} </ul> </div> ); }
398-404
: Add comment indicating mock implementationThe weather data implementation uses mock data. Consider adding a comment to make it clear this is for demonstration purposes only.
run: async ({ location }) => { + // NOTE: This is a mock implementation for demonstration purposes + // Replace with actual weather API integration in production return { location, temperature: 72 + Math.floor(Math.random() * 21) - 10, }; },
420-420
: Fix typo in default promptThere's a typo in "San Fransico" (should be "San Francisco").
- "Based on the temperature, will I need to wear extra clothes today in San Fransico? Please be detailed." + "Based on the temperature, will I need to wear extra clothes today in San Francisco? Please be detailed."docs/frontend/react-hooks.mdx (1)
448-449
: Fix grammar in the sentence.Change "the type of the streams" to "the types of the streams" to maintain proper agreement with the plural noun.
🧰 Tools
🪛 LanguageTool
[grammar] ~448-~448: In this context, ‘type’ should agree in number with the noun after ‘of’.
Context: ... ); } ``` You can provide the type of the streams to theuseRealtimeRunWithStreams
hook...(TYPE_OF_PLURAL)
references/nextjs-realtime/src/trigger/ai.ts (1)
205-209
: Handle possible undefined content when aggregating textThere is a potential for
choice.delta?.content
to be undefined, which could result inundefined
being concatenated totext
. To prevent this, filter out undefined values before joining.Apply this diff:
text += chunk.choices .map((choice) => choice.delta?.content) + .filter((content): content is string => content !== undefined) .join("");
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (15)
.changeset/khaki-ants-yawn.md
(1 hunks)docs/frontend/overview.mdx
(3 hunks)docs/frontend/react-hooks.mdx
(8 hunks)docs/introduction.mdx
(1 hunks)docs/mint.json
(9 hunks)docs/realtime/overview.mdx
(1 hunks)docs/realtime/react-hooks.mdx
(1 hunks)docs/realtime/streams.mdx
(1 hunks)docs/realtime/use-realtime-run.mdx
(0 hunks)docs/realtime/use-realtime-runs-with-tag.mdx
(0 hunks)docs/runs/metadata.mdx
(2 hunks)packages/react-hooks/src/hooks/useRun.ts
(1 hunks)packages/react-hooks/src/utils/trigger-swr.ts
(1 hunks)packages/trigger-sdk/package.json
(2 hunks)references/nextjs-realtime/src/trigger/ai.ts
(3 hunks)
💤 Files with no reviewable changes (2)
- docs/realtime/use-realtime-run.mdx
- docs/realtime/use-realtime-runs-with-tag.mdx
✅ Files skipped from review due to trivial changes (3)
- docs/mint.json
- docs/realtime/overview.mdx
- docs/realtime/react-hooks.mdx
🧰 Additional context used
🪛 LanguageTool
.changeset/khaki-ants-yawn.md
[uncategorized] ~6-~6: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...l accept accessToken and baseURL options so the use of the Provider is no longer ne...
(COMMA_COMPOUND_SENTENCE_2)
docs/frontend/overview.mdx
[uncategorized] ~94-~94: The verb “is” doesn’t seem to fit in this context, “are” is probably more formally correct.
Context: ...ou can also specify write scopes, which is required for triggering tasks from your...
(AI_HYDRA_LEO_CPT_IS_ARE)
docs/frontend/react-hooks.mdx
[grammar] ~448-~448: In this context, ‘type’ should agree in number with the noun after ‘of’.
Context: ... ); } ``` You can provide the type of the streams to the useRealtimeRunWithStreams
hook...
(TYPE_OF_PLURAL)
docs/introduction.mdx
[style] ~15-~15: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..., debugging, and managing your tasks. - We provide a Realtime API for...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~16-~16: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hooks) for building custom dashboards. We're [open source](https://github.com/tri...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
docs/realtime/streams.mdx
[style] ~7-~7: The phrase “a variety of” may be wordy. To make your writing clearer, consider replacing it.
Context: ...e world in realtime. This is useful for a variety of use cases, including AI. ## How it wor...
(A_VARIETY_OF)
docs/runs/metadata.mdx
[style] ~56-~56: This phrase is redundant. Consider using “outside”.
Context: ...If you call any of the metadata methods outside of the run function, they will have no eff...
(OUTSIDE_OF)
[misspelling] ~112-~112: Did you mean “except”?
Context: ...ur runs.) All metadata update methods (accept for flush
and stream
) are synchrono...
(ACCEPT_EXCEPT)
[uncategorized] ~294-~294: Possible missing comma found.
Context: ...and made available in the Realtime API. So for example, you could pass the body of...
(AI_HYDRA_LEO_MISSING_COMMA)
🔇 Additional comments (11)
.changeset/khaki-ants-yawn.md (1)
1-4
: LGTM on version bumps!
The patch version increments are appropriate since these changes add functionality in a backward-compatible way.
packages/react-hooks/src/utils/trigger-swr.ts (1)
2-4
: LGTM: Import changes are appropriate
The import of ApiRequestOptions
from the v3 core package is correctly added to support the new request configuration options.
packages/react-hooks/src/hooks/useRun.ts (1)
Line range hint 30-46
: LGTM! Well-implemented hook with smart refresh handling
The implementation shows good practices:
- Efficient use of SWR for data fetching and caching
- Smart refresh interval handling that stops polling when the run is completed
- Proper propagation of configuration options
- Solid error handling
packages/trigger-sdk/package.json (1)
69-69
: Verify the major version upgrade of 'ai' package
The 'ai' package has been upgraded from ^3.4.33 to ^4.0.1, which is a major version bump. This could introduce breaking changes that need to be addressed.
Please ensure:
- The upgrade is intentional and aligned with the PR objectives
- All breaking changes from [email protected] have been accounted for
- The application has been tested with this new version
docs/introduction.mdx (1)
22-31
: LGTM! Well-formatted iframe with proper security attributes.
The reformatted iframe improves readability while maintaining all necessary security attributes and YouTube embed functionality.
docs/frontend/overview.mdx (1)
7-7
: LGTM! Clear introduction with proper documentation linking.
docs/realtime/streams.mdx (1)
343-344
:
Remove duplicate import statement
The useRealtimeRunWithStreams
import is duplicated.
- import { useRealtimeRunWithStreams } from "@trigger.dev/sdk/v3";
import { useRealtimeRunWithStreams } from "@trigger.dev/sdk/v3";
Likely invalid or redundant comment.
docs/frontend/react-hooks.mdx (4)
Line range hint 31-85
: LGTM! Well-documented authentication options.
The authentication section clearly explains both direct token usage and provider-based approaches, with proper TypeScript types and comprehensive examples.
Line range hint 241-253
: LGTM! Clear explanation of hook styles.
Good explanation of the differences between SWR and Realtime hooks, with helpful guidance about rate limits and API behavior.
611-685
: LGTM! Comprehensive SWR hooks documentation.
The section provides clear examples, proper TypeScript types, and well-documented options and return values.
687-797
: LGTM! Well-documented trigger hooks.
Excellent documentation of the trigger hooks with proper TypeScript types, clear examples, and stream handling.
const { runs, error } = useRealtimeRunsWithStreams(tag, { | ||
accessToken: publicAccessToken, | ||
experimental_throttleInMs: 1000, // Throttle updates to once per second | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect parameter usage in the example.
The example uses a tag
parameter that wasn't defined in the component props. It should use runId
instead.
- const { runs, error } = useRealtimeRunsWithStreams(tag, {
+ const { runs, error } = useRealtimeRunsWithStreams(runId, {
Committable suggestion skipped: line range outside the PR's diff.
const completion = await openaiSDK.chat.completions.create({ | ||
messages: [{ role: "user", content: prompt }], | ||
model: "gpt-3.5-turbo", | ||
stream: true, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the model
parameter in OpenAI API call
The model
parameter passed into the function is not used in the API call; instead, "gpt-3.5-turbo"
is hardcoded. Update the code to use the model
parameter to respect the input.
Apply this diff to fix the issue:
messages: [{ role: "user", content: prompt }],
- model: "gpt-3.5-turbo",
+ model: model,
stream: true,
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const completion = await openaiSDK.chat.completions.create({ | |
messages: [{ role: "user", content: prompt }], | |
model: "gpt-3.5-turbo", | |
stream: true, | |
}); | |
const completion = await openaiSDK.chat.completions.create({ | |
messages: [{ role: "user", content: prompt }], | |
model: model, | |
stream: true, | |
}); |
import OpenAI from "openai"; | ||
|
||
const openaiSDK = new OpenAI({ | ||
apiKey: process.env.OPENAI_API_KEY, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for missing OpenAI API key
To prevent runtime errors when OPENAI_API_KEY
is missing, consider adding a check to ensure that process.env.OPENAI_API_KEY
is defined before creating the OpenAI SDK instance.
Apply this diff to add the error handling:
+if (!process.env.OPENAI_API_KEY) {
+ throw new Error("OPENAI_API_KEY environment variable is not set.");
+}
const openaiSDK = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import OpenAI from "openai"; | |
const openaiSDK = new OpenAI({ | |
apiKey: process.env.OPENAI_API_KEY, | |
}); | |
import OpenAI from "openai"; | |
if (!process.env.OPENAI_API_KEY) { | |
throw new Error("OPENAI_API_KEY environment variable is not set."); | |
} | |
const openaiSDK = new OpenAI({ | |
apiKey: process.env.OPENAI_API_KEY, | |
}); |
export const fetchStream = schemaTask({ | ||
id: "fetch-stream", | ||
description: "Stream data from fetch", | ||
schema: z.object({ | ||
url: z.string().url(), | ||
}), | ||
run: async ({ url }) => { | ||
logger.info("Streaming response", { url }); | ||
|
||
const response = await fetch(url); | ||
|
||
if (!response.body) { | ||
throw new Error("Response body is not readable"); | ||
} | ||
|
||
const stream = await metadata.stream( | ||
"fetch", | ||
response.body.pipeThrough(new TextDecoderStream()) | ||
); | ||
|
||
let text = ""; | ||
|
||
for await (const chunk of stream) { | ||
logger.log("Received chunk", { chunk }); | ||
|
||
text += chunk; | ||
} | ||
|
||
return { text }; | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure fetch
and TextDecoderStream
are available in Node.js environment
The fetch
API and TextDecoderStream
are used, which require Node.js 18+ or appropriate polyfills. Ensure that your runtime environment supports these APIs, or consider importing necessary packages.
If fetch
is not globally available, you can import it:
+import fetch from 'node-fetch';
For TextDecoderStream
, if it's not available, consider alternative methods to decode the stream, such as using the ReadableStream
with a custom decoder or leveraging the StringDecoder
from the string_decoder
module.
Committable suggestion skipped: line range outside the PR's diff.
@trigger.dev/react-hooks
@trigger.dev/rsc
@trigger.dev/sdk
@trigger.dev/core
@trigger.dev/build
trigger.dev
commit: |
Summary by CodeRabbit
Release Notes
New Features
accessToken
andbaseURL
options directly, simplifying authentication and API integration.useRealtimeRunWithStreams
, for enhanced data streaming capabilities.Documentation