From d1532892666ddc997b7cc796845b364d48d02377 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sun, 7 Jun 2026 16:46:47 -0700 Subject: [PATCH 1/3] docs(langgraph): voice pass on guides (lifecycle/streaming/subgraphs/time-travel/persistence) --- apps/website/content/docs/langgraph/guides/lifecycle.mdx | 4 ++-- .../website/content/docs/langgraph/guides/persistence.mdx | 8 ++++---- apps/website/content/docs/langgraph/guides/streaming.mdx | 8 +++++--- apps/website/content/docs/langgraph/guides/subgraphs.mdx | 4 ++-- .../website/content/docs/langgraph/guides/time-travel.mdx | 4 ++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/website/content/docs/langgraph/guides/lifecycle.mdx b/apps/website/content/docs/langgraph/guides/lifecycle.mdx index 9e72ab2d..76587b29 100644 --- a/apps/website/content/docs/langgraph/guides/lifecycle.mdx +++ b/apps/website/content/docs/langgraph/guides/lifecycle.mdx @@ -1,6 +1,6 @@ # Agent Lifecycle Signals -The `@threadplane/langgraph` library exposes per-agent lifecycle signals on every `LangGraphAgent` returned by `injectAgent()`. These are timestamps and classifications derived from the existing stream — useful for debugging, custom dashboards, or telemetry integrations. +The `@threadplane/langgraph` library exposes per-agent lifecycle signals on every `LangGraphAgent` returned by `injectAgent()`. They're timestamps and classifications derived from the stream you already have — handy for debugging, custom dashboards, or telemetry integrations. ## Interface @@ -70,7 +70,7 @@ export class MyComponent { } ``` -For app-wide instrumentation, provide `AgentLifecycleRegistry` and read the lifecycles registered by agents created in that injection context: +For app-wide instrumentation, provide `AgentLifecycleRegistry` and read back the lifecycles registered by agents created in that injection context: ```typescript import { ApplicationConfig, inject } from '@angular/core'; diff --git a/apps/website/content/docs/langgraph/guides/persistence.mdx b/apps/website/content/docs/langgraph/guides/persistence.mdx index a19b4ed3..d7a29f6d 100644 --- a/apps/website/content/docs/langgraph/guides/persistence.mdx +++ b/apps/website/content/docs/langgraph/guides/persistence.mdx @@ -12,7 +12,7 @@ LangGraph checkpoints agent state at every super-step. Each checkpoint is keyed ## Python: Checkpointer Setup -Every LangGraph agent needs a checkpointer to persist state between invocations. The checkpointer you choose depends on your environment. +Every LangGraph agent needs a checkpointer to persist state between invocations. Which one you choose depends on your environment. @@ -172,7 +172,7 @@ export class ChatComponent { ## Angular: Thread-List Component -A real chat application needs a sidebar showing all conversations. Here is a full thread-list component that manages multiple threads alongside your chat singleton. The active-thread signal is held in shared state and wired into `provideAgent({...})` at bootstrap; the component reads back through `injectAgent()`. +A real chat application needs a sidebar showing all conversations. Here's a full thread-list component that manages multiple threads alongside your chat singleton. The active-thread signal lives in shared state and is wired into `provideAgent({...})` at bootstrap; the component reads back through `injectAgent()`. @@ -322,7 +322,7 @@ Use the `isThreadLoading()` signal to show a skeleton UI while `injectAgent()` f ## Manual Thread Switching -Use `switchThread()` for imperative thread changes. This is useful when you want to explicitly control when the switch happens — for example, after an animation completes or a modal closes. +Use `switchThread()` for imperative thread changes. It's useful when you want to control exactly when the switch happens — for example, after an animation completes or a modal closes. ```typescript // Start a fresh conversation (null = new thread on next submit) @@ -346,7 +346,7 @@ forkConversation() { ## Checkpoint Recovery -When a connection drops mid-stream, `joinStream()` reconnects to an in-progress run without restarting the agent. This prevents duplicate work and lost tokens. +When a connection drops mid-stream, `joinStream()` reconnects to an in-progress run without restarting the agent. That prevents duplicate work and lost tokens. ```typescript // Rejoin a running stream after a network interruption diff --git a/apps/website/content/docs/langgraph/guides/streaming.mdx b/apps/website/content/docs/langgraph/guides/streaming.mdx index b5686d73..32fe23e7 100644 --- a/apps/website/content/docs/langgraph/guides/streaming.mdx +++ b/apps/website/content/docs/langgraph/guides/streaming.mdx @@ -1,6 +1,6 @@ # Streaming -Agent provides token-by-token streaming from LangGraph agents via Server-Sent Events (SSE). Every update lands directly in Angular Signals — no subscriptions, no manual change detection. +Agent streams token-by-token from LangGraph agents over Server-Sent Events (SSE). Every update lands directly in Angular Signals — no subscriptions, no manual change detection. Make sure you've completed the Installation guide first. @@ -118,7 +118,7 @@ The connection was interrupted or the agent returned an error. Inspect `error()` By default, `injectAgent()` asks LangGraph Platform for the stream modes it needs to populate its public signals: `values`, `messages-tuple`, `updates`, and `custom`. It also enables `streamSubgraphs` so namespaced subgraph events can reach the client. -Override `streamMode` per run when you need a narrower stream. `streamMode` is a submit option, not a `provideAgent()` option. +Override `streamMode` per run when you need a narrower stream. It's a submit option, not a `provideAgent()` option. @@ -173,7 +173,7 @@ Use the default modes for most chat UIs. They keep `messages()`, `state()`, `too ## Error handling -If the SSE connection drops or the agent throws, `status()` transitions to `'error'` and `error()` is populated. Use these signals to render fallback UI and retry. +If the SSE connection drops or the agent throws, `status()` flips to `'error'` and `error()` is populated. Use these signals to render a fallback UI and retry. @@ -234,6 +234,8 @@ provideAgent({ The value is in milliseconds. Pass `false` or `0` to disable batching and forward state updates immediately. Token message updates are not throttled, so live markdown and typing indicators still receive every token emission. +For me, the 16 ms default is the right starting point — it tracks a 60 fps render and you'll rarely feel it. The tradeoff of raising it is straightforward: a larger window costs you a touch of perceived latency on state signals to save renders, so only reach for it when profiling shows state updates are the bottleneck. + | Use case | Recommended throttle | |---|---| | Token-by-token typing effect | default 16 ms | diff --git a/apps/website/content/docs/langgraph/guides/subgraphs.mdx b/apps/website/content/docs/langgraph/guides/subgraphs.mdx index f1d9c592..0a41433c 100644 --- a/apps/website/content/docs/langgraph/guides/subgraphs.mdx +++ b/apps/website/content/docs/langgraph/guides/subgraphs.mdx @@ -1,6 +1,6 @@ # Subgraphs -Subgraphs let you compose complex agents from smaller, focused units. `injectAgent()` streams their output through the same message, state, tool-call, and custom-event signals as the parent graph. +Subgraphs let you compose larger agents from smaller, focused units. `injectAgent()` streams their output through the same message, state, tool-call, and custom-event signals as the parent graph. LangGraph subgraphs are graph nodes. Deep Agents-style subagents are delegated tool calls. `injectAgent()` requests subgraph streams by default, but the `subagents()` signal is populated only for tool calls whose names match `subagentToolNames` and whose args include a `subagent_type`. @@ -157,7 +157,7 @@ const researchMessages = computed(() => researchAgent()?.messages() ?? []); ## Orchestrator pattern -The orchestrator pattern delegates specialised work to subagents and merges their results. Each subagent runs its own graph independently while the parent coordinates. +The orchestrator pattern delegates specialised work to subagents and merges their results. Each subagent runs its own graph independently while the parent coordinates the whole. ```typescript // Configure in app.config.ts: diff --git a/apps/website/content/docs/langgraph/guides/time-travel.mdx b/apps/website/content/docs/langgraph/guides/time-travel.mdx index 9903d127..47da2a4c 100644 --- a/apps/website/content/docs/langgraph/guides/time-travel.mdx +++ b/apps/website/content/docs/langgraph/guides/time-travel.mdx @@ -123,7 +123,7 @@ Each runtime-neutral checkpoint exposes `id`, `label`, and `values`. Each raw `T ## Forking from a checkpoint -Submit with a specific checkpoint to branch execution from an earlier state. This creates a new branch in the thread graph while leaving the original path intact. +Submit with a specific checkpoint to branch execution from an earlier state. That creates a new branch in the thread graph while leaving the original path intact. ```typescript forkFromCheckpoint(index: number) { @@ -242,7 +242,7 @@ compareCheckpoints(indexA: number, indexB: number) { } ``` -Use the comparison result to render a diff view, highlight changed fields in your UI, or log what the agent modified during a specific step. +Use the comparison result to render a diff view, highlight changed fields in your UI, or log what the agent touched during a specific step. ## Replaying with modified input From 14805b872d3b5d774cd8d0d39b61fffddcc5286f Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sun, 7 Jun 2026 16:54:58 -0700 Subject: [PATCH 2/3] docs(langgraph): voice pass on guides (deployment/memory/interrupts/testing) --- apps/website/content/docs/langgraph/guides/deployment.mdx | 6 +++++- apps/website/content/docs/langgraph/guides/interrupts.mdx | 8 +++++--- apps/website/content/docs/langgraph/guides/memory.mdx | 6 ++++-- apps/website/content/docs/langgraph/guides/testing.mdx | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/website/content/docs/langgraph/guides/deployment.mdx b/apps/website/content/docs/langgraph/guides/deployment.mdx index 0fefcbc4..7ec2a89c 100644 --- a/apps/website/content/docs/langgraph/guides/deployment.mdx +++ b/apps/website/content/docs/langgraph/guides/deployment.mdx @@ -6,6 +6,8 @@ Deploy your LangGraph agent to the cloud and ship your Angular frontend to produ Your agent code needs a `langgraph.json` manifest at the project root. This file tells LangGraph Cloud how to build and serve your agent. +Let's start there. + ```json { "dependencies": ["."], @@ -128,6 +130,8 @@ Do not ship LangSmith or LangGraph API keys in an Angular bundle. The default `F For production, put a same-origin backend route, edge function, or API gateway in front of LangGraph. The browser calls your relative URL, and that server-side layer adds the deployment credentials. +For me, the same-origin proxy is worth the extra hop. You give up the simplicity of pointing Angular straight at the deployment, but your keys never leave the server, and HTTP-only cookies just work. + ```typescript // environment.prod.ts export const environment = { @@ -183,7 +187,7 @@ During local development with `langgraph dev`, CORS is permissive by default. Yo ## Error boundaries -Production apps need graceful error handling. Build a reactive error boundary using `injectAgent()` signals. +Production apps need graceful error handling. Let's build a reactive error boundary using `injectAgent()` signals. ```typescript import { ChangeDetectionStrategy, Component, computed } from '@angular/core'; diff --git a/apps/website/content/docs/langgraph/guides/interrupts.mdx b/apps/website/content/docs/langgraph/guides/interrupts.mdx index 53a01347..1f741709 100644 --- a/apps/website/content/docs/langgraph/guides/interrupts.mdx +++ b/apps/website/content/docs/langgraph/guides/interrupts.mdx @@ -8,7 +8,7 @@ Use interrupts when an agent action is irreversible (sending an email, placing a ## The Interrupt Lifecycle -Before diving into code, understand the five-stage lifecycle that every interrupt follows: +Before diving into code, let's walk the five-stage lifecycle that every interrupt follows: @@ -276,7 +276,7 @@ export class ApprovalComponent { ## Multi-Step Approval Pattern -Some workflows require multiple approvals in sequence. For example, an agent that plans a multi-step deployment might need approval at each stage. Each node in the graph can raise its own interrupt. +Some workflows need multiple approvals in sequence. An agent that plans a multi-step deployment might need a sign-off at each stage. Each node in the graph can raise its own interrupt. @@ -496,7 +496,9 @@ Define your interrupt payload interfaces alongside your Python state schema. Thi ## Timeout Handling -Interrupts pause graph execution indefinitely by default — the agent waits until a human responds. In production, you often need to handle cases where no one responds within a reasonable time. There are two strategies for managing interrupt timeouts. +Interrupts pause graph execution indefinitely by default — the agent waits until a human responds. In production, you often need to handle the case where no one responds within a reasonable time. There are two strategies for managing interrupt timeouts. + +For me, the server-side timeout is the safer default. It costs you a background job to run and maintain, but it fires even if the user closed the tab — which is exactly when you most need it to. **Server-side timeout with a background task:** Schedule a background job that checks for stale interrupts and resumes them with a default decision. diff --git a/apps/website/content/docs/langgraph/guides/memory.mdx b/apps/website/content/docs/langgraph/guides/memory.mdx index 53f878b8..246ca081 100644 --- a/apps/website/content/docs/langgraph/guides/memory.mdx +++ b/apps/website/content/docs/langgraph/guides/memory.mdx @@ -166,6 +166,8 @@ When `update_memory` returns `user_preferences`, the dict is merged into the exi Short-term memory is the simplest form: the conversation history and any accumulated state fields within a single thread. Every message, tool call, and state update is automatically checkpointed. When a user reconnects with the same `threadId`, the full history is restored. +Let's see it in Python first, then on the Angular side. + ```python from langgraph.checkpoint.postgres import PostgresSaver @@ -331,7 +333,7 @@ The checkpointer saves thread state (short-term memory). The Store saves cross-t ## Semantic Memory with Vector Search -For agents that accumulate hundreds or thousands of memories, keyword matching is not enough. The Store API supports semantic search with embeddings, so your agent can retrieve the most relevant memories for any given context. +For agents that accumulate hundreds or thousands of memories, keyword matching isn't enough. The Store API supports semantic search with embeddings, so your agent can retrieve the most relevant memories for any given context. ```python from langchain_openai import OpenAIEmbeddings @@ -372,7 +374,7 @@ Semantic search requires an embedding model configured on the Store. LangGraph P ## Surfacing Memory in Angular with value() -The `value()` signal is the primary way memory surfaces in your Angular components. It contains the full agent state object, including all custom memory fields. Because it is a Signal, your template re-renders automatically through OnPush change detection whenever the agent state changes. +The `value()` signal is the primary way memory surfaces in your Angular components. It contains the full agent state object, including all custom memory fields. Because it's a Signal, your template re-renders automatically through OnPush change detection whenever the agent state changes. ```typescript // The value() signal contains everything the agent knows diff --git a/apps/website/content/docs/langgraph/guides/testing.mdx b/apps/website/content/docs/langgraph/guides/testing.mdx index 3cd74ae2..6d2d8037 100644 --- a/apps/website/content/docs/langgraph/guides/testing.mdx +++ b/apps/website/content/docs/langgraph/guides/testing.mdx @@ -220,7 +220,7 @@ TestBed.runInInjectionContext(() => { ## Testing the Streaming Lifecycle -The most common test pattern verifies the full submit-to-idle lifecycle: submit sets the agent running, values arrive, and the status settles back to idle. +The most common test pattern verifies the full submit-to-idle lifecycle: submit sets the agent running, values arrive, and the status settles back to idle. Let's walk it end to end. @@ -601,7 +601,7 @@ Read signals like `chat.messages()`, `chat.status()`, `chat.interrupt()`, and `c ## Integration Testing -For end-to-end confidence, run tests against a real LangGraph dev server. The LangGraph CLI starts a local server that your tests can hit directly. +For end-to-end confidence, run tests against a real LangGraph dev server. The LangGraph CLI starts a local server your tests can hit directly. ```bash # Start the dev server From c841607c1db3e1bc9ca0df3767844155380061ed Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sun, 7 Jun 2026 17:00:57 -0700 Subject: [PATCH 3/3] docs(langgraph): voice pass on concepts --- .../langgraph/concepts/agent-architecture.mdx | 10 +++++----- .../langgraph/concepts/agent-contract.mdx | 20 +++++++++---------- .../langgraph/concepts/angular-signals.mdx | 8 ++++---- .../langgraph/concepts/langgraph-basics.mdx | 6 +++--- .../langgraph/concepts/state-management.mdx | 6 +++--- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/website/content/docs/langgraph/concepts/agent-architecture.mdx b/apps/website/content/docs/langgraph/concepts/agent-architecture.mdx index c2cf8b62..e94891c8 100644 --- a/apps/website/content/docs/langgraph/concepts/agent-architecture.mdx +++ b/apps/website/content/docs/langgraph/concepts/agent-architecture.mdx @@ -1,6 +1,6 @@ # Agent Architecture -How AI agents work — the planning, execution, and tool-calling lifecycle that `injectAgent()` connects your Angular app to. This page shows you the Python patterns that power modern agents and exactly how each pattern surfaces in Angular through `@threadplane/langgraph`. +How AI agents work — the planning, execution, and tool-calling lifecycle that `injectAgent()` connects your Angular app to. Let's walk the Python patterns behind modern agents and see exactly how each one surfaces in Angular through `@threadplane/langgraph`. Every section below shows the Python backend code first, then the Angular frontend code that consumes it. You need both halves to build a production agent application — LangGraph handles the intelligence, `injectAgent()` handles the reactivity. @@ -8,7 +8,7 @@ Every section below shows the Python backend code first, then the Angular fronte ## The Agent Loop -Every agent follows a five-phase cycle. Understanding this cycle is critical because each phase maps to a specific `injectAgent()` signal in your Angular app. +Every agent follows a five-phase cycle. It's worth understanding, because each phase maps to a specific `injectAgent()` signal in your Angular app. @@ -194,11 +194,11 @@ export class ReactAgentComponent { -The key insight: `should_continue` is the decision point. If the LLM's response contains `tool_calls`, the graph routes to the `tools` node. If not, it ends. After tools execute, the graph loops back to `model` so the LLM can reason about the tool results. This loop continues until the LLM responds without requesting any tools. +Here's the key insight: `should_continue` is the decision point. If the LLM's response contains `tool_calls`, the graph routes to the `tools` node. If not, it ends. After tools execute, the graph loops back to `model` so the LLM can reason about the tool results. This loop continues until the LLM responds without requesting any tools. ## Tool Calling Deep Dive -Tools are how agents interact with the outside world. Understanding both the Python definition and the Angular consumption is essential. +Tools are how agents interact with the outside world. You'll want both halves here — the Python definition and the Angular consumption. ### Defining Tools in Python @@ -611,7 +611,7 @@ When you submit from a previous checkpoint, LangGraph creates a new branch from ## Choosing an Architecture -Not every application needs a multi-agent swarm. Here is a decision guide for picking the right level of complexity. +Not every application needs a multi-agent swarm. Here's how I'd pick the right level of complexity — and why simpler usually wins until it can't. ### Single Agent with Tools diff --git a/apps/website/content/docs/langgraph/concepts/agent-contract.mdx b/apps/website/content/docs/langgraph/concepts/agent-contract.mdx index afa9bb6a..787ba9c1 100644 --- a/apps/website/content/docs/langgraph/concepts/agent-contract.mdx +++ b/apps/website/content/docs/langgraph/concepts/agent-contract.mdx @@ -4,7 +4,7 @@ The `Agent` contract is the spine between runtime adapters and chat UI. `@threadplane/chat` owns the contract. `@threadplane/langgraph` and `@threadplane/ag-ui` produce objects that satisfy it. Chat primitives and compositions consume it without knowing which runtime is behind the stream. -This matters because the UI should not care whether a response came from LangGraph Platform, AG-UI, a local mock, or a custom HTTP service. The boundary is explicit: adapters translate runtime events into Angular signals and a small action surface. +The UI shouldn't care whether a response came from LangGraph Platform, AG-UI, a local mock, or a custom HTTP service. That's the point. The boundary is explicit: adapters translate runtime events into Angular signals and a small action surface. ```text LangGraph Platform -- @threadplane/langgraph --+ @@ -61,7 +61,7 @@ await agent.submit({ The input can carry a new user message, an interrupt resume payload, a state patch, or a combination. The adapter decides how that maps to the backend. -This matters because chat UI can send user intent without learning backend protocol details. LangGraph can turn `resume` into a command. An AG-UI adapter can call `runAgent()`. A test mock can just record the call. +So chat UI sends user intent without learning a single backend protocol detail. LangGraph turns `resume` into a command. An AG-UI adapter calls `runAgent()`. A test mock just records the call. The second argument is intentionally small at the contract layer: @@ -88,7 +88,7 @@ Signals are the stable read model. | `interrupt?.()` | Current human-in-the-loop pause, if supported. | | `subagents?.()` | Delegated work keyed by tool-call id, if supported. | -The optional signals are important. A simple echo adapter should not fake interrupts or subagents. Components that need those concepts feature-detect the signal and render a neutral fallback when it is absent. +The optional signals matter. A simple echo adapter shouldn't fake interrupts or subagents. Components that need those concepts feature-detect the signal and render a neutral fallback when it's absent. ## Events @@ -108,7 +108,7 @@ Current event variants are deliberately narrow: | `state_update` | Sync state intended for render/generative UI stores. | | `custom` | Runtime-specific escape hatch with `name` and `data`. | -Do not mirror `messages`, `status`, `toolCalls`, `interrupt`, or `subagents` through `events$`. Put those on signals. Duplicating state creates ordering bugs and makes components guess which source wins. +Don't mirror `messages`, `status`, `toolCalls`, `interrupt`, or `subagents` through `events$`. Put those on signals. Duplicating state creates ordering bugs and makes components guess which source wins. ## Adapters And Transports @@ -124,7 +124,7 @@ Do not mirror `messages`, `status`, `toolCalls`, `interrupt`, or `subagents` thr ## Lifecycle -The UI lifecycle is intentionally boring. +The UI lifecycle is intentionally boring — and boring is the goal. 1. User input calls `submit({ message })`. 2. Adapter marks the run active through `status()` and `isLoading()`. @@ -154,16 +154,16 @@ For LangGraph-specific code, use `mockLangGraphAgent()` or `MockAgentTransport` For AG-UI integration, use `FakeAgent` or `provideFakeAgent()` from `@threadplane/ag-ui`. -This matters because the contract is the seam you can test cheaply. Most component tests should not need a network, LangGraph server, or AG-UI runtime. +The contract is the seam you can test cheaply. Most component tests shouldn't need a network, a LangGraph server, or an AG-UI runtime. ## What It Is Not -The `Agent` contract is not a backend protocol. It does not define SSE frames, AG-UI event names, LangGraph thread state, or tool execution semantics. +The `Agent` contract is not a backend protocol. It doesn't define SSE frames, AG-UI event names, LangGraph thread state, or tool execution semantics. -It is not a message database. Persistence belongs to the runtime or application state, then gets projected back through signals. +It's not a message database. Persistence belongs to the runtime or application state, then gets projected back through signals. -It is not a full orchestration API. LangGraph-specific operations such as branch selection, queued runs, checkpoint history, and raw SDK messages stay on `LangGraphAgent`. +It's not a full orchestration API. LangGraph-specific operations such as branch selection, queued runs, checkpoint history, and raw SDK messages stay on `LangGraphAgent`. -It is not a UI renderer. Rendering belongs to `@threadplane/chat`, `@threadplane/render`, and A2UI surfaces. The agent only exposes the state and events those renderers need. +It's not a UI renderer. Rendering belongs to `@threadplane/chat`, `@threadplane/render`, and A2UI surfaces. The agent only exposes the state and events those renderers need. Keep that boundary sharp. It makes adapters replaceable, tests smaller, and chat components more predictable. diff --git a/apps/website/content/docs/langgraph/concepts/angular-signals.mdx b/apps/website/content/docs/langgraph/concepts/angular-signals.mdx index 3cc0e780..f2138b17 100644 --- a/apps/website/content/docs/langgraph/concepts/angular-signals.mdx +++ b/apps/website/content/docs/langgraph/concepts/angular-signals.mdx @@ -1,6 +1,6 @@ # Angular Signals -Angular Signals are the reactive primitive that powers `injectAgent()`. If you're coming from a Python AI/agent background and wondering how Angular handles real-time streaming data, this page is your guide. Every property on a LangGraphAgent is a Signal, which means your templates update automatically as tokens arrive — no manual subscriptions, no async pipes, no RxJS boilerplate. +Angular Signals are the reactive primitive that powers `injectAgent()`. If you're coming from a Python AI/agent background and wondering how Angular handles real-time streaming data, you're in the right place. Every property on a LangGraphAgent is a Signal, so your templates update automatically as tokens arrive — no manual subscriptions, no async pipes, no RxJS boilerplate. Think of Signals like a Python property with built-in change notification. When the value changes, every consumer — templates, computed values, effects — re-evaluates automatically. If you've used Pydantic models with validators that react to field changes, Signals are the Angular equivalent but deeply integrated into the rendering engine. @@ -28,7 +28,7 @@ const doubled = computed(() => count() * 2); console.log(doubled()); // 4 ``` -The key insight: Angular knows which Signals a template reads. When those Signals change, Angular re-renders only the affected parts of the DOM. No diffing the entire tree, no zone.js overhead. +Here's the key insight: Angular knows which Signals a template reads. When those Signals change, it re-renders only the affected parts of the DOM. No diffing the entire tree, no zone.js overhead. ## How `injectAgent` Uses Signals Internally @@ -400,7 +400,7 @@ With older Observable-based patterns, you had to call `ChangeDetectorRef.markFor ## Python Agent to Angular Signals -The real power of `injectAgent()` is how it pairs a Python LangGraph agent with Angular Signals. The agent defines the logic; Signals surface the results in real time. +Where `injectAgent()` really earns its keep is how it pairs a Python LangGraph agent with Angular Signals. The agent defines the logic; Signals surface the results in real time. @@ -501,7 +501,7 @@ When the Python agent calls `search_knowledge_base`, the tool call streams to An ## Performance: Signals vs Alternatives -High-frequency token streaming puts unique pressure on a frontend framework. Here's why Signals with OnPush outperform the alternatives. +High-frequency token streaming puts real pressure on a frontend framework. Here's why Signals with OnPush hold up better than the alternatives. | Approach | Token update cost | Memory overhead | Cleanup required | |---|---|---|---| diff --git a/apps/website/content/docs/langgraph/concepts/langgraph-basics.mdx b/apps/website/content/docs/langgraph/concepts/langgraph-basics.mdx index ed66a430..fa5f7e7b 100644 --- a/apps/website/content/docs/langgraph/concepts/langgraph-basics.mdx +++ b/apps/website/content/docs/langgraph/concepts/langgraph-basics.mdx @@ -1,6 +1,6 @@ # LangGraph Basics -LangGraph is a framework for building stateful AI agents as directed graphs. If you're an Angular developer building AI-powered applications, this page teaches you how LangGraph agents work and why `injectAgent()` is the natural bridge between your frontend and your agent backend. +LangGraph is a framework for building stateful AI agents as directed graphs. If you're an Angular developer building AI-powered applications, let's look at how LangGraph agents work and why `injectAgent()` is the natural bridge between your frontend and your agent backend. Graphs give you explicit control over agent behavior. Instead of a black-box prompt-and-pray approach, you define exactly how your agent reasons, when it calls tools, and where it pauses for human input. Every step is visible, testable, and debuggable. @@ -126,7 +126,7 @@ protected readonly chat = injectAgent(); ## Agent Patterns -The power of LangGraph is in the patterns you can build. Each pattern maps to specific `injectAgent()` signals. +LangGraph shines in the patterns you can build. Each one maps to specific `injectAgent()` signals. ### Pattern 1: ReAct Agent (Tool Calling) @@ -284,7 +284,7 @@ const chat = injectAgent(); ## How `injectAgent()` Bridges the Gap -Here's why `injectAgent()` is the natural Angular companion for LangGraph: +Here's why `injectAgent()` is the natural Angular companion for LangGraph. diff --git a/apps/website/content/docs/langgraph/concepts/state-management.mdx b/apps/website/content/docs/langgraph/concepts/state-management.mdx index 6e3541f3..f9050296 100644 --- a/apps/website/content/docs/langgraph/concepts/state-management.mdx +++ b/apps/website/content/docs/langgraph/concepts/state-management.mdx @@ -10,7 +10,7 @@ LangGraph Platform owns the state. Angular owns the view. `injectAgent()` is the In a traditional Angular app, state lives in an NgRx store or a signals-based service. In a LangGraph app, **the agent's state lives on the server** — in LangGraph Platform's checkpoint store. Your Angular app is a stateless view layer that reads state through signals as the agent streams it back. -This inversion is intentional. Agent state can span multiple LLM calls, tool executions, and human-in-the-loop interrupts. It needs to survive browser refreshes, reconnections, and even server deployments. A server-side checkpoint store handles all of that automatically. Your Angular app just calls `.submit()` and reads signals. +This inversion is intentional. Agent state can span multiple LLM calls, tool executions, and human-in-the-loop interrupts. It has to survive browser refreshes, reconnections, and even server deployments. A server-side checkpoint store handles all of that for you. Your Angular app just calls `.submit()` and reads signals. @@ -37,7 +37,7 @@ Components using `OnPush` re-render only when signal values change. No manual `d ## Python State Design -On the Python side, your agent's state is a `TypedDict`. The fields you define here are exactly what `agent()` exposes in TypeScript. Getting the Python state design right is the most important architectural decision in your agent. +On the Python side, your agent's state is a `TypedDict`. The fields you define here are exactly what `agent()` exposes in TypeScript. For me, getting the Python state design right is the most important architectural decision in your agent — everything downstream inherits its shape, so it's worth slowing down for. ### The TypedDict Pattern @@ -276,7 +276,7 @@ const score = computed(() => agent.value().analysis?.score ?? 0); ## Thread State vs Application State -There are two kinds of state in a LangGraph Angular app, and keeping them separate makes your code much easier to reason about. +There are two kinds of state in a LangGraph Angular app, and keeping them separate makes your code far easier to reason about. **Thread state** is owned by LangGraph Platform. You read it through `injectAgent()` signals. You never write to it directly — you only send new input via `.submit()`.