Commit 62b5aa6
fix(langgraph): lifecycle token, error kind, root registry, required interrupt, awaitable mock transport (#1054)
* feat(langgraph): provide AGENT_LIFECYCLE and warn on ambiguous ref-less injects
`AGENT_LIFECYCLE` was exported but never provided, so `inject(AGENT_LIFECYCLE)`
threw NG0201 unless the app wired the token itself. Both forms of
`provideAgent()` now provide it, resolving to the same object as
`injectAgent().lifecycle`.
The ref form also warns in development mode when several `provideAgent(ref, …)`
calls share an injector level and the ambiguous ref-less token is resolved: the
message names every competing ref and the one that won. Injecting by ref stays
silent, and production builds never log.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(langgraph): carry the AgentErrorKind on streamErrorAt instead of the class name
`streamErrorAt().classification` stored `error.name`. The bridge normalizes
every failure through `toAgentError()` first, so the field was the literal
'AgentError' on every real stream error — useless as a discriminator.
The field is renamed to `kind` and now carries the `AgentErrorKind`
(`connection` | `auth` | `server` | `interrupted` | `aborted`), the same value
`agent.error()?.kind` carries. A failure that slipped past normalization still
falls back to a constructor name, so the type is `AgentErrorKind | string`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(langgraph): make AgentLifecycleRegistry root-provided so registration is not construction-ordered
The agent injected the registry optionally at construction, so a registry
provided below the agent's injector — or provided after the agent was built —
collected nothing. The registry is now `providedIn: 'root'`: every agent
registers into the same instance regardless of which injector built it, and an
agent created in a route or component injector is visible from the root.
Registration is also scoped to the agent's lifetime — an agent unregisters when
its injector is destroyed — so `lifecycles()` no longer accumulates dead agents.
`provideCockpitTelemetry()` stops re-providing the class, which would have
shadowed the instance agents register into.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(langgraph): declare interrupt as required on LangGraphAgent
`interrupt` is optional on the runtime-neutral `Agent` contract because a
runtime without human-in-the-loop support omits it, which meant
`injectAgent().interrupt()` did not compile under `strictNullChecks` even
though the LangGraph adapter always provides it. `LangGraphAgent` now narrows
it to a required `Signal<AgentInterrupt | undefined>`; the chat contract is
untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* feat(langgraph): make MockAgentTransport emit/emitError/close awaitable, add flush()
`stream()` is an async generator, so `emit()` only woke the suspended loop and
nothing had reached the signals when it returned. Every spec paid for that with
a hand-rolled `await new Promise(r => setTimeout(r, 0))`.
`emit()`, `emitError()` and `close()` now return a promise that settles once the
generator has drained everything queued at the time of the call (or the run has
ended), plus one macrotask so signal writes have landed. `flush()` waits the
same way without emitting. An emit after the run finished resolves instead of
hanging.
The langgraph specs that hand-rolled the macrotask flush after an emit are
converted to `await transport.emit(...)`; removing the await makes them fail, so
the await is load-bearing. Throttle waits (16 ms and up) are left alone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs(langgraph): describe the lifecycle token, root registry, error kind, required interrupt, and awaitable transport
- lifecycle: `kind` replaces `classification` and holds the `AgentErrorKind`;
the registry is root-provided and unregisters on destroy; `AGENT_LIFECYCLE`
comes from `provideAgent()` and follows the last-ref-wins rule.
- provide-agent: documents the `AGENT_LIFECYCLE` token and the dev-mode warning
on an ambiguous ref-less inject.
- testing and mock-stream-transport: every emit is awaited rather than chased
with a macrotask flush; `flush()` is documented; `chat.interrupt()` drops the
`?.` now that `LangGraphAgent` requires it. Both pages' spec fences were
executed verbatim against the adapter and pass; the transport page's first
fence was additionally missing the optimistic user message in its assertion.
- agent-contract and introduction: the narrowed `interrupt`, and the corrected
lifecycle/registry facts.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(examples): drop the dead interrupt existence guard in the demo shell
LangGraphAgent.interrupt is now a required member, so `agent.interrupt &&`
is always true and the packaged-consumer build rejects it with TS2774.
The call itself still returns AgentInterrupt | undefined, so the remaining
`agent.interrupt()` test is the real condition.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>1 parent 4a95c58 commit 62b5aa6
25 files changed
Lines changed: 576 additions & 178 deletions
File tree
- apps/website/content/docs/langgraph
- api
- concepts
- getting-started
- guides
- examples/chat/angular/src/app/shell
- libs
- cockpit-telemetry/src/lib
- langgraph/src/lib
- internals
- testing
- transport
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
29 | 42 | | |
30 | 43 | | |
31 | 44 | | |
| |||
563 | 576 | | |
564 | 577 | | |
565 | 578 | | |
566 | | - | |
| 579 | + | |
567 | 580 | | |
568 | 581 | | |
569 | 582 | | |
| |||
573 | 586 | | |
574 | 587 | | |
575 | 588 | | |
576 | | - | |
| 589 | + | |
577 | 590 | | |
578 | 591 | | |
579 | 592 | | |
| |||
641 | 654 | | |
642 | 655 | | |
643 | 656 | | |
644 | | - | |
645 | | - | |
| 657 | + | |
| 658 | + | |
646 | 659 | | |
647 | 660 | | |
648 | 661 | | |
| |||
684 | 697 | | |
685 | 698 | | |
686 | 699 | | |
687 | | - | |
688 | | - | |
| 700 | + | |
| 701 | + | |
689 | 702 | | |
690 | 703 | | |
691 | 704 | | |
| |||
697 | 710 | | |
698 | 711 | | |
699 | 712 | | |
700 | | - | |
701 | | - | |
| 713 | + | |
| 714 | + | |
702 | 715 | | |
703 | 716 | | |
704 | 717 | | |
| |||
708 | 721 | | |
709 | 722 | | |
710 | 723 | | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
711 | 730 | | |
712 | 731 | | |
713 | 732 | | |
| |||
975 | 994 | | |
976 | 995 | | |
977 | 996 | | |
978 | | - | |
| 997 | + | |
979 | 998 | | |
980 | 999 | | |
981 | 1000 | | |
| |||
1512 | 1531 | | |
1513 | 1532 | | |
1514 | 1533 | | |
1515 | | - | |
1516 | | - | |
| 1534 | + | |
| 1535 | + | |
1517 | 1536 | | |
1518 | 1537 | | |
1519 | 1538 | | |
| |||
1946 | 1965 | | |
1947 | 1966 | | |
1948 | 1967 | | |
1949 | | - | |
| 1968 | + | |
1950 | 1969 | | |
1951 | 1970 | | |
1952 | 1971 | | |
| |||
2499 | 2518 | | |
2500 | 2519 | | |
2501 | 2520 | | |
2502 | | - | |
| 2521 | + | |
2503 | 2522 | | |
2504 | 2523 | | |
2505 | 2524 | | |
| |||
Lines changed: 19 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
| 51 | + | |
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| 61 | + | |
| 62 | + | |
61 | 63 | | |
| 64 | + | |
62 | 65 | | |
63 | 66 | | |
64 | 67 | | |
| |||
69 | 72 | | |
70 | 73 | | |
71 | 74 | | |
72 | | - | |
| 75 | + | |
73 | 76 | | |
74 | 77 | | |
75 | 78 | | |
| |||
85 | 88 | | |
86 | 89 | | |
87 | 90 | | |
88 | | - | |
89 | | - | |
90 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
91 | 95 | | |
92 | 96 | | |
93 | 97 | | |
| |||
99 | 103 | | |
100 | 104 | | |
101 | 105 | | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
102 | 115 | | |
103 | 116 | | |
104 | 117 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
98 | 115 | | |
99 | 116 | | |
100 | 117 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
139 | | - | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
140 | 142 | | |
141 | 143 | | |
142 | 144 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
0 commit comments