@datalayer/agent-runtimes 1.3.104 → 1.3.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-embed/datalayer-app-main.js +82 -2
- package/lib/apps/apps/appspec.js +17 -0
- package/lib/apps/apps/checks.js +4 -0
- package/lib/apps/plugins/pap-example/index.d.ts +23 -0
- package/lib/apps/plugins/pap-example/index.js +25 -0
- package/lib/components/inspector/a2aSpans.js +8 -1
- package/lib/components/teams/SceneTranscript.js +8 -3
- package/lib/examples/PapAgentIdentityExample.d.ts +4 -0
- package/lib/examples/PapAgentIdentityExample.js +23 -0
- package/lib/examples/PapAuthorizationBoundaryExample.d.ts +4 -0
- package/lib/examples/PapAuthorizationBoundaryExample.js +23 -0
- package/lib/examples/PapCompanyDiscoveryExample.d.ts +4 -0
- package/lib/examples/PapCompanyDiscoveryExample.js +23 -0
- package/lib/examples/PapDpopProofExample.d.ts +4 -0
- package/lib/examples/PapDpopProofExample.js +23 -0
- package/lib/examples/PapGuidedJourneyExample.d.ts +4 -0
- package/lib/examples/PapGuidedJourneyExample.js +23 -0
- package/lib/examples/PapSessionLifecycleExample.d.ts +4 -0
- package/lib/examples/PapSessionLifecycleExample.js +23 -0
- package/lib/examples/example-selector.js +9 -0
- package/lib/examples/exampleGroups.d.ts +1 -1
- package/lib/examples/exampleGroups.js +3 -0
- package/lib/examples/index.d.ts +6 -0
- package/lib/examples/index.js +6 -0
- package/lib/examples/main.js +9 -0
- package/lib/examples/pap/PapAgentIdentityView.d.ts +4 -0
- package/lib/examples/pap/PapAgentIdentityView.js +55 -0
- package/lib/examples/pap/PapAuthorizationBoundaryView.d.ts +4 -0
- package/lib/examples/pap/PapAuthorizationBoundaryView.js +59 -0
- package/lib/examples/pap/PapCompanyDiscoveryView.d.ts +4 -0
- package/lib/examples/pap/PapCompanyDiscoveryView.js +62 -0
- package/lib/examples/pap/PapDpopProofView.d.ts +4 -0
- package/lib/examples/pap/PapDpopProofView.js +57 -0
- package/lib/examples/pap/PapExamplePage.d.ts +14 -0
- package/lib/examples/pap/PapExamplePage.js +6 -0
- package/lib/examples/pap/PapGuidedJourneyView.d.ts +4 -0
- package/lib/examples/pap/PapGuidedJourneyView.js +263 -0
- package/lib/examples/pap/PapSessionLifecycleView.d.ts +4 -0
- package/lib/examples/pap/PapSessionLifecycleView.js +103 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/pap/index.d.ts +42 -0
- package/lib/pap/index.js +57 -0
- package/lib/specs/apps.js +76 -15
- package/lib/specs/appspecSchema.js +27 -0
- package/lib/types/agentspecs.d.ts +12 -0
- package/package.json +2 -1
- package/scripts/codegen/generate_apps.py +3 -0
- package/scripts/validate_pap_examples.py +44 -0
package/lib/apps/apps/appspec.js
CHANGED
|
@@ -694,6 +694,15 @@ export function parseAppspec(document) {
|
|
|
694
694
|
expect: text(testCase.expect),
|
|
695
695
|
// Decided by its code (LOOP P-06), when it names the function.
|
|
696
696
|
...(text(testCase.code) ? { code: text(testCase.code) } : {}),
|
|
697
|
+
// Given files with what it is asked, when it is.
|
|
698
|
+
...(records(testCase.files).length
|
|
699
|
+
? {
|
|
700
|
+
files: records(testCase.files).map(file => ({
|
|
701
|
+
name: text(file.name),
|
|
702
|
+
text: text(file.text),
|
|
703
|
+
})),
|
|
704
|
+
}
|
|
705
|
+
: {}),
|
|
697
706
|
})),
|
|
698
707
|
verified: {
|
|
699
708
|
live: texts(verified.live),
|
|
@@ -1012,6 +1021,14 @@ export function dumpAppspec(app) {
|
|
|
1012
1021
|
ask: testCase.ask,
|
|
1013
1022
|
expect: testCase.expect,
|
|
1014
1023
|
...(testCase.code ? { code: testCase.code } : {}),
|
|
1024
|
+
...(testCase.files?.length
|
|
1025
|
+
? {
|
|
1026
|
+
files: testCase.files.map(file => ({
|
|
1027
|
+
name: file.name,
|
|
1028
|
+
text: file.text,
|
|
1029
|
+
})),
|
|
1030
|
+
}
|
|
1031
|
+
: {}),
|
|
1015
1032
|
})))
|
|
1016
1033
|
.part('verified', new Writer()
|
|
1017
1034
|
.list('live', app.tests.verified.live)
|
package/lib/apps/apps/checks.js
CHANGED
|
@@ -1033,6 +1033,10 @@ export function documentShapeProblems(document) {
|
|
|
1033
1033
|
records(tests.cases, 'tests.cases', (item, where) => {
|
|
1034
1034
|
required(item, 'ask', where);
|
|
1035
1035
|
required(item, 'expect', where);
|
|
1036
|
+
records(item.files, `${where}.files`, (file, at) => {
|
|
1037
|
+
required(file, 'name', at);
|
|
1038
|
+
required(file, 'text', at);
|
|
1039
|
+
});
|
|
1036
1040
|
});
|
|
1037
1041
|
});
|
|
1038
1042
|
mapping(d.record, 'record', record => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mould for Personal Agent Protocol gallery examples.
|
|
3
|
+
*
|
|
4
|
+
* Each example is a Reactor plugin contributing one lazy workspace view. PAP
|
|
5
|
+
* therefore enters the Loop through the same extension boundary as A2A,
|
|
6
|
+
* A2UI, editors and runtime capacities—not through a page-specific switch.
|
|
7
|
+
*
|
|
8
|
+
* @module apps/plugins/pap-example
|
|
9
|
+
*/
|
|
10
|
+
import type { ComponentType } from 'react';
|
|
11
|
+
import { type ReactorPlugin } from '@datalayer/reactor';
|
|
12
|
+
import { type LoopViewProps } from '../../core';
|
|
13
|
+
export type PapExamplePluginOptions = {
|
|
14
|
+
key: string;
|
|
15
|
+
title: string;
|
|
16
|
+
description: string;
|
|
17
|
+
load: () => Promise<{
|
|
18
|
+
default: ComponentType<LoopViewProps>;
|
|
19
|
+
}>;
|
|
20
|
+
};
|
|
21
|
+
/** Define one PAP workspace view as a Reactor plugin. */
|
|
22
|
+
export declare function definePapExamplePlugin(options: PapExamplePluginOptions): ReactorPlugin<Record<string, never>, unknown, unknown>;
|
|
23
|
+
export default definePapExamplePlugin;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { contribution, definePlugin, } from '@datalayer/reactor';
|
|
6
|
+
import { LoopViewType } from '../../core';
|
|
7
|
+
/** Define one PAP workspace view as a Reactor plugin. */
|
|
8
|
+
export function definePapExamplePlugin(options) {
|
|
9
|
+
return definePlugin({
|
|
10
|
+
name: `@datalayer/loop-plugin-pap-example-${options.key}`,
|
|
11
|
+
displayName: options.title,
|
|
12
|
+
description: options.description,
|
|
13
|
+
octicon: 'shield-lock',
|
|
14
|
+
emoji: '🔐',
|
|
15
|
+
contributes: [
|
|
16
|
+
contribution(LoopViewType, {
|
|
17
|
+
viewType: `pap-example-${options.key}`,
|
|
18
|
+
title: options.title,
|
|
19
|
+
order: -10,
|
|
20
|
+
load: options.load,
|
|
21
|
+
}, { id: `pap-example-${options.key}`, order: -10 }),
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export default definePapExamplePlugin;
|
|
@@ -63,6 +63,11 @@ export function pressedAction(message) {
|
|
|
63
63
|
}
|
|
64
64
|
const FAILED_STATES = /FAILED|REJECTED|CANCELED/;
|
|
65
65
|
/** Records what came back for one request onto its span. */
|
|
66
|
+
/** A text cut at `length` characters, its line breaks kept. */
|
|
67
|
+
function clipped(text, length) {
|
|
68
|
+
const trimmed = text.trim();
|
|
69
|
+
return trimmed.length > length ? `${trimmed.slice(0, length - 1)}…` : trimmed;
|
|
70
|
+
}
|
|
66
71
|
class ResponseRecorder {
|
|
67
72
|
options;
|
|
68
73
|
span;
|
|
@@ -217,7 +222,9 @@ class ResponseRecorder {
|
|
|
217
222
|
this.span.addEvent('a2a.artifact_update', {
|
|
218
223
|
...chunk.attributes,
|
|
219
224
|
'a2a.artifact.chunks': chunk.events.length,
|
|
220
|
-
|
|
225
|
+
// Its words as they came — a table's rows, a list's lines — cut at
|
|
226
|
+
// 2000 characters, not run into one line: the transcript draws them.
|
|
227
|
+
'a2a.message.text': chunk.text ? clipped(chunk.text, 2000) : undefined,
|
|
221
228
|
'a2a.event': jsonAttribute(chunk.events.length === 1 ? chunk.events[0] : chunk.events),
|
|
222
229
|
});
|
|
223
230
|
}
|
|
@@ -3,6 +3,7 @@ import { useMemo, useState } from 'react';
|
|
|
3
3
|
import { Button, Text } from '@primer/react';
|
|
4
4
|
import { Box } from '@datalayer/primer-addons';
|
|
5
5
|
import { useOtelLiveSpans } from '@datalayer/core/lib/otel/live';
|
|
6
|
+
import { ChatMarkdown } from '../../chat/messages/ChatMarkdown';
|
|
6
7
|
import { lineHeading, timeText, transcriptOfSpans, transcriptText, } from './sceneTranscript';
|
|
7
8
|
/** The transcript of a tracer's spans, kept current as they change. */
|
|
8
9
|
export function useSceneTranscript(tracer, members) {
|
|
@@ -32,9 +33,13 @@ export function SceneTranscript({ lines, emptyText = 'What the scene says and do
|
|
|
32
33
|
fontSize: 0,
|
|
33
34
|
pt: '2px',
|
|
34
35
|
whiteSpace: 'nowrap',
|
|
35
|
-
}, dateTime: new Date(line.at).toISOString(), children: timeText(line.at) }), _jsxs(Box, { minWidth: 0, overflowWrap: "anywhere", children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsxs(Text, { sx: {
|
|
36
|
-
fontFamily:
|
|
36
|
+
}, dateTime: new Date(line.at).toISOString(), children: timeText(line.at) }), line.kind === 'called' ? (_jsxs(Box, { minWidth: 0, overflowWrap: "anywhere", children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsxs(Text, { sx: {
|
|
37
|
+
fontFamily: 'mono',
|
|
37
38
|
color: line.failed ? 'danger.fg' : undefined,
|
|
38
|
-
}, children: [line.text, line.open ? '…' : '', line.failed ? ' (failed)' : ''] })] })
|
|
39
|
+
}, children: [line.text, line.open ? '…' : '', line.failed ? ' (failed)' : ''] })] })) : (
|
|
40
|
+
// Words, drawn as the chat draws a message (`ChatMarkdown`):
|
|
41
|
+
// a table, a list or a code block an answer gives reads as
|
|
42
|
+
// one, not as its markdown run into one line (2026-10-10).
|
|
43
|
+
_jsxs(Box, { minWidth: 0, overflowWrap: "anywhere", children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsx(Box, { sx: { color: line.failed ? 'danger.fg' : undefined }, children: _jsx(ChatMarkdown, { text: `${line.text}${line.open ? '…' : ''}${line.failed ? ' (failed)' : ''}`, density: "compact" }) })] }))] }, line.key))) })), copy && lines.length > 0 && (_jsx(Box, { mt: 2, children: _jsx(Button, { size: "small", onClick: () => void onCopy(), "data-transcript-copy": "", children: copied ? 'Copied' : 'Copy as text' }) }))] }));
|
|
39
44
|
}
|
|
40
45
|
export default SceneTranscript;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** PAP personal-agent identity mounted as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapIdentityPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'agent-identity',
|
|
15
|
+
title: 'PAP Agent Identity',
|
|
16
|
+
description: 'Verified client and signing policy without JWK coordinates.',
|
|
17
|
+
load: () => import('./pap/PapAgentIdentityView'),
|
|
18
|
+
});
|
|
19
|
+
const PapAgentIdentityExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapIdentityPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapAgentIdentityExample;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** PAP Session and Direct Sign-In boundaries as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapAuthorizationPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'authorization-boundary',
|
|
15
|
+
title: 'PAP Authorization Boundary',
|
|
16
|
+
description: 'Real Session and PKCE material kept outside model context.',
|
|
17
|
+
load: () => import('./pap/PapAuthorizationBoundaryView'),
|
|
18
|
+
});
|
|
19
|
+
const PapAuthorizationBoundaryExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapAuthorizationPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapAuthorizationBoundaryExample;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** PAP company discovery mounted as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapCompanyPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'company-discovery',
|
|
15
|
+
title: 'PAP Company Discovery',
|
|
16
|
+
description: 'Verified company metadata reduced to a model-safe summary.',
|
|
17
|
+
load: () => import('./pap/PapCompanyDiscoveryView'),
|
|
18
|
+
});
|
|
19
|
+
const PapCompanyDiscoveryExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapCompanyPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapCompanyDiscoveryExample;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** PAP DPoP proof creation mounted as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapDpopPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'dpop-proof',
|
|
15
|
+
title: 'PAP DPoP Proof',
|
|
16
|
+
description: 'Fresh request-bound proofs kept outside model and UI state.',
|
|
17
|
+
load: () => import('./pap/PapDpopProofView'),
|
|
18
|
+
});
|
|
19
|
+
const PapDpopProofExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapDpopPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapDpopProofExample;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** A narrative PAP interaction mounted as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapJourneyPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'guided-journey',
|
|
15
|
+
title: 'PAP Guided Journey',
|
|
16
|
+
description: 'A visual return journey across discovery, sign-in, and action.',
|
|
17
|
+
load: () => import('./pap/PapGuidedJourneyView'),
|
|
18
|
+
});
|
|
19
|
+
const PapGuidedJourneyExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapJourneyPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapGuidedJourneyExample;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/** PAP signed-out Session lifecycle mounted as a Reactor workspace plugin. */
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
9
|
+
import { LoopEmbed } from '../apps';
|
|
10
|
+
import { definePapExamplePlugin } from '../apps/plugins/pap-example';
|
|
11
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
12
|
+
setupPrimerPortals();
|
|
13
|
+
const PapSessionPlugin = definePapExamplePlugin({
|
|
14
|
+
key: 'session-lifecycle',
|
|
15
|
+
title: 'PAP Session Lifecycle',
|
|
16
|
+
description: 'Start, nonce retry, and renewal with credentials host-owned.',
|
|
17
|
+
load: () => import('./pap/PapSessionLifecycleView'),
|
|
18
|
+
});
|
|
19
|
+
const PapSessionLifecycleExample = () => {
|
|
20
|
+
const plugins = useMemo(() => [PapSessionPlugin], []);
|
|
21
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { height: "100vh", minHeight: 0, children: _jsx(LoopEmbed, { target: "browser", agentId: "loop-shell", defaultEditor: "none", showHeader: true, plugins: plugins }) }) }));
|
|
22
|
+
};
|
|
23
|
+
export default PapSessionLifecycleExample;
|
|
@@ -7,6 +7,7 @@ const DISPLAY_NAME_EXCEPTIONS = [
|
|
|
7
7
|
[/\bAg Ui\b/g, 'AG-UI'],
|
|
8
8
|
[/\bA2 Ui\b/g, 'A2UI'],
|
|
9
9
|
[/\bA2 A\b/g, 'A2A'],
|
|
10
|
+
[/\bPap\b/g, 'PAP'],
|
|
10
11
|
[/\bCopilot Kit\b/g, 'CopilotKit'],
|
|
11
12
|
[/\bGen Ui\b/g, 'Gen UI'],
|
|
12
13
|
[/\bM C P\b/g, 'MCP'],
|
|
@@ -37,6 +38,8 @@ function inferTags(id) {
|
|
|
37
38
|
tags.add('a2ui');
|
|
38
39
|
if (id.startsWith('AgentA2A'))
|
|
39
40
|
tags.add('a2a');
|
|
41
|
+
if (id.startsWith('Pap'))
|
|
42
|
+
tags.add('pap');
|
|
40
43
|
if (id.includes('Notebook'))
|
|
41
44
|
tags.add('notebook');
|
|
42
45
|
if (id.includes('Lexical') || id.includes('Document'))
|
|
@@ -128,6 +131,12 @@ export const EXAMPLE_ENTRIES = [
|
|
|
128
131
|
makeEntry('AgentSubagentsExample', () => import('./AgentSubagentsExample'), 'Multi-agent delegation with the in-repo subagents capability.'),
|
|
129
132
|
makeEntry('AgentA2AExample', () => import('./AgentA2AExample'), 'Delegation to separate agents over the A2A protocol, launched locally or on Datalayer runtimes.'),
|
|
130
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('PapCompanyDiscoveryExample', () => import('./PapCompanyDiscoveryExample'), 'Validate a PAP company document and reduce it to the public capabilities safe for an agent or UI.'),
|
|
135
|
+
makeEntry('PapAgentIdentityExample', () => import('./PapAgentIdentityExample'), 'Verify personal-agent client metadata and signing policy without exposing JWK coordinates.'),
|
|
136
|
+
makeEntry('PapAuthorizationBoundaryExample', () => import('./PapAuthorizationBoundaryExample'), 'Generate real Session and Direct Sign-In security material while showing only safe policy status.'),
|
|
137
|
+
makeEntry('PapDpopProofExample', () => import('./PapDpopProofExample'), 'Create fresh request-bound DPoP proofs while withholding proof, token, nonce, identifiers, and key material.'),
|
|
138
|
+
makeEntry('PapSessionLifecycleExample', () => import('./PapSessionLifecycleExample'), 'Start, retry, and renew a signed-out PAP Session while credentials remain host-owned.'),
|
|
139
|
+
makeEntry('PapGuidedJourneyExample', () => import('./PapGuidedJourneyExample'), 'Follow a visual PAP return journey across discovery, signed-out conversation, Direct Sign-In, and an exact user-authorized result.'),
|
|
131
140
|
makeEntry('AgentNotificationsExample', () => import('./AgentNotificationsExample'), 'Notifications and event routing example.'),
|
|
132
141
|
makeEntry('AgentOutputsExample', () => import('./AgentOutputsExample'), 'Structured outputs and rendering patterns.'),
|
|
133
142
|
makeEntry('AgentParametersExample', () => import('./AgentParametersExample'), 'Launch-time parameterized agent creation with JSON schema.'),
|
|
@@ -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", "AG-UI", "Chat", "Document", "Notebook", "Capabilities", "Cell", "CopilotKit"];
|
|
8
|
+
export declare const EXAMPLE_GROUP_ORDER: readonly ["Apps", "Assistant", "A2UI", "A2A", "Personal Agent Protocol", "AG-UI", "Chat", "Document", "Notebook", "Capabilities", "Cell", "CopilotKit"];
|
|
9
9
|
export declare const getExampleGroup: (id: string) => string;
|
|
@@ -14,6 +14,7 @@ export const EXAMPLE_GROUP_ORDER = [
|
|
|
14
14
|
'Assistant',
|
|
15
15
|
'A2UI',
|
|
16
16
|
'A2A',
|
|
17
|
+
'Personal Agent Protocol',
|
|
17
18
|
'AG-UI',
|
|
18
19
|
'Chat',
|
|
19
20
|
'Document',
|
|
@@ -36,6 +37,8 @@ export const getExampleGroup = (id) => {
|
|
|
36
37
|
// Agents reached over the A2A protocol: their own category, after A2UI.
|
|
37
38
|
if (id.startsWith('AgentA2A'))
|
|
38
39
|
return 'A2A';
|
|
40
|
+
if (id.startsWith('Pap'))
|
|
41
|
+
return 'Personal Agent Protocol';
|
|
39
42
|
if (id.startsWith('AgUi'))
|
|
40
43
|
return 'AG-UI';
|
|
41
44
|
if (id.startsWith('CopilotKit'))
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ 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 PapCompanyDiscoveryExample } from './PapCompanyDiscoveryExample';
|
|
31
|
+
export { default as PapAgentIdentityExample } from './PapAgentIdentityExample';
|
|
32
|
+
export { default as PapAuthorizationBoundaryExample } from './PapAuthorizationBoundaryExample';
|
|
33
|
+
export { default as PapDpopProofExample } from './PapDpopProofExample';
|
|
34
|
+
export { default as PapSessionLifecycleExample } from './PapSessionLifecycleExample';
|
|
35
|
+
export { default as PapGuidedJourneyExample } from './PapGuidedJourneyExample';
|
|
30
36
|
export { default as ScenesExample } from './ScenesExample';
|
|
31
37
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
32
38
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -33,6 +33,12 @@ 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 PapCompanyDiscoveryExample } from './PapCompanyDiscoveryExample';
|
|
37
|
+
export { default as PapAgentIdentityExample } from './PapAgentIdentityExample';
|
|
38
|
+
export { default as PapAuthorizationBoundaryExample } from './PapAuthorizationBoundaryExample';
|
|
39
|
+
export { default as PapDpopProofExample } from './PapDpopProofExample';
|
|
40
|
+
export { default as PapSessionLifecycleExample } from './PapSessionLifecycleExample';
|
|
41
|
+
export { default as PapGuidedJourneyExample } from './PapGuidedJourneyExample';
|
|
36
42
|
export { default as ScenesExample } from './ScenesExample';
|
|
37
43
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
38
44
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
package/lib/examples/main.js
CHANGED
|
@@ -78,6 +78,15 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
78
78
|
'DocumentPageAgent',
|
|
79
79
|
// The decks plugin in a Loop; the agent and the decks both live in the page.
|
|
80
80
|
'DecksAgent',
|
|
81
|
+
// PAP protocol examples are deterministic browser views. They validate
|
|
82
|
+
// fixtures and generate local Web Crypto material without allocating a
|
|
83
|
+
// runtime or authenticating to Datalayer.
|
|
84
|
+
'PapCompanyDiscoveryExample',
|
|
85
|
+
'PapAgentIdentityExample',
|
|
86
|
+
'PapAuthorizationBoundaryExample',
|
|
87
|
+
'PapDpopProofExample',
|
|
88
|
+
'PapSessionLifecycleExample',
|
|
89
|
+
'PapGuidedJourneyExample',
|
|
81
90
|
// The floating assistant: the character, its balloon and its motions need
|
|
82
91
|
// no runtime; a conversation does, and says so when there is none.
|
|
83
92
|
'AssistantExample',
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
import { useState } from 'react';
|
|
7
|
+
import { Box } from '@datalayer/primer-addons';
|
|
8
|
+
import { Button, Text, TextInput } from '@primer/react';
|
|
9
|
+
import { parseClientMetadata, parseJsonWebKeySet, } from '@datalayer/personal-agent-protocol';
|
|
10
|
+
import { PapPersonalAgentCapability, } from '../../pap';
|
|
11
|
+
import { PapExamplePage, PapResult } from './PapExamplePage';
|
|
12
|
+
const SAMPLE_CLIENT_ID = 'https://assistant.example/agent.json';
|
|
13
|
+
/** Verify client metadata and JWKS while withholding public-key coordinates. */
|
|
14
|
+
const PapAgentIdentityView = () => {
|
|
15
|
+
const [clientId, setClientId] = useState(SAMPLE_CLIENT_ID);
|
|
16
|
+
const [summary, setSummary] = useState(null);
|
|
17
|
+
const [error, setError] = useState(null);
|
|
18
|
+
const inspect = async () => {
|
|
19
|
+
setError(null);
|
|
20
|
+
try {
|
|
21
|
+
const normalized = new URL(clientId.trim()).toString();
|
|
22
|
+
const capability = new PapPersonalAgentCapability({
|
|
23
|
+
identity: {
|
|
24
|
+
fetchMetadata: async (requested) => parseClientMetadata({
|
|
25
|
+
client_id: requested,
|
|
26
|
+
client_name: 'Example Research Assistant',
|
|
27
|
+
jwks_uri: `${new URL(requested).origin}/jwks.json`,
|
|
28
|
+
redirect_uris: [`${new URL(requested).origin}/callback`],
|
|
29
|
+
token_endpoint_auth_method: 'private_key_jwt',
|
|
30
|
+
extensions: { memory: { version: '2' } },
|
|
31
|
+
}),
|
|
32
|
+
fetchJwks: async () => parseJsonWebKeySet({
|
|
33
|
+
keys: [
|
|
34
|
+
{
|
|
35
|
+
kty: 'EC',
|
|
36
|
+
crv: 'P-256',
|
|
37
|
+
x: 'withheld-x-coordinate',
|
|
38
|
+
y: 'withheld-y-coordinate',
|
|
39
|
+
use: 'sig',
|
|
40
|
+
alg: 'ES256',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
setSummary(await capability.inspectAgent(normalized));
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
setSummary(null);
|
|
50
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return (_jsxs(PapExamplePage, { eyebrow: "PAP \u00B7 Personal-agent identity", title: "Verify who signs without exposing the key", description: "PAP binds client metadata to its HTTPS client ID and verifies its JWKS. Agent Runtimes keeps only identity and signing policy; coordinates and operational endpoints stay outside the UI and model boundary.", children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: 3, p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.default", children: [_jsx(Text, { as: "label", sx: { fontWeight: 600 }, children: "Personal-agent client ID" }), _jsxs(Box, { display: "flex", gap: 2, children: [_jsx(TextInput, { block: true, value: clientId, "aria-label": "Personal-agent client ID", onChange: event => setClientId(event.target.value) }), _jsx(Button, { variant: "primary", onClick: () => void inspect(), children: "Verify sample" })] }), error ? _jsx(Text, { sx: { color: 'danger.fg' }, children: error }) : null] }), summary ? (_jsx(PapResult, { title: "Safe identity summary", value: summary })) : null] }));
|
|
54
|
+
};
|
|
55
|
+
export default PapAgentIdentityView;
|
|
@@ -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
|
+
import { useState } from 'react';
|
|
7
|
+
import { Box } from '@datalayer/primer-addons';
|
|
8
|
+
import { Button, Text } from '@primer/react';
|
|
9
|
+
import { buildDirectSignInRequest, buildSessionAssertionClaims, generatePairwiseUserId, } from '@datalayer/personal-agent-protocol';
|
|
10
|
+
import { PapExamplePage, PapResult } from './PapExamplePage';
|
|
11
|
+
/** Generate real security material and reveal only its non-secret policy. */
|
|
12
|
+
const PapAuthorizationBoundaryView = () => {
|
|
13
|
+
const [summary, setSummary] = useState(null);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const generate = async () => {
|
|
16
|
+
setError(null);
|
|
17
|
+
try {
|
|
18
|
+
const clientId = 'https://assistant.example/agent.json';
|
|
19
|
+
const tokenEndpoint = 'https://shop.example/oauth/token';
|
|
20
|
+
const claims = buildSessionAssertionClaims({
|
|
21
|
+
clientId,
|
|
22
|
+
pairwiseUserId: generatePairwiseUserId(),
|
|
23
|
+
tokenEndpoint,
|
|
24
|
+
});
|
|
25
|
+
const request = await buildDirectSignInRequest({
|
|
26
|
+
authorizationEndpoint: 'https://shop.example/oauth/authorize',
|
|
27
|
+
issuer: 'https://shop.example',
|
|
28
|
+
clientId,
|
|
29
|
+
redirectUri: 'https://assistant.example/callback',
|
|
30
|
+
scopes: ['poppy:read', 'poppy:act'],
|
|
31
|
+
});
|
|
32
|
+
setSummary({
|
|
33
|
+
session: {
|
|
34
|
+
issuerBoundToClient: claims.iss === clientId,
|
|
35
|
+
audienceBoundToTokenEndpoint: claims.aud === tokenEndpoint,
|
|
36
|
+
lifetimeSeconds: claims.exp - claims.iat,
|
|
37
|
+
pairwiseSubjectWithheld: true,
|
|
38
|
+
uniqueRequestIdWithheld: true,
|
|
39
|
+
unsignedAssertionWithheld: true,
|
|
40
|
+
},
|
|
41
|
+
directSignIn: {
|
|
42
|
+
requestedScopes: request.scopes,
|
|
43
|
+
pkceMethod: 'S256',
|
|
44
|
+
randomState: true,
|
|
45
|
+
userOwnedBrowserRequired: true,
|
|
46
|
+
authorizationUrlWithheld: true,
|
|
47
|
+
stateWithheld: true,
|
|
48
|
+
codeVerifierWithheld: true,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (cause) {
|
|
53
|
+
setSummary(null);
|
|
54
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return (_jsxs(PapExamplePage, { eyebrow: "PAP \u00B7 Authorization boundary", title: "Generate secrets in the host; return policy to the agent", description: "This example creates a real pairwise Session identity, unique assertion ID, OAuth state and S256 PKCE verifier. None crosses the Reactor view boundary. Studio hands the authorization URL directly to a user-owned browser and stores tokens behind opaque references.", children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 3, p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.default", children: [_jsx(Text, { sx: { color: 'fg.muted' }, children: "Generate a fresh Session and Direct Sign-In request inside this host." }), _jsx(Button, { variant: "primary", onClick: () => void generate(), children: "Generate safely" })] }), error ? _jsx(Text, { sx: { color: 'danger.fg' }, children: error }) : null, summary ? (_jsx(PapResult, { title: "Model-safe boundary result", value: summary })) : null] }));
|
|
58
|
+
};
|
|
59
|
+
export default PapAuthorizationBoundaryView;
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
import { useState } from 'react';
|
|
7
|
+
import { Box } from '@datalayer/primer-addons';
|
|
8
|
+
import { Button, Text, TextInput } from '@primer/react';
|
|
9
|
+
import { parseDiscoveryDocument, } from '@datalayer/personal-agent-protocol';
|
|
10
|
+
import { PapPersonalAgentCapability } from '../../pap';
|
|
11
|
+
import { PapExamplePage, PapResult } from './PapExamplePage';
|
|
12
|
+
const SAMPLE_DOMAIN = 'shop.example';
|
|
13
|
+
const sampleCompany = (domain) => ({
|
|
14
|
+
discoveryUrl: `https://${domain}/.well-known/poppy.json`,
|
|
15
|
+
document: parseDiscoveryDocument({
|
|
16
|
+
protocol_version: '0.1',
|
|
17
|
+
organization: { name: 'Example Shop', domain },
|
|
18
|
+
auth: {
|
|
19
|
+
issuer: `https://auth.${domain}`,
|
|
20
|
+
direct: { scopes: ['poppy:read'] },
|
|
21
|
+
custom_scopes: {},
|
|
22
|
+
},
|
|
23
|
+
agent: {
|
|
24
|
+
protocols: [{ type: 'a2a', endpoint: `https://${domain}/agent` }],
|
|
25
|
+
},
|
|
26
|
+
apis: [
|
|
27
|
+
{
|
|
28
|
+
type: 'openapi',
|
|
29
|
+
url: `https://${domain}/openapi.json`,
|
|
30
|
+
description: 'Read the catalogue',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
extensions: { operations: { version: '1' } },
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
/** Verify a company fixture through the same safe capability used by agents. */
|
|
37
|
+
const PapCompanyDiscoveryView = () => {
|
|
38
|
+
const [domain, setDomain] = useState(SAMPLE_DOMAIN);
|
|
39
|
+
const [summary, setSummary] = useState(null);
|
|
40
|
+
const [error, setError] = useState(null);
|
|
41
|
+
const inspect = async () => {
|
|
42
|
+
setError(null);
|
|
43
|
+
try {
|
|
44
|
+
const normalized = domain.trim().toLowerCase();
|
|
45
|
+
const capability = new PapPersonalAgentCapability({
|
|
46
|
+
discover: async (requested) => {
|
|
47
|
+
if (requested !== normalized) {
|
|
48
|
+
throw new Error('The requested domain changed during discovery.');
|
|
49
|
+
}
|
|
50
|
+
return sampleCompany(normalized);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
setSummary(await capability.discoverCompany(normalized));
|
|
54
|
+
}
|
|
55
|
+
catch (cause) {
|
|
56
|
+
setSummary(null);
|
|
57
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return (_jsxs(PapExamplePage, { eyebrow: "PAP \u00B7 Company discovery", title: "Discover capabilities, not credentials", description: "The PAP parser validates the discovery document; Agent Runtimes then projects it into a model-safe summary. Change the sample domain to see issuer and discovery binding move together.", children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: 3, p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.default", children: [_jsx(Text, { as: "label", sx: { fontWeight: 600 }, children: "Company DNS domain" }), _jsxs(Box, { display: "flex", gap: 2, children: [_jsx(TextInput, { block: true, value: domain, "aria-label": "Company DNS domain", onChange: event => setDomain(event.target.value) }), _jsx(Button, { variant: "primary", onClick: () => void inspect(), children: "Validate sample" })] }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "The sample uses an injected Reactor-compatible transport. Production replaces it with DNS-pinned HTTPS discovery." }), error ? _jsx(Text, { sx: { color: 'danger.fg' }, children: error }) : null] }), summary ? (_jsx(PapResult, { title: "Safe company summary", value: summary })) : null] }));
|
|
61
|
+
};
|
|
62
|
+
export default PapCompanyDiscoveryView;
|