🚀 Launch Week Day 5:Introducing Immutable Scans.Learn More →
Socket
Book a DemoInstallSign in
Socket

@rubriclab/agents

Package Overview
Dependencies
Maintainers
4
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rubriclab/agents

TypeScript framework for building AI agents with structured outputs, tools, and type-safe execution.

latest
Source
npmnpm
Version
0.0.84
Version published
Maintainers
4
Created
Source

@rubriclab/agents

TypeScript framework for building AI agents with structured outputs, tools, and type-safe execution.

It is part of Rubric's architecture for Generative UI when used with:

  • @rubriclab/actions
  • @rubriclab/blocks
  • @rubriclab/chains
  • @rubriclab/agents
  • @rubriclab/events

Demo

Get Started

Installation

bun add @rubriclab/actions

@rubriclab scope packages are not built, they are all raw typescript. If using in a next.js app, make sure to transpile.

// next.config.ts
import type { NextConfig } from  'next' 
export default {
	transpilePackages: ['@rubriclab/agents'],
	reactStrictMode: true
} satisfies  NextConfig

If using inside the monorepo (@rubric), simply add {"@rubriclab/agents": "*"} to dependencies and then run bun i

Quick Start

Simple Generation

import { generateObject } from '@rubriclab/agents'
import { z } from 'zod'

const result = await generateObject({
	apiKey: env.OPENAI_API_KEY,
	model: 'gpt-5.2',
	systemPrompt: 'Extract user info',
	schema: z.object({
		name: z.string(),
		age: z.number()
	}),
	messages: [{ role: 'user', content: 'I am John, 25 years old' }]
})
// { name: "John", age: 25 }

Agent with Tools

A tool agent will recurse until it has what it needs to export a final answer. By default, the format of the final answer is { answer: string }.

import { createAgent, createTool } from '@rubriclab/agents'
import { z } from 'zod'

const systemPrompt = 'You are a weather agent. Use tools to get the weather for the user.'

const weatherTool = createTool({
	schema: {
		input: z.object({ city: z.string() }),
		output: z.object({ temp: z.number(), condition: z.string() })
	},
	execute: async ({ city }) => ({ temp: 72, condition: 'sunny' })
})

const { executeAgent, eventTypes, __ToolEvent, __ResponseEvent } = createAgent({
	systemPrompt,
	tools: { getWeather: weatherTool }
})
// Execute the agent

'use server'
import env from '~/env'
import { executeWeatherAgent } from './agent'

export async function sendMessage({ userId, message }: { userId: string; message: string }) {
	const { answer } = await executeWeatherAgent({
		messages: [{ role: 'user', content: message }],
		onEvent: async events => {
			switch (events.type) {
				case 'function_call':
					switch (events.name) {
						case 'getWeather':
							console.log(`the temperature in ${events.arguments.city} is ${events.result.temp} degrees`)
					}
				case 'assistant_message':
					console.log(events.message.answer)
					break
			}
		},
		openAIKey: env.OPENAI_API_KEY
	})

	return answer
}

Response Format

You can override the default response format and agents that return complex types. Supplying an agent BOTH tools and response format will cause the agent to recurse using tools, and when ready, the response in the right format.

const responseFormat = createResponseFormat({
	name: 'research_results',
	schema: z.object({
		answer: z.string(),
		sources: z.array(z.object({ title: z.string(), url: z.string() }))
	})
})
const { executeAgent } = createAgent({
	systemPrompt,
	tools: { ... },
	responseFormat
})

Usage with other packages

Usage with @rubriclab/events

The createAgent(...) function returns eventTypes which is a record of Zod types.

const { executeAgent, eventTypes } = createAgent({
	systemPrompt,
	tools: { research: researchTool },
})

export { eventTypes as researchAgentEventTypes }
export { executeAgent as executeResearchAgent }

You can easily pass these events to the events package

import { createEventTypes } from '@rubriclab/events'
import { researchAgentEventTypes } from './agent'

export const eventTypes = createEventTypes({
	...researchAgentEventTypes
})

You can then publish them safely:

import env from '~/env'
import { executeResearchAgent } from './agent'
import { publish } from './events/server'

await executeResearchAgent({
	messages: [{ role: 'user', content: 'do something' }],
	onEvent: async events => {
		switch (events.type) {
			case 'function_call':
				await publish({
					channel: userId,
					eventType: events.name,
					payload: events
				})
				break
			case 'assistant_message':
				await publish({
					channel: userId,
					eventType: events.type,
					payload: events
				})
				break
		}
	},
	openAIKey: env.OPENAI_API_KEY
})

And consume them on the client with end to end safety:

useEvents({
		id: userId,
		on: {
			research: ({arguments, result}) => console.log(arguments.query, result.map(r => r.title)),
			assistant_message: ({message}) => console.log(message.answer)
		}
	})

Usage with @rubriclab/actions

coming soon...

Usage with @rubriclab/blocks

coming soon...

Usage with @rubriclab/chains

coming soon...

FAQs

Package last updated on 19 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts