@datalayer/agent-runtimes 1.3.105 → 1.3.108
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 +85 -5
- package/lib/apps/apps/appspec.js +17 -0
- package/lib/apps/apps/checks.js +4 -0
- package/lib/apps/apps/computer.d.ts +55 -2
- package/lib/apps/apps/computer.js +82 -4
- package/lib/apps/plugins/app-computer/AppComputer.d.ts +7 -3
- package/lib/apps/plugins/app-computer/AppComputer.js +91 -4
- 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/LoopAppComputerExample.d.ts +4 -3
- package/lib/examples/LoopAppComputerExample.js +11 -6
- 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 +448 -0
- package/lib/examples/pap/PapSessionLifecycleView.d.ts +4 -0
- package/lib/examples/pap/PapSessionLifecycleView.js +103 -0
- package/lib/specs/actions.js +22 -0
- package/lib/specs/apps.js +76 -15
- package/lib/specs/appspecSchema.js +27 -0
- package/lib/types/agentspecs.d.ts +14 -0
- package/package.json +2 -2
- package/scripts/codegen/generate_apps.py +9 -0
- package/scripts/validate_pap_examples.py +62 -0
|
@@ -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;
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { JoseDpopProofProvider, SecretValue, } from '@datalayer/personal-agent-protocol';
|
|
10
|
+
import { PapExamplePage, PapResult } from './PapExamplePage';
|
|
11
|
+
/** Create real device-held proofs while retaining only non-secret evidence. */
|
|
12
|
+
const PapDpopProofView = () => {
|
|
13
|
+
const [summary, setSummary] = useState(null);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const createProofs = async () => {
|
|
16
|
+
setError(null);
|
|
17
|
+
try {
|
|
18
|
+
const keyPair = (await globalThis.crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign', 'verify']));
|
|
19
|
+
const publicJwk = await globalThis.crypto.subtle.exportKey('jwk', keyPair.publicKey);
|
|
20
|
+
const provider = new JoseDpopProofProvider({
|
|
21
|
+
resolveKey: () => ({
|
|
22
|
+
privateKey: keyPair.privateKey,
|
|
23
|
+
publicJwk,
|
|
24
|
+
algorithm: 'ES256',
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
const request = {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
url: 'https://api.company.example/orders?draft=true#editor',
|
|
30
|
+
tenantId: 'example-tenant',
|
|
31
|
+
subject: 'host-only-pairwise-subject',
|
|
32
|
+
issuer: 'https://company.example',
|
|
33
|
+
accessToken: new SecretValue('host-only-example-token'),
|
|
34
|
+
nonce: 'host-only-company-nonce',
|
|
35
|
+
};
|
|
36
|
+
const first = await provider.create(request);
|
|
37
|
+
const second = await provider.create(request);
|
|
38
|
+
setSummary({
|
|
39
|
+
algorithm: 'ES256',
|
|
40
|
+
freshProofPerRequest: first.reveal() !== second.reveal(),
|
|
41
|
+
methodBound: true,
|
|
42
|
+
urlBoundWithoutQueryOrFragment: true,
|
|
43
|
+
accessTokenBound: true,
|
|
44
|
+
nonceIncluded: true,
|
|
45
|
+
proofRedactedByDefault: first.toJSON() === '[REDACTED]',
|
|
46
|
+
proofWithheldFromUiState: true,
|
|
47
|
+
keyMaterialWithheldFromUiState: true,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (cause) {
|
|
51
|
+
setSummary(null);
|
|
52
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return (_jsxs(PapExamplePage, { eyebrow: "PAP \u00B7 DPoP", title: "Create a fresh proof for every protected request", description: "This Reactor view creates non-exportable P-256 key material and real DPoP proofs in the browser host. Only policy evidence enters React state; proofs, tokens, nonces, identifiers and key material stay outside the agent and rendered UI. Server-side verification adds signature, request, token and replay checks.", 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 two proofs for the same request without retaining either." }), _jsx(Button, { variant: "primary", onClick: () => void createProofs(), children: "Create safely" })] }), error ? _jsx(Text, { sx: { color: 'danger.fg' }, children: error }) : null, summary ? (_jsx(PapResult, { title: "Safe DPoP evidence", value: summary })) : null] }));
|
|
56
|
+
};
|
|
57
|
+
export default PapDpopProofView;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface PapExamplePageProps {
|
|
3
|
+
title: string;
|
|
4
|
+
eyebrow: string;
|
|
5
|
+
description: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
maxWidth?: number | string;
|
|
8
|
+
}
|
|
9
|
+
/** Shared visual frame for the protocol examples. */
|
|
10
|
+
export declare const PapExamplePage: React.FC<PapExamplePageProps>;
|
|
11
|
+
export declare const PapResult: React.FC<{
|
|
12
|
+
title: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from '@datalayer/primer-addons';
|
|
3
|
+
import { Heading, Label, Text } from '@primer/react';
|
|
4
|
+
/** Shared visual frame for the protocol examples. */
|
|
5
|
+
export const PapExamplePage = ({ title, eyebrow, description, children, maxWidth = 960, }) => (_jsx(Box, { height: "100%", overflow: "auto", bg: "canvas.subtle", p: 4, children: _jsxs(Box, { maxWidth: maxWidth, mx: "auto", display: "flex", flexDirection: "column", gap: 3, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsx(Box, { children: _jsx(Label, { variant: "accent", children: eyebrow }) }), _jsx(Heading, { as: "h1", sx: { fontSize: 4 }, children: title }), _jsx(Text, { sx: { color: 'fg.muted', maxWidth: 760 }, children: description })] }), children] }) }));
|
|
6
|
+
export const PapResult = ({ title, value }) => (_jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.default", p: 3, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 2 }, children: title }), _jsx(Box, { as: "pre", m: 0, p: 3, overflow: "auto", borderRadius: 2, bg: "canvas.inset", sx: { fontSize: 1, lineHeight: 1.5 }, children: JSON.stringify(value, null, 2) })] }));
|