@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 +163 -42
- package/fesm2022/threadplane-langgraph.mjs +412 -54
- package/fesm2022/threadplane-langgraph.mjs.map +1 -1
- package/package.json +10 -1
- package/types/threadplane-langgraph.d.ts +165 -56
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,
|
|
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
|
-
|
|
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:**
|
|
14
|
-
|
|
15
|
-
## What it does
|
|
33
|
+
**Peer dependencies:**
|
|
16
34
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
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 {
|
|
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 =
|
|
50
|
-
apiUrl: 'https://your-langgraph-platform.com',
|
|
51
|
-
assistantId: 'my-agent',
|
|
52
|
-
});
|
|
74
|
+
protected readonly chat = injectAgent();
|
|
53
75
|
}
|
|
54
76
|
```
|
|
55
77
|
|
|
56
|
-
> `
|
|
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
|
-
|
|
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
|
-
//
|
|
62
|
-
const
|
|
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/
|
|
85
|
-
- [`
|
|
86
|
-
- [
|
|
87
|
-
- [
|
|
88
|
-
- [
|
|
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
|
|
213
|
+
MIT. See [LICENSE](../../LICENSE).
|