- Completed steps are replayed instantly from the journal
- LLM calls are not repeated (saving cost and time)
- Regular steps (API calls, payments) are not duplicated
Example: insurance claim reimbursement
This workflow processes an insurance claim through four steps: two agentic steps that use an LLM to understand unstructured data, and two traditional steps that call external APIs.Vercel AI
OpenAI Agents
Google ADK
Pydantic AI
LangChain
Restate TS
Restate Py
workflow-sequential.ts
const process = async (ctx: Context, {prompt}: {prompt: string}) => {
const model = wrapLanguageModel({
model: openai("gpt-5.4"),
middleware: durableCalls(ctx, { maxRetryAttempts: 3 }),
});
// Step 1: Parse the claim document (LLM step)
const { output } = await generateText({
model,
system:
"Extract the claim amount, currency, category, and description.",
prompt,
output: Output.object({schema: ClaimData})
});
// Step 2: Analyze the claim (LLM step)
const { output: valid } = await generateText({
model,
system:
"You are a claims analyst. Assess whether this claim is valid and determine the approved amount.",
prompt: `Claim: ${JSON.stringify(output)}`,
output: Output.object({schema: z.object({valid: z.boolean()})}),
});
if (!valid) {
return { analysis: "Claim is invalid", amountUsd: 0, confirmation: false };
}
// Step 3: Convert currency (regular step)
const amountUsd = await ctx.run("Convert currency", async () =>
convertCurrency(output.amount, output.currency, "USD"),
);
// Step 4: Process reimbursement (regular step)
const confirmation = await ctx.run("Process payment", async () =>
processPayment(ctx.rand.uuidv4(), amountUsd),
);
return { analysis: "Claim is valid", amountUsd, confirmation };
};
Run this example
Run this example
Install Restate and launch it:Get the example:Export your OpenAI API key and run the agent:Register the agents with Restate:Send a request to the agent:
npm install --global @restatedev/restate-server@latest @restatedev/restate@latest
restate-server
restate example typescript-vercel-ai-tour-of-agents && cd typescript-vercel-ai-tour-of-agents
npm install
export OPENAI_API_KEY=sk-...
npx tsx ./src/workflow-sequential.ts
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"prompt": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'
workflow_sequential.py
claim_service = restate.Service("ClaimReimbursement")
@claim_service.handler()
async def process(ctx: restate.Context, req: ClaimPrompt) -> dict:
# Step 1: Parse the claim document (LLM step)
parse_agent = Agent(
name="DocumentParser",
instructions="Extract the claim amount, currency, category, and description.",
output_type=ClaimData,
)
parsed = await DurableRunner.run(parse_agent, req.message)
claim = parsed.final_output
# Step 2: Analyze the claim (LLM step)
analysis_agent = Agent(
name="ClaimsAnalyst",
instructions="Assess whether this claim is valid and determine the approved amount.",
)
analysis = await DurableRunner.run(
analysis_agent, f"Claim: {parsed.final_output.model_dump_json()}"
)
# Step 3: Convert currency (regular step)
amount_usd = await ctx.run_typed(
"Convert currency",
convert_currency,
amount=claim.amount,
source=claim.currency,
target="USD",
)
# Step 4: Process reimbursement (regular step)
confirmation = await ctx.run_typed(
"Process payment",
process_payment,
claim_id=str(ctx.uuid()),
amount=amount_usd,
)
return {
"analysis": analysis.final_output,
"amount_usd": amount_usd,
"confirmation": confirmation,
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your OpenAI API key and run the agent:Register the agents with Restate:Send a request:
restate-server
restate example python-openai-agents-tour-of-agents && cd python-openai-agents-tour-of-agents
export OPENAI_API_KEY=sk-...
uv run app/workflow_sequential.py
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"message": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'
workflow_sequential.py
parse_agent = Agent(
model="gemini-2.5-flash",
name="document_parser",
instruction="Extract the claim amount, currency, category, and description.",
output_schema=ClaimData,
)
parse_app = App(name="claims", root_agent=parse_agent, plugins=[RestatePlugin()])
parse_runner = Runner(app=parse_app, session_service=RestateSessionService())
analysis_agent = Agent(
model="gemini-2.5-flash",
name="claims_analyst",
instruction="Assess whether this claim is valid and determine the approved amount.",
)
analysis_app = App(name="claims", root_agent=analysis_agent, plugins=[RestatePlugin()])
analysis_runner = Runner(app=analysis_app, session_service=RestateSessionService())
claim_service = restate.VirtualObject("ClaimReimbursement")
@claim_service.handler()
async def process(ctx: restate.ObjectContext, req: ClaimPrompt) -> dict:
# Step 1: Parse the claim document (LLM step)
parsing_events = parse_runner.run_async(
user_id=ctx.key(),
session_id=req.session_id,
new_message=Content(role="user", parts=[Part.from_text(text=req.message)]),
)
parsed = await parse_agent_response(parsing_events)
claim = ClaimData.model_validate_json(parsed)
# Step 2: Analyze the claim (LLM step)
analysis_events = analysis_runner.run_async(
user_id=ctx.key(),
session_id=req.session_id,
new_message=Content(role="user", parts=[Part.from_text(text=parsed)]),
)
analysis = await parse_agent_response(analysis_events)
# Step 3: Convert currency (regular step)
amount_usd = await ctx.run_typed(
"Convert currency",
convert_currency,
amount=claim.amount,
source=claim.currency,
target="USD",
)
# Step 4: Process reimbursement (regular step)
confirmation = await ctx.run_typed(
"Process payment",
process_payment,
claim_id=str(ctx.uuid()),
amount=amount_usd,
)
return {
"analysis": analysis,
"amount_usd": amount_usd,
"confirmation": confirmation,
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your Google API key and run the agent:Register the agents with Restate:Send a request:
restate-server
restate example python-google-adk-tour-of-agents && cd python-google-adk-tour-of-agents
export GOOGLE_API_KEY=your-api-key
uv run app/workflow_sequential.py
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/user123/process \
--json '{
"sessionId": "session-123",
"message": "Hospital bill for a broken leg. Amount: 3000 EUR. Date: 2024-10-01. Hospital: General Hospital."
}'
workflow_sequential.py
parse_agent = Agent(
"openai:gpt-5.4",
system_prompt="Extract the claim amount, currency, category, and description.",
output_type=ClaimData,
)
restate_parse_agent = RestateAgent(parse_agent)
analysis_agent = Agent(
"openai:gpt-5.4",
system_prompt="Analyze the claim and approve/deny it.",
output_type=bool,
)
restate_analysis_agent = RestateAgent(analysis_agent)
claim_service = restate.Service("ClaimReimbursement")
@claim_service.handler()
async def process(ctx: restate.Context, req: ClaimPrompt) -> dict:
# Step 1: Parse the claim document (LLM step)
parsed = await restate_parse_agent.run(req.message)
claim = parsed.output
# Step 2: Analyze the claim (LLM step)
approved = await restate_analysis_agent.run(f"Claim: {claim.model_dump_json()}")
if not approved.output:
return {"analysis": "Claim is invalid", "amountUsd": 0, "confirmation": False}
# Step 3: Convert currency (regular step)
amount_usd = await ctx.run_typed(
"Convert currency",
convert_currency,
amount=claim.amount,
source=claim.currency,
target="USD",
)
# Step 4: Process reimbursement (regular step)
confirmation = await ctx.run_typed(
"Process payment",
process_payment,
claim_id=str(ctx.uuid()),
amount=amount_usd,
)
return {
"analysis": "Claim is valid.",
"amount_usd": amount_usd,
"confirmation": confirmation,
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your OpenAI API key and run the agent:Register the agents with Restate:Send a request:
restate-server
restate example python-pydantic-ai-tour-of-agents && cd python-pydantic-ai-tour-of-agents
export OPENAI_API_KEY=sk-...
uv run app/workflow_sequential.py
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"message": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'
workflow_sequential.py
parse_agent = create_agent(
model=init_chat_model("openai:gpt-5.4"),
system_prompt="Extract the claim amount, currency, category, and description.",
response_format=ClaimData,
middleware=[RestateMiddleware()],
)
analysis_agent = create_agent(
model=init_chat_model("openai:gpt-5.4"),
system_prompt="Assess whether this claim is valid and determine the approved amount.",
middleware=[RestateMiddleware()],
)
claim_service = restate.Service("ClaimReimbursement")
@claim_service.handler()
async def process(ctx: restate.Context, req: ClaimPrompt) -> dict:
# Step 1: Parse the claim document (structured-output LLM step).
parsed = await parse_agent.ainvoke({"messages": req.message})
claim = parsed["structured_response"]
# Step 2: Analyze the claim (LLM step).
analysis = await analysis_agent.ainvoke({"messages": claim.model_dump_json()})
# Step 3: Convert currency (regular durable step).
amount_usd = await ctx.run_typed(
"Convert currency",
convert_currency,
amount=claim.amount,
source=claim.currency,
target="USD",
)
# Step 4: Process reimbursement (regular durable step).
confirmation = await ctx.run_typed(
"Process payment",
process_payment,
claim_id=str(ctx.uuid()),
amount=amount_usd,
)
return {
"analysis": analysis["messages"][-1].content,
"amount_usd": amount_usd,
"confirmation": confirmation,
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your OpenAI API key and run the agent:Register the agents with Restate:Send a request:
restate-server
restate example python-langchain-tour-of-agents && cd python-langchain-tour-of-agents
export OPENAI_API_KEY=sk-...
uv run app/workflow_sequential.py
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"message": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'
workflow-sequential.ts
async function process(ctx: Context, { message }: { message: string }) {
// Step 1: Parse the claim document (LLM step)
const { output } = await ctx.run(
"Parse claim",
async () => {
const { output } = await generateText({
model: openai("gpt-5.4"),
prompt: `Extract the claim amount, currency, category, and description. Input: ${message}`,
output: Output.object({ schema: ClaimData }),
});
return { output };
},
{ maxRetryAttempts: 3 },
);
// Step 2: Evaluate the claim (LLM step)
const { valid } = await ctx.run(
"Evaluate claim",
async () => {
const { output: valid } = await generateText({
model: openai("gpt-5.4"),
system:
"You are a claims analyst. Assess whether this claim is valid and determine the approved amount.",
prompt: `Claim: ${JSON.stringify(output)}`,
output: Output.object({schema: z.object({valid: z.boolean()})}),
});
return valid;
},
{ maxRetryAttempts: 3 },
);
if (!valid) {
return { analysis: "Claim is invalid", amountUsd: 0, confirmation: false };
}
// Step 3: Convert currency (regular step)
const amountUsd = await ctx.run("Convert currency", async () =>
convertCurrency(output.amount, output.currency, "USD"),
);
// Step 4: Process reimbursement (regular step)
const confirmation = await ctx.run("Process payment", async () =>
processPayment(ctx.rand.uuidv4(), amountUsd),
);
return { analysis: "Claim is valid", amountUsd, confirmation };
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your API key:Register the services with Restate:Send a request:
restate-server
restate example typescript-restate-tour-of-agents && cd typescript-restate-tour-of-agents
npm install
export OPENAI_API_KEY=sk-...
npx tsx ./src/workflow-sequential.ts
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"message": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'
workflow_sequential.py
claim_service = restate.Service("ClaimReimbursement")
@claim_service.handler()
async def process(ctx: restate.Context, req: ClaimPrompt) -> dict:
"""Sequentially chains LLM calls with regular function calls to process a claim."""
# Step 1: Parse the claim document (LLM step)
parsed = await ctx.run_typed(
"Parse claim document",
llm_call,
RunOptions(max_attempts=3),
messages=f"""Extract the claim amount, currency, category, and description.
Document: {req.message}""",
response_format=ClaimData,
)
if not parsed.content:
raise restate.TerminalError("LLM failed to parse claim document.")
claim = ClaimData.model_validate_json(parsed.content)
# Step 2: Analyze the claim (LLM step)
response = await ctx.run_typed(
"Evaluate claim",
llm_call,
RunOptions(max_attempts=3),
messages=f"""Assess whether this claim is valid and determine the approved amount.
Claim: {parsed.content}""",
response_format=ClaimEvaluation,
)
if not response.content:
raise restate.TerminalError("LLM failed to analyze claim.")
evaluation = ClaimEvaluation.model_validate_json(response.content)
if not evaluation.valid:
return {"analysis": "Claim is invalid."}
# Step 3: Convert currency (regular step)
amount_usd = await ctx.run_typed(
"Convert currency",
convert_currency,
amount=claim.amount,
source=claim.currency,
target="USD",
)
# Step 4: Process reimbursement (regular step)
confirmation = await ctx.run_typed(
"Process payment",
process_payment,
claim_id=str(ctx.uuid()),
amount=amount_usd,
)
return {
"analysis": "Claim is valid.",
"amount_usd": amount_usd,
"confirmation": confirmation,
}
Run this example
Run this example
Install Restate and launch it:Get the example:Export your API key:Register the services with Restate:Send a request:
restate-server
restate example python-restate-tour-of-agents && cd python-restate-tour-of-agents
export OPENAI_API_KEY=sk-...
uv run app/workflow_sequential.py
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
curl localhost:8080/restate/call/ClaimReimbursement/process --json '{
"message": "Process my hospital bill of 2024-10-01 for 3000USD for a broken leg at General Hospital."
}'