What are Actions?

Actions are discrete tasks that your AI agent can perform. They are:

  • Type-safe and predictable
  • Parameter-driven with state awareness
  • Reusable across agents
  • Modular and single responsibility

Creating Actions

Use the createAction function to define actions:

import { createAction } from "spinai";

export const sum = createAction({
  id: "sum",
  description: "Adds two numbers together.",
  parameters: {
    type: "object",
    properties: {
      a: { type: "number", description: "First number to add" },
      b: { type: "number", description: "Second number to add" },
    },
    required: ["a", "b"],
  },
  async run({ parameters }) {
    const { a, b } = parameters || {};
    const result = a + b;
    return result;
  },
});

Using context.state in actions

In some cases, you may want to use a specific value you’ve stored in state either in a previous action or in the initial agent call. You can do this by using the context.state object. This is useful if the value is static, like a user ID or email, which may not make sense to have an LLM determine via parameters.

import { createAction } from "spinai";

export const getUserInfo = createAction({
  id: "getUserInfo",
  description: "Gets user information.",
  async run({ context }) {
    const { state } = context || {};
    const userId = state?.userId;
    const user = await getUserById(userId);
    return user;
  },
});

Setting context.state in actions

In other cases, you may want to set a value in state after an action has completed. This is different than returning the value, since state can be reliable accessed within other actions, or after the agent call is done, without being stored in the agent’s message history. Return values however, are only accessible within the agent’s message, and can be used by the agent as parameters for other actions.

import { createAction } from "spinai";

export const getUserInfo = createAction({
  id: "getUserInfo",
  description: "Gets user information.",
  async run({ context }) {
    const { state } = context || {};
    const userId = state?.userId;
    const user = await getUserById(userId);
    context.state.userEmail = user.email;
    return user;
  },
});

Context vs Parameters

Parameters are values your agent passes into actions. They are dynamically determined by the LLM during the task loop and are based on the action’s parameter schema.

Context is the runtime environment that your agent has access to. It includes the state object, which is used to store and retrieve values between actions, as well as all the information you configured your agent with. This includes the input variable that you called the agent with. See Agents for a full list of all available context variables.

Returning vs context.state setting

When you return a value from an action, it allows your agent to use the value as a parameter for other actions if needed. However, it is only accessible within the agent’s message history, and to use it in actions you’ll need add it as a parameter.

On the other hand, when you set a value in context.state, it is accessible in other actions during runtime, and after the agent call is complete from the state variable.

Best practices:

  • Use context.state for values that need to be shared between actions that are robust. Things like customer emails, user IDs, etc.
  • Use parameters for values that are dynamic and need to be determined by the LLM during the task loop.

Next Steps