ngx-json-render 0.9.1 → 0.9.4
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 +117 -24
- package/fesm2022/ngx-json-render-ag-ui.mjs +308 -0
- package/fesm2022/ngx-json-render-ag-ui.mjs.map +1 -0
- package/fesm2022/ngx-json-render-devtools.mjs +3 -3
- package/fesm2022/ngx-json-render-testing.mjs +6 -6
- package/fesm2022/ngx-json-render.mjs +27 -27
- package/package.json +9 -3
- package/schematics/ng-add/index.cjs +1 -1
- package/types/ngx-json-render-ag-ui.d.ts +223 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/ngx-json-render) [](https://github.com/shteynu/ngx-json-render/actions/workflows/ci.yml) [](https://github.com/shteynu/ngx-json-render/blob/main/LICENSE)
|
|
4
4
|
|
|
5
|
-
Angular renderer for [json-render](https://github.com/vercel-labs/json-render)
|
|
5
|
+
Generative UI for Angular: a renderer for [json-render](https://github.com/vercel-labs/json-render). Give an LLM a catalog of your components, stream back a JSON spec, and render it as real Angular components. No `innerHTML`, no `eval`, no framework lock-in on the wire format.
|
|
6
6
|
|
|
7
7
|
Built on `@json-render/core` (the same spec format, expressions, state store, actions, and streaming compiler used by the React, Vue, Solid, and Svelte renderers) and idiomatic modern Angular: standalone components, signals, `OnPush` everywhere, and zoneless — no `NgZone`, no Zone.js.
|
|
8
8
|
|
|
@@ -57,12 +57,14 @@ npx skills add shteynu/ngx-json-render --skill ngx-json-render
|
|
|
57
57
|
|
|
58
58
|
The source is [`skills/ngx-json-render/SKILL.md`](https://github.com/shteynu/ngx-json-render/blob/main/skills/ngx-json-render/SKILL.md);
|
|
59
59
|
the Material catalog has one too (`--skill ngx-json-render-material`).
|
|
60
|
+
An agent that reads [llms.txt](https://llmstxt.org) instead can start from
|
|
61
|
+
<https://shteynu.github.io/ngx-json-render/llms.txt>.
|
|
60
62
|
|
|
61
63
|
## The shortest path: a ready-made catalog
|
|
62
64
|
|
|
63
65
|
Writing a catalog is the honest first step, but you do not have to take it to
|
|
64
66
|
see a spec render. [`ngx-json-render-material`](https://www.npmjs.com/package/ngx-json-render-material)
|
|
65
|
-
ships
|
|
67
|
+
ships 33 Angular Material components already registered, so a generated spec
|
|
66
68
|
renders with nothing else wired up:
|
|
67
69
|
|
|
68
70
|
```bash
|
|
@@ -107,28 +109,6 @@ export class App {
|
|
|
107
109
|
vocabulary. Everything below is the other path — your own components, which is
|
|
108
110
|
what the catalog API is for.
|
|
109
111
|
|
|
110
|
-
## ngx-json-render or Hashbrown?
|
|
111
|
-
|
|
112
|
-
[Hashbrown](https://hashbrown.dev) is the other generative-UI library for
|
|
113
|
-
Angular. Both let a model compose your components; they differ in what the
|
|
114
|
-
model emits and in how much of the agent around it they provide. Compared
|
|
115
|
-
against `@hashbrownai/angular` 0.6.1, as published on 2026-09-30:
|
|
116
|
-
|
|
117
|
-
| | ngx-json-render | Hashbrown |
|
|
118
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
-
| What the model emits | A json-render spec, streamed as RFC 6902 patches — the format the React, Vue, Svelte and Solid renderers read, so a catalog and a spec move between frameworks unchanged | Hashbrown's own JSON, generated against a schema built from the components you expose; read by Hashbrown's Angular and React clients |
|
|
120
|
-
| Server | Anything that streams text: the [AI SDK](https://ai-sdk.dev) in a few lines, or your own endpoint; `catalog.prompt()` writes the system prompt | An [AG-UI](https://docs.ag-ui.com) endpoint, built with Hashbrown's adapters (OpenAI, Anthropic, Google, Azure, Bedrock, Ollama) or your own mapping |
|
|
121
|
-
| Angular | 20, 21 and 22, each tested in CI | 22 only since 0.6 (0.5 supported 20 and 21) |
|
|
122
|
-
| Components | Your own, or 29 ready-made Angular Material ones ([`ngx-json-render-material`](https://www.npmjs.com/package/ngx-json-render-material)) | Your own (`exposeComponent`, UI kits) |
|
|
123
|
-
| Beyond rendering | Rendering-focused: state and two-way bindings in the spec, actions, visibility, repeat, watch, confirmation dialogs | An agent toolkit: client-side tools, a QuickJS sandbox for model-written code, shared agent state, interrupts, streaming Markdown |
|
|
124
|
-
| License | Apache-2.0 | MIT |
|
|
125
|
-
|
|
126
|
-
Reach for Hashbrown when you want the agent loop — tools, a sandbox, AG-UI —
|
|
127
|
-
from one library and are on Angular 22. Reach for this one when you want an
|
|
128
|
-
open spec format that is not tied to Angular or to one vendor's client, a
|
|
129
|
-
server you already have, Angular 20 or 21, or a UI that renders from a
|
|
130
|
-
ready-made Material catalog before you have written a component.
|
|
131
|
-
|
|
132
112
|
## Quick start
|
|
133
113
|
|
|
134
114
|
**1. Define a catalog** — the vocabulary the model (or your server) is allowed to use:
|
|
@@ -470,6 +450,117 @@ this package's, and both silent when you get them wrong:
|
|
|
470
450
|
writes the chunks a server route would, reads the message a client would —
|
|
471
451
|
and asserts both of these, so this section cannot quietly go stale.
|
|
472
452
|
|
|
453
|
+
### From an AG-UI agent
|
|
454
|
+
|
|
455
|
+
[AG-UI](https://docs.ag-ui.com) is the event protocol CopilotKit, LangGraph and
|
|
456
|
+
others speak between an agent and its frontend. A json-render spec travels on
|
|
457
|
+
it as an **activity** with `activityType: "json-render-spec"`
|
|
458
|
+
(`JSON_RENDER_ACTIVITY_TYPE`): `ACTIVITY_SNAPSHOT` carries a whole spec in
|
|
459
|
+
`content`, and `ACTIVITY_DELTA` carries RFC 6902 patches against it in `patch`
|
|
460
|
+
— the same patches a JSONL stream is made of. `ngx-json-render/ag-ui` reads
|
|
461
|
+
that, and needs nothing from `@ag-ui/*` at runtime: it accepts any agent and
|
|
462
|
+
event of the right shape.
|
|
463
|
+
|
|
464
|
+
With an `@ag-ui/client` agent, `injectAgentUI` gives the signals `injectUIStream`
|
|
465
|
+
gives. The app keeps running the agent; the hook only listens, so it sees every
|
|
466
|
+
run whoever starts it, and checks each spec when the run ends:
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
import { Component } from '@angular/core';
|
|
470
|
+
import { HttpAgent } from '@ag-ui/client';
|
|
471
|
+
import { JsonRenderer } from 'ngx-json-render';
|
|
472
|
+
import { injectAgentUI } from 'ngx-json-render/ag-ui';
|
|
473
|
+
import { catalog } from './catalog';
|
|
474
|
+
|
|
475
|
+
@Component({
|
|
476
|
+
imports: [JsonRenderer],
|
|
477
|
+
template: `
|
|
478
|
+
<json-render [spec]="ui.spec()" [loading]="ui.isStreaming()" />
|
|
479
|
+
<button (click)="ask('show me revenue for the quarter')">Ask</button>
|
|
480
|
+
`,
|
|
481
|
+
})
|
|
482
|
+
export class AgentPage {
|
|
483
|
+
readonly agent = new HttpAgent({ url: '/api/agent' });
|
|
484
|
+
readonly ui = injectAgentUI({ agent: this.agent, catalog, validate: 'warn' });
|
|
485
|
+
|
|
486
|
+
ask(text: string) {
|
|
487
|
+
this.agent.addMessage({ id: crypto.randomUUID(), role: 'user', content: text });
|
|
488
|
+
this.agent.runAgent();
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
`ui.surfaces()` lists every spec the agent has built, keyed by the activity's
|
|
494
|
+
`messageId`, for a run that opens more than one; `ui.spec()` is the latest.
|
|
495
|
+
Elements a delta does not touch keep their identity, so the renderer skips
|
|
496
|
+
them. Without the hook, `applyAgUiEvent(surfaces, event)` is the same fold as a
|
|
497
|
+
pure function.
|
|
498
|
+
|
|
499
|
+
**In a CopilotKit Angular app**, register the ready-made activity renderer.
|
|
500
|
+
It draws the spec with the registry and catalog from `provideJsonRender`:
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
import { provideJsonRender } from 'ngx-json-render';
|
|
504
|
+
import { jsonRenderActivityRenderer } from 'ngx-json-render/ag-ui';
|
|
505
|
+
|
|
506
|
+
providers: [
|
|
507
|
+
provideJsonRender({ registry }),
|
|
508
|
+
provideCopilotKit({
|
|
509
|
+
runtimeUrl: '/api/copilotkit',
|
|
510
|
+
renderActivityMessages: [jsonRenderActivityRenderer()],
|
|
511
|
+
}),
|
|
512
|
+
];
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**On the server**, the model's output — prose with ` ```spec ` fenced JSONL,
|
|
516
|
+
as `catalog.prompt({ mode: 'inline' })` asks for — splits into text-message
|
|
517
|
+
events and activity deltas with `createMixedStreamParser` from
|
|
518
|
+
`@json-render/core`, and `EventEncoder` from `@ag-ui/encoder` writes the
|
|
519
|
+
server-sent events:
|
|
520
|
+
|
|
521
|
+
```ts
|
|
522
|
+
// server.ts — an AG-UI endpoint (Express)
|
|
523
|
+
import { EventType, type BaseEvent, type RunAgentInput } from '@ag-ui/core';
|
|
524
|
+
import { EventEncoder } from '@ag-ui/encoder';
|
|
525
|
+
import { createMixedStreamParser } from '@json-render/core';
|
|
526
|
+
|
|
527
|
+
app.post('/api/agent', async (req, res) => {
|
|
528
|
+
const { threadId, runId, messages } = req.body as RunAgentInput;
|
|
529
|
+
const encoder = new EventEncoder({ accept: req.headers.accept });
|
|
530
|
+
const send = (event: BaseEvent) => res.write(encoder.encode(event));
|
|
531
|
+
res.setHeader('Content-Type', encoder.getContentType());
|
|
532
|
+
|
|
533
|
+
const textId = crypto.randomUUID();
|
|
534
|
+
const uiId = crypto.randomUUID();
|
|
535
|
+
send({ type: EventType.RUN_STARTED, threadId, runId } as BaseEvent);
|
|
536
|
+
send({ type: EventType.TEXT_MESSAGE_START, messageId: textId, role: 'assistant' } as BaseEvent);
|
|
537
|
+
send({ type: EventType.ACTIVITY_SNAPSHOT, messageId: uiId, activityType: 'json-render-spec',
|
|
538
|
+
content: { root: '', elements: {} } } as BaseEvent);
|
|
539
|
+
|
|
540
|
+
const parser = createMixedStreamParser({
|
|
541
|
+
onText: (line) => send({ type: EventType.TEXT_MESSAGE_CONTENT, messageId: textId,
|
|
542
|
+
delta: line + '\n' } as BaseEvent),
|
|
543
|
+
onPatch: (patch) => send({ type: EventType.ACTIVITY_DELTA, messageId: uiId,
|
|
544
|
+
activityType: 'json-render-spec', patch: [patch] } as BaseEvent),
|
|
545
|
+
});
|
|
546
|
+
const result = streamText({
|
|
547
|
+
model: anthropic('claude-sonnet-5'),
|
|
548
|
+
system: catalog.prompt({ mode: 'inline' }),
|
|
549
|
+
messages: toModelMessages(messages), // AG-UI user/assistant messages → your model's format
|
|
550
|
+
});
|
|
551
|
+
for await (const chunk of result.textStream) parser.push(chunk);
|
|
552
|
+
parser.flush();
|
|
553
|
+
|
|
554
|
+
send({ type: EventType.TEXT_MESSAGE_END, messageId: textId } as BaseEvent);
|
|
555
|
+
send({ type: EventType.RUN_FINISHED, threadId, runId } as BaseEvent);
|
|
556
|
+
res.end();
|
|
557
|
+
});
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
`projects/ngx-json-render/ag-ui/src/ag-ui.spec.ts` runs a real `HttpAgent`
|
|
561
|
+
against a replayed server-sent stream, through AG-UI's own decoder and event
|
|
562
|
+
checks, and renders the result.
|
|
563
|
+
|
|
473
564
|
### Supplying the transport
|
|
474
565
|
|
|
475
566
|
By default the request goes through the global `fetch`. Pass your own to add
|
|
@@ -1087,6 +1178,8 @@ MCP Apps (`ngx-json-render/mcp`): `injectJsonRenderApp`, `parseSpecFromToolResul
|
|
|
1087
1178
|
|
|
1088
1179
|
Router (`ngx-json-render/router`): `injectRouterNavigate`, and the type `RouterNavigateOptions`. Needs the optional peer `@angular/router`, which an Angular app on the router already has.
|
|
1089
1180
|
|
|
1181
|
+
AG-UI (`ngx-json-render/ag-ui`): `injectAgentUI`, `applyAgUiEvent`, `surfacesFromMessages`, `isJsonRenderSpec`, `JsonRenderActivity` (`<json-render-activity>`), `jsonRenderActivityRenderer`, `JSON_RENDER_ACTIVITY_TYPE`, and the types `AgUiAgent`, `AgUiEvent`, `AgUiMessage`, `AgUiSubscriber`, `AgUiSurface`, `AgentUIOptions`, `AgentUIReturn`, `JsonRenderActivityRendererConfig`, `JsonRenderActivityRendererOptions`. No peer: any agent and event of the right shape will do.
|
|
1182
|
+
|
|
1090
1183
|
Devtools (`ngx-json-render/devtools`): `JsonRenderDevtools` (`<json-render-devtools>`), and the types `DevtoolsEvent`, `PanelPosition`. Needs the optional peer `@json-render/devtools`.
|
|
1091
1184
|
|
|
1092
1185
|
Testing (`ngx-json-render/testing`): `renderSpec`, `renderComponent`, `recordedTransport`, `specStream`, `usageLine`.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { applyPatch, checkSpec, formatSpecCheckIssues, JsonRenderer } from 'ngx-json-render';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { signal, inject, DestroyRef, computed, input, Component } from '@angular/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `activityType` a json-render spec travels under.
|
|
7
|
+
*
|
|
8
|
+
* An agent sends the spec as an AG-UI activity: `ACTIVITY_SNAPSHOT` carries a
|
|
9
|
+
* whole spec in `content`, and `ACTIVITY_DELTA` carries RFC 6902 patches
|
|
10
|
+
* against it in `patch` — the same patches a json-render JSONL stream is made
|
|
11
|
+
* of. CopilotKit carries A2UI the same way, under `"a2ui-surface"`.
|
|
12
|
+
*
|
|
13
|
+
* The name says both the format and what `content` holds — a `Spec`, the
|
|
14
|
+
* object upstream calls a spec in its AI SDK part type `data-spec` — so a
|
|
15
|
+
* renderer for another framework can match it without reading these docs.
|
|
16
|
+
*/
|
|
17
|
+
const JSON_RENDER_ACTIVITY_TYPE = 'json-render-spec';
|
|
18
|
+
const EMPTY_SPEC = { root: '', elements: {} };
|
|
19
|
+
function isRecord(value) {
|
|
20
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether activity content has the shape of a spec. Only the shape: what the
|
|
24
|
+
* elements say is the renderer's and the finished-spec check's business.
|
|
25
|
+
*/
|
|
26
|
+
function isJsonRenderSpec(content) {
|
|
27
|
+
return (isRecord(content) &&
|
|
28
|
+
typeof content['root'] === 'string' &&
|
|
29
|
+
isRecord(content['elements']));
|
|
30
|
+
}
|
|
31
|
+
function isPatch(value) {
|
|
32
|
+
return (isRecord(value) &&
|
|
33
|
+
typeof value['op'] === 'string' &&
|
|
34
|
+
typeof value['path'] === 'string');
|
|
35
|
+
}
|
|
36
|
+
function upsert(surfaces, messageId, spec) {
|
|
37
|
+
const index = surfaces.findIndex((s) => s.messageId === messageId);
|
|
38
|
+
if (index === -1)
|
|
39
|
+
return [...surfaces, { messageId, spec }];
|
|
40
|
+
const next = [...surfaces];
|
|
41
|
+
next[index] = { messageId, spec };
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The surfaces an AG-UI message list holds, in message order.
|
|
46
|
+
*
|
|
47
|
+
* Used for `MESSAGES_SNAPSHOT` and to pick up the history an agent already
|
|
48
|
+
* has when a hook attaches to it.
|
|
49
|
+
*/
|
|
50
|
+
function surfacesFromMessages(messages, activityType = JSON_RENDER_ACTIVITY_TYPE) {
|
|
51
|
+
const surfaces = [];
|
|
52
|
+
for (const message of messages) {
|
|
53
|
+
const m = message;
|
|
54
|
+
if (m.role === 'activity' &&
|
|
55
|
+
m['activityType'] === activityType &&
|
|
56
|
+
isJsonRenderSpec(m['content'])) {
|
|
57
|
+
surfaces.push({ messageId: m.id, spec: m['content'] });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return surfaces;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fold one AG-UI event into the surfaces built so far.
|
|
64
|
+
*
|
|
65
|
+
* Returns the same array when the event does not concern json-render, so a
|
|
66
|
+
* signal holding the result only notifies on a real change. A delta applies
|
|
67
|
+
* through the same immutable patch engine as a JSONL stream: elements it does
|
|
68
|
+
* not touch keep their identity, and the renderer skips them.
|
|
69
|
+
*
|
|
70
|
+
* Two leniencies, both in the direction of rendering what arrived:
|
|
71
|
+
* - a delta for a surface no snapshot has opened starts from an empty spec,
|
|
72
|
+
* so an agent can stream patches the way a JSONL endpoint does;
|
|
73
|
+
* - a malformed patch op is dropped rather than failing the surface.
|
|
74
|
+
*/
|
|
75
|
+
function applyAgUiEvent(surfaces, event, activityType = JSON_RENDER_ACTIVITY_TYPE) {
|
|
76
|
+
const e = event;
|
|
77
|
+
switch (e.type) {
|
|
78
|
+
case 'ACTIVITY_SNAPSHOT': {
|
|
79
|
+
const messageId = e['messageId'];
|
|
80
|
+
if (typeof messageId !== 'string' || e['activityType'] !== activityType) {
|
|
81
|
+
return surfaces;
|
|
82
|
+
}
|
|
83
|
+
const content = e['content'];
|
|
84
|
+
if (!isJsonRenderSpec(content))
|
|
85
|
+
return surfaces;
|
|
86
|
+
// `replace: false` means "only if new": the client already has a
|
|
87
|
+
// version of this surface it should keep.
|
|
88
|
+
if (e['replace'] === false &&
|
|
89
|
+
surfaces.some((s) => s.messageId === messageId)) {
|
|
90
|
+
return surfaces;
|
|
91
|
+
}
|
|
92
|
+
return upsert(surfaces, messageId, content);
|
|
93
|
+
}
|
|
94
|
+
case 'ACTIVITY_DELTA': {
|
|
95
|
+
const messageId = e['messageId'];
|
|
96
|
+
const patch = e['patch'];
|
|
97
|
+
if (typeof messageId !== 'string' ||
|
|
98
|
+
e['activityType'] !== activityType ||
|
|
99
|
+
!Array.isArray(patch)) {
|
|
100
|
+
return surfaces;
|
|
101
|
+
}
|
|
102
|
+
const current = surfaces.find((s) => s.messageId === messageId)?.spec ?? EMPTY_SPEC;
|
|
103
|
+
let spec = current;
|
|
104
|
+
for (const op of patch) {
|
|
105
|
+
if (isPatch(op))
|
|
106
|
+
spec = applyPatch(spec, op);
|
|
107
|
+
}
|
|
108
|
+
return spec === current ? surfaces : upsert(surfaces, messageId, spec);
|
|
109
|
+
}
|
|
110
|
+
case 'MESSAGES_SNAPSHOT': {
|
|
111
|
+
const messages = e['messages'];
|
|
112
|
+
if (!Array.isArray(messages))
|
|
113
|
+
return surfaces;
|
|
114
|
+
// AG-UI's rule: a snapshot that carries any activity message carries
|
|
115
|
+
// all of them, and one that carries none leaves the client's alone.
|
|
116
|
+
const carriesActivities = messages.some((m) => isRecord(m) && m['role'] === 'activity');
|
|
117
|
+
if (!carriesActivities)
|
|
118
|
+
return surfaces;
|
|
119
|
+
return surfacesFromMessages(messages, activityType);
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
return surfaces;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Render what an AG-UI agent streams. Subscribes to the agent, folds every
|
|
128
|
+
* json-render activity it emits into signals, and checks each surface when
|
|
129
|
+
* the run ends — the same contract as `injectUIStream`, with the agent in
|
|
130
|
+
* place of the endpoint.
|
|
131
|
+
*
|
|
132
|
+
* The app keeps running the agent itself (`agent.runAgent()`, CopilotKit, a
|
|
133
|
+
* reconnect); the hook only listens, so it sees every run, whoever starts it.
|
|
134
|
+
* It starts from whatever surfaces are already in the agent's messages and
|
|
135
|
+
* unsubscribes on destroy.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* export class AgentPage {
|
|
140
|
+
* readonly agent = new HttpAgent({ url: '/api/agent' });
|
|
141
|
+
* readonly ui = injectAgentUI({ agent: this.agent, catalog });
|
|
142
|
+
* ask(text: string) {
|
|
143
|
+
* this.agent.addMessage({ id: crypto.randomUUID(), role: 'user', content: text });
|
|
144
|
+
* this.agent.runAgent();
|
|
145
|
+
* }
|
|
146
|
+
* }
|
|
147
|
+
* // template:
|
|
148
|
+
* // <json-render [spec]="ui.spec()" [registry]="registry" [loading]="ui.isStreaming()" />
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
function injectAgentUI(options) {
|
|
152
|
+
const activityType = options.activityType ?? JSON_RENDER_ACTIVITY_TYPE;
|
|
153
|
+
const validate = options.validate ?? 'off';
|
|
154
|
+
const checkOptions = {
|
|
155
|
+
limits: options.renderLimits ?? null,
|
|
156
|
+
catalog: options.catalog ?? null,
|
|
157
|
+
};
|
|
158
|
+
const surfaces = signal(surfacesFromMessages(options.agent.messages ?? [], activityType), ...(ngDevMode ? [{ debugName: "surfaces" }] : /* istanbul ignore next */ []));
|
|
159
|
+
const isStreaming = signal(false, ...(ngDevMode ? [{ debugName: "isStreaming" }] : /* istanbul ignore next */ []));
|
|
160
|
+
const error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
161
|
+
const issues = signal([], ...(ngDevMode ? [{ debugName: "issues" }] : /* istanbul ignore next */ []));
|
|
162
|
+
// Per run: which surfaces it changed, and whether it already failed.
|
|
163
|
+
let touched = new Set();
|
|
164
|
+
let failed = false;
|
|
165
|
+
const fail = (err) => {
|
|
166
|
+
failed = true;
|
|
167
|
+
error.set(err);
|
|
168
|
+
options.onError?.(err);
|
|
169
|
+
};
|
|
170
|
+
const finish = () => {
|
|
171
|
+
const found = [];
|
|
172
|
+
let next = surfaces();
|
|
173
|
+
for (const messageId of touched) {
|
|
174
|
+
const surface = next.find((s) => s.messageId === messageId);
|
|
175
|
+
if (!surface)
|
|
176
|
+
continue; // a later MESSAGES_SNAPSHOT dropped it
|
|
177
|
+
const check = checkSpec(surface.spec, validate, checkOptions);
|
|
178
|
+
found.push(...check.issues);
|
|
179
|
+
if (check.spec && check.spec !== surface.spec) {
|
|
180
|
+
const fixed = check.spec;
|
|
181
|
+
next = next.map((s) => s.messageId === messageId ? { messageId, spec: fixed } : s);
|
|
182
|
+
}
|
|
183
|
+
if (check.blocked || (validate === 'strict' && check.hasErrors)) {
|
|
184
|
+
fail(new Error(`Generated spec failed validation:\n${formatSpecCheckIssues(check.issues)}`));
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
options.onComplete?.(check.spec ?? surface.spec, messageId);
|
|
188
|
+
}
|
|
189
|
+
surfaces.set(next);
|
|
190
|
+
issues.set(found);
|
|
191
|
+
};
|
|
192
|
+
const subscription = options.agent.subscribe({
|
|
193
|
+
onRunInitialized() {
|
|
194
|
+
touched = new Set();
|
|
195
|
+
failed = false;
|
|
196
|
+
isStreaming.set(true);
|
|
197
|
+
error.set(null);
|
|
198
|
+
issues.set([]);
|
|
199
|
+
},
|
|
200
|
+
onEvent({ event }) {
|
|
201
|
+
const before = surfaces();
|
|
202
|
+
const after = applyAgUiEvent(before, event, activityType);
|
|
203
|
+
if (after === before)
|
|
204
|
+
return;
|
|
205
|
+
for (const surface of after) {
|
|
206
|
+
if (!before.includes(surface))
|
|
207
|
+
touched.add(surface.messageId);
|
|
208
|
+
}
|
|
209
|
+
surfaces.set(after);
|
|
210
|
+
},
|
|
211
|
+
onRunErrorEvent({ event }) {
|
|
212
|
+
fail(new Error(event.message));
|
|
213
|
+
},
|
|
214
|
+
onRunFailed({ error: err }) {
|
|
215
|
+
// A RUN_ERROR event already reported this run; the client then fails
|
|
216
|
+
// the run with the same message.
|
|
217
|
+
if (!failed)
|
|
218
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
219
|
+
},
|
|
220
|
+
onRunFinalized() {
|
|
221
|
+
if (!failed)
|
|
222
|
+
finish();
|
|
223
|
+
isStreaming.set(false);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
inject(DestroyRef).onDestroy(() => subscription.unsubscribe());
|
|
227
|
+
const spec = computed(() => surfaces().at(-1)?.spec ?? null, ...(ngDevMode ? [{ debugName: "spec" }] : /* istanbul ignore next */ []));
|
|
228
|
+
return {
|
|
229
|
+
surfaces: surfaces.asReadonly(),
|
|
230
|
+
spec,
|
|
231
|
+
isStreaming: isStreaming.asReadonly(),
|
|
232
|
+
error: error.asReadonly(),
|
|
233
|
+
issues: issues.asReadonly(),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Renders one json-render activity message. It takes the inputs every AG-UI
|
|
239
|
+
* activity renderer is given — CopilotKit Angular's `ActivityRenderer`
|
|
240
|
+
* contract — and draws `content` with `<json-render>`, which takes its
|
|
241
|
+
* registry, catalog and handlers from the nearest `provideJsonRender`.
|
|
242
|
+
*
|
|
243
|
+
* Register it with {@link jsonRenderActivityRenderer} rather than by hand.
|
|
244
|
+
*/
|
|
245
|
+
class JsonRenderActivity {
|
|
246
|
+
activityType = input(JSON_RENDER_ACTIVITY_TYPE, ...(ngDevMode ? [{ debugName: "activityType" }] : /* istanbul ignore next */ []));
|
|
247
|
+
content = input.required(...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
|
|
248
|
+
/** The AG-UI activity message; unused, accepted for the contract. */
|
|
249
|
+
message = input(...(ngDevMode ? [undefined, { debugName: "message" }] : /* istanbul ignore next */ []));
|
|
250
|
+
/** The agent that produced it; unused, accepted for the contract. */
|
|
251
|
+
agent = input(...(ngDevMode ? [undefined, { debugName: "agent" }] : /* istanbul ignore next */ []));
|
|
252
|
+
spec = computed(() => {
|
|
253
|
+
const content = this.content();
|
|
254
|
+
return isJsonRenderSpec(content) ? content : null;
|
|
255
|
+
}, ...(ngDevMode ? [{ debugName: "spec" }] : /* istanbul ignore next */ []));
|
|
256
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderActivity, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
257
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: JsonRenderActivity, isStandalone: true, selector: "json-render-activity", inputs: { activityType: { classPropertyName: "activityType", publicName: "activityType", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<json-render [spec]="spec()" />`, isInline: true, dependencies: [{ kind: "component", type: JsonRenderer, selector: "json-render", inputs: ["spec", "registry", "loading", "fallback", "validate", "renderLimits", "catalog", "state", "store", "handlers", "onAction", "navigate", "validationFunctions", "functions", "directives"], outputs: ["stateChange"] }] });
|
|
258
|
+
}
|
|
259
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderActivity, decorators: [{
|
|
260
|
+
type: Component,
|
|
261
|
+
args: [{
|
|
262
|
+
selector: 'json-render-activity',
|
|
263
|
+
imports: [JsonRenderer],
|
|
264
|
+
template: `<json-render [spec]="spec()" />`,
|
|
265
|
+
}]
|
|
266
|
+
}], propDecorators: { activityType: [{ type: i0.Input, args: [{ isSignal: true, alias: "activityType", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: false }] }] } });
|
|
267
|
+
/**
|
|
268
|
+
* Teach a CopilotKit Angular app to render json-render activities:
|
|
269
|
+
*
|
|
270
|
+
* ```ts
|
|
271
|
+
* providers: [
|
|
272
|
+
* provideJsonRender({ registry }),
|
|
273
|
+
* provideCopilotKit({
|
|
274
|
+
* runtimeUrl: '/api/copilotkit',
|
|
275
|
+
* renderActivityMessages: [jsonRenderActivityRenderer()],
|
|
276
|
+
* }),
|
|
277
|
+
* ]
|
|
278
|
+
* ```
|
|
279
|
+
*
|
|
280
|
+
* Content that is not a spec is rejected by the config's schema, so CopilotKit
|
|
281
|
+
* skips the message with a warning instead of mounting an empty renderer.
|
|
282
|
+
*/
|
|
283
|
+
function jsonRenderActivityRenderer(options = {}) {
|
|
284
|
+
return {
|
|
285
|
+
activityType: options.activityType ?? JSON_RENDER_ACTIVITY_TYPE,
|
|
286
|
+
...(options.agentId !== undefined ? { agentId: options.agentId } : {}),
|
|
287
|
+
content: {
|
|
288
|
+
safeParse: (content) => isJsonRenderSpec(content)
|
|
289
|
+
? { success: true, data: content }
|
|
290
|
+
: {
|
|
291
|
+
success: false,
|
|
292
|
+
error: new Error('Activity content is not a json-render spec: expected { root: string, elements: object }.'),
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
component: options.component ?? JsonRenderActivity,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/*
|
|
300
|
+
* Public API Surface of ngx-json-render/ag-ui
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Generated bundle index. Do not edit.
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
export { JSON_RENDER_ACTIVITY_TYPE, JsonRenderActivity, applyAgUiEvent, injectAgentUI, isJsonRenderSpec, jsonRenderActivityRenderer, surfacesFromMessages };
|
|
308
|
+
//# sourceMappingURL=ngx-json-render-ag-ui.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-json-render-ag-ui.mjs","sources":["../../../projects/ngx-json-render/ag-ui/src/events.ts","../../../projects/ngx-json-render/ag-ui/src/agent-ui.ts","../../../projects/ngx-json-render/ag-ui/src/json-render-activity.ts","../../../projects/ngx-json-render/ag-ui/src/public-api.ts","../../../projects/ngx-json-render/ag-ui/src/ngx-json-render-ag-ui.ts"],"sourcesContent":["import type { JsonPatch, Spec } from '@json-render/core';\nimport { applyPatch } from 'ngx-json-render';\n\n/**\n * The `activityType` a json-render spec travels under.\n *\n * An agent sends the spec as an AG-UI activity: `ACTIVITY_SNAPSHOT` carries a\n * whole spec in `content`, and `ACTIVITY_DELTA` carries RFC 6902 patches\n * against it in `patch` — the same patches a json-render JSONL stream is made\n * of. CopilotKit carries A2UI the same way, under `\"a2ui-surface\"`.\n *\n * The name says both the format and what `content` holds — a `Spec`, the\n * object upstream calls a spec in its AI SDK part type `data-spec` — so a\n * renderer for another framework can match it without reading these docs.\n */\nexport const JSON_RENDER_ACTIVITY_TYPE = 'json-render-spec';\n\n/**\n * The part of an AG-UI event this entry point reads.\n *\n * Structural on purpose: `@ag-ui/core`'s `EventType` is a string enum, so its\n * events fit a `string` here, and nothing below needs the package at runtime\n * or pins its version.\n */\nexport interface AgUiEvent {\n readonly type: string;\n}\n\n/** The part of an AG-UI message this entry point reads. */\nexport interface AgUiMessage {\n readonly id: string;\n readonly role: string;\n}\n\n/** One spec an agent is building, keyed by its activity message. */\nexport interface AgUiSurface {\n /** The activity's `messageId`; one run can build several surfaces. */\n readonly messageId: string;\n readonly spec: Spec;\n}\n\nconst EMPTY_SPEC: Spec = { root: '', elements: {} };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Whether activity content has the shape of a spec. Only the shape: what the\n * elements say is the renderer's and the finished-spec check's business.\n */\nexport function isJsonRenderSpec(content: unknown): content is Spec {\n return (\n isRecord(content) &&\n typeof content['root'] === 'string' &&\n isRecord(content['elements'])\n );\n}\n\nfunction isPatch(value: unknown): value is JsonPatch {\n return (\n isRecord(value) &&\n typeof value['op'] === 'string' &&\n typeof value['path'] === 'string'\n );\n}\n\nfunction upsert(\n surfaces: readonly AgUiSurface[],\n messageId: string,\n spec: Spec,\n): readonly AgUiSurface[] {\n const index = surfaces.findIndex((s) => s.messageId === messageId);\n if (index === -1) return [...surfaces, { messageId, spec }];\n const next = [...surfaces];\n next[index] = { messageId, spec };\n return next;\n}\n\n/**\n * The surfaces an AG-UI message list holds, in message order.\n *\n * Used for `MESSAGES_SNAPSHOT` and to pick up the history an agent already\n * has when a hook attaches to it.\n */\nexport function surfacesFromMessages(\n messages: readonly AgUiMessage[],\n activityType: string = JSON_RENDER_ACTIVITY_TYPE,\n): readonly AgUiSurface[] {\n const surfaces: AgUiSurface[] = [];\n for (const message of messages) {\n const m = message as AgUiMessage & Record<string, unknown>;\n if (\n m.role === 'activity' &&\n m['activityType'] === activityType &&\n isJsonRenderSpec(m['content'])\n ) {\n surfaces.push({ messageId: m.id, spec: m['content'] });\n }\n }\n return surfaces;\n}\n\n/**\n * Fold one AG-UI event into the surfaces built so far.\n *\n * Returns the same array when the event does not concern json-render, so a\n * signal holding the result only notifies on a real change. A delta applies\n * through the same immutable patch engine as a JSONL stream: elements it does\n * not touch keep their identity, and the renderer skips them.\n *\n * Two leniencies, both in the direction of rendering what arrived:\n * - a delta for a surface no snapshot has opened starts from an empty spec,\n * so an agent can stream patches the way a JSONL endpoint does;\n * - a malformed patch op is dropped rather than failing the surface.\n */\nexport function applyAgUiEvent(\n surfaces: readonly AgUiSurface[],\n event: AgUiEvent,\n activityType: string = JSON_RENDER_ACTIVITY_TYPE,\n): readonly AgUiSurface[] {\n const e = event as AgUiEvent & Record<string, unknown>;\n switch (e.type) {\n case 'ACTIVITY_SNAPSHOT': {\n const messageId = e['messageId'];\n if (typeof messageId !== 'string' || e['activityType'] !== activityType) {\n return surfaces;\n }\n const content = e['content'];\n if (!isJsonRenderSpec(content)) return surfaces;\n // `replace: false` means \"only if new\": the client already has a\n // version of this surface it should keep.\n if (\n e['replace'] === false &&\n surfaces.some((s) => s.messageId === messageId)\n ) {\n return surfaces;\n }\n return upsert(surfaces, messageId, content);\n }\n case 'ACTIVITY_DELTA': {\n const messageId = e['messageId'];\n const patch = e['patch'];\n if (\n typeof messageId !== 'string' ||\n e['activityType'] !== activityType ||\n !Array.isArray(patch)\n ) {\n return surfaces;\n }\n const current =\n surfaces.find((s) => s.messageId === messageId)?.spec ?? EMPTY_SPEC;\n let spec = current;\n for (const op of patch) {\n if (isPatch(op)) spec = applyPatch(spec, op);\n }\n return spec === current ? surfaces : upsert(surfaces, messageId, spec);\n }\n case 'MESSAGES_SNAPSHOT': {\n const messages = e['messages'];\n if (!Array.isArray(messages)) return surfaces;\n // AG-UI's rule: a snapshot that carries any activity message carries\n // all of them, and one that carries none leaves the client's alone.\n const carriesActivities = messages.some(\n (m) => isRecord(m) && m['role'] === 'activity',\n );\n if (!carriesActivities) return surfaces;\n return surfacesFromMessages(messages as AgUiMessage[], activityType);\n }\n default:\n return surfaces;\n }\n}\n","import {\n DestroyRef,\n type Signal,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport type { Spec } from '@json-render/core';\nimport {\n type RenderLimits,\n type SpecCatalog,\n type SpecCheckIssue,\n type SpecValidationMode,\n checkSpec,\n formatSpecCheckIssues,\n} from 'ngx-json-render';\nimport {\n type AgUiEvent,\n type AgUiMessage,\n type AgUiSurface,\n JSON_RENDER_ACTIVITY_TYPE,\n applyAgUiEvent,\n surfacesFromMessages,\n} from './events';\n\n/**\n * The callbacks of an AG-UI subscriber this entry point uses — a subset of\n * `@ag-ui/client`'s `AgentSubscriber`.\n */\nexport interface AgUiSubscriber {\n onRunInitialized?(): void;\n onEvent?(params: { event: AgUiEvent }): void;\n onRunErrorEvent?(params: { event: { message: string } }): void;\n onRunFailed?(params: { error: Error }): void;\n onRunFinalized?(): void;\n}\n\n/**\n * What {@link injectAgentUI} needs of an agent. Any `@ag-ui/client` agent —\n * `HttpAgent`, a subclass of `AbstractAgent`, the agent CopilotKit hands out —\n * already has this shape.\n */\nexport interface AgUiAgent {\n readonly messages?: readonly AgUiMessage[];\n subscribe(subscriber: AgUiSubscriber): { unsubscribe(): void };\n}\n\n/** Options for {@link injectAgentUI}. */\nexport interface AgentUIOptions {\n /** The agent whose runs build the UI. The app runs it; the hook listens. */\n agent: AgUiAgent;\n /** Defaults to {@link JSON_RENDER_ACTIVITY_TYPE}. */\n activityType?: string;\n /**\n * Called once per surface a run touched, after the finished-spec check.\n * Skipped for a run that failed, and for a surface the check rejected.\n */\n onComplete?: (spec: Spec, messageId: string) => void;\n /** Called when a run fails or a finished surface fails the check. */\n onError?: (error: Error) => void;\n /** As for `injectUIStream`: checked once per surface, when the run ends. */\n validate?: SpecValidationMode;\n /** As for `injectUIStream`; enforced whatever `validate` is. */\n renderLimits?: RenderLimits | null;\n /** As for `injectUIStream`: lets `validate` check types and props. */\n catalog?: SpecCatalog | null;\n}\n\n/** Return type of {@link injectAgentUI}. */\nexport interface AgentUIReturn {\n /** Every json-render surface the agent has built, in order of appearance. */\n readonly surfaces: Signal<readonly AgUiSurface[]>;\n /** The most recently opened surface's spec — the one most apps render. */\n readonly spec: Signal<Spec | null>;\n /** Whether a run of the agent is in progress. */\n readonly isStreaming: Signal<boolean>;\n /** The last run's error, if any. */\n readonly error: Signal<Error | null>;\n /** What the check found in the surfaces the last run finished. */\n readonly issues: Signal<readonly SpecCheckIssue[]>;\n}\n\n/**\n * Render what an AG-UI agent streams. Subscribes to the agent, folds every\n * json-render activity it emits into signals, and checks each surface when\n * the run ends — the same contract as `injectUIStream`, with the agent in\n * place of the endpoint.\n *\n * The app keeps running the agent itself (`agent.runAgent()`, CopilotKit, a\n * reconnect); the hook only listens, so it sees every run, whoever starts it.\n * It starts from whatever surfaces are already in the agent's messages and\n * unsubscribes on destroy.\n *\n * @example\n * ```ts\n * export class AgentPage {\n * readonly agent = new HttpAgent({ url: '/api/agent' });\n * readonly ui = injectAgentUI({ agent: this.agent, catalog });\n * ask(text: string) {\n * this.agent.addMessage({ id: crypto.randomUUID(), role: 'user', content: text });\n * this.agent.runAgent();\n * }\n * }\n * // template:\n * // <json-render [spec]=\"ui.spec()\" [registry]=\"registry\" [loading]=\"ui.isStreaming()\" />\n * ```\n */\nexport function injectAgentUI(options: AgentUIOptions): AgentUIReturn {\n const activityType = options.activityType ?? JSON_RENDER_ACTIVITY_TYPE;\n const validate = options.validate ?? 'off';\n const checkOptions = {\n limits: options.renderLimits ?? null,\n catalog: options.catalog ?? null,\n };\n\n const surfaces = signal<readonly AgUiSurface[]>(\n surfacesFromMessages(options.agent.messages ?? [], activityType),\n );\n const isStreaming = signal(false);\n const error = signal<Error | null>(null);\n const issues = signal<readonly SpecCheckIssue[]>([]);\n\n // Per run: which surfaces it changed, and whether it already failed.\n let touched = new Set<string>();\n let failed = false;\n\n const fail = (err: Error) => {\n failed = true;\n error.set(err);\n options.onError?.(err);\n };\n\n const finish = () => {\n const found: SpecCheckIssue[] = [];\n let next = surfaces();\n for (const messageId of touched) {\n const surface = next.find((s) => s.messageId === messageId);\n if (!surface) continue; // a later MESSAGES_SNAPSHOT dropped it\n const check = checkSpec(surface.spec, validate, checkOptions);\n found.push(...check.issues);\n if (check.spec && check.spec !== surface.spec) {\n const fixed = check.spec;\n next = next.map((s) =>\n s.messageId === messageId ? { messageId, spec: fixed } : s,\n );\n }\n if (check.blocked || (validate === 'strict' && check.hasErrors)) {\n fail(\n new Error(\n `Generated spec failed validation:\\n${formatSpecCheckIssues(check.issues)}`,\n ),\n );\n continue;\n }\n options.onComplete?.(check.spec ?? surface.spec, messageId);\n }\n surfaces.set(next);\n issues.set(found);\n };\n\n const subscription = options.agent.subscribe({\n onRunInitialized() {\n touched = new Set();\n failed = false;\n isStreaming.set(true);\n error.set(null);\n issues.set([]);\n },\n onEvent({ event }) {\n const before = surfaces();\n const after = applyAgUiEvent(before, event, activityType);\n if (after === before) return;\n for (const surface of after) {\n if (!before.includes(surface)) touched.add(surface.messageId);\n }\n surfaces.set(after);\n },\n onRunErrorEvent({ event }) {\n fail(new Error(event.message));\n },\n onRunFailed({ error: err }) {\n // A RUN_ERROR event already reported this run; the client then fails\n // the run with the same message.\n if (!failed) fail(err instanceof Error ? err : new Error(String(err)));\n },\n onRunFinalized() {\n if (!failed) finish();\n isStreaming.set(false);\n },\n });\n\n inject(DestroyRef).onDestroy(() => subscription.unsubscribe());\n\n const spec = computed(() => surfaces().at(-1)?.spec ?? null);\n\n return {\n surfaces: surfaces.asReadonly(),\n spec,\n isStreaming: isStreaming.asReadonly(),\n error: error.asReadonly(),\n issues: issues.asReadonly(),\n };\n}\n","import { Component, type Type, computed, input } from '@angular/core';\nimport type { Spec } from '@json-render/core';\nimport { JsonRenderer } from 'ngx-json-render';\nimport { JSON_RENDER_ACTIVITY_TYPE, isJsonRenderSpec } from './events';\n\n/**\n * Renders one json-render activity message. It takes the inputs every AG-UI\n * activity renderer is given — CopilotKit Angular's `ActivityRenderer`\n * contract — and draws `content` with `<json-render>`, which takes its\n * registry, catalog and handlers from the nearest `provideJsonRender`.\n *\n * Register it with {@link jsonRenderActivityRenderer} rather than by hand.\n */\n@Component({\n selector: 'json-render-activity',\n imports: [JsonRenderer],\n template: `<json-render [spec]=\"spec()\" />`,\n})\nexport class JsonRenderActivity {\n readonly activityType = input<string>(JSON_RENDER_ACTIVITY_TYPE);\n readonly content = input.required<unknown>();\n /** The AG-UI activity message; unused, accepted for the contract. */\n readonly message = input<unknown>();\n /** The agent that produced it; unused, accepted for the contract. */\n readonly agent = input<unknown>();\n\n protected readonly spec = computed<Spec | null>(() => {\n const content = this.content();\n return isJsonRenderSpec(content) ? content : null;\n });\n}\n\n/** Options for {@link jsonRenderActivityRenderer}. */\nexport interface JsonRenderActivityRendererOptions {\n /** Defaults to {@link JSON_RENDER_ACTIVITY_TYPE}. */\n activityType?: string;\n /** Limit the renderer to one agent's activities. */\n agentId?: string;\n /** A component of your own in place of {@link JsonRenderActivity}. */\n component?: Type<unknown>;\n}\n\n/**\n * An activity renderer config in the shape CopilotKit Angular's\n * `renderActivityMessages` takes, matched structurally so this package does\n * not depend on CopilotKit.\n */\nexport interface JsonRenderActivityRendererConfig {\n activityType: string;\n agentId?: string;\n content: {\n safeParse(\n content: unknown,\n ): { success: true; data: Spec } | { success: false; error?: unknown };\n };\n component: Type<any>;\n}\n\n/**\n * Teach a CopilotKit Angular app to render json-render activities:\n *\n * ```ts\n * providers: [\n * provideJsonRender({ registry }),\n * provideCopilotKit({\n * runtimeUrl: '/api/copilotkit',\n * renderActivityMessages: [jsonRenderActivityRenderer()],\n * }),\n * ]\n * ```\n *\n * Content that is not a spec is rejected by the config's schema, so CopilotKit\n * skips the message with a warning instead of mounting an empty renderer.\n */\nexport function jsonRenderActivityRenderer(\n options: JsonRenderActivityRendererOptions = {},\n): JsonRenderActivityRendererConfig {\n return {\n activityType: options.activityType ?? JSON_RENDER_ACTIVITY_TYPE,\n ...(options.agentId !== undefined ? { agentId: options.agentId } : {}),\n content: {\n safeParse: (content) =>\n isJsonRenderSpec(content)\n ? { success: true, data: content }\n : {\n success: false,\n error: new Error(\n 'Activity content is not a json-render spec: expected { root: string, elements: object }.',\n ),\n },\n },\n component: options.component ?? JsonRenderActivity,\n };\n}\n","/*\n * Public API Surface of ngx-json-render/ag-ui\n */\n\nexport {\n JSON_RENDER_ACTIVITY_TYPE,\n applyAgUiEvent,\n isJsonRenderSpec,\n surfacesFromMessages,\n type AgUiEvent,\n type AgUiMessage,\n type AgUiSurface,\n} from './events';\nexport {\n injectAgentUI,\n type AgUiAgent,\n type AgUiSubscriber,\n type AgentUIOptions,\n type AgentUIReturn,\n} from './agent-ui';\nexport {\n JsonRenderActivity,\n jsonRenderActivityRenderer,\n type JsonRenderActivityRendererConfig,\n type JsonRenderActivityRendererOptions,\n} from './json-render-activity';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -238,10 +238,10 @@ class JsonRenderDevtools {
|
|
|
238
238
|
this.events = null;
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
242
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
241
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderDevtools, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
242
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: JsonRenderDevtools, isStandalone: true, selector: "json-render-devtools", inputs: { renderer: { classPropertyName: "renderer", publicName: "renderer", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, chat: { classPropertyName: "chat", publicName: "chat", isSignal: true, isRequired: false, transformFunction: null }, initialOpen: { classPropertyName: "initialOpen", publicName: "initialOpen", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, hotkey: { classPropertyName: "hotkey", publicName: "hotkey", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, reserveSpace: { classPropertyName: "reserveSpace", publicName: "reserveSpace", isSignal: true, isRequired: false, transformFunction: null }, allowDockToggle: { classPropertyName: "allowDockToggle", publicName: "allowDockToggle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
243
243
|
}
|
|
244
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
244
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderDevtools, decorators: [{
|
|
245
245
|
type: Component,
|
|
246
246
|
args: [{
|
|
247
247
|
selector: 'json-render-devtools',
|
|
@@ -256,14 +256,14 @@ class JrComponentTestHost {
|
|
|
256
256
|
parent = inject(Injector);
|
|
257
257
|
component = signal(null, ...(ngDevMode ? [{ debugName: "component" }] : /* istanbul ignore next */ []));
|
|
258
258
|
injector = signal(this.parent, ...(ngDevMode ? [{ debugName: "injector" }] : /* istanbul ignore next */ []));
|
|
259
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
260
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
259
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrComponentTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
260
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: JrComponentTestHost, isStandalone: true, selector: "jr-component-test-host", ngImport: i0, template: `
|
|
261
261
|
@if (component(); as type) {
|
|
262
262
|
<ng-container *ngComponentOutlet="type; injector: injector()" />
|
|
263
263
|
}
|
|
264
264
|
`, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
265
265
|
}
|
|
266
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
266
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrComponentTestHost, decorators: [{
|
|
267
267
|
type: Component,
|
|
268
268
|
args: [{
|
|
269
269
|
selector: 'jr-component-test-host',
|
|
@@ -420,8 +420,8 @@ class JrTestHost {
|
|
|
420
420
|
validationFunctions = signal(undefined, ...(ngDevMode ? [{ debugName: "validationFunctions" }] : /* istanbul ignore next */ []));
|
|
421
421
|
directives = signal(undefined, ...(ngDevMode ? [{ debugName: "directives" }] : /* istanbul ignore next */ []));
|
|
422
422
|
record = () => { };
|
|
423
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
424
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
423
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
424
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: JrTestHost, isStandalone: true, selector: "jr-test-host", ngImport: i0, template: `
|
|
425
425
|
<json-render
|
|
426
426
|
[spec]="spec()"
|
|
427
427
|
[registry]="registry()"
|
|
@@ -439,7 +439,7 @@ class JrTestHost {
|
|
|
439
439
|
/>
|
|
440
440
|
`, isInline: true, dependencies: [{ kind: "component", type: JsonRenderer, selector: "json-render", inputs: ["spec", "registry", "loading", "fallback", "validate", "renderLimits", "catalog", "state", "store", "handlers", "onAction", "navigate", "validationFunctions", "functions", "directives"], outputs: ["stateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
441
441
|
}
|
|
442
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
442
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrTestHost, decorators: [{
|
|
443
443
|
type: Component,
|
|
444
444
|
args: [{
|
|
445
445
|
selector: 'jr-test-host',
|
|
@@ -47,10 +47,10 @@ class JsonRenderRootContext {
|
|
|
47
47
|
return undefined;
|
|
48
48
|
return typeof raw === 'function' ? { component: raw } : raw;
|
|
49
49
|
}
|
|
50
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
51
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
50
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderRootContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
51
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderRootContext });
|
|
52
52
|
}
|
|
53
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
53
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderRootContext, decorators: [{
|
|
54
54
|
type: Injectable
|
|
55
55
|
}] });
|
|
56
56
|
|
|
@@ -284,10 +284,10 @@ class JsonRenderStateService {
|
|
|
284
284
|
listener(changes);
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
288
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
287
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
288
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderStateService });
|
|
289
289
|
}
|
|
290
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
290
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderStateService, decorators: [{
|
|
291
291
|
type: Injectable
|
|
292
292
|
}], ctorParameters: () => [] });
|
|
293
293
|
/**
|
|
@@ -538,10 +538,10 @@ class JsonRenderValidationService {
|
|
|
538
538
|
}
|
|
539
539
|
return allValid;
|
|
540
540
|
}
|
|
541
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
542
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
541
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderValidationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
542
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderValidationService });
|
|
543
543
|
}
|
|
544
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
544
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderValidationService, decorators: [{
|
|
545
545
|
type: Injectable
|
|
546
546
|
}] });
|
|
547
547
|
/** Inject the validation service of the nearest `<json-render>` renderer. */
|
|
@@ -904,10 +904,10 @@ class JsonRenderActionsService {
|
|
|
904
904
|
this._loadingActions.set(next);
|
|
905
905
|
}
|
|
906
906
|
}
|
|
907
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
908
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
907
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderActionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
908
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderActionsService });
|
|
909
909
|
}
|
|
910
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
910
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderActionsService, decorators: [{
|
|
911
911
|
type: Injectable
|
|
912
912
|
}] });
|
|
913
913
|
/** Inject the actions service of the nearest `<json-render>` renderer. */
|
|
@@ -1031,8 +1031,8 @@ class JrConfirmDialog {
|
|
|
1031
1031
|
cancel.focus();
|
|
1032
1032
|
}
|
|
1033
1033
|
}
|
|
1034
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1035
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.
|
|
1034
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrConfirmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1035
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.25", type: JrConfirmDialog, isStandalone: true, selector: "jr-confirm-dialog", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { confirmed: "confirmed", cancelled: "cancelled" }, host: { listeners: { "keydown.escape": "cancelled.emit()" } }, viewQueries: [{ propertyName: "cancelButton", first: true, predicate: ["cancel"], descendants: true, isSignal: true }, { propertyName: "confirmButton", first: true, predicate: ["confirm"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1036
1036
|
<div class="jr-confirm-scrim" (click)="cancelled.emit()">
|
|
1037
1037
|
<div
|
|
1038
1038
|
class="jr-confirm-panel"
|
|
@@ -1063,7 +1063,7 @@ class JrConfirmDialog {
|
|
|
1063
1063
|
</div>
|
|
1064
1064
|
`, isInline: true, styles: [":host{--jr-confirm-scrim-default: rgba(0, 0, 0, .5);--jr-confirm-surface-default: #ffffff;--jr-confirm-ink-default: #111827;--jr-confirm-muted-default: #6b7280;--jr-confirm-border-default: #d1d5db;--jr-confirm-accent-default: #3b82f6;--jr-confirm-danger-default: #dc2626;--jr-confirm-on-accent-default: #ffffff}@media(prefers-color-scheme:dark){:host{--jr-confirm-scrim-default: rgba(0, 0, 0, .65);--jr-confirm-surface-default: #1f2937;--jr-confirm-ink-default: #f3f4f6;--jr-confirm-muted-default: #9ca3af;--jr-confirm-border-default: #4b5563;--jr-confirm-accent-default: #60a5fa;--jr-confirm-danger-default: #f87171;--jr-confirm-on-accent-default: #111827}}.jr-confirm-scrim{position:fixed;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background-color:var(--jr-confirm-scrim, var(--jr-confirm-scrim-default))}.jr-confirm-panel{width:100%;max-width:400px;padding:24px;border-radius:var(--jr-confirm-radius, 8px);background-color:var(--jr-confirm-surface, var(--jr-confirm-surface-default));color:var(--jr-confirm-ink, var(--jr-confirm-ink-default));box-shadow:0 20px 25px -5px #00000040}.jr-confirm-title{margin:0 0 8px;font-size:18px;font-weight:600}.jr-confirm-message{margin:0 0 24px;color:var(--jr-confirm-muted, var(--jr-confirm-muted-default))}.jr-confirm-actions{display:flex;gap:12px;justify-content:flex-end}.jr-confirm-actions button{padding:8px 16px;border-radius:6px;font:inherit;cursor:pointer}.jr-confirm-cancel{border:1px solid var(--jr-confirm-border, var(--jr-confirm-border-default));background-color:transparent;color:inherit}.jr-confirm-confirm{border:none;background-color:var(--jr-confirm-accent, var(--jr-confirm-accent-default));color:var(--jr-confirm-on-accent, var(--jr-confirm-on-accent-default))}.jr-confirm-confirm.jr-confirm-danger{background-color:var(--jr-confirm-danger, var(--jr-confirm-danger-default))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1065
1065
|
}
|
|
1066
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1066
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrConfirmDialog, decorators: [{
|
|
1067
1067
|
type: Component,
|
|
1068
1068
|
args: [{ selector: 'jr-confirm-dialog', changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1069
1069
|
'(keydown.escape)': 'cancelled.emit()',
|
|
@@ -2349,8 +2349,8 @@ class JrElement {
|
|
|
2349
2349
|
bound: true,
|
|
2350
2350
|
};
|
|
2351
2351
|
}
|
|
2352
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2353
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2352
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrElement, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2353
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: JrElement, isStandalone: true, selector: "jr-element", inputs: { elementKey: { classPropertyName: "elementKey", publicName: "elementKey", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
2354
2354
|
@if (!refusal() && rawElement() && visible() && component()) {
|
|
2355
2355
|
@if (devtoolsKey(); as dk) {
|
|
2356
2356
|
<span [attr.data-jr-key]="dk" style="display: contents">
|
|
@@ -2362,7 +2362,7 @@ class JrElement {
|
|
|
2362
2362
|
}
|
|
2363
2363
|
`, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2364
2364
|
}
|
|
2365
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2365
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrElement, decorators: [{
|
|
2366
2366
|
type: Component,
|
|
2367
2367
|
args: [{ selector: 'jr-element', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgComponentOutlet], template: `
|
|
2368
2368
|
@if (!refusal() && rawElement() && visible() && component()) {
|
|
@@ -2820,8 +2820,8 @@ class JsonRenderer {
|
|
|
2820
2820
|
parent: this.injector,
|
|
2821
2821
|
});
|
|
2822
2822
|
}, ...(ngDevMode ? [{ debugName: "confirmInjector" }] : /* istanbul ignore next */ []));
|
|
2823
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2824
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
2823
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2824
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: JsonRenderer, isStandalone: true, selector: "json-render", inputs: { spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: true, transformFunction: null }, registry: { classPropertyName: "registry", publicName: "registry", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, fallback: { classPropertyName: "fallback", publicName: "fallback", isSignal: true, isRequired: false, transformFunction: null }, validate: { classPropertyName: "validate", publicName: "validate", isSignal: true, isRequired: false, transformFunction: null }, renderLimits: { classPropertyName: "renderLimits", publicName: "renderLimits", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null }, onAction: { classPropertyName: "onAction", publicName: "onAction", isSignal: true, isRequired: false, transformFunction: null }, navigate: { classPropertyName: "navigate", publicName: "navigate", isSignal: true, isRequired: false, transformFunction: null }, validationFunctions: { classPropertyName: "validationFunctions", publicName: "validationFunctions", isSignal: true, isRequired: false, transformFunction: null }, functions: { classPropertyName: "functions", publicName: "functions", isSignal: true, isRequired: false, transformFunction: null }, directives: { classPropertyName: "directives", publicName: "directives", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stateChange: "stateChange" }, providers: [
|
|
2825
2825
|
JsonRenderRootContext,
|
|
2826
2826
|
JsonRenderStateService,
|
|
2827
2827
|
JsonRenderValidationService,
|
|
@@ -2845,7 +2845,7 @@ class JsonRenderer {
|
|
|
2845
2845
|
}
|
|
2846
2846
|
`, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "component", type: JrElement, selector: "jr-element", inputs: ["elementKey"] }, { kind: "component", type: JrConfirmDialog, selector: "jr-confirm-dialog", inputs: ["config"], outputs: ["confirmed", "cancelled"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2847
2847
|
}
|
|
2848
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2848
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderer, decorators: [{
|
|
2849
2849
|
type: Component,
|
|
2850
2850
|
args: [{ selector: 'json-render', changeDetection: ChangeDetectionStrategy.OnPush, imports: [JrElement, JrConfirmDialog, NgComponentOutlet], providers: [
|
|
2851
2851
|
JsonRenderRootContext,
|
|
@@ -2882,12 +2882,12 @@ class JrRepeatScope {
|
|
|
2882
2882
|
item = input.required(...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
|
|
2883
2883
|
index = input.required(...(ngDevMode ? [{ debugName: "index" }] : /* istanbul ignore next */ []));
|
|
2884
2884
|
basePath = input.required(...(ngDevMode ? [{ debugName: "basePath" }] : /* istanbul ignore next */ []));
|
|
2885
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2886
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
2885
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrRepeatScope, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2886
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: JrRepeatScope, isStandalone: true, selector: "jr-repeat-scope", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null }, basePath: { classPropertyName: "basePath", publicName: "basePath", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
|
|
2887
2887
|
{ provide: REPEAT_SCOPE, useExisting: forwardRef(() => JrRepeatScope) },
|
|
2888
2888
|
], ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2889
2889
|
}
|
|
2890
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2890
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrRepeatScope, decorators: [{
|
|
2891
2891
|
type: Component,
|
|
2892
2892
|
args: [{ selector: 'jr-repeat-scope', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
2893
2893
|
{ provide: REPEAT_SCOPE, useExisting: forwardRef(() => JrRepeatScope) },
|
|
@@ -3008,8 +3008,8 @@ class JrChildren {
|
|
|
3008
3008
|
}
|
|
3009
3009
|
return index;
|
|
3010
3010
|
}
|
|
3011
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
3012
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
3011
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrChildren, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3012
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: JrChildren, isStandalone: true, selector: "jr-children", inputs: { slot: { classPropertyName: "slot", publicName: "slot", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
3013
3013
|
@if (repeat()) {
|
|
3014
3014
|
@for (item of repeatItems(); track trackItem($index, item)) {
|
|
3015
3015
|
<jr-repeat-scope
|
|
@@ -3029,7 +3029,7 @@ class JrChildren {
|
|
|
3029
3029
|
}
|
|
3030
3030
|
`, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "component", type: JrElement, selector: "jr-element", inputs: ["elementKey"] }, { kind: "component", type: JrRepeatScope, selector: "jr-repeat-scope", inputs: ["item", "index", "basePath"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3031
3031
|
}
|
|
3032
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
3032
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrChildren, decorators: [{
|
|
3033
3033
|
type: Component,
|
|
3034
3034
|
args: [{ selector: 'jr-children', changeDetection: ChangeDetectionStrategy.OnPush, imports: [JrElement, JrRepeatScope], template: `
|
|
3035
3035
|
@if (repeat()) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-json-render",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.9.4",
|
|
4
|
+
"description": "Generative UI for Angular: a json-render renderer that streams AI-generated JSON specs into real Angular components with signals.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
7
7
|
"json-render",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"ai",
|
|
11
11
|
"renderer",
|
|
12
12
|
"signals",
|
|
13
|
-
"server-driven-ui"
|
|
13
|
+
"server-driven-ui",
|
|
14
|
+
"sdui",
|
|
15
|
+
"dynamic-components"
|
|
14
16
|
],
|
|
15
17
|
"license": "Apache-2.0",
|
|
16
18
|
"repository": {
|
|
@@ -63,6 +65,10 @@
|
|
|
63
65
|
"types": "./types/ngx-json-render.d.ts",
|
|
64
66
|
"default": "./fesm2022/ngx-json-render.mjs"
|
|
65
67
|
},
|
|
68
|
+
"./ag-ui": {
|
|
69
|
+
"types": "./types/ngx-json-render-ag-ui.d.ts",
|
|
70
|
+
"default": "./fesm2022/ngx-json-render-ag-ui.mjs"
|
|
71
|
+
},
|
|
66
72
|
"./devtools": {
|
|
67
73
|
"types": "./types/ngx-json-render-devtools.d.ts",
|
|
68
74
|
"default": "./fesm2022/ngx-json-render-devtools.mjs"
|
|
@@ -32,7 +32,7 @@ function ngAdd() {
|
|
|
32
32
|
'ngx-json-render is ready. Next: describe your components in a catalog,',
|
|
33
33
|
`register them, and render a spec with <json-render> — see ${README}`,
|
|
34
34
|
'No components of your own yet? `ng add ngx-json-render-material` adds',
|
|
35
|
-
'
|
|
35
|
+
'33 ready-made Angular Material ones.',
|
|
36
36
|
].join('\n'));
|
|
37
37
|
return (0, schematics_1.chain)(rules);
|
|
38
38
|
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { Spec } from '@json-render/core';
|
|
2
|
+
import * as _angular_core from '@angular/core';
|
|
3
|
+
import { Signal, Type } from '@angular/core';
|
|
4
|
+
import { SpecValidationMode, RenderLimits, SpecCatalog, SpecCheckIssue } from 'ngx-json-render';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The `activityType` a json-render spec travels under.
|
|
8
|
+
*
|
|
9
|
+
* An agent sends the spec as an AG-UI activity: `ACTIVITY_SNAPSHOT` carries a
|
|
10
|
+
* whole spec in `content`, and `ACTIVITY_DELTA` carries RFC 6902 patches
|
|
11
|
+
* against it in `patch` — the same patches a json-render JSONL stream is made
|
|
12
|
+
* of. CopilotKit carries A2UI the same way, under `"a2ui-surface"`.
|
|
13
|
+
*
|
|
14
|
+
* The name says both the format and what `content` holds — a `Spec`, the
|
|
15
|
+
* object upstream calls a spec in its AI SDK part type `data-spec` — so a
|
|
16
|
+
* renderer for another framework can match it without reading these docs.
|
|
17
|
+
*/
|
|
18
|
+
declare const JSON_RENDER_ACTIVITY_TYPE = "json-render-spec";
|
|
19
|
+
/**
|
|
20
|
+
* The part of an AG-UI event this entry point reads.
|
|
21
|
+
*
|
|
22
|
+
* Structural on purpose: `@ag-ui/core`'s `EventType` is a string enum, so its
|
|
23
|
+
* events fit a `string` here, and nothing below needs the package at runtime
|
|
24
|
+
* or pins its version.
|
|
25
|
+
*/
|
|
26
|
+
interface AgUiEvent {
|
|
27
|
+
readonly type: string;
|
|
28
|
+
}
|
|
29
|
+
/** The part of an AG-UI message this entry point reads. */
|
|
30
|
+
interface AgUiMessage {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly role: string;
|
|
33
|
+
}
|
|
34
|
+
/** One spec an agent is building, keyed by its activity message. */
|
|
35
|
+
interface AgUiSurface {
|
|
36
|
+
/** The activity's `messageId`; one run can build several surfaces. */
|
|
37
|
+
readonly messageId: string;
|
|
38
|
+
readonly spec: Spec;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether activity content has the shape of a spec. Only the shape: what the
|
|
42
|
+
* elements say is the renderer's and the finished-spec check's business.
|
|
43
|
+
*/
|
|
44
|
+
declare function isJsonRenderSpec(content: unknown): content is Spec;
|
|
45
|
+
/**
|
|
46
|
+
* The surfaces an AG-UI message list holds, in message order.
|
|
47
|
+
*
|
|
48
|
+
* Used for `MESSAGES_SNAPSHOT` and to pick up the history an agent already
|
|
49
|
+
* has when a hook attaches to it.
|
|
50
|
+
*/
|
|
51
|
+
declare function surfacesFromMessages(messages: readonly AgUiMessage[], activityType?: string): readonly AgUiSurface[];
|
|
52
|
+
/**
|
|
53
|
+
* Fold one AG-UI event into the surfaces built so far.
|
|
54
|
+
*
|
|
55
|
+
* Returns the same array when the event does not concern json-render, so a
|
|
56
|
+
* signal holding the result only notifies on a real change. A delta applies
|
|
57
|
+
* through the same immutable patch engine as a JSONL stream: elements it does
|
|
58
|
+
* not touch keep their identity, and the renderer skips them.
|
|
59
|
+
*
|
|
60
|
+
* Two leniencies, both in the direction of rendering what arrived:
|
|
61
|
+
* - a delta for a surface no snapshot has opened starts from an empty spec,
|
|
62
|
+
* so an agent can stream patches the way a JSONL endpoint does;
|
|
63
|
+
* - a malformed patch op is dropped rather than failing the surface.
|
|
64
|
+
*/
|
|
65
|
+
declare function applyAgUiEvent(surfaces: readonly AgUiSurface[], event: AgUiEvent, activityType?: string): readonly AgUiSurface[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The callbacks of an AG-UI subscriber this entry point uses — a subset of
|
|
69
|
+
* `@ag-ui/client`'s `AgentSubscriber`.
|
|
70
|
+
*/
|
|
71
|
+
interface AgUiSubscriber {
|
|
72
|
+
onRunInitialized?(): void;
|
|
73
|
+
onEvent?(params: {
|
|
74
|
+
event: AgUiEvent;
|
|
75
|
+
}): void;
|
|
76
|
+
onRunErrorEvent?(params: {
|
|
77
|
+
event: {
|
|
78
|
+
message: string;
|
|
79
|
+
};
|
|
80
|
+
}): void;
|
|
81
|
+
onRunFailed?(params: {
|
|
82
|
+
error: Error;
|
|
83
|
+
}): void;
|
|
84
|
+
onRunFinalized?(): void;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* What {@link injectAgentUI} needs of an agent. Any `@ag-ui/client` agent —
|
|
88
|
+
* `HttpAgent`, a subclass of `AbstractAgent`, the agent CopilotKit hands out —
|
|
89
|
+
* already has this shape.
|
|
90
|
+
*/
|
|
91
|
+
interface AgUiAgent {
|
|
92
|
+
readonly messages?: readonly AgUiMessage[];
|
|
93
|
+
subscribe(subscriber: AgUiSubscriber): {
|
|
94
|
+
unsubscribe(): void;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** Options for {@link injectAgentUI}. */
|
|
98
|
+
interface AgentUIOptions {
|
|
99
|
+
/** The agent whose runs build the UI. The app runs it; the hook listens. */
|
|
100
|
+
agent: AgUiAgent;
|
|
101
|
+
/** Defaults to {@link JSON_RENDER_ACTIVITY_TYPE}. */
|
|
102
|
+
activityType?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Called once per surface a run touched, after the finished-spec check.
|
|
105
|
+
* Skipped for a run that failed, and for a surface the check rejected.
|
|
106
|
+
*/
|
|
107
|
+
onComplete?: (spec: Spec, messageId: string) => void;
|
|
108
|
+
/** Called when a run fails or a finished surface fails the check. */
|
|
109
|
+
onError?: (error: Error) => void;
|
|
110
|
+
/** As for `injectUIStream`: checked once per surface, when the run ends. */
|
|
111
|
+
validate?: SpecValidationMode;
|
|
112
|
+
/** As for `injectUIStream`; enforced whatever `validate` is. */
|
|
113
|
+
renderLimits?: RenderLimits | null;
|
|
114
|
+
/** As for `injectUIStream`: lets `validate` check types and props. */
|
|
115
|
+
catalog?: SpecCatalog | null;
|
|
116
|
+
}
|
|
117
|
+
/** Return type of {@link injectAgentUI}. */
|
|
118
|
+
interface AgentUIReturn {
|
|
119
|
+
/** Every json-render surface the agent has built, in order of appearance. */
|
|
120
|
+
readonly surfaces: Signal<readonly AgUiSurface[]>;
|
|
121
|
+
/** The most recently opened surface's spec — the one most apps render. */
|
|
122
|
+
readonly spec: Signal<Spec | null>;
|
|
123
|
+
/** Whether a run of the agent is in progress. */
|
|
124
|
+
readonly isStreaming: Signal<boolean>;
|
|
125
|
+
/** The last run's error, if any. */
|
|
126
|
+
readonly error: Signal<Error | null>;
|
|
127
|
+
/** What the check found in the surfaces the last run finished. */
|
|
128
|
+
readonly issues: Signal<readonly SpecCheckIssue[]>;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Render what an AG-UI agent streams. Subscribes to the agent, folds every
|
|
132
|
+
* json-render activity it emits into signals, and checks each surface when
|
|
133
|
+
* the run ends — the same contract as `injectUIStream`, with the agent in
|
|
134
|
+
* place of the endpoint.
|
|
135
|
+
*
|
|
136
|
+
* The app keeps running the agent itself (`agent.runAgent()`, CopilotKit, a
|
|
137
|
+
* reconnect); the hook only listens, so it sees every run, whoever starts it.
|
|
138
|
+
* It starts from whatever surfaces are already in the agent's messages and
|
|
139
|
+
* unsubscribes on destroy.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* export class AgentPage {
|
|
144
|
+
* readonly agent = new HttpAgent({ url: '/api/agent' });
|
|
145
|
+
* readonly ui = injectAgentUI({ agent: this.agent, catalog });
|
|
146
|
+
* ask(text: string) {
|
|
147
|
+
* this.agent.addMessage({ id: crypto.randomUUID(), role: 'user', content: text });
|
|
148
|
+
* this.agent.runAgent();
|
|
149
|
+
* }
|
|
150
|
+
* }
|
|
151
|
+
* // template:
|
|
152
|
+
* // <json-render [spec]="ui.spec()" [registry]="registry" [loading]="ui.isStreaming()" />
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
declare function injectAgentUI(options: AgentUIOptions): AgentUIReturn;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Renders one json-render activity message. It takes the inputs every AG-UI
|
|
159
|
+
* activity renderer is given — CopilotKit Angular's `ActivityRenderer`
|
|
160
|
+
* contract — and draws `content` with `<json-render>`, which takes its
|
|
161
|
+
* registry, catalog and handlers from the nearest `provideJsonRender`.
|
|
162
|
+
*
|
|
163
|
+
* Register it with {@link jsonRenderActivityRenderer} rather than by hand.
|
|
164
|
+
*/
|
|
165
|
+
declare class JsonRenderActivity {
|
|
166
|
+
readonly activityType: _angular_core.InputSignal<string>;
|
|
167
|
+
readonly content: _angular_core.InputSignal<unknown>;
|
|
168
|
+
/** The AG-UI activity message; unused, accepted for the contract. */
|
|
169
|
+
readonly message: _angular_core.InputSignal<unknown>;
|
|
170
|
+
/** The agent that produced it; unused, accepted for the contract. */
|
|
171
|
+
readonly agent: _angular_core.InputSignal<unknown>;
|
|
172
|
+
protected readonly spec: _angular_core.Signal<Spec | null>;
|
|
173
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<JsonRenderActivity, never>;
|
|
174
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<JsonRenderActivity, "json-render-activity", never, { "activityType": { "alias": "activityType"; "required": false; "isSignal": true; }; "content": { "alias": "content"; "required": true; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "agent": { "alias": "agent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
175
|
+
}
|
|
176
|
+
/** Options for {@link jsonRenderActivityRenderer}. */
|
|
177
|
+
interface JsonRenderActivityRendererOptions {
|
|
178
|
+
/** Defaults to {@link JSON_RENDER_ACTIVITY_TYPE}. */
|
|
179
|
+
activityType?: string;
|
|
180
|
+
/** Limit the renderer to one agent's activities. */
|
|
181
|
+
agentId?: string;
|
|
182
|
+
/** A component of your own in place of {@link JsonRenderActivity}. */
|
|
183
|
+
component?: Type<unknown>;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* An activity renderer config in the shape CopilotKit Angular's
|
|
187
|
+
* `renderActivityMessages` takes, matched structurally so this package does
|
|
188
|
+
* not depend on CopilotKit.
|
|
189
|
+
*/
|
|
190
|
+
interface JsonRenderActivityRendererConfig {
|
|
191
|
+
activityType: string;
|
|
192
|
+
agentId?: string;
|
|
193
|
+
content: {
|
|
194
|
+
safeParse(content: unknown): {
|
|
195
|
+
success: true;
|
|
196
|
+
data: Spec;
|
|
197
|
+
} | {
|
|
198
|
+
success: false;
|
|
199
|
+
error?: unknown;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
component: Type<any>;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Teach a CopilotKit Angular app to render json-render activities:
|
|
206
|
+
*
|
|
207
|
+
* ```ts
|
|
208
|
+
* providers: [
|
|
209
|
+
* provideJsonRender({ registry }),
|
|
210
|
+
* provideCopilotKit({
|
|
211
|
+
* runtimeUrl: '/api/copilotkit',
|
|
212
|
+
* renderActivityMessages: [jsonRenderActivityRenderer()],
|
|
213
|
+
* }),
|
|
214
|
+
* ]
|
|
215
|
+
* ```
|
|
216
|
+
*
|
|
217
|
+
* Content that is not a spec is rejected by the config's schema, so CopilotKit
|
|
218
|
+
* skips the message with a warning instead of mounting an empty renderer.
|
|
219
|
+
*/
|
|
220
|
+
declare function jsonRenderActivityRenderer(options?: JsonRenderActivityRendererOptions): JsonRenderActivityRendererConfig;
|
|
221
|
+
|
|
222
|
+
export { JSON_RENDER_ACTIVITY_TYPE, JsonRenderActivity, applyAgUiEvent, injectAgentUI, isJsonRenderSpec, jsonRenderActivityRenderer, surfacesFromMessages };
|
|
223
|
+
export type { AgUiAgent, AgUiEvent, AgUiMessage, AgUiSubscriber, AgUiSurface, AgentUIOptions, AgentUIReturn, JsonRenderActivityRendererConfig, JsonRenderActivityRendererOptions };
|