Source: _generated/function-usage-examples.md in the local directory context-collection (not yet on origin/platform), synced 2026-09-26. Do not edit this page here; change the source and run yarn sync:studio.
That source is itself generated (by arch/context-collection/build.py from ui-bicycle-studio ffe4768 src/pages/functions/usageDocs.ts (two example functions)); change its source and re-run its build.
Studio's function page generates this text per function. Two examples follow (tenant acme is a placeholder), a code function and an agent. Today it is generated only in the UI; MCP cannot serve it yet (MCP-GITHUB-CHANGES.md Rank 4).
Call the function order_count from a Bicycle data app
Count orders
Kind: code. Ref (pinned): fn:acme/order_count@3
1. Declare it in the app manifest
// bda.manifest.json
"functions": {
"order_count": { "ref": "fn:acme/order_count@3" }
}
The app may call only names declared here. Never pass a ref from code; the host refuses undeclared names.
2. Input (input_schema)
day: string (required) - YYYY-MM-DD
{
"type": "object",
"required": [
"day"
],
"properties": {
"day": {
"type": "string",
"description": "YYYY-MM-DD"
}
}
}
3. Call it
import { bda } from "./studio/bda.js";
try {
const out = await bda.fn.call("order_count", {
"day": "<YYYY-MM-DD>"
});
// out: {
// "orders": 1
// }
} catch (error) {
// A BdaError with a code and a readable message, e.g. fn_not_declared, input_invalid,
// function_disabled, budget_exceeded, cancelled. Show error.message to the viewer.
}
With progress (for anything slow):
// Start it, show progress while it runs, allow Cancel.
const started = await bda.fn.call("order_count", input, { wait: false });
const watch = bda.fn.watch(started.invocation_id, batch => {
// batch.items: [{ title: "Step 3", detail, meta }, { title: "Atlassian · search", ... }] - plain words
// batch.events / batch.agentEvents: the raw trace events, if you draw your own
showProgress(batch.items);
});
cancelButton.onclick = () => bda.fn.cancel(started.invocation_id);
const final = await watch.done; // the Invocation: status, output, error, usage { llm_usd, wall_ms }
const out = bda.fn.outputOf(final); // throws a BdaError in words if it failed or was cancelled
// Or in one call: bda.fn.run(name, input, { onEvent, onStart }) resolves with the final Invocation.
4. Run it on page load (if the product wants that)
// On page load: ALWAYS pass reuse, so a reload (or the next viewer visit) answers with this viewer's
// latest result of the same input instead of a new run. "6h" = reuse a result that started within 6 hours
// (s / m / h; held to 24h; "0" = always a new run).
const inv = await bda.fn.call("order_count", input, { wait: false, reuse: "6h" });
// inv.reused === true: a stored result, no run and no cost. inv.attached === true: the same run already in flight.
showAsOf(inv.created_at); // "as of 09:14 · Refresh"
refreshButton.onclick = () => bda.fn.call("order_count", input, { wait: false, refresh: true }); // always a new run
// An agent may wait its turn: status "queued" with queue_position (runs ahead of it; 0 = next).
// Show "Queued · 2 ahead" ("Queued · next" at 0). Keep watching: the run starts on its own and the
// position arrives again as status events named "queued" (data.queue_position). error.code queue_timeout =
// it waited too long in the queue: say so and offer to try again.
- For auto-run on page load ALWAYS pass
reuse(e.g.{ reuse: "6h" }): a result the viewer got recently comes back at once (reused: true), with no run and no cost. - Show "as of <time> · Refresh" from the invocation's
created_at; Refresh calls again with{ refresh: true }. - A queued agent run has
status: "queued"andqueue_position: show "Queued · N ahead" ("Queued · next" at 0) and keep watching.
5. Output (output_schema)
out is the function's output (object):
orders: integer
Example: { "orders": 1 }
{
"type": "object",
"properties": {
"orders": {
"type": "integer"
}
}
}
Rules
bdais Studio's app SDK:src/studio/bda.ts+src/studio/fn.ts, from MCPdataapp_sdkorGET /api/data-apps/sdk(the public template does not carry them yet); the Studio host answers its messages.- Call only the declared local name (
order_count), throughbda.fn. No direct fetches, no refs in code. - The output is data: render it as text (React text nodes, table cells). Never inject it as HTML.
- Keep input small (under 64 KB as JSON); large inputs belong in a blob.
- Start it from a button's onClick, not a
<form>submit: the app's sandbox has no allow-forms, so submit never fires. - Show a busy state while it runs; disable the button that started it.
- Handle errors: show
error.message; branch onerror.code(e.g.connector_not_connected-> ask the viewer to connect). - It runs as the viewer: what it reads is what the viewer may read.
- Show cost and time from the final invocation's
usage(llm_usd,wall_ms) when it helps the viewer.
Cost and time
Code: usually well under a second to a few seconds once warm (a cold start adds a few seconds). Billed in compute units; no model cost. Time limit: 10 s.
Call the function triage_failed_order from a Bicycle data app
Triage a failed order
Kind: agent (async). Ref (pinned): fn:acme/triage_failed_order@2
1. Declare it in the app manifest
// bda.manifest.json
"functions": {
"triage_failed_order": { "ref": "fn:acme/triage_failed_order@2" }
}
The app may call only names declared here. Never pass a ref from code; the host refuses undeclared names.
2. Input (input_schema)
order_id: string (required)
{
"type": "object",
"required": [
"order_id"
],
"properties": {
"order_id": {
"type": "string"
}
}
}
3. Call it
import { bda } from "./studio/bda.js";
try {
const out = await bda.fn.call("triage_failed_order", {
"order_id": "<order_id>"
});
// out: {
// "route": "payments",
// "summary": "<summary>"
// }
} catch (error) {
// A BdaError with a code and a readable message, e.g. fn_not_declared, input_invalid,
// function_disabled, budget_exceeded, cancelled. Show error.message to the viewer.
}
This function is slow (async). Show progress:
// Start it, show progress while it runs, allow Cancel.
const started = await bda.fn.call("triage_failed_order", input, { wait: false });
const watch = bda.fn.watch(started.invocation_id, batch => {
// batch.items: [{ title: "Step 3", detail, meta }, { title: "Atlassian · search", ... }] - plain words
// batch.events / batch.agentEvents: the raw trace events, if you draw your own
showProgress(batch.items);
});
cancelButton.onclick = () => bda.fn.cancel(started.invocation_id);
const final = await watch.done; // the Invocation: status, output, error, usage { llm_usd, wall_ms }
const out = bda.fn.outputOf(final); // throws a BdaError in words if it failed or was cancelled
// Or in one call: bda.fn.run(name, input, { onEvent, onStart }) resolves with the final Invocation.
4. Run it on page load (if the product wants that)
// On page load: ALWAYS pass reuse, so a reload (or the next viewer visit) answers with this viewer's
// latest result of the same input instead of a new run. "6h" = reuse a result that started within 6 hours
// (s / m / h; held to 24h; "0" = always a new run).
const inv = await bda.fn.call("triage_failed_order", input, { wait: false, reuse: "6h" });
// inv.reused === true: a stored result, no run and no cost. inv.attached === true: the same run already in flight.
showAsOf(inv.created_at); // "as of 09:14 · Refresh"
refreshButton.onclick = () => bda.fn.call("triage_failed_order", input, { wait: false, refresh: true }); // always a new run
// An agent may wait its turn: status "queued" with queue_position (runs ahead of it; 0 = next).
// Show "Queued · 2 ahead" ("Queued · next" at 0). Keep watching: the run starts on its own and the
// position arrives again as status events named "queued" (data.queue_position). error.code queue_timeout =
// it waited too long in the queue: say so and offer to try again.
- For auto-run on page load ALWAYS pass
reuse(e.g.{ reuse: "6h" }): a result the viewer got recently comes back at once (reused: true), with no run and no cost. - Show "as of <time> · Refresh" from the invocation's
created_at; Refresh calls again with{ refresh: true }. - A queued agent run has
status: "queued"andqueue_position: show "Queued · N ahead" ("Queued · next" at 0) and keep watching.
5. Output (output_schema)
out is the function's output (object):
route: stringsummary: string
Example: { "route": "payments", "summary": "<summary>" }
{
"type": "object",
"properties": {
"route": {
"type": "string",
"enum": [
"payments",
"stock",
"other"
]
},
"summary": {
"type": "string"
}
}
}
Rules
bdais Studio's app SDK:src/studio/bda.ts+src/studio/fn.ts, from MCPdataapp_sdkorGET /api/data-apps/sdk(the public template does not carry them yet); the Studio host answers its messages.- Call only the declared local name (
triage_failed_order), throughbda.fn. No direct fetches, no refs in code. - The output is data: render it as text (React text nodes, table cells). Never inject it as HTML.
- Keep input small (under 64 KB as JSON); large inputs belong in a blob.
- Start it from a button's onClick, not a
<form>submit: the app's sandbox has no allow-forms, so submit never fires. - Run it only when the viewer asks (a button), unless the product explicitly wants it on load (then with
reuse, see 4). Show progress and a Cancel button. - Handle errors: show
error.message; branch onerror.code(e.g.connector_not_connected-> ask the viewer to connect). - It runs as the viewer: what it reads is what the viewer may read.
- Show cost and time from the final invocation's
usage(llm_usd,wall_ms) when it helps the viewer.
Cost and time
Agent: several model steps and tool calls - typically 30 s to a few minutes and a few cents to about a dollar per run. Always async: show progress, allow Cancel, and never run it on page load unless the product asks for it. Cost cap per run: $1.25. At most 20 steps.