{"id":16596083,"url":"https://github.com/valgaze/speedybot-mini","last_synced_at":"2025-10-29T12:30:50.771Z","repository":{"id":57367314,"uuid":"420118455","full_name":"valgaze/speedybot-mini","owner":"valgaze","description":"Invisible and indispensable conversation design tooling (serverless bots)","archived":false,"fork":false,"pushed_at":"2023-12-08T08:05:23.000Z","size":19343,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"deploy","last_synced_at":"2024-08-11T11:24:47.187Z","etag":null,"topics":["chat","chat-bot","chatbot","conversation","conversational-agents","conversational-ai","conversational-bots","serverle","webex","webex-teams"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/valgaze.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-10-22T13:55:27.000Z","updated_at":"2024-02-20T01:54:49.000Z","dependencies_parsed_at":"2023-12-06T05:22:35.222Z","dependency_job_id":"e3ff1bf1-847f-4704-8433-c49bea102567","html_url":"https://github.com/valgaze/speedybot-mini","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valgaze%2Fspeedybot-mini","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valgaze%2Fspeedybot-mini/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valgaze%2Fspeedybot-mini/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valgaze%2Fspeedybot-mini/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valgaze","download_url":"https://codeload.github.com/valgaze/speedybot-mini/tar.gz/refs/heads/deploy","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219857756,"owners_count":16556056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","chat-bot","chatbot","conversation","conversational-agents","conversational-ai","conversational-bots","serverle","webex","webex-teams"],"created_at":"2024-10-11T23:52:19.982Z","updated_at":"2025-10-29T12:30:48.136Z","avatar_url":"https://github.com/valgaze.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/speedybot-mini\"\u003e\n    \u003cimg src=\"https://github.com/valgaze/speedybot-mini/raw/deploy/docs/assets/logo.png?raw=true\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003e\u003ca href=\"https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/modules.md#classes\"\u003e📚 API Docs\u003c/a\u003e |\n  \u003ca href=\"#quickstarts\"\u003e🚀 Quickstarts\u003c/a\u003e\u003c/b\u003e |\n  \u003ca href=\"https://github.com/valgaze/speedybot-mini/discussions\"\u003e💬 Get Help\u003c/a\u003e\u003c/b\u003e\n\u003c/p\u003e\n\n[![npm version](https://badge.fury.io/js/speedybot-mini.svg)](https://www.npmjs.com/package/speedybot-mini)\n\n## Speedybot-mini\n\nSpeedybot is a tool to take you from zero to a user-valuable bot as quickly as possible w/ a buttery-smooth developer experience. In short, Speedybot lets you focus on the stuff that actually matters-- content and powerful integrations.\n\nIf you're in a hurry, see the **[quickstarts](#quickstarts)** to get up and running fast on a variety of infrastructure (websockets, server, serverless, container-less, etc).\n\n- 🌟 Zero External Dependencies 🌟\n- Adds support **[tappable suggestion \"chips\"](#chips)**\n- Includes **[SpeedyCard card builder](#speedycard)** (create rich **[Adaptive Cards](https://developer.webex.com/docs/api/guides/cards)** without wrangling JSON)\n- Lots of handy utilities for things like **[alerts, cards, files, and more](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/BotInst.md#methods)**\n- Locale \u0026 i18n support\n- Runs on virtually any infrastructure-- servers, V8 isolates, containers, container-less, edge, etc\n\nThe era of manually writing \"handlers\" or matching text with RegEx's is coming to an end (though Speedybot has several trick to make writing those easier). In the future, there will be far fewer \"keyword\" handlers and instead deeper integration with 3rd-party conversation services like **[Voiceflow](https://www.voiceflow.com/)**, **[Amazon Lex](https://aws.amazon.com/lex/)**, **[DialogFlow](https://cloud.google.com/dialogflow/docs)** and Speedybot can help make that transition as smooth as possible\n\n## Quickstarts\n\nYou can get up and running FAST with Speedybot. Speedybot can run on a variety of architectures and environments\n\n- **[speedybot garage 🔧🤖, manage webhooks/secrets/admin](https://codepen.io/valgaze/pen/MWVjEZV)**\n\n- 📚 **[API Docs](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/modules.md#classes)**\n\n| Platform                                                                                                                          | Needs server? | Needs webhooks? |\n| --------------------------------------------------------------------------------------------------------------------------------- | ------------- | --------------- |\n| **[🔌 Deploy with websockets](https://github.com/valgaze/speedybot-mini/tree/deploy/examples/websockets)**                        | ❌            | ❌              |\n| **[💻 Deploy to Simple Express Server](https://github.com/valgaze/speedybot-mini/tree/deploy/examples/express-incoming-webhook)** | ✅            | ✅              |\n| **[λ Deploy to AWS Lamda](https://github.com/valgaze/speedybot-mini/tree/deploy/examples/aws-lambda)**                            | ❌            | ✅              |\n| **[🔥 Deploy to Worker](https://github.com/valgaze/speedybot-mini/tree/deploy/examples/worker)**                                  | ❌            | ✅              |\n| **[🦖 Deploy to Deno](https://github.com/valgaze/speedybot-mini/tree/deploy/examples/deno)**                                      | ❌            | ✅              |\n\n## Syntax\n\n```sh\nnpm install speedybot-mini\n```\n\n**[See starter bot](https://github.com/valgaze/speedybot-mini/blob/deploy/settings/config.ts)**\n\n## How to make a bot\n\n## Keywords\n\nSpeedybot is made up of \"handlers\" that trigger based on special conditions-- depending on your needs you'll probably need only one or two in your project\n\n| Keyword                                                                                                       | Description                                                                                                                                             |\n| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **[.contains](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#contains)** | This will match if a trigger phrase is the 1st or only word in a message sent from a user                                                               |\n| **[.fuzzy](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#fuzzy)**       | This will match if a trigger phrase exists _anywhere_ inside a message sent from the user                                                               |\n| **[.exact](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#exact)**       | This will match if a trigger phrase is exactly (case-sensitve) a message sent from a user                                                               |\n| **[.fuzzy](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#regex)**       | This will match if a message sent from a user passes the regex                                                                                          |\n| **[.every](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#every)**       | This will match on every message from a user                                                                                                            |\n| **[.nlu](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#nlu)**           | This will match on every message from a user except if the trigger phrase is used by hard-coded handler, designed for use with natural language systems |\n| **[.onSubmit](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#onSubmit)** | This will trigger when data is sent from an **[](https://developer.webex.com/docs/api/guides/cards)**                                                   |\n| **[.onFile](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#onFile)**     | This will trigger every time a file is sent to the agent and will provide file meta data                                                                |\n| **[.onCamera](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#onCamera)** | This will trigger every time an image file sent to the agent                                                                                            |\n| **[.noMatch](https://github.com/valgaze/speedybot-mini/blob/deploy/api-docs/classes/Speedybot.md#noMatch)**   | This will trigger if there are no registered handlers for the user's text                                                                               |\n\n\u003cdetails\u003e\n\u003csummary\u003eNote on Precedence\u003c/summary\u003e\n\nRule: the 1st registered handler will match in the event of a conflict\n\nEx. Below since it was set first, fuzzy will take precedence over `contains`\n\n```ts\nimport { Speedybot, Config } from \"speedybot-mini\";\n\nconst botConfig: Config = {\n  token: \"__REPLACE__ME__\",\n};\n\n// 1) Initialize your bot w/ config\nconst CultureBot = new Speedybot(botConfig);\n\nCultureBot.fuzzy(\"hi\", ($bot, msg) =\u003e {\n  $bot.send(\"Fuzzy launched\");\n});\n\nCultureBot.contains(\"hi\", ($bot, msg) =\u003e {\n  $bot.send(\"Contains launched\");\n});\n```\n\n\u003c/details\u003e\n\nSee the main **[sample for all you can do](./settings/config.ts)**, but here's how you could make a simple agent\n\n```ts\nimport { Speedybot } from \"speedybot-mini\";\n\n// In a production environment use a secrets manager to pass in token\n// Get a token: https://developer.webex.com/my-apps/new/bot\nconst botConfig = { token: \"__REPLACE__ME__\" };\n\n// 1) Initialize your bot w/ config\nconst CultureBot = new Speedybot(botConfig);\n\n// 2) Export your bot\nexport default CultureBot;\n\n// 3) Do whatever you want!\n\n// Match handlers based on user input\nCultureBot.contains([\"hi\", \"yo\", \"hola\"], async ($bot, msg) =\u003e {\n  $bot.send(`You said '${msg.text}', ${msg.author.displayName}!`);\n  $bot.send(\n    $bot\n      .card({\n        title: `Hi ${msg.author.displayName}!`,\n        subTitle: `Glad to have you here, you said ${msg.text}`,\n        chips: [\"ping\", \"pong\"],\n      })\n      .setInput(`What's on your mind?`)\n  );\n});\n\n// Can also do Regex's\nCultureBot.regex(new RegExp(\"x\"), ($bot, msg) =\u003e {\n  $bot.send(`Regex matched on this text:  ${msg.text}`);\n});\n\n// Special keywords: .onSubmit, .onFile, .onCamera, .every, .noMatch, etc\n\n// Handle AdpativeCard submissions\nCultureBot.onSubmit(($bot, msg) =\u003e {\n  $bot.send(`You submitted ${JSON.stringify(msg.data.inputs)}`);\n});\n\n// Runs on file upload, can pass bytes to 3rd-party service\nCultureBot.onFile(async ($bot, msg, fileData) =\u003e {\n  $bot.send(`You uploaded '${fileData.fileName}'`);\n  $bot.send(`snip: ${fileData.markdownSnippet}`);\n  $bot.send(fileData.data);\n}).config({ matchText: true });\n\n// Runs on EVERY input, kinda like middleware\n// This is where you would interact with an NLU service like DialogFlow, Amazon Lex, Voiceflow, etc\nCultureBot.every(async ($bot, msg) =\u003e {\n  const { text } = msg;\n  $bot.log(`.every handler ran with this text: '${text}'`);\n}).config({\n  skipList: [\"$clear\"],\n});\n\n// If no matched handlers\nCultureBot.noMatch(($bot, msg) =\u003e {\n  $bot.say(`Bummer, there was no matching handler for '${msg.text}'`);\n});\n```\n\nThere's much more, see this **[sample for all you can do](./settings/config.ts)**\n\n## SpeedyCard\n\nex. Tell the bot \"sendcard\" to get a card, type into the card \u0026 tap submit, catch submission using _\u003c@submit\u003e_ and echo back to user.\n\n- Getting started with AdaptiveCards (https://developer.webex.com/docs/api/guides/cards) can be a bit cumbersome and error-prone\n\n- SpeedyCard is a limited subset of AdaptiveCards with basic features with a focus on user interaction \u0026 simplicity (title, text, input box, menu-select, no \"collapsable\" sections, etc)\n\n- Inspired a bit by SwiftUI: https://developer.apple.com/xcode/swiftui/\n\n![sb](https://github.com/valgaze/speedybot-mini/raw/deploy/docs/assets/demo_sendcard.gif)\n\n\u003cdetails\u003e\n\u003csummary\u003e(Tap to see code)\u003c/summary\u003e\n\n```ts\nimport { Speedybot } from \"speedybot-mini\";\n\n// In a production environment use a secrets manager to pass in token\n// Get a token: https://developer.webex.com/my-apps/new/bot\nconst botConfig = { token: \"__REPLACE__ME__\" };\n\n// 1) Initialize your bot w/ config\nconst CultureBot = new Speedybot(botConfig);\n\n// 2) Export your bot\nexport default CultureBot;\n\n// 3) Do whatever you want!\n// Match handlers based on user input like\nCultureBot.contains(\"hi\", async ($bot, msg) =\u003e {\n  $bot.send(`You said '${msg.text}', ${msg.author.displayName}!`);\n});\n\n// Handle/capture AdpativeCard submissions\nCultureBot.onSubmit(($bot, msg) =\u003e {\n  $bot.send(`You submitted ${JSON.stringify(msg.data.inputs)}`);\n});\n\n// send a card\n\nCultureBot.contains(\"sendcard\", async ($bot, msg) =\u003e {\n  const cardPayload = $bot\n    .card()\n    .setTitle(\"System is 👍\")\n    .setSubtitle(\"If you see this card, everything is working\")\n    .setImage(\"https://i.imgur.com/SW78JRd.jpg\")\n    .setInput(`What's on your mind?`)\n    .setTable([[`Bot's Time`, new Date().toTimeString()]])\n    .setData({ mySpecialData: { a: 1, b: 2 } })\n    .setUrl(\n      \"https://www.youtube.com/watch?v=3GwjfUFyY6M\",\n      \"Take a moment to celebrate\"\n    );\n});\n```\n\n\u003c/details\u003e\n\n## Chips\n\nex. Tell the bot \"chips\" to get a card with tappable \"chips\"\n\n![sb](https://github.com/valgaze/speedybot-mini/raw/deploy/docs/assets/demo_chips.gif)\n\n\u003cdetails\u003e\n\u003csummary\u003e(Tap to see code)\u003c/summary\u003e\n\n```ts\nimport { Speedybot } from \"speedybot-mini\";\n\n// In a production environment use a secrets manager to pass in token\n// Get a token: https://developer.webex.com/my-apps/new/bot\nconst botConfig = { token: \"__REPLACE__ME__\" };\n\n// 1) Initialize your bot w/ config\nconst CultureBot = new Speedybot(botConfig);\n\n// 2) Export your bot\nexport default CultureBot;\n\n// 3) Do whatever you want!\n// Match handlers based on user input like\nCultureBot.contains(\"hi\", async ($bot, msg) =\u003e {\n  $bot.send(`You said '${msg.text}', ${msg.author.displayName}!`);\n});\n\n// Handle/capture AdpativeCard submissions (non-chip submission)\nCultureBot.onSubmit(($bot, msg) =\u003e {\n  $bot.send(`You submitted ${JSON.stringify(msg.data.inputs)}`);\n});\n\nCultureBot.contains([\"ping\", \"pong\"], ($bot, msg) =\u003e {\n  const { text } = msg;\n  if (text === \"ping\") {\n    $bot.send(\"pong\");\n  } else if (text === \"pong\") {\n    $bot.send(\"ping\");\n  }\n});\n\n// send a card with tappable chips\n\nCultureBot.contains(\"chips\", async ($bot, msg) =\u003e {\n  $bot.send(\n    $bot\n      .card()\n      .setChips([\n        \"hey\",\n        \"ping\",\n        { label: \"say the phrase pong\", keyword: \"pong\" },\n      ])\n  );\n});\n```\n\n\u003c/details\u003e\n\n## Credits/Attribution\n\n- Cookie image courtesy of Daniel Lopez: https://unsplash.com/photos/aT7CE57EZL8 \u0026 https://unsplash.com/@soydanielwolf\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalgaze%2Fspeedybot-mini","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalgaze%2Fspeedybot-mini","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalgaze%2Fspeedybot-mini/lists"}