惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 聂微东
爱范儿
爱范儿
Jina AI
Jina AI
博客园 - Franky
IT之家
IT之家
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
M
MIT News - Artificial intelligence
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
人人都是产品经理
人人都是产品经理
腾讯CDC
博客园_首页
月光博客
月光博客
有赞技术团队
有赞技术团队
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
MyScale Blog
MyScale Blog

Workflow SDK Documentation

Patterns for Defining Tools Human-in-the-Loop Building Durable AI Agents Queueing User Messages Resumable Streams Streaming Updates from Tools API Reference Workflow Globals Changelog Resilient run start Cookbook Building a World Deploying Astro Express Fastify Hono Getting Started NestJS Next.js Nitro Nuxt Python SvelteKit Vite corrupted-event-log fetch-in-workflow hook-conflict Errors node-js-module-in-workflow
Sleep, Suspense, and Scheduling
2026-05-31 · via Workflow SDK Documentation

Schedule recurring actions, handle rate limiting, and wait for external state in AI agents.

AI agents sometimes need to pause execution in order to schedule recurring or future actions, wait before retrying an operation (e.g. for rate limiting), or wait for external state to be available.

Workflow SDK's sleep function enables Agents to pause execution without consuming resources, and resume at a specified time, after a specified duration, or in response to an external event. Workflow operation that suspend will survive restarts, new deploys, and infrastructure changes, independent of whether the suspense takes seconds or months.

See the sleep() API Reference for the full list of supported duration formats and detailed API documentation, and see the hooks documentation for more information on how to resume in response to external events.

Sleep is a built-in function in Workflow SDK, so exposing it as a tool is as simple as wrapping it in a tool definition. Learn more about how to define tools in Patterns for Defining Tools.

Define the Tool

Add a new "sleep" tool to the tools defined in workflows/chat/steps/tools.ts:

import { getWritable, sleep } from "workflow"; 

// ... existing imports ...

async function executeSleep( 
  { durationMs }: { durationMs: number }, 
) { 
  // Note: No "use step" here - sleep is a workflow-level function
  await sleep(durationMs); 
  return { message: `Slept for ${durationMs}ms` }; 
}

// ... existing tool functions ...

export const flightBookingTools = {
 // ... existing tool definitions ...
 sleep: { 
  description: "Pause execution for a specified duration", 
  inputSchema: z.object({ 
    durationMs: z.number().describe("Duration to sleep in milliseconds"), 
  }), 
  execute: executeSleep, 
 } 
}

Note that the sleep() function must be called from within a workflow context, not from within a step. This is why executeSleep does not have "use step" - it runs in the workflow context where sleep() is available.

This already makes the full sleep functionality available to the Agent!

Show the tool status in the UI

To round it off, extend the UI to display the tool call status. This can be done either by displaying the tool call information directly, or by emitting custom data parts to the stream (see Streaming Updates from Tools for more details). In this case, since there aren't any fine-grained progress updates to show, we'll just display the tool call information directly:

export default function ChatPage() {

  // ...

  const { stop, messages, sendMessage, status, setMessages } =
    useChat<MyUIMessage>({
      // ... options
    });

  // ...

  return (
    <div className="flex flex-col w-full max-w-2xl pt-12 pb-24 mx-auto stretch">
      // ...

      <Conversation className="mb-10">
        <ConversationContent>
          {messages.map((message, index) => {
            const hasText = message.parts.some((part) => part.type === "text");

            return (
              <div key={message.id}>
                // ...
                <Message from={message.role}>
                  <MessageContent>
                    {message.parts.map((part, partIndex) => {

                      // ...

                      if (
                        part.type === "tool-searchFlights" ||
                        part.type === "tool-checkFlightStatus" ||
                        part.type === "tool-getAirportInfo" ||
                        part.type === "tool-bookFlight" ||
                        part.type === "tool-checkBaggageAllowance"
                        part.type === "tool-sleep"
                      ) {
                        // ...
                      }
                      return null;
                    })}
                  </MessageContent>
                </Message>
              </div>
            );
          })}
        </ConversationContent>
        <ConversationScrollButton />
      </Conversation>

      // ...
    </div>
  );
}

function renderToolOutput(part: any) {
  // ...
  switch (part.type) {
    // ...
    case "tool-sleep": { 
      return ( 
        <div className="space-y-2">
          <p className="text-sm font-medium">Sleeping for {part.input.durationMs}ms...</p>
        </div>
      ); 
    }
    // ...
}

Now, try out the Flight Booking Agent again, and ask it to sleep for 10 seconds before checking any flight. You'll see the agent pause, and the UI reflect the tool call status.

Aside from providing sleep() as a tool, there are other use cases for Agents that commonly call for suspension and resumption.

Rate Limiting

When hitting API rate limits, use RetryableError with a delay:

import { RetryableError } from "workflow";

async function callRateLimitedAPI(endpoint: string) {
  "use step";

  const response = await fetch(endpoint);

  if (response.status === 429) {
    const retryAfter = response.headers.get("Retry-After");
    throw new RetryableError("Rate limited", {
      retryAfter: retryAfter ? parseInt(retryAfter) * 1000 : "1m",
    });
  }

  return response.json();
}