@threadplane/chat 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/CHANGELOG.md +3 -0
- package/README.md +233 -90
- package/fesm2022/threadplane-chat-testing.mjs +0 -2
- package/fesm2022/threadplane-chat-testing.mjs.map +1 -1
- package/fesm2022/threadplane-chat.mjs +794 -200
- package/fesm2022/threadplane-chat.mjs.map +1 -1
- package/package.json +2 -2
- package/types/threadplane-chat-testing.d.ts +15 -1
- package/types/threadplane-chat.d.ts +238 -25
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
### Changed
|
|
6
6
|
|
|
7
|
+
- **`@angular/forms` peer dependency removed:** `chat-input` now binds its textarea with a direct `[value]`/`(input)` pair (fixes the composer keeping sent text under zoneless + OnPush). `@threadplane/chat` no longer requires `@angular/forms` — consumers may drop it unless they use it themselves.
|
|
8
|
+
- **json-render store isolation:** `<chat>`'s json-render message surfaces no longer fall back to the conversation-wide internal store — each surface self-seeds from its spec's `state` unless you pass an explicit `[store]`. Pass `[store]` (e.g. `signalStateStore({})`) when dashboards should receive backend agent state (STATE_SNAPSHOT) or share live values across surfaces; same-key dashboards in different messages are now isolated by default. Tool views (`chat-tool-views`) keep the previous shared-store behavior.
|
|
9
|
+
- **Public API trim:** `@threadplane/chat` no longer re-exports `provideViews` / `VIEW_REGISTRY` from `@threadplane/render`. Consumers using `<render-spec>` / `<render-element>` directly should import from `@threadplane/render`. For chat's markdown view overrides, provide `MARKDOWN_VIEW_REGISTRY` directly using `overrideViews(cacheplaneMarkdownViews, { … })` from `@threadplane/render` — the previously-documented `provideViews(withViews(…))` pattern never actually drove rendering.
|
|
7
10
|
- **License:** `@threadplane/chat` is dual-licensed under PolyForm Noncommercial 1.0.0 (free noncommercial use) or a Threadplane Commercial license (production use inside a for-profit context).
|
|
8
11
|
|
|
9
12
|
### Migration
|
package/README.md
CHANGED
|
@@ -1,28 +1,54 @@
|
|
|
1
1
|
# @threadplane/chat
|
|
2
2
|
|
|
3
|
-
Drop-in agent chat UI for Angular 20+. Headless primitives that read
|
|
3
|
+
Drop-in agent chat UI for Angular 20+. Headless UI primitives plus opinionated compositions that read a runtime-neutral `Agent` contract — ship a production chat surface in days without coupling to a specific backend.
|
|
4
4
|
|
|
5
5
|
Part of [Threadplane](https://github.com/cacheplane/angular-agent-framework).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p>
|
|
8
|
+
<a href="https://www.npmjs.com/package/@threadplane/chat">
|
|
9
|
+
<img alt="npm version" src="https://img.shields.io/npm/v/@threadplane%2Fchat?color=6C8EFF&labelColor=080B14&style=flat-square" />
|
|
10
|
+
</a>
|
|
11
|
+
<img alt="Angular 20+" src="https://img.shields.io/badge/Angular-20%2B%20%7C%2021-6C8EFF?labelColor=080B14&style=flat-square" />
|
|
12
|
+
<img alt="License" src="https://img.shields.io/badge/License-PolyForm%20NC%20%7C%20Commercial-6C8EFF?labelColor=080B14&style=flat-square" />
|
|
13
|
+
</p>
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
**Source-available.** Free for noncommercial use under PolyForm Noncommercial License 1.0.0. Commercial production use — SaaS, internal tools, agency work, paid client projects — requires a [Threadplane Commercial license](https://threadplane.ai/pricing).
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
---
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
## What it does
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
- **Full chat surface in one tag.** `<chat [agent]="agent" />` wires up message history, streaming output, typing indicator, input, interrupts, tool calls, subagents, citations, and generative UI — all from a single binding.
|
|
22
|
+
- **Layered architecture.** Use the opinionated compositions for fast shipping, drop down to individual primitives (30+) to build custom layouts, or mix both.
|
|
23
|
+
- **Runtime-neutral.** Compositions consume an `Agent` contract. The library has no hard dependency on LangGraph, AG-UI, or any other backend — swap or combine adapters without touching your UI.
|
|
24
|
+
- **A2UI generative UI.** Agents emit structured surface specs; `<a2ui-surface>` renders them as interactive Angular components with a themeable `--a2ui-*` token system.
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
- Open-source applications released under an OSI-approved license
|
|
19
|
-
- 30 calendar days of commercial evaluation from your first commercial use (good-faith — no tracking, no email required)
|
|
26
|
+
---
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
## Install
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
```bash
|
|
31
|
+
npm install @threadplane/chat
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Peer dependencies:**
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
```
|
|
37
|
+
@angular/core ^20.0.0 || ^21.0.0
|
|
38
|
+
@angular/common ^20.0.0 || ^21.0.0
|
|
39
|
+
@angular/platform-browser ^20.0.0 || ^21.0.0
|
|
40
|
+
@threadplane/licensing *
|
|
41
|
+
@threadplane/render *
|
|
42
|
+
@threadplane/a2ui *
|
|
43
|
+
@json-render/core ^0.16.0
|
|
44
|
+
@langchain/core ^1.1.33
|
|
45
|
+
rxjs ~7.8.0
|
|
46
|
+
marked ^15.0.0 || ^16.0.0
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
26
52
|
|
|
27
53
|
```typescript
|
|
28
54
|
// app.config.ts
|
|
@@ -30,134 +56,251 @@ import { ApplicationConfig } from '@angular/core';
|
|
|
30
56
|
import { provideChat } from '@threadplane/chat';
|
|
31
57
|
|
|
32
58
|
export const appConfig: ApplicationConfig = {
|
|
33
|
-
providers: [
|
|
34
|
-
provideChat({
|
|
35
|
-
license: 'eyJ…', // The token from your purchase email.
|
|
36
|
-
}),
|
|
37
|
-
],
|
|
59
|
+
providers: [provideChat({ license: 'eyJ…' })],
|
|
38
60
|
};
|
|
39
61
|
```
|
|
40
62
|
|
|
41
|
-
|
|
63
|
+
```typescript
|
|
64
|
+
// my.component.ts
|
|
65
|
+
import { Component } from '@angular/core';
|
|
66
|
+
import { ChatComponent } from '@threadplane/chat';
|
|
67
|
+
import { agent } from '@threadplane/langgraph';
|
|
68
|
+
|
|
69
|
+
@Component({
|
|
70
|
+
selector: 'app-root',
|
|
71
|
+
imports: [ChatComponent],
|
|
72
|
+
template: `<chat [agent]="myAgent" />`,
|
|
73
|
+
})
|
|
74
|
+
export class AppComponent {
|
|
75
|
+
myAgent = agent({ apiUrl: '/api/langgraph', graphId: 'agent' });
|
|
76
|
+
}
|
|
77
|
+
```
|
|
42
78
|
|
|
43
|
-
|
|
79
|
+
Get the `agent` signal from `@threadplane/langgraph` (for LangGraph Platform backends) or `@threadplane/ag-ui` (for AG-UI-compatible backends). See those packages for setup details.
|
|
44
80
|
|
|
45
|
-
|
|
46
|
-
declare const THREADPLANE_LICENSE: string | undefined;
|
|
81
|
+
---
|
|
47
82
|
|
|
48
|
-
|
|
49
|
-
provideChat({
|
|
50
|
-
license: typeof THREADPLANE_LICENSE === 'string' ? THREADPLANE_LICENSE : undefined,
|
|
51
|
-
}),
|
|
52
|
-
],
|
|
53
|
-
```
|
|
83
|
+
## Capabilities
|
|
54
84
|
|
|
55
|
-
|
|
85
|
+
### Compositions
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
Ready-to-use full-feature layouts:
|
|
58
88
|
|
|
59
|
-
|
|
89
|
+
| Component | Selector | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `ChatComponent` | `<chat>` | Full-page chat layout; primary entry point |
|
|
92
|
+
| `ChatPopupComponent` | `<chat-popup>` | Floating popup with a launcher button |
|
|
93
|
+
| `ChatSidebarComponent` | `<chat-sidebar>` | Sidebar-docked layout |
|
|
94
|
+
| `ChatSidenavComponent` | `<chat-sidenav>` | Sidenav host with project/thread list panel |
|
|
95
|
+
| `ChatTimelineSliderComponent` | `<chat-timeline-slider>` | Time-travel slider for agent checkpoint history |
|
|
96
|
+
| `ChatInterruptPanelComponent` | `<chat-interrupt-panel>` | Full interrupt-handling composition |
|
|
97
|
+
| `ChatApprovalCardComponent` | `<chat-approval-card>` | Approval/rejection dialog for HITL flows |
|
|
98
|
+
| `ChatToolCallCardComponent` | `<chat-tool-call-card>` | Rich card for a single tool call |
|
|
99
|
+
| `ChatSubagentCardComponent` | `<chat-subagent-card>` | Rich card for a subagent delegation |
|
|
60
100
|
|
|
61
|
-
|
|
62
|
-
- **`@threadplane/ag-ui`** — for any AG-UI-compatible backend (LangGraph, CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime).
|
|
101
|
+
### Primitives
|
|
63
102
|
|
|
64
|
-
|
|
103
|
+
30+ standalone components for custom layouts:
|
|
65
104
|
|
|
66
|
-
|
|
105
|
+
`<chat-message-list>`, `<chat-message>`, `<chat-message-actions>`, `<chat-window>`, `<chat-input>`, `<chat-typing-indicator>`, `<chat-tool-calls>`, `<chat-subagents>`, `<chat-citations>`, `<chat-streaming-md>`, `<chat-trace>`, `<chat-reasoning>`, `<chat-interrupt>`, `<chat-error>`, `<chat-scroll-bubble>`, `<chat-launcher-button>`, `<chat-suggestions>`, `<chat-welcome>`, `<chat-select>`, `<chat-thread-list>`, `<chat-project-list>`, `<chat-timeline>`, `<chat-generative-ui>`, `<chat-genui-skeleton>`, `<chat-overflow-menu>`, `<chat-confirm-dialog>`, `<chat-history-search-palette>`, `<chat-sidenav-scrim>`.
|
|
67
106
|
|
|
68
|
-
|
|
107
|
+
Custom content templates for message bubbles, tool call rows, and citation cards use structural directives: `MessageTemplateDirective`, `ChatToolCallTemplateDirective`, and `ChatCitationCardTemplateDirective`.
|
|
69
108
|
|
|
70
|
-
|
|
109
|
+
### Human-in-the-loop (interrupts)
|
|
71
110
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
111
|
+
`<chat-interrupt-panel>` surfaces the current `AgentInterrupt` from an agent and renders approve/reject controls. `<chat-approval-card>` composes as a dialog for explicit approval workflows. Both emit typed action results (`InterruptAction`, `ChatApprovalAction`) that the caller submits back to the agent.
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<chat-interrupt-panel
|
|
115
|
+
[agent]="agent"
|
|
116
|
+
(interruptAction)="onAction($event)"
|
|
117
|
+
/>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Tool calls and subagents
|
|
121
|
+
|
|
122
|
+
`<chat-tool-calls>` renders in-progress and completed tool calls. Customize per-call layout with `ChatToolCallTemplateDirective` — the `chatToolCallTemplate` input takes a tool name to match, or `"*"` for all; the template context exposes the `ToolCall` (`$implicit`) and its `status`:
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<chat-tool-calls [agent]="agent">
|
|
126
|
+
<ng-template chatToolCallTemplate="*" let-call let-status="status">
|
|
127
|
+
<my-tool-card [call]="call" [status]="status" />
|
|
128
|
+
</ng-template>
|
|
129
|
+
</chat-tool-calls>
|
|
81
130
|
```
|
|
82
131
|
|
|
83
|
-
|
|
132
|
+
`<chat-subagents>` and `<chat-subagent-card>` track delegated subagent activity with live status.
|
|
84
133
|
|
|
85
|
-
|
|
134
|
+
### Citations
|
|
86
135
|
|
|
87
|
-
|
|
136
|
+
The `Citation` interface provides structured source metadata for assistant messages:
|
|
88
137
|
|
|
89
|
-
|
|
138
|
+
```ts
|
|
139
|
+
interface Citation {
|
|
140
|
+
id: string;
|
|
141
|
+
index?: number; // 1-based display index for inline superscript markers
|
|
142
|
+
title?: string;
|
|
143
|
+
url?: string;
|
|
144
|
+
snippet?: string;
|
|
145
|
+
extra?: unknown; // adapter-specific fields
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Use `<chat-citations>` to render a collapsible sources panel under assistant messages. Customize the card layout with the `chatCitationCard` template directive:
|
|
90
150
|
|
|
91
151
|
```html
|
|
92
|
-
<chat [agent]="agent" />
|
|
93
|
-
<!-- or explicit: -->
|
|
94
152
|
<chat-citations [message]="message">
|
|
95
153
|
<ng-template chatCitationCard let-citation>
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
<p class="text-sm text-gray-600">{{ citation.snippet }}</p>
|
|
99
|
-
</div>
|
|
154
|
+
<a [href]="citation.url">{{ citation.title }}</a>
|
|
155
|
+
<p>{{ citation.snippet }}</p>
|
|
100
156
|
</ng-template>
|
|
101
157
|
</chat-citations>
|
|
102
158
|
```
|
|
103
159
|
|
|
104
|
-
|
|
160
|
+
Inline citation markers are rendered automatically by `MarkdownCitationReferenceComponent` inside streaming markdown output — superscript indices link to the corresponding card in the sources panel.
|
|
161
|
+
|
|
162
|
+
`CitationsResolverService` resolves raw `Citation` references into `ResolvedCitation` objects with full source metadata.
|
|
163
|
+
|
|
164
|
+
**Adapter integration:**
|
|
165
|
+
- **LangGraph** — reads from `message.additional_kwargs.citations` (preferred) or `.sources` (fallback).
|
|
166
|
+
- **AG-UI** — `bridgeCitationsState` reads `state.citations[messageId]` from the agent state on `STATE_SNAPSHOT` and `STATE_DELTA` events.
|
|
105
167
|
|
|
106
|
-
|
|
168
|
+
### GenUI / A2UI surfaces
|
|
107
169
|
|
|
108
|
-
|
|
170
|
+
`<chat-generative-ui>` renders A2UI surface specs emitted by agents. `<a2ui-surface>` is the underlying host that maps the spec to Angular catalog components (`A2uiButtonComponent`, `A2uiTextFieldComponent`, `A2uiCheckBoxComponent`, etc.).
|
|
109
171
|
|
|
110
|
-
|
|
172
|
+
Agents can emit surface specs via `buildA2uiActionMessage(...)`. Actions from catalog components flow back to the agent as structured messages.
|
|
111
173
|
|
|
112
|
-
-
|
|
113
|
-
- **AG-UI** — reads from STATE_DELTA at JSON Pointer `/citations/{messageId}`
|
|
174
|
+
The built-in catalog ships via `a2uiBasicCatalog`. Compose a custom catalog with `withViews()` and pass it to the surface.
|
|
114
175
|
|
|
115
|
-
|
|
176
|
+
### Streaming markdown
|
|
116
177
|
|
|
117
|
-
|
|
178
|
+
`<chat-streaming-md>` renders markdown token-by-token as the agent streams. The `cacheplaneMarkdownViews` registry maps each CommonMark node type to an Angular component.
|
|
118
179
|
|
|
119
|
-
|
|
180
|
+
Override individual node renderers:
|
|
120
181
|
|
|
121
|
-
|
|
182
|
+
```typescript
|
|
183
|
+
import { MARKDOWN_VIEW_REGISTRY, cacheplaneMarkdownViews } from '@threadplane/chat';
|
|
184
|
+
import { overrideViews } from '@threadplane/render';
|
|
185
|
+
import { MyCodeBlockComponent } from './my-code-block.component';
|
|
186
|
+
|
|
187
|
+
providers: [
|
|
188
|
+
{
|
|
189
|
+
provide: MARKDOWN_VIEW_REGISTRY,
|
|
190
|
+
useValue: overrideViews(cacheplaneMarkdownViews, { 'code-block': MyCodeBlockComponent }),
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
```
|
|
122
194
|
|
|
123
|
-
|
|
195
|
+
Per-instance, bind the registry on `<chat-streaming-md [viewRegistry]="…" />` instead. Styling uses the existing `--ngaf-chat-*` / `--a2ui-*` tokens — see the [Theming](#theming) section.
|
|
124
196
|
|
|
125
|
-
|
|
126
|
-
- `primaryColor` — hex `#RRGGBB`
|
|
197
|
+
The `renderMarkdown(md, options?)` function produces a parse tree for use outside streaming contexts.
|
|
127
198
|
|
|
128
|
-
|
|
199
|
+
### Theming
|
|
129
200
|
|
|
130
|
-
|
|
201
|
+
`<a2ui-surface>` declares ~50 `--a2ui-*` CSS custom properties at `:host` with dark-theme defaults covering color, spacing, typography, shape radius, focus ring, motion, and elevation. Catalog components consume them via `var(--a2ui-*)`.
|
|
131
202
|
|
|
132
|
-
|
|
203
|
+
**Built-in presets** — import one in your global stylesheet:
|
|
133
204
|
|
|
134
205
|
```css
|
|
135
|
-
/*
|
|
136
|
-
@import '@threadplane/chat/themes/default-
|
|
137
|
-
@import '@threadplane/chat/themes/
|
|
138
|
-
@import '@threadplane/chat/themes/material-
|
|
139
|
-
@import '@threadplane/chat/themes/material-light.css'; /* Material Design 3 light */
|
|
206
|
+
@import '@threadplane/chat/themes/default-dark.css'; /* lib defaults, explicit */
|
|
207
|
+
@import '@threadplane/chat/themes/default-light.css'; /* neutral light, blue accent */
|
|
208
|
+
@import '@threadplane/chat/themes/material-dark.css'; /* Material Design 3 dark */
|
|
209
|
+
@import '@threadplane/chat/themes/material-light.css'; /* Material Design 3 light */
|
|
140
210
|
```
|
|
141
211
|
|
|
142
|
-
Material presets map
|
|
212
|
+
Material presets map M3 color tokens to the `--a2ui-*` vocabulary with no `@angular/material` runtime dependency.
|
|
143
213
|
|
|
144
|
-
|
|
214
|
+
**Agent-driven theming.** Agents control two knobs per the A2UI v1 wire format, set via `beginRendering.styles`: `font` (font family string) and `primaryColor` (hex `#RRGGBB`). These flow to `<a2ui-surface>` as inline styles and take precedence over `:root` defaults for that surface.
|
|
145
215
|
|
|
146
|
-
Override any
|
|
216
|
+
**Custom themes.** Override any token at `:root`:
|
|
147
217
|
|
|
148
218
|
```css
|
|
149
219
|
:root {
|
|
150
|
-
--a2ui-primary: #FF6B35;
|
|
151
|
-
--a2ui-shape-medium: 4px;
|
|
152
|
-
--a2ui-spacing-3: 16px;
|
|
220
|
+
--a2ui-primary: #FF6B35;
|
|
221
|
+
--a2ui-shape-medium: 4px;
|
|
222
|
+
--a2ui-spacing-3: 16px;
|
|
153
223
|
}
|
|
154
224
|
```
|
|
155
225
|
|
|
156
|
-
The token
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
226
|
+
The full token vocabulary (`--a2ui-primary`, `--a2ui-spacing-1..7`, `--a2ui-typography-*`, `--a2ui-shape-*`, `--a2ui-elevation-*`, etc.) is documented at [threadplane.ai/docs/chat](https://threadplane.ai/docs/chat).
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Runtime adapters
|
|
231
|
+
|
|
232
|
+
Chat compositions consume the runtime-neutral `Agent` contract. Two adapters ship today:
|
|
233
|
+
|
|
234
|
+
- **`@threadplane/langgraph`** — for LangGraph / LangGraph Platform backends.
|
|
235
|
+
- **`@threadplane/ag-ui`** — for AG-UI-compatible backends (LangGraph, CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime).
|
|
236
|
+
|
|
237
|
+
Custom backends implement the `Agent` (or `AgentWithHistory`) interface directly with no library dependency.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Commercial use
|
|
242
|
+
|
|
243
|
+
Building a commercial product, SaaS application, internal business tool, agency deliverable, or paid client project with `@threadplane/chat` requires a Threadplane Commercial license.
|
|
244
|
+
|
|
245
|
+
Free under PolyForm Noncommercial:
|
|
246
|
+
|
|
247
|
+
- Personal, hobby, student, academic, nonprofit, and public-demo use
|
|
248
|
+
- Open-source applications released under an OSI-approved license
|
|
249
|
+
- 30 calendar days of commercial evaluation from your first commercial use (good-faith — no tracking, no email required)
|
|
250
|
+
|
|
251
|
+
See [COMMERCIAL-USE.md](./COMMERCIAL-USE.md) for the definition of commercial use, [LICENSE-COMMERCIAL.md](./LICENSE-COMMERCIAL.md) for the commercial license summary, and the [Threadplane pricing page](https://threadplane.ai/pricing) for plans.
|
|
252
|
+
|
|
253
|
+
## Using a commercial license
|
|
254
|
+
|
|
255
|
+
After purchase, Threadplane emails a signed license token to the address on your receipt. The license is valid for 12 months. Pass the token to `provideChat()`:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// app.config.ts
|
|
259
|
+
import { ApplicationConfig } from '@angular/core';
|
|
260
|
+
import { provideChat } from '@threadplane/chat';
|
|
261
|
+
|
|
262
|
+
export const appConfig: ApplicationConfig = {
|
|
263
|
+
providers: [
|
|
264
|
+
provideChat({
|
|
265
|
+
license: 'eyJ…', // Token from your purchase email.
|
|
266
|
+
}),
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The library verifies the token's signature on boot. A missing, expired, or tampered token logs a `console.warn` advisory but does not block rendering — chat continues to work either way. Tokens are validated offline; no calls to Threadplane are made at runtime.
|
|
272
|
+
|
|
273
|
+
The license string is safe to commit to source control for private repositories, or read from a build-time env var for public ones:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
declare const THREADPLANE_LICENSE: string | undefined;
|
|
277
|
+
|
|
278
|
+
providers: [
|
|
279
|
+
provideChat({
|
|
280
|
+
license: typeof THREADPLANE_LICENSE === 'string' ? THREADPLANE_LICENSE : undefined,
|
|
281
|
+
}),
|
|
282
|
+
],
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Reliability
|
|
288
|
+
|
|
289
|
+
`@threadplane/chat` follows a patch-only release cadence (`0.0.x`). The runtime-neutral `Agent` contract is a stability boundary: adapter updates do not break chat UI code and vice versa. The package is covered by the monorepo's CI lint, test, and build pipeline on every commit.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Documentation
|
|
294
|
+
|
|
295
|
+
Full API reference, capability matrix, and examples: [threadplane.ai/docs/chat](https://threadplane.ai/docs/chat).
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
`@threadplane/chat` is dual-licensed:
|
|
302
|
+
|
|
303
|
+
- **Noncommercial use:** [PolyForm Noncommercial License 1.0.0](./LICENSE.md)
|
|
304
|
+
- **Commercial use:** [Threadplane Commercial License](./LICENSE-COMMERCIAL.md)
|
|
305
|
+
|
|
306
|
+
See [COMMERCIAL-USE.md](./COMMERCIAL-USE.md) for the definition of commercial use.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threadplane-chat-testing.mjs","sources":["../../../../libs/chat/testing/agent-conformance.ts","../../../../libs/chat/testing/agent-with-history-conformance.ts","../../../../libs/chat/testing/reasoning-fixture.ts","../../../../libs/chat/testing/public-api.ts","../../../../libs/chat/testing/threadplane-chat-testing.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\nimport { describe, it, expect } from 'vitest';\nimport type { Agent } from '@threadplane/chat';\n\n/**\n * Runs a suite of contract conformance assertions against a factory that\n * produces a fresh Agent. Adapter packages should call this in their\n * own test suites to verify the contract is satisfied.\n */\nexport function runAgentConformance(\n label: string,\n factory: () => Agent,\n): void {\n describe(`${label} — Agent conformance`, () => {\n it('exposes required core signals', () => {\n const a = factory();\n expect(typeof a.messages).toBe('function');\n expect(typeof a.status).toBe('function');\n expect(typeof a.isLoading).toBe('function');\n expect(typeof a.error).toBe('function');\n expect(typeof a.toolCalls).toBe('function');\n expect(typeof a.state).toBe('function');\n });\n\n it('messages() returns an array', () => {\n expect(Array.isArray(factory().messages())).toBe(true);\n });\n\n it('toolCalls() returns an array', () => {\n expect(Array.isArray(factory().toolCalls())).toBe(true);\n });\n\n it('state() returns a plain object', () => {\n const v = factory().state();\n expect(typeof v).toBe('object');\n expect(v).not.toBeNull();\n });\n\n it('status() returns one of the allowed values', () => {\n expect(['idle', 'running', 'error']).toContain(factory().status());\n });\n\n it('isLoading() is true only when status === \"running\"', () => {\n const a = factory();\n if (a.isLoading()) {\n expect(a.status()).toBe('running');\n }\n });\n\n it('submit() returns a Promise', () => {\n const result = factory().submit({ message: 'test' });\n expect(result).toBeInstanceOf(Promise);\n });\n\n it('stop() returns a Promise', () => {\n const result = factory().stop();\n expect(result).toBeInstanceOf(Promise);\n });\n\n it('events$ is an Observable-like with .subscribe', () => {\n const agent = factory();\n expect(typeof agent.events$.subscribe).toBe('function');\n });\n });\n}\n","// SPDX-License-Identifier: MIT\nimport { describe, it, expect } from 'vitest';\nimport type { AgentWithHistory, AgentCheckpoint } from '@threadplane/chat';\nimport { runAgentConformance } from './agent-conformance';\n\n/**\n * Conformance suite for AgentWithHistory implementations.\n *\n * Runs the base Agent conformance suite, then verifies the history\n * signal is present and returns an array of AgentCheckpoint-shaped entries.\n */\nexport function runAgentWithHistoryConformance(\n label: string,\n factory: (seed?: { history?: AgentCheckpoint[] }) => AgentWithHistory,\n): void {\n runAgentConformance(label, () => factory());\n\n describe(`${label} — history`, () => {\n it('exposes a history signal', () => {\n const agent = factory();\n expect(typeof agent.history).toBe('function');\n expect(Array.isArray(agent.history())).toBe(true);\n });\n\n it('reflects seeded checkpoints', () => {\n const seed: AgentCheckpoint[] = [\n { id: 'c1', label: 'Step 1', values: { foo: 1 } },\n { id: 'c2', label: 'Step 2', values: { foo: 2 } },\n ];\n const agent = factory({ history: seed });\n const entries = agent.history();\n expect(entries).toHaveLength(2);\n expect(entries[0].id).toBe('c1');\n expect(entries[1].values).toEqual({ foo: 2 });\n });\n });\n}\n","// libs/chat/testing/reasoning-fixture.ts\n// SPDX-License-Identifier: MIT\n//\n// Provider-neutral fixture for the reasoning conformance test. Both\n// adapters (langgraph + ag-ui) translate this abstract sequence into\n// their own wire format and assert that the resulting Agent.messages()\n// produces a single assistant Message with the expected reasoning\n// string, response content, and a numeric (>= 0) reasoningDurationMs.\n//\n// \"Abstract events\" mirror the AG-UI shape — REASONING_*/TEXT_*. Any\n// adapter that streams reasoning before text should be able to satisfy\n// this fixture. The shared assertions live in\n// `assertReasoningFixtureMessages(messages)` so each adapter's spec\n// just constructs the events and calls the assertion.\n\nimport type { Message } from '@threadplane/chat';\n\nexport const REASONING_FIXTURE_MESSAGE_ID = 'fixture-msg-1';\nexport const REASONING_FIXTURE_REASONING = 'I read the prompt and decided to greet the user.';\nexport const REASONING_FIXTURE_RESPONSE = 'Hello!';\n\nexport interface AbstractEvent {\n kind:\n | 'reasoning-start'\n | 'reasoning-chunk'\n | 'reasoning-end'\n | 'text-start'\n | 'text-chunk'\n | 'text-end';\n delta?: string;\n}\n\n/**\n * Canonical sequence: reasoning starts, three reasoning chunks, reasoning\n * ends, text starts, three text chunks, text ends.\n */\nexport const REASONING_FIXTURE_EVENTS: AbstractEvent[] = [\n { kind: 'reasoning-start' },\n { kind: 'reasoning-chunk', delta: 'I read the prompt ' },\n { kind: 'reasoning-chunk', delta: 'and decided ' },\n { kind: 'reasoning-chunk', delta: 'to greet the user.' },\n { kind: 'reasoning-end' },\n { kind: 'text-start' },\n { kind: 'text-chunk', delta: 'Hel' },\n { kind: 'text-chunk', delta: 'lo' },\n { kind: 'text-chunk', delta: '!' },\n { kind: 'text-end' },\n];\n\n/**\n * Assertion — common to both adapters. Throws if the produced messages\n * don't match the shared expectation.\n */\nexport function assertReasoningFixtureMessages(messages: readonly Message[]): void {\n if (messages.length !== 1) {\n throw new Error(`Expected exactly 1 message, got ${messages.length}: ${JSON.stringify(messages)}`);\n }\n const m = messages[0];\n if (m.role !== 'assistant') {\n throw new Error(`Expected assistant role, got ${m.role}`);\n }\n if (m.content !== REASONING_FIXTURE_RESPONSE) {\n throw new Error(`Expected content ${JSON.stringify(REASONING_FIXTURE_RESPONSE)}, got ${JSON.stringify(m.content)}`);\n }\n if (m.reasoning !== REASONING_FIXTURE_REASONING) {\n throw new Error(`Expected reasoning ${JSON.stringify(REASONING_FIXTURE_REASONING)}, got ${JSON.stringify(m.reasoning)}`);\n }\n if (typeof m.reasoningDurationMs !== 'number') {\n throw new Error(`Expected reasoningDurationMs to be a number, got ${typeof m.reasoningDurationMs}`);\n }\n if (m.reasoningDurationMs < 0) {\n throw new Error(`Expected reasoningDurationMs >= 0, got ${m.reasoningDurationMs}`);\n }\n}\n","// SPDX-License-Identifier: MIT\nexport { runAgentConformance } from './agent-conformance';\nexport { runAgentWithHistoryConformance } from './agent-with-history-conformance';\nexport {\n REASONING_FIXTURE_MESSAGE_ID,\n REASONING_FIXTURE_REASONING,\n REASONING_FIXTURE_RESPONSE,\n REASONING_FIXTURE_EVENTS,\n assertReasoningFixtureMessages,\n type AbstractEvent,\n} from './reasoning-fixture';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"threadplane-chat-testing.mjs","sources":["../../../../libs/chat/testing/agent-conformance.ts","../../../../libs/chat/testing/agent-with-history-conformance.ts","../../../../libs/chat/testing/reasoning-fixture.ts","../../../../libs/chat/testing/threadplane-chat-testing.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\nimport { describe, it, expect } from 'vitest';\nimport type { Agent } from '@threadplane/chat';\n\n/**\n * Runs a suite of contract conformance assertions against a factory that\n * produces a fresh Agent. Adapter packages should call this in their\n * own test suites to verify the contract is satisfied.\n */\nexport function runAgentConformance(\n label: string,\n factory: () => Agent,\n): void {\n describe(`${label} — Agent conformance`, () => {\n it('exposes required core signals', () => {\n const a = factory();\n expect(typeof a.messages).toBe('function');\n expect(typeof a.status).toBe('function');\n expect(typeof a.isLoading).toBe('function');\n expect(typeof a.error).toBe('function');\n expect(typeof a.toolCalls).toBe('function');\n expect(typeof a.state).toBe('function');\n });\n\n it('messages() returns an array', () => {\n expect(Array.isArray(factory().messages())).toBe(true);\n });\n\n it('toolCalls() returns an array', () => {\n expect(Array.isArray(factory().toolCalls())).toBe(true);\n });\n\n it('state() returns a plain object', () => {\n const v = factory().state();\n expect(typeof v).toBe('object');\n expect(v).not.toBeNull();\n });\n\n it('status() returns one of the allowed values', () => {\n expect(['idle', 'running', 'error']).toContain(factory().status());\n });\n\n it('isLoading() is true only when status === \"running\"', () => {\n const a = factory();\n if (a.isLoading()) {\n expect(a.status()).toBe('running');\n }\n });\n\n it('submit() returns a Promise', () => {\n const result = factory().submit({ message: 'test' });\n expect(result).toBeInstanceOf(Promise);\n });\n\n it('stop() returns a Promise', () => {\n const result = factory().stop();\n expect(result).toBeInstanceOf(Promise);\n });\n\n it('events$ is an Observable-like with .subscribe', () => {\n const agent = factory();\n expect(typeof agent.events$.subscribe).toBe('function');\n });\n });\n}\n","// SPDX-License-Identifier: MIT\nimport { describe, it, expect } from 'vitest';\nimport type { AgentWithHistory, AgentCheckpoint } from '@threadplane/chat';\nimport { runAgentConformance } from './agent-conformance';\n\n/**\n * Conformance suite for AgentWithHistory implementations.\n *\n * Runs the base Agent conformance suite, then verifies the history\n * signal is present and returns an array of AgentCheckpoint-shaped entries.\n */\nexport function runAgentWithHistoryConformance(\n label: string,\n factory: (seed?: { history?: AgentCheckpoint[] }) => AgentWithHistory,\n): void {\n runAgentConformance(label, () => factory());\n\n describe(`${label} — history`, () => {\n it('exposes a history signal', () => {\n const agent = factory();\n expect(typeof agent.history).toBe('function');\n expect(Array.isArray(agent.history())).toBe(true);\n });\n\n it('reflects seeded checkpoints', () => {\n const seed: AgentCheckpoint[] = [\n { id: 'c1', label: 'Step 1', values: { foo: 1 } },\n { id: 'c2', label: 'Step 2', values: { foo: 2 } },\n ];\n const agent = factory({ history: seed });\n const entries = agent.history();\n expect(entries).toHaveLength(2);\n expect(entries[0].id).toBe('c1');\n expect(entries[1].values).toEqual({ foo: 2 });\n });\n });\n}\n","// libs/chat/testing/reasoning-fixture.ts\n// SPDX-License-Identifier: MIT\n//\n// Provider-neutral fixture for the reasoning conformance test. Both\n// adapters (langgraph + ag-ui) translate this abstract sequence into\n// their own wire format and assert that the resulting Agent.messages()\n// produces a single assistant Message with the expected reasoning\n// string, response content, and a numeric (>= 0) reasoningDurationMs.\n//\n// \"Abstract events\" mirror the AG-UI shape — REASONING_*/TEXT_*. Any\n// adapter that streams reasoning before text should be able to satisfy\n// this fixture. The shared assertions live in\n// `assertReasoningFixtureMessages(messages)` so each adapter's spec\n// just constructs the events and calls the assertion.\n\nimport type { Message } from '@threadplane/chat';\n\nexport const REASONING_FIXTURE_MESSAGE_ID = 'fixture-msg-1';\nexport const REASONING_FIXTURE_REASONING = 'I read the prompt and decided to greet the user.';\nexport const REASONING_FIXTURE_RESPONSE = 'Hello!';\n\nexport interface AbstractEvent {\n kind:\n | 'reasoning-start'\n | 'reasoning-chunk'\n | 'reasoning-end'\n | 'text-start'\n | 'text-chunk'\n | 'text-end';\n delta?: string;\n}\n\n/**\n * Canonical sequence: reasoning starts, three reasoning chunks, reasoning\n * ends, text starts, three text chunks, text ends.\n */\nexport const REASONING_FIXTURE_EVENTS: AbstractEvent[] = [\n { kind: 'reasoning-start' },\n { kind: 'reasoning-chunk', delta: 'I read the prompt ' },\n { kind: 'reasoning-chunk', delta: 'and decided ' },\n { kind: 'reasoning-chunk', delta: 'to greet the user.' },\n { kind: 'reasoning-end' },\n { kind: 'text-start' },\n { kind: 'text-chunk', delta: 'Hel' },\n { kind: 'text-chunk', delta: 'lo' },\n { kind: 'text-chunk', delta: '!' },\n { kind: 'text-end' },\n];\n\n/**\n * Assertion — common to both adapters. Throws if the produced messages\n * don't match the shared expectation.\n */\nexport function assertReasoningFixtureMessages(messages: readonly Message[]): void {\n if (messages.length !== 1) {\n throw new Error(`Expected exactly 1 message, got ${messages.length}: ${JSON.stringify(messages)}`);\n }\n const m = messages[0];\n if (m.role !== 'assistant') {\n throw new Error(`Expected assistant role, got ${m.role}`);\n }\n if (m.content !== REASONING_FIXTURE_RESPONSE) {\n throw new Error(`Expected content ${JSON.stringify(REASONING_FIXTURE_RESPONSE)}, got ${JSON.stringify(m.content)}`);\n }\n if (m.reasoning !== REASONING_FIXTURE_REASONING) {\n throw new Error(`Expected reasoning ${JSON.stringify(REASONING_FIXTURE_REASONING)}, got ${JSON.stringify(m.reasoning)}`);\n }\n if (typeof m.reasoningDurationMs !== 'number') {\n throw new Error(`Expected reasoningDurationMs to be a number, got ${typeof m.reasoningDurationMs}`);\n }\n if (m.reasoningDurationMs < 0) {\n throw new Error(`Expected reasoningDurationMs >= 0, got ${m.reasoningDurationMs}`);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|