@copilotkit/shared 1.73.0 → 1.73.2-canary.1790068297

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.
Files changed (74) hide show
  1. package/README.md +22 -0
  2. package/dist/attachments/content.cjs +17 -0
  3. package/dist/attachments/content.cjs.map +1 -0
  4. package/dist/attachments/content.d.cts +9 -0
  5. package/dist/attachments/content.d.cts.map +1 -0
  6. package/dist/attachments/content.d.mts +9 -0
  7. package/dist/attachments/content.d.mts.map +1 -0
  8. package/dist/attachments/content.mjs +16 -0
  9. package/dist/attachments/content.mjs.map +1 -0
  10. package/dist/event-transforms/index.cjs +15 -0
  11. package/dist/event-transforms/index.d.cts +4 -0
  12. package/dist/event-transforms/index.d.mts +4 -0
  13. package/dist/event-transforms/index.mjs +5 -0
  14. package/dist/event-transforms/open-generative-ui-middleware.cjs +286 -0
  15. package/dist/event-transforms/open-generative-ui-middleware.cjs.map +1 -0
  16. package/dist/event-transforms/open-generative-ui-middleware.d.cts +60 -0
  17. package/dist/event-transforms/open-generative-ui-middleware.d.cts.map +1 -0
  18. package/dist/event-transforms/open-generative-ui-middleware.d.mts +60 -0
  19. package/dist/event-transforms/open-generative-ui-middleware.d.mts.map +1 -0
  20. package/dist/event-transforms/open-generative-ui-middleware.mjs +283 -0
  21. package/dist/event-transforms/open-generative-ui-middleware.mjs.map +1 -0
  22. package/dist/event-transforms/recorded-events.cjs +59 -0
  23. package/dist/event-transforms/recorded-events.cjs.map +1 -0
  24. package/dist/event-transforms/recorded-events.d.cts +23 -0
  25. package/dist/event-transforms/recorded-events.d.cts.map +1 -0
  26. package/dist/event-transforms/recorded-events.d.mts +23 -0
  27. package/dist/event-transforms/recorded-events.d.mts.map +1 -0
  28. package/dist/event-transforms/recorded-events.mjs +58 -0
  29. package/dist/event-transforms/recorded-events.mjs.map +1 -0
  30. package/dist/index.cjs +8 -0
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +3 -1
  33. package/dist/index.d.cts.map +1 -1
  34. package/dist/index.d.mts +3 -1
  35. package/dist/index.d.mts.map +1 -1
  36. package/dist/index.mjs +3 -1
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/index.umd.js +224 -1
  39. package/dist/index.umd.js.map +1 -1
  40. package/dist/package.cjs +1 -1
  41. package/dist/package.mjs +1 -1
  42. package/dist/types/message.d.cts +3 -3
  43. package/dist/types/message.d.cts.map +1 -1
  44. package/dist/types/message.d.mts +3 -3
  45. package/dist/types/message.d.mts.map +1 -1
  46. package/dist/utils/index.cjs +1 -0
  47. package/dist/utils/index.cjs.map +1 -1
  48. package/dist/utils/index.d.cts +1 -0
  49. package/dist/utils/index.d.cts.map +1 -1
  50. package/dist/utils/index.d.mts +1 -0
  51. package/dist/utils/index.d.mts.map +1 -1
  52. package/dist/utils/index.mjs +1 -0
  53. package/dist/utils/index.mjs.map +1 -1
  54. package/dist/utils/row-render-keys.cjs +206 -0
  55. package/dist/utils/row-render-keys.cjs.map +1 -0
  56. package/dist/utils/row-render-keys.d.cts +65 -0
  57. package/dist/utils/row-render-keys.d.cts.map +1 -0
  58. package/dist/utils/row-render-keys.d.mts +65 -0
  59. package/dist/utils/row-render-keys.d.mts.map +1 -0
  60. package/dist/utils/row-render-keys.mjs +201 -0
  61. package/dist/utils/row-render-keys.mjs.map +1 -0
  62. package/package.json +12 -1
  63. package/src/__tests__/root-entry-browser-safety.test.ts +7 -1
  64. package/src/attachments/content.test.ts +48 -0
  65. package/src/attachments/content.ts +16 -0
  66. package/src/attachments/index.ts +2 -0
  67. package/src/event-transforms/index.ts +5 -0
  68. package/src/event-transforms/open-generative-ui-middleware.ts +392 -0
  69. package/src/event-transforms/recorded-events.test.ts +166 -0
  70. package/src/event-transforms/recorded-events.ts +74 -0
  71. package/src/utils/__tests__/row-render-keys.test.ts +388 -0
  72. package/src/utils/index.ts +1 -0
  73. package/src/utils/row-render-keys.ts +263 -0
  74. package/tsdown.config.ts +7 -4
package/README.md CHANGED
@@ -198,3 +198,25 @@ request the optional metadata route when a runtime reports
198
198
  # Documentation
199
199
 
