{"_id":"@aelio/sdk","_rev":"2-33296f8e78bd92194d6ed070b300f348","name":"@aelio/sdk","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@aelio/sdk","version":"0.1.0","keywords":["aelio","sdk","conversational","ai","agent","whatsapp","chatbot","llm","websocket"],"license":"Apache-2.0","_id":"@aelio/sdk@0.1.0","maintainers":[{"name":"sanjithvprabhu","email":"sanjithvprabhu@gmail.com"}],"homepage":"https://github.com/aelio-dev/aelio#readme","bugs":{"url":"https://github.com/aelio-dev/aelio/issues"},"dist":{"shasum":"9d4e7eb2d22d66a6a818faff59cf2f4083b678ff","tarball":"https://registry.npmjs.org/@aelio/sdk/-/sdk-0.1.0.tgz","fileCount":5,"integrity":"sha512-uzOV+q/bOSu/d892MHN6lsxGPK2riJ+wAirLblSQF1GgCgY0EG3cOsLWviuO585Dh5qeuwyqQe/xF1FUqcgcQQ==","signatures":[{"sig":"MEUCID9tQk7sPkBmZRmdKOrm23SShAw3U8A7Vg6qwYLMHk3ZAiEAqrcnV5AkatqbJPQfS7Tyr0PCXdRoXSV5lG6SGidBX9g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53089},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"249199a6f2e7d32bc091a7335b04be31909cafcc","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit"},"_npmUser":{"name":"sanjithvprabhu","email":"sanjithvprabhu@gmail.com"},"repository":{"url":"git+https://github.com/aelio-dev/aelio.git","type":"git","directory":"packages/sdk-node"},"_npmVersion":"10.8.2","description":"Aelio SDK — expose your backend functions to the Aelio conversational runtime over a single outbound WebSocket. Your auth, DB, and business logic stay in your process.","directories":{},"_nodeVersion":"20.20.1","dependencies":{"ws":"^8.18.2","zod":"^3.25.67"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","@types/ws":"^8.18.1","typescript":"^5.8.3","@aelio/protocol":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1783293543540_0.5197122482917849","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aelio/sdk","version":"0.1.1","description":"Aelio SDK — expose your backend functions to the Aelio conversational runtime over a single outbound WebSocket. Your auth, DB, and business logic stay in your process.","license":"Apache-2.0","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"keywords":["aelio","sdk","conversational","ai","agent","whatsapp","chatbot","llm","websocket"],"homepage":"https://github.com/aelio-dev/aelio#readme","repository":{"type":"git","url":"git+https://github.com/aelio-dev/aelio.git","directory":"sdk/node"},"bugs":{"url":"https://github.com/aelio-dev/aelio/issues"},"engines":{"node":">=20"},"publishConfig":{"access":"public"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","dev":"tsup --watch"},"dependencies":{"ws":"^8.18.2","zod":"^3.25.67"},"devDependencies":{"@aelio/protocol":"workspace:*","@types/ws":"^8.18.1","tsup":"^8.5.0","typescript":"^5.8.3"},"_id":"@aelio/sdk@0.1.1","gitHead":"92762d7bce4e6c05f240cc9dc4815bf80eaeca87","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-uAmgvfjuTChrFCGAD+1J7uPu5VucAzPpCrFz/noyTkTmzINBk++X3GGaDOa3BVMKcDrvo5CcPE2k+afEUpoWBw==","shasum":"7be4e12e385953e17ce7a7529bfa03269cc2131e","tarball":"https://registry.npmjs.org/@aelio/sdk/-/sdk-0.1.1.tgz","fileCount":5,"unpackedSize":64956,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIENJTnN4FuV16/4PECVcRQa/5wHdd4Q+RBa8t3hsMzucAiEAsoFYg5pfuJNy2tQoCG3FFpJIqWHZnRAKW7Q8YX6qflU="}]},"_npmUser":{"name":"sanjithvprabhu","email":"sanjithvprabhu@gmail.com"},"directories":{},"maintainers":[{"name":"sanjithvprabhu","email":"sanjithvprabhu@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.1_1783757524844_0.8194621799925361"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-05T23:19:03.394Z","modified":"2026-07-11T08:12:05.097Z","0.1.0":"2026-07-05T23:19:03.681Z","0.1.1":"2026-07-11T08:12:04.975Z"},"bugs":{"url":"https://github.com/aelio-dev/aelio/issues"},"license":"Apache-2.0","homepage":"https://github.com/aelio-dev/aelio#readme","keywords":["aelio","sdk","conversational","ai","agent","whatsapp","chatbot","llm","websocket"],"repository":{"type":"git","url":"git+https://github.com/aelio-dev/aelio.git","directory":"sdk/node"},"description":"Aelio SDK — expose your backend functions to the Aelio conversational runtime over a single outbound WebSocket. Your auth, DB, and business logic stay in your process.","maintainers":[{"name":"sanjithvprabhu","email":"sanjithvprabhu@gmail.com"}],"readme":"# @aelio/sdk\n\nThe Node.js/TypeScript SDK for [Aelio](https://github.com/aelio-dev/aelio) — the open-source conversational runtime for SaaS products.\n\nInstall it in your existing backend, expose a few functions, and Aelio gives your\ncustomers a chat/voice experience on WhatsApp and Web. Your auth, DB, and business\nlogic stay in your process — the SDK dials **out** to the Aelio server over a single\npersistent WebSocket, so there are no inbound ports or webhooks to configure.\n\n## Install\n\n```bash\nnpm install @aelio/sdk\n```\n\n## Usage\n\n```typescript\nimport { aelio } from '@aelio/sdk'\n\naelio.expose('getOrderStatus', async ({ orderId }, ctx) => {\n  // ctx.customerId is your own user ID — scope your queries normally\n  return await db.orders.findOne({ id: orderId, userId: ctx.customerId })\n}, {\n  description: 'Get the status of a customer order',\n  params: { orderId: 'string' },\n  safety: 'read'\n})\n\naelio.expose('cancelOrder', async ({ orderId }, ctx) => {\n  return await db.orders.cancel(orderId, { userId: ctx.customerId })\n}, {\n  description: 'Cancel a pending order',\n  params: { orderId: 'string' },\n  safety: 'write' // write actions are confirmed with the user before running\n})\n\nawait aelio.listen({\n  secret: process.env.AELIO_SECRET,\n  url: process.env.AELIO_SERVER_URL ?? 'ws://127.0.0.1:3000',\n})\n```\n\nThat's the whole integration.\n\n## Declaring parameters\n\nEach parameter in `params` can be declared three interchangeable ways — mix them freely:\n\n```typescript\naelio.expose('listOrders', handler, {\n  description: \"List the customer's orders, optionally filtered\",\n  params: {\n    customerRef: 'string',                 // required string\n    status: 'string?',                      // optional — trailing \"?\"\n    limit: { type: 'number', optional: true },\n    sort: {\n      type: 'string',\n      description: 'Sort order',            // shown to the model\n      enum: ['newest', 'oldest'],          // constrains the choice\n      optional: true,\n    },\n    tags: { type: 'array', items: 'string', optional: true },\n  },\n  safety: 'read',\n})\n```\n\n| Form | Example | Meaning |\n|---|---|---|\n| Shorthand | `'string'` | required, type only |\n| Optional shorthand | `'string?'` | optional (trailing `?`) |\n| Object | `{ type, description?, optional?, enum?, format?, items? }` | full control |\n\nSupported types: `string`, `number`, `integer`, `boolean`, `array`, `object`.\n\nTwo things Aelio does for you with this:\n- **Required vs optional** is passed to the LLM correctly, so it won't pester the user for values you marked optional, and it *will* gather the ones you require.\n- **Missing required arguments are caught** before your handler runs — Aelio asks the model to collect them instead of calling your function with `undefined`.\n\n## Bring your own messaging channel\n\nAelio ships a built-in Meta WhatsApp adapter (configure credentials in `config.yaml`\nand you're done). But if you use a *different* provider — Twilio, Gupshup, 360dialog,\nSMS, anything — you can wire it from your own backend with two hooks, and Aelio keeps\n**zero provider code and zero provider credentials**:\n\n```typescript\n// 1) Deliver replies through YOUR provider. Aelio calls this after each turn\n//    (and for proactive messages). It is NOT an LLM tool — delivery is automatic.\naelio.onSend(async ({ channel, to, content }) => {\n  await myProvider.messages.create({ to, body: content })\n})\n\n// 2) In your own webhook route, hand Aelio inbound messages. You own the webhook,\n//    signature verification, and provider parsing; Aelio takes over identity,\n//    memory, the LLM turn, safety, and the reply.\napp.post('/my-whatsapp-webhook', (req, res) => {\n  const { from, text } = myProvider.parse(req.body)\n  aelio.ingest({ channel: 'whatsapp', from, text })\n  res.sendStatus(200)\n})\n```\n\nOn the Aelio server, set the channel provider to `sdk`:\n\n```yaml\nchannels:\n  whatsapp:\n    enabled: true\n    provider: sdk   # inbound via ingest(), delivery via onSend — no creds on Aelio\n```\n\nAdding a new provider becomes ~20 lines in your codebase, with no Aelio changes.\n\n## Safety levels\n\n| Level | Behavior |\n|---|---|\n| `read` | Auto-allowed. The assistant can call freely. |\n| `write` | Requires explicit user confirmation in the conversation before it runs. |\n| `destructive` | Blocked from chat in V1. |\n\n## Lifecycle states, policies, and flows\n\nDeclare your customer lifecycle catalog in the SDK. **You** set each customer's\ncurrent state from your backend; Aelio enforces boundaries in conversation and\nfilters tools per state.\n\n```typescript\naelio.state('onboarding', {\n  description: 'New user. Setup only — no billing or upgrade topics.',\n  allowedTools: ['listOrders', 'getSubscription'],\n  blockedTools: ['upgradePlan', 'cancelOrder'],\n})\n\naelio.state('active', {\n  description: 'Fully onboarded customer. Full product support.',\n})\n\n// Declarative lifecycle transitions: the harness advances the customer's state\n// automatically when a tool succeeds (guard-checked). Your set_state push always\n// overrides. `guards.requiresFields` gates a state on customer-profile fields.\naelio.state('cart', {\n  description: 'Building an order.',\n  transitions: [{ onToolSuccess: 'createOrder', to: 'awaiting_payment' }],\n})\n\naelio.policy('stay-in-lifecycle', {\n  description: 'Only discuss topics appropriate for the current lifecycle state.',\n  severity: 'hard',\n})\n\naelio.flow('onboarding_setup', {\n  state: 'onboarding',\n  description: 'Guide setup: orders → subscription → invoices',\n  steps: {\n    review_orders: { goal: 'Review existing orders', tool: 'listOrders' },\n    check_plan: { goal: 'Check subscription plan', tool: 'getSubscription' },\n  },\n})\n\n// When your app knows the customer's stage (login, webhook, cron…):\naelio.setCustomerState(userId, 'onboarding')\naelio.setFlowProgress(userId, 'onboarding_setup', 1, ['review_orders'])\n```\n\n## API\n\n- `aelio.expose(name, handler, schema)` — register a callable function.\n- `aelio.persona(text)` — set the assistant's voice (head of the system prompt).\n- `aelio.describe(text)` — describe what your product does; grounds the harness\n  planner so it plans well and declines the impossible gracefully.\n- `aelio.state(id, schema)` — declare a lifecycle state, its tool boundaries, and\n  optional `transitions` / `guards`.\n- `aelio.policy(id, schema)` — declare a conversation policy.\n- `aelio.flow(id, schema)` — declare a guided multi-step flow for a state.\n- `aelio.setCustomerState(customerId, stateId, reason?)` — push current state to Aelio.\n- `aelio.setFlowProgress(customerId, flowId, stepIndex, completedSteps?)` — update flow progress.\n- `aelio.listen({ secret, url? })` — connect to the Aelio server (auto-reconnect + heartbeat).\n- `aelio.disconnect()` — drain and close.\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}