@asyncify-hq/agent
v0.4.0
Published
Agent SDK for Asyncify — receive normalized conversation events from any channel, reply, and fire notification workflows mid-conversation
Maintainers
Readme
@asyncify-hq/agent
Build the brain; Asyncify handles the channels. This SDK receives normalized conversation events from Asyncify (any channel — in-app today, more coming), lets your code reply, and batches signals — conversation metadata, workflow triggers, resolution — into the single HTTP response.
Zero dependencies. Works with plain Node http, Express, Fastify, or any
framework that exposes the raw request.
Quickstart
Register an agent (dashboard → Agents, or the API) with the URL your handler will listen on. Copy the signing secret — it is shown once.
Write the brain:
import http from 'node:http';
import { defineAgent, createHandler } from '@asyncify-hq/agent';
const support = defineAgent({
async onMessage(ctx) {
// ctx.history is pre-shaped for LLM SDKs: [{ role, content }, ...]
if (ctx.message.text.toLowerCase().includes('order')) {
ctx.metadata.set('topic', 'orders');
// fire a real notification workflow, mid-conversation
ctx.trigger('order-replacement', { payload: { order: '#1042' } });
return 'So sorry! A replacement is on the way — confirmation email incoming.';
}
if (ctx.message.text.toLowerCase().includes('thanks')) {
ctx.resolve('customer satisfied');
return 'Anytime!';
}
return `You said: ${ctx.message.text}`;
},
});
http
.createServer(createHandler(support, { signingSecret: process.env.ASYNCIFY_AGENT_SECRET! }))
.listen(4100);- Send a message from the
<AgentChat />widget (@asyncify-hq/react) or the API — your handler answers, Asyncify delivers.
Buttons & clicks
Offer tappable choices with a reply; a tap comes back as an action event. The platform renders them natively per channel — widget buttons, Telegram inline keyboards (retired after the tap), a numbered options list in email:
const support = defineAgent({
onMessage(ctx) {
ctx.reply('How should we fix this?', {
buttons: [
{ id: 'resend', label: 'Resend the order' },
{ id: 'human', label: 'Talk to a human' },
],
});
},
onAction(ctx) {
if (ctx.action?.id === 'resend') {
ctx.trigger('order-replacement');
return 'Done — confirmation on the way.';
}
return 'You got it — a teammate will pick this up shortly.';
},
});Agents without onAction receive clicks as plain messages — nothing
breaks if you skip it.
Adding an LLM
ctx.history maps directly onto chat-completion messages:
const { text } = await generateText({
model: openai('gpt-4o-mini'),
system: 'You are a support agent for Acme.',
messages: [...ctx.history, { role: 'user', content: ctx.message.text }],
});
return text;Security
Every request is HMAC-SHA256 signed (x-asyncify-signature over
timestamp.body, replay-protected by x-asyncify-timestamp). The handler
rejects anything unsigned or stale; verifySignature is exported if you
need to verify manually.
