@datalayer/agent-runtimes 1.5.45 → 1.5.47
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/dist-embed/datalayer-app-main.js +4 -4
- package/lib/portable/conversation.d.ts +6 -0
- package/lib/portable/conversation.js +29 -1
- package/lib/portable/hosts/__tests__/fixtures/lock-with-jupyter.json +40 -0
- package/lib/portable/hosts/__tests__/fixtures/npm-ls-with-jupyter.json +21 -0
- package/lib/portable/hosts/agentClient.d.ts +167 -0
- package/lib/portable/hosts/agentClient.js +346 -0
- package/lib/portable/hosts/approvalRenderers.d.ts +43 -0
- package/lib/portable/hosts/approvalRenderers.js +180 -0
- package/lib/portable/hosts/client.d.ts +95 -0
- package/lib/portable/hosts/client.js +174 -0
- package/lib/portable/hosts/contracts.d.ts +199 -0
- package/lib/portable/hosts/contracts.js +235 -0
- package/lib/portable/hosts/contracts.json +381 -0
- package/lib/portable/hosts/deadLetters.d.ts +41 -0
- package/lib/portable/hosts/deadLetters.js +124 -0
- package/lib/portable/hosts/deliveries.d.ts +76 -0
- package/lib/portable/hosts/deliveries.js +147 -0
- package/lib/portable/hosts/forbiddenGraph.d.ts +77 -0
- package/lib/portable/hosts/forbiddenGraph.js +174 -0
- package/lib/portable/hosts/health.d.ts +35 -0
- package/lib/portable/hosts/health.js +92 -0
- package/lib/portable/hosts/index.d.ts +40 -0
- package/lib/portable/hosts/index.js +45 -0
- package/lib/portable/hosts/observability.d.ts +67 -0
- package/lib/portable/hosts/observability.js +171 -0
- package/lib/portable/hosts/postgresQueue.d.ts +55 -0
- package/lib/portable/hosts/postgresQueue.js +217 -0
- package/lib/portable/hosts/queue.d.ts +47 -0
- package/lib/portable/hosts/queue.js +63 -0
- package/lib/portable/hosts/quotas.d.ts +81 -0
- package/lib/portable/hosts/quotas.js +147 -0
- package/lib/portable/hosts/rateLimit.d.ts +13 -0
- package/lib/portable/hosts/rateLimit.js +8 -0
- package/lib/portable/hosts/resolution.d.ts +54 -0
- package/lib/portable/hosts/resolution.js +46 -0
- package/lib/portable/hosts/schema.d.ts +19 -0
- package/lib/portable/hosts/schema.js +81 -0
- package/lib/portable/hosts/secretCipher.d.ts +23 -0
- package/lib/portable/hosts/secretCipher.js +45 -0
- package/lib/portable/hosts/sessionUid.d.ts +7 -0
- package/lib/portable/hosts/sessionUid.js +28 -0
- package/lib/portable/hosts/turnState.d.ts +45 -0
- package/lib/portable/hosts/turnState.js +113 -0
- package/lib/portable/index.d.ts +2 -0
- package/lib/portable/index.js +3 -0
- package/lib/portable/semantic-events.json +480 -0
- package/lib/portable/semantic.d.ts +78 -0
- package/lib/portable/semantic.js +100 -0
- package/lib/portable/semanticOfAgUi.d.ts +41 -0
- package/lib/portable/semanticOfAgUi.js +108 -0
- package/lib/protocols/A2AAdapter.js +19 -0
- package/lib/test-setup.js +17 -14
- package/package.json +1 -1
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"about": "The semantic agent events a chat host renders (Slack, Discord: plans/DISCORD.md DC-005, plans/SLACK.md S-004, S-205), and the AG-UI events of agent-runtimes' session API (agent_runtimes/routes/apps.py, agent_runtimes/loop/apps/sessions.py, agent_runtimes/loop/apps/external_turns.py) each reduces to. src/portable/semanticOfAgUi.ts reduces every case (src/portable/__tests__/semantic.unit.test.ts); agent_runtimes/tests/test_semantic_events_contract.py holds the cases to what the runtime emits.",
|
|
4
|
+
"kinds": [
|
|
5
|
+
"text",
|
|
6
|
+
"progress",
|
|
7
|
+
"tool",
|
|
8
|
+
"approval",
|
|
9
|
+
"table",
|
|
10
|
+
"file",
|
|
11
|
+
"citation",
|
|
12
|
+
"ask",
|
|
13
|
+
"completion",
|
|
14
|
+
"stop",
|
|
15
|
+
"error"
|
|
16
|
+
],
|
|
17
|
+
"producers": {
|
|
18
|
+
"text": "AG-UI TEXT_MESSAGE_CONTENT / TEXT_MESSAGE_CHUNK delta",
|
|
19
|
+
"progress": "AG-UI STEP_STARTED stepName",
|
|
20
|
+
"tool": "AG-UI TOOL_CALL_START (running), TOOL_CALL_RESULT (complete, or failed when success is false)",
|
|
21
|
+
"approval": "AG-UI TOOL_CALL_RESULT whose result says pending_approval; the decision itself arrives as an approval.requested delivery",
|
|
22
|
+
"table": "a Markdown table in the answer (src/portable/semantic.ts answerParts); no AG-UI event carries one",
|
|
23
|
+
"file": "none in agent-runtimes 1.5.45: reserved, rendered as a safe HTTPS link when produced",
|
|
24
|
+
"citation": "an HTTPS Markdown link in the answer (answerParts); no AG-UI event carries one",
|
|
25
|
+
"ask": "AG-UI RUN_FINISHED with result.asking (agent_runtimes/loop/apps/sessions.py question_of); the run stream carries no loop.ask event",
|
|
26
|
+
"completion": "AG-UI RUN_FINISHED without asking",
|
|
27
|
+
"stop": "the host itself, after its own Stop: a stopped session's stream ends without RUN_FINISHED or RUN_ERROR (agent_runtimes/loop/apps/sessions.py stop, _close); no AG-UI event carries it",
|
|
28
|
+
"error": "AG-UI RUN_ERROR message"
|
|
29
|
+
},
|
|
30
|
+
"cases": [
|
|
31
|
+
{
|
|
32
|
+
"agui": [
|
|
33
|
+
{
|
|
34
|
+
"type": "TEXT_MESSAGE_CONTENT",
|
|
35
|
+
"messageId": "m1",
|
|
36
|
+
"delta": "Option B "
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"semantic": [
|
|
40
|
+
{
|
|
41
|
+
"kind": "text",
|
|
42
|
+
"text": "Option B "
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"agui": [
|
|
48
|
+
{
|
|
49
|
+
"type": "TEXT_MESSAGE_CHUNK",
|
|
50
|
+
"messageId": "m1",
|
|
51
|
+
"delta": "is safer."
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"semantic": [
|
|
55
|
+
{
|
|
56
|
+
"kind": "text",
|
|
57
|
+
"text": "is safer."
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"agui": [
|
|
63
|
+
{
|
|
64
|
+
"type": "TEXT_MESSAGE_CONTENT",
|
|
65
|
+
"messageId": "m1",
|
|
66
|
+
"delta": ""
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"semantic": []
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"agui": [
|
|
73
|
+
{
|
|
74
|
+
"type": "STEP_STARTED",
|
|
75
|
+
"stepName": "Reading the launch notes"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"semantic": [
|
|
79
|
+
{
|
|
80
|
+
"kind": "progress",
|
|
81
|
+
"label": "Reading the launch notes"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"agui": [
|
|
87
|
+
{
|
|
88
|
+
"type": "TOOL_CALL_START",
|
|
89
|
+
"toolCallId": "c1",
|
|
90
|
+
"toolCallName": "search"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "TOOL_CALL_ARGS",
|
|
94
|
+
"toolCallId": "c1",
|
|
95
|
+
"delta": "{\"q\":\"launch\"}"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"type": "TOOL_CALL_END",
|
|
99
|
+
"toolCallId": "c1"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "TOOL_CALL_RESULT",
|
|
103
|
+
"toolCallId": "c1",
|
|
104
|
+
"messageId": "r1",
|
|
105
|
+
"content": "{\"success\": true}"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"semantic": [
|
|
109
|
+
{
|
|
110
|
+
"kind": "tool",
|
|
111
|
+
"id": "c1",
|
|
112
|
+
"name": "search",
|
|
113
|
+
"status": "running"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"kind": "tool",
|
|
117
|
+
"id": "c1",
|
|
118
|
+
"name": "search",
|
|
119
|
+
"status": "complete"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"agui": [
|
|
125
|
+
{
|
|
126
|
+
"type": "TOOL_CALL_START",
|
|
127
|
+
"toolCallId": "c2",
|
|
128
|
+
"toolCallName": "run_code"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"type": "TOOL_CALL_RESULT",
|
|
132
|
+
"toolCallId": "c2",
|
|
133
|
+
"messageId": "r2",
|
|
134
|
+
"content": "{\"success\": false, \"execution_error\": \"boom\"}"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"semantic": [
|
|
138
|
+
{
|
|
139
|
+
"kind": "tool",
|
|
140
|
+
"id": "c2",
|
|
141
|
+
"name": "run_code",
|
|
142
|
+
"status": "running"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"kind": "tool",
|
|
146
|
+
"id": "c2",
|
|
147
|
+
"name": "run_code",
|
|
148
|
+
"status": "failed"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"agui": [
|
|
154
|
+
{
|
|
155
|
+
"type": "TOOL_CALL_START",
|
|
156
|
+
"toolCallId": "c3",
|
|
157
|
+
"toolCallName": "send_email"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"type": "TOOL_CALL_RESULT",
|
|
161
|
+
"toolCallId": "c3",
|
|
162
|
+
"messageId": "r3",
|
|
163
|
+
"content": "{\"pending_approval\": true}"
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"semantic": [
|
|
167
|
+
{
|
|
168
|
+
"kind": "tool",
|
|
169
|
+
"id": "c3",
|
|
170
|
+
"name": "send_email",
|
|
171
|
+
"status": "running"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"kind": "approval",
|
|
175
|
+
"toolCallId": "c3",
|
|
176
|
+
"toolName": "send_email"
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"agui": [
|
|
182
|
+
{
|
|
183
|
+
"type": "RUN_FINISHED",
|
|
184
|
+
"threadId": "S1",
|
|
185
|
+
"runId": "t1"
|
|
186
|
+
}
|
|
187
|
+
],
|
|
188
|
+
"semantic": [
|
|
189
|
+
{
|
|
190
|
+
"kind": "completion"
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"agui": [
|
|
196
|
+
{
|
|
197
|
+
"type": "RUN_FINISHED",
|
|
198
|
+
"threadId": "S1",
|
|
199
|
+
"runId": "t1",
|
|
200
|
+
"result": {
|
|
201
|
+
"asking": {
|
|
202
|
+
"kind": "choice",
|
|
203
|
+
"prompt": "Which option?",
|
|
204
|
+
"options": ["A", "B"]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"semantic": [
|
|
210
|
+
{
|
|
211
|
+
"kind": "ask",
|
|
212
|
+
"question": {
|
|
213
|
+
"kind": "choice",
|
|
214
|
+
"prompt": "Which option?",
|
|
215
|
+
"options": ["A", "B"]
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"agui": [
|
|
222
|
+
{
|
|
223
|
+
"type": "RUN_FINISHED",
|
|
224
|
+
"threadId": "S1",
|
|
225
|
+
"runId": "t1",
|
|
226
|
+
"result": {
|
|
227
|
+
"asking": {
|
|
228
|
+
"kind": "text",
|
|
229
|
+
"prompt": "Which quarter?"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
"semantic": [
|
|
235
|
+
{
|
|
236
|
+
"kind": "ask",
|
|
237
|
+
"question": {
|
|
238
|
+
"kind": "text",
|
|
239
|
+
"prompt": "Which quarter?"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"agui": [
|
|
246
|
+
{
|
|
247
|
+
"type": "RUN_FINISHED",
|
|
248
|
+
"threadId": "S1",
|
|
249
|
+
"runId": "t1",
|
|
250
|
+
"result": {
|
|
251
|
+
"asking": {
|
|
252
|
+
"kind": "signature",
|
|
253
|
+
"prompt": "Sign here"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"semantic": [
|
|
259
|
+
{
|
|
260
|
+
"kind": "ask",
|
|
261
|
+
"question": {
|
|
262
|
+
"kind": "form",
|
|
263
|
+
"prompt": "Sign here"
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"agui": [
|
|
270
|
+
{
|
|
271
|
+
"type": "RUN_FINISHED",
|
|
272
|
+
"threadId": "S1",
|
|
273
|
+
"runId": "t1",
|
|
274
|
+
"result": {
|
|
275
|
+
"asking": {
|
|
276
|
+
"kind": "form",
|
|
277
|
+
"prompt": "Your details",
|
|
278
|
+
"schema": {}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
"semantic": [
|
|
284
|
+
{
|
|
285
|
+
"kind": "ask",
|
|
286
|
+
"question": {
|
|
287
|
+
"kind": "form",
|
|
288
|
+
"prompt": "Your details"
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"agui": [
|
|
295
|
+
{
|
|
296
|
+
"type": "RUN_FINISHED",
|
|
297
|
+
"threadId": "S1",
|
|
298
|
+
"runId": "t1",
|
|
299
|
+
"result": {
|
|
300
|
+
"asking": {
|
|
301
|
+
"kind": "file",
|
|
302
|
+
"prompt": "Your receipt",
|
|
303
|
+
"accept": ["application/pdf"],
|
|
304
|
+
"max_bytes": 1000000
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
"semantic": [
|
|
310
|
+
{
|
|
311
|
+
"kind": "ask",
|
|
312
|
+
"question": {
|
|
313
|
+
"kind": "file",
|
|
314
|
+
"prompt": "Your receipt"
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"agui": [
|
|
321
|
+
{
|
|
322
|
+
"type": "CUSTOM",
|
|
323
|
+
"name": "loop.turn",
|
|
324
|
+
"value": {
|
|
325
|
+
"turn": "t1",
|
|
326
|
+
"external_event_id": "Ev1",
|
|
327
|
+
"replayed": false,
|
|
328
|
+
"state": "running"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
],
|
|
332
|
+
"semantic": []
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"agui": [
|
|
336
|
+
{
|
|
337
|
+
"type": "RUN_ERROR",
|
|
338
|
+
"message": "The model is unavailable."
|
|
339
|
+
}
|
|
340
|
+
],
|
|
341
|
+
"semantic": [
|
|
342
|
+
{
|
|
343
|
+
"kind": "error",
|
|
344
|
+
"message": "The model is unavailable."
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"agui": [
|
|
350
|
+
{
|
|
351
|
+
"type": "CUSTOM",
|
|
352
|
+
"name": "loop.session",
|
|
353
|
+
"value": {
|
|
354
|
+
"uid": "S1"
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"type": "CUSTOM",
|
|
359
|
+
"name": "reactor.ui",
|
|
360
|
+
"value": {}
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"type": "RUN_STARTED",
|
|
364
|
+
"threadId": "S1",
|
|
365
|
+
"runId": "t1"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"type": "MESSAGES_SNAPSHOT",
|
|
369
|
+
"messages": []
|
|
370
|
+
}
|
|
371
|
+
],
|
|
372
|
+
"semantic": []
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"agui": [
|
|
376
|
+
{
|
|
377
|
+
"type": "CUSTOM",
|
|
378
|
+
"name": "loop.turn",
|
|
379
|
+
"value": {
|
|
380
|
+
"session": "S1",
|
|
381
|
+
"turn": "t1",
|
|
382
|
+
"external_event_id": "Ev1",
|
|
383
|
+
"replayed": true,
|
|
384
|
+
"state": "finished"
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
],
|
|
388
|
+
"semantic": []
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"agui": [
|
|
392
|
+
{
|
|
393
|
+
"type": "CUSTOM",
|
|
394
|
+
"name": "loop.turn",
|
|
395
|
+
"value": {
|
|
396
|
+
"session": "S1",
|
|
397
|
+
"turn": "t1",
|
|
398
|
+
"external_event_id": "Ev1",
|
|
399
|
+
"replayed": true,
|
|
400
|
+
"state": "failed"
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
],
|
|
404
|
+
"semantic": []
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"agui": [
|
|
408
|
+
{
|
|
409
|
+
"type": "CUSTOM",
|
|
410
|
+
"name": "loop.page",
|
|
411
|
+
"value": {
|
|
412
|
+
"inputs": {},
|
|
413
|
+
"outputs": {}
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"type": "CUSTOM",
|
|
418
|
+
"name": "voice.say",
|
|
419
|
+
"value": {
|
|
420
|
+
"text": "Hello",
|
|
421
|
+
"voice": "",
|
|
422
|
+
"language": "en"
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"type": "CUSTOM",
|
|
427
|
+
"name": "voice.interrupted",
|
|
428
|
+
"value": {}
|
|
429
|
+
}
|
|
430
|
+
],
|
|
431
|
+
"semantic": []
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"agui": [
|
|
435
|
+
{
|
|
436
|
+
"type": "TEXT_MESSAGE_START",
|
|
437
|
+
"messageId": "m2",
|
|
438
|
+
"role": "assistant"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
"type": "TEXT_MESSAGE_END",
|
|
442
|
+
"messageId": "m2"
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
"type": "STEP_FINISHED",
|
|
446
|
+
"stepName": "Reading the launch notes"
|
|
447
|
+
}
|
|
448
|
+
],
|
|
449
|
+
"semantic": []
|
|
450
|
+
}
|
|
451
|
+
],
|
|
452
|
+
"answers": [
|
|
453
|
+
{
|
|
454
|
+
"answer": "Two options.\n\n| Option | Risk |\n|---|---|\n| A | High |\n| B | Low |\n\nSee [the launch notes](https://datalayer.ai/notes) and [an unsafe link](javascript:alert(1)).",
|
|
455
|
+
"parts": [
|
|
456
|
+
{
|
|
457
|
+
"kind": "text",
|
|
458
|
+
"text": "Two options."
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"kind": "table",
|
|
462
|
+
"columns": ["Option", "Risk"],
|
|
463
|
+
"rows": [
|
|
464
|
+
["A", "High"],
|
|
465
|
+
["B", "Low"]
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"kind": "text",
|
|
470
|
+
"text": "See [the launch notes](https://datalayer.ai/notes) and [an unsafe link](javascript:alert(1))."
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"kind": "citation",
|
|
474
|
+
"title": "the launch notes",
|
|
475
|
+
"url": "https://datalayer.ai/notes"
|
|
476
|
+
}
|
|
477
|
+
]
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The semantic agent events a chat host renders (Slack, Discord), version 1:
|
|
3
|
+
* a session's AG-UI stream reduced to what a host shows (`semanticOfAgUi.ts`),
|
|
4
|
+
* never a notebook widget or a web component. The contract and its fixture
|
|
5
|
+
* cases are `semantic-events.json`, beside this file, tested here
|
|
6
|
+
* (`__tests__/semantic.unit.test.ts`) and by the runtime that emits the
|
|
7
|
+
* events (`agent_runtimes/tests/test_semantic_events_contract.py`).
|
|
8
|
+
*
|
|
9
|
+
* Moved from the Slack service (plans/DISCORD.md DC-005, SLACK S-004, S-205).
|
|
10
|
+
*
|
|
11
|
+
* @module portable/semantic
|
|
12
|
+
*/
|
|
13
|
+
export declare const SEMANTIC_EVENTS_VERSION = 1;
|
|
14
|
+
export declare const SEMANTIC_KINDS: readonly ["text", "progress", "tool", "approval", "table", "file", "citation", "ask", "completion", "stop", "error"];
|
|
15
|
+
export type SemanticKind = (typeof SEMANTIC_KINDS)[number];
|
|
16
|
+
export type AskQuestion = Readonly<{
|
|
17
|
+
/** `text` and `choice` are answered in the host; `file` and `form` hand off to Datalayer. */
|
|
18
|
+
kind: 'text' | 'choice' | 'file' | 'form';
|
|
19
|
+
prompt: string;
|
|
20
|
+
options?: readonly string[];
|
|
21
|
+
}>;
|
|
22
|
+
export type SemanticEvent = Readonly<{
|
|
23
|
+
kind: 'text';
|
|
24
|
+
text: string;
|
|
25
|
+
}> | Readonly<{
|
|
26
|
+
kind: 'progress';
|
|
27
|
+
label: string;
|
|
28
|
+
}> | Readonly<{
|
|
29
|
+
kind: 'tool';
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
status: 'running' | 'complete' | 'failed';
|
|
33
|
+
}> | Readonly<{
|
|
34
|
+
kind: 'approval';
|
|
35
|
+
toolCallId: string;
|
|
36
|
+
toolName: string;
|
|
37
|
+
}> | Readonly<{
|
|
38
|
+
kind: 'table';
|
|
39
|
+
columns: readonly string[];
|
|
40
|
+
rows: readonly (readonly string[])[];
|
|
41
|
+
}> | Readonly<{
|
|
42
|
+
kind: 'file';
|
|
43
|
+
name: string;
|
|
44
|
+
url: string;
|
|
45
|
+
mediaType?: string;
|
|
46
|
+
}> | Readonly<{
|
|
47
|
+
kind: 'citation';
|
|
48
|
+
title: string;
|
|
49
|
+
url: string;
|
|
50
|
+
}> | Readonly<{
|
|
51
|
+
kind: 'ask';
|
|
52
|
+
question: AskQuestion;
|
|
53
|
+
}> | Readonly<{
|
|
54
|
+
kind: 'completion';
|
|
55
|
+
text?: string;
|
|
56
|
+
}> | Readonly<{
|
|
57
|
+
kind: 'stop';
|
|
58
|
+
}> | Readonly<{
|
|
59
|
+
kind: 'error';
|
|
60
|
+
message: string;
|
|
61
|
+
}>;
|
|
62
|
+
/** Whether an event ends the turn's presentation. */
|
|
63
|
+
export declare function isTerminal(event: SemanticEvent): boolean;
|
|
64
|
+
/** One part of a finished answer: words, a table, or a citation. */
|
|
65
|
+
export type AnswerPart = Readonly<{
|
|
66
|
+
kind: 'text';
|
|
67
|
+
text: string;
|
|
68
|
+
}> | Extract<SemanticEvent, {
|
|
69
|
+
kind: 'table';
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'citation';
|
|
72
|
+
}>;
|
|
73
|
+
/**
|
|
74
|
+
* The parts of an answer as a host shows them: its Markdown tables as tables,
|
|
75
|
+
* its HTTPS links as citations (once each, in order), the rest as words. Only
|
|
76
|
+
* `https:` links are citations: any other scheme stays words.
|
|
77
|
+
*/
|
|
78
|
+
export declare function answerParts(answer: string): AnswerPart[];
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The semantic agent events a chat host renders (Slack, Discord), version 1:
|
|
7
|
+
* a session's AG-UI stream reduced to what a host shows (`semanticOfAgUi.ts`),
|
|
8
|
+
* never a notebook widget or a web component. The contract and its fixture
|
|
9
|
+
* cases are `semantic-events.json`, beside this file, tested here
|
|
10
|
+
* (`__tests__/semantic.unit.test.ts`) and by the runtime that emits the
|
|
11
|
+
* events (`agent_runtimes/tests/test_semantic_events_contract.py`).
|
|
12
|
+
*
|
|
13
|
+
* Moved from the Slack service (plans/DISCORD.md DC-005, SLACK S-004, S-205).
|
|
14
|
+
*
|
|
15
|
+
* @module portable/semantic
|
|
16
|
+
*/
|
|
17
|
+
export const SEMANTIC_EVENTS_VERSION = 1;
|
|
18
|
+
export const SEMANTIC_KINDS = [
|
|
19
|
+
'text',
|
|
20
|
+
'progress',
|
|
21
|
+
'tool',
|
|
22
|
+
'approval',
|
|
23
|
+
'table',
|
|
24
|
+
'file',
|
|
25
|
+
'citation',
|
|
26
|
+
'ask',
|
|
27
|
+
'completion',
|
|
28
|
+
'stop',
|
|
29
|
+
'error',
|
|
30
|
+
];
|
|
31
|
+
/** Whether an event ends the turn's presentation. */
|
|
32
|
+
export function isTerminal(event) {
|
|
33
|
+
return (event.kind === 'completion' ||
|
|
34
|
+
event.kind === 'stop' ||
|
|
35
|
+
event.kind === 'error' ||
|
|
36
|
+
event.kind === 'ask');
|
|
37
|
+
}
|
|
38
|
+
const TABLE_ROW = /^\s*\|.*\|\s*$/;
|
|
39
|
+
const TABLE_RULE = /^\s*\|(\s*:?-{3,}:?\s*\|)+\s*$/;
|
|
40
|
+
const LINK = /\[([^\]\n]{1,300})\]\((https:\/\/[^\s)]{1,2000})\)/g;
|
|
41
|
+
function cells(line) {
|
|
42
|
+
return line
|
|
43
|
+
.trim()
|
|
44
|
+
.replace(/^\|/, '')
|
|
45
|
+
.replace(/\|$/, '')
|
|
46
|
+
.split('|')
|
|
47
|
+
.map(cell => cell.trim());
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The parts of an answer as a host shows them: its Markdown tables as tables,
|
|
51
|
+
* its HTTPS links as citations (once each, in order), the rest as words. Only
|
|
52
|
+
* `https:` links are citations: any other scheme stays words.
|
|
53
|
+
*/
|
|
54
|
+
export function answerParts(answer) {
|
|
55
|
+
const parts = [];
|
|
56
|
+
const lines = answer.split('\n');
|
|
57
|
+
let words = [];
|
|
58
|
+
const flush = () => {
|
|
59
|
+
const text = words.join('\n').trim();
|
|
60
|
+
if (text) {
|
|
61
|
+
parts.push({ kind: 'text', text });
|
|
62
|
+
}
|
|
63
|
+
words = [];
|
|
64
|
+
};
|
|
65
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
66
|
+
const line = lines[index] ?? '';
|
|
67
|
+
const rule = lines[index + 1] ?? '';
|
|
68
|
+
if (TABLE_ROW.test(line) && TABLE_RULE.test(rule)) {
|
|
69
|
+
flush();
|
|
70
|
+
const columns = cells(line);
|
|
71
|
+
const rows = [];
|
|
72
|
+
index += 2;
|
|
73
|
+
while (index < lines.length && TABLE_ROW.test(lines[index] ?? '')) {
|
|
74
|
+
const row = cells(lines[index] ?? '');
|
|
75
|
+
rows.push(columns.map((_, column) => row[column] ?? ''));
|
|
76
|
+
index += 1;
|
|
77
|
+
}
|
|
78
|
+
index -= 1;
|
|
79
|
+
parts.push({ kind: 'table', columns, rows });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
words.push(line);
|
|
83
|
+
}
|
|
84
|
+
flush();
|
|
85
|
+
const seen = new Set();
|
|
86
|
+
for (const part of [...parts]) {
|
|
87
|
+
if (part.kind !== 'text') {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
for (const match of part.text.matchAll(LINK)) {
|
|
91
|
+
const [, title, url] = match;
|
|
92
|
+
if (!title || !url || seen.has(url)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
seen.add(url);
|
|
96
|
+
parts.push({ kind: 'citation', title, url });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return parts;
|
|
100
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A session's AG-UI events reduced to the semantic events a chat host
|
|
3
|
+
* renders (`semantic.ts`, version 1). A stream is read with `AgUiFrames` or
|
|
4
|
+
* `readRunStream` (`agui.ts`); this says what each event means to a host.
|
|
5
|
+
*
|
|
6
|
+
* The runtime's `loop.turn` event says which turn a stream is and where it
|
|
7
|
+
* stands (`running`, `finished`, `failed`: agent_runtimes/loop/apps/
|
|
8
|
+
* external_turns.py); a stopped session's stream ends without a run end,
|
|
9
|
+
* so `stop` is never read from an event: the host that pressed Stop says it.
|
|
10
|
+
* A question is read from `RUN_FINISHED.result.asking` only: the run stream
|
|
11
|
+
* carries no `loop.ask` event (that is the record's word, `record.py`).
|
|
12
|
+
*
|
|
13
|
+
* Moved from the Slack service (plans/DISCORD.md DC-005, SLACK S-205).
|
|
14
|
+
*
|
|
15
|
+
* @module portable/semanticOfAgUi
|
|
16
|
+
*/
|
|
17
|
+
import type { AgUiEvent } from './agui';
|
|
18
|
+
import type { AskQuestion, SemanticEvent } from './semantic';
|
|
19
|
+
/** What one turn says of itself: its id, and whether it is a replay. */
|
|
20
|
+
export type TurnInfo = Readonly<{
|
|
21
|
+
replayed: boolean;
|
|
22
|
+
session: string;
|
|
23
|
+
state: string;
|
|
24
|
+
turn: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** The turn a `loop.turn` event names, or `undefined` for any other event. */
|
|
27
|
+
export declare function turnOf(event: AgUiEvent): TurnInfo | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The question a turn ends on (`RUN_FINISHED.result.asking`), as
|
|
30
|
+
* a host asks it, or `undefined` when the value is not a question. A kind a
|
|
31
|
+
* host does not know is answered in Datalayer, as a form (SLACK S-307):
|
|
32
|
+
* never guessed to be text. (`conversation.ts`'s `questionOf`, for a native
|
|
33
|
+
* client, throws on such a kind instead.)
|
|
34
|
+
*/
|
|
35
|
+
export declare function askQuestionOf(value: unknown): AskQuestion | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The semantic events (version 1) one AG-UI event means: none for an event a
|
|
38
|
+
* host does not show. `tools` keeps each running call's name by its id, for
|
|
39
|
+
* its result.
|
|
40
|
+
*/
|
|
41
|
+
export declare function semanticOf(event: AgUiEvent, tools: Map<string, string>): SemanticEvent[];
|