From a62cb3e60b6e84d4ff8221d36dc7d50958bd19b2 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Thu, 13 Feb 2025 14:51:43 +0000 Subject: [PATCH] Agent docs examples (#1706) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Uses image cards for the frameworks * Removes old snippets * New AI agents side menu section * WIP adding new ai agent pages * Better overview page * More copy added to the agent example pages * Copy improvements * Removes “Creating a project” page and side menu section * Fixes broken links * Updates to the latest Mintlify version, fixes issues, changes theme * Adds descriptions to the main dropdown menu items * Reformatted Introduction docs ‘landing page’ * Retry heartbeat timeouts by putting back in the queue (#1689) * If there’s a heartbeat error and no attempts we put it back in the queue to try again * When nacking, return whether it was put back in the queue or not * Try and nack, if it fails then fail the run * Consolidated switch statement * Fail executing/retrying runs * OOM retrying on larger machines (#1691) * OOM retrying on larger machines * Create forty-windows-shop.md * Update forty-windows-shop.md * Only retry again if the machine is different from the original * Kubernetes OOMs appear as non-zero sigkills, adding support for treating these as OOMs * Complete the original attempt span if retrying due to an OOM * Revert "Complete the original attempt span if retrying due to an OOM" This reverts commit 5f652c6212728c170f12d95484587b425dd89df9. * chore: Update version for release (#1666) Co-authored-by: github-actions[bot] * Release 3.3.14 * Set machine when triggering docs * Batch queue runs that are waiting for deploy (#1693) * Detect ffmpeg OOM errors, added manual OutOfMemoryError (#1694) * Detect ffmpeg OOM errors, added manual OutOfMemoryError * Create eighty-spies-knock.md * Improved the machines docs, including the new OutOfMemoryError * chore: Update version for release (#1695) Co-authored-by: github-actions[bot] * Release 3.3.15 * Create new partitioned TaskEvent table, and switch to it gradually as new runs are created (#1696) * Create new partitioned TaskEvent table, and switch to it gradually as new runs are created * Add env var for partition window in seconds * Make startCreatedAt required in task event store * Don't create an attempt if the run is final, batchTriggerAndWait bad continue fix (#1698) * WIP fix for ResumeAttemptService selecting the wrong attempt (which has no error or output) * Don’t create an attempt if the run is already in a final status * Don’t get all the columns for the query. Improved the logging. * Added a log to the batch example * Filter out the undefined values * Fix missing logs on child runs by using the root task run createdAt if it exists (#1697) * Provider changes to support image cache (#1700) * add env var for additional pull secrets * make static images configurable * optional image prefixes * optional labels with sample rates * add missing core paths * remove excessive logs * Fix run container exits after OOM retries (#1701) * remove unused imports * tell run to exit before force requeue * handle exit for case where we already retried after oom * improve retry span and add machine props * don't try to exit run in dev * Upgrade local dev to use electric beta.15 (#1699) * Text fixes * Removed pnpm files --------- Co-authored-by: Matt Aitken Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Eric Allam Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com> --- docs/docs.json | 484 ++++++++++++++++++ docs/guides/ai-agents/evaluator-optimizer.png | Bin 0 -> 20053 bytes .../ai-agents/generate-translate-copy.mdx | 120 +++++ .../guides/ai-agents/orchestrator-workers.png | Bin 0 -> 17641 bytes docs/guides/ai-agents/overview.mdx | 17 + docs/guides/ai-agents/parallelization.png | Bin 0 -> 16124 bytes docs/guides/ai-agents/prompt-chaining.png | Bin 0 -> 16700 bytes .../ai-agents/respond-and-check-content.mdx | 134 +++++ docs/guides/ai-agents/route-question.mdx | 114 +++++ docs/guides/ai-agents/routing.png | Bin 0 -> 17817 bytes .../guides/ai-agents/translate-and-refine.mdx | 170 ++++++ docs/guides/ai-agents/verify-news-article.mdx | 220 ++++++++ docs/guides/dashboard/creating-a-project.mdx | 36 -- .../example-projects/realtime-fal-ai.mdx | 20 +- .../examples/fal-ai-image-to-cartoon.mdx | 12 +- docs/guides/examples/fal-ai-realtime.mdx | 14 +- docs/guides/examples/scrape-hacker-news.mdx | 14 +- .../supabase-edge-functions-basic.mdx | 2 +- ...abase-edge-functions-database-webhooks.mdx | 2 +- docs/guides/introduction.mdx | 24 +- .../creating-a-project-1.png | Bin 202959 -> 0 bytes .../creating-a-project-2.png | Bin 156237 -> 0 bytes .../creating-a-project-3.png | Bin 205705 -> 0 bytes docs/images/intro-browserbase.jpg | Bin 0 -> 5397 bytes docs/images/intro-deepgram.jpg | Bin 0 -> 5951 bytes docs/images/intro-examples.jpg | Bin 0 -> 23883 bytes docs/images/intro-fal.jpg | Bin 0 -> 7463 bytes docs/images/intro-ffmpeg.jpg | Bin 0 -> 15533 bytes docs/images/intro-firecrawl.jpg | Bin 0 -> 11637 bytes docs/images/intro-frameworks.jpg | Bin 0 -> 25339 bytes docs/images/intro-libreoffice.jpg | Bin 0 -> 6022 bytes docs/images/intro-openai.jpg | Bin 0 -> 12924 bytes docs/images/intro-puppeteer.jpg | Bin 0 -> 9871 bytes docs/images/intro-quickstart.jpg | Bin 0 -> 25454 bytes docs/images/intro-resend.jpg | Bin 0 -> 5696 bytes docs/images/intro-sentry.jpg | Bin 0 -> 10346 bytes docs/images/intro-sharp.jpg | Bin 0 -> 10501 bytes docs/images/intro-supabase.jpg | Bin 0 -> 7874 bytes docs/images/intro-vercel.jpg | Bin 0 -> 4539 bytes docs/images/intro-video.jpg | Bin 0 -> 23246 bytes docs/images/logo-bun.png | Bin 0 -> 14260 bytes docs/images/logo-nextjs.png | Bin 0 -> 8014 bytes docs/images/logo-nodejs-1.png | Bin 0 -> 14096 bytes docs/images/logo-nodejs.png | Bin 0 -> 6632 bytes docs/images/logo-remix.png | Bin 0 -> 14259 bytes docs/introduction.mdx | 135 +++-- docs/mint.json | 392 -------------- docs/realtime/overview.mdx | 14 +- docs/snippets/card-bun.mdx | 10 - docs/snippets/card-nextjs.mdx | 22 - docs/snippets/card-nodejs.mdx | 11 - docs/snippets/card-remix.mdx | 206 -------- docs/snippets/card-supabase.mdx | 34 -- docs/snippets/framework-prerequisites.mdx | 2 +- docs/video-walkthrough.mdx | 4 +- 55 files changed, 1396 insertions(+), 817 deletions(-) create mode 100644 docs/docs.json create mode 100644 docs/guides/ai-agents/evaluator-optimizer.png create mode 100644 docs/guides/ai-agents/generate-translate-copy.mdx create mode 100644 docs/guides/ai-agents/orchestrator-workers.png create mode 100644 docs/guides/ai-agents/overview.mdx create mode 100644 docs/guides/ai-agents/parallelization.png create mode 100644 docs/guides/ai-agents/prompt-chaining.png create mode 100644 docs/guides/ai-agents/respond-and-check-content.mdx create mode 100644 docs/guides/ai-agents/route-question.mdx create mode 100644 docs/guides/ai-agents/routing.png create mode 100644 docs/guides/ai-agents/translate-and-refine.mdx create mode 100644 docs/guides/ai-agents/verify-news-article.mdx delete mode 100644 docs/guides/dashboard/creating-a-project.mdx delete mode 100644 docs/images/creating-a-project/creating-a-project-1.png delete mode 100644 docs/images/creating-a-project/creating-a-project-2.png delete mode 100644 docs/images/creating-a-project/creating-a-project-3.png create mode 100644 docs/images/intro-browserbase.jpg create mode 100644 docs/images/intro-deepgram.jpg create mode 100644 docs/images/intro-examples.jpg create mode 100644 docs/images/intro-fal.jpg create mode 100644 docs/images/intro-ffmpeg.jpg create mode 100644 docs/images/intro-firecrawl.jpg create mode 100644 docs/images/intro-frameworks.jpg create mode 100644 docs/images/intro-libreoffice.jpg create mode 100644 docs/images/intro-openai.jpg create mode 100644 docs/images/intro-puppeteer.jpg create mode 100644 docs/images/intro-quickstart.jpg create mode 100644 docs/images/intro-resend.jpg create mode 100644 docs/images/intro-sentry.jpg create mode 100644 docs/images/intro-sharp.jpg create mode 100644 docs/images/intro-supabase.jpg create mode 100644 docs/images/intro-vercel.jpg create mode 100644 docs/images/intro-video.jpg create mode 100644 docs/images/logo-bun.png create mode 100644 docs/images/logo-nextjs.png create mode 100644 docs/images/logo-nodejs-1.png create mode 100644 docs/images/logo-nodejs.png create mode 100644 docs/images/logo-remix.png delete mode 100644 docs/mint.json delete mode 100644 docs/snippets/card-bun.mdx delete mode 100644 docs/snippets/card-nextjs.mdx delete mode 100644 docs/snippets/card-nodejs.mdx delete mode 100644 docs/snippets/card-remix.mdx delete mode 100644 docs/snippets/card-supabase.mdx diff --git a/docs/docs.json b/docs/docs.json new file mode 100644 index 000000000..8649b22cb --- /dev/null +++ b/docs/docs.json @@ -0,0 +1,484 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "maple", + "name": "Trigger.dev", + "description": "Trigger.dev is an open source background jobs framework that lets you write reliable workflows in plain async code. Run long-running AI tasks, handle complex background jobs, and build AI agents with built-in queuing, automatic retries, and real-time monitoring. No timeouts, elastic scaling, and zero infrastructure management required.", + "colors": { + "primary": "#A8FF53", + "light": "#A8FF53", + "dark": "#A8FF53" + }, + "favicon": "/images/favicon.png", + "navigation": { + "dropdowns": [ + { + "dropdown": "Documentation", + "description": "Resources for Trigger.dev", + "icon": "book-open", + "groups": [ + { + "group": "Getting started", + "pages": ["introduction", "quick-start", "video-walkthrough", "how-it-works", "limits"] + }, + { + "group": "Fundamentals", + "pages": [ + { + "group": "Tasks", + "pages": ["tasks/overview", "tasks/schemaTask", "tasks/scheduled"] + }, + "triggering", + "runs", + "apikeys", + { + "group": "Configuration", + "pages": ["config/config-file", "config/extensions/overview"] + } + ] + }, + { + "group": "Development", + "pages": ["cli-dev", "run-tests"] + }, + { + "group": "Deployment", + "pages": [ + "cli-deploy", + "deploy-environment-variables", + "github-actions", + { + "group": "Deployment integrations", + "pages": ["vercel-integration"] + } + ] + }, + { + "group": "Writing tasks", + "pages": [ + "writing-tasks-introduction", + "logging", + "errors-retrying", + { + "group": "Wait", + "pages": ["wait", "wait-for", "wait-until", "wait-for-event", "wait-for-request"] + }, + "queue-concurrency", + "versioning", + "machines", + "idempotency", + "replaying", + "runs/max-duration", + "tags", + "runs/metadata", + "run-usage", + "context", + "bulk-actions", + "examples" + ] + }, + { + "group": "Frontend usage", + "pages": [ + "frontend/overview", + { + "group": "React hooks", + "pages": [ + "frontend/react-hooks/overview", + "frontend/react-hooks/realtime", + "frontend/react-hooks/triggering" + ] + } + ] + }, + { + "group": "Realtime API", + "pages": [ + "realtime/overview", + "realtime/streams", + "realtime/react-hooks", + "realtime/subscribe-to-run", + "realtime/subscribe-to-runs-with-tag", + "realtime/subscribe-to-batch" + ] + }, + { + "group": "API reference", + "pages": [ + "management/overview", + { + "group": "Tasks API", + "pages": ["management/tasks/trigger", "management/tasks/batch-trigger"] + }, + { + "group": "Runs API", + "pages": [ + "management/runs/list", + "management/runs/retrieve", + "management/runs/replay", + "management/runs/cancel", + "management/runs/reschedule", + "management/runs/update-metadata" + ] + }, + { + "group": "Schedules API", + "pages": [ + "management/schedules/list", + "management/schedules/create", + "management/schedules/retrieve", + "management/schedules/update", + "management/schedules/delete", + "management/schedules/deactivate", + "management/schedules/activate", + "management/schedules/timezones" + ] + }, + { + "group": "Env Vars API", + "pages": [ + "management/envvars/list", + "management/envvars/import", + "management/envvars/create", + "management/envvars/retrieve", + "management/envvars/update", + "management/envvars/delete" + ] + }, + { + "group": "Projects API", + "pages": ["management/projects/runs"] + } + ] + }, + { + "group": "CLI", + "pages": [ + "cli-introduction", + { + "group": "Commands", + "pages": [ + "cli-login-commands", + "cli-init-commands", + "cli-dev-commands", + "cli-deploy-commands", + "cli-whoami-commands", + "cli-logout-commands", + "cli-list-profiles-commands", + "cli-update-commands" + ] + } + ] + }, + { + "group": "Open source", + "pages": [ + "open-source-self-hosting", + "open-source-contributing", + "github-repo", + "changelog", + "roadmap" + ] + }, + { + "group": "Troubleshooting", + "pages": [ + "troubleshooting", + "upgrading-packages", + "upgrading-beta", + "troubleshooting-alerts", + "troubleshooting-uptime-status", + "troubleshooting-github-issues", + "request-feature" + ] + }, + { + "group": "Help", + "pages": ["community", "help-slack", "help-email"] + } + ] + }, + { + "dropdown": "Guides & examples", + "description": "A great way to get started", + "icon": "book", + "groups": [ + { + "group": "Introduction", + "pages": ["guides/introduction"] + }, + { + "group": "Frameworks", + "pages": [ + "guides/frameworks/bun", + "guides/frameworks/nextjs", + "guides/frameworks/nodejs", + "guides/frameworks/remix" + ] + }, + { + "group": "Guides", + "pages": [ + { + "group": "AI Agents", + "icon": { + "name": "microchip-ai", + "style": "regular" + }, + "pages": [ + "guides/ai-agents/overview", + "guides/ai-agents/generate-translate-copy", + "guides/ai-agents/route-question", + "guides/ai-agents/respond-and-check-content", + "guides/ai-agents/verify-news-article", + "guides/ai-agents/translate-and-refine" + ] + }, + "guides/frameworks/drizzle", + "guides/frameworks/prisma", + "guides/frameworks/sequin", + { + "group": "Supabase", + "icon": { + "name": "bolt", + "style": "solid" + }, + "pages": [ + "guides/frameworks/supabase-guides-overview", + "guides/frameworks/supabase-edge-functions-basic", + "guides/frameworks/supabase-edge-functions-database-webhooks" + ] + }, + { + "group": "Webhooks", + "icon": { + "name": "webhook", + "style": "solid" + }, + "pages": [ + "guides/frameworks/webhooks-guides-overview", + "guides/frameworks/nextjs-webhooks", + "guides/frameworks/remix-webhooks", + "guides/examples/stripe-webhook" + ] + } + ] + }, + { + "group": "Example projects", + "pages": [ + "guides/example-projects/realtime-fal-ai", + "guides/example-projects/batch-llm-evaluator", + "guides/example-projects/realtime-csv-importer", + "guides/example-projects/vercel-ai-sdk-image-generator" + ] + }, + { + "group": "Example tasks", + "pages": [ + "guides/examples/dall-e3-generate-image", + "guides/examples/deepgram-transcribe-audio", + "guides/examples/fal-ai-image-to-cartoon", + "guides/examples/fal-ai-realtime", + "guides/examples/ffmpeg-video-processing", + "guides/examples/firecrawl-url-crawl", + "guides/examples/libreoffice-pdf-conversion", + "guides/examples/open-ai-with-retrying", + "guides/examples/pdf-to-image", + "guides/examples/puppeteer", + "guides/examples/scrape-hacker-news", + "guides/examples/sentry-error-tracking", + "guides/examples/sharp-image-processing", + "guides/examples/supabase-database-operations", + "guides/examples/supabase-storage-upload", + "guides/examples/react-pdf", + "guides/examples/resend-email-sequence", + "guides/examples/vercel-ai-sdk", + "guides/examples/vercel-sync-env-vars" + ] + }, + { + "group": "Migrations", + "pages": ["guides/use-cases/upgrading-from-v2"] + } + ] + } + ] + }, + "logo": { + "light": "/logo/light.png", + "dark": "/logo/dark.png", + "href": "https://trigger.dev" + }, + "api": { + "openapi": ["openapi.yml", "v3-openapi.yaml"], + "playground": { + "display": "simple" + } + }, + "appearance": { + "default": "dark", + "strict": true + }, + "background": { + "color": { + "light": "#fff", + "dark": "#121317" + } + }, + "navbar": { + "primary": { + "type": "github", + "href": "https://github.com/triggerdotdev/trigger.dev" + } + }, + "footer": { + "socials": { + "x": "https://twitter.com/triggerdotdev", + "github": "https://github.com/triggerdotdev", + "linkedin": "https://www.linkedin.com/company/triggerdotdev" + }, + "links": [ + { + "header": "Developers", + "items": [ + { + "label": "Changelog", + "href": "https://trigger.dev/changelog" + }, + { + "label": "Contributing", + "href": "https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md" + }, + { + "label": "Open source", + "href": "https://github.com/triggerdotdev/trigger.dev?tab=Apache-2.0-1-ov-file#readme" + }, + { + "label": "GitHub", + "href": "https://github.com/triggerdotdev/trigger.dev" + }, + { + "label": "OSS Friends", + "href": "https://trigger.dev/oss-friends" + } + ] + }, + { + "header": "Product", + "items": [ + { + "label": "Pricing", + "href": "https://trigger.dev/pricing" + }, + { + "label": "How it works", + "href": "https://trigger.dev/#how-it-works" + }, + { + "label": "Features", + "href": "https://trigger.dev/product" + }, + { + "label": "Roadmap", + "href": "https://feedback.trigger.dev/roadmap" + }, + { + "label": "FAQs", + "href": "https://trigger.dev/pricing#faqs" + }, + { + "label": "Uptime status", + "href": "https://status.trigger.dev/" + } + ] + }, + { + "header": "Company", + "items": [ + { + "label": "Blog", + "href": "https://trigger.dev/blog" + }, + { + "label": "Contact", + "href": "https://trigger.dev/contact" + }, + { + "label": "Careers", + "href": "https://trigger.dev/jobs" + }, + { + "label": "Privacy", + "href": "https://trigger.dev/legal/privacy" + }, + { + "label": "Terms of service", + "href": "https://trigger.dev/legal" + } + ] + } + ] + }, + "redirects": [ + { + "source": "/v3/feature-matrix", + "destination": "https://feedback.trigger.dev/roadmap" + }, + { + "source": "/v3/upgrading-from-v2", + "destination": "/guides/use-cases/upgrading-from-v2" + }, + { + "source": "/v3/open-source-self-hosting", + "destination": "/open-source-self-hosting" + }, + { + "source": "/v3/:slug*", + "destination": "/:slug*" + }, + { + "source": "/reattempting-replaying", + "destination": "/replaying" + }, + { + "source": "/tasks-overview", + "destination": "/tasks/overview" + }, + { + "source": "/tasks-scheduled", + "destination": "/tasks/scheduled" + }, + { + "source": "/trigger-folder", + "destination": "/config/config-file" + }, + { + "source": "/trigger-config", + "destination": "/config/config-file" + }, + { + "source": "/guides/frameworks/introduction", + "destination": "/guides/introduction" + }, + { + "source": "/guides/examples/intro", + "destination": "/guides/introduction" + }, + { + "source": "/examples/:slug*", + "destination": "/guides/examples/:slug*" + }, + { + "source": "/realtime", + "destination": "/realtime/overview" + }, + { + "source": "/runs-and-attempts", + "destination": "/runs" + }, + { + "source": "/frontend/react-hooks", + "destination": "/frontend/react-hooks/overview" + } + ] +} diff --git a/docs/guides/ai-agents/evaluator-optimizer.png b/docs/guides/ai-agents/evaluator-optimizer.png new file mode 100644 index 0000000000000000000000000000000000000000..4ec95643cf112fed442c3a0b6d20d9308893fd50 GIT binary patch literal 20053 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 Y`FhJfnYsn7uRx}Iy85}Sb4q9e0NNACWB>pF literal 0 HcmV?d00001 diff --git a/docs/guides/ai-agents/generate-translate-copy.mdx b/docs/guides/ai-agents/generate-translate-copy.mdx new file mode 100644 index 000000000..127cb028e --- /dev/null +++ b/docs/guides/ai-agents/generate-translate-copy.mdx @@ -0,0 +1,120 @@ +--- +title: "Generate and translate copy" +sidebarTitle: "Generate & translate copy" +description: "Create an AI agent workflow that generates and translates copy" +--- + +## Overview + +**Prompt chaining** is an AI workflow pattern that decomposes a complex task into a sequence of steps, where each LLM call processes the output of the previous one. This approach trades off latency for higher accuracy by making each LLM call an easier, more focused task, with the ability to add programmatic checks between steps to ensure the process remains on track. + +![Generating and translating copy](/guides/ai-agents/prompt-chaining.png) + +## Example task + +In this example, we'll create a workflow that generates and translates copy. This approach is particularly effective when tasks require different models or approaches for different inputs. + +**This task:** + +- Uses `generateText` from [Vercel's AI SDK](https://sdk.vercel.ai/docs/introduction) to interact with OpenAI models +- Uses `experimental_telemetry` to provide LLM logs +- Generates marketing copy based on subject and target word count +- Validates the generated copy meets word count requirements (±10 words) +- Translates the validated copy to the target language while preserving tone + +```typescript +import { openai } from "@ai-sdk/openai"; +import { task } from "@trigger.dev/sdk/v3"; +import { generateText } from "ai"; + +export interface TranslatePayload { + marketingSubject: string; + targetLanguage: string; + targetWordCount: number; +} + +export const generateAndTranslateTask = task({ + id: "generate-and-translate-copy", + maxDuration: 300, // Stop executing after 5 mins of compute + run: async (payload: TranslatePayload) => { + // Step 1: Generate marketing copy + const generatedCopy = await generateText({ + model: openai("o1-mini"), + messages: [ + { + role: "system", + content: "You are an expert copywriter.", + }, + { + role: "user", + content: `Generate as close as possible to ${payload.targetWordCount} words of compelling marketing copy for ${payload.marketingSubject}`, + }, + ], + experimental_telemetry: { + isEnabled: true, + functionId: "generate-and-translate-copy", + }, + }); + + // Gate: Validate the generated copy meets the word count target + const wordCount = generatedCopy.text.split(/\s+/).length; + + if ( + wordCount < payload.targetWordCount - 10 || + wordCount > payload.targetWordCount + 10 + ) { + throw new Error( + `Generated copy length (${wordCount} words) is outside acceptable range of ${ + payload.targetWordCount - 10 + }-${payload.targetWordCount + 10} words` + ); + } + + // Step 2: Translate to target language + const translatedCopy = await generateText({ + model: openai("o1-mini"), + messages: [ + { + role: "system", + content: `You are an expert translator specializing in marketing content translation into ${payload.targetLanguage}.`, + }, + { + role: "user", + content: `Translate the following marketing copy to ${payload.targetLanguage}, maintaining the same tone and marketing impact:\n\n${generatedCopy}`, + }, + ], + experimental_telemetry: { + isEnabled: true, + functionId: "generate-and-translate-copy", + }, + }); + + return { + englishCopy: generatedCopy, + translatedCopy, + }; + }, +}); +``` + +## Run a test + +On the Test page in the dashboard, select the `generate-and-translate-copy` task and include a payload like the following: + +```json +{ + marketingSubject: "The controversial new Jaguar electric concept car", + targetLanguage: "Spanish", + targetWordCount: 100, +} +``` + +This example payload generates copy and then translates it using sequential LLM calls. The translation only begins after the generated copy has been validated against the word count requirements. + +