Skip to content

Commit 65e42c7

Browse files
committed
feat: implement article flow with parallel steps and retry logic
- Added task functions for fetching, summarizing, extracting keywords, and publishing - Updated flow definition to run summarize and extract keywords in parallel - Included retry mechanism in summarize function via attemptNumber parameter - Simplified flow configuration with maxAttempts and default settings - Improved code clarity and structure for Phase 2 article processing flow
1 parent 0fafb70 commit 65e42c7

34 files changed

+20786
-15184
lines changed

.tool-versions

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
nodejs 24.11.0
2+
pnpm 10.20.0

PHASE_2_ARTICLE_FLOW.md

Lines changed: 87 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
**Goal:** Implement 4-step article processing flow with state management. Establish data flow foundation for observability features.
66

77
**Success Criteria:**
8+
89
- ✅ Article processing flow with 4 steps (fetch, summarize, extractKeywords, publish)
910
- ✅ Simulated retry on summarize step
1011
- ✅ pgflow State Store manages run state
@@ -25,12 +26,27 @@ cd ../..
2526
```
2627

2728
This installs:
28-
- `@xyflow/svelte` - DAG visualization
29-
- `shiki` - Syntax highlighting
29+
30+
- `@xyflow/svelte` - DAG visualization (used in Phase 3)
31+
- `shiki` - Syntax highlighting (used in Phase 4+)
32+
33+
**Note:** Installing all frontend dependencies now simplifies later phases and avoids switching contexts when building UI components.
34+
35+
---
36+
37+
### 2. Copy Logo Assets
38+
39+
Copy pgflow logos for header component (used in Phase 6):
40+
41+
```bash
42+
cp pkgs/website/src/assets/pgflow-logo-*.svg apps/demo/static/
43+
```
44+
45+
This copies both light and dark variants of the pgflow logo.
3046

3147
---
3248

33-
### 2. Create Article Flow Worker
49+
### 3. Create Article Flow Worker
3450

3551
Create new Edge Function for the article flow:
3652

@@ -43,55 +59,75 @@ This creates `apps/demo/supabase/functions/article_flow_worker/` directory.
4359

4460
---
4561

46-
### 3. Create Article Processing Flow
62+
### 4. Create Article Processing Flow
4763

4864
Create `apps/demo/supabase/functions/article_flow_worker/article_flow.ts` with 4 steps:
4965

5066
```typescript
5167
import { Flow } from '@pgflow/dsl';
5268

