Actions
Built-in actions, integration providers, and creating custom actions.
Actions are the building blocks of flows. Each action defines a node type — with a parameter schema, an execute function, and a provider grouping for the UI palette. Every action is automatically available as both a flow node and an agent tool.
Core Actions
The core provider contains the fundamental building blocks available in every flow:
- Input / Output — Define the entry point and return values of a flow
- Model — Call an LLM (OpenAI or Anthropic) with a prompt
- If/Else — Conditional branching
- JQ — Transform JSON data using JQ syntax
- Template String — Generate text from Nunjucks templates
Integration Providers
Invect ships with actions for a growing set of third-party services. Each provider groups related actions under a common prefix (e.g. gmail.*, github.*). The full list of available providers and their actions is visible in the flow editor's node palette.
Current providers include: Gmail, Slack, GitHub, Google Drive, Google Docs, Google Sheets, Google Calendar, Linear, Microsoft 365, Postgres, and HTTP.
Most integration actions require a credential to authenticate with the external service.
Creating Custom Actions
You can define your own actions and register them with Invect:
import { defineAction } from '@invect/core';
import { z } from 'zod';
export const myAction = defineAction({
id: 'custom.my_action',
name: 'My Custom Action',
description: 'Does something specific to my app',
provider: {
id: 'custom',
name: 'Custom',
icon: 'Wrench',
},
params: {
schema: z.object({
input: z.string().describe('The input to process'),
}),
fields: [
{ name: 'input', label: 'Input', type: 'text', required: true },
],
},
async execute(params, context) {
// Your custom logic here
return { success: true, output: { processed: params.input } };
},
});Register it as a plugin or call registerAction after initialization:
import type { InvectPlugin } from '@invect/core';
export const myPlugin: InvectPlugin = {
id: 'custom',
actions: [myAction],
};
// Then in your config:
createInvectRouter({
baseDatabaseConfig: { type: 'sqlite', connectionString: 'file:./dev.db', id: 'main' },
plugins: [myPlugin],
});Custom actions appear in the node palette under your chosen provider and are automatically available as agent tools.
Execution Context
The context object passed to execute provides:
| Property | Description |
|---|---|
context.incomingData | Output from upstream nodes (keyed by node slug) |
context.flowInputs | The original inputs passed to the flow run |
context.credential | The resolved credential (if credential.required is set) |
context.logger | Structured logger scoped to this execution |
context.functions.submitPrompt | Send a prompt to an LLM (with batch support) |
context.functions.getCredential | Fetch a credential by ID at runtime |
Accessing Upstream Data
async execute(params, context) {
// Access output from an upstream node with slug "fetch_user"
const user = context.incomingData.fetch_user;
return { success: true, output: { greeting: `Hello, ${user.name}` } };
}Using a Credential
export const myAction = defineAction({
id: 'my_provider.my_action',
credential: {
required: true,
oauth2Provider: 'my_service', // or omit for API key credentials
},
async execute(params, context) {
const token = context.credential?.config?.accessToken;
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${token}` },
});
return { success: true, output: await response.json() };
},
});For a more extensible approach to adding large sets of custom actions, see Plugins.