A focused demo of durable programmatic Think turns. It shows how to submit a message turn, receive an immediate durable ACK, retry safely with an idempotency key, inspect status later, cancel active work, and declare a recurring scheduled task.
npm install
npm startOpen the dev URL and use the dashboard to:
- Submit a prompt.
- See the immediate
{ submissionId, accepted, status }receipt. - Watch the submission move through
pending,running, and a terminal status. - Retry with the same idempotency key and confirm no duplicate turn is created.
- Cancel a pending or running submission.
- Inspect the code-declared hourly scheduled task. To watch it fire quickly
during local development, temporarily change it to
every 5 minutes.
Use submitMessages() when a webhook, RPC caller, or parent Worker needs to
start a Think turn but cannot wait for the model response.
const submission = await this.submitMessages(
[
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: prompt }]
}
],
{ idempotencyKey: externalJobId }
);The caller can return submission.submissionId immediately, then poll or render
inspectSubmission() / listSubmissions() later.
The same durable submission path is used by declarative scheduled tasks:
getScheduledTasks(): ThinkScheduledTasks {
return {
hourlyQueueDigest: {
schedule: "every 1 hour",
prompt:
"Write a concise hourly reminder that durable background task queues should be checked for stuck or failed work."
}
};
}Think reconciles this declaration on startup, schedules the next occurrence, and submits each run with a stable idempotency key so retries do not duplicate work. The example uses an hourly cadence to avoid surprising model usage; shorten it locally if you want to watch automatic submissions appear while the dashboard is open.
src/server.ts defines TaskAgent extends Think and exposes callable methods:
submitTask(prompt, idempotencyKey)wrapssubmitMessages().inspectTask(submissionId)wrapsinspectSubmission().listTasks(status?)wrapslistSubmissions().cancelTask(submissionId)wrapscancelSubmission().getScheduledTasks()declares an hourly background digest.
src/client.tsx is a submission dashboard, not a normal chat UI. It highlights
the lifecycle that matters for server-to-server callers: durable acceptance,
idempotent retry, queue status, cancellation, and terminal history.
- Use
saveMessages()when the caller can wait for the Think turn to finish. - Use
submitMessages()when the caller needs a fast durable receipt and safe retry. - Use
startFiber()around the submission when the caller also owns external side effects, such as accepting a webhook once, restoring provider state, and posting a visible reply. - Use
getScheduledTasks()when the same durable Think turn should be created on a recurring schedule. - Use Workflows when the job is a multi-step process with retries, approvals, or long waits beyond one Think turn.