69+
// Task functions (implementations can be simple for Phase 2)
70+
async function fetchArticle(url: string) {
71+
const response = await fetch(`https://r.jina.ai/${url}`);
72+
const content = await response.text();
73+
return { content, title: 'Article Title' };
74+
}
75+
76+
function summarizeArticle(content: string, attemptNumber: number) {
77+
// Simulate failure on first attempt for retry demo
78+
if (attemptNumber === 1) {
79+
throw new Error('Simulated failure for retry demo');
80+
}
81+
return { summary: `Summary of article`, sentiment: 'positive' };
82+
}
83+
84+
function extractKeywords(content: string) {
85+
return { keywords: ['keyword1', 'keyword2', 'keyword3'] };
86+
}
87+
88+
function publishArticle(data: { summary: any; keywords: any }) {
89+
return {
90+
articleId: crypto.randomUUID(),
91+
publishedAt: new Date().toISOString(),
92+
...data,
93+
};
94+
}
95+
96+
// Flow definition - clean and minimal
5397
export default new Flow<{ url: string }>({
5498
slug: 'article_flow',
5599
maxAttempts: 3,
56-
baseDelay: 1,
57-
timeout: 60
58100
})
59-
.step({ slug: 'fetch_article' }, async (input) => {
60-
// Call r.jina.ai API
61-
const response = await fetch(`https://r.jina.ai/${input.run.url}`);
62-
const content = await response.text();
63-
return { content, title: 'Article Title' };
64-
})
65-
.step({ slug: 'summarize' }, (input) => {
66-
// Simulate failure on first attempt
67-
if (input.attemptNumber === 1) {
68-
throw new Error('Simulated failure for retry demo');
69-
}
70-
return `Summary of: ${input.steps.fetch_article.title}`;
71-
})
72-
.step({ slug: 'extract_keywords' }, (input) => {
73-
// Runs parallel with summarize
74-
return ['keyword1', 'keyword2', 'keyword3'];
75-
})
76-
.step({ slug: 'publish' }, (input) => {
77-
// Depends on both summarize and extract_keywords
78-
return {
79-
articleId: 'article_123',
80-
summary: input.steps.summarize,
81-
keywords: input.steps.extract_keywords
82-
};
83-
});
101+
.step({ slug: 'fetch_article' }, async (input) => fetchArticle(input.run.url))
102+
.step({ slug: 'summarize', dependsOn: ['fetch_article'] }, (input) =>
103+
summarizeArticle(input.fetch_article.content, input.attemptNumber)
104+
)
105+
.step({ slug: 'extract_keywords', dependsOn: ['fetch_article'] }, (input) =>
106+
extractKeywords(input.fetch_article.content)
107+
)
108+
.step(
109+
{ slug: 'publish', dependsOn: ['summarize', 'extract_keywords'] },
110+
(input) =>
111+
publishArticle({
112+
summary: input.summarize,
113+
keywords: input.extract_keywords,
114+
})
115+
);
84116
```
85117

86118
**Key patterns:**
119+
87120
- Flow slug is `article_flow` (with underscore)
88-
- Parallel execution: summarize and extractKeywords run simultaneously (both depend only on fetch_article)
89-
- Retry simulation: Use `attemptNumber` param to fail first attempt
90-
- Flow config: `maxAttempts: 3, baseDelay: 1, timeout: 60`
121+
- Task functions defined separately for clarity
122+
- Parallel execution: `summarize` and `extract_keywords` run simultaneously (both depend only on `fetch_article`)
123+
- Retry simulation: `summarizeArticle` checks `attemptNumber` to fail first attempt
124+
- Diamond DAG shape: 1 → 2 parallel → 1
125+
- Minimal config: Only `slug` and `maxAttempts` (defaults used for baseDelay/timeout)
126+
- Explicit `dependsOn` arrays show flow structure clearly
91127

92128
---
93129

94-
### 4. Create Edge Function Worker
130+
### 5. Create Edge Function Worker
95131

96132
Create `apps/demo/supabase/functions/article_flow_worker/index.ts`:
97133

@@ -104,7 +140,7 @@ EdgeWorker.start(ArticleFlow);
104140

105141
---
106142

107-
### 5. Create Deno Import Map
143+
### 6. Create Deno Import Map
108144

109145
Create `apps/demo/supabase/functions/article_flow_worker/deno.json`:
110146

@@ -128,7 +164,7 @@ Create `apps/demo/supabase/functions/article_flow_worker/deno.json`:
128164

129165
---
130166

131-
### 6. Configure Edge Function in config.toml
167+
### 7. Configure Edge Function in config.toml
132168

133169
Edit `apps/demo/supabase/config.toml`, add at the end:
134170

@@ -144,7 +180,7 @@ entrypoint = "./functions/article_flow_worker/index.ts"
144180

145181
---
146182

147-
### 7. Set Environment Variables
183+
### 8. Set Environment Variables
148184

149185
Create `apps/demo/supabase/.env.local` with `JINA_API_KEY` (optional for now):
150186

@@ -154,7 +190,7 @@ JINA_API_KEY=your_jina_api_key_here
154190

155191
---
156192

157-
### 8. Rebuild and Re-vendor
193+
### 9. Rebuild and Re-vendor
158194

159195
```bash
160196
pnpm nx build core dsl client
@@ -163,7 +199,7 @@ pnpm nx sync-edge-deps demo
163199

164200
---
165201

166-
### 9. Test Edge Function Locally
202+
### 10. Test Edge Function Locally
167203

