Skip to content
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

Merged
merged 6 commits into from
Mar 27, 2025

Conversation

ericallam
Copy link
Member

@ericallam ericallam commented Mar 27, 2025

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:

const token = await wait.createToken();

await auth.withAuth(
  {
    accessToken: token.publicAccessToken,
  },
  async () => {
    await wait.completeToken(token.id, { status: "approved" });
  }
);

You can also create Public Access Tokens separately:

const publicAccessToken = await auth.createPublicToken({
  scopes: {
    write: {
      waitpoints: token.id,
    },
  },
  expirationTime: "1h",
});

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:

import { useWaitToken } from '@trigger.dev/react-hooks';
import type { myTask } from './path/to/task';

const { complete, isLoading, isCompleted, error } = useWaitToken('waitpoint-id');
// Complete the waitpoint with an output
complete({ foo: 'bar' });

Fixes

This PR also includes the following fixes:

  • Dequeueing a run that doesn't have a retry config no longer fails
  • Assign the runId to the Metadata Manager to fix the metadata flushing
  • Completing waitpoints multiple times now works as expected

Summary by CodeRabbit

  • New Features

    • Enhanced API endpoints with JWT authentication and detailed response headers.
    • Introduced public token support and expanded authorization to include waitpoints.
    • Added a custom React hook for managing asynchronous wait tokens and new chat interface components in sample projects.
  • Improvements

    • Streamlined error handling, logging, and data processing for improved stability and type safety.
  • Documentation

    • Updated configuration files and project documentation to simplify setup and deployment.

Copy link

changeset-bot bot commented Mar 27, 2025

⚠️ No Changeset found

Latest commit: 90e2598

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Copy link
Contributor

coderabbitai bot commented Mar 27, 2025

Walkthrough

This 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

