This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Enrich on ingest: LLM summaries at write time

New papers now get Letta API enrichment immediately when ingested,
no separate /api/enrich step needed. Falls back to heuristic summary
if Letta is unavailable.

Both poll endpoint and cron handler enriched.

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta Code <noreply@letta.com>

author
Nandi
co-author
Letta Code
date (May 17, 2026, 9:56 PM -0700) commit 5d0e0727 parent c5be4bc6
+58 -3
+58 -3
src/worker.ts
··· 209 209 let errors = 0; 210 210 const errorDetails: string[] = []; 211 211 212 + const apiKey = process.env.LETTA_API_KEY; 213 + const agentId = process.env.LETTA_AGENT_ID; 214 + 212 215 for (const post of newPosts) { 213 216 try { 214 - const summary = await buildSummary(post); 217 + let summary = await buildSummary(post); 218 + 219 + // Enrich with LLM if available 220 + if (apiKey && agentId) { 221 + try { 222 + const enrichment = await enrichWithLetta( 223 + { title: summary.title, paperUrl: summary.paperUrl, abstract: summary.abstract, domains: summary.domains, venue: summary.venue }, 224 + apiKey, 225 + agentId, 226 + ); 227 + if (enrichment.title) summary.title = enrichment.title; 228 + summary.summary = enrichment.summary; 229 + summary.domains = enrichment.domains; 230 + if (enrichment.takeaway) (summary as any).takeaway = enrichment.takeaway; 231 + } catch (err: any) { 232 + console.error(`Enrichment failed for ${post.paperUrl}: ${err?.message ?? err}, using heuristic`); 233 + } 234 + } 235 + 215 236 const result = await writeSummaryToPds(post, summary); 216 237 217 238 // Index the new record into D1 directly ··· 468 489 } 469 490 470 491 const newPosts = posts.filter(p => !existingUrls.has(p.paperUrl)); 492 + const apiKey = process.env.LETTA_API_KEY; 493 + const agentId = process.env.LETTA_AGENT_ID; 471 494 472 495 for (const post of newPosts) { 473 496 try { 474 - const summary = await buildSummary(post); 497 + let summary = await buildSummary(post); 498 + 499 + // Enrich with LLM if available 500 + if (apiKey && agentId) { 501 + try { 502 + const enrichment = await enrichWithLetta( 503 + { title: summary.title, paperUrl: summary.paperUrl, abstract: summary.abstract, domains: summary.domains, venue: summary.venue }, 504 + apiKey, 505 + agentId, 506 + ); 507 + if (enrichment.title) summary.title = enrichment.title; 508 + summary.summary = enrichment.summary; 509 + summary.domains = enrichment.domains; 510 + if (enrichment.takeaway) (summary as any).takeaway = enrichment.takeaway; 511 + } catch { 512 + // Fall back to heuristic summary 513 + } 514 + } 515 + 475 516 const result = await writeSummaryToPds(post, summary); 476 - await contrail.notify(result.uri); 517 + 518 + // Index into D1 519 + const rkey = result.uri.split("/").pop() || ""; 520 + await db 521 + .prepare("INSERT OR REPLACE INTO records_summary (uri, cid, did, rkey, record, time_us, indexed_at) VALUES (?, ?, ?, ?, ?, ?, ?)") 522 + .bind(result.uri, result.cid, "did:plc:3kkhul7jznlb6ba7rprzawnj", rkey, JSON.stringify({ 523 + $type: "org.latha.papers.summary", 524 + ...summary, 525 + sourceUri: post.postUri, 526 + posterDid: post.posterDid, 527 + posterHandle: post.posterHandle, 528 + postText: post.postText, 529 + indexedAt: new Date().toISOString(), 530 + }), Date.now() * 1000, Date.now() * 1000) 531 + .run(); 477 532 } catch (err: any) { 478 533 console.error(`Cron: failed to write summary for ${post.paperUrl}: ${err?.message ?? err}`); 479 534 }