Functions
Functions are reusable, sandboxed code snippets in your workspace. You write JavaScript or Python, define inputs and outputs, bind workspace resources, and return a result agents, workflows, widgets, and MCP can call as a tool.
Use them to encapsulate scoring, transforms, lookups, or multi-step logic behind a clear name — without giving the sandbox raw network access.
When to use
- Encapsulate business logic that agents and workflows should call as a tool
- Compose queries, agents, workflows, blocks, and other functions behind one schema
- Keep sandboxed code free of raw network access or arbitrary imports
The sandbox cannot call the network or load packages on its own. Bind queries, blocks, agents, workflows, or other functions and call them through vt.
Create a function
Open Build → Functions for a workspace-wide function, or open an agent’s builder and use the Functions panel for one scoped to that agent.
- Click Create Function (or Build With AI to draft it in Studio).
- Enter a Name, optional Description, and Language (JavaScript or Python).
- Click Create — Vettero opens the function detail page.
Language is fixed after create. Workspace functions appear under Global in the agent tools picker; agent-scoped ones appear under Local.
Open the editor
From the function detail page, click Edit. Use Save when you are done. You can also open Build With AI to change the function in Studio.
| Section | What you configure |
|---|---|
| Name / Description | Identity; the description becomes tool help text for agents and MCP |
| Input schema | JSON Schema for the args object callers pass in |
| Output schema | JSON Schema for the value your code returns |
| Bound resources | Queries, functions, agents, workflows, or blocks the code may call |
| Code | Function body only — the runtime wraps it for you |
In the code panel, the chrome shows the wrapper (async function name(args) { … } or async def name(args):). You only write the body.
Run a function
Open the function editor and click Run. Fill in the arguments from the input schema. Vettero saves that input on the function so the next run starts from the same values.
Run executes the saved function and shows the output in the dialog. If you still have unsaved edits, Vettero saves them first. Agents, workflows, and widgets do not use this sample input — they pass their own arguments.
Bind resources
Click Add under Bound resources. Each binding needs a unique key, a type, and the target resource.
| Type | What you can bind |
|---|---|
| Query | Any workspace query |
| Function | Any other workspace function (max nesting depth 5) |
| Agent | Must use the general channel |
| Workflow | Must use the general channel |
| Block | A tool-capable block; pick a Service when the block is service-scoped |
Only keys you list here are callable from code. A function cannot bind itself.
Write the code
Call bound resources through the injected vt helper. Pass a plain object as input (or omit it for {}).
| Method | What it does |
|---|---|
await vt.runQuery(key, input?) | Runs a bound query (typically { rows, total }) |
await vt.runFunction(key, input?) | Runs a nested function (max depth 5) |
await vt.runWorkflow(key, input?) | Awaits a workflow run; throws if it fails or waits for human approval |
await vt.runAgent(key, input?) | Awaits an agent run; throws if it fails or waits for human approval |
await vt.runBlock(key, input?) | Runs a bound block; human-in-the-loop interrupts are not supported |
JavaScript example
const { rows, total } = await vt.runQuery('orders', { status: args.status })
return { count: rows?.length ?? 0, total }
Python example
query = await vt.runQuery('orders', { 'status': args['status'] })
rows = query['rows'] if query else []
return { 'count': len(rows), 'total': query.get('total') if query else 0 }
Attach to an agent
In the agent builder, open Config → Tools → Manage Tools → Function. Pick a function.
You can also type # in the agent Task and select the function — that mentions it in the prompt and attaches it as a tool.
Limits
- JavaScript: no
import/require/ network in the isolate — use bound resources viavt. About 10MB memory; about 3s with no resources; up to about 5 minutes when resources are bound. - Python: about 15s with no resources; up to about 5 minutes when resources are bound.
Where functions are used
| Place | How |
|---|---|
| Agents | Tools → Function, or # mention in the Task |
| MCP Servers | List functions on an MCP server; each becomes an MCP tool |
| Widgets | Bind as a resource or job and call from the widget |
| Other functions | Bind as a Function resource and call vt.runFunction |