sup
The sup package contains information about the patch being run and provides access to various methods for interacting with the Sup platform.
Every patch has a global sup value that can be accessed from anywhere in the code.
Properties
sup.id
string
Contains a unique string ID for the patch.
sup.id can be useful for connecting patches to share functionality.
sup.user
User
Contains a User value for the user that ran the patch for the current message.
Note: Patch interactions (like sup.button or onReply) never change the patch’s User value. User will always be the initial user that ran the patch for the current message.
sup.message
SupMessage optional
Contains a SupMessage value for the current message.
sup.chat
SupChat
Contains a SupChat value for the chat the patch was run in.
sup.chat.fs provides file storage access scoped to the current chat. See sup.fs.
sup.thread
SupThread optional
Thread-scoped helpers. This is only available when the patch is running in a thread context.
if (sup.thread) { const messages = sup.thread.history.list({ limit: 50, offset: 0 }); const total = sup.thread.history.count(); sup.thread.send('Following up in the thread');}sup.thread.history.list(options?) → SupMessage[]
Returns messages in the current thread.
limit: Maximum messages to returnoffset: Number of messages to skip (pagination)
sup.thread.history.count() → number
Returns the total number of messages in the current thread.
sup.thread.send(firstArg?, ...args) → void
Sends a message into the current thread.
if (sup.thread) { sup.thread.send('Build finished'); sup.thread.send('Here is the preview:', sup.image('https://example.com/preview.png'));}sup.isReply
boolean
sup.isReply returns true if the patch was run with a reply message attached.
When true, sup.reply returns a SupMessage value.
sup.reply
SupMessage optional
Contains a SupMessage value for the message that the current message is replying to.
sup.reply is only available when sup.isReply is true, otherwise it is undefined.
sup.input
SupInput
Contains a SupInput value for the current message. Patches usually receive user input through this object.
sup.assets
(SupImage | SupAudio | SupVideo | SupFile)[]
// Iterate over all assetsfor (const asset of sup.assets) { console.log(asset.filename);}
// Filter by type using built-in accessorsconst images = sup.assets.images; // SupImage[]const audios = sup.assets.audios; // SupAudio[]const videos = sup.assets.videos; // SupVideo[]const files = sup.assets.files; // SupFile[] (non-media files)Returns an array of all assets uploaded in the patch editor. Each asset has a filename property.
The array also has convenient accessors for filtering by type:
.images- All image assets (SupImage[]).audios- All audio assets (SupAudio[]).videos- All video assets (SupVideo[]).files- All non-media file assets (SupFile[])
CRITICAL: To get a specific asset by name, use sup.asset(name) NOT sup.assets[name]
// ❌ WRONG - This does NOT work (sup.assets is an array, not an object)const img = sup.assets["myimage.png"]; // WRONG!const img = sup.assets[filename]; // WRONG!
// ✅ CORRECT - Use sup.asset() to look up by filenameconst img = sup.asset("myimage.png"); // Correct!const img = sup.asset(filename); // Correct!sup.fs
SupFiles
Provides file storage access for the current chat, with cross-chat reads available through absolute paths when supported.
sup.fs.write('/images/output.png', sup.image('https://example.com/image.png'));const saved = sup.fs.read('/images/output.png');return saved;See the sup.fs reference for exists, list, mkdir, move, read, stat, and write.
sup.this
SupPatch
const currentPatchId = sup.this.id;const sourceCode = sup.this.code;
// Note: sup.this cannot call its own run() method or access its own public functions// to prevent infinite recursionContains metadata about the currently executing patch. This is a self-referential SupPatch object that provides information about the patch that’s currently running.
Properties:
id: The unique ID of the current patchcode: The source code of the current patchauthor: TheUserwho created this patch
Limitations:
- Cannot call
sup.this.run()- will throw an error to prevent recursion - Cannot access
sup.this.publicproperties - will throw an error to prevent recursion
This is useful for patches that need to know their own identity or source code, such as for logging, debugging, or meta-programming scenarios.
sup.caller
SupCaller
// Check if run by a user or another patchif (sup.caller.type === 'user') { return `Run by ${sup.caller.user.username}`;} else { return `Called by patch ${sup.caller.patch.name}`;}
// Check if this is a preview (unsent draft)sup.caller.isPreview // => true or falseContains a SupCaller object describing what invoked this patch. The type property is 'user' when run directly by a user, or 'patch' when called by another patch via patch.run() or patch.public.
sup.intent
SupIntent
Provides intent return values that open native Sup flows with prefilled values.
const image = sup.ai.image.create('emoji of a shooting star');return sup.intent.emoji({ name: 'star', image });See the sup.intent reference.
sup.lookup
SupLookup
Looks up chats, users, patches, and emojis by ID or slug.
const patch = sup.lookup.patch('/shahruz/weather');if (patch) { return patch.run();}See the sup.lookup reference.
Methods
sup.audio()
(urlOrBlob: string | Blob) → SupAudio
const audio = sup.audio("https://example.com/audio.mp3");const audio = sup.audio("asset.mp3");Creates a new SupAudio object from a URL, blob, or the filename of an asset uploaded in the editor. Returning this from main() will display the audio in the chat.
sup.image()
(src: string | Blob | SupSVG | SupHTML) → Image
const image = sup.image("https://example.com/image.jpg");Creates a new SupImage object from the specified URL, blob, SVG, asset uploaded in the editor, or HTML (takes a screenshot). Returning this from main() display the image in the chat.
sup.video()
(url: string | SupImage) → SupVideo
const video = sup.video("https://example.com/video.mp4");const videoFromImage = sup.video(sup.image("image.jpg")); // Convert image to 3-second videoconst customDurationVideo = sup.video(sup.image("slide.png")) .edit() .duration(5) // Override default 3-second duration .render();Creates a new SupVideo object from the specified URL or SupImage. When using a SupImage, it creates a 3-second video by default, which can be customized using the .edit().duration() method. Returning this from main() will display the video in the chat.
sup.file()
(url: string, mimeType: string) → SupFile
const file = sup.file("https://example.com/data.json", "application/json");const file = sup.file("document.pdf", "application/pdf"); // From uploaded assetCreates a new SupFile object from a URL or the filename of an asset uploaded in the editor. The mimeType parameter specifies the file’s MIME type. Returning this from main() will display a downloadable file attachment in the chat.
sup.sequence()
(clips: (SupVideo | SupImage | string)[]) → SupSequence
const sequence = sup.sequence([ "https://example.com/video1.mp4", // Full URL sup.video("video2.mp4"), // SupVideo (supports asset names) sup.image("image.jpg") // SupImage (supports asset names)]);const finalVideo = sequence.render();Creates a video sequence from multiple clips (videos, images, or URLs). Returns a SupSequence object that can be edited and rendered into a final video.
sup.html()
(html: string | SupBundle | SupFile, options?: HTMLOptions) → SupHTML
const html = sup.html("<h1>Hello, world!</h1>");Creates a new SupHTML object from the specified HTML content. Returning this from main() will display the HTML inline in the chat.
Accepts a raw HTML string, a SupBundle from sup.asset() (extracted zip bundle), or a SupFile from sup.asset() (standalone HTML file — its content is fetched automatically).
Refer to the HTMLOptions interface for available options.
sup.button()
(label: string, clickCallbackFn: Function, value?: any) → Button
The click callback function receives an argument of type:
{ "user": User, "value": any}function main() { const roll = sup.get("roll"); const lastRoller = sup.get("lastRoller"); return [ roll ? `${lastRoller} rolled a ${roll}` : `Click to roll the dice`, sup.button("Roll", handleClick, sup.random.integer(1, 6)), ];}
function handleClick(e) { sup.set("roll", e.value); sup.set("lastRoller", e.user.username);}Creates an interactive button that can be returned from main(). The callback function must be defined at the top level of your patch.
sup.keys()
→ string[]
const keys = sup.keys(); // ["gameActive", "currentRound", ...]Returns an array of all keys stored in the current scope’s datastore. If called inside a chat, this is equivalent to sup.chat.keys(). Otherwise, it is equivalent to sup.global.keys().
Keys that have been set() during the current patch run are included in the results, even before they are persisted to the database.
sup.set()
(key: string, value: any) → void
let count = sup.get("count") || 0;count++;sup.set("count", count);Sets a key-value pair in the patch’s chat state. This is equivalent to sup.chat.set().
The key can be any string, and the value can be any JSON-serializable object (including Sup classes like SupUser, SupImage, SupMessage, etc.).
To use different scopes of the datastore, refer to the set/get functions available in SupUser, SupMessage and SupGlobal.
sup.get()
(key: string) → any | null
sup.set("message", "Hello, world!");const message = sup.get("message"); // "Hello, world!"
// Returns null if the key does not existconst notFound = sup.get("notFound"); // nullRetrieves the value of a key from the patch’s chat-level state.
If the key does not exist, sup.get returns null.
sup.status()
(status: string) → void
sup.status("Fetching data...");Sets a status message for the patch while it is running.
Calling sup.status more than once in a patch run replaces the previous status message.
The status message is automatically cleared when the patch finishes running.
sup.fetch()
(url: string, options?: { method?: string; headers?: Headers; body?: string }) → FetchResponse
// GET request + JSON responseconst response = sup.fetch("https://dummyjson.com/test");const json = response.json(); // { "status": "ok", method: "GET" }
// GET request + Text responseconst response = sup.fetch("https://dummyjson.com/test");const text = response.text(); // `{"status":"ok","method":"GET"}` (string)
// GET request + Blob responseconst response = sup.fetch("https://dummyjson.com/image/150");const blob = response.blob(); // Blob for the image
// POST request + JSON responseconst response = sup.fetch("https://dummyjson.com/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: "value" }),});const json = response.json(); // { "status": "ok", method: "POST" }Performs an HTTP request to the specified URL.
The options parameter can be used to customize the request method, headers, and body.
The response should be handled using the json, text, or blob methods on the returned FetchResponse object.
sup.uuid()
→ string
const id = sup.uuid(); // "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" (v4 UUID)Generates a random UUID (v4) string.
sup.asset()
(filename: string) → SupAudio | SupImage | SupVideo | SupFile | SupBundle
This is the correct way to get an asset by filename.
// ✅ CORRECT - Look up assets by filename using sup.asset()const image = sup.asset("image.jpg");const audio = sup.asset("sound.mp3");const video = sup.asset("clip.mp4");const bundle = sup.asset("myApp"); // Uploaded zip bundle
// ❌ WRONG - Do NOT use sup.assets[name] (that's an array, not an object)const image = sup.assets["image.jpg"]; // WRONG! Will not work!Returns the asset matching the given filename. The returned asset can be a SupImage, SupAudio, SupVideo, SupFile, or SupBundle depending on what was uploaded. Zip files uploaded as assets are automatically processed as bundles.
Both SupBundle and SupFile assets (e.g. a standalone .html file) can be passed directly to sup.html():
// Bundle (from uploaded zip)sup.html(sup.asset("myApp"));
// Standalone HTML filesup.html(sup.asset("index.html"));sup.secret()
(key: string) → string
const apiKey = sup.secret("API_KEY");Loads a secret value from the patch’s secrets by key.
Secrets can be used to store sensitive information like API keys.
If the secret does not exist, sup.secret will throw an error.
sup.emoji()
(name: string) → SupEmoji | undefined
const emoji = sup.emoji("baby/a");Loads an emoji from Sup emoji library by name.
sup.scrape()
(url: string, prompt?: string) → string
const scrape = sup.scrape( "https://en.wikipedia.org/wiki/Wikipedia:On_this_day/Today", "Summarize the events listed on this page.");Performs a web scrape on the specified URL with an optional prompt for AI processing.
If a prompt is provided, the response string will be the AI-generated response.
Otherwise, the response string will be a Markdown-formatted version of the web page’s primary contents.
sup.screenshot()
(url: string, selector?: string) → SupImage
// Screenshot entire pageconst screenshot = sup.screenshot("https://example.com");
// Screenshot specific elementconst element = sup.screenshot("https://example.com", "#main-content");Takes a screenshot of the specified URL and returns it as a SupImage. Optionally provide a CSS selector to capture only a specific element on the page.
sup.makePublic()
(...Function[]) → void
function init() { sup.makePublic([add, reset, getCount]);}
function main() { const count = sup.get("count") || 0; return [count, sup.button("Add", add)];}
function add() { let count = sup.get("count") || 0; count++; sup.set("count", count);}
function reset() { sup.set("count", 0);}
function getCount() { return sup.get("count") || 0;}Makes the specified functions public, allowing them to be called from other patches. makePublic should be called in the init function. It can accept one or more functions as arguments.
sup.patch()
(patchIdOrFullname: string) → SupPatch
function main() { // Using patch ID const patch1 = sup.patch("cm37ij7tq000008l5h9asc2tb");
// Using full name format /username/patchname const patch2 = sup.patch("/hiro/counter");
// Call public functions via .public patch1.public.add(); const count = patch1.public.getCount();
// Access patch properties const sourceCode = patch2.code; const patchId = patch2.id;
// Directly run the patch's main() function const result = patch2.run("Hello", "World");
return count;}Retrieves an instance of another patch by its ID or full name. You can specify either:
- A patch ID (e.g.,
"cm37ij7tq000008l5h9asc2tb") - A full name in the format
/username/patchname(e.g.,"/hiro/counter")
The returned SupPatch object provides access to the patch’s public functions, source code, and other properties.
SupPatch Properties
patch.id
string - The unique ID of the patch.
patch.code
string - The source code of the patch.
patch.author
User - The author (creator) of the patch. Returns a SupUser object with properties like username, displayName, pfp, bio, etc.
const patch = sup.patch("/hiro/counter");const authorName = patch.author.username;const authorBio = patch.author.bio;
// Also available on sup.thisconst myAuthor = sup.this.author;patch.public
object - Contains all functions and data exposed via sup.makePublic(). Access public functions as patch.public.functionName() and public data as patch.public.dataName.
SupPatch Methods
patch.run(...args)
(...args: any[]) → any - Directly invokes the patch’s main() function with the provided arguments, bypassing the normal message input system.
sup.dump()
(obj: any) → string
const obj = { foo: "bar", nested: { value: 123 } };const str = sup.dump(obj); // Returns a debugging string representationReturns a debugging string representation of the given object.
sup.serialize()
(obj: SupSerializable) → JSONObject
const data = { foo: "bar", image: sup.image("example.jpg") };const serialized = sup.serialize(data);Serializes a Sup-serializable object into a JSON-compatible format. Supports serializing Sup objects like SupImage, SupAudio, SupVideo, etc.
sup.deserialize()
(obj: JSONObject) → SupSerializable
const serialized = { type: "image", url: "example.jpg" };const image = sup.deserialize(serialized);Deserializes a JSON object serialized via sup.serialize.
sup.metadata()
(data: any) → SupMetadata
// Chess game: return visible board image with invisible game stateconst boardImage = renderBoard(fen);return [ boardImage, sup.metadata({ fen: "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1", pgn: "1. e4" })];Another patch can access this metadata when replying:
// Access game state from the replied-to messageconst gameState = sup.reply.metadata[0];const currentFen = gameState.fen;const moveHistory = gameState.pgn;Creates a SupMetadata object containing data that won’t be rendered in the chat but can be accessed by other patches and NPCs. This is useful for passing structured data between patches or providing context to AI-powered NPCs without cluttering the visible output.
Note: metadata returns an array since a message can contain multiple metadata objects.
sup.sleep()
(ms: number) → void
sup.sleep(1000); // Pause for 1 secondPauses execution for the specified number of milliseconds.
sup.svg()
(content: string) → SupSVG
const svg = sup.svg( '<svg><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/></svg>');Creates a new SupSVG object from the specified SVG content.
sup.gif()
(imagesOrVideo: SupImage[] | SupVideo, options?: { frameRate?: number }) → SupImage
const gif = sup.gif([sup.image("image1.jpg"), sup.image("image2.jpg")]);Creates a GIF (as a SupImage object) from the provided images or video.
sup.segment()
(users, matchingElements?, notMatchingElements?) → SupSegment
Important limitations:
- Client-side only: Segments control what is displayed, but all segment data is sent to every user
- No access restriction: This is for UI personalization, not security. Do not include sensitive data in segments—check
sup.userin your patch logic instead
// Show different content to a specific userconst segment = sup.segment( user, "Content only this user sees", "Content everyone else sees");
// Target multiple usersconst segment = sup.segment( [user1, user2], ["Content for these users"], ["Content for others"]);Creates a SupSegment that shows different content to different users.