@datalayer/agent-runtimes 1.5.44 → 1.5.46

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 (69) hide show
  1. package/dist-embed/chunks/{ChatView-kCmBbnDa.js → ChatView-Dy-IgGFL.js} +1 -1
  2. package/dist-embed/datalayer-app-main.js +99 -94
  3. package/lib/apps/plugins/chat/ChatView.js +2 -2
  4. package/lib/chat/ChatFloating.js +1 -1
  5. package/lib/chat/base/ChatBase.js +23 -8
  6. package/lib/chat/messages/ChatMessageList.d.ts +7 -1
  7. package/lib/chat/messages/ChatMessageList.js +8 -2
  8. package/lib/portable/hosts/__tests__/fixtures/lock-with-jupyter.json +40 -0
  9. package/lib/portable/hosts/__tests__/fixtures/npm-ls-with-jupyter.json +21 -0
  10. package/lib/portable/hosts/agentClient.d.ts +167 -0
  11. package/lib/portable/hosts/agentClient.js +346 -0
  12. package/lib/portable/hosts/approvalRenderers.d.ts +43 -0
  13. package/lib/portable/hosts/approvalRenderers.js +180 -0
  14. package/lib/portable/hosts/client.d.ts +95 -0
  15. package/lib/portable/hosts/client.js +174 -0
  16. package/lib/portable/hosts/contracts.d.ts +199 -0
  17. package/lib/portable/hosts/contracts.js +235 -0
  18. package/lib/portable/hosts/contracts.json +381 -0
  19. package/lib/portable/hosts/deadLetters.d.ts +41 -0
  20. package/lib/portable/hosts/deadLetters.js +124 -0
  21. package/lib/portable/hosts/deliveries.d.ts +76 -0
  22. package/lib/portable/hosts/deliveries.js +147 -0
  23. package/lib/portable/hosts/forbiddenGraph.d.ts +77 -0
  24. package/lib/portable/hosts/forbiddenGraph.js +174 -0
  25. package/lib/portable/hosts/health.d.ts +35 -0
  26. package/lib/portable/hosts/health.js +92 -0
  27. package/lib/portable/hosts/index.d.ts +40 -0
  28. package/lib/portable/hosts/index.js +45 -0
  29. package/lib/portable/hosts/observability.d.ts +67 -0
  30. package/lib/portable/hosts/observability.js +171 -0
  31. package/lib/portable/hosts/postgresQueue.d.ts +55 -0
  32. package/lib/portable/hosts/postgresQueue.js +217 -0
  33. package/lib/portable/hosts/queue.d.ts +47 -0
  34. package/lib/portable/hosts/queue.js +63 -0
  35. package/lib/portable/hosts/quotas.d.ts +81 -0
  36. package/lib/portable/hosts/quotas.js +147 -0
  37. package/lib/portable/hosts/rateLimit.d.ts +13 -0
  38. package/lib/portable/hosts/rateLimit.js +8 -0
  39. package/lib/portable/hosts/resolution.d.ts +54 -0
  40. package/lib/portable/hosts/resolution.js +46 -0
  41. package/lib/portable/hosts/schema.d.ts +19 -0
  42. package/lib/portable/hosts/schema.js +81 -0
  43. package/lib/portable/hosts/secretCipher.d.ts +23 -0
  44. package/lib/portable/hosts/secretCipher.js +45 -0
  45. package/lib/portable/hosts/sessionUid.d.ts +7 -0
  46. package/lib/portable/hosts/sessionUid.js +28 -0
  47. package/lib/portable/hosts/turnState.d.ts +45 -0
  48. package/lib/portable/hosts/turnState.js +113 -0
  49. package/lib/portable/index.d.ts +2 -0
  50. package/lib/portable/index.js +3 -0
  51. package/lib/portable/semantic-events.json +480 -0
  52. package/lib/portable/semantic.d.ts +78 -0
  53. package/lib/portable/semantic.js +100 -0
  54. package/lib/portable/semanticOfAgUi.d.ts +41 -0
  55. package/lib/portable/semanticOfAgUi.js +108 -0
  56. package/lib/protocols/A2AAdapter.js +19 -0
  57. package/lib/protocols/VercelAIAdapter.js +11 -0
  58. package/lib/specs/voices.js +62 -0
  59. package/lib/test-setup.js +17 -14
  60. package/lib/types/chat.d.ts +10 -0
  61. package/lib/voice/ComposerVoice.js +12 -3
  62. package/lib/voice/captions.d.ts +31 -0
  63. package/lib/voice/captions.js +156 -0
  64. package/lib/voice/handsFree.d.ts +12 -0
  65. package/lib/voice/handsFree.js +18 -0
  66. package/lib/voice/serverHearing.d.ts +29 -0
  67. package/lib/voice/serverHearing.js +78 -2
  68. package/package.json +1 -1
  69. package/scripts/voice/measure.py +77 -17