168204
```bash
169205
cd apps/demo
@@ -174,7 +210,7 @@ npx -y supabase@latest functions serve article_flow_worker
174210

175211
---
176212

177-
### 10. Create pgflow State Store
213+
### 11. Create pgflow State Store
178214

179215
Create `apps/demo/src/lib/stores/pgflow-state.svelte.ts`:
180216

@@ -199,6 +235,7 @@ export const pgflowState = new PgflowState();
199235
**Purpose:** Central state management for flow execution, used by all UI components
200236

201237
**Key patterns:**
238+
202239
- Use Svelte 5 runes: `$state` and `$derived`
203240
- Export singleton instance
204241
- Will be updated in Phase 3 when building UI
@@ -207,14 +244,15 @@ export const pgflowState = new PgflowState();
207244

208245
## Validation Checklist
209246

210-
- [ ] Article flow worker created (`article_flow_worker/`)
211-
- [ ] 4-step flow created with simulated retry
212-
- [ ] Worker configured in `config.toml` with `verify_jwt = false`
213-
- [ ] Deno import map created with all dependencies
214-
- [ ] pgflow State Store created and exported
215-
- [ ] All dependencies installed (`@xyflow/svelte`, `shiki`)
216-
- [ ] Edge Function serves successfully
217-
- [ ] Build succeeds
247+
- [x] All dependencies installed (`@xyflow/svelte`, `shiki`)
248+
- [x] Logo assets copied to `apps/demo/static/`
249+
- [x] Article flow worker created (`article_flow_worker/`)
250+
- [x] 4-step flow created with simulated retry
251+
- [x] Worker configured in `config.toml` with `verify_jwt = false`
252+
- [x] Deno import map created with all dependencies
253+
- [x] pgflow State Store created and exported
254+
- [x] Edge Function serves successfully
255+
- [x] Build succeeds
218256

219257
---
220258

PHASE_3_DAG_DEBUG.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,19 @@
1919

2020
## Tasks
2121

22-
### 7. Create DAG Component
22+
### 1. Verify Dependencies
23+
24+
Confirm `@xyflow/svelte` was installed in Phase 2:
25+
26+
```bash
27+
ls apps/demo/node_modules/@xyflow/svelte
28+
```
29+
30+
**If missing:** Run `cd apps/demo && pnpm add @xyflow/svelte && cd ../..`
31+
32+
---
33+
34+
### 2. Create DAG Component
2335

2436
Create `apps/demo/src/lib/components/DAGVisualization.svelte`:
2537

@@ -31,7 +43,7 @@ Use `@xyflow/svelte` to render 4 nodes:
3143

3244
---
3345

34-
### 8. Create Debug Panel Component
46+
### 3. Create Debug Panel Component
3547

3648
Create `apps/demo/src/lib/components/DebugPanel.svelte` with 3 sections:
3749

@@ -43,7 +55,7 @@ Create `apps/demo/src/lib/components/DebugPanel.svelte` with 3 sections:
4355

4456
---
4557

46-
### 9. Create Demo Page Layout
58+
### 4. Create Demo Page Layout
4759

4860
Update `apps/demo/src/routes/+page.svelte`:
4961

@@ -57,11 +69,11 @@ Update `apps/demo/src/routes/+page.svelte`:
5769

5870
---
5971

60-
### 10. Add Brand Assets and Styles
72+
### 5. Add Brand Styles
6173

62-
Copy logos from website to static folder:
74+
Verify logos were copied in Phase 2:
6375
```bash
64-
cp pkgs/website/src/assets/pgflow-logo-*.svg apps/demo/static/
76+
ls apps/demo/static/pgflow-logo-*.svg
6577
```
6678

6779
Create `apps/demo/src/app.css` with pgflow brand colors:
@@ -74,7 +86,7 @@ Import styles in `apps/demo/src/routes/+layout.svelte`
7486

7587
---
7688

77-
### 11. Test Complete Flow
89+
### 6. Test Complete Flow
7890

7991
```bash
8092
cd apps/demo

apps/demo/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
},
3939
"dependencies": {
4040
"@pgflow/client": "workspace:*",
41-
"@supabase/supabase-js": "^2.78.0"
41+
"@pgflow/dsl": "workspace:*",
42+
"@supabase/supabase-js": "^2.78.0",
43+
"@xyflow/svelte": "^1.4.1",
44+
"shiki": "^3.14.0"
4245
}
4346
}

apps/demo/project.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@
66
"targets": {
77
"dev": {
88
"executor": "nx:run-commands",
9+
"dependsOn": ["^build"],
910
"options": {
1011
"command": "vite dev",
1112
"cwd": "apps/demo"
1213
}
1314
},
15+
"dev:remote": {
16+
"executor": "nx:run-commands",
17+
"dependsOn": ["^build"],
18+
"options": {
19+
"command": "vite dev --host 0.0.0.0",
20+
"cwd": "apps/demo"
21+
}
22+
},
1423
"build": {
1524
"executor": "nx:run-commands",
1625
"options": {
@@ -34,6 +43,13 @@
3443
"command": "./scripts/sync-edge-deps.sh",
3544
"cwd": "apps/demo"
3645
}
46+
},
47+
"test": {
48+
"executor": "nx:run-commands",
49+
"options": {
50+
"command": "deno test --allow-env --allow-net tests/",
51+
"cwd": "apps/demo/supabase/functions/article_flow_worker"
52+
}
3753
}
3854
}
3955
}

0 commit comments

Comments
 (0)