Agent Runtime
Installation

Start a new Agent Runtime Project

To create a new Agent Runtime project, run the following command:

npm create agent-runtime@latest

This should scaffold out the following files:

  • src/agent.ts - The main agent file.
  • src/tools - A directory for custom tools.
  • src/prompts - A directory for custom prompts.
  • src/types - A directory for custom types.

We'll primarily be working in the src/agent.ts file to build out the agent.

Run the agent

To run the agent, run the following command:

npm run dev

This will start the agent in development mode, which will hot reload as you make changes.

Understanding how agents work

Agent Runtime uses a fuzzy happy path approach to building agents. You define the happy path, which is the main logic of the agent. For example, let's build a podcast generator agent.

Let's review the src/agent.ts file to see what a happy path looks like.

const agent = createAgent({
  input: z.object({
    blogPost: z.url(),
  }),
  happyPath: (input) => ([
    do(`Fetch the HTML content from the ${input.blogPost} and extract out only the article portion of the HTML. Remove any HTML tags and return only the text.`).with(fetch),
    do('Generate a podcast script based on the article, split it into two speakers and about 10 minutes long. Come up with a personable example about the topic for the blog post content. Make sure to highlight a specific problem that the authors have had before and now based on the blog post content, it is solved.').as({
      script: z.array(z.object({
        speaker: z.string(),
        content: z.string(),
      })),
    }),
    run(async ({ state }) => {
      const voices = await Promise.all(state.script.map(async (item) => {
        const voice = await elevenLabs(item.speaker, item.content);
        return {
          speaker: item.speaker === 'bob' ? 'Will (US male)' : 'Matilda (US female)',
          audio: voice,
        };
      }));
 
      const podcast = joinAudioFiles(voices.map((voice) => voice.audio));
 
      fileStorage.upload(`${state.blogPost.title}-${Date.now()}.mp3`, podcast);
    })
  ])
});

This is a happy path that will be executed if the agent is able to complete the happy path. If the agent is unable to complete the happy path, it will self-correct based on goals and guardrails.

Goals and guardrails

Goals and guardrails are used to guide the agent's behavior if the happy path fails. Goals are used to make sure the agent is on track to achieve the desired outcome (moving into the right direction). Guardrails are used to make sure the agent is not deviating from the happy path (prevents harmful deviations from the happy path).

Visual representation of goals and guardrails

You want to be careful with guardrails as the benefits of agents are their ability to dynamically adjust to non-deterministic environments. Overusing guardrails can make the agent rigid and less able to adapt to an unexpected situation.

Use goals to guide the agent's behavior

Goals are used to guide the agent's behavior towards the desired outcome. For example, you can define the purpose of the podcast. Is it for marketing, education, or entertainment?

const agent = createAgent({
  goals: ["An agent that generates a podcast script based on a blog post for marketing purposes. Make sure it's not overly obvious that it's a marketing podcast. Keep the product placement subtle and natural. Instead highlight the problem that the product solves. Make sure to include a call to action at the end of the podcast."],
  input: z.object({
    blogPost: z.url(),
  }),
  happyPath: (input) => ([
    // ...
  ]),
});

Use guardrails to guide the agent's behavior

Guardrails are used to guide the agent's behavior if the happy path fails. For example, if the agent generates a script that is too long. We can generate a guardrail to ask the agent to self-correct and shorten the script.

const agent = createAgent({
  input: z.object({
    blogPost: z.url(),
  }),
  guardrails: [
    check("if the script is too long by approximating the time it takes to read the script. Calculate the time it takes to read by summing up the number of words in the script and divide it by 110. If it's beyond 12 minutes").then("shorten the script to a bit fewer words")
  ],
  happyPath: (input) => ([
    // ...
  ]),
});

Agent Runtime will automatically configure a "judge" agent to evaluate the guardrails and make sure the agent is following the happy path correctly.

In this case, we defined the guardrail in natural language, however, where possible, Agent Runtime will automatically guardrails into programmatic, determinstic code to reduce the agent's cost and latency. Think of Agent Runtime having a built-in code interpreter. If you want to define a guardrail in code, you can do so by returning a function from the guardrail.

const agent = createAgent({
  input: z.object({
    blogPost: z.url(),
  }),
  guardrails: [
    check("if the script is too long", run((script) => {
      const wordCount = script.split(' ').length
      const timeToRead = wordCount / 110
 
      if (timeToRead > 12) {
        return do("shorten the script to a bit fewer words")
      }
 
      return do("keep the script as is")
    }))
  ],
  happyPath: (input) => ([
    // ...
  ]),
});

On this page