Tasks are GitHub Actions-style workflows that define multi-step actions in Julep. Think of them as recipes that tell an agent exactly how to accomplish a goal. For example, a task might outline the steps to “Summarize a Research Paper” or “Debug a Code Issue”.
name: Summarize Documentdescription: Create a concise summary of any documentinput_schema: type: object properties: document_text: type: string description: The text to summarize
⚠️ Workflow Input Size Warning: Avoid passing extremely large objects as input to your workflows, as this can cause execution failures. Large inputs (such as massive JSON objects, extensive arrays, or huge text files) may exceed memory limits or hit serialization constraints.What to do instead:
Break large data into smaller chunks and process them iteratively
Use file uploads and pass file references instead of raw content
Implement pagination for large datasets
Rule of thumb: If your input data is larger than a few megabytes, consider alternative approaches.
A task can be made up of multiple sub-workflows. These sub-workflows can be named and can be used to break down complex tasks into smaller, more manageable pieces.
YAML
Copy
name: Summarize Documentdescription: Create a concise summary of any documentsample_sub_workflow:- prompt: |- $ f'Tell me a joke about {steps[0].input.topic}:'main:- workflow: sample_sub_workflow arguments: topic: AI
In any step, you can access the input and output of a step using the steps[index].output or steps[index].input variable. For example:
Copy
- evaluate: topic: $ steps[0].input.topic
Copy
- evaluate: topic: $ steps[0].output.topic
In Julep, the steps are indexed from 0. So the first step is steps[0] and the second step is steps[1] and so on.
Furthermore the first step input is nothing but the task input and the last step output is nothing but the output of the task.
To learn more about how to use the $ variable and new syntax, please refer to the New Syntax section.
Input schemas help catch errors early by validating all inputs before execution starts.
Here’s how these components work together:
YAML
Copy
name: Process Customer Feedbackdescription: Analyze and categorize customer feedbackinput_schema: type: object required: ["feedback_text"] properties: feedback_text: type: string sentiment_analysis: type: boolean default: truetools:- name: get_weather_info type: integration integration: provider: weather setup: openweathermap_api_key: OPENWEATHERMAP_API_KEYmain:- tool: get_weather_info arguments: location: $ steps[0].input.location- prompt: |- $ f"""The weather in {steps[0].output.location} is the following: {steps[0].output.weather} <task> Analyze the weather and provide a summary of the weather in the location. Include some recommendations on what to wear based on the weather. </task> """
Here’s a simple task that summarizes a document and checks if the summary is too long. We first define the task in a YAML file and then create it using the Julep SDK.
Copy
name: Summarize Documentdescription: Create a concise summary of any documentinput_schema: type: object properties: document_text: type: string description: The text to summarizemain: - prompt: |- $ f'''Analyze the following text and create a summary: {steps[0].input.document_text}''' unwrap: true - evaluate: too_long: $ len(_) > 500 - if: $ _.too_long then: prompt: |- $ f'''Make the summary more concise: {steps[0].output}''' unwrap: true else: evaluate: content: $ steps[0].output
Check out the API reference here or SDK reference (Python here or JavaScript here for more details on different operations you can perform on tasks.
# Execute a taskexecution = client.executions.create( task_id=task.id, input={ "document_text": "This is a sample document" })# Monitor progresswhile True: result = client.executions.get(execution.id) if result.status in ["succeeded", "failed"]: break time.sleep(1)
Check out the API reference here or SDK reference (Python here or JavaScript here for more details on different operations you can perform on tasks.
Julep agents can power tasks by providing memory, context, or tools. Tasks are multi-step workflows designed for complex, automated execution. Whenever you create a task, you can associate it with an agent if you want to leverage that agent’s capabilities. Unlike sessions, tasks are not meant for real-time interaction; they run through a defined workflow to achieve a goal.For example:
Copy
import yaml# Create an agentagent = client.agents.create( name="Customer Support Agent", about="An agent that handles customer support requests", model="gpt-4o",)# Add a tool to the agentclient.agents.tools.create( agent_id=agent.id, **yaml.safe_load(""" name: send_email type: integration integration: provider: email method: send setup: host: "smtp.example.com" port: 587 user: "your_username" password: "your_password" """),)# Create a task that inherits this tooltask = client.tasks.create( agent_id=agent.id, **yaml.safe_load(""" name: Handle Support Request # Make sure to set this to true if you want to inherit tools from the agent inherit_tools: true input_schema: type: object properties: customer_email: type: string description: The email of the customer subject: type: string body: type: string description: The body of the email main: - prompt: - role: system content: You are a customer support agent who works for Julep AI. You will be given a support request from a customer. You will need to handle the request by sending a reply email to the customer. - role: user content: |- $ f"""Handle the support request from this email: {steps[0].input.customer_email} The subject of the email is this: {steps[0].input.subject} --- The body of the email is this: {steps[0].input.body} """ unwrap: true - tool: send_email arguments: to: $ steps[0].input.customer_email from: "[email protected]" subject: "$ f'Re: {steps[0].input.subject}'" body: $ steps[0].output """))
Task can leverage tools to perform complex operations. There are 2 ways of defining tools for tasks:
Associate a tool with an agent, and inherit it in the task definition by setting inherit_tools to true while creating the task. Example:
Copy
client.agents.tools.create( agent_id="agent_id", **yaml.safe_load(""" name: get_weather_info type: integration integration: provider: weather setup: openweathermap_api_key: "your_openweathermap_api_key" """)task = client.tasks.create( agent_id="agent_id", **yaml.safe_load(""" name: Get Weather Info inherit_tools: true main: - tool: get_weather_info arguments: location: New York """))
Define a tool in the task definition. Example:
Copy
task = client.tasks.create( agent_id="agent_id", **yaml.safe_load(""" name: Get Weather Info tools: - name: get_weather_info type: integration integration: provider: weather setup: openweathermap_api_key: "your_openweathermap_api_key" main: - tool: get_weather_info arguments: location: New York """))
When you define a tool in the task definition, it is available to all steps in that task only. On the other hand, when you associate a tool with an agent, it is available to all the Tasks associated with that agent.