-
-
Notifications
You must be signed in to change notification settings - Fork 672
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
v4: Waitpoint PAT completion, fix dequeuing without retry config, fixed metadata #1826
Conversation
…a way to throw an error to output from the run, adding an icon option to logger.trace
|
WalkthroughThis update spans multiple modules and projects. In the webapp API routes, new exports and configuration properties (JWT, authorization, CORS) are introduced while deprecating older properties. The API client now returns enriched response headers with JWT claims. Internal task and waitpoint error handling is streamlined, and new error types have been added. Enhancements affect CLI workers’ metadata tracking and logger/tracer method signatures. A new React hook for wait tokens is implemented, and Trigger SDK types are expanded. Additionally, several reference projects now include a comprehensive Next.js agent loop setup with complete configuration files and UI components. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Route
participant Auth
participant Database
Client->>API_Route: Sends request to complete waitpoint
API_Route->>API_Route: Invokes createActionApiRoute (action & loader)
API_Route->>Auth: Validate JWT & authorization
Auth-->>API_Route: Validated token
API_Route->>Database: Update waitpoint (complete waitpoint)
Database-->>API_Route: Return updated record
API_Route->>Client: Responds with status & JWT claims in headers
sequenceDiagram
participant User
participant WebUI
participant MainApp
participant AgentLoopTask
participant AI_Model
User->>WebUI: Enters chat message
WebUI->>MainApp: Submit prompt (with publicAccessToken)
MainApp->>AgentLoopTask: Trigger wait token creation & processing
AgentLoopTask->>AI_Model: Send conversation context and prompt
AI_Model-->>AgentLoopTask: Return streamed response
AgentLoopTask->>MainApp: Update conversation state
MainApp->>WebUI: Render updated chat interface
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (5)
🪧 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: 2
🔭 Outside diff range comments (1)
packages/core/src/v3/logger/taskLogger.ts (1)
126-138
:⚠️ Potential issueUpdate NoopTaskLogger to match new method signatures.
The
NoopTaskLogger
implementation needs to be updated to match the new method signatures that use theTraceOptions
type to maintain type consistency across implementations.- trace<T>(name: string, fn: (span: Span) => Promise<T>): Promise<T> { + trace<T>(name: string, fn: (span: Span) => Promise<T>, options?: TraceOptions): Promise<T> { return fn({} as Span); } - startSpan(): Span { + startSpan(name: string, options?: TraceOptions): Span { return {} as Span; }
🧹 Nitpick comments (15)
references/agent-loop/next.config.ts (1)
3-5
: Review: Placeholder Configuration Object
The declaration ofnextConfig
with a placeholder comment is appropriate for a new file. However, ensure that you eventually populate this object with the required configuration options for your Next.js project, as the placeholder is a reminder for future work.references/agent-loop/.gitignore (1)
33-35
: Environment Files Handling
The rule for.env*
files is appropriate as it allows opting in for committing environment files when necessary.Consider adding a brief comment clarifying which specific environment files might be committed and under what circumstances.
references/agent-loop/trigger.config.ts (1)
1-7
: Configuration looks good, but consider security implications of hardcoded project IDThe Trigger.dev configuration is well-structured with appropriate settings for source directory and maximum duration (1 hour). However, be mindful about committing the hardcoded project ID to version control if it's sensitive or environment-specific.
Consider using environment variables for the project ID to make the configuration more portable across different environments:
import { defineConfig } from "@trigger.dev/sdk"; export default defineConfig({ - project: "proj_hgknlxlflfcemqogujnt", + project: process.env.TRIGGER_PROJECT_ID || "proj_hgknlxlflfcemqogujnt", dirs: ["./src/trigger"], maxDuration: 3600, });references/agent-loop/src/app/layout.tsx (1)
1-34
: Root layout component looks good.This is a standard Next.js root layout component with proper font configuration and metadata setup. The component structure follows Next.js best practices.
One suggestion for improvement: consider updating the generic metadata with more specific information for the Agent Loop application.
export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Agent Loop - Trigger.dev", + description: "A reference implementation of an agent loop using Trigger.dev", };references/agent-loop/src/components/chat-interface.tsx (1)
1-31
: Chat interface component looks good.The component is well-structured with proper TypeScript interfaces and follows React best practices. The conditional styling based on message role is implemented effectively.
Two minor suggestions:
- Consider adding a timestamp or ID to the Message interface for better key management
- The current implementation uses array indices as React keys, which might cause issues with message reordering or deletion
interface Message { role: "user" | "assistant" content: string + id?: string + timestamp?: Date } export default function ChatInterface({ messages }: ChatInterfaceProps) { return ( <div className="space-y-4 p-4"> {messages.map((message, index) => ( - <div key={index} className={cn("flex", message.role === "user" ? "justify-end" : "justify-start")}> + <div key={message.id || `message-${index}`} className={cn("flex", message.role === "user" ? "justify-end" : "justify-start")}> {/* ... rest of component ... */} </div> ))} </div> ) }references/agent-loop/package.json (1)
1-37
: Dependencies look good but version pinning approach is inconsistent.The package.json file properly sets up the Next.js project with all necessary dependencies for the agent loop functionality. However, I noticed inconsistent version pinning:
- Some dependencies use exact versions (e.g.,
"@ai-sdk/openai": "1.3.3"
)- Others use caret ranges (e.g.,
"class-variance-authority": "^0.7.1"
)- Workspace dependencies use
workspace:*
Consider standardizing the approach to version management for better dependency predictability.
references/agent-loop/src/components/main-app.tsx (2)
14-18
: Well-defined types for chat conversation and response streams.These type definitions provide clear structure for the conversation data and the response streams.
Note that the
ResponseStreams
type uses an empty object{}
as its generic parameter. Consider replacing with a more specific type if applicable.- type ResponseStreams = { - [K in `responses.${number | string}`]: TextStreamPart<{}>; - }; + type ResponseStreams = { + [K in `responses.${number | string}`]: TextStreamPart<Record<string, unknown>>; + };🧰 Tools
🪛 Biome (1.9.4)
[error] 17-17: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
88-131
: Implemented MainApp component with clean UI for chat interaction.The component provides a responsive chat interface with appropriate handling for user input and form submission.
The implementation includes:
- Integration with the useAgentLoop hook
- State management for user input
- Form handling with empty message prevention
- Conditional rendering of initial prompt or chat interface
- Responsive design with appropriate styling
One improvement suggestion:
The component doesn't show any UI feedback while responses are loading. Consider adding a visual indicator when isLoading is true:
<form onSubmit={handleSubmit} className="flex gap-2"> <input type="text" value={input} onChange={(e) => setInput(e.target.value)} placeholder="Type a message..." className="flex-1 p-3 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary" /> <button type="submit" disabled={isLoading || !input.trim()} className="p-3 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50" > - <Send size={20} /> + {isLoading ? <span className="animate-spin">⟳</span> : <Send size={20} />} </button> </form>packages/react-hooks/src/hooks/useWaitToken.ts (2)
46-60
: Consider adding timeout handling for network requests.While the implementation handles API client and waitpoint ID validation well, it doesn't address potential timeout issues during network requests. Consider adding timeout handling to improve user experience in intermittent network conditions.
async function completeWaitpoint(id: string, { arg: { output } }: { arg: { output: TOutput } }) { if (!apiClient) { throw new Error("Could not complete waitpoint in useWaitToken: Missing access token"); } if (!waitpointId) { throw new Error("Could not complete waitpoint in useWaitToken: Missing waitpoint ID"); } + try { const result = await apiClient.completeWaitpointToken(waitpointId, { data: output, + timeout: 10000, // 10 second timeout }); return result; + } catch (error) { + if (error instanceof Error && error.name === 'AbortError') { + throw new Error('Request timed out when completing waitpoint'); + } + throw error; + } }
65-72
: Consider adding debounce or throttle for the complete function.In user-facing components, it's common for users to accidentally click buttons multiple times. Consider adding debounce or throttle functionality to the complete function to prevent duplicate submissions.
return { complete: (output) => { + // Prevent multiple rapid submissions + if (mutation.isMutating) { + return; + } // trigger the task with the given payload mutation.trigger({ output }); }, isLoading: mutation.isMutating, isCompleted: !!mutation.data?.success, isReady: !!waitpointId, error: mutation.error, };apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts (1)
48-52
: Consider removing or enabling the commented-out codeThis commented-out block checking if a waitpoint is already completed suggests a partially implemented feature. Consider either fully implementing it or removing it until ready for production.
- // if (waitpoint.status === "COMPLETED") { - // return json<CompleteWaitpointTokenResponseBody>({ - // success: true, - // }); - // }packages/core/src/v3/apiClient/index.ts (1)
679-709
: Enhanced token handling for waitpoint tokensThe implementation now properly processes JWT tokens from response headers or generates new ones when needed, adding them as
publicAccessToken
to the response. This is an important security enhancement.Consider extracting the JWT generation logic to a separate helper function since similar code appears in multiple places in this file:
+ private async generateTokenFromClaims(claims: any, scopes: string[], expirationTime: string = "24h") { + return generateJWT({ + secretKey: this.accessToken, + payload: { + ...claims, + scopes, + }, + expirationTime, + }); + } createWaitpointToken(options: CreateWaitpointTokenRequestBody, requestOptions?: ZodFetchOptions) { return zodfetch( CreateWaitpointTokenResponseBody, `${this.baseUrl}/api/v1/waitpoints/tokens`, { method: "POST", headers: this.#getHeaders(false), body: JSON.stringify(options), }, { ...mergeRequestOptions(this.defaultRequestOptions, requestOptions), prepareData: async (data, response) => { const jwtHeader = response.headers.get("x-trigger-jwt"); if (typeof jwtHeader === "string") { return { ...data, publicAccessToken: jwtHeader, }; } const claimsHeader = response.headers.get("x-trigger-jwt-claims"); const claims = claimsHeader ? JSON.parse(claimsHeader) : undefined; - const jwt = await generateJWT({ - secretKey: this.accessToken, - payload: { - ...claims, - scopes: [`write:waitpoints:${data.id}`], - }, - expirationTime: "24h", - }); + const jwt = await this.generateTokenFromClaims(claims, [`write:waitpoints:${data.id}`], "24h"); return { ...data, publicAccessToken: jwt, }; }, } ) as ApiPromise<CreateWaitpointTokenResponse>; }references/agent-loop/src/trigger/agent.ts (2)
6-6
: Consider adding documentation forMAX_STEPS
constant.The purpose of limiting the conversation to 10 steps should be documented to explain the reasoning behind this specific limit.
-const MAX_STEPS = 10; +// Limit conversation to 10 steps to prevent excessive resource usage and token consumption +const MAX_STEPS = 10;
39-42
: Consider a shorter token expiration time.The token expiration is set to 1 day, which is quite long. For interactive loops, a shorter timeout might be more appropriate to avoid dangling resources if users abandon conversations.
- // This token will expire in 1 day - const token = await wait.createToken({ timeout: "1d" }); + // Use a more reasonable timeout for interactive conversations + const token = await wait.createToken({ timeout: "4h" });packages/core/src/v3/apiClient/core.ts (1)
147-154
: Type casting may hide potential issues.The explicit type casting of
fetchResult
to a specific promise type might mask potential type incompatibilities. Consider refactoring to ensure type compatibility without explicit casting.- return new OffsetLimitPagePromise( - fetchResult as Promise<ZodFetchResult<OffsetLimitPageResponse<z.output<TItemSchema>>>>, - schema, - url, - params, - requestInit, - options - ); + // Create a properly typed variable to ensure type compatibility + const typedFetchResult: Promise<ZodFetchResult<OffsetLimitPageResponse<z.output<TItemSchema>>>> = fetchResult; + + return new OffsetLimitPagePromise( + typedFetchResult, + schema, + url, + params, + requestInit, + options + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (7)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
references/agent-loop/public/file.svg
is excluded by!**/*.svg
references/agent-loop/public/globe.svg
is excluded by!**/*.svg
references/agent-loop/public/next.svg
is excluded by!**/*.svg
references/agent-loop/public/vercel.svg
is excluded by!**/*.svg
references/agent-loop/public/window.svg
is excluded by!**/*.svg
references/agent-loop/src/app/favicon.ico
is excluded by!**/*.ico
📒 Files selected for processing (40)
apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts
(3 hunks)apps/webapp/app/routes/api.v1.waitpoints.tokens.ts
(3 hunks)apps/webapp/app/services/authorization.server.ts
(1 hunks)internal-packages/run-engine/src/engine/errors.ts
(0 hunks)internal-packages/run-engine/src/engine/systems/dequeueSystem.ts
(1 hunks)internal-packages/run-engine/src/engine/systems/waitpointSystem.ts
(3 hunks)packages/cli-v3/src/entryPoints/dev-run-worker.ts
(1 hunks)packages/cli-v3/src/entryPoints/managed-run-worker.ts
(1 hunks)packages/core/src/v3/apiClient/core.ts
(5 hunks)packages/core/src/v3/apiClient/index.ts
(5 hunks)packages/core/src/v3/errors.ts
(1 hunks)packages/core/src/v3/logger/index.ts
(2 hunks)packages/core/src/v3/logger/taskLogger.ts
(3 hunks)packages/core/src/v3/schemas/common.ts
(0 hunks)packages/core/src/v3/tracer.ts
(2 hunks)packages/core/src/v3/workers/taskExecutor.ts
(2 hunks)packages/react-hooks/src/hooks/useWaitToken.ts
(1 hunks)packages/react-hooks/src/index.ts
(1 hunks)packages/trigger-sdk/src/v3/auth.ts
(1 hunks)packages/trigger-sdk/src/v3/index.ts
(1 hunks)packages/trigger-sdk/src/v3/wait.ts
(2 hunks)references/agent-loop/.gitignore
(1 hunks)references/agent-loop/README.md
(1 hunks)references/agent-loop/components.json
(1 hunks)references/agent-loop/next.config.ts
(1 hunks)references/agent-loop/package.json
(1 hunks)references/agent-loop/postcss.config.mjs
(1 hunks)references/agent-loop/src/app/globals.css
(1 hunks)references/agent-loop/src/app/layout.tsx
(1 hunks)references/agent-loop/src/app/page.tsx
(1 hunks)references/agent-loop/src/components/chat-interface.tsx
(1 hunks)references/agent-loop/src/components/initial-prompt.tsx
(1 hunks)references/agent-loop/src/components/main-app.tsx
(1 hunks)references/agent-loop/src/lib/utils.ts
(1 hunks)references/agent-loop/src/trigger/agent.ts
(1 hunks)references/agent-loop/src/trigger/schemas.ts
(1 hunks)references/agent-loop/tailwind.config.ts
(1 hunks)references/agent-loop/trigger.config.ts
(1 hunks)references/agent-loop/tsconfig.json
(1 hunks)references/hello-world/src/trigger/waits.ts
(3 hunks)
💤 Files with no reviewable changes (2)
- internal-packages/run-engine/src/engine/errors.ts
- packages/core/src/v3/schemas/common.ts
🧰 Additional context used
🧬 Code Definitions (7)
references/agent-loop/src/app/page.tsx (2)
packages/trigger-sdk/src/v3/index.ts (1)
auth
(56-56)references/agent-loop/src/components/main-app.tsx (1)
MainApp
(88-131)
packages/cli-v3/src/entryPoints/dev-run-worker.ts (2)
packages/core/src/v3/workers/taskExecutor.ts (2)
execution
(982-1097)execution
(1224-1240)apps/webapp/app/v3/services/completeAttempt.server.ts (3)
execution
(553-643)execution
(645-699)execution
(701-710)
packages/cli-v3/src/entryPoints/managed-run-worker.ts (1)
packages/core/src/v3/workers/taskExecutor.ts (2)
execution
(982-1097)execution
(1224-1240)
packages/core/src/v3/tracer.ts (1)
packages/core/src/v3/errors.ts (1)
isCompleteTaskWithOutput
(153-155)
packages/trigger-sdk/src/v3/wait.ts (2)
packages/core/src/v3/apiClient/core.ts (1)
ApiPromise
(412-464)packages/core/src/v3/apiClient/index.ts (1)
CreateWaitpointTokenResponse
(81-85)
apps/webapp/app/routes/api.v1.waitpoints.tokens.ts (1)
packages/core/src/v3/schemas/api.ts (2)
CreateWaitpointTokenResponseBody
(945-948)CreateWaitpointTokenResponseBody
(949-949)
packages/core/src/v3/apiClient/core.ts (2)
packages/trigger-sdk/src/v3/index.ts (1)
RetryOptions
(3-3)packages/core/src/v3/tracer.ts (1)
TriggerTracer
(42-199)
🪛 Biome (1.9.4)
references/agent-loop/src/components/main-app.tsx
[error] 17-17: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: typecheck / typecheck
- GitHub Check: units / 🧪 Unit Tests
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (74)
references/agent-loop/next.config.ts (2)
1-2
: Review: Correct Use of Type-Only Import
The import ofNextConfig
using TypeScript’s type-only syntax is spot on. This approach ensures that the type is used solely for type-checking without adding runtime overhead.
7-7
: Review: Proper Default Export
The default export ofnextConfig
is correctly implemented, which conforms to Next.js standards for configuration files.references/agent-loop/.gitignore (9)
1-2
: Header and Reference Link
The introductory comment provides a useful reference to the GitHub guide on ignoring files. This is a good practice for future maintainers.
3-12
: Dependencies Ignore Rules
This block correctly excludes common dependency folders like/node_modules
,/pnp
, and all items in.yarn/*
, while still allowing critical subdirectories with negation (e.g.,!.yarn/patches
). This structure is clear and follows best practices.
13-15
: Testing Artifacts Exclusion
Excluding the/coverage
folder used for test coverage reports is appropriate. The section is concise and clear.
16-19
: Next.js Build Outputs
The entries for/.next/
and/out/
ensure that Next.js build outputs are not tracked. This is standard for Next.js projects.
20-22
: Production Build Directory
The rule to ignore/build
is suitable, assuming that this folder contains production artifacts that should not be versioned.
23-26
: Miscellaneous File Exclusions
Files like.DS_Store
and*.pem
are properly excluded. These entries help prevent accidental commits of system-specific or sensitive files.
27-32
: Debug Log Files Exclusion
This section correctly ignores various debug log files from npm, yarn, and pnpm. It aligns with best practices for keeping the repository clean from noise.
36-38
: Vercel Artifacts Exclusion
Ignoring the.vercel
folder correctly prevents deployment-specific files from being tracked.
39-41
: TypeScript Build Artifacts
Excluding*.tsbuildinfo
andnext-env.d.ts
is consistent with TypeScript best practices, ensuring that build artifacts are not versioned.references/agent-loop/postcss.config.mjs (1)
1-5
:❓ Verification inconclusive
Check Tailwind plugin name - potential naming issue
The plugin name
@tailwindcss/postcss
appears unusual. The standard Tailwind CSS PostCSS plugin is typically named justtailwindcss
.Fix the plugin name and consider adding autoprefixer which is commonly used with Tailwind:
const config = { - plugins: ["@tailwindcss/postcss"], + plugins: ["tailwindcss", "autoprefixer"], }; export default config;
🌐 Web query:
What is the correct plugin name for Tailwind CSS in PostCSS configuration?
💡 Result:
To configure Tailwind CSS with PostCSS, the correct plugin name depends on your Tailwind version:
For Tailwind CSS v3.x:
// postcss.config.js module.exports = { plugins: { tailwindcss: {}, // Official plugin name [2][3][4][12] autoprefixer: {}, } }For Tailwind CSS v4.x+:
// postcss.config.js module.exports = { plugins: { "@tailwindcss/postcss": {} // New package name in v4 [5][9][16] } }Key differences:
- v3 uses the
tailwindcss
package directly [1][2]- v4 requires the separate
@tailwindcss/postcss
package [4][8][15]- Both versions require autoprefixer for vendor prefixes in v3 setups [1][2]
If you're seeing errors about plugin names, check your package versions:
# For v3 npm install -D tailwindcss@3 postcss autoprefixer # For v4 npm install -D @tailwindcss/postcss tailwindcssAlways verify your configuration matches the version shown in
package.json
. The v4 change was introduced to improve integration with modern build tools and PostCSS 8+ [4][15].Citations:
- 1: https://v3.tailwindcss.com/docs/installation/using-postcss
- 2: https://gist.github.com/xpharsh/929e39f23b2d005c966aa795b6013b02
- 3: https://rsbuild.dev/guide/basic/tailwindcss-v3
- 4: https://tailwindcss.com/docs/installation/using-postcss
- 5: https://www.youtube.com/watch?v=syx_y2_XLCM
- 6: https://night-tailwindcss.vercel.app/docs/plugins
- 7: https://github.com/tailwindlabs/minimal-tailwind-postcss-plugin
- 8: https://tailwindcss.com/docs/guides/nextjs
- 9: https://dev.to/zev/how-do-postcss-tailwind-work-part-1-shrinking-the-build-4a0d
- 10: https://www.youtube.com/watch?v=ieObfhXqJtc
- 11: https://www.talentica.com/blogs/a-guide-to-installing-tailwind-as-a-postcss-plugin/
- 12: https://www.npmjs.com/package/@tailwindcss/postcss/v/4.0.0-alpha.13
- 13: https://tailwindcss.com/docs
- 14: https://tailwindcss.com/docs/using-with-preprocessors
- 15: [v4] It looks like you're trying to use
tailwindcss
directly as a PostCSS plugin. tailwindlabs/tailwindcss#15735
Verify Tailwind CSS Version for Correct Plugin Configuration
Based on the latest Tailwind CSS documentation, the correct PostCSS plugin name depends on your Tailwind version:
- Tailwind CSS v4+: Your current configuration using
@tailwindcss/postcss
is valid.- Tailwind CSS v3.x: The configuration should use the plugin named
tailwindcss
and includeautoprefixer
.Please check your project’s Tailwind version (typically from
package.json
) and update the configuration accordingly. For example, if you are on v3.x, update as follows:const config = { - plugins: ["@tailwindcss/postcss"], + plugins: ["tailwindcss", "autoprefixer"], }; export default config;packages/trigger-sdk/src/v3/index.ts (1)
36-36
: Export addition looks goodAdding
CompleteTaskWithOutput
to the exports alongside other error types is appropriate and follows the established pattern.packages/react-hooks/src/index.ts (1)
6-6
: Export addition follows consistent patternThe export of the new
useWaitToken
hook follows the established pattern for exposing hooks from this package.references/agent-loop/src/app/page.tsx (1)
1-8
: LGTM! Well-implemented Next.js page component.The component correctly:
- Imports the required dependencies
- Creates a public access token asynchronously
- Passes the token to the MainApp component with proper prop structure
This implementation serves as a good entrypoint for the agent loop example.
references/agent-loop/src/lib/utils.ts (1)
1-6
: Clean utility function implementation for Tailwind class name management.The
cn
function correctly usesclsx
to combine class names andtwMerge
to handle Tailwind CSS class conflicts, following established best practices for conditional class name handling in Tailwind projects.references/agent-loop/src/trigger/schemas.ts (1)
1-10
: Well-structured Zod schema for wait token metadata.The schema correctly defines the structure for the agent loop metadata with appropriate validation. The type export provides type safety when working with this structure throughout the codebase.
packages/cli-v3/src/entryPoints/managed-run-worker.ts (1)
379-380
: Good addition for metadata tracking.Setting the
runId
on therunMetadataManager
ensures that metadata operations are properly associated with the current execution run, which is crucial for accurate tracking and debugging.references/agent-loop/src/components/initial-prompt.tsx (1)
1-14
: LGTM! Well-structured welcome component.The
InitialPrompt
component is cleanly implemented with good organization of UI elements and appropriate Tailwind CSS classes for styling.packages/cli-v3/src/entryPoints/dev-run-worker.ts (1)
381-382
: Proper tracking of run ID in metadata.This change ensures that the run ID is correctly associated with the metadata manager before task execution, which will enable proper tracking and association of metadata with the specific run.
references/agent-loop/components.json (1)
1-21
: LGTM! Well-configured shadcn/ui setup.The configuration is properly structured with all necessary settings for the UI component library, including style preferences, Tailwind settings, and import aliases.
references/agent-loop/src/app/globals.css (1)
1-122
: LGTM! Well-structured theming system.The CSS implementation follows modern practices with:
- Well-organized CSS variables for theming
- Clear separation between light and dark modes
- Usage of the oklch color format for better color representation
- Proper layering with Tailwind's @layer system
apps/webapp/app/services/authorization.server.ts (1)
3-3
: Authorization updated to support waitpoints. LGTM!The addition of "waitpoints" to the
ResourceTypes
constant properly extends the authorization system to handle this new resource type. This change aligns well with the PR objective of completing waitpoint PAT functionality.packages/trigger-sdk/src/v3/auth.ts (2)
57-60
: New waitpoints permission property looks good.The addition of the
waitpoints
property toPublicTokenPermissionProperties
follows the same pattern as other resource types, with proper documentation and consistent typing.
66-66
: Write permission is no longer deprecated.The removal of the deprecated comment from the
write
property suggests it's now fully supported.references/agent-loop/README.md (1)
1-37
: LGTM! Standard Next.js README.This is a standard README generated by create-next-app that provides basic instructions for running and deploying a Next.js application. It contains helpful information for developers who will be working with this agent-loop reference project.
references/agent-loop/package.json (1)
18-20
:✅ Verification successful
Verify Next.js and React compatibility.
You're using React 19.0.0 which is very recent. Make sure it's fully compatible with the Next.js version you've specified (15.2.4).
🌐 Web query:
Is React 19.0.0 compatible with Next.js 15.2.4?
💡 Result:
Yes, React 19.0.0 is compatible with Next.js 15.2.4. Here's a breakdown of the key details:
Compatibility Overview
- Official Support: Next.js 15 requires React 19 as its minimum version, confirmed by Next.js upgrade guides[1][3][5][11].
- Core Integration: Next.js 15's App Router uses React 19 by default, while backward compatibility allows Pages Router users to stay on React 18 temporarily[11].
Key Technical Considerations
Dependency Management:
npm install [email protected] [email protected] [email protected]Peer dependency conflicts may require installation flags:
npm install --force # OR npm install --legacy-peer-deps
API Changes:
useFormState
→useActionState
[5]- New async APIs for cookies/headers[5]:
const cookieStore = await cookies() // Async in React 19Third-Party Packages:
- Some libraries require manual fixes (e.g., Recharts needs
react-is
override)[3]:{ "overrides": { "react-is": "^19.0.0-rc-69d4b800-20241021" } }Developer Experience Improvements
- Automatic Codemods:
npx @next/codemod@canary upgrade latest- Error Handling:
- Hydration errors now show visual diffs[4]
- New error boundaries with
onCaughtError
/onUncaughtError
[4]Current Limitations
- Mixed Router usage (App + Pages) with different React versions isn't recommended[11]
- Typing inconsistencies may occur during transition periods[11]
Next.js 15.2.4 and React 19.0.0 are production-ready when using the App Router, with full documentation and migration tools available[5][11]. Most compatibility issues stem from third-party packages needing dependency updates rather than Next.js/React core integration.
Citations:
- 1: https://www.scalablepath.com/react/react-19
- 2: https://nextjs.org/docs/messages/react-version
- 3: https://ui.shadcn.com/docs/react-19
- 4: https://react.dev/blog/2024/12/05/react-19
- 5: https://nextjs.org/docs/app/building-your-application/upgrading/version-15
- 6: https://nextjs.org/docs/pages/api-reference/cli/next
- 7: https://www.eitbiz.com/blog/react-19-whats-new-in-its-latest-updates-and-features/
- 8: https://endoflife.date/nextjs
- 9: Compatibility with React 19 and Next.js 15 ant-design/ant-design#51458
- 10: https://www.freecodecamp.org/news/new-react-19-features-you-should-know-with-code-examples/
- 11: https://nextjs.org/blog/next-15
- 12: https://www.npmjs.com/search?q=keywords%3Areact
- 13: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
- 14: https://nextjs.org/blog/next-15-2
- 15: https://www.youtube.com/watch?v=4JsTCSYst9M
- 16: https://nextjs.org/blog
- 17: https://www.npmjs.com/package/next/v/15.2.4
Compatibility Verified: Next.js 15.2.4 and React 19.0.0 are fully compatible.
Based on the latest documentation and upgrade guides, using React 19.0.0 with Next.js 15.2.4 is supported (especially when using the App Router). While peer dependency conflicts might sometimes require flags like
--force
or--legacy-peer-deps
during installation, no changes are needed with respect to these core dependencies.packages/core/src/v3/tracer.ts (2)
20-20
: LGTM! Added import for CompleteTaskWithOutput check.The import of
isCompleteTaskWithOutput
from the errors module is necessary for the error handling improvement in the startActiveSpan method.
135-142
: Good improvement to handle CompleteTaskWithOutput errors.This change properly handles
CompleteTaskWithOutput
errors by ending the span before rethrowing the error. This is important because:
- It ensures that spans are properly concluded even when tasks complete with output
- It prevents span leaks and improves tracing accuracy
- It maintains the proper error propagation
This aligns with the PR objective of fixing waitpoint completion.
references/agent-loop/tsconfig.json (1)
1-28
: Solid TypeScript configuration for Next.js project.The TypeScript configuration is well-structured for a Next.js application with appropriate settings:
- Target ES2017 which is suitable for modern browsers
- Strict type checking enabled, which is good for code quality
- Proper module resolution settings for bundlers
- Next.js plugin correctly configured
- Path aliases set up for clean imports from src directory
This configuration will provide good type safety for the agent loop implementation.
packages/core/src/v3/workers/taskExecutor.ts (2)
7-7
: New imported function for enhanced error handling.The
isCompleteTaskWithOutput
function is now imported to support the new error handling approach in the#callRun
method.
154-162
: Improved error handling in #callRun.The method now handles a new error type
CompleteTaskWithOutput
which allows tasks to return structured output via exception handling. This enhancement provides a more graceful way to complete tasks with output when encountering specific conditions.The implementation correctly:
- Wraps the existing functionality in a try-catch block
- Checks for specialized error type before re-throwing
- Extracts the output property when the specialized error is detected
This pattern enables more flexible control flow while preserving the original error propagation for unexpected errors.
apps/webapp/app/routes/api.v1.waitpoints.tokens.ts (4)
16-16
: Imported AuthenticatedEnvironment for JWT claims.Added import for
AuthenticatedEnvironment
to support the new JWT claims functionality.
81-81
: Added response headers generation for authentication data.The generated headers will be included in the API response, enabling clients to access authentication information.
88-88
: Enhanced JSON response with authentication headers.The response now includes JWT claims in the headers, which will help clients authenticate subsequent requests.
102-113
: Added responseHeaders function to generate JWT claims.This function creates a structured object containing the environment ID and a public flag, exposing them as JWT claims in the response headers.
The implementation:
- Creates a JSON string containing
sub
(subject) andpub
(public) claims- Returns an object with the header key "x-trigger-jwt-claims"
This enables clients to parse authentication information directly from the response headers.
references/agent-loop/src/components/main-app.tsx (1)
3-13
: Comprehensive imports for chat application functionality.The file imports React hooks, components, and types required for implementing the agent loop chat interface.
packages/core/src/v3/errors.ts (2)
143-151
: Added CompleteTaskWithOutput error class.This new error class provides a clean mechanism for tasks to return outputs through exception handling, enhancing flow control options.
The implementation is clean and straightforward:
- The class extends the base Error class
- It stores the output in a readonly property
- It sets appropriate name and message for debugging
153-155
: Added type guard for CompleteTaskWithOutput.This type guard function allows for safe type checking of error objects, ensuring they are instances of the CompleteTaskWithOutput class before accessing the output property.
The implementation follows TypeScript's type guard pattern:
- Returns a boolean indicating if the error is an instance of CompleteTaskWithOutput
- Uses the return type
error is CompleteTaskWithOutput
for type narrowing- Performs appropriate checks against Error instance and name
This enables safer error handling in the calling code.
packages/trigger-sdk/src/v3/wait.ts (2)
22-22
: Type addition enhances response with public access token.The new
CreateWaitpointTokenResponse
type is imported to reflect the updated response structure from the API.
55-55
: Updated return type to include the public access token.The function's return type has been changed from
ApiPromise<CreateWaitpointTokenResponseBody>
toApiPromise<CreateWaitpointTokenResponse>
, allowing consuming code to access the public access token that can be used for authentication against this specific waitpoint.references/hello-world/src/trigger/waits.ts (4)
1-1
: Added auth module import for token authentication.The auth module is imported to support public access token creation and authentication.
11-11
: Added parameter to optionally use public token for completion.The new
completeWithPublicToken
parameter allows the function to demonstrate how to complete a waitpoint using a public access token instead of the default authorization.Also applies to: 19-19
44-51
: Added public access token creation with scoped permissions.Creating a public access token with limited write scope specifically for this waitpoint is a good security practice, restricting the token to only what's necessary.
54-65
: Implemented conditional authentication strategy for token completion.The conditional logic handles both authentication methods:
- When
completeWithPublicToken
is true, the token is completed usingauth.withAuth
with the public token- Otherwise, it uses the default authentication method
This demonstrates how to properly implement public access token authentication patterns.
internal-packages/run-engine/src/engine/systems/dequeueSystem.ts (1)
312-312
:❓ Verification inconclusive
Simplified retry configuration handling by removing error states.
The previous implementation would log an error and invoke the system failure handler when a retry configuration was invalid or missing. The new implementation gracefully handles these cases by simply using optional chaining (
?.
), resulting inundefined
if the configuration is invalid.This change makes the system more resilient by not treating these as critical errors, but you should verify that all consuming code correctly handles an undefined
maxAttempts
value.
🏁 Script executed:
#!/bin/bash # Look for places where maxAttempts might be used without checking for undefined # Note: 'null' checks would still work as 'undefined' is falsy echo "Checking for potential issues where maxAttempts is used without null/undefined checking..." rg -A 3 "maxAttempts" | grep -v "\?\." | grep -v "if.*maxAttempts" | grep -v "maxAttempts.*undefined"Length of output: 57583
Review Update: Confirm Consuming Code’s Handling of Optional maxAttempts
The change now employs optional chaining when reading the retry configuration (i.e.
maxAttempts = parsedConfig.data?.maxAttempts
), which results in anundefined
value when the configuration is absent or invalid. This simplifies the error handling by removing previous error logging and system failure triggers.Verifying across the codebase shows that most consumers of
maxAttempts
are configured with fallback values or explicitly supplied numeric literals. In particular, indequeueSystem.ts
a log entry indicates that ifmaxAttempts
isn’t set, the system falls back to using the task’s retry configuration.Action Items:
- Ensure that every consumer of
maxAttempts
in the codebase (especially within retry logic) correctly handles anundefined
value without causing unintended behavior.- Confirm that any downstream logic that relies on
maxAttempts
incorporates appropriate defaulting or conditional handling when the value is not provided.packages/react-hooks/src/hooks/useWaitToken.ts (1)
1-75
: Well-designed React hook for waitpoint completion.This hook provides a clean interface for completing a waitpoint and tracking completion state in React applications. It follows React best practices:
- Uses the "use" prefix for a custom hook
- Employs SWR for efficient state management
- Provides clear error handling for missing tokens or API access
- Returns a well-structured interface with completion state tracking
This implementation will be useful for front-end applications that need to complete waitpoints directly.
references/agent-loop/tailwind.config.ts (1)
1-81
: Well-structured Tailwind configuration with comprehensive theming setupThe configuration includes all necessary elements for a robust Tailwind setup: proper content paths, container configuration, and an extensive theme customization with HSL color variables. The accordion animations are also well-defined.
apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts (2)
16-29
: API route enhanced with JWT support and precise authorization controlsThe route now properly exports both
action
andloader
functions, adds JWT authentication support, and defines specific authorization requirements for waitpoints.
80-80
: Export updated to include loader functionThe export statement has been correctly updated to include the newly destructured
loader
function.packages/core/src/v3/logger/index.ts (3)
1-3
: Updated imports to use custom TraceOptions instead of OpenTelemetry SpanOptionsThe change to import the custom
TraceOptions
type improves the logging API by allowing for custom tracing options specific to your application needs.
58-60
:❓ Verification inconclusive
Method signature updated for startSpan to use custom TraceOptions
The
startSpan
method now accepts the customTraceOptions
type instead of OpenTelemetry'sSpanOptions
.
🏁 Script executed:
#!/bin/bash # Verify that all callers of this method are using compatible options rg -A 2 "\.startSpan\(" --type typescriptLength of output: 78
Attention: Update the verification command for startSpan usage
It appears that the shell command to verify all callers of
startSpan
used an unrecognized file type flag (--type typescript
). Please update the command to search valid TypeScript files (for example, using-g '*.ts'
or--type ts
) to ensure that all call sites correctly pass the new customTraceOptions
. For instance:rg -A 2 "\.startSpan\(" -g '*.ts'This will properly confirm that all consumers of
startSpan
are using the compatible options.
50-56
:❓ Verification inconclusive
Method signature updated to use custom TraceOptions
The
trace
method now accepts the customTraceOptions
type instead of the generic OpenTelemetrySpanOptions
, while still returning an OpenTelemetrySpan
.
🏁 Script executed:
#!/bin/bash # Verify that all callers of this method are using compatible options rg -A 2 "\.trace\(" --type typescriptLength of output: 74
Action Required: Please verify that all call sites of the
trace
method correctly use the updated customTraceOptions
.The original verification script attempted to search with
--type typescript
, which is not recognized by ripgrep. To ensure a proper check, please re-run the search with the appropriate file types (e.g.,ts
andtsx
). For example, you can use the following scripts:#!/bin/bash echo "Searching for .trace calls in TS files..." rg -A 2 "\.trace\(" --type ts echo "Searching for .trace calls in TSX files..." rg -A 2 "\.trace\(" --type tsxThis will help confirm that all callers are compatible with the new method signature. Once verified, please confirm that the changes work as expected.
packages/core/src/v3/apiClient/index.ts (4)
79-85
: New type definition for waitpoint token responses with access tokensThe new
CreateWaitpointTokenResponse
type enhances the original response by including apublicAccessToken
property, which will provide clients with the necessary authentication token.
227-227
: Parameter order changed in destructuring assignmentThe order of destructured parameters has been switched from
{ response, data }
to{ data, response }
for consistency. Ensure all consumers of this API are compatible with this change.
274-274
: Parameter order changed in destructuring assignmentSimilar to the previous instance, the parameter order has been changed for consistency.
760-763
: Simplified request options for completeWaitpointTokenThe code has been simplified while maintaining the same functionality by directly spreading the merged request options.
references/agent-loop/src/trigger/agent.ts (3)
1-14
: Clean import structure and well-defined schema definition.The imports are well-organized, and the schema definition with z.object() properly defines the task parameters with sensible defaults.
73-87
: Good error handling for missing user response.The implementation correctly handles the case when no next message is received, throwing a
CompleteTaskWithOutput
exception to gracefully exit the task with the current waitpoint.
8-98
: Well-structured agent loop implementation.The overall structure of the agent loop is well-designed with a clear logical flow. It properly initializes the conversation, handles responses streaming, maintains conversation context, and provides appropriate logging throughout the process.
internal-packages/run-engine/src/engine/systems/waitpointSystem.ts (5)
1-1
: Good import of essential error handling utilities.The import of
timeoutError
andtryCatch
from the core package demonstrates a thoughtful approach to error handling.
69-79
: Improved logging of affectedTaskRuns state.Good defensive programming by checking for empty affectedTaskRuns and logging the state, which will help in troubleshooting waitpoint issues.
81-92
: Well-structured error handling with tryCatch.The use of
tryCatch
utility function simplifies error handling and makes the code more readable than traditional try-catch blocks.
94-106
: Thorough error handling for P2025 error codes.The code properly handles the scenario when a waitpoint is not found (P2025 Prisma error) by attempting to retrieve it again. It also logs other errors before rethrowing them.
137-137
:✅ Verification successful
Return type simplification may impact consumers.
The method now returns just the
waitpoint
directly instead of the previous object containing bothwaitpoint
andaffectedTaskRuns
. Verify that all callers of this method have been updated to handle the new return type.
🏁 Script executed:
#!/bin/bash # Check for usages of the completeWaitpoint method where destructuring or property access on the return value might occur rg -A 5 -B 5 "completeWaitpoint" --type ts | grep -E "(const|let|var).*=.*completeWaitpoint" | grep -E "\.waitpoint|\.affectedTaskRuns|\{.*waitpoint.*\}"Length of output: 894
Return type change verified:
The changes appear safe. Our grep inspection for usages ofcompleteWaitpoint
revealed assignments like:
- In
apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts
- In several files under
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.$waitpointFriendlyId.complete/route.tsx
None of these usages involve destructuring or accessing a
.waitpoint
or.affectedTaskRuns
property on the returned value, suggesting that all consumers have been updated to accommodate the simplified return type.packages/core/src/v3/logger/taskLogger.ts (5)
9-9
: Good use of utility type.Adding the
Prettify
utility type import improves type readability for complex types.
21-25
: Well-defined TraceOptions type with icon support.The new
TraceOptions
type is well-designed, extendingSpanOptions
with an optionalicon
property. UsingPrettify
ensures the resulting type is more readable in IDE tooltips.
33-34
: Updated method signatures with enhanced type safety.The method signatures for
trace
andstartSpan
have been updated to use the newTraceOptions
type, maintaining API consistency while adding new functionality.
97-107
: Clean implementation of icon support in trace method.The refactored
trace
method now properly handles theicon
property, setting theSTYLE_ICON
attribute conditionally. This implementation is clean and maintains backward compatibility.
109-119
: Consistent implementation in startSpan method.The
startSpan
method follows the same pattern astrace
, ensuring consistency across the API. The conditional inclusion of the icon attribute is well-implemented.packages/core/src/v3/apiClient/core.ts (4)
8-8
: Enhanced tracing capabilities with suppressTracing import.Adding the
suppressTracing
import from @opentelemetry/core enhances the control over tracing behavior in API calls.
30-38
: Improved type definition with generic parameter clarity.Changing from
T
toTData
for the generic parameter provides better semantic clarity about the data being handled. The updated method signatures foronResponseBody
andprepareData
enhance flexibility by providing access to both the parsed data and the raw response.
198-198
: Enhanced type safety in _doZodFetch options parameter.The
options
parameter type is now more precisely tied to the schema's output type, which improves type safety and reduces potential type errors.
211-213
: Improved data preparation with access to response.The
prepareData
method now receives both the parsed data and the raw response, allowing for more sophisticated data transformation based on response headers or other attributes.
export function useAgentLoop({ publicAccessToken }: { publicAccessToken: string }) { | ||
const triggerInstance = useRealtimeTaskTriggerWithStreams< | ||
typeof agentLoopExample, | ||
ResponseStreams | ||
>("agent-loop-example", { | ||
accessToken: publicAccessToken, | ||
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | ||
}); | ||
const [conversation, setConversation] = useState<ChatConversation>([]); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [waitToken, setWaitToken] = useState<AgentLoopMetadata | null>(null); | ||
|
||
const waitTokenInstance = useWaitToken(waitToken?.waitToken.id, { | ||
enabled: !!waitToken?.waitToken.id, | ||
accessToken: waitToken?.waitToken.publicAccessToken, | ||
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | ||
}); | ||
|
||
const waitTokenStream = waitToken?.waitToken.id | ||
? triggerInstance.streams[`responses.${waitToken?.waitToken.id}`] | ||
: undefined; | ||
|
||
const textStream = waitTokenStream | ||
?.map((part) => { | ||
if (part.type === "text-delta") { | ||
return part.textDelta; | ||
} | ||
}) | ||
.join(""); | ||
|
||
console.log("textStream", textStream); | ||
|
||
if (triggerInstance.run) { | ||
console.log("run", triggerInstance.run); | ||
|
||
const metadata = AgentLoopMetadata.safeParse(triggerInstance.run.metadata); | ||
|
||
if (!metadata.success) { | ||
console.error("Failed to parse metadata", metadata.error); | ||
} else { | ||
console.log("metadata", metadata.data); | ||
|
||
setWaitToken(metadata.data); | ||
} | ||
} | ||
|
||
return { | ||
continueConversation: (prompt: string) => { | ||
if (waitTokenInstance.isReady) { | ||
waitTokenInstance.complete({ | ||
message: prompt, | ||
}); | ||
} else { | ||
const result = triggerInstance.submit({ | ||
model: "gpt-4o-mini", | ||
prompt, | ||
}); | ||
|
||
setConversation((prev) => [...prev, { role: "user", content: prompt }]); | ||
|
||
return result; | ||
} | ||
}, | ||
conversation, | ||
isLoading, | ||
}; | ||
} |
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.
Implemented useAgentLoop hook for managing conversation state.
This hook effectively manages the conversation state, loading status, wait tokens, and handles the communication with the trigger.dev service.
The hook includes:
- State management for conversation, loading status, and wait tokens
- Integration with trigger.dev hooks for real-time task triggering and waiting
- Stream processing for text responses
- Metadata parsing with appropriate error handling
- Helper method for continuing conversations
A few minor concerns to consider:
- The console.log statements (lines 50 and 53) should be removed or converted to debug logs in production code.
- console.log("textStream", textStream);
+ // Use a logger with appropriate log levels
+ // logger.debug("textStream", textStream);
- The isLoading state is defined but never updated, potentially leading to incorrect UI states.
const { continueConversation, conversation, isLoading } = useAgentLoop({ publicAccessToken });
Consider updating the isLoading state in the hook:
return {
continueConversation: (prompt: string) => {
+ setIsLoading(true);
if (waitTokenInstance.isReady) {
waitTokenInstance.complete({
message: prompt,
+ }).finally(() => {
+ setIsLoading(false);
});
} else {
const result = triggerInstance.submit({
model: "gpt-4o-mini",
prompt,
+ }).finally(() => {
+ setIsLoading(false);
});
setConversation((prev) => [...prev, { role: "user", content: prompt }]);
return result;
}
},
conversation,
isLoading,
};
📝 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.
export function useAgentLoop({ publicAccessToken }: { publicAccessToken: string }) { | |
const triggerInstance = useRealtimeTaskTriggerWithStreams< | |
typeof agentLoopExample, | |
ResponseStreams | |
>("agent-loop-example", { | |
accessToken: publicAccessToken, | |
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | |
}); | |
const [conversation, setConversation] = useState<ChatConversation>([]); | |
const [isLoading, setIsLoading] = useState(false); | |
const [waitToken, setWaitToken] = useState<AgentLoopMetadata | null>(null); | |
const waitTokenInstance = useWaitToken(waitToken?.waitToken.id, { | |
enabled: !!waitToken?.waitToken.id, | |
accessToken: waitToken?.waitToken.publicAccessToken, | |
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | |
}); | |
const waitTokenStream = waitToken?.waitToken.id | |
? triggerInstance.streams[`responses.${waitToken?.waitToken.id}`] | |
: undefined; | |
const textStream = waitTokenStream | |
?.map((part) => { | |
if (part.type === "text-delta") { | |
return part.textDelta; | |
} | |
}) | |
.join(""); | |
console.log("textStream", textStream); | |
if (triggerInstance.run) { | |
console.log("run", triggerInstance.run); | |
const metadata = AgentLoopMetadata.safeParse(triggerInstance.run.metadata); | |
if (!metadata.success) { | |
console.error("Failed to parse metadata", metadata.error); | |
} else { | |
console.log("metadata", metadata.data); | |
setWaitToken(metadata.data); | |
} | |
} | |
return { | |
continueConversation: (prompt: string) => { | |
if (waitTokenInstance.isReady) { | |
waitTokenInstance.complete({ | |
message: prompt, | |
}); | |
} else { | |
const result = triggerInstance.submit({ | |
model: "gpt-4o-mini", | |
prompt, | |
}); | |
setConversation((prev) => [...prev, { role: "user", content: prompt }]); | |
return result; | |
} | |
}, | |
conversation, | |
isLoading, | |
}; | |
} | |
export function useAgentLoop({ publicAccessToken }: { publicAccessToken: string }) { | |
const triggerInstance = useRealtimeTaskTriggerWithStreams< | |
typeof agentLoopExample, | |
ResponseStreams | |
>("agent-loop-example", { | |
accessToken: publicAccessToken, | |
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | |
}); | |
const [conversation, setConversation] = useState<ChatConversation>([]); | |
const [isLoading, setIsLoading] = useState(false); | |
const [waitToken, setWaitToken] = useState<AgentLoopMetadata | null>(null); | |
const waitTokenInstance = useWaitToken(waitToken?.waitToken.id, { | |
enabled: !!waitToken?.waitToken.id, | |
accessToken: waitToken?.waitToken.publicAccessToken, | |
baseURL: process.env.NEXT_PUBLIC_TRIGGER_API_URL, | |
}); | |
const waitTokenStream = waitToken?.waitToken.id | |
? triggerInstance.streams[`responses.${waitToken?.waitToken.id}`] | |
: undefined; | |
const textStream = waitTokenStream | |
?.map((part) => { | |
if (part.type === "text-delta") { | |
return part.textDelta; | |
} | |
}) | |
.join(""); | |
// Use a logger with appropriate log levels | |
// logger.debug("textStream", textStream); | |
if (triggerInstance.run) { | |
console.log("run", triggerInstance.run); | |
const metadata = AgentLoopMetadata.safeParse(triggerInstance.run.metadata); | |
if (!metadata.success) { | |
console.error("Failed to parse metadata", metadata.error); | |
} else { | |
console.log("metadata", metadata.data); | |
setWaitToken(metadata.data); | |
} | |
} | |
return { | |
continueConversation: (prompt: string) => { | |
setIsLoading(true); | |
if (waitTokenInstance.isReady) { | |
waitTokenInstance.complete({ | |
message: prompt, | |
}).finally(() => { | |
setIsLoading(false); | |
}); | |
} else { | |
const result = triggerInstance.submit({ | |
model: "gpt-4o-mini", | |
prompt, | |
}).finally(() => { | |
setIsLoading(false); | |
}); | |
setConversation((prev) => [...prev, { role: "user", content: prompt }]); | |
return result; | |
} | |
}, | |
conversation, | |
isLoading, | |
}; | |
} |
for await (const chunk of stream) { | ||
if (chunk.type === "text-delta") { | ||
assistantResponse += chunk.textDelta; | ||
} | ||
} |
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
Include error handling for stream processing.
The stream processing loop lacks error handling. If the stream encounters errors during iteration, the current implementation might fail silently or disrupt the conversation flow.
- for await (const chunk of stream) {
- if (chunk.type === "text-delta") {
- assistantResponse += chunk.textDelta;
- }
- }
+ try {
+ for await (const chunk of stream) {
+ if (chunk.type === "text-delta") {
+ assistantResponse += chunk.textDelta;
+ }
+ }
+ } catch (error) {
+ logger.error("Error processing stream", { error });
+ assistantResponse += "\n[Error: Failed to process the complete response]";
+ }
📝 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.
for await (const chunk of stream) { | |
if (chunk.type === "text-delta") { | |
assistantResponse += chunk.textDelta; | |
} | |
} | |
try { | |
for await (const chunk of stream) { | |
if (chunk.type === "text-delta") { | |
assistantResponse += chunk.textDelta; | |
} | |
} | |
} catch (error) { | |
logger.error("Error processing stream", { error }); | |
assistantResponse += "\n[Error: Failed to process the complete response]"; | |
} |
Waitpoint PAT completion
You can now complete waitpoint tokens via Public Access Token authentication, and we automatically will generate a public access token capable of completion the waitpoint token when creating one:
You can also create Public Access Tokens separately:
We've also added a
useWaitToken
react hook to@trigger.dev/react-hooks
to make it easy to complete wait tokens from your React frontend:Fixes
This PR also includes the following fixes:
runId
to the Metadata Manager to fix the metadata flushingSummary by CodeRabbit
New Features
Improvements
Documentation