decocms 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +373 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add/add.d.ts +7 -0
- package/dist/commands/add/add.d.ts.map +1 -0
- package/dist/commands/add/add.js +90 -0
- package/dist/commands/add/add.js.map +1 -0
- package/dist/commands/auth/login.d.ts +2 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +125 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +2 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +51 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/config/configure.d.ts +2 -0
- package/dist/commands/config/configure.d.ts.map +1 -0
- package/dist/commands/config/configure.js +51 -0
- package/dist/commands/config/configure.js.map +1 -0
- package/dist/commands/create/create.d.ts +3 -0
- package/dist/commands/create/create.d.ts.map +1 -0
- package/dist/commands/create/create.js +238 -0
- package/dist/commands/create/create.js.map +1 -0
- package/dist/commands/dev/dev.d.ts +8 -0
- package/dist/commands/dev/dev.d.ts.map +1 -0
- package/dist/commands/dev/dev.js +64 -0
- package/dist/commands/dev/dev.js.map +1 -0
- package/dist/commands/dev/link.d.ts +8 -0
- package/dist/commands/dev/link.d.ts.map +1 -0
- package/dist/commands/dev/link.js +124 -0
- package/dist/commands/dev/link.js.map +1 -0
- package/dist/commands/gen/gen.d.ts +11 -0
- package/dist/commands/gen/gen.d.ts.map +1 -0
- package/dist/commands/gen/gen.js +341 -0
- package/dist/commands/gen/gen.js.map +1 -0
- package/dist/commands/hosting/deploy.d.ts +19 -0
- package/dist/commands/hosting/deploy.d.ts.map +1 -0
- package/dist/commands/hosting/deploy.js +194 -0
- package/dist/commands/hosting/deploy.js.map +1 -0
- package/dist/commands/hosting/list.d.ts +6 -0
- package/dist/commands/hosting/list.d.ts.map +1 -0
- package/dist/commands/hosting/list.js +26 -0
- package/dist/commands/hosting/list.js.map +1 -0
- package/dist/commands/hosting/promote.d.ts +11 -0
- package/dist/commands/hosting/promote.d.ts.map +1 -0
- package/dist/commands/hosting/promote.js +153 -0
- package/dist/commands/hosting/promote.js.map +1 -0
- package/dist/commands/update/update.d.ts +4 -0
- package/dist/commands/update/update.d.ts.map +1 -0
- package/dist/commands/update/update.js +242 -0
- package/dist/commands/update/update.js.map +1 -0
- package/dist/commands/update/upgrade.d.ts +4 -0
- package/dist/commands/update/upgrade.d.ts.map +1 -0
- package/dist/commands/update/upgrade.js +157 -0
- package/dist/commands/update/upgrade.js.map +1 -0
- package/dist/lib/config.d.ts +309 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +262 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +10 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +16 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/fs.d.ts +40 -0
- package/dist/lib/fs.d.ts.map +1 -0
- package/dist/lib/fs.js +162 -0
- package/dist/lib/fs.js.map +1 -0
- package/dist/lib/mcp.d.ts +34 -0
- package/dist/lib/mcp.d.ts.map +1 -0
- package/dist/lib/mcp.js +19 -0
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/parse-binding-tool.d.ts +12 -0
- package/dist/lib/parse-binding-tool.d.ts.map +1 -0
- package/dist/lib/parse-binding-tool.js +15 -0
- package/dist/lib/parse-binding-tool.js.map +1 -0
- package/dist/lib/prompt-ide-setup.d.ts +27 -0
- package/dist/lib/prompt-ide-setup.d.ts.map +1 -0
- package/dist/lib/prompt-ide-setup.js +158 -0
- package/dist/lib/prompt-ide-setup.js.map +1 -0
- package/dist/lib/prompt-integrations.d.ts +7 -0
- package/dist/lib/prompt-integrations.d.ts.map +1 -0
- package/dist/lib/prompt-integrations.js +84 -0
- package/dist/lib/prompt-integrations.js.map +1 -0
- package/dist/lib/prompt-workspace.d.ts +2 -0
- package/dist/lib/prompt-workspace.d.ts.map +1 -0
- package/dist/lib/prompt-workspace.js +93 -0
- package/dist/lib/prompt-workspace.js.map +1 -0
- package/dist/lib/runtime.d.ts +5 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/runtime.js +15 -0
- package/dist/lib/runtime.js.map +1 -0
- package/dist/lib/session.d.ts +39 -0
- package/dist/lib/session.d.ts.map +1 -0
- package/dist/lib/session.js +124 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/slugify.d.ts +13 -0
- package/dist/lib/slugify.d.ts.map +1 -0
- package/dist/lib/slugify.js +27 -0
- package/dist/lib/slugify.js.map +1 -0
- package/dist/lib/supabase.d.ts +5 -0
- package/dist/lib/supabase.d.ts.map +1 -0
- package/dist/lib/supabase.js +19 -0
- package/dist/lib/supabase.js.map +1 -0
- package/dist/lib/wrangler.d.ts +9 -0
- package/dist/lib/wrangler.d.ts.map +1 -0
- package/dist/lib/wrangler.js +118 -0
- package/dist/lib/wrangler.js.map +1 -0
- package/dist/rules/deco-chat.mdc +902 -0
- package/package.json +79 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Comprehensive guide for developing applications on the deco.chat platform, covering tools, workflows, and best practices
|
|
3
|
+
globs: ["**/*.ts", "**/*.tsx"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# deco.chat Platform Development Rules
|
|
8
|
+
|
|
9
|
+
## 🎯 Overview
|
|
10
|
+
|
|
11
|
+
deco.chat is a powerful platform for creating MCP (Model Context Protocol) tools and workflows that can automate any kind of workload. This rule file provides comprehensive guidance for developing applications on the deco.chat platform.
|
|
12
|
+
|
|
13
|
+
## 🚀 Getting Started
|
|
14
|
+
|
|
15
|
+
### Prerequisites
|
|
16
|
+
- **Deno** installed on your system
|
|
17
|
+
- Access to deco.chat platform
|
|
18
|
+
- Basic TypeScript knowledge
|
|
19
|
+
|
|
20
|
+
### Initial Setup Commands
|
|
21
|
+
```bash
|
|
22
|
+
# Install CLI
|
|
23
|
+
deno run -A jsr:@deco/cli
|
|
24
|
+
|
|
25
|
+
# Configure project
|
|
26
|
+
deno run -A jsr:@deco/cli config
|
|
27
|
+
|
|
28
|
+
# Development
|
|
29
|
+
npm run dev
|
|
30
|
+
|
|
31
|
+
# Deploy
|
|
32
|
+
npm run deploy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Project Structure
|
|
36
|
+
```
|
|
37
|
+
project/
|
|
38
|
+
├── main.ts # Main application
|
|
39
|
+
├── deco.gen.ts # Auto-generated types
|
|
40
|
+
├── package.json # Dependencies
|
|
41
|
+
├── wrangler.toml # Cloudflare config
|
|
42
|
+
└── README.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🔧 Core Concepts
|
|
46
|
+
|
|
47
|
+
### 1. Environment (Env) Object
|
|
48
|
+
The `env` object contains all available integrations and tools. Each integration is namespaced:
|
|
49
|
+
```typescript
|
|
50
|
+
interface Env {
|
|
51
|
+
INTEGRATION_NAME: {
|
|
52
|
+
TOOL_NAME: (input: ToolInput) => Promise<ToolOutput>;
|
|
53
|
+
};
|
|
54
|
+
DECO_CHAT_WORKSPACE_API: {
|
|
55
|
+
// Workspace-specific tools
|
|
56
|
+
};
|
|
57
|
+
DECO_CHAT_API: {
|
|
58
|
+
// Global API tools
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Tools
|
|
64
|
+
Tools are individual functions that perform specific tasks. They can:
|
|
65
|
+
- Call external APIs
|
|
66
|
+
- Process data
|
|
67
|
+
- Interact with databases
|
|
68
|
+
- Generate content using AI
|
|
69
|
+
|
|
70
|
+
### 3. Workflows
|
|
71
|
+
Workflows orchestrate multiple tools using Mastra's control flow patterns. They should:
|
|
72
|
+
- **Split I/O operations** into separate steps
|
|
73
|
+
- **Use control flow** for data processing and logic
|
|
74
|
+
- **Keep each step focused** on a single tool invocation
|
|
75
|
+
|
|
76
|
+
## 📝 Creating Tools
|
|
77
|
+
|
|
78
|
+
### Core Imports
|
|
79
|
+
```typescript
|
|
80
|
+
import { withRuntime } from "@deco/workers-runtime";
|
|
81
|
+
import {
|
|
82
|
+
createStepFromTool,
|
|
83
|
+
createTool,
|
|
84
|
+
createWorkflow,
|
|
85
|
+
} from "@deco/workers-runtime/mastra";
|
|
86
|
+
import { z } from "zod";
|
|
87
|
+
import { Env } from "./deco.gen";
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Basic Tool Pattern
|
|
91
|
+
```typescript
|
|
92
|
+
const createMyTool = (env: Env) =>
|
|
93
|
+
createTool({
|
|
94
|
+
id: "TOOL_ID",
|
|
95
|
+
description: "Tool description",
|
|
96
|
+
inputSchema: z.object({
|
|
97
|
+
param1: z.string(),
|
|
98
|
+
param2: z.number().optional(),
|
|
99
|
+
}),
|
|
100
|
+
outputSchema: z.object({
|
|
101
|
+
result: z.string(),
|
|
102
|
+
}),
|
|
103
|
+
execute: async ({ context }) => {
|
|
104
|
+
// ONE tool call only
|
|
105
|
+
const response = await env.INTEGRATION.TOOL({
|
|
106
|
+
// parameters
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return { result: response.data };
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Tool Best Practices
|
|
115
|
+
1. **Single Responsibility**: Each tool should do one thing well
|
|
116
|
+
2. **Input Validation**: Use Zod schemas to validate inputs
|
|
117
|
+
3. **Error Handling**: Always handle potential errors gracefully
|
|
118
|
+
4. **Type Safety**: Leverage TypeScript for type safety
|
|
119
|
+
|
|
120
|
+
## 🔄 Creating Workflows
|
|
121
|
+
|
|
122
|
+
### Workflow Philosophy - GOLDEN RULE
|
|
123
|
+
**IMPORTANT**: Follow this principle for optimal workflow design:
|
|
124
|
+
- **Each step should invoke only ONE tool** from `env.INTEGRATION_NAME.TOOL_NAME`
|
|
125
|
+
- **All data processing, logic, and control flow** should be handled by Mastra workflow operators
|
|
126
|
+
- **Split complex operations** into multiple steps rather than combining them
|
|
127
|
+
|
|
128
|
+
### Basic Workflow Pattern
|
|
129
|
+
```typescript
|
|
130
|
+
const createMyWorkflow = (env: Env) => {
|
|
131
|
+
const step1 = createStepFromTool(createTool1(env));
|
|
132
|
+
const step2 = createStepFromTool(createTool2(env));
|
|
133
|
+
|
|
134
|
+
return createWorkflow({
|
|
135
|
+
id: "WORKFLOW_ID",
|
|
136
|
+
inputSchema: z.object({ input: z.string() }),
|
|
137
|
+
outputSchema: z.object({ output: z.string() }),
|
|
138
|
+
})
|
|
139
|
+
.then(step1)
|
|
140
|
+
.map((context) => ({
|
|
141
|
+
...context,
|
|
142
|
+
// Data processing here
|
|
143
|
+
}))
|
|
144
|
+
.then(step2)
|
|
145
|
+
.commit();
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Control Flow Operators
|
|
150
|
+
|
|
151
|
+
#### 1. Sequential (.then)
|
|
152
|
+
```typescript
|
|
153
|
+
.then(step1)
|
|
154
|
+
.then(step2)
|
|
155
|
+
.then(step3)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### 2. Parallel (.parallel)
|
|
159
|
+
```typescript
|
|
160
|
+
.parallel([
|
|
161
|
+
step1,
|
|
162
|
+
step2,
|
|
163
|
+
step3
|
|
164
|
+
])
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### 3. Conditional (.branch)
|
|
168
|
+
```typescript
|
|
169
|
+
.branch(
|
|
170
|
+
(context) => condition,
|
|
171
|
+
(workflow) => workflow.then(stepIfTrue),
|
|
172
|
+
(workflow) => workflow.then(stepIfFalse)
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### 4. Data Transformation (.map)
|
|
177
|
+
```typescript
|
|
178
|
+
.map((context) => ({
|
|
179
|
+
...context,
|
|
180
|
+
processedData: context.rawData.toUpperCase(),
|
|
181
|
+
isValid: context.rawData.length > 0
|
|
182
|
+
}))
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### 5. Looping (.repeat)
|
|
186
|
+
```typescript
|
|
187
|
+
.repeat(
|
|
188
|
+
(context) => context.items,
|
|
189
|
+
processItem
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 🔁 Looping with `.dountil`
|
|
194
|
+
|
|
195
|
+
### What is `.dountil`?
|
|
196
|
+
|
|
197
|
+
The `.dountil` operator allows you to **repeat a workflow step** (typically a polling or status-checking tool) until a specified condition is met. This is especially useful for workflows that need to wait for an asynchronous task to complete, such as polling an external API or a long-running browser automation.
|
|
198
|
+
|
|
199
|
+
### How does it work?
|
|
200
|
+
|
|
201
|
+
- You provide a step (created with `createStepFromTool`) that will be executed repeatedly.
|
|
202
|
+
- You provide a predicate function that receives the **output of the repeated step** (as `inputData`) and returns `true` when the loop should stop.
|
|
203
|
+
|
|
204
|
+
### Usage Pattern
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
.then(scrapeStep)
|
|
208
|
+
.dountil(
|
|
209
|
+
pollTaskStep,
|
|
210
|
+
async ({ inputData }) => {
|
|
211
|
+
// inputData is the output of pollTaskStep
|
|
212
|
+
return inputData.status === "finished";
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
.map(async ({ getStepResult }) => ({
|
|
216
|
+
// Use getStepResult(pollTaskStep) to access the final output
|
|
217
|
+
output: getStepResult(pollTaskStep).output,
|
|
218
|
+
prompt: getStepResult(pollTaskStep).prompt,
|
|
219
|
+
taskId: getStepResult(pollTaskStep).taskId,
|
|
220
|
+
}))
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Key Points
|
|
224
|
+
|
|
225
|
+
- The **first argument** to `.dountil` is the step to repeat.
|
|
226
|
+
- The **second argument** is an async predicate function that receives an object with `inputData`, which is the output of the repeated step.
|
|
227
|
+
- The loop continues until the predicate returns `true`.
|
|
228
|
+
- After `.dountil`, you can use `.map` and `getStepResult(pollTaskStep)` to access the final output.
|
|
229
|
+
|
|
230
|
+
### Real-World Example
|
|
231
|
+
|
|
232
|
+
Suppose you want to scrape a website, poll for the scraping task to finish, and then process the result:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
const pollTaskStep = createStepFromTool(pollTaskTool);
|
|
236
|
+
|
|
237
|
+
return createWorkflow({
|
|
238
|
+
// ...
|
|
239
|
+
})
|
|
240
|
+
.then(scrapeStep)
|
|
241
|
+
.dountil(
|
|
242
|
+
pollTaskStep,
|
|
243
|
+
async ({ inputData }) => {
|
|
244
|
+
// inputData is the output of pollTaskStep
|
|
245
|
+
return inputData.status === "finished";
|
|
246
|
+
}
|
|
247
|
+
)
|
|
248
|
+
.map(async ({ getStepResult }) => ({
|
|
249
|
+
// getStepResult(pollTaskStep) gives you the final poll result
|
|
250
|
+
output: getStepResult(pollTaskStep).output,
|
|
251
|
+
prompt: getStepResult(pollTaskStep).prompt,
|
|
252
|
+
taskId: getStepResult(pollTaskStep).taskId,
|
|
253
|
+
}))
|
|
254
|
+
// ... continue workflow
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Best Practices
|
|
258
|
+
|
|
259
|
+
- Use `.dountil` for polling or waiting scenarios.
|
|
260
|
+
- Always check the output (`inputData`) of your polling step for the completion condition.
|
|
261
|
+
- Use `.map` and `getStepResult` after `.dountil` to extract the final result for downstream steps.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
**Summary Table for `.dountil`:**
|
|
266
|
+
|
|
267
|
+
| Parameter | Description |
|
|
268
|
+
|-------------------|------------------------------------------------------------------|
|
|
269
|
+
| Step | The step to repeat (e.g., polling tool) |
|
|
270
|
+
| Predicate | Function receiving `{ inputData }` (output of the step) |
|
|
271
|
+
| Loop Exit | Predicate returns `true` when loop should stop |
|
|
272
|
+
| Access Result | Use `.map` and `getStepResult(step)` after `.dountil` |
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
**In short:**
|
|
277
|
+
`.dountil(step, predicate)` repeats `step` until `predicate({ inputData })` returns `true`. Afterward, use `.map` and `getStepResult(step)` to access the final output.
|
|
278
|
+
|
|
279
|
+
## 🗺️ Data Transformation with `.map` and Accessing Previous Step Results
|
|
280
|
+
|
|
281
|
+
The `.map` operator allows you to transform, enrich, or combine data between tool steps. Use `.map` to:
|
|
282
|
+
|
|
283
|
+
- Prepare or reformat data for the next tool
|
|
284
|
+
- Combine results from multiple previous steps
|
|
285
|
+
- Add custom logic or computed fields
|
|
286
|
+
|
|
287
|
+
### Basic Usage of `.map`
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
.then(fetchUserData)
|
|
291
|
+
.map(({ inputData }) => ({
|
|
292
|
+
// Add a computed field
|
|
293
|
+
...inputData,
|
|
294
|
+
isActive: inputData.status === "active",
|
|
295
|
+
}))
|
|
296
|
+
.then(processUser)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Accessing Previous Step Results with `getStepResult`
|
|
300
|
+
|
|
301
|
+
When you need to access the output of a specific previous step (not just the immediate last one), use the `getStepResult` function provided in the `.map` context.
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
const stepA = createStepFromTool(toolA(env));
|
|
305
|
+
const stepB = createStepFromTool(toolB(env));
|
|
306
|
+
|
|
307
|
+
return createWorkflow({
|
|
308
|
+
// ...
|
|
309
|
+
})
|
|
310
|
+
.then(stepA)
|
|
311
|
+
.then(stepB)
|
|
312
|
+
.map(({ inputData, getStepResult }) => {
|
|
313
|
+
const resultA = getStepResult(stepA);
|
|
314
|
+
const resultB = getStepResult(stepB);
|
|
315
|
+
return {
|
|
316
|
+
combined: `${resultA.value} + ${resultB.value}`,
|
|
317
|
+
};
|
|
318
|
+
})
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
- `getStepResult(step)` retrieves the output of any previous step.
|
|
322
|
+
- This is especially useful when you need to merge or reference data from multiple steps.
|
|
323
|
+
|
|
324
|
+
### Real-World Example
|
|
325
|
+
|
|
326
|
+
In a workflow that summarizes a YouTube video, you might want to combine the video search result, transcript, and summary into a single output. Here’s how you can do it:
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
const searchStep = createStepFromTool(createYouTubeSearchTool(env));
|
|
330
|
+
const transcriptStep = createStepFromTool(createYouTubeTranscriptTool(env));
|
|
331
|
+
const summarizeStep = createStepFromTool(createSummarizeTextTool(env));
|
|
332
|
+
|
|
333
|
+
return createWorkflow({
|
|
334
|
+
id: "YOUTUBE_VIDEO_SUMMARY",
|
|
335
|
+
inputSchema: z.object({ query: z.string() }),
|
|
336
|
+
outputSchema: z.object({
|
|
337
|
+
videoId: z.string(),
|
|
338
|
+
title: z.string(),
|
|
339
|
+
description: z.string(),
|
|
340
|
+
transcript: z.string(),
|
|
341
|
+
summary: z.string(),
|
|
342
|
+
}),
|
|
343
|
+
})
|
|
344
|
+
.then(searchStep)
|
|
345
|
+
.map(async ({ inputData }) => ({ videoId: inputData.videoId }))
|
|
346
|
+
.then(transcriptStep)
|
|
347
|
+
.map(async ({ inputData, getStepResult }) => {
|
|
348
|
+
const searchResult = getStepResult(searchStep);
|
|
349
|
+
return {
|
|
350
|
+
videoId: searchResult.videoId,
|
|
351
|
+
title: searchResult.title,
|
|
352
|
+
description: searchResult.description,
|
|
353
|
+
transcript: inputData.transcript,
|
|
354
|
+
};
|
|
355
|
+
})
|
|
356
|
+
.then(summarizeStep)
|
|
357
|
+
.map(async ({ inputData, getStepResult }) => {
|
|
358
|
+
const searchResult = getStepResult(searchStep);
|
|
359
|
+
const transcriptResult = getStepResult(transcriptStep);
|
|
360
|
+
return {
|
|
361
|
+
videoId: searchResult.videoId,
|
|
362
|
+
title: searchResult.title,
|
|
363
|
+
description: searchResult.description,
|
|
364
|
+
transcript: transcriptResult.transcript,
|
|
365
|
+
summary: inputData.summary,
|
|
366
|
+
};
|
|
367
|
+
})
|
|
368
|
+
.commit();
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Best Practices
|
|
372
|
+
|
|
373
|
+
- Use `.map` for all data processing, not inside tool `execute` functions.
|
|
374
|
+
- Use `getStepResult` to keep your workflow logic clear and maintainable.
|
|
375
|
+
- Keep each step focused on a single responsibility and use `.map` to orchestrate data flow between steps.
|
|
376
|
+
|
|
377
|
+
## 🔌 Integration Usage Patterns
|
|
378
|
+
|
|
379
|
+
### AI Generation
|
|
380
|
+
```typescript
|
|
381
|
+
const aiResponse = await env.GIMENES.AGENT_GENERATE_TEXT({
|
|
382
|
+
message: "Your prompt",
|
|
383
|
+
options: { model: "gpt-4" }
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Database Operations
|
|
388
|
+
```typescript
|
|
389
|
+
const dbResult = await env.DECO_CHAT_WORKSPACE_API.DATABASES_RUN_SQL({
|
|
390
|
+
sql: "SELECT * FROM table",
|
|
391
|
+
params: [param1, param2]
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### File System Operations
|
|
396
|
+
```typescript
|
|
397
|
+
const fileContent = await env.DECO_CHAT_WORKSPACE_API.FS_READ({
|
|
398
|
+
path: "/path/to/file",
|
|
399
|
+
expiresIn: 3600
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## 📋 Configuration Files
|
|
404
|
+
|
|
405
|
+
### wrangler.toml
|
|
406
|
+
```toml
|
|
407
|
+
main = "main.ts"
|
|
408
|
+
compatibility_date = "2025-06-17"
|
|
409
|
+
compatibility_flags = [ "nodejs_compat" ]
|
|
410
|
+
|
|
411
|
+
[deco]
|
|
412
|
+
app = "your-app"
|
|
413
|
+
workspace = "your-workspace"
|
|
414
|
+
enable_workflows = true
|
|
415
|
+
|
|
416
|
+
[[deco.bindings]]
|
|
417
|
+
name = "INTEGRATION_NAME"
|
|
418
|
+
type = "mcp"
|
|
419
|
+
integration_id = "your-id"
|
|
420
|
+
|
|
421
|
+
[[migrations]]
|
|
422
|
+
tag = "v1"
|
|
423
|
+
new_classes = [ "Workflow" ]
|
|
424
|
+
|
|
425
|
+
[durable_objects]
|
|
426
|
+
[[durable_objects.bindings]]
|
|
427
|
+
name = "DECO_CHAT_WORKFLOW_DO"
|
|
428
|
+
class_name = "Workflow"
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### package.json
|
|
432
|
+
```json
|
|
433
|
+
{
|
|
434
|
+
"scripts": {
|
|
435
|
+
"dev": "deco dev",
|
|
436
|
+
"deploy": "wrangler deploy --dry-run --outdir dist && cd dist && deco deploy"
|
|
437
|
+
},
|
|
438
|
+
"dependencies": {
|
|
439
|
+
"@deco/workers-runtime": "npm:@jsr/deco__workers-runtime@^0.2.20",
|
|
440
|
+
"zod": "^3.24.2"
|
|
441
|
+
},
|
|
442
|
+
"devDependencies": {
|
|
443
|
+
"@deco/cli": "npm:@jsr/deco__cli@^0.5.12"
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## 🎯 Golden Rules
|
|
449
|
+
|
|
450
|
+
1. **One Tool Per Step**: Each workflow step should call only ONE `env.INTEGRATION.TOOL()`
|
|
451
|
+
2. **Control Flow for Logic**: Use `.map()`, `.branch()`, `.parallel()` for data processing
|
|
452
|
+
3. **Split Complex Operations**: Break down into multiple focused steps
|
|
453
|
+
4. **Validate Inputs**: Always use Zod schemas
|
|
454
|
+
5. **Handle Errors**: Use branching for error scenarios
|
|
455
|
+
6. **Type Safety**: Leverage TypeScript and generated types
|
|
456
|
+
|
|
457
|
+
## 🔍 Common Patterns
|
|
458
|
+
|
|
459
|
+
### Data Validation
|
|
460
|
+
```typescript
|
|
461
|
+
.map((context) => ({
|
|
462
|
+
...context,
|
|
463
|
+
isValid: context.data && context.data.length > 0,
|
|
464
|
+
dataCount: context.data?.length || 0
|
|
465
|
+
}))
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Error Handling
|
|
469
|
+
```typescript
|
|
470
|
+
.branch(
|
|
471
|
+
(context) => context.isValid,
|
|
472
|
+
(workflow) => workflow.then(processData),
|
|
473
|
+
(workflow) => workflow.map((context) => ({
|
|
474
|
+
...context,
|
|
475
|
+
success: false,
|
|
476
|
+
error: "Invalid data"
|
|
477
|
+
}))
|
|
478
|
+
)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Parallel Processing
|
|
482
|
+
```typescript
|
|
483
|
+
.parallel([
|
|
484
|
+
fetchUserProfile,
|
|
485
|
+
fetchUserPreferences,
|
|
486
|
+
fetchUserActivity
|
|
487
|
+
])
|
|
488
|
+
.map((context) => ({
|
|
489
|
+
...context,
|
|
490
|
+
hasCompleteData: context.profile && context.preferences && context.activity
|
|
491
|
+
}))
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Conditional Processing
|
|
495
|
+
```typescript
|
|
496
|
+
.branch(
|
|
497
|
+
(context) => context.dataType === "users",
|
|
498
|
+
(workflow) => workflow.then(processUsers),
|
|
499
|
+
(workflow) => workflow.then(processProducts)
|
|
500
|
+
)
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## 🚨 Anti-Patterns to Avoid
|
|
504
|
+
|
|
505
|
+
### ❌ Multiple Tool Calls in One Step
|
|
506
|
+
```typescript
|
|
507
|
+
// DON'T DO THIS
|
|
508
|
+
execute: async ({ context }) => {
|
|
509
|
+
const data1 = await env.API1.TOOL1({...});
|
|
510
|
+
const data2 = await env.API2.TOOL2({...});
|
|
511
|
+
const data3 = await env.API3.TOOL3({...});
|
|
512
|
+
return { result: "combined" };
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### ❌ Complex Logic in Tools
|
|
517
|
+
```typescript
|
|
518
|
+
// DON'T DO THIS
|
|
519
|
+
execute: async ({ context }) => {
|
|
520
|
+
const data = await env.API.TOOL({...});
|
|
521
|
+
|
|
522
|
+
// Complex processing logic here
|
|
523
|
+
const processed = data.map(item => ({
|
|
524
|
+
...item,
|
|
525
|
+
calculated: item.value * 2,
|
|
526
|
+
formatted: item.name.toUpperCase(),
|
|
527
|
+
validated: item.id > 0
|
|
528
|
+
})).filter(item => item.validated);
|
|
529
|
+
|
|
530
|
+
return { result: processed };
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### ✅ Do This Instead
|
|
535
|
+
```typescript
|
|
536
|
+
// Step 1: Fetch data
|
|
537
|
+
const fetchData = createStepFromTool(createFetchTool(env));
|
|
538
|
+
|
|
539
|
+
// Step 2: Process data (in workflow)
|
|
540
|
+
.then(fetchData)
|
|
541
|
+
.map((context) => ({
|
|
542
|
+
...context,
|
|
543
|
+
processed: context.data.map(item => ({
|
|
544
|
+
...item,
|
|
545
|
+
calculated: item.value * 2,
|
|
546
|
+
formatted: item.name.toUpperCase(),
|
|
547
|
+
validated: item.id > 0
|
|
548
|
+
})).filter(item => item.validated)
|
|
549
|
+
}))
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## 📚 Practical Examples
|
|
553
|
+
|
|
554
|
+
### Example 1: User Data Processing Pipeline
|
|
555
|
+
|
|
556
|
+
#### ❌ Bad Approach (Don't Do This)
|
|
557
|
+
```typescript
|
|
558
|
+
// DON'T: Combining multiple tool calls in one step
|
|
559
|
+
const createBadUserProcessor = (env: Env) =>
|
|
560
|
+
createTool({
|
|
561
|
+
id: "BAD_USER_PROCESSOR",
|
|
562
|
+
description: "Process user data - BAD EXAMPLE",
|
|
563
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
564
|
+
outputSchema: z.object({ result: z.string() }),
|
|
565
|
+
execute: async ({ context }) => {
|
|
566
|
+
// Multiple tool calls in one step - AVOID THIS
|
|
567
|
+
const userData = await env.DECO_CHAT_WORKSPACE_API.DATABASES_RUN_SQL({
|
|
568
|
+
sql: "SELECT * FROM users WHERE id = ?",
|
|
569
|
+
params: [context.userId]
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const aiAnalysis = await env.GIMENES.AGENT_GENERATE_TEXT({
|
|
573
|
+
message: `Analyze user data: ${JSON.stringify(userData)}`
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
const savedResult = await env.DECO_CHAT_WORKSPACE_API.FS_WRITE({
|
|
577
|
+
path: `/users/${context.userId}/analysis.json`,
|
|
578
|
+
content: aiAnalysis.text,
|
|
579
|
+
contentType: "application/json"
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
return { result: "processed" };
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
#### ✅ Good Approach (Do This)
|
|
588
|
+
```typescript
|
|
589
|
+
// DO: Split into separate steps, use control flow for processing
|
|
590
|
+
const createUserDataWorkflow = (env: Env) => {
|
|
591
|
+
// Step 1: Fetch user data (ONE tool call)
|
|
592
|
+
const fetchUserData = createStepFromTool(
|
|
593
|
+
createTool({
|
|
594
|
+
id: "FETCH_USER_DATA",
|
|
595
|
+
description: "Fetch user data from database",
|
|
596
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
597
|
+
outputSchema: z.object({ userData: z.any() }),
|
|
598
|
+
execute: async ({ context }) => {
|
|
599
|
+
const result = await env.DECO_CHAT_WORKSPACE_API.DATABASES_RUN_SQL({
|
|
600
|
+
sql: "SELECT * FROM users WHERE id = ?",
|
|
601
|
+
params: [context.userId]
|
|
602
|
+
});
|
|
603
|
+
return { userData: result };
|
|
604
|
+
},
|
|
605
|
+
})(env)
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
// Step 2: Analyze with AI (ONE tool call)
|
|
609
|
+
const analyzeUserData = createStepFromTool(
|
|
610
|
+
createTool({
|
|
611
|
+
id: "ANALYZE_USER_DATA",
|
|
612
|
+
description: "Analyze user data with AI",
|
|
613
|
+
inputSchema: z.object({ userData: z.any() }),
|
|
614
|
+
outputSchema: z.object({ analysis: z.string() }),
|
|
615
|
+
execute: async ({ context }) => {
|
|
616
|
+
const result = await env.GIMENES.AGENT_GENERATE_TEXT({
|
|
617
|
+
message: `Analyze this user data: ${JSON.stringify(context.userData)}`
|
|
618
|
+
});
|
|
619
|
+
return { analysis: result.text || "" };
|
|
620
|
+
},
|
|
621
|
+
})(env)
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
// Step 3: Save results (ONE tool call)
|
|
625
|
+
const saveAnalysis = createStepFromTool(
|
|
626
|
+
createTool({
|
|
627
|
+
id: "SAVE_ANALYSIS",
|
|
628
|
+
description: "Save analysis to file system",
|
|
629
|
+
inputSchema: z.object({
|
|
630
|
+
userId: z.string(),
|
|
631
|
+
analysis: z.string()
|
|
632
|
+
}),
|
|
633
|
+
outputSchema: z.object({ saved: z.boolean() }),
|
|
634
|
+
execute: async ({ context }) => {
|
|
635
|
+
await env.DECO_CHAT_WORKSPACE_API.FS_WRITE({
|
|
636
|
+
path: `/users/${context.userId}/analysis.json`,
|
|
637
|
+
content: context.analysis,
|
|
638
|
+
contentType: "application/json"
|
|
639
|
+
});
|
|
640
|
+
return { saved: true };
|
|
641
|
+
},
|
|
642
|
+
})(env)
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
return createWorkflow({
|
|
646
|
+
id: "USER_DATA_WORKFLOW",
|
|
647
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
648
|
+
outputSchema: z.object({
|
|
649
|
+
success: z.boolean(),
|
|
650
|
+
analysis: z.string(),
|
|
651
|
+
saved: z.boolean()
|
|
652
|
+
}),
|
|
653
|
+
})
|
|
654
|
+
.then(fetchUserData)
|
|
655
|
+
.map((context) => ({
|
|
656
|
+
...context,
|
|
657
|
+
// Data processing logic here (not in tools)
|
|
658
|
+
processedUserData: context.userData.results?.[0] || null,
|
|
659
|
+
hasValidData: context.userData.results?.length > 0
|
|
660
|
+
}))
|
|
661
|
+
.branch(
|
|
662
|
+
(context) => context.hasValidData,
|
|
663
|
+
(workflow) => workflow
|
|
664
|
+
.then(analyzeUserData)
|
|
665
|
+
.map((context) => ({
|
|
666
|
+
...context,
|
|
667
|
+
// More data processing
|
|
668
|
+
analysisLength: context.analysis.length,
|
|
669
|
+
isLongAnalysis: context.analysis.length > 500
|
|
670
|
+
}))
|
|
671
|
+
.then(saveAnalysis)
|
|
672
|
+
.map((context) => ({
|
|
673
|
+
...context,
|
|
674
|
+
success: true
|
|
675
|
+
})),
|
|
676
|
+
(workflow) => workflow
|
|
677
|
+
.map((context) => ({
|
|
678
|
+
...context,
|
|
679
|
+
success: false,
|
|
680
|
+
analysis: "No user data found",
|
|
681
|
+
saved: false
|
|
682
|
+
}))
|
|
683
|
+
)
|
|
684
|
+
.commit();
|
|
685
|
+
};
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### Example 2: Multi-Service Integration
|
|
689
|
+
```typescript
|
|
690
|
+
const createMultiServiceWorkflow = (env: Env) => {
|
|
691
|
+
// Step 1: Fetch data from external API
|
|
692
|
+
const fetchExternalData = createStepFromTool(
|
|
693
|
+
createTool({
|
|
694
|
+
id: "FETCH_EXTERNAL_DATA",
|
|
695
|
+
description: "Fetch data from external service",
|
|
696
|
+
inputSchema: z.object({ query: z.string() }),
|
|
697
|
+
outputSchema: z.object({ externalData: z.any() }),
|
|
698
|
+
execute: async ({ context }) => {
|
|
699
|
+
const result = await env.EXTERNAL_API.GET_DATA({
|
|
700
|
+
query: context.query
|
|
701
|
+
});
|
|
702
|
+
return { externalData: result };
|
|
703
|
+
},
|
|
704
|
+
})(env)
|
|
705
|
+
);
|
|
706
|
+
|
|
707
|
+
// Step 2: Process with AI
|
|
708
|
+
const processWithAI = createStepFromTool(
|
|
709
|
+
createTool({
|
|
710
|
+
id: "PROCESS_WITH_AI",
|
|
711
|
+
description: "Process data with AI",
|
|
712
|
+
inputSchema: z.object({ data: z.any() }),
|
|
713
|
+
outputSchema: z.object({ processedData: z.string() }),
|
|
714
|
+
execute: async ({ context }) => {
|
|
715
|
+
const result = await env.GIMENES.AGENT_GENERATE_TEXT({
|
|
716
|
+
message: `Process this data: ${JSON.stringify(context.data)}`
|
|
717
|
+
});
|
|
718
|
+
return { processedData: result.text || "" };
|
|
719
|
+
},
|
|
720
|
+
})(env)
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
return createWorkflow({
|
|
724
|
+
id: "MULTI_SERVICE_WORKFLOW",
|
|
725
|
+
inputSchema: z.object({
|
|
726
|
+
query: z.string(),
|
|
727
|
+
userId: z.string()
|
|
728
|
+
}),
|
|
729
|
+
outputSchema: z.object({
|
|
730
|
+
success: z.boolean(),
|
|
731
|
+
processedData: z.string()
|
|
732
|
+
}),
|
|
733
|
+
})
|
|
734
|
+
.then(fetchExternalData)
|
|
735
|
+
.map((context) => ({
|
|
736
|
+
...context,
|
|
737
|
+
// Data validation and processing
|
|
738
|
+
isValidData: context.externalData && context.externalData.length > 0,
|
|
739
|
+
dataCount: context.externalData?.length || 0
|
|
740
|
+
}))
|
|
741
|
+
.branch(
|
|
742
|
+
(context) => context.isValidData,
|
|
743
|
+
(workflow) => workflow
|
|
744
|
+
.then(processWithAI)
|
|
745
|
+
.map((context) => ({
|
|
746
|
+
...context,
|
|
747
|
+
success: true
|
|
748
|
+
})),
|
|
749
|
+
(workflow) => workflow
|
|
750
|
+
.map((context) => ({
|
|
751
|
+
...context,
|
|
752
|
+
success: false,
|
|
753
|
+
processedData: "No valid data found"
|
|
754
|
+
}))
|
|
755
|
+
)
|
|
756
|
+
.commit();
|
|
757
|
+
};
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### Example 3: Parallel Processing
|
|
761
|
+
```typescript
|
|
762
|
+
const createParallelProcessingWorkflow = (env: Env) => {
|
|
763
|
+
// Step 1: Fetch user profile
|
|
764
|
+
const fetchUserProfile = createStepFromTool(
|
|
765
|
+
createTool({
|
|
766
|
+
id: "FETCH_USER_PROFILE",
|
|
767
|
+
description: "Fetch user profile data",
|
|
768
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
769
|
+
outputSchema: z.object({ profile: z.any() }),
|
|
770
|
+
execute: async ({ context }) => {
|
|
771
|
+
const result = await env.DECO_CHAT_WORKSPACE_API.DATABASES_RUN_SQL({
|
|
772
|
+
sql: "SELECT * FROM user_profiles WHERE user_id = ?",
|
|
773
|
+
params: [context.userId]
|
|
774
|
+
});
|
|
775
|
+
return { profile: result.results?.[0] };
|
|
776
|
+
},
|
|
777
|
+
})(env)
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
// Step 2: Fetch user preferences
|
|
781
|
+
const fetchUserPreferences = createStepFromTool(
|
|
782
|
+
createTool({
|
|
783
|
+
id: "FETCH_USER_PREFERENCES",
|
|
784
|
+
description: "Fetch user preferences",
|
|
785
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
786
|
+
outputSchema: z.object({ preferences: z.any() }),
|
|
787
|
+
execute: async ({ context }) => {
|
|
788
|
+
const result = await env.DECO_CHAT_WORKSPACE_API.DATABASES_RUN_SQL({
|
|
789
|
+
sql: "SELECT * FROM user_preferences WHERE user_id = ?",
|
|
790
|
+
params: [context.userId]
|
|
791
|
+
});
|
|
792
|
+
return { preferences: result.results?.[0] };
|
|
793
|
+
},
|
|
794
|
+
})(env)
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
return createWorkflow({
|
|
798
|
+
id: "PARALLEL_PROCESSING_WORKFLOW",
|
|
799
|
+
inputSchema: z.object({ userId: z.string() }),
|
|
800
|
+
outputSchema: z.object({
|
|
801
|
+
success: z.boolean(),
|
|
802
|
+
dataSummary: z.any()
|
|
803
|
+
}),
|
|
804
|
+
})
|
|
805
|
+
.parallel([
|
|
806
|
+
fetchUserProfile,
|
|
807
|
+
fetchUserPreferences
|
|
808
|
+
])
|
|
809
|
+
.map((context) => ({
|
|
810
|
+
...context,
|
|
811
|
+
// Combine and validate parallel results
|
|
812
|
+
hasCompleteData: context.profile && context.preferences,
|
|
813
|
+
dataSummary: {
|
|
814
|
+
profileComplete: !!context.profile,
|
|
815
|
+
preferencesComplete: !!context.preferences
|
|
816
|
+
}
|
|
817
|
+
}))
|
|
818
|
+
.branch(
|
|
819
|
+
(context) => context.hasCompleteData,
|
|
820
|
+
(workflow) => workflow
|
|
821
|
+
.map((context) => ({
|
|
822
|
+
...context,
|
|
823
|
+
success: true
|
|
824
|
+
})),
|
|
825
|
+
(workflow) => workflow
|
|
826
|
+
.map((context) => ({
|
|
827
|
+
...context,
|
|
828
|
+
success: false
|
|
829
|
+
}))
|
|
830
|
+
)
|
|
831
|
+
.commit();
|
|
832
|
+
};
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
## 🔍 Debugging and Testing
|
|
836
|
+
|
|
837
|
+
### Local Development
|
|
838
|
+
```bash
|
|
839
|
+
# Start with debugging
|
|
840
|
+
deco dev --debug
|
|
841
|
+
|
|
842
|
+
# Check logs
|
|
843
|
+
deco logs
|
|
844
|
+
|
|
845
|
+
# Test specific workflow
|
|
846
|
+
deco test workflow-name
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Common Issues
|
|
850
|
+
1. **Type Errors**: Check your Zod schemas and TypeScript types
|
|
851
|
+
2. **Integration Errors**: Verify integration configuration and credentials
|
|
852
|
+
3. **Workflow Errors**: Check step dependencies and data flow
|
|
853
|
+
4. **Deployment Errors**: Verify wrangler.toml configuration
|
|
854
|
+
|
|
855
|
+
## 📚 Best Practices Summary
|
|
856
|
+
|
|
857
|
+
### 1. Workflow Design
|
|
858
|
+
- **Keep steps atomic**: Each step should do one thing
|
|
859
|
+
- **Use control flow for logic**: Leverage `.map`, `.branch`, `.parallel`
|
|
860
|
+
- **Separate concerns**: I/O operations vs data processing
|
|
861
|
+
- **Handle errors gracefully**: Use try-catch and proper error schemas
|
|
862
|
+
|
|
863
|
+
### 2. Tool Design
|
|
864
|
+
- **Validate inputs**: Always use Zod schemas
|
|
865
|
+
- **Provide clear descriptions**: Help users understand what your tool does
|
|
866
|
+
- **Return consistent outputs**: Use predictable data structures
|
|
867
|
+
- **Handle edge cases**: Consider what happens when things go wrong
|
|
868
|
+
|
|
869
|
+
### 3. Integration Usage
|
|
870
|
+
- **Check documentation**: Each integration has specific parameters
|
|
871
|
+
- **Use TypeScript**: Leverage the generated types for type safety
|
|
872
|
+
- **Handle rate limits**: Be mindful of API limitations
|
|
873
|
+
- **Cache when appropriate**: Avoid unnecessary repeated calls
|
|
874
|
+
|
|
875
|
+
### 4. Performance
|
|
876
|
+
- **Parallelize when possible**: Use `.parallel` for independent operations
|
|
877
|
+
- **Batch operations**: Group related operations together
|
|
878
|
+
- **Optimize data flow**: Minimize data transformation overhead
|
|
879
|
+
|
|
880
|
+
## 📖 Additional Resources
|
|
881
|
+
|
|
882
|
+
- **Mastra Workflows**: https://mastra.ai/en/docs/workflows/control-flow
|
|
883
|
+
- **Data Mapping**: https://mastra.ai/en/docs/workflows/input-data-mapping
|
|
884
|
+
- **deco.chat Documentation**: Platform-specific guides and examples
|
|
885
|
+
- **TypeScript Documentation**: For advanced type usage
|
|
886
|
+
- **Zod Documentation**: For schema validation patterns
|
|
887
|
+
|
|
888
|
+
## 🎯 Key Takeaways
|
|
889
|
+
|
|
890
|
+
Remember the core principle: **Each workflow step should invoke only ONE tool, and all other processing should use Mastra's control flow operators**. This approach ensures:
|
|
891
|
+
|
|
892
|
+
- **Maintainability**: Clear separation of concerns
|
|
893
|
+
- **Testability**: Each step can be tested independently
|
|
894
|
+
- **Scalability**: Easy to modify and extend workflows
|
|
895
|
+
- **Performance**: Optimal execution patterns
|
|
896
|
+
|
|
897
|
+
Start simple, build incrementally, and leverage the power of deco.chat's integration ecosystem to create powerful automation workflows!
|
|
898
|
+
|
|
899
|
+
- **Scalability**: Easy to modify and extend workflows
|
|
900
|
+
- **Performance**: Optimal execution patterns
|
|
901
|
+
|
|
902
|
+
Start simple, build incrementally, and leverage the power of deco.chat's integration ecosystem to create powerful automation workflows!
|