@ag-ui/proto 0.0.27

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.
@@ -0,0 +1,23 @@
1
+
2
+ 
3
+ > @ag-ui/proto@0.0.27 build /Users/mme/Code/ag-ui-protocol/typescript-sdk/packages/proto
4
+ > tsup
5
+
6
+ CLI Building entry: src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v8.4.0
9
+ CLI Using tsup config: /Users/mme/Code/ag-ui-protocol/typescript-sdk/packages/proto/tsup.config.ts
10
+ CLI Target: es2019
11
+ CLI Cleaning output folder
12
+ ESM Build start
13
+ CJS Build start
14
+ ESM dist/index.mjs 60.80 KB
15
+ ESM dist/index.mjs.map 122.38 KB
16
+ ESM ⚡️ Build success in 14ms
17
+ CJS dist/index.js 62.64 KB
18
+ CJS dist/index.js.map 122.19 KB
19
+ CJS ⚡️ Build success in 15ms
20
+ DTS Build start
21
+ DTS ⚡️ Build success in 1047ms
22
+ DTS dist/index.d.mts 481.00 B
23
+ DTS dist/index.d.ts 481.00 B
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @ag-ui/proto@0.0.27 generate /Users/mme/Code/ag-ui-protocol/typescript-sdk/packages/proto
4
+ > protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./src/generated --ts_proto_opt=esModuleInterop=true,outputJsonMethods=false,outputClientImpl=false -I ./src/proto ./src/proto/*.proto
5
+
@@ -0,0 +1,268 @@
1
+ import {
2
+ BaseEvent,
3
+ EventType,
4
+ MessagesSnapshotEvent,
5
+ TextMessageStartEvent,
6
+ TextMessageContentEvent,
7
+ TextMessageEndEvent,
8
+ } from "@ag-ui/core";
9
+ import { expect, describe, it } from "@jest/globals";
10
+ import { encode, decode } from "../src/proto";
11
+ import { expectRoundTripEquality } from "./test-utils";
12
+
13
+ describe("Message Events", () => {
14
+ describe("TextMessageStartEvent", () => {
15
+ it("should round-trip encode/decode correctly", () => {
16
+ const event: TextMessageStartEvent = {
17
+ type: EventType.TEXT_MESSAGE_START,
18
+ timestamp: Date.now(),
19
+ messageId: "msg-1",
20
+ role: "assistant",
21
+ };
22
+
23
+ expectRoundTripEquality(event);
24
+ });
25
+
26
+ it("should handle missing optional fields", () => {
27
+ const event: TextMessageStartEvent = {
28
+ type: EventType.TEXT_MESSAGE_START,
29
+ messageId: "msg-1",
30
+ role: "assistant",
31
+ };
32
+
33
+ expectRoundTripEquality(event);
34
+ });
35
+ });
36
+
37
+ describe("TextMessageContentEvent", () => {
38
+ it("should round-trip encode/decode correctly", () => {
39
+ const event: TextMessageContentEvent = {
40
+ type: EventType.TEXT_MESSAGE_CONTENT,
41
+ timestamp: Date.now(),
42
+ messageId: "msg-1",
43
+ delta: "Hello, how can I help you today?",
44
+ };
45
+
46
+ expectRoundTripEquality(event);
47
+ });
48
+
49
+ it("should handle special characters in content delta", () => {
50
+ const event: TextMessageContentEvent = {
51
+ type: EventType.TEXT_MESSAGE_CONTENT,
52
+ messageId: "msg-1",
53
+ delta: "Special chars: 🚀 ñ € 😊 \n\t\"'\\`",
54
+ };
55
+
56
+ expectRoundTripEquality(event);
57
+ });
58
+ });
59
+
60
+ describe("TextMessageEndEvent", () => {
61
+ it("should round-trip encode/decode correctly", () => {
62
+ const event: TextMessageEndEvent = {
63
+ type: EventType.TEXT_MESSAGE_END,
64
+ timestamp: Date.now(),
65
+ messageId: "msg-1",
66
+ };
67
+
68
+ expectRoundTripEquality(event);
69
+ });
70
+ });
71
+
72
+ describe("MessagesSnapshotEvent", () => {
73
+ it("should round-trip encode/decode with multiple messages", () => {
74
+ const event: MessagesSnapshotEvent = {
75
+ type: EventType.MESSAGES_SNAPSHOT,
76
+ timestamp: Date.now(),
77
+ messages: [
78
+ {
79
+ id: "msg-1",
80
+ role: "user",
81
+ content: "Can you help me with my task?",
82
+ },
83
+ {
84
+ id: "msg-2",
85
+ role: "assistant",
86
+ content: "I'd be happy to help! What task do you need assistance with?",
87
+ },
88
+ ],
89
+ };
90
+
91
+ expectRoundTripEquality(event);
92
+ });
93
+
94
+ it("should handle messages with tool calls", () => {
95
+ const event: MessagesSnapshotEvent = {
96
+ type: EventType.MESSAGES_SNAPSHOT,
97
+ messages: [
98
+ {
99
+ id: "msg-1",
100
+ role: "user",
101
+ content: "What's the weather in San Francisco?",
102
+ },
103
+ {
104
+ id: "msg-2",
105
+ role: "assistant",
106
+ content: "Let me check the weather for you.",
107
+ toolCalls: [
108
+ {
109
+ id: "tool-1",
110
+ type: "function",
111
+ function: {
112
+ name: "get_weather",
113
+ arguments: JSON.stringify({ location: "San Francisco" }),
114
+ },
115
+ },
116
+ ],
117
+ },
118
+ ],
119
+ };
120
+
121
+ expectRoundTripEquality(event);
122
+ });
123
+
124
+ it("should handle messages with multiple tool calls and complex arguments", () => {
125
+ const event: MessagesSnapshotEvent = {
126
+ type: EventType.MESSAGES_SNAPSHOT,
127
+ messages: [
128
+ {
129
+ id: "msg-1",
130
+ role: "assistant",
131
+ content: undefined, // Changed from null to undefined
132
+ toolCalls: [
133
+ {
134
+ id: "tool-1",
135
+ type: "function",
136
+ function: {
137
+ name: "analyze_data",
138
+ arguments: JSON.stringify({
139
+ dataset: "sales_2023",
140
+ metrics: ["revenue", "growth", "conversion"],
141
+ filters: {
142
+ region: "North America",
143
+ timeframe: { start: "2023-01-01", end: "2023-12-31" },
144
+ },
145
+ }),
146
+ },
147
+ },
148
+ {
149
+ id: "tool-2",
150
+ type: "function",
151
+ function: {
152
+ name: "generate_report",
153
+ arguments: JSON.stringify({
154
+ title: "Annual Sales Report",
155
+ format: "pdf",
156
+ sections: ["summary", "detailed_analysis", "recommendations"],
157
+ }),
158
+ },
159
+ },
160
+ ],
161
+ },
162
+ ],
163
+ };
164
+
165
+ expectRoundTripEquality(event);
166
+ });
167
+
168
+ it("should handle messages with undefined toolCalls", () => {
169
+ const event: MessagesSnapshotEvent = {
170
+ type: EventType.MESSAGES_SNAPSHOT,
171
+ messages: [
172
+ {
173
+ id: "msg-1",
174
+ role: "user",
175
+ content: "Hello",
176
+ },
177
+ {
178
+ id: "msg-2",
179
+ role: "assistant",
180
+ content: "Hi there!",
181
+ // No toolCalls field
182
+ },
183
+ ],
184
+ };
185
+
186
+ const encoded = encode(event);
187
+ const decoded = decode(encoded) as MessagesSnapshotEvent;
188
+
189
+ // Check messages length
190
+ expect(decoded.messages).toHaveLength(event.messages.length);
191
+
192
+ // Check first message
193
+ expect(decoded.messages[0].id).toBe(event.messages[0].id);
194
+ expect(decoded.messages[0].role).toBe(event.messages[0].role);
195
+ expect(decoded.messages[0].content).toBe(event.messages[0].content);
196
+ expect((decoded.messages[0] as any).toolCalls).toBeUndefined();
197
+
198
+ // Check second message
199
+ expect(decoded.messages[1].id).toBe(event.messages[1].id);
200
+ expect(decoded.messages[1].role).toBe(event.messages[1].role);
201
+ expect(decoded.messages[1].content).toBe(event.messages[1].content);
202
+ expect((decoded.messages[1] as any).toolCalls).toBeUndefined();
203
+ });
204
+
205
+ it("should handle messages with empty toolCalls array", () => {
206
+ const event: MessagesSnapshotEvent = {
207
+ type: EventType.MESSAGES_SNAPSHOT,
208
+ messages: [
209
+ {
210
+ id: "msg-1",
211
+ role: "assistant",
212
+ content: "I processed your request.",
213
+ toolCalls: [], // Explicitly empty array
214
+ },
215
+ ],
216
+ };
217
+
218
+ const encoded = encode(event);
219
+ const decoded = decode(encoded) as MessagesSnapshotEvent;
220
+
221
+ // Check that empty toolCalls array is converted to undefined
222
+ expect(decoded.messages[0].id).toBe(event.messages[0].id);
223
+ expect(decoded.messages[0].role).toBe(event.messages[0].role);
224
+ expect(decoded.messages[0].content).toBe(event.messages[0].content);
225
+ expect((decoded.messages[0] as any).toolCalls).toBeUndefined();
226
+ });
227
+
228
+ // Test for mixed messages (one with empty toolCalls, one with non-empty)
229
+ it("should correctly handle a mix of messages with empty and non-empty toolCalls", () => {
230
+ const event: MessagesSnapshotEvent = {
231
+ type: EventType.MESSAGES_SNAPSHOT,
232
+ messages: [
233
+ {
234
+ id: "msg-1",
235
+ role: "assistant",
236
+ content: "First message",
237
+ toolCalls: [], // Empty array that should be converted to undefined
238
+ },
239
+ {
240
+ id: "msg-2",
241
+ role: "assistant",
242
+ content: "Second message",
243
+ toolCalls: [
244
+ {
245
+ id: "tool-1",
246
+ type: "function",
247
+ function: {
248
+ name: "test_function",
249
+ arguments: "{}",
250
+ },
251
+ },
252
+ ],
253
+ },
254
+ ],
255
+ };
256
+
257
+ const encoded = encode(event);
258
+ const decoded = decode(encoded) as MessagesSnapshotEvent;
259
+
260
+ // Check first message (empty toolCalls should be undefined)
261
+ expect((decoded.messages[0] as any).toolCalls).toBeUndefined();
262
+
263
+ // Check second message (non-empty toolCalls should be preserved)
264
+ expect((decoded.messages[1] as any).toolCalls).toBeDefined();
265
+ expect((decoded.messages[1] as any).toolCalls?.length).toBe(1);
266
+ });
267
+ });
268
+ });
@@ -0,0 +1,194 @@
1
+ import { encode, decode } from "../src/proto";
2
+ import {
3
+ BaseEvent,
4
+ EventType,
5
+ StateDeltaEvent,
6
+ ToolCallStartEvent,
7
+ MessagesSnapshotEvent,
8
+ } from "@ag-ui/core";
9
+ import { describe, it, expect } from "@jest/globals";
10
+ import * as protoEvents from "../src/generated/events";
11
+
12
+ describe("Proto", () => {
13
+ it("should encode events", () => {
14
+ const event: BaseEvent = {
15
+ type: EventType.TOOL_CALL_START,
16
+ timestamp: Date.now(),
17
+ };
18
+ const encoded = encode(event);
19
+ expect(encoded).toBeInstanceOf(Uint8Array);
20
+ });
21
+ it("should handle state delta events encoding", () => {
22
+ const event: StateDeltaEvent = {
23
+ type: EventType.STATE_DELTA,
24
+ timestamp: Date.now(),
25
+ delta: [{ op: "add", path: "/foo", value: "bar" }],
26
+ };
27
+ const encoded = encode(event);
28
+ expect(encoded).toBeInstanceOf(Uint8Array);
29
+ });
30
+ // Test for round-trip encoding/decoding
31
+ it("should correctly round-trip encode/decode an event", () => {
32
+ const originalEvent: ToolCallStartEvent = {
33
+ type: EventType.TOOL_CALL_START,
34
+ toolCallId: "123",
35
+ toolCallName: "test",
36
+ };
37
+ const encoded = encode(originalEvent);
38
+ const decoded = decode(encoded);
39
+ expect(decoded.type).toBe(originalEvent.type);
40
+ expect(decoded.timestamp).toBe(originalEvent.timestamp);
41
+ });
42
+ // Test for StateDeltaEvent round-trip
43
+ it("should correctly round-trip encode/decode a StateDeltaEvent event", () => {
44
+ const originalEvent: StateDeltaEvent = {
45
+ type: EventType.STATE_DELTA,
46
+ timestamp: 1698765432123,
47
+ delta: [
48
+ { op: "add", path: "/foo", value: "bar" },
49
+ { op: "remove", path: "/baz" },
50
+ ],
51
+ };
52
+ const encoded = encode(originalEvent);
53
+ const decoded = decode(encoded) as StateDeltaEvent;
54
+
55
+ expect(decoded.type).toBe(originalEvent.type);
56
+ expect(decoded.timestamp).toBe(originalEvent.timestamp);
57
+ expect(decoded.delta).toHaveLength(originalEvent.delta.length);
58
+ // Check delta operations
59
+ expect(decoded.delta[0].op).toBe(originalEvent.delta[0].op);
60
+ expect(decoded.delta[0].path).toBe(originalEvent.delta[0].path);
61
+ expect(decoded.delta[0].value).toBe(originalEvent.delta[0].value);
62
+ expect(decoded.delta[1].op).toBe(originalEvent.delta[1].op);
63
+ expect(decoded.delta[1].path).toBe(originalEvent.delta[1].path);
64
+ });
65
+ // Test for complex values
66
+ it("should correctly handle complex values in StateDeltaEvent events", () => {
67
+ const complexValue = {
68
+ nested: {
69
+ array: [1, 2, 3],
70
+ object: { key: "value" },
71
+ },
72
+ boolean: true,
73
+ number: 42,
74
+ };
75
+ const originalEvent: StateDeltaEvent = {
76
+ type: EventType.STATE_DELTA,
77
+ timestamp: 1698765432123,
78
+ delta: [{ op: "add", path: "/complex", value: complexValue }],
79
+ };
80
+ const encoded = encode(originalEvent);
81
+ const decoded = decode(encoded) as StateDeltaEvent;
82
+ expect(decoded.delta[0].value).toEqual(complexValue);
83
+ });
84
+ it("should correctly encode/decode a MessagesSnapshotEvent event with tool calls", () => {
85
+ const originalEvent: MessagesSnapshotEvent = {
86
+ type: EventType.MESSAGES_SNAPSHOT,
87
+ timestamp: 1698765432123,
88
+ messages: [
89
+ {
90
+ id: "msg-1",
91
+ role: "user",
92
+ content: "Hello, can you help me with something?",
93
+ },
94
+ {
95
+ id: "msg-2",
96
+ role: "assistant",
97
+ content: "I'll help you analyze that data.",
98
+ toolCalls: [
99
+ {
100
+ id: "tool-call-1",
101
+ type: "function",
102
+ function: {
103
+ name: "analyze_data",
104
+ arguments: JSON.stringify({
105
+ dataset: "sales_q2",
106
+ metrics: ["revenue", "growth"],
107
+ }),
108
+ },
109
+ },
110
+ {
111
+ id: "tool-call-2",
112
+ type: "function",
113
+ function: {
114
+ name: "generate_chart",
115
+ arguments: JSON.stringify({
116
+ chartType: "bar",
117
+ data: "processed_data",
118
+ }),
119
+ },
120
+ },
121
+ ],
122
+ },
123
+ ],
124
+ };
125
+
126
+ const encoded = encode(originalEvent);
127
+ const decoded = decode(encoded) as MessagesSnapshotEvent;
128
+
129
+ // Verify basic event properties
130
+ expect(decoded.type).toBe(originalEvent.type);
131
+ expect(decoded.timestamp).toBe(originalEvent.timestamp);
132
+
133
+ // Verify messages array
134
+ expect(decoded.messages).toHaveLength(originalEvent.messages.length);
135
+
136
+ // Verify first message (user)
137
+ expect(decoded.messages[0].id).toBe(originalEvent.messages[0].id);
138
+ expect(decoded.messages[0].role).toBe(originalEvent.messages[0].role);
139
+ expect(decoded.messages[0].content).toBe(originalEvent.messages[0].content);
140
+
141
+ // Verify second message (assistant with tool calls)
142
+ expect(decoded.messages[1].id).toBe(originalEvent.messages[1].id);
143
+ expect(decoded.messages[1].role).toBe(originalEvent.messages[1].role);
144
+ expect(decoded.messages[1].content).toBe(originalEvent.messages[1].content);
145
+
146
+ // Verify tool calls
147
+ expect((decoded.messages[1] as any).toolCalls).toBeDefined();
148
+ expect((decoded.messages[1] as any).toolCalls).toHaveLength(
149
+ (originalEvent.messages[1] as any).toolCalls!.length,
150
+ );
151
+
152
+ // Verify first tool call
153
+ expect((decoded.messages[1] as any).toolCalls![0].id).toBe(
154
+ (originalEvent.messages[1] as any).toolCalls![0].id,
155
+ );
156
+ expect((decoded.messages[1] as any).toolCalls![0].type).toBe(
157
+ (originalEvent.messages[1] as any).toolCalls![0].type,
158
+ );
159
+ expect((decoded.messages[1] as any).toolCalls![0].function.name).toBe(
160
+ (originalEvent.messages[1] as any).toolCalls![0].function.name,
161
+ );
162
+
163
+ // Parse and compare JSON arguments
164
+ const decodedArgs1 = JSON.parse((decoded.messages[1] as any).toolCalls![0].function.arguments);
165
+ const originalArgs1 = JSON.parse(
166
+ (originalEvent.messages[1] as any).toolCalls![0].function.arguments,
167
+ );
168
+ expect(decodedArgs1).toEqual(originalArgs1);
169
+
170
+ // Verify second tool call
171
+ expect((decoded.messages[1] as any).toolCalls![1].id).toBe(
172
+ (originalEvent.messages[1] as any).toolCalls![1].id,
173
+ );
174
+ expect((decoded.messages[1] as any).toolCalls![1].function.name).toBe(
175
+ (originalEvent.messages[1] as any).toolCalls![1].function.name,
176
+ );
177
+
178
+ const decodedArgs2 = JSON.parse((decoded.messages[1] as any).toolCalls![1].function.arguments);
179
+ const originalArgs2 = JSON.parse(
180
+ (originalEvent.messages[1] as any).toolCalls![1].function.arguments,
181
+ );
182
+ expect(decodedArgs2).toEqual(originalArgs2);
183
+ });
184
+
185
+ // Test for the "Invalid event" error case
186
+ it("should throw an error when decoding an invalid event", () => {
187
+ // Create an empty Event message without any oneof field set
188
+ const emptyEvent = protoEvents.Event.create({});
189
+ const encodedEmpty = protoEvents.Event.encode(emptyEvent).finish();
190
+
191
+ // Attempt to decode the empty event should throw an error
192
+ expect(() => decode(encodedEmpty)).toThrow("Invalid event");
193
+ });
194
+ });