Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c7ff328
fix(website): add track shake animation to ProblemSection stall phase
blove Apr 6, 2026
0184028
fix(website): ProblemSection quality fixes — timer cleanup, unique SV…
blove Apr 6, 2026
066cc01
feat: add FullStackSection with animated stack diagram and roadmap strip
blove Apr 6, 2026
e51db0b
feat: add ChatFeaturesSection with 4 interactive chat scenarios
blove Apr 6, 2026
35b5012
feat: add FairComparisonSection comparison table
blove Apr 6, 2026
69ad158
feat: wire ProblemSection, FullStackSection, ChatFeaturesSection, Fai…
blove Apr 6, 2026
ac787c4
chore: add puppeteer devDependency and generate-whitepaper script
blove Apr 6, 2026
e8a2025
feat: add whitepaper signup API route with NDJSON persistence
blove Apr 6, 2026
1fdf4e8
feat: add whitepaper generation script
blove Apr 6, 2026
d1b8655
feat: add WhitePaperSection with free download and optional lead-gen …
blove Apr 6, 2026
b424eda
feat: add WhitePaperSection to landing page; remove useStream parity …
blove Apr 6, 2026
136a331
fix(whitepaper): add JetBrains Mono to Google Fonts URL and regenerat…
blove Apr 6, 2026
4f769f9
feat: add PilotHero component and /pilot-to-prod page skeleton
blove Apr 6, 2026
c5d9478
fix: PilotHero responsive padding, eyebrow style conflict, page metadata
blove Apr 6, 2026
28d68a8
feat: add WhatIsIncluded 3-column component for pilot-to-prod page
blove Apr 6, 2026
359825c
feat: add HowItWorks 3-phase timeline for pilot-to-prod page
blove Apr 6, 2026
2a9ded1
feat: add PricingSignal pricing callout for pilot-to-prod page
blove Apr 6, 2026
a24da8d
feat: add WhitePaperGate 5-field lead gen form for pilot-to-prod page
blove Apr 6, 2026
738ad97
fix: change role=alert to role=status to match aria-live=polite in Wh…
blove Apr 6, 2026
4204842
feat: add PilotFooterCTA and wire complete pilot-to-prod page
blove Apr 6, 2026
e1af11c
fix: use tokens.colors.accent in PilotFooterCTA, add aria-hidden to p…
blove Apr 6, 2026
1c2537b
feat: add Pilot to Prod nav link and restructure homepage (remove Fea…
blove Apr 6, 2026
f708460
fix: correct design-tokens import path in pilot-to-prod page (3 level…
blove Apr 6, 2026
2578383
fix: apply full review findings — messaging, mobile, UX, and RiskRemo…
blove Apr 6, 2026
1caf6c9
fix: remove remaining useStream parity messaging from layout, Footer,…
blove Apr 6, 2026
a153786
fix: second review pass — docs messaging, title, broken link, a11y la…
blove Apr 6, 2026
3d4b40e
feat: add whitepaper.pdf to public directory
blove Apr 6, 2026
51e92f9
feat: citation badges on stats, pricing reframe to app deployment lic…
blove Apr 6, 2026
3198951
feat: subtler citation badge + citations on all 77% claims
blove Apr 6, 2026
d08bd56
docs: add FullStackSection redesign spec (EM/CTO layer narrative + Ge…
blove Apr 6, 2026
a88fc3c
feat(website): redesign FullStackSection for EM/CTO audience
blove Apr 6, 2026
cb7348d
merge: integrate rebrand + chat polish from main into website narrative
blove Apr 6, 2026
d46f364
docs: apply Angular Stream Resource rebrand to narrative components
blove Apr 6, 2026
cb6f7f4
chore: sync package-lock.json after merge
blove Apr 6, 2026
624c955
fix(website): update e2e test for new landing page structure
blove Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,5 @@ apps/website/public/demo/
out
.vercel

# LangGraph
.langgraph_api/
langgraph-combined.json

# Playwright
test-results/

# Deploy output
deploy/
# Whitepaper signup data
apps/website/data/
2 changes: 1 addition & 1 deletion apps/website/content/AGENTS.md.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# stream-resource v@VERSION@

Angular streaming library for LangChain/LangGraph. Provides `streamResource()` — full parity with React's `useStream()`.
Angular streaming library for LangChain/LangGraph. Provides `streamResource()` — Signal-native streaming for Angular agents, built for LangGraph.

## Install
npm install stream-resource
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/CLAUDE.md.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# stream-resource v@VERSION@

Angular streaming library for LangChain/LangGraph. Provides `streamResource()` — full parity with React's `useStream()`.
Angular streaming library for LangChain/LangGraph. Provides `streamResource()` — Signal-native streaming for Angular agents, built for LangGraph.

## Install
npm install stream-resource
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Introduction

StreamResource brings full parity with React's `useStream()` hook to Angular 20+. Build streaming AI applications with Angular Signals, connect to LangGraph agents, and ship production-ready frontends for your AI products.
StreamResource is the Signal-native streaming library for Angular 20+ — built natively for LangGraph, without React translation layers. Build streaming AI applications with Angular Signals, connect to LangGraph agents, and ship production-ready frontends for your AI products.

<Callout type="info" title="What you'll learn">
This guide walks you through the complete workflow: build a LangGraph agent in Python, run it locally, connect it to an Angular app with streamResource(), and deploy to production.
Expand Down
5 changes: 2 additions & 3 deletions apps/website/e2e/website.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ test('landing page renders architecture section', async ({ page }) => {
await expect(page.getByText('Architecture').first()).toBeVisible();
});

test('landing page renders 6 feature cards', async ({ page }) => {
test('landing page renders fair comparison section', async ({ page }) => {
await page.goto('/');
const featureSection = page.locator('section').filter({ hasText: 'Features' });
await expect(featureSection).toBeVisible();
await expect(page.getByText('What Angular Stream Resource adds').first()).toBeVisible();
});

test('pricing page shows 4 plan cards', async ({ page }) => {
Expand Down
167 changes: 167 additions & 0 deletions apps/website/public/whitepaper-preview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;600&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Inter',sans-serif;color:#1a1a2e;background:#fff}
.chapter-body p{font-size:15px;line-height:1.75;color:#333;margin-bottom:18px}
.chapter-body h3{font-family:'EB Garamond',serif;font-size:22px;font-weight:700;color:#1a1a2e;margin:28px 0 12px}
.chapter-body ul{margin:0 0 18px 20px}
.chapter-body li{font-size:15px;line-height:1.7;color:#333;margin-bottom:6px}
.chapter-body pre{background:#1a1b26;color:#c8ccee;padding:20px 24px;border-radius:8px;font-size:13px;line-height:1.65;overflow-x:auto;margin:24px 0;white-space:pre-wrap}
.chapter-body code{font-family:'JetBrains Mono',monospace;font-size:13px}
.chapter-body strong{font-weight:600}
</style>
</head>
<body>

<!-- Cover -->
<div style="height:100vh;display:flex;flex-direction:column;justify-content:flex-end;padding:80px 80px 100px;background:linear-gradient(135deg,#fef0f3 0%,#f4f0ff 45%,#eaf3ff 70%,#e6f4ff 100%);page-break-after:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.12em;color:#004090;font-weight:700;margin-bottom:24px">StreamResource · Production Readiness Guide</div>
<h1 style="font-family:'EB Garamond',serif;font-size:52px;font-weight:800;line-height:1.1;color:#1a1a2e;margin-bottom:20px">From Prototype<br>to Production</h1>
<p style="font-family:'EB Garamond',serif;font-style:italic;font-size:20px;color:#555770;margin-bottom:40px">The Angular Agent Readiness Guide</p>
<div style="font-size:13px;color:#888;font-family:monospace">cacheplane.io · 2026</div>
<div style="margin-top:16px;padding:8px 14px;background:rgba(255,160,50,.12);border:1px solid rgba(255,160,50,.3);border-radius:6px;font-family:monospace;font-size:11px;color:#c47a00;display:inline-block">⚠ PREVIEW — placeholder content. Set ANTHROPIC_API_KEY and run npm run generate-whitepaper for real content.</div>
</div>

<!-- TOC -->
<div style="padding:80px;page-break-after:always">
<h2 style="font-family:'EB Garamond',serif;font-size:32px;font-weight:700;color:#1a1a2e;margin-bottom:32px">Contents</h2>

<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">01</span>
<span style="flex:1">Streaming State Management</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">02</span>
<span style="flex:1">Thread Persistence</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">03</span>
<span style="flex:1">Tool-Call Rendering</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">04</span>
<span style="flex:1">Human Approval Flows</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">05</span>
<span style="flex:1">Generative UI</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:15px;color:#444">
<span style="font-family:monospace;font-size:11px;color:#004090;font-weight:700;min-width:24px">06</span>
<span style="flex:1">Deterministic Testing</span>
</div>
</div>

<!-- Chapters -->

<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 1</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Streaming State Management</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>When you move from prototype to production, the requirements change fundamentally. What worked in a demo — direct API calls, synchronous state, manual zone management — falls apart at scale.</p>
<h3>The Signals-Native Approach</h3>
<p>StreamResource provides a signals-native approach that eliminates the boilerplate:</p>
<pre><code>@Component({...})
export class ChatComponent {
chat = streamResource<{ messages: BaseMessage[] }>({
assistantId: 'chat_agent',
});
}
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Are your message signals OnPush-compatible?</li>
<li>Is isStreaming() driving your loading UI without polling?</li>
<li>Are you avoiding manual zone patching?</li></ul></div>
</section>
<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 2</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Thread Persistence</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>Demos work with ephemeral state. Production agents need conversation history that survives page refreshes, tab switches, and navigation — wired to LangGraph's MemorySaver backend.</p>
<h3>The threadId Pattern</h3>
<pre><code>provideStreamResource({
apiUrl: 'http://localhost:2024',
threadId: signal(localStorage.getItem('threadId')),
onThreadId: (id) => localStorage.setItem('threadId', id),
})
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Does your agent UI resume threads correctly after a browser refresh?</li>
<li>Can users switch between conversations?</li>
<li>Is thread state scoped correctly per user?</li></ul></div>
</section>
<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 3</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Tool-Call Rendering</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>LangGraph agents invoke tools mid-stream. The UI needs to show tool execution state in real time — steps appearing as the tool runs, a final result, and collapsible history.</p>
<h3>Progressive Disclosure</h3>
<pre><code><chat-tool-call-card
[toolCall]="msg.tool_calls[0]"
[collapsed]="!isStreaming()">
</chat-tool-call-card>
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Do your tool call cards handle partial step state during streaming?</li>
<li>Is tool history collapsible after completion?</li>
<li>Can you distinguish pending vs. completed tool calls?</li></ul></div>
</section>
<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 4</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Human Approval Flows</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>Production agents that take consequential actions must pause for human approval before proceeding. This requires a tight loop between LangGraph's interrupt() primitive and Angular UI.</p>
<h3>The Interrupt Pattern</h3>
<pre><code>// In your component
approved = computed(() => this.chat.interrupt()?.approved ?? false);
onApprove() {
this.chat.submit(null, { command: { resume: true } });
}
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Can your agent UI recover gracefully if a user cancels an interrupt?</li>
<li>Are approve/edit/cancel actions clearly mapped to resume commands?</li>
<li>Is interrupt state persisted across refreshes?</li></ul></div>
</section>
<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 5</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Generative UI</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>The most advanced production agents emit structured UI specs — not just text. A data analysis agent might render a live table. A booking agent might render a reservation form.</p>
<h3>The Registry Pattern</h3>
<pre><code>defineAngularRegistry({
'data-table': DataTableComponent,
'booking-form': BookingFormComponent,
'chart-widget': ChartWidgetComponent,
});
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Can your agent emit UI components without tight coupling to the frontend codebase?</li>
<li>Does JSON patch streaming enable progressive UI updates?</li>
<li>Is your component registry decoupled from agent logic?</li></ul></div>
</section>
<section style="padding:80px;page-break-before:always">
<div style="font-family:monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.1em;color:#004090;font-weight:700;margin-bottom:16px">Chapter 6</div>
<h2 style="font-family:'EB Garamond',serif;font-size:36px;font-weight:800;color:#1a1a2e;margin-bottom:28px;line-height:1.15">Deterministic Testing</h2>
<div class="chapter-body"><h3>Overview</h3>
<p>Agent UIs are notoriously hard to test because they depend on live LLM responses. Flaky tests, slow CI, and inability to reproduce edge cases are the main reasons agent UIs ship with low confidence.</p>
<h3>The MockStreamTransport Approach</h3>
<pre><code>const ref = createMockStreamResourceRef<ChatState>();
ref.messages.set([{ role: 'assistant', content: 'Hello' }]);
ref.isStreaming.set(false);
expect(fixture.nativeElement.querySelector('.message').textContent)
.toBe('Hello');
</code></pre>
<h3>Production Checklist</h3>
<ul><li>Do your agent component tests run offline and complete in under 100ms each?</li>
<li>Are streaming, interrupts, tool calls, and generative UI all tested in isolation?</li>
<li>Is MockStreamTransport used instead of mocking streamResource() itself?</li></ul></div>
</section>

</body>
</html>
Binary file added apps/website/public/whitepaper.pdf
Binary file not shown.
Loading