PAIPAI

Tool Context

How a tool gets workspace, services, and identity without ctx.identity.

A tool only sees ctx.context. That value is either:

  1. The agent's runtimeContext, when it already matches the tool, or
  2. The result of mapContext at registration, when the tool needs a narrower shape.

There is no ambient caller. If the tool needs workspaceId, put it in context.

Declare what the tool needs

export const lookupCustomer = defineTool({
  id: "lookupCustomer",
  description: "Read a customer by id",
  inputSchema: z.object({ customerId: z.string() }),
  outputSchema: z.object({ name: z.string() }),
  contextSchema: z.object({
    customerStore: z.custom<CustomerStore>(),
  }),
  execute: async (ctx) => {
    return ctx.context.customerStore.read(ctx.input.customerId);
  },
});

contextSchema is for TypeScript and for the runtime to reject a bad registration. It is not sent to the model.

Same shape as the agent

If runtimeContext is already { customerStore, … } and the extra fields are fine, register the tool directly:

defineAgent({
  runtimeContext: async ({ identity }) => ({
    customerStore: await stores.forWorkspace(identity.workspaceId),
  }),
  tools: { lookupCustomer },
});

Narrower shape: mapContext

When the agent context is a bag of services and the tool only wants one:

defineAgent({
  runtimeContext: async ({ identity }) => ({
    workspaceId: identity.workspaceId,
    stores: await loadStores(identity.workspaceId),
  }),
  tools: {
    lookupCustomer: {
      tool: lookupCustomer,
      mapContext: ({ runtimeContext }) => ({
        customerStore: runtimeContext.stores.customers,
      }),
    },
  },
});

mapContext also receives identity and clientData. Use that when the tool's context should include a tenant id the agent bag does not already have:

mapContext: ({ runtimeContext, identity }) => ({
  customerStore: runtimeContext.stores.customers,
  workspaceId: identity.workspaceId,
}),

Registering a context tool without a compatible agent context is a type error. Dynamic tool maps fail at resolution before the model sees the tool.

What belongs where

Put it inExamples
identityuserId, workspaceId — ids only
runtimeContextDB handles, permissions, "today"
ctx.contextExactly what this tool's execute needs
clientDataOpen document, current view — untrusted

Do not put records on identity. Look records up in runtimeContext so they stay current. See Identity.

Next

On this page