@@ -0,0 +1,113 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export class TurnState {
6
+ #answer = '';
7
+ #asking;
8
+ #approvals = [];
9
+ #ended;
10
+ #error;
11
+ #files = [];
12
+ #status = 'Working…';
13
+ #tools = new Map();
14
+ /** Whether the turn finished while it streamed: else a `turn.completed` delivery finishes it. */
15
+ get complete() {
16
+ return this.#ended === 'completion';
17
+ }
18
+ /** Whether the turn ended (answered, stopped, failed) or waits on a question. */
19
+ get ended() {
20
+ return this.#ended !== undefined || this.#asking !== undefined;
21
+ }
22
+ /** Whether the turn still runs: not ended, and asking nothing. */
23
+ get running() {
24
+ return !this.ended;
25
+ }
26
+ /** The answer so far, its tables and citations as Markdown. */
27
+ get answer() {
28
+ return this.#answer;
29
+ }
30
+ /** The question the turn ends on, if any. */
31
+ get asking() {
32
+ return this.#asking;
33
+ }
34
+ /** The tools whose approval the turn waited on, in order. */
35
+ get approvals() {
36
+ return this.#approvals;
37
+ }
38
+ /** How the turn ended, if it did. */
39
+ get ending() {
40
+ return this.#ended;
41
+ }
42
+ /** What the run said when it failed. */
43
+ get error() {
44
+ return this.#error;
45
+ }
46
+ get files() {
47
+ return this.#files;
48
+ }
49
+ /** The status line: what the turn is doing now. */
50
+ get status() {
51
+ return this.#status;
52
+ }
53
+ /** Each tool the turn used, by its call, in the order first seen. */
54
+ get tools() {
55
+ return this.#tools;
56
+ }
57
+ apply(event) {
58
+ switch (event.kind) {
59
+ case 'text':
60
+ this.#answer += event.text;
61
+ break;
62
+ case 'progress':
63
+ this.#status = event.label;
64
+ break;
65
+ case 'tool':
66
+ this.#tools.set(event.id || event.name, {
67
+ name: event.name,
68
+ status: event.status,
69
+ });
70
+ this.#status = `${event.status === 'running' ? 'Using' : event.status === 'failed' ? 'Failed:' : 'Used'} ${event.name}`;
71
+ break;
72
+ case 'approval':
73
+ this.#approvals.push(event.toolName);
74
+ this.#status = `Waiting for approval to use ${event.toolName}`;
75
+ break;
76
+ case 'file':
77
+ this.#files.push({
78
+ mediaType: event.mediaType,
79
+ name: event.name,
80
+ url: event.url,
81
+ });
82
+ break;
83
+ case 'table':
84
+ this.#answer += `\n\n| ${event.columns.join(' | ')} |\n|${event.columns.map(() => '---').join('|')}|\n${event.rows.map(row => `| ${row.join(' | ')} |`).join('\n')}\n`;
85
+ break;
86
+ case 'citation':
87
+ this.#answer += `\n[${event.title}](${event.url})`;
88
+ break;
89
+ case 'ask':
90
+ this.#asking = event.question;
91
+ this.#status = 'Waiting for your answer';
92
+ break;
93
+ case 'completion':
94
+ // The streamed words are the answer: a completion's text only
95
+ // stands in for none, never repeated after them.
96
+ if (event.text && !this.#answer) {
97
+ this.#answer = event.text;
98
+ }
99
+ this.#ended = 'completion';
100
+ this.#status = 'Complete';
101
+ break;
102
+ case 'stop':
103
+ this.#ended = 'stop';
104
+ this.#status = 'Stopped';
105
+ break;
106
+ case 'error':
107
+ this.#ended = 'error';
108
+ this.#error = event.message;
109
+ this.#status = 'Could not finish';
110
+ break;
111
+ }
112
+ }
113
+ }
@@ -9,6 +9,8 @@
9
9
  export { messageOfApproval, normalizeApproval, whyAsked, type ApprovalArgs, type ApprovalRecord, type MessageAsked, } from './approvals';
10
10
  export { actionOf, APPROVAL_CARD_WORDS, approvalCardOf, argumentsShown, type ApprovalCard, type ApprovalCardProps, type ApprovalCardSource, } from './approvalCard';
11
11
  export { AgUiFrames, endsRun, eventsOfStream, NOT_STREAMING, REACTOR_UI_NAME, readRunStream, RUN_CUT_SHORT, toolResultOf, UI_ON_RUN, type AgUiEvent, type ToolResultSaid, } from './agui';
12
+ export { answerParts, isTerminal, SEMANTIC_EVENTS_VERSION, SEMANTIC_KINDS, type AnswerPart, type AskQuestion, type SemanticEvent, type SemanticKind, } from './semantic';
13
+ export { askQuestionOf, semanticOf, turnOf, type TurnInfo, } from './semanticOfAgUi';
12
14
  export { AG_UI_NOT_ALLOWED, AG_UI_NOT_ON_RUNTIME, agUiRefusal, refusalBody, refusalDetail, } from './agUiRefusal';
13
15
  export { ASKED_FOR_TAG, askedOf, RUN_END_WORDS } from './records';
14
16
  export { messagesOfThread, openThread, snapshotOfStream, THREAD_WORDS, } from './thread';
@@ -15,6 +15,9 @@ export { messageOfApproval, normalizeApproval, whyAsked, } from './approvals';
15
15
  export { actionOf, APPROVAL_CARD_WORDS, approvalCardOf, argumentsShown, } from './approvalCard';
16
16
  // A run's stream, read as every client reads it.
17
17
  export { AgUiFrames, endsRun, eventsOfStream, NOT_STREAMING, REACTOR_UI_NAME, readRunStream, RUN_CUT_SHORT, toolResultOf, UI_ON_RUN, } from './agui';
18
+ // A run's stream reduced to what a chat host shows (DISCORD DC-005, SLACK S-205).
19
+ export { answerParts, isTerminal, SEMANTIC_EVENTS_VERSION, SEMANTIC_KINDS, } from './semantic';
20
+ export { askQuestionOf, semanticOf, turnOf, } from './semanticOfAgUi';
18
21
  export { AG_UI_NOT_ALLOWED, AG_UI_NOT_ON_RUNTIME, agUiRefusal, refusalBody, refusalDetail, } from './agUiRefusal';
19
22
  // The record's words, and a person's conversation read again.
20
23
  export { ASKED_FOR_TAG, askedOf, RUN_END_WORDS } from './records';
@@ -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[];