
Research
/Security News
Malicious Chrome Extension Performs Hidden Affiliate Hijacking
A Chrome extension claiming to hide Amazon ads was found secretly hijacking affiliate links, replacing creators’ tags with its own without user consent.
@rubriclab/agents
Advanced tools
TypeScript framework for building AI agents with structured outputs, tools, and type-safe execution.
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:
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 runbun i
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 }
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
}
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
})
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)
}
})
coming soon...
coming soon...
coming soon...
FAQs
TypeScript framework for building AI agents with structured outputs, tools, and type-safe execution.
We found that @rubriclab/agents demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

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.

Research
/Security News
A Chrome extension claiming to hide Amazon ads was found secretly hijacking affiliate links, replacing creators’ tags with its own without user consent.

Security News
A surge of AI-generated vulnerability reports has pushed open source maintainers to rethink bug bounties and tighten security disclosure processes.

Product
Scan results now load faster and remain consistent over time, with stable URLs and on-demand rescans for fresh security data.