@threadplane/langgraph 0.0.47 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,28 @@
1
1
  # @threadplane/langgraph
2
2
 
3
- Adapter that wraps a LangGraph agent into the runtime-neutral `Agent` contract from `@threadplane/chat`. The Angular equivalent of LangGraph's React `useStream()` hook — signal-driven access to messages, status, tool calls, interrupts, subagents, regenerate, and thread history.
3
+ Adapter that wraps a LangGraph agent into the runtime-neutral `Agent` contract from `@threadplane/chat`. The Angular equivalent of LangGraph's React `useStream()` hook — signal-driven access to messages, status, tool calls, interrupts, subagents, branch history, and thread persistence.
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@threadplane/langgraph">
7
+ <img alt="npm version" src="https://img.shields.io/npm/v/@threadplane%2Flanggraph?color=6C8EFF&labelColor=080B14&style=flat-square" />
8
+ </a>
9
+ <a href="https://angular.dev">
10
+ <img alt="Angular 20+" src="https://img.shields.io/badge/Angular-20%2B%20%7C%2021-6C8EFF?labelColor=080B14&style=flat-square" />
11
+ </a>
12
+ <a href="https://opensource.org/licenses/MIT">
13
+ <img alt="MIT" src="https://img.shields.io/badge/License-MIT-6C8EFF?labelColor=080B14&style=flat-square" />
14
+ </a>
15
+ </p>
16
+
17
+ > Talking to a non-LangGraph backend? See [`@threadplane/ag-ui`](https://www.npmjs.com/package/@threadplane/ag-ui) — same API shape, AG-UI protocol underneath.
4
18
 
5
- Part of [Threadplane](https://github.com/cacheplane/angular-agent-framework). MIT licensed.
19
+ ## What it does
20
+
21
+ - **`provideAgent()`** — wire the LangGraph adapter into Angular DI. Provided at the root injector or at any component subtree (multi-thread UIs work via Angular's hierarchical DI).
22
+ - **`injectAgent()`** — retrieve the configured `LangGraphAgent` in any component. Returns a `LangGraphAgent` whose entire state surface (`messages`, `status`, `isLoading`, `error`, `interrupt`, `toolCalls`, `subagents`, `queue`, `branch`, `history`, and more) is exposed as Angular Signals. No subscriptions, no `async` pipe, no zone.js required.
23
+ - **Human-in-the-loop** — `interrupt()` delivers a runtime-neutral interrupt value; `langGraphInterrupts()` exposes the raw LangGraph interrupt list when you need it.
24
+ - **Subagent streaming** — `subagents()` + `getSubagent(toolCallId)`, `getSubagentsByType(type)`, `getSubagentsByMessage(msg)`, and `activeSubagents()` surface streaming subgraph state without extra bookkeeping.
25
+ - **Time-travel and thread persistence** — `branch()` / `history()` / `experimentalBranchTree()` enable checkpoint navigation; `LangGraphThreadsAdapter` provides SDK-backed thread CRUD so you never have to hand-roll thread management.
6
26
 
7
27
  ## Install
8
28
 
@@ -10,18 +30,20 @@ Part of [Threadplane](https://github.com/cacheplane/angular-agent-framework). MI
10
30
  npm install @threadplane/langgraph @threadplane/chat
11
31
  ```
12
32
 
13
- **Peer dependencies:** `@angular/core ^20.0.0 || ^21.0.0`, `@langchain/core ^1.1.0`, `@langchain/langgraph-sdk ^1.7.0`, `rxjs ~7.8.0`
14
-
15
- ## What it does
33
+ **Peer dependencies:**
16
34
 
17
- - **`agent()`** — Angular Signal-based handle to a LangGraph streaming run. Returns `messages()`, `status()`, `isLoading()`, `error()`, `interrupt()`, `toolCalls()`, plus actions (`submit`, `stop`, `regenerate`, `reload`).
18
- - **`provideAgent()`** — configure the LangGraph endpoint once in `app.config.ts`. Per-call overrides are accepted by `agent()` itself.
19
- - **Thread persistence** — pass `threadId: signal(...)` + `onThreadId` to round-trip thread IDs through your own storage (localStorage, URL, etc.).
20
- - **`MockAgentTransport`** — deterministic in-memory transport for tests. Never mock `agent()` itself; swap the transport instead.
21
- - **`extractCitations()`** — populates `Message.citations` from LangGraph message metadata. Reads from `additional_kwargs.citations` (preferred) or `additional_kwargs.sources` (fallback).
35
+ ```
36
+ @threadplane/chat *
37
+ @angular/core ^20.0.0 || ^21.0.0
38
+ @langchain/core ^1.1.33
39
+ @langchain/langgraph-sdk ^1.7.4
40
+ rxjs ~7.8.0
41
+ ```
22
42
 
23
43
  ## Quick start
24
44
 
45
+ Configure the LangGraph endpoint once in `app.config.ts`:
46
+
25
47
  ```ts
26
48
  // app.config.ts
27
49
  import { provideAgent } from '@threadplane/langgraph';
@@ -30,15 +52,18 @@ export const appConfig: ApplicationConfig = {
30
52
  providers: [
31
53
  provideAgent({
32
54
  apiUrl: 'https://your-langgraph-platform.com',
55
+ assistantId: 'my-agent',
33
56
  }),
34
57
  ],
35
58
  };
36
59
  ```
37
60
 
61
+ Then call `injectAgent()` in any component and pass the result to `<chat />`:
62
+
38
63
  ```ts
39
64
  // chat.component.ts
40
65
  import { Component } from '@angular/core';
41
- import { agent } from '@threadplane/langgraph';
66
+ import { injectAgent } from '@threadplane/langgraph';
42
67
  import { ChatComponent } from '@threadplane/chat';
43
68
 
44
69
  @Component({
@@ -46,47 +71,143 @@ import { ChatComponent } from '@threadplane/chat';
46
71
  template: `<chat [agent]="chat" />`,
47
72
  })
48
73
  export class ChatComponentHost {
49
- chat = agent({
50
- apiUrl: 'https://your-langgraph-platform.com',
51
- assistantId: 'my-agent',
52
- });
74
+ protected readonly chat = injectAgent();
53
75
  }
54
76
  ```
55
77
 
56
- > `agent()` must be called within an Angular injection context (component field initializer or constructor). Calling it in `ngOnInit` or any async context throws `NG0203: inject() must be called from an injection context`.
78
+ > `injectAgent()` must be called within an Angular injection context — a component field initializer or constructor. Calling it in `ngOnInit` or any async context throws `NG0203: inject() must be called from an injection context`.
57
79
 
58
- ## Citations example
80
+ > Need a different agent for a specific component subtree (e.g., a sidebar showing a separate conversation)? Re-provide `provideAgent({...})` in that component's `providers: []` array — Angular's hierarchical DI takes care of the rest.
81
+
82
+ ## Capabilities
83
+
84
+ ### Messages, status, and errors
85
+
86
+ | Signal | Type | Description |
87
+ |---|---|---|
88
+ | `messages()` | `Message[]` | Accumulated chat messages from the stream |
89
+ | `status()` | `'idle' \| 'running' \| 'error'` | Runtime-neutral run status |
90
+ | `isLoading()` | `boolean` | `true` while a run is streaming |
91
+ | `error()` | `unknown \| null` | Last error, if any |
92
+
93
+ ### Human-in-the-loop (interrupts)
59
94
 
60
95
  ```ts
61
- // In your LangGraph node:
62
- const response = await llm.invoke([...]);
63
-
64
- return new AIMessage({
65
- content: response.content,
66
- additional_kwargs: {
67
- citations: [
68
- {
69
- id: 'doc-1',
70
- index: 1,
71
- title: 'Example Article',
72
- url: 'https://example.com/article',
73
- snippet: 'Relevant excerpt...',
74
- },
75
- ],
76
- },
77
- });
78
-
79
- // Message.citations auto-populates in @threadplane/chat via extractCitations()
96
+ const pending = chat.interrupt(); // runtime-neutral interrupt value
97
+ const raw = chat.langGraphInterrupts(); // raw LangGraph Interrupt[]
80
98
  ```
81
99
 
100
+ Resume by calling `chat.submit(response)`.
101
+
102
+ ### Tool calls
103
+
104
+ `toolCalls()` is a Signal of all tool call entries observed in the current run, updated incrementally as the stream progresses.
105
+
106
+ ### Subagents
107
+
108
+ ```ts
109
+ chat.subagents() // Signal<Map<string, Subagent>> of all subagents
110
+ chat.activeSubagents() // currently streaming subagents (SubagentStreamRef[])
111
+ chat.getSubagent(toolCallId) // look up by tool call ID
112
+ chat.getSubagentsByType(type) // filter by subagent type
113
+ chat.getSubagentsByMessage(msg) // filter by parent message
114
+ ```
115
+
116
+ ### Queue
117
+
118
+ `queue()` exposes pending run entries when the agent is configured with a multitask strategy that queues concurrent submissions.
119
+
120
+ ### Branch, history, and time-travel
121
+
122
+ ```ts
123
+ chat.branch() // current branch identifier Signal
124
+ chat.setBranch(b) // switch to a checkpoint branch
125
+ chat.history() // runtime-neutral history entries
126
+ chat.langGraphHistory() // raw LangGraph ThreadState[]
127
+ chat.experimentalBranchTree() // full branching tree for time-travel UI
128
+ ```
129
+
130
+ ### Actions
131
+
132
+ ```ts
133
+ chat.submit(input, opts?) // send a new message
134
+ chat.stop() // cancel the active run
135
+ chat.regenerate(assistantMessageIndex) // re-run from a prior assistant turn
136
+ chat.reload() // re-run the last submission
137
+ chat.switchThread(threadId) // load a different thread
138
+ chat.joinStream(runId, lastEventId?) // reconnect to an in-flight run
139
+ ```
140
+
141
+ ### Thread persistence
142
+
143
+ `LangGraphThreadsAdapter` is a drop-in, SDK-backed thread store. Provide it alongside the agent config:
144
+
145
+ ```ts
146
+ import { provideAgent, LangGraphThreadsAdapter, LANGGRAPH_THREADS_CONFIG } from '@threadplane/langgraph';
147
+
148
+ export const appConfig: ApplicationConfig = {
149
+ providers: [
150
+ provideAgent({ apiUrl: 'https://your-langgraph-platform.com' }),
151
+ { provide: LANGGRAPH_THREADS_CONFIG, useValue: { apiUrl: 'https://your-langgraph-platform.com' } },
152
+ LangGraphThreadsAdapter,
153
+ ],
154
+ };
155
+ ```
156
+
157
+ Pair it with the lifecycle helpers to keep your thread list fresh:
158
+
159
+ ```ts
160
+ import { refreshOnRunEnd, refreshOnTransition } from '@threadplane/langgraph';
161
+
162
+ refreshOnRunEnd(chat, () => threadsAdapter.loadThreads());
163
+ ```
164
+
165
+ ### Citations
166
+
167
+ `extractCitations(msg)` reads citation metadata from a LangGraph message's `additional_kwargs`, returning `Citation[] | undefined` (`undefined` when no citation metadata is present). It checks `additional_kwargs.citations` first, falling back to `additional_kwargs.sources`.
168
+
169
+ ```ts
170
+ import { extractCitations } from '@threadplane/langgraph';
171
+
172
+ const citations = extractCitations(message);
173
+ ```
174
+
175
+ `Citation` is a type from `@threadplane/chat`; `CitationsResolverService` and `provideChat` also live there.
176
+
177
+ ## Testing
178
+
179
+ ```ts
180
+ // Fake backend — streams canned tokens, no server:
181
+ import { provideFakeAgent } from '@threadplane/langgraph';
182
+ providers: [provideFakeAgent({ tokens: ['Hello', ' world'] })];
183
+ ```
184
+
185
+ For component/unit tests, use the writable-signal mock `mockLangGraphAgent()`
186
+ (it extends the neutral `mockAgent` from `@threadplane/chat`). See
187
+ [Choosing an adapter → Testing](https://threadplane.ai/docs/choosing-an-adapter#testing).
188
+
189
+ Need to hand-script exact wire events (tool calls, interrupts, multi-batch
190
+ lifecycles)? `MockAgentTransport` is the advanced escape hatch — swap the
191
+ transport, never mock `injectAgent()` itself.
192
+
193
+ ## Reliability
194
+
195
+ **Runtime-neutral contract.** `LangGraphAgent` implements the `Agent` contract from `@threadplane/chat`. Components that depend only on that contract are portable across adapters (`@threadplane/ag-ui`, future adapters) without modification.
196
+
197
+ **Release policy.** Patch-only `0.0.x` releases — every change, including breaking ones, increments the patch version until the library reaches `1.0.0`.
198
+
199
+ **CI.** The "Library — lint / test / build" job runs lint, tests, and build on every pull request.
200
+
82
201
  ## Documentation
83
202
 
84
- - [Quickstart](https://threadplane.ai/docs/agent/getting-started/quickstart)
85
- - [`agent()` API reference](https://threadplane.ai/docs/agent/api/agent)
86
- - [Human-in-the-loop / interrupts](https://threadplane.ai/docs/agent/guides/interrupts)
87
- - [Thread persistence](https://threadplane.ai/docs/agent/guides/persistence)
88
- - [Testing with `MockAgentTransport`](https://threadplane.ai/docs/agent/guides/testing)
203
+ - [Quickstart](https://threadplane.ai/docs/langgraph/getting-started/quickstart)
204
+ - [`injectAgent()` API reference](https://threadplane.ai/docs/langgraph/api/inject-agent)
205
+ - [`provideAgent()` API reference](https://threadplane.ai/docs/langgraph/api/provide-agent)
206
+ - [Human-in-the-loop / interrupts](https://threadplane.ai/docs/langgraph/guides/interrupts)
207
+ - [Thread persistence](https://threadplane.ai/docs/langgraph/guides/persistence)
208
+ - [Testing with `MockAgentTransport`](https://threadplane.ai/docs/langgraph/guides/testing)
209
+ - [Choosing an adapter (LangGraph vs AG-UI)](https://threadplane.ai/docs/choosing-an-adapter)
89
210
 
90
211
  ## License
91
212
 
92
- MIT — free for any use. See [LICENSE](../../LICENSE).
213
+ MIT. See [LICENSE](../../LICENSE).