File(s) Summary of Changes
apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpoint...complete.ts
apps/webapp/app/routes/api.v1.waitpoints.tokens.ts
apps/webapp/app/services/authorization.server.ts
Added new loader export; enhanced API route configuration with JWT, authorization, CORS properties; introduced responseHeaders for JWT claims; expanded resource types with “waitpoints”.
internal-packages/run-engine/src/engine/errors.ts
.../dequeueSystem.ts
.../waitpointSystem.ts
Simplified error handling by removing retry config errors; refactored waitpoint completion to use try-catch and direct Prisma client calls.
packages/cli-v3/src/entryPoints/dev-run-worker.ts
.../managed-run-worker.ts
Assigned runId to runMetadataManager during the execution of EXECUTE_TASK_RUN messages.
packages/core/src/v3/apiClient/core.ts
.../apiClient/index.ts
packages/core/src/v3/errors.ts
packages/core/src/v3/logger/*
packages/core/src/v3/tracer.ts
packages/core/src/v3/workers/taskExecutor.ts
packages/core/src/v3/schemas/common.ts
Updated API client types and method signatures; introduced CreateWaitpointTokenResponse and new error class CompleteTaskWithOutput; modified logger and tracer to use new TraceOptions; refined retry logic and error processing in task executor.
packages/react-hooks/src/hooks/useWaitToken.ts
packages/react-hooks/src/index.ts
packages/trigger-sdk/src/v3/auth.ts
.../index.ts
packages/trigger-sdk/src/v3/wait.ts
Added new useWaitToken React hook; expanded token response types; added optional waitpoints property in authentication types; exported CompleteTaskWithOutput in Trigger SDK.
Multiple files under references/agent-loop/ Introduced a full Next.js agent loop project with new config files (.gitignore, README, package.json, Tailwind, PostCSS, tsconfig, etc.), React components (chat interface, initial prompt, main app), utility functions, agent task, and schema definitions.
references/hello-world/src/trigger/waits.ts Modified the waitToken task to accept an optional completeWithPublicToken parameter, enabling public access token generation and authenticated token completion.

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
Loading
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
Loading

Poem

I’m a rabbit who loves to hop,
Over code hills without a stop.
New tokens, errors, and hooks all in line,
A joyful dance in logic so fine.
With each update, I bounce with glee,
Celebrating changes as happy as can be!
🐇💻 Hop on, let’s code and be free!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46b3020 and 90e2598.

📒 Files selected for processing (1)
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.complete.ts
⏰ 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)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 issue

Update NoopTaskLogger to match new method signatures.

The NoopTaskLogger implementation needs to be updated to match the new method signatures that use the TraceOptions 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 of nextConfig 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 ID

The 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:

  1. Consider adding a timestamp or ID to the Message interface for better key management
  2. 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:

  1. Integration with the useAgentLoop hook
  2. State management for user input
  3. Form handling with empty message prevention
  4. Conditional rendering of initial prompt or chat interface
  5. 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 code

This 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 tokens

The 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 for MAX_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

📥 Commits

Reviewing files that changed from the base of the PR and between be02439 and 46b3020.

⛔ 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 of NextConfig 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 of nextConfig 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 and next-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 just tailwindcss.

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 tailwindcss

Always 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:


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 include autoprefixer.

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 good

Adding 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 pattern

The 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:

  1. Imports the required dependencies
  2. Creates a public access token asynchronously
  3. 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 uses clsx to combine class names and twMerge 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 the runMetadataManager 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 to PublicTokenPermissionProperties 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

  1. Dependency Management:

    Peer dependency conflicts may require installation flags:

    npm install --force # OR npm install --legacy-peer-deps
  2. API Changes:

    • useFormStateuseActionState[5]
    • New async APIs for cookies/headers[5]:
    const cookieStore = await cookies() // Async in React 19
  3. Third-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:


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:

  1. It ensures that spans are properly concluded even when tasks complete with output
  2. It prevents span leaks and improves tracing accuracy
  3. 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:

  1. Wraps the existing functionality in a try-catch block
  2. Checks for specialized error type before re-throwing
  3. 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:

  1. Creates a JSON string containing sub (subject) and pub (public) claims
  2. 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:

  1. The class extends the base Error class
  2. It stores the output in a readonly property
  3. 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:

  1. Returns a boolean indicating if the error is an instance of CompleteTaskWithOutput
  2. Uses the return type error is CompleteTaskWithOutput for type narrowing
  3. 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> to ApiPromise<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:

  1. When completeWithPublicToken is true, the token is completed using auth.withAuth with the public token
  2. 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 in undefined 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 an undefined 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, in dequeueSystem.ts a log entry indicates that if maxAttempts 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 an undefined 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:

  1. Uses the "use" prefix for a custom hook
  2. Employs SWR for efficient state management
  3. Provides clear error handling for missing tokens or API access
  4. 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 setup

The 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 controls

The route now properly exports both action and loader functions, adds JWT authentication support, and defines specific authorization requirements for waitpoints.


80-80: Export updated to include loader function

The 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 SpanOptions

The 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 custom TraceOptions type instead of OpenTelemetry's SpanOptions.


🏁 Script executed:

#!/bin/bash
# Verify that all callers of this method are using compatible options
rg -A 2 "\.startSpan\(" --type typescript

Length 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 custom TraceOptions. 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 custom TraceOptions type instead of the generic OpenTelemetry SpanOptions, while still returning an OpenTelemetry Span.


🏁 Script executed:

#!/bin/bash
# Verify that all callers of this method are using compatible options
rg -A 2 "\.trace\(" --type typescript

Length of output: 74


Action Required: Please verify that all call sites of the trace method correctly use the updated custom TraceOptions.

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 and tsx). 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 tsx

This 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 tokens

The new CreateWaitpointTokenResponse type enhances the original response by including a publicAccessToken property, which will provide clients with the necessary authentication token.


227-227: Parameter order changed in destructuring assignment

The 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 assignment

Similar to the previous instance, the parameter order has been changed for consistency.


760-763: Simplified request options for completeWaitpointToken

The 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 and tryCatch 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 both waitpoint and affectedTaskRuns. 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 of completeWaitpoint 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, extending SpanOptions with an optional icon property. Using Prettify ensures the resulting type is more readable in IDE tooltips.


33-34: Updated method signatures with enhanced type safety.

The method signatures for trace and startSpan have been updated to use the new TraceOptions 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 the icon property, setting the STYLE_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 as trace, 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 to TData for the generic parameter provides better semantic clarity about the data being handled. The updated method signatures for onResponseBody and prepareData 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.

Comment on lines +20 to +86
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,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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:

  1. State management for conversation, loading status, and wait tokens
  2. Integration with trigger.dev hooks for real-time task triggering and waiting
  3. Stream processing for text responses
  4. Metadata parsing with appropriate error handling
  5. Helper method for continuing conversations

A few minor concerns to consider:

  1. 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);
  1. 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.

Suggested change
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,
};
}

Comment on lines +60 to +64
for await (const chunk of stream) {
if (chunk.type === "text-delta") {
assistantResponse += chunk.textDelta;
}
}
Copy link
Contributor

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.

Suggested change
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]";
}

@ericallam ericallam merged commit 0e82698 into main Mar 27, 2025
12 checks passed
@ericallam ericallam deleted the v4/frontend-waitpoint-completion branch March 27, 2025 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants