1export class IngestWorkflow extends AgentWorkflow<Klippy, IngestParams> {
2 async run(event: AgentWorkflowEvent<IngestParams>, step: AgentWorkflowStep) {
3 const db = createD1Database(this.env.DB);
4 const { sourceId } = event.payload;
5 const source = await step.do('load', () => db.find(sources, sourceId));
6 if (!source || source.status !== 'queued') return { skipped: true };
7
8 try {
9 // A link is fetched and turned into Markdown. A note or a file already has its text.
10 if (source.kind === 'link' && source.url) {
11 // Websites fail now and then: try 3 more times, waiting 5 s, then 10 s, then 20 s.
12 const page = await step.do('fetch', { retries: { limit: 3, delay: '5 seconds', backoff: 'exponential' }, timeout: '1 minute' }, () =>
13 readLinkAsMarkdown(this.env, source.url!),
14 );
15 await step.do('store', () => db.update(sources, sourceId, { title: page.title.slice(0, 200), body: page.body }));
16 }
17 await step.do('ready', () => db.update(sources, sourceId, { status: 'ready' }));
18 return { sourceId, status: 'ready' };
19 } catch (error) {
20 // Out of retries: mark it failed, so Klippy can say so instead of pretending it read the page.
21 await step.do('failed', () => db.update(sources, sourceId, { status: 'failed' }));
22 throw error;
23 }
24 }
25}