@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
|
@@ -29,7 +29,7 @@ export interface LibraryAgentspec {
|
|
|
29
29
|
welcomeDocument?: string | null;
|
|
30
30
|
sandboxVariant?: string | null;
|
|
31
31
|
protocol?: string | null;
|
|
32
|
-
|
|
32
|
+
ui?: string | null;
|
|
33
33
|
trigger?: Record<string, unknown> | null;
|
|
34
34
|
modelConfig?: Record<string, unknown> | null;
|
|
35
35
|
mcpServerTools?: Array<Record<string, unknown>> | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signed requests (Web Bot Auth) in the browser (AGENT_PROTOCOLS EX-10): a
|
|
3
|
+
* key generated in the page signs one request; the page shows the three
|
|
4
|
+
* headers, the signature base the key signed, and what a website's check
|
|
5
|
+
* finds — verified, then the same request replayed and one with its path
|
|
6
|
+
* changed, both refused. The key never leaves the page and is never shown.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
declare const ProtocolSignedRequestsExample: React.FC;
|
|
10
|
+
export default ProtocolSignedRequestsExample;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Signed requests (Web Bot Auth) in the browser (AGENT_PROTOCOLS EX-10): a
|
|
8
|
+
* key generated in the page signs one request; the page shows the three
|
|
9
|
+
* headers, the signature base the key signed, and what a website's check
|
|
10
|
+
* finds — verified, then the same request replayed and one with its path
|
|
11
|
+
* changed, both refused. The key never leaves the page and is never shown.
|
|
12
|
+
*/
|
|
13
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
14
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
15
|
+
import { Button, Flash, Heading, Label, Text } from '@primer/react';
|
|
16
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
17
|
+
import { signedRequestDemo, } from './protocols/signedRequestsDemo';
|
|
18
|
+
setupPrimerPortals();
|
|
19
|
+
const Mono = ({ children, label, }) => (_jsxs(Box, { mb: 3, children: [_jsx(Text, { as: "div", sx: { fontWeight: 'semibold', fontSize: 1, mb: 1 }, children: label }), _jsx(Box, { as: "pre", p: 2, m: 0, bg: "canvas.subtle", borderRadius: 2, sx: { fontSize: 0, whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }, children: children })] }));
|
|
20
|
+
const OUTCOME_VARIANT = {
|
|
21
|
+
verified: 'success',
|
|
22
|
+
invalid: 'danger',
|
|
23
|
+
unverified: 'attention',
|
|
24
|
+
};
|
|
25
|
+
const ProtocolSignedRequestsExample = () => {
|
|
26
|
+
const [demo, setDemo] = useState(null);
|
|
27
|
+
const [error, setError] = useState('');
|
|
28
|
+
const run = useCallback(() => {
|
|
29
|
+
setError('');
|
|
30
|
+
signedRequestDemo()
|
|
31
|
+
.then(setDemo)
|
|
32
|
+
.catch(failure => setError(String(failure?.message ?? failure)));
|
|
33
|
+
}, []);
|
|
34
|
+
useEffect(run, [run]);
|
|
35
|
+
return (_jsx(ThemedProvider, { children: _jsxs(Box, { p: 4, maxWidth: 880, mx: "auto", children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Signed requests" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', mt: 0 }, children: "Web Bot Auth (draft-ietf-webbotauth-httpsig-protocol-00): a key generated in this page signs a request to a shop; the shop checks it against the agent's key directory. The private key is never shown." }), _jsx(Button, { onClick: run, sx: { mb: 3 }, children: "Sign again with a new key" }), error ? _jsx(Flash, { variant: "danger", children: error }) : null, demo ? (_jsxs(_Fragment, { children: [_jsxs(Mono, { label: "Request", children: ["GET ", demo.url] }), _jsx(Mono, { label: "Signature-Agent", children: demo.headers['Signature-Agent'] }), _jsx(Mono, { label: "Signature-Input", children: demo.headers['Signature-Input'] }), _jsx(Mono, { label: "Signature", children: demo.headers.Signature }), _jsx(Mono, { label: "Signature base (what the key signed)", children: demo.base }), _jsx(Mono, { label: "Public key in the directory (keyid: its thumbprint)", children: JSON.stringify(demo.publicJwk, null, 2) }), _jsx(Box, { display: "grid", gap: 2, children: [
|
|
36
|
+
['The shop checks it', demo.verified],
|
|
37
|
+
['The same request again', demo.replayed],
|
|
38
|
+
['Its path changed', demo.tampered],
|
|
39
|
+
].map(([what, found]) => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "baseline", children: [_jsx(Label, { variant: OUTCOME_VARIANT[found.outcome], children: found.outcome }), _jsxs(Text, { sx: { fontSize: 1 }, children: [what, found.reason ? `: ${found.reason}` : ''] })] }, what))) })] })) : null] }) }));
|
|
40
|
+
};
|
|
41
|
+
export default ProtocolSignedRequestsExample;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UCP checkout approved as a card (AGENT_PROTOCOLS EX-10, after EX-04):
|
|
3
|
+
* the UCP client buys from *Example Store*, the local test merchant running
|
|
4
|
+
* in the page. The exact purchase is proposed; completing it asks the
|
|
5
|
+
* approver — the card below — once; approving buys once, and the same
|
|
6
|
+
* proposal is refused after. The test payment's token is never shown.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
declare const ProtocolUcpCheckoutExample: React.FC;
|
|
10
|
+
export default ProtocolUcpCheckoutExample;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* A UCP checkout approved as a card (AGENT_PROTOCOLS EX-10, after EX-04):
|
|
8
|
+
* the UCP client buys from *Example Store*, the local test merchant running
|
|
9
|
+
* in the page. The exact purchase is proposed; completing it asks the
|
|
10
|
+
* approver — the card below — once; approving buys once, and the same
|
|
11
|
+
* proposal is refused after. The test payment's token is never shown.
|
|
12
|
+
*/
|
|
13
|
+
import { useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
15
|
+
import { Button, Flash, Heading, Text } from '@primer/react';
|
|
16
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
17
|
+
import { buy, proposeTea, ucpCheckoutDemo } from './protocols/ucpCheckoutDemo';
|
|
18
|
+
setupPrimerPortals();
|
|
19
|
+
const ProtocolUcpCheckoutExample = () => {
|
|
20
|
+
const answer = useRef(null);
|
|
21
|
+
const [asking, setAsking] = useState(false);
|
|
22
|
+
const demo = useMemo(() => ucpCheckoutDemo(() => new Promise(resolve => {
|
|
23
|
+
answer.current = resolve;
|
|
24
|
+
setAsking(true);
|
|
25
|
+
})), []);
|
|
26
|
+
const [proposal, setProposal] = useState(null);
|
|
27
|
+
const [said, setSaid] = useState([]);
|
|
28
|
+
const [working, setWorking] = useState(false);
|
|
29
|
+
const propose = async () => {
|
|
30
|
+
setWorking(true);
|
|
31
|
+
try {
|
|
32
|
+
setProposal(await proposeTea(demo));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
setSaid(s => [
|
|
36
|
+
...s,
|
|
37
|
+
{ ok: false, says: String(error.message) },
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
setWorking(false);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const complete = async () => {
|
|
45
|
+
if (!proposal)
|
|
46
|
+
return;
|
|
47
|
+
setWorking(true);
|
|
48
|
+
const outcome = await buy(demo, proposal.proposal);
|
|
49
|
+
setSaid(s => [...s, outcome]);
|
|
50
|
+
setWorking(false);
|
|
51
|
+
};
|
|
52
|
+
const decide = (approved) => {
|
|
53
|
+
setAsking(false);
|
|
54
|
+
answer.current?.(approved);
|
|
55
|
+
answer.current = null;
|
|
56
|
+
};
|
|
57
|
+
return (_jsx(ThemedProvider, { children: _jsxs(Box, { p: 4, maxWidth: 720, mx: "auto", children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "UCP checkout" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', mt: 0 }, children: "Universal Commerce Protocol 2026-08-25, against Example Store, a test merchant running in this page. Nothing is bought without the card below, and a proposal buys once." }), _jsxs(Box, { display: "flex", gap: 2, mb: 3, flexWrap: "wrap", children: [_jsx(Button, { onClick: propose, disabled: working || asking, children: "Propose 2 \u00D7 Sencha green tea" }), _jsx(Button, { variant: "primary", onClick: complete, disabled: !proposal || working, children: "Complete the purchase" })] }), proposal && asking ? (_jsxs(Box, { p: 3, mb: 3, border: "1px solid", borderColor: "attention.emphasis", borderRadius: 2, role: "dialog", "aria-label": "Approve this purchase", children: [_jsx(Text, { as: "p", sx: { fontWeight: 'semibold', mt: 0 }, children: "Approve this purchase?" }), _jsx(Text, { as: "p", children: proposal.says }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 0 }, children: ["Revision ", proposal.proposal.revision.slice(0, 12), "\u2026 \u2014 if the basket changes, it is proposed again."] }), _jsxs(Box, { display: "flex", gap: 2, children: [_jsx(Button, { variant: "primary", onClick: () => decide(true), children: "Approve" }), _jsx(Button, { onClick: () => decide(false), children: "Decline" })] })] })) : proposal ? (_jsxs(Text, { as: "p", sx: { fontSize: 1 }, children: ["Proposed: ", proposal.says] })) : null, said.map((each, index) => (_jsx(Flash, { variant: each.ok ? 'success' : 'warning', sx: { mb: 2 }, children: each.says }, index))), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 0 }, children: ["Orders at the store: ", demo.orders.length] })] }) }));
|
|
58
|
+
};
|
|
59
|
+
export default ProtocolUcpCheckoutExample;
|
|
@@ -131,6 +131,8 @@ export const EXAMPLE_ENTRIES = [
|
|
|
131
131
|
makeEntry('AgentSubagentsExample', () => import('./AgentSubagentsExample'), 'Multi-agent delegation with the in-repo subagents capability.'),
|
|
132
132
|
makeEntry('AgentA2AExample', () => import('./AgentA2AExample'), 'Delegation to separate agents over the A2A protocol, launched locally or on Datalayer runtimes.'),
|
|
133
133
|
makeEntry('AgentA2ATeamExample', () => import('./AgentA2ATeamExample'), 'Two applications as a team over A2A: Sales in the browser (@a2a-js/sdk) asks Accounting on a runtime (fasta2a, Odoo read only), each an Office Assistant character.'),
|
|
134
|
+
makeEntry('ProtocolSignedRequestsExample', () => import('./ProtocolSignedRequestsExample'), 'Web Bot Auth in the browser: a key made in the page signs a request — its three headers and the signature base — verified, then a replay and a changed path refused.'),
|
|
135
|
+
makeEntry('ProtocolUcpCheckoutExample', () => import('./ProtocolUcpCheckoutExample'), 'A UCP checkout at a test store in the page: the exact purchase proposed, approved on a card once, bought once.'),
|
|
134
136
|
makeEntry('PapCompanyDiscoveryExample', () => import('./PapCompanyDiscoveryExample'), 'Validate a PAP company document and reduce it to the public capabilities safe for an agent or UI.'),
|
|
135
137
|
makeEntry('PapAgentIdentityExample', () => import('./PapAgentIdentityExample'), 'Verify personal-agent client metadata and signing policy without exposing JWK coordinates.'),
|
|
136
138
|
makeEntry('PapAuthorizationBoundaryExample', () => import('./PapAuthorizationBoundaryExample'), 'Generate real Session and Direct Sign-In security material while showing only safe policy status.'),
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module examples/exampleGroups
|
|
7
7
|
*/
|
|
8
|
-
export declare const EXAMPLE_GROUP_ORDER: readonly ["Apps", "Assistant", "A2UI", "A2A", "Personal Agent Protocol", "AG-UI", "Chat", "Document", "Notebook", "Capabilities", "Cell", "CopilotKit"];
|
|
8
|
+
export declare const EXAMPLE_GROUP_ORDER: readonly ["Apps", "Assistant", "A2UI", "A2A", "Personal Agent Protocol", "Agent protocols", "AG-UI", "Chat", "Document", "Notebook", "Capabilities", "Cell", "CopilotKit"];
|
|
9
9
|
export declare const getExampleGroup: (id: string) => string;
|
|
@@ -15,6 +15,7 @@ export const EXAMPLE_GROUP_ORDER = [
|
|
|
15
15
|
'A2UI',
|
|
16
16
|
'A2A',
|
|
17
17
|
'Personal Agent Protocol',
|
|
18
|
+
'Agent protocols',
|
|
18
19
|
'AG-UI',
|
|
19
20
|
'Chat',
|
|
20
21
|
'Document',
|
|
@@ -39,6 +40,9 @@ export const getExampleGroup = (id) => {
|
|
|
39
40
|
return 'A2A';
|
|
40
41
|
if (id.startsWith('Pap'))
|
|
41
42
|
return 'Personal Agent Protocol';
|
|
43
|
+
// The other agent protocols' examples: signed requests, commerce (AGENT_PROTOCOLS EX-10).
|
|
44
|
+
if (id.startsWith('Protocol'))
|
|
45
|
+
return 'Agent protocols';
|
|
42
46
|
if (id.startsWith('AgUi'))
|
|
43
47
|
return 'AG-UI';
|
|
44
48
|
if (id.startsWith('CopilotKit'))
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
|
27
27
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
28
28
|
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
29
29
|
export { default as AgentA2ATeamExample } from './AgentA2ATeamExample';
|
|
30
|
+
export { default as ProtocolSignedRequestsExample } from './ProtocolSignedRequestsExample';
|
|
31
|
+
export { default as ProtocolUcpCheckoutExample } from './ProtocolUcpCheckoutExample';
|
|
30
32
|
export { default as PapCompanyDiscoveryExample } from './PapCompanyDiscoveryExample';
|
|
31
33
|
export { default as PapAgentIdentityExample } from './PapAgentIdentityExample';
|
|
32
34
|
export { default as PapAuthorizationBoundaryExample } from './PapAuthorizationBoundaryExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -33,6 +33,8 @@ export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
|
33
33
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
34
34
|
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
35
35
|
export { default as AgentA2ATeamExample } from './AgentA2ATeamExample';
|
|
36
|
+
export { default as ProtocolSignedRequestsExample } from './ProtocolSignedRequestsExample';
|
|
37
|
+
export { default as ProtocolUcpCheckoutExample } from './ProtocolUcpCheckoutExample';
|
|
36
38
|
export { default as PapCompanyDiscoveryExample } from './PapCompanyDiscoveryExample';
|
|
37
39
|
export { default as PapAgentIdentityExample } from './PapAgentIdentityExample';
|
|
38
40
|
export { default as PapAuthorizationBoundaryExample } from './PapAuthorizationBoundaryExample';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The *Signed requests* gallery example's work (AGENT_PROTOCOLS EX-10): a
|
|
3
|
+
* fresh Ed25519 key generated in the page, one request signed with it
|
|
4
|
+
* (`signRequest`), the three headers and the signature base the signer was
|
|
5
|
+
* handed, then the request verified against the key's directory — and the
|
|
6
|
+
* same request replayed, and one with its path changed, both refused.
|
|
7
|
+
*
|
|
8
|
+
* The key never leaves the page and is never shown: only its public JWK and
|
|
9
|
+
* thumbprint are. No network: the directory is read from memory.
|
|
10
|
+
*
|
|
11
|
+
* @module examples/protocols/signedRequestsDemo
|
|
12
|
+
*/
|
|
13
|
+
import { type PublicJwk, type SignedHeaders, type Verification } from '../../protocols/web-bot-auth';
|
|
14
|
+
export interface SignedRequestDemo {
|
|
15
|
+
/** The key's thumbprint, the `keyid` of the signature. */
|
|
16
|
+
keyid: string;
|
|
17
|
+
publicJwk: PublicJwk;
|
|
18
|
+
url: string;
|
|
19
|
+
headers: SignedHeaders;
|
|
20
|
+
/** The signature base, exactly as the signer signed it. */
|
|
21
|
+
base: string;
|
|
22
|
+
verified: Verification;
|
|
23
|
+
replayed: Verification;
|
|
24
|
+
tampered: Verification;
|
|
25
|
+
}
|
|
26
|
+
/** Sign one request with a fresh key, and verify it three ways. */
|
|
27
|
+
export declare function signedRequestDemo(url?: string, agent?: string): Promise<SignedRequestDemo>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The *Signed requests* gallery example's work (AGENT_PROTOCOLS EX-10): a
|
|
7
|
+
* fresh Ed25519 key generated in the page, one request signed with it
|
|
8
|
+
* (`signRequest`), the three headers and the signature base the signer was
|
|
9
|
+
* handed, then the request verified against the key's directory — and the
|
|
10
|
+
* same request replayed, and one with its path changed, both refused.
|
|
11
|
+
*
|
|
12
|
+
* The key never leaves the page and is never shown: only its public JWK and
|
|
13
|
+
* thumbprint are. No network: the directory is read from memory.
|
|
14
|
+
*
|
|
15
|
+
* @module examples/protocols/signedRequestsDemo
|
|
16
|
+
*/
|
|
17
|
+
import { InMemoryNonceStore, generateLocalSigner, keyResolver, signRequest, verifyRequest, } from '../../protocols/web-bot-auth';
|
|
18
|
+
/** A signer that keeps what it was asked to sign: the signature base. */
|
|
19
|
+
function recording(signer) {
|
|
20
|
+
const bases = [];
|
|
21
|
+
return {
|
|
22
|
+
keyid: signer.keyid,
|
|
23
|
+
algorithm: signer.algorithm,
|
|
24
|
+
bases,
|
|
25
|
+
async sign(data) {
|
|
26
|
+
bases.push(new TextDecoder().decode(data));
|
|
27
|
+
return signer.sign(data);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Sign one request with a fresh key, and verify it three ways. */
|
|
32
|
+
export async function signedRequestDemo(url = 'https://shop.example/products?q=tea', agent = 'https://agent.example') {
|
|
33
|
+
const { signer, publicJwk } = await generateLocalSigner();
|
|
34
|
+
const keeping = recording(signer);
|
|
35
|
+
const headers = await signRequest(new Request(url), keeping, { agent });
|
|
36
|
+
// The shop finds the agent's keys in its directory: here, in memory.
|
|
37
|
+
const resolver = keyResolver({
|
|
38
|
+
directory: { keys: async () => [publicJwk] },
|
|
39
|
+
});
|
|
40
|
+
const nonceStore = new InMemoryNonceStore();
|
|
41
|
+
const sent = (to) => new Request(to, { headers: { ...headers } });
|
|
42
|
+
const verified = await verifyRequest(sent(url), resolver, { nonceStore });
|
|
43
|
+
const replayed = await verifyRequest(sent(url), resolver, { nonceStore });
|
|
44
|
+
const changed = new URL(url);
|
|
45
|
+
changed.pathname = '/checkout';
|
|
46
|
+
const tampered = await verifyRequest(sent(changed.toString()), resolver, {
|
|
47
|
+
nonceStore: new InMemoryNonceStore(),
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
keyid: signer.keyid,
|
|
51
|
+
publicJwk,
|
|
52
|
+
url,
|
|
53
|
+
headers,
|
|
54
|
+
base: keeping.bases[0] ?? '',
|
|
55
|
+
verified,
|
|
56
|
+
replayed,
|
|
57
|
+
tampered,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The *UCP checkout* gallery example's work (AGENT_PROTOCOLS EX-10, after
|
|
3
|
+
* EX-04): the UCP client buying from *Example Store*, the local test
|
|
4
|
+
* merchant running in the page (`protocols/ucp/merchant`). A checkout is
|
|
5
|
+
* proposed as an exact, revisioned purchase; completing it asks the host's
|
|
6
|
+
* approver — the page's card — once, and the proposal is spent whatever the
|
|
7
|
+
* answer. The payment is the test handler's; its token is never shown.
|
|
8
|
+
*
|
|
9
|
+
* @module examples/protocols/ucpCheckoutDemo
|
|
10
|
+
*/
|
|
11
|
+
import { type ReactorPlatform } from '@datalayer/reactor';
|
|
12
|
+
import { UcpClient, type CheckoutProposal } from '../../protocols/ucp';
|
|
13
|
+
export declare const STORE = "https://store.example";
|
|
14
|
+
export declare const AGENT_PROFILE = "https://agent.example/.well-known/ucp";
|
|
15
|
+
/** The test payment's token: held by the host, never in a summary or a proposal. */
|
|
16
|
+
export declare const TEST_TOKEN = "tok_test_gallery_never_shown";
|
|
17
|
+
export interface UcpCheckoutDemo {
|
|
18
|
+
client: UcpClient;
|
|
19
|
+
reactor: ReactorPlatform;
|
|
20
|
+
orders: Array<{
|
|
21
|
+
order: string;
|
|
22
|
+
checkout: string;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
/** The client, the store, and a host whose approver is `decide`. */
|
|
26
|
+
export declare function ucpCheckoutDemo(decide: (proposal: CheckoutProposal) => Promise<boolean>): UcpCheckoutDemo;
|
|
27
|
+
/** Find the tea, put `quantity` in a checkout with the buyer's email, and propose it. */
|
|
28
|
+
export declare function proposeTea(demo: UcpCheckoutDemo, quantity?: number, email?: string): Promise<{
|
|
29
|
+
proposal: CheckoutProposal;
|
|
30
|
+
says: string;
|
|
31
|
+
}>;
|
|
32
|
+
/** Complete the proposal: the approver is asked; the order, or why not. */
|
|
33
|
+
export declare function buy(demo: UcpCheckoutDemo, proposal: CheckoutProposal): Promise<{
|
|
34
|
+
ok: boolean;
|
|
35
|
+
says: string;
|
|
36
|
+
}>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The *UCP checkout* gallery example's work (AGENT_PROTOCOLS EX-10, after
|
|
7
|
+
* EX-04): the UCP client buying from *Example Store*, the local test
|
|
8
|
+
* merchant running in the page (`protocols/ucp/merchant`). A checkout is
|
|
9
|
+
* proposed as an exact, revisioned purchase; completing it asks the host's
|
|
10
|
+
* approver — the page's card — once, and the proposal is spent whatever the
|
|
11
|
+
* answer. The payment is the test handler's; its token is never shown.
|
|
12
|
+
*
|
|
13
|
+
* @module examples/protocols/ucpCheckoutDemo
|
|
14
|
+
*/
|
|
15
|
+
import { contribution, definePlugin, } from '@datalayer/reactor';
|
|
16
|
+
import { buildProtocolsReactor } from '../../protocols/agentProtocols';
|
|
17
|
+
import { UcpApprovers, UcpClient, UcpPaymentInstruments, checkoutSummary, proposalSummary, } from '../../protocols/ucp';
|
|
18
|
+
import { EXAMPLE_STORE_HANDLER_ID, exampleStore, } from '../../protocols/ucp/merchant';
|
|
19
|
+
export const STORE = 'https://store.example';
|
|
20
|
+
export const AGENT_PROFILE = 'https://agent.example/.well-known/ucp';
|
|
21
|
+
/** The test payment's token: held by the host, never in a summary or a proposal. */
|
|
22
|
+
export const TEST_TOKEN = 'tok_test_gallery_never_shown';
|
|
23
|
+
/** The client, the store, and a host whose approver is `decide`. */
|
|
24
|
+
export function ucpCheckoutDemo(decide) {
|
|
25
|
+
const store = exampleStore(STORE);
|
|
26
|
+
const host = definePlugin({
|
|
27
|
+
name: 'gallery-host',
|
|
28
|
+
contributes: [
|
|
29
|
+
contribution(UcpApprovers, { approve: decide }, { id: 'person', order: 10 }),
|
|
30
|
+
contribution(UcpPaymentInstruments, {
|
|
31
|
+
instrument: async () => ({
|
|
32
|
+
id: 'pi_1',
|
|
33
|
+
handler_id: EXAMPLE_STORE_HANDLER_ID,
|
|
34
|
+
type: 'card',
|
|
35
|
+
credential: { type: 'PAYMENT_GATEWAY', token: TEST_TOKEN },
|
|
36
|
+
}),
|
|
37
|
+
}, { id: 'custody', order: 10 }),
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
client: new UcpClient(STORE, AGENT_PROFILE, store.fetch),
|
|
42
|
+
reactor: buildProtocolsReactor([host]),
|
|
43
|
+
orders: store.orders,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Find the tea, put `quantity` in a checkout with the buyer's email, and propose it. */
|
|
47
|
+
export async function proposeTea(demo, quantity = 2, email = 'ana@example.com') {
|
|
48
|
+
const [product] = await demo.client.search('sencha');
|
|
49
|
+
const created = await demo.client.createCheckout([
|
|
50
|
+
{ id: product.id, quantity },
|
|
51
|
+
]);
|
|
52
|
+
await demo.client.updateCheckout(created.id, { buyer: { email } });
|
|
53
|
+
const proposal = await demo.client.proposeCompletion(created.id);
|
|
54
|
+
return { proposal, says: proposalSummary(proposal) };
|
|
55
|
+
}
|
|
56
|
+
/** Complete the proposal: the approver is asked; the order, or why not. */
|
|
57
|
+
export async function buy(demo, proposal) {
|
|
58
|
+
try {
|
|
59
|
+
const done = checkoutSummary(await demo.client.complete(proposal, demo.reactor));
|
|
60
|
+
return {
|
|
61
|
+
ok: true,
|
|
62
|
+
says: `Bought: order ${done.order?.id}, ${done.status}.`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return { ok: false, says: `Not bought: ${error.message}.` };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -7,6 +7,8 @@ import type { ProtocolAdapterConfig } from '../types';
|
|
|
7
7
|
import type { ChatMessage } from '../types/messages';
|
|
8
8
|
import type { ToolDefinition, ToolExecutionResult } from '../types/tools';
|
|
9
9
|
import { BaseProtocolAdapter } from './BaseProtocolAdapter';
|
|
10
|
+
/** What the page says when a run's stream closes before the run said how it ended. */
|
|
11
|
+
export declare const RUN_CUT_SHORT = "The run stopped before it finished, without an answer or an error: send it again.";
|
|
10
12
|
/**
|
|
11
13
|
* AG-UI specific configuration
|
|
12
14
|
*/
|
|
@@ -110,6 +112,11 @@ export declare class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
110
112
|
* Parse SSE stream from AG-UI response
|
|
111
113
|
*/
|
|
112
114
|
private parseSSEStream;
|
|
115
|
+
/**
|
|
116
|
+
* A `reactor.ui` op on the run stream: refused, and said as an error. The
|
|
117
|
+
* ops come over the conversation's ui socket (REACTOR_UI RU-W).
|
|
118
|
+
*/
|
|
119
|
+
private refuseUiOnRun;
|
|
113
120
|
/**
|
|
114
121
|
* Handle individual AG-UI events
|
|
115
122
|
*
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
import { generateMessageId, createAssistantMessage } from '../types/messages';
|
|
6
6
|
import { agUiRefusal, refusalBody } from './agUiRefusal';
|
|
7
7
|
import { BaseProtocolAdapter } from './BaseProtocolAdapter';
|
|
8
|
+
import { AGUI_NAME } from '@datalayer/reactor/ui';
|
|
9
|
+
/** What the page says when a run's stream closes before the run said how it ended. */
|
|
10
|
+
export const RUN_CUT_SHORT = 'The run stopped before it finished, without an answer or an error: send it again.';
|
|
8
11
|
/**
|
|
9
12
|
* AG-UI protocol adapter
|
|
10
13
|
* Uses HTTP POST with SSE streaming for responses
|
|
@@ -426,11 +429,20 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
426
429
|
});
|
|
427
430
|
}
|
|
428
431
|
this._streamParsingDepth++;
|
|
432
|
+
// Whether the run said how it ended. A stream that closes without
|
|
433
|
+
// RUN_FINISHED or RUN_ERROR is a run cut short — by the runtime, a proxy
|
|
434
|
+
// or the network — and the page says so instead of waiting for an answer
|
|
435
|
+
// that is not coming (a Preview gave no answer for minutes, 2026-10-12).
|
|
436
|
+
let ended = false;
|
|
429
437
|
try {
|
|
430
438
|
while (true) {
|
|
431
439
|
const { done, value } = await reader.read();
|
|
432
|
-
if (done)
|
|
440
|
+
if (done) {
|
|
441
|
+
if (!ended) {
|
|
442
|
+
throw new Error(RUN_CUT_SHORT);
|
|
443
|
+
}
|
|
433
444
|
break;
|
|
445
|
+
}
|
|
434
446
|
buffer += decoder.decode(value, { stream: true });
|
|
435
447
|
const lines = buffer.split('\n');
|
|
436
448
|
buffer = lines.pop() || '';
|
|
@@ -444,6 +456,10 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
444
456
|
const data = line.slice(6);
|
|
445
457
|
try {
|
|
446
458
|
const event = JSON.parse(data);
|
|
459
|
+
const kind = event.type;
|
|
460
|
+
if (kind === 'RUN_FINISHED' || kind === 'RUN_ERROR') {
|
|
461
|
+
ended = true;
|
|
462
|
+
}
|
|
447
463
|
this.handleAGUIEvent(event, {
|
|
448
464
|
getCurrentMessageId: () => currentMessageId,
|
|
449
465
|
setCurrentMessageId: id => {
|
|
@@ -483,6 +499,17 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
483
499
|
}
|
|
484
500
|
}
|
|
485
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* A `reactor.ui` op on the run stream: refused, and said as an error. The
|
|
504
|
+
* ops come over the conversation's ui socket (REACTOR_UI RU-W).
|
|
505
|
+
*/
|
|
506
|
+
refuseUiOnRun() {
|
|
507
|
+
this.emit({
|
|
508
|
+
type: 'error',
|
|
509
|
+
error: new Error('A reactor.ui op came on the run stream: it comes over the ui socket (REACTOR_UI RU-W).'),
|
|
510
|
+
timestamp: new Date(),
|
|
511
|
+
});
|
|
512
|
+
}
|
|
486
513
|
/**
|
|
487
514
|
* Handle individual AG-UI events
|
|
488
515
|
*
|
|
@@ -684,14 +711,27 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
684
711
|
});
|
|
685
712
|
break;
|
|
686
713
|
}
|
|
714
|
+
case 'ACTIVITY_SNAPSHOT':
|
|
715
|
+
case 'ACTIVITY_DELTA': {
|
|
716
|
+
// `reactor.ui` ops come over the conversation's ui socket, never
|
|
717
|
+
// the run stream (REACTOR_UI RU-W): one here is refused. Any other
|
|
718
|
+
// activity is nobody's here.
|
|
719
|
+
if (event.activityType === AGUI_NAME) {
|
|
720
|
+
this.refuseUiOnRun();
|
|
721
|
+
}
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
687
724
|
case 'CUSTOM': {
|
|
688
725
|
const name = event.name;
|
|
689
|
-
|
|
726
|
+
if (name === AGUI_NAME) {
|
|
727
|
+
this.refuseUiOnRun();
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
690
730
|
this.emit({
|
|
691
731
|
type: 'activity',
|
|
692
732
|
activity: {
|
|
693
733
|
type: name || 'custom',
|
|
694
|
-
data: value,
|
|
734
|
+
data: event.value,
|
|
695
735
|
},
|
|
696
736
|
timestamp: new Date(),
|
|
697
737
|
});
|
|
@@ -56,6 +56,7 @@ export const A2APlugin = definePlugin({
|
|
|
56
56
|
status: 'implemented',
|
|
57
57
|
specification: 'https://a2a-protocol.org/latest/specification/',
|
|
58
58
|
plugin: A2A_PLUGIN,
|
|
59
|
+
catalogue: 'a2a',
|
|
59
60
|
points: EXTENSION_POINTS.map(point => point.id),
|
|
60
61
|
}, { id: 'a2a', order: DEFAULT_ORDER }),
|
|
61
62
|
contribution(A2AOrchestrationExtensions, orchestration, {
|
|
@@ -59,6 +59,7 @@ export const AgenticCommercePlugin = definePlugin({
|
|
|
59
59
|
status: 'partial',
|
|
60
60
|
specification: `https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/tree/main/spec/${AGENTIC_COMMERCE_VERSION}`,
|
|
61
61
|
plugin: AGENTIC_COMMERCE_PLUGIN,
|
|
62
|
+
catalogue: 'acp',
|
|
62
63
|
points: POINTS.map(point => point.id),
|
|
63
64
|
}, { id: 'agentic_commerce', order: DEFAULT_ORDER }),
|
|
64
65
|
],
|
package/lib/protocols/core.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ export interface ProtocolDescription {
|
|
|
26
26
|
status: 'implemented' | 'partial' | 'planned';
|
|
27
27
|
specification: string;
|
|
28
28
|
plugin: string;
|
|
29
|
+
/**
|
|
30
|
+
* Its id in the agentspecs protocols catalogue (`agentspecs/protocols`,
|
|
31
|
+
* AGENT_PROTOCOLS PS-01): `web-bot-auth`, `acp`… — how Studio reads a
|
|
32
|
+
* runtime's answer against the catalogue (PR-50).
|
|
33
|
+
*/
|
|
34
|
+
catalogue: string;
|
|
29
35
|
/** The contribution points its plugin declares, its extensions' included. */
|
|
30
36
|
points: string[];
|
|
31
37
|
}
|
|
@@ -69,6 +69,7 @@ export const PactPlugin = definePlugin({
|
|
|
69
69
|
status: 'partial',
|
|
70
70
|
specification: 'https://github.com/openpactprotocol/openpactprotocol/blob/main/docs/spec.md',
|
|
71
71
|
plugin: PACT_PLUGIN,
|
|
72
|
+
catalogue: 'pact',
|
|
72
73
|
points: POINTS.map(point => point.id),
|
|
73
74
|
}, { id: 'pact', order: DEFAULT_ORDER }),
|
|
74
75
|
contribution(PactDelegatedProfiles, { grantType: DEVICE_CODE_GRANT }, { id: 'device-code', order: DEFAULT_ORDER }),
|
|
@@ -64,6 +64,7 @@ export const UcpPlugin = definePlugin({
|
|
|
64
64
|
status: 'partial',
|
|
65
65
|
specification: `https://ucp.dev/${UCP_VERSION}/specification/overview`,
|
|
66
66
|
plugin: UCP_PLUGIN,
|
|
67
|
+
catalogue: 'ucp',
|
|
67
68
|
points: UCP_POINTS.map(point => point.id),
|
|
68
69
|
}, { id: 'ucp', order: DEFAULT_ORDER }),
|
|
69
70
|
],
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** The store's products, as the Python store lists them. */
|
|
2
|
+
export declare const EXAMPLE_STORE_CATALOG: Record<string, {
|
|
3
|
+
title: string;
|
|
4
|
+
price: number;
|
|
5
|
+
}>;
|
|
6
|
+
/** The one payment handler it takes, and the prefix of its test tokens. */
|
|
7
|
+
export declare const EXAMPLE_STORE_HANDLER_ID = "test_pay_1";
|
|
8
|
+
/** The store: its `fetch`, and the orders it took. */
|
|
9
|
+
export declare function exampleStore(base?: string): {
|
|
10
|
+
fetch: typeof fetch;
|
|
11
|
+
orders: Array<{
|
|
12
|
+
order: string;
|
|
13
|
+
checkout: string;
|
|
14
|
+
}>;
|
|
15
|
+
};
|