diff --git a/docs/assets/bongo.png b/docs/assets/bongo.png
deleted file mode 100644
index 4c59ffa..0000000
Binary files a/docs/assets/bongo.png and /dev/null differ
diff --git a/docs/assets/build_a_bot.gif b/docs/assets/build_a_bot.gif
deleted file mode 100644
index c80db63..0000000
Binary files a/docs/assets/build_a_bot.gif and /dev/null differ
diff --git a/docs/assets/card_nosubmit.gif b/docs/assets/card_nosubmit.gif
deleted file mode 100644
index ed91917..0000000
Binary files a/docs/assets/card_nosubmit.gif and /dev/null differ
diff --git a/docs/assets/deno/deno_addcode.png b/docs/assets/deno/deno_addcode.png
deleted file mode 100644
index 36fc3fc..0000000
Binary files a/docs/assets/deno/deno_addcode.png and /dev/null differ
diff --git a/docs/assets/deno/deno_playground.png b/docs/assets/deno/deno_playground.png
deleted file mode 100644
index f9e455a..0000000
Binary files a/docs/assets/deno/deno_playground.png and /dev/null differ
diff --git a/docs/assets/deno/deno_webhook.png b/docs/assets/deno/deno_webhook.png
deleted file mode 100644
index da14863..0000000
Binary files a/docs/assets/deno/deno_webhook.png and /dev/null differ
diff --git a/docs/assets/deno/set_secrets.png b/docs/assets/deno/set_secrets.png
deleted file mode 100644
index 5df12bc..0000000
Binary files a/docs/assets/deno/set_secrets.png and /dev/null differ
diff --git a/docs/assets/deno/set_secrets_saved.png b/docs/assets/deno/set_secrets_saved.png
deleted file mode 100644
index 4bb1741..0000000
Binary files a/docs/assets/deno/set_secrets_saved.png and /dev/null differ
diff --git a/docs/assets/download.png b/docs/assets/download.png
deleted file mode 100644
index d35ee71..0000000
Binary files a/docs/assets/download.png and /dev/null differ
diff --git a/docs/assets/download2.png b/docs/assets/download2.png
deleted file mode 100644
index 05da32b..0000000
Binary files a/docs/assets/download2.png and /dev/null differ
diff --git a/docs/assets/regen_token.gif b/docs/assets/regen_token.gif
deleted file mode 100644
index e9bfa70..0000000
Binary files a/docs/assets/regen_token.gif and /dev/null differ
diff --git a/docs/assets/speedy.jpeg b/docs/assets/speedy.jpeg
deleted file mode 100644
index 060f7d9..0000000
Binary files a/docs/assets/speedy.jpeg and /dev/null differ
diff --git a/docs/examples/deno/README.md b/docs/examples/deno/README.md
index c3b8652..376d23b 100644
--- a/docs/examples/deno/README.md
+++ b/docs/examples/deno/README.md
@@ -16,192 +16,11 @@ Note: The steps below assume you have a **[working WebEx account](https://develo
- Press the blue "New Playground" button
-![sb](./../../assets/deno/deno_playground.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_playground.png)
-Note: There are many (better) ways to setup Deno, but for now we can just use the Playground and copy/paste everything in the panel below:
+Note: There are many (better) ways to setup Deno, but for now we can just use the Playground and copy/paste everything in **[index.ts](./index.ts)**
-## 2a) Copy the code below into the playground
-
-💡 Tap here to open code (copy me)
-
-```ts
-import { SpeedyBot, logoRoll } from "https://cdn.skypack.dev/speedybot@latest";
-
-Deno.serve(async (req: Request) => {
- if (req.method === "GET") {
- return new Response(`Server is running ${new Date()} ${logoRoll()}`);
- }
-
- const CONFIG = {
- token: Deno.env.get("token"),
- webhookSecret: Deno.env.get("webhookSecret"),
- };
-
- if (req.method === "POST") {
- const signature =
- req.headers.get("x-spark-signature") ||
- req.headers.get("X-Spark-Signature");
- const Bot = new SpeedyBot(CONFIG.token);
- const json = await req.json();
-
- if (signature) {
- const validateWebhook = async (
- requestData: T,
- secret: string,
- signature: string
- ): Promise => {
- const stringyBody =
- typeof requestData !== "string"
- ? JSON.stringify(requestData)
- : requestData;
- const algo = {
- name: "HMAC",
- hash: "SHA-1",
- };
- const enc = {
- name: "UTF-8",
- };
- const hmacKey = await crypto.subtle.importKey(
- "raw",
- new TextEncoder().encode(secret),
- algo,
- false,
- ["sign"]
- );
- const hmacData = await crypto.subtle.sign(
- algo,
- hmacKey,
- new TextEncoder().encode(stringyBody)
- );
-
- const bufferToHex = (buffer: ArrayBufferLike) => {
- return Array.prototype.map
- .call(new Uint8Array(buffer), (x) =>
- ("00" + x.toString(16)).slice(-2)
- )
- .join("");
- };
- const hmacDataHex = bufferToHex(hmacData);
- return hmacDataHex === signature;
- };
- const proceed = await validateWebhook(
- json,
- CONFIG.webhookSecret,
- signature
- );
- if (proceed === false) {
- return new Response("Webhook Secret Rejected");
- }
- }
-
- Bot.exact("$clear", async ($) => {
- await $.clearScreen();
- return $.end;
- });
-
- Bot.addStep(async ($) => {
- if ($.data && !$.data.showCard) {
- const dataSnippet = $.buildDataSnippet($.data);
- await $.send(`This data was submitted:`);
- await $.send(dataSnippet);
- return $.end;
- } else {
- return $.next;
- }
- });
-
- Bot.addStep(async ($) => {
- await $.send(`helllllooo, you said "${$.text}"`);
- const card = $.card().survey([
- {
- type: "text",
- question: "What is the name of your company?",
- id: "company_name",
- },
- {
- type: "text",
- question: "Describe the service performed by the vendor.",
- id: "service_type",
- },
- {
- type: "picker-date",
- question: "When was the service provided?",
- id: "service_date",
- },
- {
- type: "single-select",
- question: "How would you rate the quality of service?",
- choices: ["Excellent", "Good", "Average", "Poor", "Very poor"],
- id: "service_quality",
- },
- {
- type: "multi-select",
- question: "What were the highlights of the service?",
- choices: [
- "Communication",
- "Punctuality",
- "Time to Resolution",
- "Friendliness",
- "Cost",
- ],
- id: "service_highlights",
- },
- {
- type: "single-select",
- question:
- "Would you consider using our services again in the future?",
- choices: [
- "Definitely",
- "Probably",
- "Not sure",
- "Probably not",
- "Definitely not",
- ],
- id: "future_use",
- },
- {
- type: "textarea",
- question:
- "Please provide any other comments or suggestions for improvement.",
- id: "other_comments",
- },
- {
- type: "picker-time",
- question: "What time of day is preferable for future contact?",
- id: "preferred_contact_time",
- },
- {
- type: "picker-dropdown",
- question: "Preferred method of communication for future updates?",
- choices: ["Email", "Phone", "Text"],
- id: "communication_method",
- },
- ]);
-
- await $.send(card);
-
- return $.next;
- });
-
- Bot.captureError(async (payload) => {
- const { roomId } = payload;
- if (roomId) {
- await Bot.sendTo(
- roomId,
- `Whoops, there was a problem: ${payload.message}`
- );
- }
- });
-
- await Bot.runMiddleware(json);
- }
- return new Response(`Request processed`); // webhooks should return **something**
-});
-```
-
-
-
-![sb](./../../assets/deno/deno_addcode.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_addcode.png)
## 3) Expose your bot access token to Deno
@@ -211,51 +30,24 @@ Deno.serve(async (req: Request) => {
- If you're using a webhook secret (which you should), add it as a secret `webhookSecret`
-![sb](./../../assets/deno/set_secrets.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/set_secrets.png)
Verify you hit save underneath each secret you add to the playground
-![sb](./../../assets/deno/set_secrets_saved.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/set_secrets_saved.png)
## 4) Register your webhook
-- Right now if you try to interact with your "deployed" agent nothing happens, nobody is "home" to answer the knock at the door
+- Grab your playground's URL (it'll be a strange name like https://noisy-bongodrum-75.deno.dev) and register your webhook using SpeedyBot Garage
-- Grab your playground's URL (it'll likely be a strange/random name like https://noisy-bongodrum-75.deno.dev) and register your webhook using SpeedyBot Garage
+- Visit https://speedybot.js.org/garage and select **webhooks** and add your URL and optional (though highly recommeneded) webhook secret
-- Hop on over to the **[SpeedyBot Garage (https://speedybot.js.org/garage)](https://speedybot.js.org/garage)**, enter your access token, select the Webhooks tab, and then **Add New Webhook** and add your Worker's URL and (optionally but hopefully) a webhook secret
+- If all went well you should see this and your bot is up and running on Deno!
-
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_webhook.png)
## 5) Take it for a spin
After connecting webhooks, send your bot a message to take it for a spin
-
-
-
+
diff --git a/docs/new.md b/docs/new.md
index 305a31a..7f8419d 100644
--- a/docs/new.md
+++ b/docs/new.md
@@ -13,7 +13,7 @@ Follow the quick setup below to go from zero to a SpeedyBot running on your loca
The flow to get a token will look roughly like this:
settings page
https://speedybot.js.org/new
-
-
+
diff --git a/examples/deno/README.md b/examples/deno/README.md
index 5e4b5eb..376d23b 100644
--- a/examples/deno/README.md
+++ b/examples/deno/README.md
@@ -16,11 +16,11 @@ Note: The steps below assume you have a **[working WebEx account](https://develo
- Press the blue "New Playground" button
-![sb](./../../docs/assets/deno/deno_playground.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_playground.png)
Note: There are many (better) ways to setup Deno, but for now we can just use the Playground and copy/paste everything in **[index.ts](./index.ts)**
-![sb](./../../docs/assets/deno/deno_addcode.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_addcode.png)
## 3) Expose your bot access token to Deno
@@ -30,11 +30,11 @@ Note: There are many (better) ways to setup Deno, but for now we can just use th
- If you're using a webhook secret (which you should), add it as a secret `webhookSecret`
-![sb](./../../docs/assets/deno/set_secrets.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/set_secrets.png)
Verify you hit save underneath each secret you add to the playground
-![sb](./../../docs/assets/deno/set_secrets_saved.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/set_secrets_saved.png)
## 4) Register your webhook
@@ -44,7 +44,7 @@ Verify you hit save underneath each secret you add to the playground
- If all went well you should see this and your bot is up and running on Deno!
-![sb](./../../docs/assets/deno/deno_webhook.png)
+![sb](https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/deno/deno_webhook.png)
## 5) Take it for a spin
diff --git a/examples/llm-stream/settings/bot.ts b/examples/llm-stream/settings/bot.ts
index f6bf259..e5ea317 100644
--- a/examples/llm-stream/settings/bot.ts
+++ b/examples/llm-stream/settings/bot.ts
@@ -1,9 +1,9 @@
import { SpeedyBot } from "speedybot";
import { OpenAIStream } from "./llm-stream";
-const Bot = new SpeedyBot();
+const Bot = new SpeedyBot<"OPEN_AI_KEY">();
-const showDebug = false;
+const showDebug = false; // show debug info flag
Bot.exact("$clear", async ($) => {
await $.clearScreen();
@@ -34,6 +34,7 @@ Bot.addStep(async ($) => {
if ($.text) {
const rootMsg = await $.reply("Thinking...");
OpenAIStream(
+ Bot.getSecret("OPEN_AI_KEY") as string,
$.text,
async (curr, isFinal) => {
await $.edit(rootMsg, curr);
diff --git a/examples/llm-stream/settings/launch.ts b/examples/llm-stream/settings/launch.ts
index 494fb6e..b08a228 100644
--- a/examples/llm-stream/settings/launch.ts
+++ b/examples/llm-stream/settings/launch.ts
@@ -4,11 +4,22 @@ import { config } from "dotenv";
import { resolve } from "path";
config({ path: resolve(__dirname, "..", ".env") });
import { announceExit, websocketLauncher } from "../util";
+import Bot from "./bot";
process.on("exit", announceExit);
-import Bot from "./bot";
+// Assert these are available on process.env yadda-yadda, otherwise would have to `process.env.BOT_TOKEN as string`
+declare global {
+ namespace NodeJS {
+ interface ProcessEnv {
+ BOT_TOKEN: string;
+ OPEN_AI_KEY: string;
+ }
+ }
+}
+// Add secrets
Bot.setToken(process.env.BOT_TOKEN as string);
+Bot.addSecret("OPEN_AI_KEY", process.env.OPEN_AI_KEY);
// Pass in your SpeedyBot
websocketLauncher(Bot).catch((e) => console.log("##", e));
diff --git a/examples/llm-stream/settings/llm-stream.ts b/examples/llm-stream/settings/llm-stream.ts
index 5b65bcd..ca434c2 100644
--- a/examples/llm-stream/settings/llm-stream.ts
+++ b/examples/llm-stream/settings/llm-stream.ts
@@ -18,6 +18,7 @@ type Chunk = {
};
export const OpenAIStream = async (
+ apiKey: string,
prompt: string,
cb: (currentChunk: string, isFinale: boolean) => void,
config: Partial = {},
@@ -32,7 +33,7 @@ export const OpenAIStream = async (
content: prompt,
}),
},
- { apiKey: process.env.OPEN_AI_KEY }
+ { apiKey }
);
// type handler = (chunk: string, isFinished?: boolean) => void;
diff --git a/examples/speedybot-starter/settings/launch.ts b/examples/speedybot-starter/settings/launch.ts
index 494fb6e..f6ebfd2 100644
--- a/examples/speedybot-starter/settings/launch.ts
+++ b/examples/speedybot-starter/settings/launch.ts
@@ -4,9 +4,8 @@ import { config } from "dotenv";
import { resolve } from "path";
config({ path: resolve(__dirname, "..", ".env") });
import { announceExit, websocketLauncher } from "../util";
-process.on("exit", announceExit);
-
import Bot from "./bot";
+process.on("exit", announceExit);
Bot.setToken(process.env.BOT_TOKEN as string);
diff --git a/examples/voiceflow-kb/settings/launch.ts b/examples/voiceflow-kb/settings/launch.ts
index 494fb6e..7cf5ab6 100644
--- a/examples/voiceflow-kb/settings/launch.ts
+++ b/examples/voiceflow-kb/settings/launch.ts
@@ -4,11 +4,22 @@ import { config } from "dotenv";
import { resolve } from "path";
config({ path: resolve(__dirname, "..", ".env") });
import { announceExit, websocketLauncher } from "../util";
+import Bot from "./bot";
process.on("exit", announceExit);
-import Bot from "./bot";
+// Assert these are available on process.env yadda-yadda, otherwise would have to `process.env.BOT_TOKEN as string`
+declare global {
+ namespace NodeJS {
+ interface ProcessEnv {
+ BOT_TOKEN: string;
+ VOICEFLOW_API_KEY: string;
+ }
+ }
+}
+// Add secrets
Bot.setToken(process.env.BOT_TOKEN as string);
+Bot.addSecret("VOICEFLOW_API_KEY", process.env.VOICEFLOW_API_KEY);
// Pass in your SpeedyBot
websocketLauncher(Bot).catch((e) => console.log("##", e));
diff --git a/examples/voiceflow/settings/launch.ts b/examples/voiceflow/settings/launch.ts
index 494fb6e..7cf5ab6 100644
--- a/examples/voiceflow/settings/launch.ts
+++ b/examples/voiceflow/settings/launch.ts
@@ -4,11 +4,22 @@ import { config } from "dotenv";
import { resolve } from "path";
config({ path: resolve(__dirname, "..", ".env") });
import { announceExit, websocketLauncher } from "../util";
+import Bot from "./bot";
process.on("exit", announceExit);
-import Bot from "./bot";
+// Assert these are available on process.env yadda-yadda, otherwise would have to `process.env.BOT_TOKEN as string`
+declare global {
+ namespace NodeJS {
+ interface ProcessEnv {
+ BOT_TOKEN: string;
+ VOICEFLOW_API_KEY: string;
+ }
+ }
+}
+// Add secrets
Bot.setToken(process.env.BOT_TOKEN as string);
+Bot.addSecret("VOICEFLOW_API_KEY", process.env.VOICEFLOW_API_KEY);
// Pass in your SpeedyBot
websocketLauncher(Bot).catch((e) => console.log("##", e));
diff --git a/package.json b/package.json
index 1f0e0c9..fe53c2e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "speedybot",
- "version": "2.0.2",
+ "version": "2.0.3",
"main": "dist/cjs/src/index.js",
"module": "dist/mjs/src/index.js",
"types": "dist/mjs/src/index.d.ts",
diff --git a/src/cards.ts b/src/cards.ts
index 0454af6..5c84e2d 100644
--- a/src/cards.ts
+++ b/src/cards.ts
@@ -453,8 +453,9 @@ export class SpeedyCard {
}
addHeader(text: string, config: HeaderConfig = {}) {
+ const hasURL = config.iconURL?.includes("http");
+
const textPayload = {
- width: "stretch",
items: [
{
type: "TextBlock",
@@ -475,18 +476,30 @@ export class SpeedyCard {
};
const iconPayload = config.iconURL
- ? {
- width: "32px",
- items: [
- {
- type: "Image",
- horizontalAlignment: config.iconAlignment ?? "Left",
- url: config.iconURL,
- ...(config.iconRound && { style: "person" }),
- width: `${config.iconWidth ?? "16"}px`,
- },
- ],
- }
+ ? hasURL
+ ? {
+ width: "32px",
+ items: [
+ {
+ type: "Image",
+ horizontalAlignment: config.iconAlignment ?? "Left",
+ url: config.iconURL,
+ ...(config.iconRound && { style: "person" }),
+ width: `${config.iconWidth ?? "16"}px`,
+ },
+ ],
+ }
+ : {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: config.iconURL,
+ verticalContentAlignment: "Center",
+ },
+ ],
+ }
: null;
const headerPayload: {
@@ -494,6 +507,7 @@ export class SpeedyCard {
columns: (typeof textPayload | typeof iconPayload)[];
} = {
type: "ColumnSet",
+
columns: config.rtl
? [textPayload, iconPayload].filter(Boolean)
: [iconPayload, textPayload].filter(Boolean),