Connecting your logic
Understanding the main components of the SDK

Input Schema
The input schema is based on Zod, because it is one of the most powerful static type inference toolings.
The schema makes the handler functions type-safe and enables you to define what the AI agent is allowed to fill in and what not. Giving you full control to reduce halluzinations. You can define multiple types
cmdBar.defineAction({
// […] Other config
inputSchema: z.object({
websiteLinks: fillableByAI(z.array(z.string())),
dataStoreId: z.string(),
numberOfDataPointsToCreate: fillableByAI(z.number())
})
})
Preview handler (the human in the loop)
The preview handlers run immediately after CmdBar AI came up with an action flow. Its the place where you can make sure the input for the handler is valid and the user is fine with the selected data.
cmdBar.defineAction({
name: 'crawlData',
description: 'Crawls websites inorder to create reference data and stores it in a data store',
displayName: 'Crawl websites',
inputSchema: z.object({
websiteLinks: fillableByAI(z.array(z.string())),
dataStoreId: z.string(),
}),
previewHandler: async ({ websiteLinks, dataStoreId }, { hil }) => {
// dataStoreId will be undefined since AI can't know that.
const links = [];
// main human in'the loop interfaces...
const { askForInput, display } = hil;
// validating input...
if (websiteLinks && websiteLinks.length > 0) {
links.push(...websiteLinks);
} else {
const link = await askForInput.text({
label: 'Provide a link to crawl',
placeholder: 'https://www.doc.com/abc',
});
links.push(link);
}
// requesting dynamic / critical input
const dataStores = await getAvailableDataStores();
const _dataStoreId = await askForInput.enum({
label: 'Where should the data be stored?',
options: new Map(dataStores.map((ds) => [ds.id, ds.name])),
});
return { dataStoreId: _dataStoreId, websiteLinks: links };
},
handler: async (validatedInput, context) => {},
});

Handler (the action itself)
The handler runs for each action after the user hits "execute". It has the same capabilities and api as the previewHandler but its supposed used for executing the actual logic and only ask for input in edge cases.
cmdBar.defineAction({
name: 'crawlData',
description: 'Crawls websites inorder to create reference data and stores it in a data store',
displayName: 'Crawl websites',
inputSchema: z.object({
websiteLinks: fillableByAI(z.array(z.string())),
dataStoreId: z.string(),
}),
// [...] - preview handler
handler: async (validatedInput, context) => {
const { display } = context.hil;
display.log('The action is running');
await new Promise((resolve) => setTimeout(resolve, 1000));
display.log('And this log will stay and not replace the other');
await new Promise((resolve) => setTimeout(resolve, 1000));
const liveLog = display.syncedLog();
liveLog.log('...');
liveLog.log('currently its working on crawling...');
await new Promise((resolve) => setTimeout(resolve, 4000));
liveLog.log('crawling done');
await new Promise((resolve) => setTimeout(resolve, 6000));
liveLog.log('live logging updates the log in real time');
await new Promise((resolve) => setTimeout(resolve, 3000));
// closing the livelog connection
liveLog.close();
await new Promise((resolve) => setTimeout(resolve, 1000));
liveLog.hide();
display.log('The action is done and the live log is hidden');
},
});

Last updated