Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
f739e22
refactor(website): migrate to shadcn/ui component primitives (#1)
blove Apr 3, 2026
fe1c63a
docs: add glassy gradient redesign spec
blove Apr 4, 2026
35d9621
docs: add glassy gradient redesign implementation plan
blove Apr 4, 2026
e9bc6f7
feat(website): update design tokens for glassy gradient redesign
blove Apr 4, 2026
65dec95
feat(website): update global CSS for light glassy theme
blove Apr 4, 2026
ee7181a
feat(website): apply gradient background and glass to Hero
blove Apr 4, 2026
7246e8a
feat(website): update ArchDiagram for light glassy theme
blove Apr 4, 2026
d41d0d0
feat(website): apply glass cards to FeatureStrip
blove Apr 4, 2026
9044bbc
feat(website): apply glass treatment to ApiRefTable
blove Apr 4, 2026
3320ab2
feat(website): apply glass border to CodeBlock
blove Apr 4, 2026
e5528c4
feat(website): add gradient background to API reference page
blove Apr 4, 2026
3dbd63b
feat(website): apply glass cards to PricingGrid
blove Apr 4, 2026
51259b5
feat(website): apply glass container to CompareTable
blove Apr 4, 2026
efe3eb1
feat(website): apply glass treatment to LeadForm
blove Apr 4, 2026
bf43e62
feat(website): add gradient background to pricing page
blove Apr 4, 2026
20a4f6b
feat(website): update GenerativeUIFrame outer frame for glass theme
blove Apr 4, 2026
6a23e65
feat(website): apply gradient background to landing page
blove Apr 4, 2026
09b0258
feat(website): apply glass treatment to Nav
blove Apr 4, 2026
853ef79
feat(website): apply glass treatment to Footer
blove Apr 4, 2026
6f7de1e
feat(website): apply glass treatment to InstallStrip
blove Apr 4, 2026
468c872
feat(website): update CopyPromptButton to new accent colors
blove Apr 4, 2026
96d3727
feat(website): apply glass treatment to DocsSidebar
blove Apr 4, 2026
6e1bc3e
feat(website): switch MdxRenderer to light prose theme
blove Apr 4, 2026
6a3dcb7
feat(website): add gradient background to docs page
blove Apr 4, 2026
39382b5
fix(website): correct design-tokens import paths
blove Apr 4, 2026
4dd316c
fix(website): use unicode chars instead of HTML entities in JSX
blove Apr 4, 2026
fe65593
feat(website): expand architecture diagram with two-row layout and de…
blove Apr 4, 2026
4235524
feat(website): redesign hero animation with multi-step agent UI
blove Apr 4, 2026
f257902
fix(website): make API reference gradient fill full viewport
blove Apr 4, 2026
6b123d5
feat(website): add GitHub link to nav bar
blove Apr 4, 2026
d29f68c
feat(website): update hero copy button to full setup snippet
blove Apr 4, 2026
e22b94c
feat(website): remove live demo section from landing page
blove Apr 4, 2026
5a80256
docs: add homepage expansion implementation plan
blove Apr 4, 2026
b3b3381
feat(website): add interactive tabbed ValueProps section
blove Apr 4, 2026
e338f4d
feat(website): add reusable CapabilityCard component
blove Apr 4, 2026
615f54c
feat(website): add CockpitCTA and StatsStrip sections
blove Apr 4, 2026
d8270cd
feat(website): add LangGraph and Deep Agents capability showcases
blove Apr 4, 2026
604a79f
feat(website): wire up all new homepage sections
blove Apr 4, 2026
d8f892e
refactor(website): reorder homepage for optimal landing page flow
blove Apr 4, 2026
5c3c017
feat(website): redesign architecture as interactive vertical glass la…
blove Apr 4, 2026
b8896d4
fix(website): mobile responsive polish
blove Apr 4, 2026
10d6030
feat(website): expand footer and add scroll animations
blove Apr 4, 2026
2e297db
docs: add docs refresh design spec
blove Apr 4, 2026
d957f6e
docs: add docs infrastructure implementation plan
blove Apr 4, 2026
57674e3
feat(website): add docs navigation config
blove Apr 4, 2026
e6dd42f
feat(website): add new docs loader (cockpit-independent)
blove Apr 4, 2026
ee7df20
feat(website): add placeholder docs content (3 pages)
blove Apr 4, 2026
7cfbf17
feat(website): add custom MDX components (Callout, Steps, Tabs, Card,…
blove Apr 4, 2026
d09571c
feat(website): add collapsible docs sidebar with section groups
blove Apr 4, 2026
6baa1e9
feat(website): add DocsBreadcrumb and DocsPrevNext components
blove Apr 4, 2026
ab0e956
feat(website): add Cmd+K search modal for docs
blove Apr 4, 2026
f77453f
feat(website): wire up new docs routing with MDX components and sidebar
blove Apr 4, 2026
6819449
fix(website): make Tabs items prop optional with fallback
blove Apr 4, 2026
829ddee
Merge remote-tracking branch 'origin/main' into kind-margulis
blove Apr 4, 2026
28e3739
fix(website): fix DocsSidebarNew type error in useState
blove Apr 4, 2026
73be0b0
refactor(website): remove old docs system and shadcn UI remnants
blove Apr 4, 2026
da8511d
docs: add autogenerated API reference design spec
blove Apr 4, 2026
c0c7336
fix(website): update e2e and unit tests for new docs system
blove Apr 4, 2026
83c6766
docs: add API reference autogen implementation plan
blove Apr 4, 2026
1fc2cab
docs(stream-resource): add JSDoc to streamResource() and provideStrea…
blove Apr 4, 2026
c21745f
docs(stream-resource): add JSDoc to all public types and interfaces
blove Apr 4, 2026
7134a38
feat: glassy gradient website redesign + docs refresh (#3)
blove Apr 4, 2026
f2f4bf3
docs(stream-resource): add JSDoc to FetchStreamTransport and MockStre…
blove Apr 4, 2026
0262dde
feat(website): add API reference MDX stub pages
blove Apr 4, 2026
6c704a2
feat(website): enhance TypeDoc script for structured API docs JSON
blove Apr 4, 2026
2471988
feat(website): add ApiDocRenderer component for autogenerated API docs
blove Apr 4, 2026
d130f85
feat(website): wire API doc pages with autogenerated content from JSON
blove Apr 4, 2026
7b155f7
ci: add generate-api-docs step before website build
blove Apr 4, 2026
3e379ea
chore: trigger CI
blove Apr 4, 2026
aa14b63
Merge remote-tracking branch 'origin/main' into kind-margulis
blove Apr 4, 2026
fd87060
feat: autogenerated API reference from JSDoc (#4)
blove Apr 4, 2026
d8eaac3
docs: add docs content authoring plan
blove Apr 4, 2026
3270c9d
docs(website): write Quick Start guide
blove Apr 4, 2026
448dd06
docs(website): write Time Travel guide
blove Apr 4, 2026
a75efd7
docs(website): write Subgraphs guide
blove Apr 4, 2026
7c910f6
docs(website): write Persistence guide
blove Apr 4, 2026
fb8d5b7
docs(website): write Installation guide
blove Apr 4, 2026
dd87b07
docs(website): write Interrupts guide
blove Apr 4, 2026
fb6f6c2
docs(website): write Testing guide
blove Apr 4, 2026
30242d2
docs(website): write Deployment guide
blove Apr 4, 2026
d7a7e6b
docs(website): write Memory guide
blove Apr 4, 2026
1be0e0a
docs(website): write Angular Signals concept page
blove Apr 4, 2026
3c5d6dc
docs(website): write LangGraph Basics concept page
blove Apr 4, 2026
384056b
docs(website): write Agent Architecture concept page
blove Apr 4, 2026
bf7a1ca
docs(website): write State Management concept page
blove Apr 4, 2026
6311d85
docs(website): enhance Introduction page with expanded content
blove Apr 4, 2026
67e5b9c
docs: complete docs content authoring - 15 pages (#5)
blove Apr 4, 2026
4ed7f18
docs: add Mintlify alignment design spec
blove Apr 4, 2026
ba9080c
docs: add Mintlify alignment implementation plan
blove Apr 4, 2026
3060d8b
feat(website): Mintlify-aligned docs design overhaul
blove Apr 4, 2026
42f2722
Merge remote-tracking branch 'origin/main' into kind-margulis
blove Apr 4, 2026
576ba52
fix(website): fix e2e test for multiple aside elements (sidebar + TOC)
blove Apr 4, 2026
00af0f2
fix(website): fix TOC links with rehype-slug + remove stale plan
blove Apr 4, 2026
3db9db3
fix(website): mobile docs polish
blove Apr 4, 2026
b997bf7
docs: add expanded introduction design spec
blove Apr 4, 2026
4250aa1
docs(website): expand introduction into full end-to-end tutorial
blove Apr 4, 2026
9d0e8d3
feat(website): redesign Callout with glass treatment and SVG icons
blove Apr 4, 2026
0fe18ef
Merge remote-tracking branch 'origin/main' into claude/kind-margulis
blove Apr 4, 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
318 changes: 292 additions & 26 deletions apps/website/content/docs-v2/getting-started/introduction.mdx
Original file line number Diff line number Diff line change
@@ -1,63 +1,329 @@
# Introduction

StreamResource brings full parity with React's `useStream()` hook to Angular 20+. It's the enterprise streaming resource for LangChain and Angular — built natively with Angular Signals, not wrapped or adapted.
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.

<Callout type="info" title="Who is this for?">
StreamResource serves two audiences: **Angular developers** building AI-powered applications, and **AI/agent developers** who need a production Angular frontend for their LangGraph agents.
<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.
</Callout>

## What is streamResource()?

`streamResource()` is an Angular function that creates a reactive connection to a LangGraph agent. It returns an object whose properties are Angular Signals — meaning your templates update automatically as the agent streams responses.
`streamResource()` is an Angular function that creates a reactive, streaming connection to a LangGraph agent. It returns an object whose properties are Angular Signals — meaning your templates update automatically as the agent streams responses, token by token.

```typescript
const chat = streamResource<{ messages: BaseMessage[] }>({
assistantId: 'chat_agent',
});

// Every property is a Signal
chat.messages() // Signal<BaseMessage[]>
chat.status() // Signal<'idle' | 'loading' | 'resolved' | 'error'>
chat.interrupt() // Signal<Interrupt | undefined>
chat.history() // Signal<ThreadState[]>
// Every property is a Signal — reactive, synchronous, no subscriptions
chat.messages() // Signal<BaseMessage[]>
chat.status() // Signal<'idle' | 'loading' | 'resolved' | 'error'>
chat.error() // Signal<Error | null>
chat.interrupt() // Signal<Interrupt | undefined>
chat.history() // Signal<ThreadState[]>
```

## What you can build
No RxJS. No manual subscriptions. No async pipes. Just Signals that work with Angular's `OnPush` change detection out of the box.

## The Architecture

StreamResource sits between your Angular app and LangGraph Platform:

<Steps>
<Step title="Your Angular app calls streamResource()">
Creates a reactive resource bound to a specific agent. All state is exposed as Signals.
</Step>
<Step title="FetchStreamTransport opens an SSE connection">
Sends HTTP POST to LangGraph Platform, receives Server-Sent Events with state updates.
</Step>
<Step title="LangGraph Platform runs your agent graph">
Executes nodes, calls tools, manages checkpoints. Streams results back in real-time.
</Step>
<Step title="Signals update your templates automatically">
As tokens arrive, `messages()` updates. Angular re-renders only the affected components.
</Step>
</Steps>

## Build Your Agent

LangGraph agents are Python programs defined as directed graphs. Here's a minimal chat agent using the example from this repository:

<Tabs items={['agent.py', 'langgraph.json']}>
<Tab>

```python
# examples/chat-agent/src/chat_agent/agent.py
from langchain_core.messages import SystemMessage
from langchain_core.runnables import RunnableConfig
from langgraph.graph import END, START, MessagesState, StateGraph
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

def call_model(state: MessagesState, config: RunnableConfig) -> dict:
"""Invoke the LLM with the current message history."""
system_prompt = config.get("configurable", {}).get(
"system_prompt", "You are a helpful assistant."
)
messages = [SystemMessage(content=system_prompt)] + state["messages"]
response = llm.invoke(messages)
return {"messages": [response]}

# Build the graph: START -> call_model -> END
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_edge(START, "call_model")
builder.add_edge("call_model", END)

graph = builder.compile()
```

</Tab>
<Tab>

```json
{
"dependencies": ["."],
"graphs": {
"chat_agent": "./src/chat_agent/agent.py:graph"
},
"env": ".env",
"python_version": "3.12"
}
```

</Tab>
</Tabs>

<Callout type="tip" title="What's happening here?">
`MessagesState` manages a list of messages. The `call_model` node takes the current messages, adds a system prompt, and calls the LLM. The graph runs this single node and returns the response. LangGraph handles streaming, checkpointing, and thread management automatically.
</Callout>

## Run Your Agent Locally

<Steps>
<Step title="Streaming chat interfaces">
Token-by-token streaming with real-time UI updates. Messages arrive as they're generated.
<Step title="Install the LangGraph CLI">

```bash
pip install -U "langgraph-cli[inmem]"
```

</Step>
<Step title="Set up your environment">

Create a `.env` file with your API keys:

```bash
OPENAI_API_KEY=sk-...
LANGSMITH_API_KEY=lsv2_...
```

</Step>
<Step title="Start the dev server">

```bash
cd examples/chat-agent
langgraph dev
```

Your agent is now running at `http://localhost:2024`. You can test it in LangGraph Studio at `https://smith.langchain.com/studio/`.

</Step>
</Steps>

## Connect with Angular

Now connect your Angular app to the running agent using streamResource().

<Steps>
<Step title="Install the package">

```bash
npm install @cacheplane/stream-resource
```

</Step>
<Step title="Configure the provider">

```typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideStreamResource } from '@cacheplane/stream-resource';

export const appConfig: ApplicationConfig = {
providers: [
provideStreamResource({
apiUrl: 'http://localhost:2024',
}),
],
};
```

</Step>
<Step title="Human-in-the-loop workflows">
Agents pause for approval, confirmation, or correction. Your UI handles the interrupt and resumes execution.
<Step title="Build your chat component">

<Tabs items={['TypeScript', 'Template']}>
<Tab>

```typescript
// chat.component.ts
import { Component, signal, computed } from '@angular/core';
import { streamResource } from '@cacheplane/stream-resource';
import type { BaseMessage } from '@langchain/core/messages';

@Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChatComponent {
input = signal('');

// Create the streaming resource — this is the core API
chat = streamResource<{ messages: BaseMessage[] }>({
assistantId: 'chat_agent',
threadId: signal(localStorage.getItem('threadId')),
onThreadId: (id) => localStorage.setItem('threadId', id),
});

// Derived signals — compose with computed()
isStreaming = computed(() => this.chat.status() === 'loading');
messageCount = computed(() => this.chat.messages().length);

send() {
const msg = this.input();
if (!msg.trim()) return;
this.chat.submit({
messages: [{ role: 'user', content: msg }],
});
this.input.set('');
}
}
```

</Tab>
<Tab>

```html
<!-- chat.component.html -->
<div class="chat-container">
<!-- Message list — updates token-by-token -->
@for (msg of chat.messages(); track $index) {
<div [class]="'message ' + msg.role">
<p>{{ msg.content }}</p>
</div>
}

<!-- Streaming indicator -->
@if (isStreaming()) {
<div class="typing">Agent is thinking...</div>
}

<!-- Error display -->
@if (chat.error(); as err) {
<div class="error">{{ err.message }}</div>
}

<!-- Input form -->
<form (submit)="send(); $event.preventDefault()">
<input
[ngModel]="input()"
(ngModelChange)="input.set($event)"
placeholder="Type a message..."
/>
<button type="submit" [disabled]="isStreaming()">
Send
</button>
</form>
</div>
```

</Tab>
</Tabs>

</Step>
<Step title="Multi-agent dashboards">
Track multiple subagents working in parallel, each with their own message stream and status.
<Step title="Run your Angular app">

```bash
ng serve
```

Open `http://localhost:4200` and start chatting with your agent. Messages stream in real-time as the LLM generates them.

</Step>
<Step title="Time-travel debugging tools">
Inspect agent execution history, fork from checkpoints, and explore alternate paths.
</Steps>

## Key Concepts

Here's what streamResource() gives you out of the box:

| Feature | Signal | Description |
|---------|--------|-------------|
| **Messages** | `chat.messages()` | Live message list, updates as tokens arrive |
| **Status** | `chat.status()` | Current state: idle, loading, resolved, error |
| **Thread persistence** | `threadId` option | Conversations survive page refreshes |
| **Interrupts** | `chat.interrupt()` | Agent pauses for human input |
| **History** | `chat.history()` | Full checkpoint timeline for time-travel |
| **Subagents** | `chat.subagents()` | Track delegated agent work |
| **Tool calls** | `chat.toolCalls()` | See what tools the agent is using |

## Deploy to Production

When you're ready to go live, deploy your agent to LangGraph Cloud.

<Steps>
<Step title="Push your agent to GitHub">

Your agent code (the Python project with `langgraph.json`) needs to be in a GitHub repository.

</Step>
<Step title="Deploy via LangSmith">

Go to [LangSmith Deployments](https://smith.langchain.com) and click **+ New Deployment**. Connect your GitHub repo and deploy. This takes about 15 minutes.

</Step>
<Step title="Update your Angular config">

Point `apiUrl` to your deployment URL:

```typescript
provideStreamResource({
apiUrl: 'https://your-deployment.langsmith.dev',
})
```

</Step>
</Steps>

## Guides
<Callout type="info" title="Stateless frontend">
Your Angular app is a stateless client. All agent state lives on LangGraph Platform. This means you can deploy your Angular app anywhere — CDN, edge, SSR — without state management concerns.
</Callout>

## What's Next

<CardGroup cols={2}>
<Card title="Quick Start" href="/docs/getting-started/quickstart">
Build a chat component in 5 minutes
</Card>
<Card title="Installation" href="/docs/getting-started/installation">
Detailed setup and configuration
Detailed 5-minute walkthrough with a complete chat component
</Card>
<Card title="Streaming" href="/docs/guides/streaming">
Token-by-token updates via SSE
Token-by-token updates, stream modes, and status tracking
</Card>
<Card title="Persistence" href="/docs/guides/persistence">
Thread persistence across sessions
Thread persistence across sessions and reactive thread switching
</Card>
<Card title="Interrupts" href="/docs/guides/interrupts">
Human-in-the-loop approval flows
Human-in-the-loop approval and confirmation flows
</Card>
<Card title="Testing" href="/docs/guides/testing">
Deterministic testing with MockStreamTransport
</Card>
<Card title="Angular Signals" href="/docs/concepts/angular-signals">
Deep dive into how Signals power streamResource
</Card>
<Card title="LangGraph Basics" href="/docs/concepts/langgraph-basics">
Graphs, nodes, edges, and state for Angular developers
</Card>
<Card title="API Reference" href="/docs/api/stream-resource">
Complete streamResource() function reference
</Card>
</CardGroup>
8 changes: 6 additions & 2 deletions apps/website/src/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DocsSearch } from '../../../components/docs/DocsSearch';
import { getDocBySlug, getAllDocSlugs } from '../../../lib/docs-new';
import { ApiDocRenderer, type ApiDocEntry } from '../../../components/docs/ApiDocRenderer';
import { DocsTOC } from '../../../components/docs/DocsTOC';
import { DocsMobileNav } from '../../../components/docs/DocsMobileNav';
import { extractHeadings } from '../../../lib/extract-headings';
import fs from 'fs';
import path from 'path';
Expand Down Expand Up @@ -43,11 +44,14 @@ export default async function DocsPage({ params }: { params: Promise<{ slug?: st
if (!doc) notFound();

return (
<div className="flex min-h-screen pt-16" style={{ background: 'var(--gradient-bg-flow)' }}>
<div className="flex min-h-screen pt-16 overflow-x-hidden" style={{ background: 'var(--gradient-bg-flow)' }}>
<DocsSearch />
<DocsSidebarNew activeSection={section} activeSlug={slug} />
<div className="flex-1 flex" style={{ background: 'rgba(255, 255, 255, 0.85)' }}>
<div className="flex-1 flex min-w-0" style={{ background: 'rgba(255, 255, 255, 0.85)' }}>
<div className="flex-1 min-w-0">
<div className="px-4 pt-4 sm:hidden">
<DocsMobileNav activeSection={section} activeSlug={slug} />
</div>
<MdxRendererNew source={doc.content} section={section} slug={slug} title={doc.title} />
{section === 'api' && (() => {
const entries = loadApiDocs();
Expand Down
1 change: 1 addition & 0 deletions apps/website/src/app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ html {
font-weight: 400;
}

.docs-prose { overflow-wrap: break-word; word-break: break-word; }
.docs-prose h1 { font-size: 1.875rem; font-weight: 700; margin-top: 0; margin-bottom: 1rem; font-family: var(--font-garamond); }
.docs-prose h2 { font-size: 1.5rem; font-weight: 600; margin-top: 2.5rem; margin-bottom: 1rem; font-family: var(--font-garamond); }
.docs-prose h3 { font-size: 1.25rem; font-weight: 600; margin-top: 2rem; margin-bottom: 0.75rem; font-family: var(--font-garamond); }
Expand Down
Loading