@datalayer/agent-runtimes 1.3.114 → 1.5.0
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/chunks/ChatView-CaBuPTyG.js +32 -0
- package/dist-embed/chunks/{DeckComponent-CuRWiARr.js → DeckComponent-cRJJMGgt.js} +1 -1
- package/dist-embed/chunks/{DocumentView-BYU2HREd.js → DocumentView-CiqN9ze6.js} +1 -1
- package/dist-embed/chunks/{EphemeralDocument-BjFSuQKH.js → EphemeralDocument-BjJfn7J-.js} +1 -1
- package/dist-embed/chunks/{ExcalidrawComponent-CFLnMPnf.js → ExcalidrawComponent-BtNXWUN8.js} +1 -1
- package/dist-embed/chunks/{ExcalidrawModal-CB9d5Vpk.js → ExcalidrawModal-C6SEKFlD.js} +1 -1
- package/dist-embed/chunks/{JupyterLexicalExtension-CYnZrelh.js → JupyterLexicalExtension-BuRLImy5.js} +5 -5
- package/dist-embed/chunks/{NotebookToolSurfaces-D62q-lbb.js → NotebookToolSurfaces-ktcGRm7d.js} +1 -1
- package/dist-embed/chunks/{Output-2KxoKu5F.js → Output-BscOPLqE.js} +10 -10
- package/dist-embed/chunks/{YouTubePlugin-CjODyxZ2.js → YouTubePlugin-xBjNr2Iu.js} +1 -1
- package/dist-embed/chunks/{ar-SA-G6X2FPQ2-C-zAYgA-.js → ar-SA-G6X2FPQ2-BB82iKLz.js} +1 -1
- package/dist-embed/chunks/{az-AZ-76LH7QW2-BHq5js6U.js → az-AZ-76LH7QW2-DsMRKXlw.js} +1 -1
- package/dist-embed/chunks/{bg-BG-XCXSNQG7-BTcNNcTc.js → bg-BG-XCXSNQG7-43Y1kPxa.js} +1 -1
- package/dist-embed/chunks/{bn-BD-2XOGV67Q-DXRk27u1.js → bn-BD-2XOGV67Q-CLqPJBll.js} +1 -1
- package/dist-embed/chunks/{ca-ES-6MX7JW3Y-D-0J9rqp.js → ca-ES-6MX7JW3Y-CDFGSEh3.js} +1 -1
- package/dist-embed/chunks/{cs-CZ-2BRQDIVT-CgN3I-57.js → cs-CZ-2BRQDIVT-ByNB8eZd.js} +1 -1
- package/dist-embed/chunks/{da-DK-5WZEPLOC-CHQloSoX.js → da-DK-5WZEPLOC-B7MrVwy8.js} +1 -1
- package/dist-embed/chunks/{de-DE-XR44H4JA-C-Hq84pe.js → de-DE-XR44H4JA-CN1cdk94.js} +1 -1
- package/dist-embed/chunks/{el-GR-BZB4AONW-MTzGcSsP.js → el-GR-BZB4AONW-DnaGhWD1.js} +1 -1
- package/dist-embed/chunks/{es-ES-U4NZUMDT-Thj-4Rwn.js → es-ES-U4NZUMDT-DE1vZzDE.js} +1 -1
- package/dist-embed/chunks/{eu-ES-A7QVB2H4-BEEyNQo-.js → eu-ES-A7QVB2H4-DmHB0zpm.js} +1 -1
- package/dist-embed/chunks/{fa-IR-HGAKTJCU-CtUGmNBZ.js → fa-IR-HGAKTJCU-CNzE8tJj.js} +1 -1
- package/dist-embed/chunks/{fi-FI-Z5N7JZ37-6GMgpkSu.js → fi-FI-Z5N7JZ37-Ca2vTFQC.js} +1 -1
- package/dist-embed/chunks/{fr-FR-RHASNOE6-BakNCbxj.js → fr-FR-RHASNOE6-B0yWFX3_.js} +1 -1
- package/dist-embed/chunks/{gl-ES-HMX3MZ6V-Cwkb9OPk.js → gl-ES-HMX3MZ6V-2_3FMVJq.js} +1 -1
- package/dist-embed/chunks/{he-IL-6SHJWFNN-BaMmvCkr.js → he-IL-6SHJWFNN-BW1lby00.js} +1 -1
- package/dist-embed/chunks/{hi-IN-IWLTKZ5I-1aWewhep.js → hi-IN-IWLTKZ5I-DTixfSwB.js} +1 -1
- package/dist-embed/chunks/{hu-HU-A5ZG7DT2-BIHI23BQ.js → hu-HU-A5ZG7DT2-DOfYwLWP.js} +1 -1
- package/dist-embed/chunks/{id-ID-SAP4L64H-CYpgmx8X.js → id-ID-SAP4L64H-Cwtdtkvg.js} +1 -1
- package/dist-embed/chunks/{index-BhSMzuKq.js → index--qMT5k1q.js} +1 -1
- package/dist-embed/chunks/{index-b1yzCiTq.js → index-B-UP9DlM.js} +1 -1
- package/dist-embed/chunks/{index-DMKsCn-y.js → index-BAwsCLGT.js} +1 -1
- package/dist-embed/chunks/{index-BUhqZVtg.js → index-BITOMOWN.js} +1 -1
- package/dist-embed/chunks/{index-1wTrAXI1.js → index-B_9UD0bt.js} +2 -2
- package/dist-embed/chunks/{index-DtlUttQj.js → index-BgFbP5P0.js} +1 -1
- package/dist-embed/chunks/{index-CC-Ht79i.js → index-CMUTS_sA.js} +1 -1
- package/dist-embed/chunks/{index-B7nmHsEo.js → index-Cgf7tlW3.js} +1 -1
- package/dist-embed/chunks/{index-CsZ2HycN.js → index-CrNfUmIU.js} +1 -1
- package/dist-embed/chunks/{index-DIOcQUrz.js → index-CzuLxFBK.js} +1 -1
- package/dist-embed/chunks/{index-EmZm7_bH.js → index-DEn5R18M.js} +1 -1
- package/dist-embed/chunks/{index-DeVZ-nmF.js → index-DFEBhySA.js} +1 -1
- package/dist-embed/chunks/{index-CMYyiALV.js → index-DYkwi0aX.js} +1 -1
- package/dist-embed/chunks/{index-Fzz2KjFM.js → index-DvpdAlVH.js} +1 -1
- package/dist-embed/chunks/{index-W7TVoWP5.js → index-Dyh5xopp.js} +1 -1
- package/dist-embed/chunks/{index-en9Yf1Yz.js → index-Jt4bWLoz.js} +1 -1
- package/dist-embed/chunks/{index-BbucLMre.js → index-S-sjhoD3.js} +1 -1
- package/dist-embed/chunks/{index-D18sf241.js → index-TRLGqZaF.js} +1 -1
- package/dist-embed/chunks/{index-ZZnjmFwm.js → index-YcqCoWJl.js} +1 -1
- package/dist-embed/chunks/{index-BFLtEBuP.js → index-sQy5cmWo.js} +1 -1
- package/dist-embed/chunks/{it-IT-JPQ66NNP-CLcqplyX.js → it-IT-JPQ66NNP-C3xZ61-6.js} +1 -1
- package/dist-embed/chunks/{ja-JP-DBVTYXUO-u8Qe6tR7.js → ja-JP-DBVTYXUO-CeTmglEb.js} +1 -1
- package/dist-embed/chunks/{kaa-6HZHGXH3-BG2kx50I.js → kaa-6HZHGXH3-D6Jr6B6Y.js} +1 -1
- package/dist-embed/chunks/{kab-KAB-ZGHBKWFO-CSYUpRxd.js → kab-KAB-ZGHBKWFO-pEXBqeuG.js} +1 -1
- package/dist-embed/chunks/{kk-KZ-P5N5QNE5-CpBMgHAz.js → kk-KZ-P5N5QNE5-BRJunmHm.js} +1 -1
- package/dist-embed/chunks/{km-KH-HSX4SM5Z-CoMUUQMb.js → km-KH-HSX4SM5Z--GJgT9rN.js} +1 -1
- package/dist-embed/chunks/{ko-KR-MTYHY66A-DwxY8CGI.js → ko-KR-MTYHY66A-Bjnez4qR.js} +1 -1
- package/dist-embed/chunks/{ku-TR-6OUDTVRD-UoNYUfm0.js → ku-TR-6OUDTVRD-DgOdYJrS.js} +1 -1
- package/dist-embed/chunks/{lt-LT-XHIRWOB4-Dr4uXaEj.js → lt-LT-XHIRWOB4-BMwhrtjM.js} +1 -1
- package/dist-embed/chunks/{lv-LV-5QDEKY6T-CNC56J-_.js → lv-LV-5QDEKY6T-0pxW7YE0.js} +1 -1
- package/dist-embed/chunks/{mr-IN-CRQNXWMA-BKWa9nzZ.js → mr-IN-CRQNXWMA-tndp8BXC.js} +1 -1
- package/dist-embed/chunks/{my-MM-5M5IBNSE-bwAzOWhV.js → my-MM-5M5IBNSE-sispDhO4.js} +1 -1
- package/dist-embed/chunks/{nb-NO-T6EIAALU-CkpsChor.js → nb-NO-T6EIAALU-CjBurOuS.js} +1 -1
- package/dist-embed/chunks/{nl-NL-IS3SIHDZ-COVk4rlb.js → nl-NL-IS3SIHDZ-B58EVmr3.js} +1 -1
- package/dist-embed/chunks/{nn-NO-6E72VCQL-DlyFF-C1.js → nn-NO-6E72VCQL-D1p7LZSq.js} +1 -1
- package/dist-embed/chunks/{oc-FR-POXYY2M6-CFDosV2C.js → oc-FR-POXYY2M6-C1M8sddP.js} +1 -1
- package/dist-embed/chunks/{pa-IN-N4M65BXN-BKRB3O0U.js → pa-IN-N4M65BXN-D8ESzASl.js} +1 -1
- package/dist-embed/chunks/{percentages-BXMCSKIN-D7pnqUsZ.js → percentages-BXMCSKIN-BihMTsFR.js} +3 -3
- package/dist-embed/chunks/{pl-PL-T2D74RX3-C5r2Tds7.js → pl-PL-T2D74RX3-DQGe6LHC.js} +1 -1
- package/dist-embed/chunks/{pt-BR-5N22H2LF-CDnT98bW.js → pt-BR-5N22H2LF-CvXBgZQs.js} +1 -1
- package/dist-embed/chunks/{pt-PT-UZXXM6DQ-C6c4SPk1.js → pt-PT-UZXXM6DQ-BMnnlIUJ.js} +1 -1
- package/dist-embed/chunks/{ro-RO-JPDTUUEW-CW6pbzEZ.js → ro-RO-JPDTUUEW-DZ-9UUH7.js} +1 -1
- package/dist-embed/chunks/{ru-RU-B4JR7IUQ-CbaAJG0w.js → ru-RU-B4JR7IUQ-JlRBwjob.js} +1 -1
- package/dist-embed/chunks/{si-LK-N5RQ5JYF-BZkUjpXF.js → si-LK-N5RQ5JYF-Bx8kHnkd.js} +1 -1
- package/dist-embed/chunks/{sk-SK-C5VTKIMK-DsfWgpPU.js → sk-SK-C5VTKIMK-xsfEfbZb.js} +1 -1
- package/dist-embed/chunks/{sl-SI-NN7IZMDC-Kx0FqxKU.js → sl-SI-NN7IZMDC-SQYUECnr.js} +1 -1
- package/dist-embed/chunks/{subset-shared.chunk-DM3l9OuH.js → subset-shared.chunk-Ch6j8nKC.js} +1 -1
- package/dist-embed/chunks/{subset-worker.chunk-4w4yibm3.js → subset-worker.chunk-pJjck5pR.js} +1 -1
- package/dist-embed/chunks/{sv-SE-XGPEYMSR-DY0ryO-L.js → sv-SE-XGPEYMSR-BxcjSHE2.js} +1 -1
- package/dist-embed/chunks/{ta-IN-2NMHFXQM-CWpIs0i0.js → ta-IN-2NMHFXQM-rItSkDUS.js} +1 -1
- package/dist-embed/chunks/{th-TH-HPSO5L25-Cwkcfb3u.js → th-TH-HPSO5L25-B7UzESFj.js} +1 -1
- package/dist-embed/chunks/{tr-TR-DEFEU3FU-BqJZZl-Y.js → tr-TR-DEFEU3FU-Ci6oNfEX.js} +1 -1
- package/dist-embed/chunks/{uk-UA-QMV73CPH-Dg213mG4.js → uk-UA-QMV73CPH-C9csqvO6.js} +1 -1
- package/dist-embed/chunks/{vi-VN-M7AON7JQ-DY94NKxF.js → vi-VN-M7AON7JQ-DRAj2kZj.js} +1 -1
- package/dist-embed/chunks/{zh-CN-LNUGB5OW-B6I9A7sA.js → zh-CN-LNUGB5OW-DLOyW8hH.js} +1 -1
- package/dist-embed/chunks/{zh-HK-E62DVLB3-D3oqgDOt.js → zh-HK-E62DVLB3-DwC6_2Ws.js} +1 -1
- package/dist-embed/chunks/{zh-TW-RAJ6MFWO-CYwgY0Jo.js → zh-TW-RAJ6MFWO-DEMugIwa.js} +1 -1
- package/dist-embed/datalayer-app-main.js +156 -156
- package/lib/apps/apps/appspec.d.ts +13 -0
- package/lib/apps/apps/appspec.js +93 -0
- package/lib/apps/apps/checks.d.ts +1 -1
- package/lib/apps/apps/checks.js +2 -2
- package/lib/apps/apps/customComponents.js +1 -1
- package/lib/apps/core/canvasBlocks.d.ts +3 -3
- package/lib/apps/core/canvasParts.d.ts +6 -4
- package/lib/apps/core/index.d.ts +8 -0
- package/lib/apps/embed/AppEmbed.js +13 -20
- package/lib/apps/embed/embedSession.d.ts +8 -4
- package/lib/apps/embed/embedSession.js +16 -9
- package/lib/apps/embed/hostBridge.d.ts +47 -13
- package/lib/apps/embed/hostBridge.js +135 -18
- package/lib/apps/index.d.ts +1 -1
- package/lib/apps/index.js +1 -1
- package/lib/apps/plugins/a2ui-surface/AnswerShows.d.ts +21 -0
- package/lib/apps/plugins/a2ui-surface/AnswerShows.js +29 -0
- package/lib/apps/plugins/a2ui-surface/SurfaceToolResult.js +4 -7
- package/lib/apps/plugins/a2ui-surface/index.d.ts +2 -1
- package/lib/apps/plugins/a2ui-surface/index.js +10 -1
- package/lib/apps/plugins/a2ui-surface/toolResult.d.ts +20 -11
- package/lib/apps/plugins/a2ui-surface/toolResult.js +27 -11
- package/lib/apps/plugins/app-components/index.d.ts +1 -1
- package/lib/apps/plugins/app-components/index.js +2 -2
- package/lib/apps/plugins/app-elements/AppElements.d.ts +3 -3
- package/lib/apps/plugins/app-elements/AppElements.js +5 -20
- package/lib/apps/plugins/app-elements/QuestionView.d.ts +30 -0
- package/lib/apps/plugins/app-elements/QuestionView.js +70 -0
- package/lib/apps/plugins/app-elements/index.d.ts +7 -4
- package/lib/apps/plugins/app-elements/index.js +14 -5
- package/lib/apps/plugins/app-page/appPageModel.d.ts +6 -8
- package/lib/apps/plugins/app-page/appPageModel.js +0 -2
- package/lib/apps/plugins/app-page/pageRun.d.ts +2 -2
- package/lib/apps/plugins/app-page/pageRun.js +3 -3
- package/lib/apps/plugins/canvas-blocks/index.d.ts +13 -13
- package/lib/apps/plugins/canvas-blocks/index.js +24 -24
- package/lib/apps/plugins/canvas-parts/index.d.ts +7 -1
- package/lib/apps/plugins/canvas-parts/index.js +36 -0
- package/lib/apps/plugins/chat/ChatView.js +29 -3
- package/lib/chat/base/ChatBase.js +264 -43
- package/lib/chat/base/loopElement.d.ts +16 -17
- package/lib/chat/base/loopElement.js +11 -27
- package/lib/chat/base/loopStep.d.ts +15 -15
- package/lib/chat/base/loopStep.js +10 -13
- package/lib/chat/base/loopWindow.d.ts +15 -20
- package/lib/chat/base/loopWindow.js +26 -27
- package/lib/chat/base/uiFiles.d.ts +29 -0
- package/lib/chat/base/uiFiles.js +69 -0
- package/lib/chat/base/uiOps.d.ts +96 -0
- package/lib/chat/base/uiOps.js +251 -0
- package/lib/chat/messages/ChatMessageList.d.ts +13 -1
- package/lib/chat/messages/ChatMessageList.js +4 -4
- package/lib/components/a2ui/datalayer/Chart.d.ts +1 -1
- package/lib/components/a2ui/datalayer/schema.js +1 -1
- package/lib/components/teams/AnswerSurfaces.d.ts +3 -2
- package/lib/components/teams/AnswerSurfaces.js +7 -7
- package/lib/components/teams/useA2ATeam.d.ts +1 -1
- package/lib/config/AgentConfiguration.d.ts +1 -1
- package/lib/examples/ProtocolSignedRequestsExample.d.ts +10 -0
- package/lib/examples/ProtocolSignedRequestsExample.js +41 -0
- package/lib/examples/ProtocolUcpCheckoutExample.d.ts +10 -0
- package/lib/examples/ProtocolUcpCheckoutExample.js +59 -0
- package/lib/examples/example-selector.js +2 -0
- package/lib/examples/exampleGroups.d.ts +1 -1
- package/lib/examples/exampleGroups.js +4 -0
- package/lib/examples/index.d.ts +2 -0
- package/lib/examples/index.js +2 -0
- package/lib/examples/protocols/signedRequestsDemo.d.ts +27 -0
- package/lib/examples/protocols/signedRequestsDemo.js +59 -0
- package/lib/examples/protocols/ucpCheckoutDemo.d.ts +36 -0
- package/lib/examples/protocols/ucpCheckoutDemo.js +68 -0
- package/lib/protocols/AGUIAdapter.d.ts +7 -0
- package/lib/protocols/AGUIAdapter.js +43 -3
- package/lib/protocols/a2a/index.js +1 -0
- package/lib/protocols/agentic-commerce/index.js +1 -0
- package/lib/protocols/core.d.ts +6 -0
- package/lib/protocols/mcp/index.js +1 -0
- package/lib/protocols/pact/index.js +1 -0
- package/lib/protocols/ucp/index.js +1 -0
- package/lib/protocols/ucp/merchant.d.ts +15 -0
- package/lib/protocols/ucp/merchant.js +257 -0
- package/lib/protocols/web-bot-auth/index.js +1 -0
- package/lib/specs/agents/agents.js +338 -169
- package/lib/specs/apps.js +134 -6
- package/lib/specs/appspecSchema.js +59 -0
- package/lib/specs/cogs.js +6 -3
- package/lib/specs/index.d.ts +2 -1
- package/lib/specs/index.js +2 -1
- package/lib/specs/protocols.d.ts +24 -0
- package/lib/specs/protocols.js +197 -0
- package/lib/specs/ui.d.ts +21 -0
- package/lib/specs/{uiPlugins.js → ui.js} +14 -14
- package/lib/types/agentspecs.d.ts +69 -5
- package/lib/types/messages.d.ts +7 -0
- package/lib/types/protocol.d.ts +15 -0
- package/package.json +2 -2
- package/scripts/codegen/generate_agents.py +43 -8
- package/scripts/codegen/generate_protocols.py +207 -0
- package/scripts/codegen/generate_sandbox_agents.py +1 -1
- package/scripts/codegen/{generate_ui_plugins.py → generate_ui.py} +40 -40
- package/scripts/gen_workers.py +2 -2
- package/dist-embed/chunks/ChatView-D41Nx5rC.js +0 -32
- package/lib/chat/base/loopMessage.d.ts +0 -37
- package/lib/chat/base/loopMessage.js +0 -37
- package/lib/specs/uiPlugins.d.ts +0 -21
|
@@ -19,6 +19,8 @@ import { useContext } from 'react';
|
|
|
19
19
|
import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
20
20
|
import { Text, Spinner, IconButton } from '@primer/react';
|
|
21
21
|
import { ReactorLazy } from '@datalayer/reactor/react';
|
|
22
|
+
import { ANSWER_ACTION, emptyUiModel, isFileRef, uploadFile, } from '@datalayer/reactor/ui';
|
|
23
|
+
import { UiSocket } from '@datalayer/reactor/ui/ws';
|
|
22
24
|
import { SkeletonText } from '@primer/react/experimental';
|
|
23
25
|
import { SidebarExpandIcon } from '@primer/octicons-react';
|
|
24
26
|
import { notebookStore, JupyterReactTheme } from '@datalayer/jupyter-react';
|
|
@@ -70,10 +72,11 @@ const ephemeralNotebookRefused = lazyViewRefused('notebook');
|
|
|
70
72
|
import { useNotebookTools } from '../../tools/adapters/agent-runtimes/notebookHooks';
|
|
71
73
|
import { useAgentInspectorTracer } from '../../components/inspector/agentSpans';
|
|
72
74
|
import { chatSpanRecorder, } from '../../components/inspector/chatSpans';
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
75
|
+
import { isStepDisplay, withLoopStep } from './loopStep';
|
|
76
|
+
import { applyLoopElement } from './loopElement';
|
|
77
|
+
import { tellLoopWindow } from './loopWindow';
|
|
78
|
+
import { displayPressOf, placeable, routeUiOp, withPress, withUiOp, } from './uiOps';
|
|
79
|
+
import { namesFiles, withUploadedFiles, } from './uiFiles';
|
|
77
80
|
import { useChatWords } from '../ChatLanguage';
|
|
78
81
|
// Tracks pending prompts already auto-sent for a given conversation scope.
|
|
79
82
|
// This prevents layout-driven unmount/remount cycles from re-sending prompts.
|
|
@@ -1196,6 +1199,10 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1196
1199
|
const [historyLoaded, setHistoryLoaded] = useState(!historyScopeId);
|
|
1197
1200
|
const [historyRefreshTick, setHistoryRefreshTick] = useState(0);
|
|
1198
1201
|
const historyRetryAttemptsRef = useRef(new Map());
|
|
1202
|
+
// The steps of an application's code shown so far, as displays (patched
|
|
1203
|
+
// as they stream), and the elements it showed (REACTOR_UI RU-3).
|
|
1204
|
+
const uiStepsRef = useRef(emptyUiModel());
|
|
1205
|
+
const uiElementsRef = useRef(new Set());
|
|
1199
1206
|
// Adapter-ready flag — flipped to true once the protocol adapter is initialised
|
|
1200
1207
|
const [adapterReady, setAdapterReady] = useState(false);
|
|
1201
1208
|
// Guard so each distinct pending prompt is sent at most once. Stores the
|
|
@@ -1578,6 +1585,187 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1578
1585
|
threadGivenRef.current?.onStarted?.(id);
|
|
1579
1586
|
}
|
|
1580
1587
|
}, []);
|
|
1588
|
+
/*
|
|
1589
|
+
* The conversation's ui channel (REACTOR_UI RU-W): one WebSocket per
|
|
1590
|
+
* conversation, its thread the scope, opened once its session is there
|
|
1591
|
+
* (the first event of its first run, or a thread reopened). What its
|
|
1592
|
+
* messages show, its steps, its elements, its authors and its window
|
|
1593
|
+
* messages arrive here as `reactor.ui` ops; the presses of what they
|
|
1594
|
+
* offered go up it. An op about a message the run stream has not brought
|
|
1595
|
+
* yet — they are two connections — waits for it (`placeable`).
|
|
1596
|
+
*/
|
|
1597
|
+
const uiSocketRef = useRef(null);
|
|
1598
|
+
const parkedUiOpsRef = useRef([]);
|
|
1599
|
+
const historyStepsRef = useRef(new Set());
|
|
1600
|
+
const displayItemsRef = useRef([]);
|
|
1601
|
+
const uiSocketUrl = protocol?.uiSocket;
|
|
1602
|
+
const uiSocketTokenRef = useRef(protocol?.authToken);
|
|
1603
|
+
uiSocketTokenRef.current = protocol?.authToken;
|
|
1604
|
+
/*
|
|
1605
|
+
* Its files (REACTOR_UI RU-6): uploaded to its runtime before the run or
|
|
1606
|
+
* the press that names them, the conversation's thread their scope; the
|
|
1607
|
+
* run carries the ref, never the bytes.
|
|
1608
|
+
*/
|
|
1609
|
+
const uiFilesUrl = protocol?.uiFiles;
|
|
1610
|
+
const uploadToConversation = useCallback(file => {
|
|
1611
|
+
if (!uiFilesUrl) {
|
|
1612
|
+
return Promise.reject(new Error('This conversation takes no file.'));
|
|
1613
|
+
}
|
|
1614
|
+
return uploadFile(file, {
|
|
1615
|
+
url: uiFilesUrl,
|
|
1616
|
+
scope: threadIdRef.current,
|
|
1617
|
+
token: uiSocketTokenRef.current,
|
|
1618
|
+
});
|
|
1619
|
+
}, [uiFilesUrl]);
|
|
1620
|
+
const applyToMessages = useCallback((op) => {
|
|
1621
|
+
const apply = (items) => {
|
|
1622
|
+
try {
|
|
1623
|
+
return withUiOp(items, op);
|
|
1624
|
+
}
|
|
1625
|
+
catch (error) {
|
|
1626
|
+
console.error('[ChatBase] reactor.ui op not applied:', error);
|
|
1627
|
+
return items;
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
setDisplayItems(prev => apply(prev));
|
|
1631
|
+
if (useStoreMode) {
|
|
1632
|
+
const store = useChatStore.getState();
|
|
1633
|
+
store.setMessages(apply(store.messages));
|
|
1634
|
+
}
|
|
1635
|
+
}, [useStoreMode]);
|
|
1636
|
+
const applySocketOp = useCallback((op, history) => {
|
|
1637
|
+
// The past is drawn again, never acted on: a window message is not
|
|
1638
|
+
// raised again, and the steps of turns long over are not drawn again.
|
|
1639
|
+
if (history) {
|
|
1640
|
+
if (op.op === 'window')
|
|
1641
|
+
return;
|
|
1642
|
+
if ((op.op === 'show' || op.op === 'ask') && isStepDisplay(op.body)) {
|
|
1643
|
+
historyStepsRef.current.add(op.body.id);
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
if ((op.op === 'patch' || op.op === 'append') &&
|
|
1647
|
+
historyStepsRef.current.has(op.id)) {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
let next;
|
|
1652
|
+
try {
|
|
1653
|
+
next = routeUiOp(op, uiStepsRef.current, uiElementsRef.current);
|
|
1654
|
+
}
|
|
1655
|
+
catch (error) {
|
|
1656
|
+
console.error('[ChatBase] reactor.ui op not applied:', error);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
uiStepsRef.current = next.steps;
|
|
1660
|
+
const routed = next.routed;
|
|
1661
|
+
if (routed.to === 'window') {
|
|
1662
|
+
// For the page it sits in, outside the conversation (LOOP P-25).
|
|
1663
|
+
tellLoopWindow(routed.data);
|
|
1664
|
+
}
|
|
1665
|
+
else if (routed.to === 'step') {
|
|
1666
|
+
// A step of its code, drawn as it runs (LOOP P-16).
|
|
1667
|
+
const step = routed.step;
|
|
1668
|
+
setDisplayItems(prev => withLoopStep(prev, step));
|
|
1669
|
+
}
|
|
1670
|
+
else if (routed.to === 'element') {
|
|
1671
|
+
// In a side panel or on a page of its own (LOOP P-18).
|
|
1672
|
+
uiElementsRef.current.add(routed.change.id);
|
|
1673
|
+
applyLoopElement(routed.change);
|
|
1674
|
+
}
|
|
1675
|
+
else if (!placeable(displayItemsRef.current, routed.op)) {
|
|
1676
|
+
const under = routed.op.op === 'show' || routed.op.op === 'ask'
|
|
1677
|
+
? routed.op.body.data?.message_id
|
|
1678
|
+
: undefined;
|
|
1679
|
+
if (history && typeof under === 'string') {
|
|
1680
|
+
// Shown in the past under a message that said nothing: the
|
|
1681
|
+
// thread did not draw it, the chat draws it for what it showed.
|
|
1682
|
+
const placeholder = {
|
|
1683
|
+
id: under,
|
|
1684
|
+
role: 'assistant',
|
|
1685
|
+
content: '',
|
|
1686
|
+
createdAt: new Date(),
|
|
1687
|
+
};
|
|
1688
|
+
displayItemsRef.current = [...displayItemsRef.current, placeholder];
|
|
1689
|
+
setDisplayItems(prev => prev.some(item => item.id === under)
|
|
1690
|
+
? prev
|
|
1691
|
+
: [...prev, placeholder]);
|
|
1692
|
+
if (useStoreMode)
|
|
1693
|
+
useChatStore.getState().addMessage(placeholder);
|
|
1694
|
+
applyToMessages(routed.op);
|
|
1695
|
+
}
|
|
1696
|
+
else {
|
|
1697
|
+
parkedUiOpsRef.current.push(routed.op);
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
else {
|
|
1701
|
+
applyToMessages(routed.op);
|
|
1702
|
+
}
|
|
1703
|
+
}, [applyToMessages, useStoreMode]);
|
|
1704
|
+
const applySocketOpRef = useRef(applySocketOp);
|
|
1705
|
+
applySocketOpRef.current = applySocketOp;
|
|
1706
|
+
// What waited for its message, applied once the message is here.
|
|
1707
|
+
useEffect(() => {
|
|
1708
|
+
displayItemsRef.current = displayItems;
|
|
1709
|
+
if (parkedUiOpsRef.current.length === 0)
|
|
1710
|
+
return;
|
|
1711
|
+
const parked = parkedUiOpsRef.current.splice(0);
|
|
1712
|
+
let items = displayItems;
|
|
1713
|
+
for (const op of parked) {
|
|
1714
|
+
if (!placeable(items, op)) {
|
|
1715
|
+
parkedUiOpsRef.current.push(op);
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
try {
|
|
1719
|
+
items = withUiOp(items, op);
|
|
1720
|
+
}
|
|
1721
|
+
catch {
|
|
1722
|
+
// Said by `applyToMessages`, which refuses it the same way.
|
|
1723
|
+
}
|
|
1724
|
+
applyToMessages(op);
|
|
1725
|
+
}
|
|
1726
|
+
}, [displayItems, applyToMessages]);
|
|
1727
|
+
/** The conversation's ui socket, opened for its thread when it is not yet. */
|
|
1728
|
+
const ensureUiSocket = useCallback(() => {
|
|
1729
|
+
if (!uiSocketUrl)
|
|
1730
|
+
return null;
|
|
1731
|
+
const scope = threadIdRef.current;
|
|
1732
|
+
const open = uiSocketRef.current;
|
|
1733
|
+
if (open && open.scope === scope)
|
|
1734
|
+
return open.socket;
|
|
1735
|
+
// Another conversation: what the last one showed goes with it.
|
|
1736
|
+
open?.socket.close();
|
|
1737
|
+
uiStepsRef.current = emptyUiModel();
|
|
1738
|
+
uiElementsRef.current = new Set();
|
|
1739
|
+
parkedUiOpsRef.current = [];
|
|
1740
|
+
historyStepsRef.current = new Set();
|
|
1741
|
+
const socket = new UiSocket({
|
|
1742
|
+
url: uiSocketUrl,
|
|
1743
|
+
scope,
|
|
1744
|
+
token: () => uiSocketTokenRef.current ?? '',
|
|
1745
|
+
onOp: (op, _seq, history) => applySocketOpRef.current(op, history),
|
|
1746
|
+
onStatus: (status, reason) => {
|
|
1747
|
+
if (status === 'refused' || status === 'gone') {
|
|
1748
|
+
console.error(`[ChatBase] ui socket ${status}: ${reason ?? ''}`);
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
});
|
|
1752
|
+
uiSocketRef.current = { socket, scope };
|
|
1753
|
+
socket.connect();
|
|
1754
|
+
return socket;
|
|
1755
|
+
}, [uiSocketUrl]);
|
|
1756
|
+
const ensureUiSocketRef = useRef(ensureUiSocket);
|
|
1757
|
+
ensureUiSocketRef.current = ensureUiSocket;
|
|
1758
|
+
// A thread reopened has its session already: its socket opens now.
|
|
1759
|
+
useEffect(() => {
|
|
1760
|
+
if (thread?.messages.length)
|
|
1761
|
+
ensureUiSocketRef.current();
|
|
1762
|
+
return () => {
|
|
1763
|
+
uiSocketRef.current?.socket.close();
|
|
1764
|
+
uiSocketRef.current = null;
|
|
1765
|
+
};
|
|
1766
|
+
// At mount: the thread it was given.
|
|
1767
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1768
|
+
}, []);
|
|
1581
1769
|
const messagesContainerRef = useRef(null);
|
|
1582
1770
|
const messagesEndRef = useRef(null);
|
|
1583
1771
|
const inputRef = useRef(null);
|
|
@@ -2378,6 +2566,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2378
2566
|
adapterRef.current = adapter;
|
|
2379
2567
|
setAdapterReady(true);
|
|
2380
2568
|
unsubscribeRef.current = adapter.subscribe((event) => {
|
|
2569
|
+
// The run's session is there once it answers: its ui socket opens.
|
|
2570
|
+
ensureUiSocketRef.current();
|
|
2381
2571
|
/*
|
|
2382
2572
|
* Nothing more from a turn the reader has stopped.
|
|
2383
2573
|
*
|
|
@@ -2707,45 +2897,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2707
2897
|
}
|
|
2708
2898
|
}
|
|
2709
2899
|
break;
|
|
2710
|
-
case 'activity':
|
|
2711
|
-
//
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
setDisplayItems(prev => withLoopStep(prev, step));
|
|
2715
|
-
break;
|
|
2716
|
-
}
|
|
2717
|
-
// What its code tells the page it sits in, outside the
|
|
2718
|
-
// conversation (LOOP P-25): handed to whoever listens.
|
|
2719
|
-
const windowMessage = loopWindowMessage(event.activity);
|
|
2720
|
-
if (windowMessage) {
|
|
2721
|
-
tellLoopWindow(windowMessage.data);
|
|
2722
|
-
break;
|
|
2723
|
-
}
|
|
2724
|
-
// An element its code opened in a side panel or on a page of its
|
|
2725
|
-
// own, changed or closed (LOOP P-18): kept for whoever draws them.
|
|
2726
|
-
const element = loopElementChange(event.activity);
|
|
2727
|
-
if (element) {
|
|
2728
|
-
applyLoopElement(element);
|
|
2729
|
-
break;
|
|
2730
|
-
}
|
|
2731
|
-
// An application's code changed a message it sent: its author
|
|
2732
|
-
// said, or the message taken away (LOOP P-15).
|
|
2733
|
-
const change = loopMessageChange(event.activity);
|
|
2734
|
-
if (!change)
|
|
2735
|
-
break;
|
|
2736
|
-
setDisplayItems(prev => withLoopMessage(prev, change));
|
|
2737
|
-
if (useStoreMode) {
|
|
2738
|
-
if ('removed' in change) {
|
|
2739
|
-
useChatStore.getState().deleteMessage(change.id);
|
|
2740
|
-
}
|
|
2741
|
-
else {
|
|
2742
|
-
useChatStore.getState().updateMessage(change.id, {
|
|
2743
|
-
speaker: speakerOf(change.author),
|
|
2744
|
-
});
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2900
|
+
case 'activity':
|
|
2901
|
+
// What the server says besides the conversation's text comes on
|
|
2902
|
+
// the ui socket (REACTOR_UI RU-W); the run's other activities —
|
|
2903
|
+
// `loop.session`, `loop.page` — are their readers'.
|
|
2747
2904
|
break;
|
|
2748
|
-
}
|
|
2749
2905
|
case 'done':
|
|
2750
2906
|
/*
|
|
2751
2907
|
* What the turn cost, when nobody else is counting.
|
|
@@ -2949,6 +3105,38 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2949
3105
|
return;
|
|
2950
3106
|
if (!adapterRef.current && !onSendMessage)
|
|
2951
3107
|
return;
|
|
3108
|
+
// Its files are uploaded first: the run names their refs (RU-6).
|
|
3109
|
+
if (forwardedPropsGiven && namesFiles(forwardedPropsGiven)) {
|
|
3110
|
+
try {
|
|
3111
|
+
forwardedPropsGiven = await withUploadedFiles(forwardedPropsGiven, uploadToConversation);
|
|
3112
|
+
}
|
|
3113
|
+
catch (failure) {
|
|
3114
|
+
setError(failure instanceof Error ? failure : new Error(String(failure)));
|
|
3115
|
+
return;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
// A press of what a display offered goes up the ui socket, checked
|
|
3119
|
+
// there; the run that answers it names it only (REACTOR_UI RU-W).
|
|
3120
|
+
const pressed = displayPressOf(forwardedPropsGiven);
|
|
3121
|
+
if (pressed && forwardedPropsGiven) {
|
|
3122
|
+
const socket = uiSocketRef.current?.socket;
|
|
3123
|
+
if (!socket) {
|
|
3124
|
+
setError(new Error('This conversation’s ui channel is not open.'));
|
|
3125
|
+
return;
|
|
3126
|
+
}
|
|
3127
|
+
try {
|
|
3128
|
+
const result = await socket.act(pressed);
|
|
3129
|
+
if (!result.ok) {
|
|
3130
|
+
setError(new Error(result.detail || `The press was refused (${result.status}).`));
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
forwardedPropsGiven = withPress(forwardedPropsGiven, result.value);
|
|
3134
|
+
}
|
|
3135
|
+
catch (failure) {
|
|
3136
|
+
setError(failure instanceof Error ? failure : new Error(String(failure)));
|
|
3137
|
+
return;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
2952
3140
|
stoppedRef.current = false;
|
|
2953
3141
|
inspectAnswerRef.current = '';
|
|
2954
3142
|
recorderRef.current?.recorder.turnStarted(messageContent, selectedModel || undefined);
|
|
@@ -3099,6 +3287,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3099
3287
|
getEnabledSkillIds,
|
|
3100
3288
|
noteThreadStarted,
|
|
3101
3289
|
chatText,
|
|
3290
|
+
uploadToConversation,
|
|
3102
3291
|
]);
|
|
3103
3292
|
// Send pending prompt once history loaded and adapter/handler available
|
|
3104
3293
|
useEffect(() => {
|
|
@@ -3221,6 +3410,38 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3221
3410
|
protocol?.authToken,
|
|
3222
3411
|
protocol?.agentId,
|
|
3223
3412
|
]);
|
|
3413
|
+
/*
|
|
3414
|
+
* How a message's display presses what it offered (REACTOR_UI RU-4,
|
|
3415
|
+
* RU-W): with the token of the offer, as the run's press — which
|
|
3416
|
+
* `handleSend` sends up the ui socket before the run, the run naming it
|
|
3417
|
+
* only. An answer is the person's words in the conversation; any other
|
|
3418
|
+
* press, the action's name.
|
|
3419
|
+
*/
|
|
3420
|
+
const actOnDisplay = useCallback((display) => async (action) => {
|
|
3421
|
+
const offer = display.actions?.find(one => one.name === action.action);
|
|
3422
|
+
if (!offer) {
|
|
3423
|
+
throw new Error(`“${action.action}” was not offered here.`);
|
|
3424
|
+
}
|
|
3425
|
+
const value = action.payload
|
|
3426
|
+
?.value;
|
|
3427
|
+
const words = action.action === ANSWER_ACTION
|
|
3428
|
+
? typeof value === 'string'
|
|
3429
|
+
? value
|
|
3430
|
+
: isFileRef(value)
|
|
3431
|
+
? value.name
|
|
3432
|
+
: 'Answered.'
|
|
3433
|
+
: action.action;
|
|
3434
|
+
await handleSend(words, {
|
|
3435
|
+
loop: {
|
|
3436
|
+
action: {
|
|
3437
|
+
name: action.action,
|
|
3438
|
+
display_id: display.id,
|
|
3439
|
+
token: offer.token,
|
|
3440
|
+
payload: action.payload ?? {},
|
|
3441
|
+
},
|
|
3442
|
+
},
|
|
3443
|
+
});
|
|
3444
|
+
}, [handleSend]);
|
|
3224
3445
|
// ---- handleNewChat ----
|
|
3225
3446
|
const handleNewChat = useCallback(() => {
|
|
3226
3447
|
setDisplayItems([]);
|
|
@@ -3618,7 +3839,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3618
3839
|
rows inside carry their own horizontal padding, which becomes the
|
|
3619
3840
|
margin once the cap does bind.
|
|
3620
3841
|
*/
|
|
3621
|
-
width: "100%", maxWidth: 920, mx: "auto", bg: "canvas.default", children: [_jsx(ChatMessageList, { displayItems: welcomedItems, isLoading: isLoading, isStreaming: isStreaming, showLoadingIndicator: showLoadingIndicator, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: defaultAvatarConfig, padding: padding,
|
|
3842
|
+
width: "100%", maxWidth: 920, mx: "auto", bg: "canvas.default", children: [_jsx(ChatMessageList, { displayItems: welcomedItems, actOn: protocol?.uiSocket ? actOnDisplay : undefined, upload: protocol?.uiFiles ? uploadToConversation : undefined, isLoading: isLoading, isStreaming: isStreaming, showLoadingIndicator: showLoadingIndicator, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: defaultAvatarConfig, padding: padding,
|
|
3622
3843
|
// Tool calls are drawn by the page's Reactor plugins; a named
|
|
3623
3844
|
// notebook's cell surfaces stand in for the default row of its tools,
|
|
3624
3845
|
// so every chat with a headless notebook gets the same transcript.
|
|
@@ -3,16 +3,14 @@
|
|
|
3
3
|
* panel beside the conversation, or on a page of its own over it. Inline,
|
|
4
4
|
* an element is a message, and the chat draws it as one (P-04).
|
|
5
5
|
*
|
|
6
|
-
* The session API
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* application on it.
|
|
6
|
+
* The session API shows it as a `reactor.ui` display that says where it
|
|
7
|
+
* shows in its data (`where: "panel" | "page"`, with its `title`) — an
|
|
8
|
+
* answer's display (REACTOR_UI RU-2) — and closes it with a `remove` of its
|
|
9
|
+
* id (RU-3). The chat does not draw it: it keeps what is open here, and
|
|
10
|
+
* whoever draws panels and pages (the `app-elements` plugin) listens. One
|
|
11
|
+
* store per page, as there is one chat per application on it.
|
|
13
12
|
*/
|
|
14
|
-
|
|
15
|
-
export declare const LOOP_ELEMENT = "loop.element";
|
|
13
|
+
import type { Display } from '@datalayer/reactor/ui';
|
|
16
14
|
/** Where an element opens, besides inline. */
|
|
17
15
|
export type LoopElementWhere = 'panel' | 'page';
|
|
18
16
|
/** An element open in a side panel or on a page. */
|
|
@@ -20,19 +18,20 @@ export type LoopElement = {
|
|
|
20
18
|
id: string;
|
|
21
19
|
where: LoopElementWhere;
|
|
22
20
|
title: string;
|
|
23
|
-
/** The
|
|
24
|
-
shows:
|
|
21
|
+
/** The display it draws: what an answer shows (`AnswerShows`). */
|
|
22
|
+
shows: Display;
|
|
25
23
|
};
|
|
26
|
-
/** What
|
|
24
|
+
/** What changed: an element opened or changed, or one closed. */
|
|
27
25
|
export type LoopElementChange = LoopElement | {
|
|
28
26
|
id: string;
|
|
29
27
|
closed: true;
|
|
30
28
|
};
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The element a display is, or `null` for one shown inline, under its
|
|
31
|
+
* message: a display is an element when it says it shows in a panel or on
|
|
32
|
+
* a page.
|
|
33
|
+
*/
|
|
34
|
+
export declare function elementOfDisplay(display: Display): LoopElement | null;
|
|
36
35
|
/**
|
|
37
36
|
* The elements open with a change applied: one opened is added last, one
|
|
38
37
|
* changed is replaced where it is, one closed is taken away.
|
|
@@ -3,36 +3,20 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* The session API says it with a `CUSTOM` event named `loop.element` —
|
|
11
|
-
* `{id, where, title, shows}`, `shows` the A2UI surface an answer's
|
|
12
|
-
* components are drawn from, or `{id, closed: true}` — which the AG-UI
|
|
13
|
-
* adapter hands on as an `activity`. The chat does not draw it: it keeps
|
|
14
|
-
* what is open here, and whoever draws panels and pages (the `app-elements`
|
|
15
|
-
* plugin) listens. One store per page, as there is one chat per
|
|
16
|
-
* application on it.
|
|
6
|
+
* The element a display is, or `null` for one shown inline, under its
|
|
7
|
+
* message: a display is an element when it says it shows in a panel or on
|
|
8
|
+
* a page.
|
|
17
9
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export function loopElementChange(activity) {
|
|
22
|
-
if (!activity || activity.type !== LOOP_ELEMENT)
|
|
23
|
-
return null;
|
|
24
|
-
const data = activity.data;
|
|
25
|
-
if (!data || typeof data.id !== 'string' || !data.id)
|
|
26
|
-
return null;
|
|
27
|
-
if (data.closed === true)
|
|
28
|
-
return { id: data.id, closed: true };
|
|
29
|
-
if (data.where !== 'panel' && data.where !== 'page')
|
|
10
|
+
export function elementOfDisplay(display) {
|
|
11
|
+
const where = display.data?.where;
|
|
12
|
+
if (where !== 'panel' && where !== 'page')
|
|
30
13
|
return null;
|
|
14
|
+
const title = display.data?.title;
|
|
31
15
|
return {
|
|
32
|
-
id:
|
|
33
|
-
where
|
|
34
|
-
title: typeof
|
|
35
|
-
shows:
|
|
16
|
+
id: display.id,
|
|
17
|
+
where,
|
|
18
|
+
title: typeof title === 'string' ? title : '',
|
|
19
|
+
shows: display,
|
|
36
20
|
};
|
|
37
21
|
}
|
|
38
22
|
/**
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
* (LOOP P-16): the chain of thought.
|
|
4
4
|
*
|
|
5
5
|
* AG-UI's `STEP_STARTED` and `STEP_FINISHED` carry a step's name only; the
|
|
6
|
-
* session API
|
|
7
|
-
* `loop.step`
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* session API shows the step whole beside them as a `reactor.ui` display of
|
|
7
|
+
* type `application/vnd.datalayer.loop.step+json` (REACTOR_UI RU-3) — its
|
|
8
|
+
* data `{name, kind, parent_id, input, output, error, started_at,
|
|
9
|
+
* ended_at}`, its id the step's — shown as it starts and again as it ends,
|
|
10
|
+
* its output patched in as it streams (LOOP P-31). A step is drawn as the
|
|
11
|
+
* chat draws a tool call: one row, collapsed, its input and output inside,
|
|
12
|
+
* running until it ends; a nested step says the step it is in.
|
|
13
13
|
*/
|
|
14
|
+
import type { Display } from '@datalayer/reactor/ui';
|
|
14
15
|
import type { DisplayItem, ToolCallMessage } from '../../types/chat';
|
|
15
|
-
/** The
|
|
16
|
-
export declare const
|
|
17
|
-
/** A step, as
|
|
16
|
+
/** The display type of a step. */
|
|
17
|
+
export declare const STEP_DISPLAY_TYPE = "application/vnd.datalayer.loop.step+json";
|
|
18
|
+
/** A step, as its display says it. */
|
|
18
19
|
export type LoopStep = {
|
|
19
20
|
id: string;
|
|
20
21
|
name: string;
|
|
@@ -25,11 +26,10 @@ export type LoopStep = {
|
|
|
25
26
|
error: string;
|
|
26
27
|
ended: boolean;
|
|
27
28
|
};
|
|
28
|
-
/**
|
|
29
|
-
export declare
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} | undefined): LoopStep | null;
|
|
29
|
+
/** Whether a display is a step's. */
|
|
30
|
+
export declare const isStepDisplay: (display: Display) => boolean;
|
|
31
|
+
/** The step a step's display says. Throws for one that is not a step's. */
|
|
32
|
+
export declare function stepOfDisplay(display: Display): LoopStep;
|
|
33
33
|
/** The id of the row a step is drawn as. */
|
|
34
34
|
export declare const stepCallId: (id: string) => string;
|
|
35
35
|
/** A step as the row the chat draws a tool call as. */
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
/** The
|
|
6
|
-
export const
|
|
7
|
-
/**
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const data =
|
|
12
|
-
if (!data
|
|
13
|
-
|
|
14
|
-
!data.id ||
|
|
15
|
-
typeof data.name !== 'string') {
|
|
16
|
-
return null;
|
|
5
|
+
/** The display type of a step. */
|
|
6
|
+
export const STEP_DISPLAY_TYPE = 'application/vnd.datalayer.loop.step+json';
|
|
7
|
+
/** Whether a display is a step's. */
|
|
8
|
+
export const isStepDisplay = (display) => display.type === STEP_DISPLAY_TYPE;
|
|
9
|
+
/** The step a step's display says. Throws for one that is not a step's. */
|
|
10
|
+
export function stepOfDisplay(display) {
|
|
11
|
+
const data = display.data ?? {};
|
|
12
|
+
if (!isStepDisplay(display) || typeof data.name !== 'string') {
|
|
13
|
+
throw new Error(`Display ${display.id} is not a step`);
|
|
17
14
|
}
|
|
18
15
|
return {
|
|
19
|
-
id:
|
|
16
|
+
id: display.id,
|
|
20
17
|
name: data.name,
|
|
21
18
|
kind: typeof data.kind === 'string' ? data.kind : 'run',
|
|
22
19
|
parentId: typeof data.parent_id === 'string' && data.parent_id
|
|
@@ -2,30 +2,25 @@
|
|
|
2
2
|
* Window messages (LOOP P-25): what an application's code tells the page it
|
|
3
3
|
* sits in, outside the conversation — ``session.send_window_message(data)``.
|
|
4
4
|
*
|
|
5
|
-
* The session
|
|
6
|
-
* `{data}`
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The session says it with a `reactor.ui` `window` op named `message`, its
|
|
6
|
+
* `args` `{data}` (REACTOR_UI RU-3), on the conversation's ui socket (RU-W). The chat does not draw it: it hands
|
|
7
|
+
* it to whoever listens here — the embed's host bridge, which raises it on
|
|
8
|
+
* the element as its `window-message` event. A window op of another name is
|
|
9
|
+
* not one this page acts on: refused, it throws.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
data: unknown;
|
|
16
|
-
} | undefined): {
|
|
17
|
-
data: unknown;
|
|
18
|
-
} | null;
|
|
11
|
+
import { type WindowOp } from '@datalayer/reactor/ui';
|
|
12
|
+
/** The name of the window op that hands the page a message. */
|
|
13
|
+
export declare const WINDOW_MESSAGE = "message";
|
|
14
|
+
/** What a window op hands the page. Throws for a window op of another name. */
|
|
15
|
+
export declare function windowMessageOf(op: WindowOp): unknown;
|
|
19
16
|
/** Hand a window message to whoever listens. */
|
|
20
17
|
export declare function tellLoopWindow(data: unknown): void;
|
|
21
18
|
/** Listen for window messages. Returns the unsubscribe. */
|
|
22
19
|
export declare function onLoopWindowMessage(listener: (data: unknown) => void): () => void;
|
|
23
20
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Why the turn a window message posted by the page ran failed — its
|
|
22
|
+
* `RUN_ERROR`'s sentence — or `null`. What its code tells the page back comes
|
|
23
|
+
* on the conversation's ui socket (REACTOR_UI RU-W), never on this stream: a
|
|
24
|
+
* `reactor.ui` event here is refused.
|
|
27
25
|
*/
|
|
28
|
-
export declare function
|
|
29
|
-
said: unknown[];
|
|
30
|
-
error: string | null;
|
|
31
|
-
};
|
|
26
|
+
export declare function windowTurnErrorOf(stream: string): string | null;
|