@datalayer/agent-runtimes 1.5.83 → 1.5.85
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/assets/loro_wasm_bg-XW642dR7.wasm +0 -0
- package/dist-embed/chunks/{DeckComponent-9fShp5EH.js → DeckComponent-YdJOxQXT.js} +1 -1
- package/dist-embed/chunks/{DocumentView-DKhM55kg.js → DocumentView-DM-hlTc_.js} +1 -1
- package/dist-embed/chunks/{EphemeralDocument-C0_-sZg-.js → EphemeralDocument-B72SGhNu.js} +1 -1
- package/dist-embed/chunks/{ExcalidrawComponent-B5qoSnHE.js → ExcalidrawComponent-DdlI5Tll.js} +1 -1
- package/dist-embed/chunks/{ExcalidrawModal-DLDzJz7F.js → ExcalidrawModal-DbGpgFBD.js} +1 -1
- package/dist-embed/chunks/{JupyterLexicalExtension-2AkqHLoO.js → JupyterLexicalExtension-BXeUUzz7.js} +46 -46
- package/dist-embed/chunks/{YouTubePlugin-VNlkEtVU.js → YouTubePlugin-BZneOR95.js} +1 -1
- package/dist-embed/chunks/{ar-SA-G6X2FPQ2-Cqss6Q62.js → ar-SA-G6X2FPQ2-BamUG1DS.js} +1 -1
- package/dist-embed/chunks/{az-AZ-76LH7QW2-lD6kXi4J.js → az-AZ-76LH7QW2-Dj8Unmrc.js} +1 -1
- package/dist-embed/chunks/{bg-BG-XCXSNQG7-2BArB_Ch.js → bg-BG-XCXSNQG7-D5eDDJTP.js} +1 -1
- package/dist-embed/chunks/{bn-BD-2XOGV67Q-CBEeK0DN.js → bn-BD-2XOGV67Q-BtdKy5Qj.js} +1 -1
- package/dist-embed/chunks/{ca-ES-6MX7JW3Y-DmhCP7qy.js → ca-ES-6MX7JW3Y-B1_G67dI.js} +1 -1
- package/dist-embed/chunks/{cs-CZ-2BRQDIVT-jdPxvKmz.js → cs-CZ-2BRQDIVT-cvUFGqN3.js} +1 -1
- package/dist-embed/chunks/{da-DK-5WZEPLOC-vjNwrU4T.js → da-DK-5WZEPLOC-B0GASd9Y.js} +1 -1
- package/dist-embed/chunks/{de-DE-XR44H4JA-B6zQ6e3N.js → de-DE-XR44H4JA-BXX-hBxk.js} +1 -1
- package/dist-embed/chunks/{el-GR-BZB4AONW-CBhimaPi.js → el-GR-BZB4AONW-CmOubvn_.js} +1 -1
- package/dist-embed/chunks/{es-ES-U4NZUMDT-COAfPMQS.js → es-ES-U4NZUMDT-CUXrz6y_.js} +1 -1
- package/dist-embed/chunks/{eu-ES-A7QVB2H4-CiYUAKuY.js → eu-ES-A7QVB2H4-UidDpFzE.js} +1 -1
- package/dist-embed/chunks/{fa-IR-HGAKTJCU-CW2b0s1I.js → fa-IR-HGAKTJCU-c14o5fY5.js} +1 -1
- package/dist-embed/chunks/{fi-FI-Z5N7JZ37-MCVKKeJl.js → fi-FI-Z5N7JZ37-C2N4F3P9.js} +1 -1
- package/dist-embed/chunks/{fr-FR-RHASNOE6-DZMkwkhL.js → fr-FR-RHASNOE6-Docsp2bQ.js} +1 -1
- package/dist-embed/chunks/{gl-ES-HMX3MZ6V-D8LdswtD.js → gl-ES-HMX3MZ6V-ChUFEvG4.js} +1 -1
- package/dist-embed/chunks/{he-IL-6SHJWFNN-D4A-WPuC.js → he-IL-6SHJWFNN-Dm7uysTx.js} +1 -1
- package/dist-embed/chunks/{hi-IN-IWLTKZ5I-DO3QdFAK.js → hi-IN-IWLTKZ5I-CeY2Albs.js} +1 -1
- package/dist-embed/chunks/{hu-HU-A5ZG7DT2-BOPacqST.js → hu-HU-A5ZG7DT2-DCDid3ls.js} +1 -1
- package/dist-embed/chunks/{id-ID-SAP4L64H-BDQ5wEDe.js → id-ID-SAP4L64H-Cu9nTzN4.js} +1 -1
- package/dist-embed/chunks/{index-DjTtL0TF.js → index-BlWhVENa.js} +1 -1
- package/dist-embed/chunks/{index-B9M5uQX3.js → index-DNxREKJB.js} +1 -1
- package/dist-embed/chunks/{it-IT-JPQ66NNP-bzbg9EMd.js → it-IT-JPQ66NNP-BFikXjfD.js} +1 -1
- package/dist-embed/chunks/{ja-JP-DBVTYXUO-Szvm49iH.js → ja-JP-DBVTYXUO-BmKD-yse.js} +1 -1
- package/dist-embed/chunks/{kaa-6HZHGXH3-CmjctWJC.js → kaa-6HZHGXH3-Db041Jip.js} +1 -1
- package/dist-embed/chunks/{kab-KAB-ZGHBKWFO-2neAyT0K.js → kab-KAB-ZGHBKWFO-BCvIk325.js} +1 -1
- package/dist-embed/chunks/{kk-KZ-P5N5QNE5-DFBQnc6O.js → kk-KZ-P5N5QNE5-BuOKPJvy.js} +1 -1
- package/dist-embed/chunks/{km-KH-HSX4SM5Z-BBsrLBf3.js → km-KH-HSX4SM5Z-BMHxKgUF.js} +1 -1
- package/dist-embed/chunks/{ko-KR-MTYHY66A-BhpsFd8K.js → ko-KR-MTYHY66A-CrGHLzSs.js} +1 -1
- package/dist-embed/chunks/{ku-TR-6OUDTVRD-BkmYi70s.js → ku-TR-6OUDTVRD-OWTQ-E4j.js} +1 -1
- package/dist-embed/chunks/{lt-LT-XHIRWOB4-BQzLQ3IM.js → lt-LT-XHIRWOB4-cWU3pPV4.js} +1 -1
- package/dist-embed/chunks/{lv-LV-5QDEKY6T-C2uG3w1b.js → lv-LV-5QDEKY6T-BxDTvB6y.js} +1 -1
- package/dist-embed/chunks/{mr-IN-CRQNXWMA-c0ua0Wep.js → mr-IN-CRQNXWMA-CqyfFYLc.js} +1 -1
- package/dist-embed/chunks/{my-MM-5M5IBNSE-CHwcQNVK.js → my-MM-5M5IBNSE-Cx7zaUxn.js} +1 -1
- package/dist-embed/chunks/{nb-NO-T6EIAALU-ExHLJdKL.js → nb-NO-T6EIAALU-B2mtxO3c.js} +1 -1
- package/dist-embed/chunks/{nl-NL-IS3SIHDZ-BZVh9P58.js → nl-NL-IS3SIHDZ-CXUwM9QK.js} +1 -1
- package/dist-embed/chunks/{nn-NO-6E72VCQL-B0Lsdzal.js → nn-NO-6E72VCQL-CHyB0wsS.js} +1 -1
- package/dist-embed/chunks/{oc-FR-POXYY2M6-6h1IfczT.js → oc-FR-POXYY2M6-PWsq-UBi.js} +1 -1
- package/dist-embed/chunks/{pa-IN-N4M65BXN-BatFUiwy.js → pa-IN-N4M65BXN-CY1sLit6.js} +1 -1
- package/dist-embed/chunks/{percentages-BXMCSKIN-CUieN6MU.js → percentages-BXMCSKIN-B8HDDw-F.js} +3 -3
- package/dist-embed/chunks/{pl-PL-T2D74RX3-DX6A7KgW.js → pl-PL-T2D74RX3-BsM9Abo3.js} +1 -1
- package/dist-embed/chunks/{pt-BR-5N22H2LF-N7HLFrzO.js → pt-BR-5N22H2LF-BNWoCeUd.js} +1 -1
- package/dist-embed/chunks/{pt-PT-UZXXM6DQ-DUZk-o8n.js → pt-PT-UZXXM6DQ-DBoCufKc.js} +1 -1
- package/dist-embed/chunks/{ro-RO-JPDTUUEW-eOhj0vob.js → ro-RO-JPDTUUEW-K_k74TtF.js} +1 -1
- package/dist-embed/chunks/{ru-RU-B4JR7IUQ-adV0gXfd.js → ru-RU-B4JR7IUQ-CGEGiyDu.js} +1 -1
- package/dist-embed/chunks/{si-LK-N5RQ5JYF-Bw2cyfz1.js → si-LK-N5RQ5JYF-BViNwnfQ.js} +1 -1
- package/dist-embed/chunks/{sk-SK-C5VTKIMK-CKE2DmyW.js → sk-SK-C5VTKIMK-DU3L7Dsq.js} +1 -1
- package/dist-embed/chunks/{sl-SI-NN7IZMDC-CFc8Y3VE.js → sl-SI-NN7IZMDC-DKaPsJRy.js} +1 -1
- package/dist-embed/chunks/{subset-shared.chunk-Dma4VCy8.js → subset-shared.chunk-BMSr0xzY.js} +1 -1
- package/dist-embed/chunks/{subset-worker.chunk-Bz00tIvB.js → subset-worker.chunk-CtzfGuvc.js} +1 -1
- package/dist-embed/chunks/{sv-SE-XGPEYMSR-BbadENuL.js → sv-SE-XGPEYMSR-CIE6pYzb.js} +1 -1
- package/dist-embed/chunks/{ta-IN-2NMHFXQM-DIcMv2m_.js → ta-IN-2NMHFXQM-n0YSquYB.js} +1 -1
- package/dist-embed/chunks/{th-TH-HPSO5L25-Dg_SsP8U.js → th-TH-HPSO5L25-Dqs6nDFF.js} +1 -1
- package/dist-embed/chunks/{tr-TR-DEFEU3FU-CT-y06oR.js → tr-TR-DEFEU3FU-DV00_VI-.js} +1 -1
- package/dist-embed/chunks/{uk-UA-QMV73CPH-BZ5Ohlyz.js → uk-UA-QMV73CPH-Brc-9Imh.js} +1 -1
- package/dist-embed/chunks/{vi-VN-M7AON7JQ-BJsFLDTl.js → vi-VN-M7AON7JQ-Dpi-23XP.js} +1 -1
- package/dist-embed/chunks/{zh-CN-LNUGB5OW-BEBj3lBa.js → zh-CN-LNUGB5OW-OieOX5TM.js} +1 -1
- package/dist-embed/chunks/{zh-HK-E62DVLB3-DaP5iF63.js → zh-HK-E62DVLB3-DXp_54pc.js} +1 -1
- package/dist-embed/chunks/{zh-TW-RAJ6MFWO-Du-01YeM.js → zh-TW-RAJ6MFWO-DGPCsgPG.js} +1 -1
- package/dist-embed/datalayer-app-main.js +56 -56
- package/lib/apps/apps/appspec.js +1 -0
- package/lib/chat/base/ChatBase.js +2 -2
- package/lib/chat/base/conversationItems.d.ts +7 -0
- package/lib/chat/base/conversationItems.js +30 -0
- package/lib/portable/hosts/contracts.d.ts +1 -1
- package/lib/portable/hosts/contracts.js +1 -1
- package/lib/portable/hosts/contracts.json +59 -1
- package/lib/portable/hosts/forbiddenGraph.js +1 -0
- package/lib/portable/hosts/index.d.ts +1 -1
- package/lib/portable/hosts/index.js +1 -1
- package/lib/portable/hosts/sessionUid.d.ts +3 -1
- package/lib/portable/hosts/sessionUid.js +3 -1
- package/lib/portable/semantic-events.json +117 -2
- package/lib/portable/semantic.d.ts +13 -1
- package/lib/portable/semantic.js +1 -12
- package/lib/portable/semanticOfAgUi.js +15 -3
- package/lib/specs/appspecSchema.js +2 -1
- package/lib/types/agentspecs.d.ts +1 -1
- package/lib/types/tools.d.ts +6 -0
- package/package.json +1 -1
- package/dist-embed/assets/loro_wasm_bg-BjoaHtGs.wasm +0 -0
package/lib/apps/apps/appspec.js
CHANGED
|
@@ -39,7 +39,7 @@ import { AI_MODEL_CATALOGUE, DEFAULT_MODEL, isChatModel, } from '../../specs/mod
|
|
|
39
39
|
import { internalQueryClient, isToolCallMessage, getMessageText, createProtocolAdapter, getApiBaseFromConfig, sanitizeAssistantContent, } from '../../utils/index.js';
|
|
40
40
|
import { BROWSER_LIMITS, emptyConversation, HARNESS_TOOL_CALL, reduceConversation, withError, withoutItems, withPrompt, withTurnEnded, } from '../../portable/conversation.js';
|
|
41
41
|
import { conversationEventsOf, snapshotOfMessages, } from '../../portable/adapterEvents.js';
|
|
42
|
-
import { conversationDrawer, emptyChatLayer, rowIdOf, toolCallOf, } from './conversationItems.js';
|
|
42
|
+
import { conversationDrawer, emptyChatLayer, rowIdOf, toolCallOf, withToolSummaries, } from './conversationItems.js';
|
|
43
43
|
import { useConfig, useSkills, useSkillActions, useContextSnapshot, useSandbox, } from '../../hooks/index.js';
|
|
44
44
|
import { useAgentRuntimeWebSocket } from '../../hooks/useAgentRuntimes.js';
|
|
45
45
|
import { agentRuntimeStore, useAgentRuntimeStore, useAgentRuntimeWsState, } from '../../stores/agentRuntimeStore.js';
|
|
@@ -1163,7 +1163,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1163
1163
|
const chatTextRef = useRef(chatText);
|
|
1164
1164
|
chatTextRef.current = chatText;
|
|
1165
1165
|
const drawConversation = useMemo(() => conversationDrawer(text => chatTextRef.current.error(text)), []);
|
|
1166
|
-
const displayItems = useMemo(() => drawConversation(conversation, layer), [drawConversation, conversation, layer]);
|
|
1166
|
+
const displayItems = useMemo(() => withToolSummaries(drawConversation(conversation, layer), frontendTools), [drawConversation, conversation, layer, frontendTools]);
|
|
1167
1167
|
const displayItemsRef = useRef(displayItems);
|
|
1168
1168
|
displayItemsRef.current = displayItems;
|
|
1169
1169
|
/*
|
|
@@ -16,6 +16,7 @@ import type { Display } from '@datalayer/reactor/ui';
|
|
|
16
16
|
import type { ConversationItem, ConversationState } from '../../portable/conversation';
|
|
17
17
|
import type { DisplayItem, DisplayToolCallStatus, ToolCallMessage } from '../../types/chat';
|
|
18
18
|
import type { ChatMessage, MessageSpeaker } from '../../types/messages';
|
|
19
|
+
import type { FrontendToolDefinition } from '../../types/tools';
|
|
19
20
|
type ToolItem = Extract<ConversationItem, {
|
|
20
21
|
kind: 'tool';
|
|
21
22
|
}>;
|
|
@@ -46,6 +47,12 @@ export declare const rowIdOf: (item: DisplayItem) => string;
|
|
|
46
47
|
export declare function cardStatusOf(item: ToolItem): DisplayToolCallStatus;
|
|
47
48
|
/** A tool call as its card draws it. */
|
|
48
49
|
export declare function toolCallOf(item: ToolItem): ToolCallMessage;
|
|
50
|
+
/**
|
|
51
|
+
* The cards of the page's own tools, with what each says of its call
|
|
52
|
+
* (`summaryOf`) once it returned. A card nothing changes is the one drawn,
|
|
53
|
+
* so React leaves it as it was.
|
|
54
|
+
*/
|
|
55
|
+
export declare function withToolSummaries(items: DisplayItem[], tools?: readonly Pick<FrontendToolDefinition, 'name' | 'summaryOf'>[]): DisplayItem[];
|
|
49
56
|
/**
|
|
50
57
|
* A drawer of a conversation: each row drawn once, and drawn again only when
|
|
51
58
|
* it, or what the web holds beside it, changed — so a message streaming
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
+
import { isToolCallMessage } from '../../utils/index.js';
|
|
5
6
|
export const emptyChatLayer = () => ({
|
|
6
7
|
extras: new Map(),
|
|
7
8
|
displays: new Map(),
|
|
@@ -52,6 +53,35 @@ export function toolCallOf(item) {
|
|
|
52
53
|
...(item.exitCode !== null ? { exitCode: item.exitCode } : {}),
|
|
53
54
|
};
|
|
54
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The cards of the page's own tools, with what each says of its call
|
|
58
|
+
* (`summaryOf`) once it returned. A card nothing changes is the one drawn,
|
|
59
|
+
* so React leaves it as it was.
|
|
60
|
+
*/
|
|
61
|
+
export function withToolSummaries(items, tools = []) {
|
|
62
|
+
const summarizing = tools.filter(tool => tool.summaryOf);
|
|
63
|
+
if (summarizing.length === 0) {
|
|
64
|
+
return items;
|
|
65
|
+
}
|
|
66
|
+
let changed = false;
|
|
67
|
+
const said = items.map(item => {
|
|
68
|
+
if (!isToolCallMessage(item)) {
|
|
69
|
+
return item;
|
|
70
|
+
}
|
|
71
|
+
const call = item;
|
|
72
|
+
const tool = summarizing.find(entry => entry.name === call.toolName);
|
|
73
|
+
if (!tool?.summaryOf || call.result === undefined) {
|
|
74
|
+
return item;
|
|
75
|
+
}
|
|
76
|
+
const summary = tool.summaryOf(call.args, call.result)?.trim();
|
|
77
|
+
if (!summary || summary === call.summary) {
|
|
78
|
+
return item;
|
|
79
|
+
}
|
|
80
|
+
changed = true;
|
|
81
|
+
return { ...call, summary };
|
|
82
|
+
});
|
|
83
|
+
return changed ? said : items;
|
|
84
|
+
}
|
|
55
85
|
/**
|
|
56
86
|
* A drawer of a conversation: each row drawn once, and drawn again only when
|
|
57
87
|
* it, or what the web holds beside it, changed — so a message streaming
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
/**
|
|
3
|
-
* The generic Datalayer host contracts, as ai-agents answers them, for every chat host (Slack, Discord).
|
|
3
|
+
* The generic Datalayer host contracts, as ai-agents answers them, for every chat host (Slack, Discord, WhatsApp).
|
|
4
4
|
* These shapes are shared with ai-agents through `contracts.json`, beside
|
|
5
5
|
* this file and byte-identical to ai-agents' `tests/fixtures/hosts/`, which
|
|
6
6
|
* both sides test. A delivery's `target` stays opaque here: each host
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
/**
|
|
8
|
-
* The generic Datalayer host contracts, as ai-agents answers them, for every chat host (Slack, Discord).
|
|
8
|
+
* The generic Datalayer host contracts, as ai-agents answers them, for every chat host (Slack, Discord, WhatsApp).
|
|
9
9
|
* These shapes are shared with ai-agents through `contracts.json`, beside
|
|
10
10
|
* this file and byte-identical to ai-agents' `tests/fixtures/hosts/`, which
|
|
11
11
|
* both sides test. A delivery's `target` stays opaque here: each host
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"about": "The generic host contracts of the chat hosts, as ai-agents and the runtime's session API answer them. Shared verbatim by ai-agents (tests/fixtures/hosts) and agent-runtimes (src/portable/hosts, read by the Slack and
|
|
3
|
+
"about": "The generic host contracts of the chat hosts, as ai-agents and the runtime's session API answer them. Shared verbatim by ai-agents (tests/fixtures/hosts) and agent-runtimes (src/portable/hosts, read by the Slack, Discord and WhatsApp adapters from lib/portable/hosts): each side's tests check its half against this file.",
|
|
4
4
|
"headers": {
|
|
5
5
|
"host_key": "X-Datalayer-Host-Key",
|
|
6
6
|
"signature": "X-Datalayer-Signature",
|
|
@@ -493,5 +493,63 @@
|
|
|
493
493
|
"threadId": "456789012345678901",
|
|
494
494
|
"userId": "567890123456789012"
|
|
495
495
|
}
|
|
496
|
+
},
|
|
497
|
+
"whatsapp": {
|
|
498
|
+
"about": "WhatsApp's forms of the generic contracts: the installation is <waba_id>:<phone_number_id>, one per connected business number; a person is their business-scoped user id (BSUID: a country code, a period and up to 128 characters; never the phone number), which the external id pattern admits as it is, no hash in between; a 1:1 chat is a direct place named by the BSUID, a group a channel named by its group id; the session uid is hostSessionUid(\"whatsapp\", [waba_id, phone_number_id, user_id]) for a chat and [waba_id, phone_number_id, group_id] for a group; a turn's provenance names the message by its wamid.",
|
|
499
|
+
"waba_id": "102290129340398",
|
|
500
|
+
"phone_number_id": "106540352242922",
|
|
501
|
+
"bind_request": {
|
|
502
|
+
"code": "dlhc_…",
|
|
503
|
+
"external_id": "102290129340398:106540352242922",
|
|
504
|
+
"name": "Acme"
|
|
505
|
+
},
|
|
506
|
+
"external_user_id": "US.13491208655302741918",
|
|
507
|
+
"external_user_name": "Alice",
|
|
508
|
+
"external_user_id_longest": "US.11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
|
509
|
+
"direct": {
|
|
510
|
+
"place": {
|
|
511
|
+
"kind": "direct",
|
|
512
|
+
"id": "US.13491208655302741918"
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
"group": {
|
|
516
|
+
"id": "120363025246125486",
|
|
517
|
+
"place": {
|
|
518
|
+
"kind": "channel",
|
|
519
|
+
"id": "120363025246125486"
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
"session": {
|
|
523
|
+
"parts": [
|
|
524
|
+
"102290129340398",
|
|
525
|
+
"106540352242922",
|
|
526
|
+
"US.13491208655302741918"
|
|
527
|
+
],
|
|
528
|
+
"uid": "whatsapp-870e7e8165519947ec9c7df03d378b342cee380e"
|
|
529
|
+
},
|
|
530
|
+
"group_session": {
|
|
531
|
+
"parts": [
|
|
532
|
+
"102290129340398",
|
|
533
|
+
"106540352242922",
|
|
534
|
+
"120363025246125486"
|
|
535
|
+
],
|
|
536
|
+
"uid": "whatsapp-49aeadff03b2d02e6359121f9a55bae904640b35"
|
|
537
|
+
},
|
|
538
|
+
"provenance": {
|
|
539
|
+
"host_kind": "whatsapp",
|
|
540
|
+
"place": {
|
|
541
|
+
"kind": "direct",
|
|
542
|
+
"id": "US.13491208655302741918"
|
|
543
|
+
},
|
|
544
|
+
"message_id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgASGBQzQUY3RjU0QjRFRjc2MzBCNkJCNAA="
|
|
545
|
+
},
|
|
546
|
+
"target": {
|
|
547
|
+
"phoneNumberId": "106540352242922",
|
|
548
|
+
"userId": "US.13491208655302741918"
|
|
549
|
+
},
|
|
550
|
+
"group_target": {
|
|
551
|
+
"phoneNumberId": "106540352242922",
|
|
552
|
+
"groupId": "120363025246125486"
|
|
553
|
+
}
|
|
496
554
|
}
|
|
497
555
|
}
|
|
@@ -26,6 +26,7 @@ export const FORBIDDEN = [
|
|
|
26
26
|
/^@datalayer\/reactor$/,
|
|
27
27
|
/^@datalayer\/slack$/,
|
|
28
28
|
/^@datalayer\/discord$/,
|
|
29
|
+
/^@datalayer\/whatsapp$/,
|
|
29
30
|
];
|
|
30
31
|
export const isForbidden = (name) => FORBIDDEN.some(pattern => pattern.test(name));
|
|
31
32
|
/** The package name an import specifier names: `@scope/name/deep` → `@scope/name`. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What a chat host service (Slack, Discord) shares, on Node: the ai-agents
|
|
2
|
+
* What a chat host service (Slack, Discord, WhatsApp) shares, on Node: the ai-agents
|
|
3
3
|
* host contracts and client, the agent client over the session API, the
|
|
4
4
|
* semantic events a turn is reduced to, approval renderers, deliveries, the
|
|
5
5
|
* turn's state, application resolution, the durable queue, quotas, secrets
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* What a chat host service (Slack, Discord) shares, on Node: the ai-agents
|
|
6
|
+
* What a chat host service (Slack, Discord, WhatsApp) shares, on Node: the ai-agents
|
|
7
7
|
* host contracts and client, the agent client over the session API, the
|
|
8
8
|
* semantic events a turn is reduced to, approval renderers, deliveries, the
|
|
9
9
|
* turn's state, application resolution, the durable queue, quotas, secrets
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* `<kind>-<40 hex>`: the SHA-256 of the thread's parts joined by `:`, and
|
|
3
3
|
* `:<generation>` once the thread started over or switched application. The
|
|
4
4
|
* same parts give the same uid (Slack: app, enterprise or `-`, team,
|
|
5
|
-
* channel, thread ts; Discord: application, guild, channel, thread
|
|
5
|
+
* channel, thread ts; Discord: application, guild, channel, thread;
|
|
6
|
+
* WhatsApp: WABA, phone number id, and the person's BSUID for a chat or the
|
|
7
|
+
* group's id for a group).
|
|
6
8
|
*/
|
|
7
9
|
export declare function hostSessionUid(kind: string, parts: readonly string[], generation?: number): string;
|
|
@@ -13,7 +13,9 @@ import { createHash } from 'node:crypto';
|
|
|
13
13
|
* `<kind>-<40 hex>`: the SHA-256 of the thread's parts joined by `:`, and
|
|
14
14
|
* `:<generation>` once the thread started over or switched application. The
|
|
15
15
|
* same parts give the same uid (Slack: app, enterprise or `-`, team,
|
|
16
|
-
* channel, thread ts; Discord: application, guild, channel, thread
|
|
16
|
+
* channel, thread ts; Discord: application, guild, channel, thread;
|
|
17
|
+
* WhatsApp: WABA, phone number id, and the person's BSUID for a chat or the
|
|
18
|
+
* group's id for a group).
|
|
17
19
|
*/
|
|
18
20
|
export function hostSessionUid(kind, parts, generation) {
|
|
19
21
|
if (!/^[a-z][a-z0-9-]{1,31}$/.test(kind)) {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"ask",
|
|
13
13
|
"completion",
|
|
14
14
|
"stop",
|
|
15
|
-
"error"
|
|
15
|
+
"error",
|
|
16
|
+
"sign-in"
|
|
16
17
|
],
|
|
17
18
|
"producers": {
|
|
18
19
|
"text": "AG-UI TEXT_MESSAGE_CONTENT / TEXT_MESSAGE_CHUNK delta",
|
|
@@ -25,7 +26,8 @@
|
|
|
25
26
|
"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
27
|
"completion": "AG-UI RUN_FINISHED without asking",
|
|
27
28
|
"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
|
+
"error": "AG-UI RUN_ERROR message",
|
|
30
|
+
"sign-in": "AG-UI TOOL_CALL_RESULT of pap_sign_in (or pact_sign_in, with or without a gateway prefix) whose result is a sign-in waiting for the person with an https page (src/portable/signIn.ts readPapSignIn), after the tool's complete row; a page that is not https gives the row only"
|
|
29
31
|
},
|
|
30
32
|
"cases": [
|
|
31
33
|
{
|
|
@@ -447,6 +449,119 @@
|
|
|
447
449
|
}
|
|
448
450
|
],
|
|
449
451
|
"semantic": []
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"agui": [
|
|
455
|
+
{
|
|
456
|
+
"type": "TOOL_CALL_START",
|
|
457
|
+
"toolCallId": "c9",
|
|
458
|
+
"toolCallName": "pap_sign_in"
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"type": "TOOL_CALL_RESULT",
|
|
462
|
+
"toolCallId": "c9",
|
|
463
|
+
"messageId": "r9",
|
|
464
|
+
"content": "{\"status\": \"waiting_for_the_person\", \"mode\": \"direct\", \"open\": \"https://iam.example.com/pap/start/t1\", \"company\": \"manzanita.example\", \"organization_name\": \"Manzanita\", \"organization_domain\": \"manzanita.example\"}"
|
|
465
|
+
}
|
|
466
|
+
],
|
|
467
|
+
"semantic": [
|
|
468
|
+
{
|
|
469
|
+
"kind": "tool",
|
|
470
|
+
"id": "c9",
|
|
471
|
+
"name": "pap_sign_in",
|
|
472
|
+
"status": "running"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
"kind": "tool",
|
|
476
|
+
"id": "c9",
|
|
477
|
+
"name": "pap_sign_in",
|
|
478
|
+
"status": "complete"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"kind": "sign-in",
|
|
482
|
+
"toolCallId": "c9",
|
|
483
|
+
"toolName": "pap_sign_in",
|
|
484
|
+
"signIn": {
|
|
485
|
+
"mode": "direct",
|
|
486
|
+
"open": "https://iam.example.com/pap/start/t1",
|
|
487
|
+
"host": "iam.example.com",
|
|
488
|
+
"company": "manzanita.example",
|
|
489
|
+
"organization": {
|
|
490
|
+
"name": "Manzanita",
|
|
491
|
+
"domain": "manzanita.example"
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
]
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"agui": [
|
|
499
|
+
{
|
|
500
|
+
"type": "TOOL_CALL_START",
|
|
501
|
+
"toolCallId": "c10",
|
|
502
|
+
"toolCallName": "gateway_pap_sign_in"
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"type": "TOOL_CALL_RESULT",
|
|
506
|
+
"toolCallId": "c10",
|
|
507
|
+
"messageId": "r10",
|
|
508
|
+
"content": "{\"structuredContent\": {\"status\": \"waiting_for_the_person\", \"mode\": \"device\", \"open\": \"https://manzanita.example/device\", \"code\": \"WDJB-MJHT\"}}"
|
|
509
|
+
}
|
|
510
|
+
],
|
|
511
|
+
"semantic": [
|
|
512
|
+
{
|
|
513
|
+
"kind": "tool",
|
|
514
|
+
"id": "c10",
|
|
515
|
+
"name": "gateway_pap_sign_in",
|
|
516
|
+
"status": "running"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"kind": "tool",
|
|
520
|
+
"id": "c10",
|
|
521
|
+
"name": "gateway_pap_sign_in",
|
|
522
|
+
"status": "complete"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"kind": "sign-in",
|
|
526
|
+
"toolCallId": "c10",
|
|
527
|
+
"toolName": "gateway_pap_sign_in",
|
|
528
|
+
"signIn": {
|
|
529
|
+
"mode": "device",
|
|
530
|
+
"open": "https://manzanita.example/device",
|
|
531
|
+
"host": "manzanita.example",
|
|
532
|
+
"code": "WDJB-MJHT"
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
]
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"agui": [
|
|
539
|
+
{
|
|
540
|
+
"type": "TOOL_CALL_START",
|
|
541
|
+
"toolCallId": "c11",
|
|
542
|
+
"toolCallName": "pap_sign_in"
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"type": "TOOL_CALL_RESULT",
|
|
546
|
+
"toolCallId": "c11",
|
|
547
|
+
"messageId": "r11",
|
|
548
|
+
"content": "{\"status\": \"waiting_for_the_person\", \"mode\": \"direct\", \"open\": \"http://manzanita.example/signin\"}"
|
|
549
|
+
}
|
|
550
|
+
],
|
|
551
|
+
"semantic": [
|
|
552
|
+
{
|
|
553
|
+
"kind": "tool",
|
|
554
|
+
"id": "c11",
|
|
555
|
+
"name": "pap_sign_in",
|
|
556
|
+
"status": "running"
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"kind": "tool",
|
|
560
|
+
"id": "c11",
|
|
561
|
+
"name": "pap_sign_in",
|
|
562
|
+
"status": "complete"
|
|
563
|
+
}
|
|
564
|
+
]
|
|
450
565
|
}
|
|
451
566
|
],
|
|
452
567
|
"answers": [
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module portable/semantic
|
|
12
12
|
*/
|
|
13
|
+
import type { PapSignInWaiting } from './signIn';
|
|
13
14
|
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 declare const SEMANTIC_KINDS: readonly ["text", "progress", "tool", "approval", "table", "file", "citation", "ask", "completion", "stop", "error", "sign-in"];
|
|
15
16
|
export type SemanticKind = (typeof SEMANTIC_KINDS)[number];
|
|
16
17
|
export type AskQuestion = Readonly<{
|
|
17
18
|
/** `text` and `choice` are answered in the host; `file` and `form` hand off to Datalayer. */
|
|
@@ -58,6 +59,17 @@ export type SemanticEvent = Readonly<{
|
|
|
58
59
|
}> | Readonly<{
|
|
59
60
|
kind: 'error';
|
|
60
61
|
message: string;
|
|
62
|
+
}> | Readonly<{
|
|
63
|
+
/**
|
|
64
|
+
* A company's sign-in waiting for the person (`pap_sign_in`, or a
|
|
65
|
+
* business's `pact_sign_in`): its page (https only), mode and code,
|
|
66
|
+
* as `signIn.ts` reads them. A host shows it as a button or the code
|
|
67
|
+
* with the page; the turn goes on once the person has signed in.
|
|
68
|
+
*/
|
|
69
|
+
kind: 'sign-in';
|
|
70
|
+
toolCallId: string;
|
|
71
|
+
toolName: string;
|
|
72
|
+
signIn: PapSignInWaiting;
|
|
61
73
|
}>;
|
|
62
74
|
/** Whether an event ends the turn's presentation. */
|
|
63
75
|
export declare function isTerminal(event: SemanticEvent): boolean;
|
package/lib/portable/semantic.js
CHANGED
|
@@ -2,18 +2,6 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
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 (DC-005, S-004, S-205).
|
|
14
|
-
*
|
|
15
|
-
* @module portable/semantic
|
|
16
|
-
*/
|
|
17
5
|
export const SEMANTIC_EVENTS_VERSION = 1;
|
|
18
6
|
export const SEMANTIC_KINDS = [
|
|
19
7
|
'text',
|
|
@@ -27,6 +15,7 @@ export const SEMANTIC_KINDS = [
|
|
|
27
15
|
'completion',
|
|
28
16
|
'stop',
|
|
29
17
|
'error',
|
|
18
|
+
'sign-in',
|
|
30
19
|
];
|
|
31
20
|
/** Whether an event ends the turn's presentation. */
|
|
32
21
|
export function isTerminal(event) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
+
import { isPapSignInTool, readPapSignIn } from './signIn.js';
|
|
5
6
|
/** A string field of an event, or the fallback: never an object stringified. */
|
|
6
7
|
const stringOf = (value, fallback = '') => typeof value === 'string' ? value : fallback;
|
|
7
8
|
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -84,9 +85,20 @@ export function semanticOf(event, tools) {
|
|
|
84
85
|
return [{ kind: 'approval', toolCallId: id, toolName: name }];
|
|
85
86
|
}
|
|
86
87
|
const failed = result?.success === false || result?.isError === true;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const done = {
|
|
89
|
+
kind: 'tool',
|
|
90
|
+
id,
|
|
91
|
+
name,
|
|
92
|
+
status: failed ? 'failed' : 'complete',
|
|
93
|
+
};
|
|
94
|
+
// A company's sign-in waiting for the person: the host shows its page.
|
|
95
|
+
// A page that is not https is never shown: the tool's row says it.
|
|
96
|
+
const signIn = isPapSignInTool(name)
|
|
97
|
+
? readPapSignIn(event.content)
|
|
98
|
+
: null;
|
|
99
|
+
return signIn && !('refused' in signIn)
|
|
100
|
+
? [done, { kind: 'sign-in', toolCallId: id, toolName: name, signIn }]
|
|
101
|
+
: [done];
|
|
90
102
|
}
|
|
91
103
|
case 'STEP_STARTED':
|
|
92
104
|
return typeof event.stepName === 'string' && event.stepName
|
|
@@ -1961,7 +1961,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
1961
1961
|
properties: {
|
|
1962
1962
|
variant: {
|
|
1963
1963
|
$ref: '#/$defs/ThemeVariant',
|
|
1964
|
-
description: 'The theme: `datalayer`, `spatial`, `lovely`, `matrix`, `earth`, `sand`, `ivory`, `sun` or `
|
|
1964
|
+
description: 'The theme: `datalayer`, `spatial`, `lovely`, `matrix`, `earth`, `sand`, `ivory`, `sun`, `loop` or `vscode`',
|
|
1965
1965
|
},
|
|
1966
1966
|
mode: {
|
|
1967
1967
|
anyOf: [
|
|
@@ -2505,6 +2505,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
2505
2505
|
'ivory',
|
|
2506
2506
|
'sun',
|
|
2507
2507
|
'loop',
|
|
2508
|
+
'vscode',
|
|
2508
2509
|
],
|
|
2509
2510
|
title: 'ThemeVariant',
|
|
2510
2511
|
type: 'string',
|
|
@@ -717,7 +717,7 @@ export type AppLayout = 'chat' | 'page' | 'split';
|
|
|
717
717
|
/** The one colour of an application; everything else is neutral. */
|
|
718
718
|
export type AppAccent = 'green' | 'rose' | 'sky' | 'lime' | 'sun' | 'violet';
|
|
719
719
|
/** A theme of Appearance's, which an application may run in (T-30). */
|
|
720
|
-
export type AppThemeVariant = 'datalayer' | 'spatial' | 'lovely' | 'matrix' | 'earth' | 'sand' | 'ivory' | 'sun' | 'loop';
|
|
720
|
+
export type AppThemeVariant = 'datalayer' | 'spatial' | 'lovely' | 'matrix' | 'earth' | 'sand' | 'ivory' | 'sun' | 'loop' | 'vscode';
|
|
721
721
|
/** The colour mode it is worn in: `auto` follows the device. */
|
|
722
722
|
export type AppThemeMode = 'light' | 'dark' | 'auto';
|
|
723
723
|
/**
|
package/lib/types/tools.d.ts
CHANGED
|
@@ -149,6 +149,12 @@ export interface FrontendToolDefinition<TArgs = Record<string, unknown>, TResult
|
|
|
149
149
|
* Required when location is 'frontend' (default)
|
|
150
150
|
*/
|
|
151
151
|
handler?: (args: TArgs) => Promise<TResult>;
|
|
152
|
+
/**
|
|
153
|
+
* What its card says in place of its arguments' summary, from what it
|
|
154
|
+
* returned (`on analysis.ipynb`, the file a host's editor tool ran on);
|
|
155
|
+
* `undefined` keeps the arguments' summary. Asked only once it returned.
|
|
156
|
+
*/
|
|
157
|
+
summaryOf?: (args: TArgs, result: TResult) => string | undefined;
|
|
152
158
|
/**
|
|
153
159
|
* Optional render function for custom UI during execution
|
|
154
160
|
*/
|
package/package.json
CHANGED
|
Binary file
|