200
200
  To get started with CopilotKit, please check out the [documentation](https://docs.copilotkit.ai).
201
+
202
+ ## Event and attachment conversion
203
+
204
+ `createAttachmentContent` from `@copilotkit/shared` builds the same AG-UI
205
+ attachment content part used by the React, Angular, and Vue chat components.
206
+ It preserves the source and merges the filename into metadata, with explicit
207
+ metadata taking precedence.
208
+
209
+ The Node-only `@copilotkit/shared/event-transforms` entry exports
210
+ `OpenGenerativeUIMiddleware`, the existing upstream `A2UIMiddleware`, and
211
+ `transformRecordedEvents(input, events, options)`. The latter applies the same
212
+ converters to one recorded, pre-middleware AG-UI run without executing tools or
213
+ contacting an agent. Enable converters explicitly with `openGenerativeUI: true`
214
+ and/or `a2ui: { ...originalRuntimeOptions }`. Pass the recorded input, including
215
+ prior messages and catalog context, to preserve live conversion behavior.
216
+
217
+ The result includes the original events and generated activities in runtime
218
+ order. The caller owns persistence IDs, historical timestamps, and provenance.
219
+ A2UI can generate random message IDs for synthetic tool results; an importer
220
+ that needs deterministic IDs must assign them before saving. Do not process
221
+ already transformed histories a second time. This entry does not include MCP
222
+ execution or recreate runtime configuration absent from the recording.
@@ -0,0 +1,17 @@
1
+
2
+ //#region src/attachments/content.ts
3
+ /** Build the AG-UI content part used when sending a ready attachment. */
4
+ function createAttachmentContent(attachment) {
5
+ return {
6
+ type: attachment.type,
7
+ source: attachment.source,
8
+ metadata: {
9
+ ...attachment.filename ? { filename: attachment.filename } : {},
10
+ ...attachment.metadata
11
+ }
12
+ };
13
+ }
14
+
15
+ //#endregion
16
+ exports.createAttachmentContent = createAttachmentContent;
17
+ //# sourceMappingURL=content.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.cjs","names":[],"sources":["../../src/attachments/content.ts"],"sourcesContent":["import type { InputContent } from \"@ag-ui/core\";\nimport type { Attachment } from \"./types\";\n\n/** Build the AG-UI content part used when sending a ready attachment. */\nexport function createAttachmentContent(\n attachment: Pick<Attachment, \"type\" | \"source\" | \"filename\" | \"metadata\">,\n): InputContent {\n return {\n type: attachment.type,\n source: attachment.source,\n metadata: {\n ...(attachment.filename ? { filename: attachment.filename } : {}),\n ...attachment.metadata,\n },\n };\n}\n"],"mappings":";;;AAIA,SAAgB,wBACd,YACc;AACd,QAAO;EACL,MAAM,WAAW;EACjB,QAAQ,WAAW;EACnB,UAAU;GACR,GAAI,WAAW,WAAW,EAAE,UAAU,WAAW,UAAU,GAAG,EAAE;GAChE,GAAG,WAAW;GACf;EACF"}
@@ -0,0 +1,9 @@
1
+ import { Attachment } from "./types.cjs";
2
+ import { InputContent } from "@ag-ui/core";
3
+
4
+ //#region src/attachments/content.d.ts
5
+ /** Build the AG-UI content part used when sending a ready attachment. */
6
+ declare function createAttachmentContent(attachment: Pick<Attachment, "type" | "source" | "filename" | "metadata">): InputContent;
7
+ //#endregion
8
+ export { createAttachmentContent };
9
+ //# sourceMappingURL=content.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.cts","names":[],"sources":["../../src/attachments/content.ts"],"mappings":";;;;;iBAIgB,uBAAA,CACd,UAAA,EAAY,IAAA,CAAK,UAAA,iDAChB,YAAA"}
@@ -0,0 +1,9 @@
1
+ import { Attachment } from "./types.mjs";
2
+ import { InputContent } from "@ag-ui/core";
3
+
4
+ //#region src/attachments/content.d.ts
5
+ /** Build the AG-UI content part used when sending a ready attachment. */
6
+ declare function createAttachmentContent(attachment: Pick<Attachment, "type" | "source" | "filename" | "metadata">): InputContent;
7
+ //#endregion
8
+ export { createAttachmentContent };
9
+ //# sourceMappingURL=content.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.mts","names":[],"sources":["../../src/attachments/content.ts"],"mappings":";;;;;iBAIgB,uBAAA,CACd,UAAA,EAAY,IAAA,CAAK,UAAA,iDAChB,YAAA"}
@@ -0,0 +1,16 @@
1
+ //#region src/attachments/content.ts
2
+ /** Build the AG-UI content part used when sending a ready attachment. */
3
+ function createAttachmentContent(attachment) {
4
+ return {
5
+ type: attachment.type,
6
+ source: attachment.source,
7
+ metadata: {
8
+ ...attachment.filename ? { filename: attachment.filename } : {},
9
+ ...attachment.metadata
10
+ }
11
+ };
12
+ }
13
+
14
+ //#endregion
15
+ export { createAttachmentContent };
16
+ //# sourceMappingURL=content.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.mjs","names":[],"sources":["../../src/attachments/content.ts"],"sourcesContent":["import type { InputContent } from \"@ag-ui/core\";\nimport type { Attachment } from \"./types\";\n\n/** Build the AG-UI content part used when sending a ready attachment. */\nexport function createAttachmentContent(\n attachment: Pick<Attachment, \"type\" | \"source\" | \"filename\" | \"metadata\">,\n): InputContent {\n return {\n type: attachment.type,\n source: attachment.source,\n metadata: {\n ...(attachment.filename ? { filename: attachment.filename } : {}),\n ...attachment.metadata,\n },\n };\n}\n"],"mappings":";;AAIA,SAAgB,wBACd,YACc;AACd,QAAO;EACL,MAAM,WAAW;EACjB,QAAQ,WAAW;EACnB,UAAU;GACR,GAAI,WAAW,WAAW,EAAE,UAAU,WAAW,UAAU,GAAG,EAAE;GAChE,GAAG,WAAW;GACf;EACF"}
@@ -0,0 +1,15 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ const require_open_generative_ui_middleware = require('./open-generative-ui-middleware.cjs');
4
+ const require_recorded_events = require('./recorded-events.cjs');
5
+ let _ag_ui_a2ui_middleware = require("@ag-ui/a2ui-middleware");
6
+
7
+ Object.defineProperty(exports, 'A2UIMiddleware', {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _ag_ui_a2ui_middleware.A2UIMiddleware;
11
+ }
12
+ });
13
+ exports.ArgsParser = require_open_generative_ui_middleware.ArgsParser;
14
+ exports.OpenGenerativeUIMiddleware = require_open_generative_ui_middleware.OpenGenerativeUIMiddleware;
15
+ exports.transformRecordedEvents = require_recorded_events.transformRecordedEvents;
@@ -0,0 +1,4 @@
1
+ import { ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware } from "./open-generative-ui-middleware.cjs";
2
+ import { RecordedEventTransformOptions, transformRecordedEvents } from "./recorded-events.cjs";
3
+ import { A2UIMiddleware, A2UIMiddlewareConfig } from "@ag-ui/a2ui-middleware";
4
+ export { A2UIMiddleware, type A2UIMiddlewareConfig, ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware, RecordedEventTransformOptions, transformRecordedEvents };
@@ -0,0 +1,4 @@
1
+ import { ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware } from "./open-generative-ui-middleware.mjs";
2
+ import { RecordedEventTransformOptions, transformRecordedEvents } from "./recorded-events.mjs";
3
+ import { A2UIMiddleware, A2UIMiddlewareConfig } from "@ag-ui/a2ui-middleware";
4
+ export { A2UIMiddleware, type A2UIMiddlewareConfig, ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware, RecordedEventTransformOptions, transformRecordedEvents };
@@ -0,0 +1,5 @@
1
+ import { ArgsParser, OpenGenerativeUIMiddleware } from "./open-generative-ui-middleware.mjs";
2
+ import { transformRecordedEvents } from "./recorded-events.mjs";
3
+ import { A2UIMiddleware } from "@ag-ui/a2ui-middleware";
4
+
5
+ export { A2UIMiddleware, ArgsParser, OpenGenerativeUIMiddleware, transformRecordedEvents };
@@ -0,0 +1,286 @@
1
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
2
+ let _ag_ui_client = require("@ag-ui/client");
3
+ let rxjs = require("rxjs");
4
+ let clarinet = require("clarinet");
5
+ clarinet = require_runtime.__toESM(clarinet);
6
+
7
+ //#region src/event-transforms/open-generative-ui-middleware.ts
8
+ const TOOL_NAME = "generateSandboxedUi";
9
+ const ACTIVITY_TYPE = "open-generative-ui";
10
+ /**
11
+ * Tracks incremental JSON parsing state for a single tool call's arguments.
12
+ * Emits activity events via the onEvent callback as parameters complete.
13
+ */
14
+ var ArgsParser = class {
15
+ constructor(toolCallId, onEvent) {
16
+ this.currentKey = null;
17
+ this.depth = 0;
18
+ this.currentArrayKey = null;
19
+ this.snapshotEmitted = false;
20
+ this.streamingHtmlKey = false;
21
+ this.htmlEmittedLength = 0;
22
+ this.htmlArrayEmitted = false;
23
+ this.params = {};
24
+ this.messageId = `${toolCallId}-activity`;
25
+ this.onEvent = onEvent;
26
+ this.parser = clarinet.default.parser();
27
+ this.parser.onopenobject = (key) => {
28
+ this.depth++;
29
+ if (key !== void 0 && this.depth === 1) {
30
+ this.currentKey = key;
31
+ this.initHtmlStreaming(key);
32
+ }
33
+ };
34
+ this.parser.onkey = (key) => {
35
+ if (this.depth === 1) {
36
+ this.currentKey = key;
37
+ this.initHtmlStreaming(key);
38
+ }
39
+ };
40
+ this.parser.onvalue = (value) => {
41
+ if (this.depth === 1 && this.currentKey) if (this.currentArrayKey) {
42
+ const strValue = String(value);
43
+ if (this.currentArrayKey === "jsExpressions") {
44
+ if (!this.params.jsExpressions) this.params.jsExpressions = [];
45
+ this.params.jsExpressions.push(strValue);
46
+ } else if (this.currentArrayKey === "placeholderMessages") {
47
+ if (!this.params.placeholderMessages) this.params.placeholderMessages = [];
48
+ this.params.placeholderMessages.push(strValue);
49
+ }
50
+ this.emitArrayItemDelta(this.currentArrayKey, strValue);
51
+ } else if (this.streamingHtmlKey) {
52
+ const fullHtml = value != null ? String(value) : "";
53
+ this.params.html = fullHtml || void 0;
54
+ this.emitPendingHtml(fullHtml);
55
+ this.emitParamDelta("htmlComplete", true);
56
+ this.streamingHtmlKey = false;
57
+ } else this.setParam(this.currentKey, value);
58
+ };
59
+ this.parser.onopenarray = () => {
60
+ if (this.depth === 1 && this.currentKey) {
61
+ const key = this.currentKey;
62
+ if (key === "jsExpressions" || key === "placeholderMessages") {
63
+ this.currentArrayKey = key;
64
+ if (key === "jsExpressions") this.params.jsExpressions = [];
65
+ else this.params.placeholderMessages = [];
66
+ this.emitParamDelta(key, []);
67
+ }
68
+ }
69
+ };
70
+ this.parser.onclosearray = () => {
71
+ if (this.depth === 1) {
72
+ if (this.currentArrayKey === "jsExpressions") this.emitParamDelta("jsExpressionsComplete", true);
73
+ this.currentArrayKey = null;
74
+ }
75
+ };
76
+ this.parser.oncloseobject = () => {
77
+ this.depth--;
78
+ };
79
+ this.parser.onerror = (err) => {
80
+ console.warn("[OpenGenerativeUI] JSON parse error in streaming args, resuming:", err?.message ?? err);
81
+ this.parser.error = null;
82
+ this.parser.resume();
83
+ };
84
+ }
85
+ write(chunk) {
86
+ this.parser.write(chunk);
87
+ this.flushHtmlChunks();
88
+ }
89
+ initHtmlStreaming(key) {
90
+ if (key === "html") {
91
+ this.streamingHtmlKey = true;
92
+ this.htmlEmittedLength = 0;
93
+ this.htmlArrayEmitted = false;
94
+ }
95
+ }
96
+ /**
97
+ * Read clarinet's internal textNode buffer to emit html chunks incrementally.
98
+ * Called after every write() so partial string content is emitted as it streams in.
99
+ */
100
+ flushHtmlChunks() {
101
+ if (!this.streamingHtmlKey) return;
102
+ const textNode = this.parser.textNode;
103
+ if (typeof textNode !== "string") return;
104
+ if (textNode.length === this.htmlEmittedLength) return;
105
+ this.emitPendingHtml(textNode);
106
+ }
107
+ /**
108
+ * Emit accumulated html content since the last emission.
109
+ * Called by flushHtmlChunks and directly when html completes.
110
+ */
111
+ emitPendingHtml(textNode) {
112
+ const newContent = textNode.slice(this.htmlEmittedLength);
113
+ if (newContent.length === 0) return;
114
+ if (!this.htmlArrayEmitted) {
115
+ this.htmlArrayEmitted = true;
116
+ this.emitParamDelta("html", []);
117
+ }
118
+ this.emitArrayItemDelta("html", newContent);
119
+ this.htmlEmittedLength = textNode.length;
120
+ }
121
+ setParam(key, value) {
122
+ switch (key) {
123
+ case "initialHeight":
124
+ this.params.initialHeight = typeof value === "number" ? value : void 0;
125
+ if (this.snapshotEmitted) this.emitParamDelta("initialHeight", this.params.initialHeight);
126
+ else this.emitSnapshot();
127
+ break;
128
+ case "css":
129
+ this.params.css = value != null ? String(value) : void 0;
130
+ this.emitParamDelta("css", this.params.css);
131
+ this.emitParamDelta("cssComplete", true);
132
+ break;
133
+ case "jsFunctions":
134
+ this.params.jsFunctions = value != null ? String(value) : void 0;
135
+ this.emitParamDelta("jsFunctions", this.params.jsFunctions);
136
+ this.emitParamDelta("jsFunctionsComplete", true);
137
+ break;
138
+ }
139
+ }
140
+ emitSnapshot() {
141
+ if (this.snapshotEmitted) return;
142
+ this.snapshotEmitted = true;
143
+ const event = {
144
+ type: _ag_ui_client.EventType.ACTIVITY_SNAPSHOT,
145
+ messageId: this.messageId,
146
+ activityType: ACTIVITY_TYPE,
147
+ content: {
148
+ initialHeight: this.params.initialHeight,
149
+ generating: true
150
+ }
151
+ };
152
+ this.onEvent(event);
153
+ }
154
+ emitParamDelta(key, value) {
155
+ if (value === void 0) return;
156
+ this.emitSnapshot();
157
+ const event = {
158
+ type: _ag_ui_client.EventType.ACTIVITY_DELTA,
159
+ messageId: this.messageId,
160
+ activityType: ACTIVITY_TYPE,
161
+ patch: [{
162
+ op: "add",
163
+ path: `/${key}`,
164
+ value
165
+ }]
166
+ };
167
+ this.onEvent(event);
168
+ }
169
+ emitArrayItemDelta(arrayKey, value) {
170
+ this.emitSnapshot();
171
+ const event = {
172
+ type: _ag_ui_client.EventType.ACTIVITY_DELTA,
173
+ messageId: this.messageId,
174
+ activityType: ACTIVITY_TYPE,
175
+ patch: [{
176
+ op: "add",
177
+ path: `/${arrayKey}/-`,
178
+ value
179
+ }]
180
+ };
181
+ this.onEvent(event);
182
+ }
183
+ };
184
+ var OpenGenerativeUIMiddleware = class extends _ag_ui_client.Middleware {
185
+ run(input, next) {
186
+ return this.processStream(this.runNextWithState(input, next));
187
+ }
188
+ processStream(source) {
189
+ return new rxjs.Observable((subscriber) => {
190
+ let heldRunFinished = null;
191
+ const activeParsers = /* @__PURE__ */ new Map();
192
+ const heldToolCallEvents = /* @__PURE__ */ new Map();
193
+ const flushedToolCalls = /* @__PURE__ */ new Set();
194
+ const flushHeldEvents = (toolCallId) => {
195
+ if (flushedToolCalls.has(toolCallId)) return;
196
+ flushedToolCalls.add(toolCallId);
197
+ const held = heldToolCallEvents.get(toolCallId);
198
+ if (held) {
199
+ for (const e of held) subscriber.next(e);
200
+ heldToolCallEvents.delete(toolCallId);
201
+ }
202
+ };
203
+ const subscription = source.subscribe({
204
+ next: (eventWithState) => {
205
+ const event = eventWithState.event;
206
+ if (heldRunFinished) {
207
+ subscriber.next(heldRunFinished.event);
208
+ heldRunFinished = null;
209
+ }
210
+ if (event.type === _ag_ui_client.EventType.RUN_FINISHED) {
211
+ heldRunFinished = eventWithState;
212
+ return;
213
+ }
214
+ if (event.type === _ag_ui_client.EventType.TOOL_CALL_START) {
215
+ const startEvent = event;
216
+ if (startEvent.toolCallName === TOOL_NAME) {
217
+ heldToolCallEvents.set(startEvent.toolCallId, [event]);
218
+ activeParsers.set(startEvent.toolCallId, new ArgsParser(startEvent.toolCallId, (activityEvent) => {
219
+ subscriber.next(activityEvent);
220
+ flushHeldEvents(startEvent.toolCallId);
221
+ }));
222
+ return;
223
+ }
224
+ }
225
+ if (event.type === _ag_ui_client.EventType.TOOL_CALL_ARGS) {
226
+ const argsEvent = event;
227
+ const parser = activeParsers.get(argsEvent.toolCallId);
228
+ if (parser) {
229
+ if (!flushedToolCalls.has(argsEvent.toolCallId)) heldToolCallEvents.get(argsEvent.toolCallId).push(event);
230
+ else subscriber.next(event);
231
+ parser.write(argsEvent.delta);
232
+ return;
233
+ }
234
+ }
235
+ if (event.type === _ag_ui_client.EventType.TOOL_CALL_END) {
236
+ const endEvent = event;
237
+ const parser = activeParsers.get(endEvent.toolCallId);
238
+ if (parser) {
239
+ const completeEvent = {
240
+ type: _ag_ui_client.EventType.ACTIVITY_DELTA,
241
+ messageId: parser.messageId,
242
+ activityType: ACTIVITY_TYPE,
243
+ patch: [{
244
+ op: "add",
245
+ path: "/generating",
246
+ value: false
247
+ }]
248
+ };
249
+ subscriber.next(completeEvent);
250
+ if (!flushedToolCalls.has(endEvent.toolCallId)) heldToolCallEvents.get(endEvent.toolCallId).push(event);
251
+ else subscriber.next(event);
252
+ return;
253
+ }
254
+ }
255
+ subscriber.next(event);
256
+ },
257
+ error: (err) => {
258
+ for (const [, events] of heldToolCallEvents) for (const event of events) subscriber.next(event);
259
+ heldToolCallEvents.clear();
260
+ if (heldRunFinished) {
261
+ subscriber.next(heldRunFinished.event);
262
+ heldRunFinished = null;
263
+ }
264
+ subscriber.error(err);
265
+ },
266
+ complete: () => {
267
+ heldToolCallEvents.forEach((_, toolCallId) => {
268
+ flushHeldEvents(toolCallId);
269
+ });
270
+ if (heldRunFinished) {
271
+ subscriber.next(heldRunFinished.event);
272
+ heldRunFinished = null;
273
+ }
274
+ activeParsers.clear();
275
+ subscriber.complete();
276
+ }
277
+ });
278
+ return () => subscription.unsubscribe();
279
+ });
280
+ }
281
+ };
282
+
283
+ //#endregion
284
+ exports.ArgsParser = ArgsParser;
285
+ exports.OpenGenerativeUIMiddleware = OpenGenerativeUIMiddleware;
286
+ //# sourceMappingURL=open-generative-ui-middleware.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-generative-ui-middleware.cjs","names":["EventType","Middleware","Observable"],"sources":["../../src/event-transforms/open-generative-ui-middleware.ts"],"sourcesContent":["import type {\n RunAgentInput,\n AbstractAgent,\n BaseEvent,\n ToolCallStartEvent,\n ToolCallArgsEvent,\n ActivitySnapshotEventProps,\n ActivityDeltaEvent,\n} from \"@ag-ui/client\";\nimport { Middleware, EventType } from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport clarinet from \"clarinet\";\n\nconst TOOL_NAME = \"generateSandboxedUi\";\nconst ACTIVITY_TYPE = \"open-generative-ui\";\n\n/**\n * Parsed parameters from the generateSandboxedUi tool call.\n */\nexport interface GenerateSandboxedUIParams {\n initialHeight?: number;\n placeholderMessages?: string[];\n css?: string;\n html?: string;\n jsFunctions?: string;\n jsExpressions?: string[];\n}\n\n/**\n * Callback invoked by ArgsParser whenever a parameter (or array item) finishes parsing.\n */\nexport type OnParamEvent = (event: BaseEvent) => void;\n\n/**\n * Tracks incremental JSON parsing state for a single tool call's arguments.\n * Emits activity events via the onEvent callback as parameters complete.\n */\nexport class ArgsParser {\n private parser: ReturnType<typeof clarinet.parser> & {\n error?: Error | null;\n textNode?: string;\n };\n private currentKey: string | null = null;\n private depth = 0;\n private currentArrayKey: string | null = null;\n private snapshotEmitted = false;\n\n // Streaming html state — reads parser.textNode to emit incremental chunks\n private streamingHtmlKey = false;\n private htmlEmittedLength = 0;\n private htmlArrayEmitted = false;\n\n public readonly params: GenerateSandboxedUIParams = {};\n public readonly messageId: string;\n private readonly onEvent: OnParamEvent;\n\n constructor(toolCallId: string, onEvent: OnParamEvent) {\n this.messageId = `${toolCallId}-activity`;\n this.onEvent = onEvent;\n this.parser = clarinet.parser();\n\n this.parser.onopenobject = (key: string | undefined) => {\n this.depth++;\n if (key !== undefined && this.depth === 1) {\n this.currentKey = key;\n this.initHtmlStreaming(key);\n }\n };\n\n this.parser.onkey = (key: string) => {\n if (this.depth === 1) {\n this.currentKey = key;\n this.initHtmlStreaming(key);\n }\n };\n\n this.parser.onvalue = (value: string | boolean | number | null) => {\n if (this.depth === 1 && this.currentKey) {\n if (this.currentArrayKey) {\n const strValue = String(value);\n if (this.currentArrayKey === \"jsExpressions\") {\n if (!this.params.jsExpressions) this.params.jsExpressions = [];\n this.params.jsExpressions.push(strValue);\n } else if (this.currentArrayKey === \"placeholderMessages\") {\n if (!this.params.placeholderMessages)\n this.params.placeholderMessages = [];\n this.params.placeholderMessages.push(strValue);\n }\n this.emitArrayItemDelta(this.currentArrayKey, strValue);\n } else if (this.streamingHtmlKey) {\n // HTML string completed — flush any remaining content immediately + htmlComplete\n const fullHtml = value != null ? String(value) : \"\";\n this.params.html = fullHtml || undefined;\n this.emitPendingHtml(fullHtml);\n this.emitParamDelta(\"htmlComplete\", true);\n this.streamingHtmlKey = false;\n } else {\n this.setParam(this.currentKey, value);\n }\n }\n };\n\n this.parser.onopenarray = () => {\n if (this.depth === 1 && this.currentKey) {\n const key = this.currentKey;\n if (key === \"jsExpressions\" || key === \"placeholderMessages\") {\n this.currentArrayKey = key;\n if (key === \"jsExpressions\") this.params.jsExpressions = [];\n else this.params.placeholderMessages = [];\n // Emit a delta to create the array in the activity content.\n // Subsequent \"add\" ops with path \"/<key>/-\" append to this array.\n this.emitParamDelta(key, []);\n }\n }\n };\n\n this.parser.onclosearray = () => {\n if (this.depth === 1) {\n if (this.currentArrayKey === \"jsExpressions\") {\n this.emitParamDelta(\"jsExpressionsComplete\", true);\n }\n this.currentArrayKey = null;\n }\n };\n\n this.parser.oncloseobject = () => {\n this.depth--;\n };\n\n this.parser.onerror = (err: Error) => {\n console.warn(\n \"[OpenGenerativeUI] JSON parse error in streaming args, resuming:\",\n err?.message ?? err,\n );\n // Reset error state so parsing can continue with the next chunk\n this.parser.error = null;\n this.parser.resume();\n };\n }\n\n write(chunk: string): void {\n this.parser.write(chunk);\n this.flushHtmlChunks();\n }\n\n private initHtmlStreaming(key: string): void {\n if (key === \"html\") {\n this.streamingHtmlKey = true;\n this.htmlEmittedLength = 0;\n this.htmlArrayEmitted = false;\n }\n }\n\n /**\n * Read clarinet's internal textNode buffer to emit html chunks incrementally.\n * Called after every write() so partial string content is emitted as it streams in.\n */\n private flushHtmlChunks(): void {\n if (!this.streamingHtmlKey) return;\n const textNode = this.parser.textNode;\n if (typeof textNode !== \"string\") return;\n if (textNode.length === this.htmlEmittedLength) return;\n\n this.emitPendingHtml(textNode);\n }\n\n /**\n * Emit accumulated html content since the last emission.\n * Called by flushHtmlChunks and directly when html completes.\n */\n private emitPendingHtml(textNode: string): void {\n const newContent = textNode.slice(this.htmlEmittedLength);\n if (newContent.length === 0) return;\n\n if (!this.htmlArrayEmitted) {\n this.htmlArrayEmitted = true;\n this.emitParamDelta(\"html\", []);\n }\n this.emitArrayItemDelta(\"html\", newContent);\n this.htmlEmittedLength = textNode.length;\n }\n\n private setParam(key: string, value: string | boolean | number | null): void {\n switch (key) {\n case \"initialHeight\":\n this.params.initialHeight =\n typeof value === \"number\" ? value : undefined;\n if (this.snapshotEmitted) {\n // Snapshot already went out (another param parsed first) — deliver\n // the height as a delta instead.\n this.emitParamDelta(\"initialHeight\", this.params.initialHeight);\n } else {\n this.emitSnapshot();\n }\n break;\n case \"css\":\n this.params.css = value != null ? String(value) : undefined;\n this.emitParamDelta(\"css\", this.params.css);\n this.emitParamDelta(\"cssComplete\", true);\n break;\n case \"jsFunctions\":\n this.params.jsFunctions = value != null ? String(value) : undefined;\n this.emitParamDelta(\"jsFunctions\", this.params.jsFunctions);\n this.emitParamDelta(\"jsFunctionsComplete\", true);\n break;\n }\n }\n\n private emitSnapshot(): void {\n if (this.snapshotEmitted) return;\n this.snapshotEmitted = true;\n\n const event = {\n type: EventType.ACTIVITY_SNAPSHOT,\n messageId: this.messageId,\n activityType: ACTIVITY_TYPE,\n content: { initialHeight: this.params.initialHeight, generating: true },\n } satisfies ActivitySnapshotEventProps;\n this.onEvent(event);\n }\n\n private emitParamDelta(key: string, value: unknown): void {\n // A JSON Patch \"add\" requires a value; emitting one without it (e.g. when\n // the LLM sends a null/empty jsFunctions or css) makes fast-json-patch\n // reject the whole patch client-side with OPERATION_VALUE_REQUIRED and\n // drops it. Skip the delta when there's nothing to add.\n if (value === undefined) return;\n // The activity message must exist before any delta can be applied —\n // the client silently drops ACTIVITY_DELTA events whose messageId has\n // no prior ACTIVITY_SNAPSHOT. The LLM controls the key order of the\n // streamed args, so the snapshot cannot wait for initialHeight.\n this.emitSnapshot();\n const event: ActivityDeltaEvent = {\n type: EventType.ACTIVITY_DELTA,\n messageId: this.messageId,\n activityType: ACTIVITY_TYPE,\n patch: [{ op: \"add\", path: `/${key}`, value }],\n };\n this.onEvent(event);\n }\n\n private emitArrayItemDelta(arrayKey: string, value: string): void {\n this.emitSnapshot();\n const event: ActivityDeltaEvent = {\n type: EventType.ACTIVITY_DELTA,\n messageId: this.messageId,\n activityType: ACTIVITY_TYPE,\n patch: [{ op: \"add\", path: `/${arrayKey}/-`, value }],\n };\n this.onEvent(event);\n }\n}\n\n/**\n * Extract EventWithState type from Middleware.runNextWithState return type\n */\ntype ExtractObservableType<T> = T extends Observable<infer U> ? U : never;\ntype RunNextWithStateReturn = ReturnType<Middleware[\"runNextWithState\"]>;\ntype EventWithState = ExtractObservableType<RunNextWithStateReturn>;\n\nexport class OpenGenerativeUIMiddleware extends Middleware {\n run(input: RunAgentInput, next: AbstractAgent): Observable<BaseEvent> {\n return this.processStream(this.runNextWithState(input, next));\n }\n\n private processStream(\n source: Observable<EventWithState>,\n ): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber) => {\n let heldRunFinished: EventWithState | null = null;\n // Track active generateSandboxedUi tool call IDs → their streaming parser\n const activeParsers = new Map<string, ArgsParser>();\n // Hold genui tool call events until the first activity event is emitted\n const heldToolCallEvents = new Map<string, BaseEvent[]>();\n const flushedToolCalls = new Set<string>();\n\n const flushHeldEvents = (toolCallId: string) => {\n if (flushedToolCalls.has(toolCallId)) return;\n flushedToolCalls.add(toolCallId);\n const held = heldToolCallEvents.get(toolCallId);\n if (held) {\n for (const e of held) {\n subscriber.next(e);\n }\n heldToolCallEvents.delete(toolCallId);\n }\n };\n\n const subscription = source.subscribe({\n next: (eventWithState) => {\n const event = eventWithState.event;\n\n if (heldRunFinished) {\n subscriber.next(heldRunFinished.event);\n heldRunFinished = null;\n }\n\n if (event.type === EventType.RUN_FINISHED) {\n heldRunFinished = eventWithState;\n return;\n }\n\n // Hold TOOL_CALL_START for genui until the first activity event\n if (event.type === EventType.TOOL_CALL_START) {\n const startEvent = event as ToolCallStartEvent;\n if (startEvent.toolCallName === TOOL_NAME) {\n heldToolCallEvents.set(startEvent.toolCallId, [event]);\n activeParsers.set(\n startEvent.toolCallId,\n new ArgsParser(startEvent.toolCallId, (activityEvent) => {\n subscriber.next(activityEvent);\n flushHeldEvents(startEvent.toolCallId);\n }),\n );\n return;\n }\n }\n\n // Hold or emit TOOL_CALL_ARGS for genui tool calls\n if (event.type === EventType.TOOL_CALL_ARGS) {\n const argsEvent = event as ToolCallArgsEvent;\n const parser = activeParsers.get(argsEvent.toolCallId);\n if (parser) {\n if (!flushedToolCalls.has(argsEvent.toolCallId)) {\n heldToolCallEvents.get(argsEvent.toolCallId)!.push(event);\n } else {\n subscriber.next(event);\n }\n parser.write(argsEvent.delta);\n return;\n }\n }\n\n // Hold or emit TOOL_CALL_END for genui tool calls\n if (event.type === EventType.TOOL_CALL_END) {\n const endEvent = event as { toolCallId: string } & BaseEvent;\n const parser = activeParsers.get(endEvent.toolCallId);\n if (parser) {\n // Mark generation complete\n const completeEvent: ActivityDeltaEvent = {\n type: EventType.ACTIVITY_DELTA,\n messageId: parser.messageId,\n activityType: ACTIVITY_TYPE,\n patch: [{ op: \"add\", path: \"/generating\", value: false }],\n };\n subscriber.next(completeEvent);\n\n if (!flushedToolCalls.has(endEvent.toolCallId)) {\n heldToolCallEvents.get(endEvent.toolCallId)!.push(event);\n } else {\n subscriber.next(event);\n }\n return;\n }\n }\n\n subscriber.next(event);\n },\n error: (err) => {\n // Flush any held tool call events so downstream sees them before the error\n for (const [, events] of heldToolCallEvents) {\n for (const event of events) {\n subscriber.next(event);\n }\n }\n heldToolCallEvents.clear();\n\n if (heldRunFinished) {\n subscriber.next(heldRunFinished.event);\n heldRunFinished = null;\n }\n subscriber.error(err);\n },\n complete: () => {\n // Flush any remaining held tool call events (e.g. parser never emitted)\n heldToolCallEvents.forEach((_, toolCallId) => {\n flushHeldEvents(toolCallId);\n });\n\n if (heldRunFinished) {\n subscriber.next(heldRunFinished.event);\n heldRunFinished = null;\n }\n activeParsers.clear();\n subscriber.complete();\n },\n });\n\n return () => subscription.unsubscribe();\n });\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { AbstractAgent, BaseEvent, Middleware, RunAgentInput } from "@ag-ui/client";
2
+ import { Observable } from "rxjs";
3
+
4
+ //#region src/event-transforms/open-generative-ui-middleware.d.ts
5
+ /**
6
+ * Parsed parameters from the generateSandboxedUi tool call.
7
+ */
8
+ interface GenerateSandboxedUIParams {
9
+ initialHeight?: number;
10
+ placeholderMessages?: string[];
11
+ css?: string;
12
+ html?: string;
13
+ jsFunctions?: string;
14
+ jsExpressions?: string[];
15
+ }
16
+ /**
17
+ * Callback invoked by ArgsParser whenever a parameter (or array item) finishes parsing.
18
+ */
19
+ type OnParamEvent = (event: BaseEvent) => void;
20
+ /**
21
+ * Tracks incremental JSON parsing state for a single tool call's arguments.
22
+ * Emits activity events via the onEvent callback as parameters complete.
23
+ */
24
+ declare class ArgsParser {
25
+ private parser;
26
+ private currentKey;
27
+ private depth;
28
+ private currentArrayKey;
29
+ private snapshotEmitted;
30
+ private streamingHtmlKey;
31
+ private htmlEmittedLength;
32
+ private htmlArrayEmitted;
33
+ readonly params: GenerateSandboxedUIParams;
34
+ readonly messageId: string;
35
+ private readonly onEvent;
36
+ constructor(toolCallId: string, onEvent: OnParamEvent);
37
+ write(chunk: string): void;
38
+ private initHtmlStreaming;
39
+ /**
40
+ * Read clarinet's internal textNode buffer to emit html chunks incrementally.
41
+ * Called after every write() so partial string content is emitted as it streams in.
42
+ */
43
+ private flushHtmlChunks;
44
+ /**
45
+ * Emit accumulated html content since the last emission.
46
+ * Called by flushHtmlChunks and directly when html completes.
47
+ */
48
+ private emitPendingHtml;
49
+ private setParam;
50
+ private emitSnapshot;
51
+ private emitParamDelta;
52
+ private emitArrayItemDelta;
53
+ }
54
+ declare class OpenGenerativeUIMiddleware extends Middleware {
55
+ run(input: RunAgentInput, next: AbstractAgent): Observable<BaseEvent>;
56
+ private processStream;
57
+ }
58
+ //#endregion
59
+ export { ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware };
60
+ //# sourceMappingURL=open-generative-ui-middleware.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-generative-ui-middleware.d.cts","names":[],"sources":["../../src/event-transforms/open-generative-ui-middleware.ts"],"mappings":";;;;;AAmBA;;UAAiB,yBAAA;EACf,aAAA;EACA,mBAAA;EACA,GAAA;EACA,IAAA;EACA,WAAA;EACA,aAAA;AAAA;;;AAMF;KAAY,YAAA,IAAgB,KAAA,EAAO,SAAA;;;;AAMnC;cAAa,UAAA;EAAA,QACH,MAAA;EAAA,QAIA,UAAA;EAAA,QACA,KAAA;EAAA,QACA,eAAA;EAAA,QACA,eAAA;EAAA,QAGA,gBAAA;EAAA,QACA,iBAAA;EAAA,QACA,gBAAA;EAAA,SAEQ,MAAA,EAAQ,yBAAA;EAAA,SACR,SAAA;EAAA,iBACC,OAAA;cAEL,UAAA,UAAoB,OAAA,EAAS,YAAA;EAoFzC,KAAA,CAAM,KAAA;EAAA,QAKE,iBAAA;;;;;UAYA,eAAA;EAjBF;;;;EAAA,QA8BE,eAAA;EAAA,QAYA,QAAA;EAAA,QA0BA,YAAA;EAAA,QAaA,cAAA;EAAA,QAoBA,kBAAA;AAAA;AAAA,cAmBG,0BAAA,SAAmC,UAAA;EAC9C,GAAA,CAAI,KAAA,EAAO,aAAA,EAAe,IAAA,EAAM,aAAA,GAAgB,UAAA,CAAW,SAAA;EAAA,QAInD,aAAA;AAAA"}
@@ -0,0 +1,60 @@
1
+ import { AbstractAgent, BaseEvent, Middleware, RunAgentInput } from "@ag-ui/client";
2
+ import { Observable } from "rxjs";
3
+
4
+ //#region src/event-transforms/open-generative-ui-middleware.d.ts
5
+ /**
6
+ * Parsed parameters from the generateSandboxedUi tool call.
7
+ */
8
+ interface GenerateSandboxedUIParams {
9
+ initialHeight?: number;
10
+ placeholderMessages?: string[];
11
+ css?: string;
12
+ html?: string;
13
+ jsFunctions?: string;
14
+ jsExpressions?: string[];
15
+ }
16
+ /**
17
+ * Callback invoked by ArgsParser whenever a parameter (or array item) finishes parsing.
18
+ */
19
+ type OnParamEvent = (event: BaseEvent) => void;
20
+ /**
21
+ * Tracks incremental JSON parsing state for a single tool call's arguments.
22
+ * Emits activity events via the onEvent callback as parameters complete.
23
+ */
24
+ declare class ArgsParser {
25
+ private parser;
26
+ private currentKey;
27
+ private depth;
28
+ private currentArrayKey;
29
+ private snapshotEmitted;
30
+ private streamingHtmlKey;
31
+ private htmlEmittedLength;
32
+ private htmlArrayEmitted;
33
+ readonly params: GenerateSandboxedUIParams;
34
+ readonly messageId: string;
35
+ private readonly onEvent;
36
+ constructor(toolCallId: string, onEvent: OnParamEvent);
37
+ write(chunk: string): void;
38
+ private initHtmlStreaming;
39
+ /**
40
+ * Read clarinet's internal textNode buffer to emit html chunks incrementally.
41
+ * Called after every write() so partial string content is emitted as it streams in.
42
+ */
43
+ private flushHtmlChunks;
44
+ /**
45
+ * Emit accumulated html content since the last emission.
46
+ * Called by flushHtmlChunks and directly when html completes.
47
+ */
48
+ private emitPendingHtml;
49
+ private setParam;
50
+ private emitSnapshot;
51
+ private emitParamDelta;
52
+ private emitArrayItemDelta;
53
+ }
54
+ declare class OpenGenerativeUIMiddleware extends Middleware {
55
+ run(input: RunAgentInput, next: AbstractAgent): Observable<BaseEvent>;
56
+ private processStream;
57
+ }
58
+ //#endregion
59
+ export { ArgsParser, GenerateSandboxedUIParams, OnParamEvent, OpenGenerativeUIMiddleware };
60
+ //# sourceMappingURL=open-generative-ui-middleware.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-generative-ui-middleware.d.mts","names":[],"sources":["../../src/event-transforms/open-generative-ui-middleware.ts"],"mappings":";;;;;AAmBA;;UAAiB,yBAAA;EACf,aAAA;EACA,mBAAA;EACA,GAAA;EACA,IAAA;EACA,WAAA;EACA,aAAA;AAAA;;;AAMF;KAAY,YAAA,IAAgB,KAAA,EAAO,SAAA;;;;AAMnC;cAAa,UAAA;EAAA,QACH,MAAA;EAAA,QAIA,UAAA;EAAA,QACA,KAAA;EAAA,QACA,eAAA;EAAA,QACA,eAAA;EAAA,QAGA,gBAAA;EAAA,QACA,iBAAA;EAAA,QACA,gBAAA;EAAA,SAEQ,MAAA,EAAQ,yBAAA;EAAA,SACR,SAAA;EAAA,iBACC,OAAA;cAEL,UAAA,UAAoB,OAAA,EAAS,YAAA;EAoFzC,KAAA,CAAM,KAAA;EAAA,QAKE,iBAAA;;;;;UAYA,eAAA;EAjBF;;;;EAAA,QA8BE,eAAA;EAAA,QAYA,QAAA;EAAA,QA0BA,YAAA;EAAA,QAaA,cAAA;EAAA,QAoBA,kBAAA;AAAA;AAAA,cAmBG,0BAAA,SAAmC,UAAA;EAC9C,GAAA,CAAI,KAAA,EAAO,aAAA,EAAe,IAAA,EAAM,aAAA,GAAgB,UAAA,CAAW,SAAA;EAAA,QAInD,aAAA;AAAA"}