@datalayer/agent-runtimes 1.3.84 → 1.3.86
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/lib/chat/ChatFloating.d.ts +5 -4
- package/lib/chat/ChatFloating.js +8 -6
- package/lib/chat/ChatLanguage.d.ts +17 -0
- package/lib/chat/ChatLanguage.js +29 -0
- package/lib/chat/assistant/AssistantStage.d.ts +4 -4
- package/lib/chat/assistant/AssistantStage.js +4 -2
- package/lib/chat/assistant/BalloonParts.d.ts +2 -1
- package/lib/chat/assistant/BalloonParts.js +12 -5
- package/lib/chat/assistant/BalloonVisual.js +3 -1
- package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
- package/lib/chat/assistant/ConversationBalloon.js +3 -2
- package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
- package/lib/chat/assistant/SpeechBalloon.js +10 -7
- package/lib/chat/assistant/toolLine.d.ts +8 -4
- package/lib/chat/assistant/toolLine.js +13 -9
- package/lib/chat/base/ChatBase.js +14 -11
- package/lib/chat/display/EmptyState.js +3 -1
- package/lib/chat/index.d.ts +2 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/messages/ChatMessages.js +3 -1
- package/lib/chat/messages/TurnFooter.js +3 -1
- package/lib/chat/prompt/InputPrompt.js +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +3 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
- package/lib/chat/tools/ToolApprovalBanner.js +5 -3
- package/lib/chat/tools/ToolApprovalDialog.js +5 -3
- package/lib/chat/tools/ToolCallDisplay.js +29 -25
- package/lib/chat/words.d.ts +102 -0
- package/lib/chat/words.js +460 -0
- package/lib/components/a2ui/custom/index.d.ts +39 -0
- package/lib/components/a2ui/custom/index.js +95 -0
- package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
- package/lib/components/a2ui/custom/sandbox.js +188 -0
- package/lib/components/a2ui/datalayer/index.d.ts +1 -1
- package/lib/components/a2ui/datalayer/index.js +1 -1
- package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
- package/lib/components/a2ui/datalayer/schema.js +12 -1
- package/lib/components/a2ui/index.d.ts +1 -0
- package/lib/components/a2ui/index.js +1 -0
- package/lib/components/a2ui/visibleWhen.d.ts +12 -1
- package/lib/components/a2ui/visibleWhen.js +24 -3
- package/lib/components/inspector/AgentInspector.d.ts +25 -44
- package/lib/components/inspector/AgentInspector.js +27 -215
- package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
- package/lib/components/inspector/AgentInspectorDialog.js +2 -2
- package/lib/components/inspector/a2aSpans.d.ts +51 -0
- package/lib/components/inspector/a2aSpans.js +373 -0
- package/lib/components/inspector/agentSpans.d.ts +120 -0
- package/lib/components/inspector/agentSpans.js +253 -0
- package/lib/components/inspector/chatSpans.d.ts +36 -0
- package/lib/components/inspector/chatSpans.js +50 -0
- package/lib/components/inspector/classify.d.ts +11 -8
- package/lib/components/inspector/classify.js +23 -24
- package/lib/components/inspector/index.d.ts +7 -7
- package/lib/components/inspector/index.js +7 -7
- package/lib/components/teams/A2ATeamGraph.d.ts +117 -22
- package/lib/components/teams/A2ATeamGraph.js +217 -97
- package/lib/components/teams/SceneTranscript.d.ts +29 -0
- package/lib/components/teams/SceneTranscript.js +54 -0
- package/lib/components/teams/SceneView.d.ts +41 -0
- package/lib/components/teams/SceneView.js +28 -0
- package/lib/components/teams/index.d.ts +4 -0
- package/lib/components/teams/index.js +4 -0
- package/lib/components/teams/sceneStage.d.ts +120 -0
- package/lib/components/teams/sceneStage.js +170 -0
- package/lib/components/teams/sceneTranscript.d.ts +74 -0
- package/lib/components/teams/sceneTranscript.js +294 -0
- package/lib/components/teams/teamConnections.d.ts +2 -2
- package/lib/components/teams/teamConnections.js +3 -3
- package/lib/components/teams/useA2ATeam.d.ts +94 -22
- package/lib/components/teams/useA2ATeam.js +356 -140
- package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
- package/lib/examples/AgentA2ATeamExample.js +70 -60
- package/lib/examples/AssistantExample.js +2 -2
- package/lib/examples/ScenesExample.d.ts +26 -0
- package/lib/examples/ScenesExample.js +241 -0
- package/lib/examples/example-selector.js +1 -0
- package/lib/examples/exampleGroups.js +3 -0
- package/lib/examples/index.d.ts +1 -0
- package/lib/examples/index.js +1 -0
- package/lib/examples/main.js +4 -0
- package/lib/loop/apps/AppComposer.d.ts +2 -1
- package/lib/loop/apps/AppComposer.js +6 -3
- package/lib/loop/apps/AppRenderer.d.ts +2 -1
- package/lib/loop/apps/AppRenderer.js +34 -25
- package/lib/loop/apps/appspec.d.ts +11 -1
- package/lib/loop/apps/appspec.js +115 -1
- package/lib/loop/apps/checks.d.ts +8 -0
- package/lib/loop/apps/checks.js +106 -4
- package/lib/loop/apps/customComponents.d.ts +41 -0
- package/lib/loop/apps/customComponents.js +260 -0
- package/lib/loop/apps/hostTools.d.ts +8 -1
- package/lib/loop/apps/hostTools.js +9 -0
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/core/a2uiComponents.d.ts +10 -0
- package/lib/loop/core/a2uiComponents.js +15 -0
- package/lib/loop/core/index.d.ts +1 -0
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/embed/AppEmbed.d.ts +11 -3
- package/lib/loop/embed/AppEmbed.js +42 -16
- package/lib/loop/embed/element.d.ts +5 -0
- package/lib/loop/embed/element.js +61 -5
- package/lib/loop/embed/embedConfig.d.ts +8 -0
- package/lib/loop/embed/embedConfig.js +18 -0
- package/lib/loop/embed/hostBridge.d.ts +28 -2
- package/lib/loop/embed/hostBridge.js +22 -2
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
- package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
- package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
- package/lib/loop/plugins/app-components/index.d.ts +26 -0
- package/lib/loop/plugins/app-components/index.js +56 -0
- package/lib/loop/plugins/app-elements/AppElements.js +4 -1
- package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
- package/lib/loop/plugins/app-page/AppPage.js +106 -8
- package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
- package/lib/loop/plugins/app-page/appPageModel.js +120 -4
- package/lib/loop/plugins/app-page/index.d.ts +1 -0
- package/lib/loop/plugins/app-page/index.js +1 -0
- package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
- package/lib/loop/plugins/app-page/pageRun.js +111 -0
- package/lib/loop/plugins/assistant/index.js +8 -6
- package/lib/loop/plugins/chat/ChatView.js +6 -4
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/chat/index.js +2 -1
- package/lib/models/PageTag.d.ts +1 -1
- package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
- package/lib/specs/actions.js +78 -1
- package/lib/specs/apps.d.ts +5 -0
- package/lib/specs/apps.js +1384 -231
- package/lib/specs/appspecSchema.js +191 -1
- package/lib/specs/index.d.ts +1 -0
- package/lib/specs/index.js +1 -0
- package/lib/specs/mcpServers.js +8 -2
- package/lib/specs/scenes.d.ts +21 -0
- package/lib/specs/scenes.js +1191 -0
- package/lib/specs/teams/teams.d.ts +3 -0
- package/lib/specs/teams/teams.js +249 -0
- package/lib/types/agentspecs.d.ts +70 -0
- package/lib/types/chat.d.ts +6 -5
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/scenes.d.ts +207 -0
- package/lib/types/scenes.js +5 -0
- package/lib/types/teams.d.ts +13 -2
- package/package.json +4 -4
- package/scripts/codegen/generate_agents.py +1 -0
- package/scripts/codegen/generate_apps.py +4 -2
- package/scripts/codegen/generate_scenes.py +301 -0
- package/scripts/codegen/generate_teams.py +15 -2
- package/lib/components/inspector/JsonTree.d.ts +0 -24
- package/lib/components/inspector/JsonTree.js +0 -89
- package/lib/components/inspector/a2aInspect.d.ts +0 -56
- package/lib/components/inspector/a2aInspect.js +0 -478
- package/lib/components/inspector/agentInspector.d.ts +0 -179
- package/lib/components/inspector/agentInspector.js +0 -267
- package/lib/components/inspector/chatInspect.d.ts +0 -38
- package/lib/components/inspector/chatInspect.js +0 -65
|
@@ -1,220 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { ActionList, ActionMenu, Button, Label, Text } from '@primer/react';
|
|
4
|
-
import { Box } from '@datalayer/primer-addons';
|
|
5
|
-
import { DownloadIcon, PlayIcon, TrashIcon, PauseIcon, } from '@primer/octicons-react';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { OtelLiveSpans, } from '@datalayer/core/lib/otel/views/OtelLiveSpans';
|
|
6
3
|
import { SpecMark } from '../../chat/marks';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const KIND_VARIANTS = {
|
|
31
|
-
request: 'accent',
|
|
32
|
-
'status-update': 'attention',
|
|
33
|
-
'artifact-update': 'success',
|
|
34
|
-
task: 'secondary',
|
|
35
|
-
message: 'done',
|
|
36
|
-
'agent-card': 'secondary',
|
|
37
|
-
response: 'secondary',
|
|
38
|
-
'tool-call': 'sponsors',
|
|
39
|
-
turn: 'primary',
|
|
40
|
-
error: 'danger',
|
|
41
|
-
approval: 'severe',
|
|
42
|
-
};
|
|
43
|
-
const pad = (value, length = 2) => String(value).padStart(length, '0');
|
|
44
|
-
/** A time of day, to the millisecond: `15:44:31.299`. */
|
|
45
|
-
export function clockTime(at) {
|
|
46
|
-
const date = new Date(at);
|
|
47
|
-
return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}`;
|
|
48
|
-
}
|
|
49
|
-
/** Time since the first entry: `+1.204s`. */
|
|
50
|
-
export function sinceFirst(at, first) {
|
|
51
|
-
return `+${((at - first) / 1000).toFixed(3)}s`;
|
|
52
|
-
}
|
|
53
|
-
/** How long a call took: `412 ms`, `3.4 s`. */
|
|
54
|
-
export function durationText(ms) {
|
|
55
|
-
return ms < 1000 ? `${Math.round(ms)} ms` : `${(ms / 1000).toFixed(1)} s`;
|
|
56
|
-
}
|
|
57
|
-
/** The entries a filter keeps: an empty set keeps every value. */
|
|
58
|
-
export function filterEntries(entries, filter) {
|
|
59
|
-
return entries.filter(entry => (!filter.sources.size || filter.sources.has(entry.source)) &&
|
|
60
|
-
(!filter.kinds.size || filter.kinds.has(entry.kind)) &&
|
|
61
|
-
(!filter.actors.size || filter.actors.has(entry.actor)));
|
|
62
|
-
}
|
|
63
|
-
/** A session, as JSON. */
|
|
64
|
-
export function exportEntries(entries) {
|
|
65
|
-
return { exportedAt: new Date().toISOString(), entries: [...entries] };
|
|
66
|
-
}
|
|
67
|
-
function toggle(set, value) {
|
|
68
|
-
const next = new Set(set);
|
|
69
|
-
if (next.has(value)) {
|
|
70
|
-
next.delete(value);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
next.add(value);
|
|
74
|
-
}
|
|
75
|
-
return next;
|
|
76
|
-
}
|
|
77
|
-
function FilterMenu({ label, options, selected, onToggle, onAll, name, }) {
|
|
78
|
-
return (_jsxs(ActionMenu, { children: [_jsxs(ActionMenu.Button, { size: "small", "data-inspector-filter": label.toLowerCase(), children: [label, selected.size ? ` · ${selected.size}` : ''] }), _jsx(ActionMenu.Overlay, { width: "auto", children: _jsxs(ActionList, { selectionVariant: "multiple", "aria-label": label, children: [_jsx(ActionList.Item, { selected: !selected.size, onSelect: onAll, children: "All" }), _jsx(ActionList.Divider, {}), options.map(option => (_jsx(ActionList.Item, { selected: selected.has(option), onSelect: () => onToggle(option), children: name(option) }, option)))] }) })] }));
|
|
79
|
-
}
|
|
80
|
-
function Payload({ title, value, large, }) {
|
|
81
|
-
const bytes = useMemo(() => {
|
|
82
|
-
try {
|
|
83
|
-
return new TextEncoder().encode(JSON.stringify(value) ?? '').length;
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
}, [value]);
|
|
89
|
-
const [shown, setShown] = useState(bytes <= large);
|
|
90
|
-
return (_jsxs(Box, { sx: { minWidth: 0 }, "data-inspector-payload": title, children: [_jsxs(Text, { sx: {
|
|
91
|
-
fontSize: 0,
|
|
92
|
-
color: 'fg.muted',
|
|
93
|
-
fontWeight: 600,
|
|
94
|
-
display: 'block',
|
|
95
|
-
}, children: [title, " \u00B7 ", formatBytes(bytes)] }), shown ? (_jsx(JsonTree, { value: value, expandDepth: bytes > large ? 1 : 2 })) : (_jsxs(Button, { size: "small", onClick: () => setShown(true), "data-inspector-large": "", children: ["Show ", formatBytes(bytes)] }))] }));
|
|
96
|
-
}
|
|
97
|
-
function Row({ entry, first, open, onToggle, large, agent, }) {
|
|
98
|
-
const ended = entry.endedAt !== undefined;
|
|
99
|
-
return (_jsxs(Box, { as: "li", "data-inspector-entry": entry.id, "data-inspector-source": entry.source, "data-inspector-kind": entry.kind, "data-inspector-status": entry.status ?? '', sx: {
|
|
100
|
-
borderBottom: '1px solid',
|
|
101
|
-
borderColor: 'border.muted',
|
|
102
|
-
listStyle: 'none',
|
|
103
|
-
}, children: [_jsxs(Box, { as: "button", type: "button", "aria-expanded": open, onClick: onToggle, sx: {
|
|
104
|
-
width: '100%',
|
|
105
|
-
display: 'grid',
|
|
106
|
-
gridTemplateColumns: ['auto 1fr', 'auto auto auto minmax(0, 1fr)'],
|
|
107
|
-
columnGap: 2,
|
|
108
|
-
rowGap: 1,
|
|
109
|
-
alignItems: 'center',
|
|
110
|
-
px: 2,
|
|
111
|
-
py: 1,
|
|
112
|
-
border: 0,
|
|
113
|
-
bg: open ? 'canvas.subtle' : 'transparent',
|
|
114
|
-
color: 'fg.default',
|
|
115
|
-
font: 'inherit',
|
|
116
|
-
fontSize: 0,
|
|
117
|
-
textAlign: 'left',
|
|
118
|
-
cursor: 'pointer',
|
|
119
|
-
'&:hover': { bg: 'canvas.subtle' },
|
|
120
|
-
}, children: [_jsxs(Box, { sx: { fontFamily: 'mono', color: 'fg.muted', whiteSpace: 'nowrap' }, children: [_jsx("span", { title: new Date(entry.at).toISOString(), children: clockTime(entry.at) }), ' ', _jsx(Text, { sx: { opacity: 0.7 }, children: sinceFirst(entry.at, first) })] }), _jsx(Text, { sx: { whiteSpace: 'nowrap', fontWeight: 600 }, "data-inspector-direction": "", children: directionFrom(entry, agent) }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [_jsx(Label, { size: "small", variant: "secondary", children: AGENT_INSPECTOR_SOURCE_LABELS[entry.source] }), _jsx(Label, { size: "small", variant: KIND_VARIANTS[entry.kind] ?? 'secondary', children: entry.kind })] }), _jsxs(Box, { sx: { display: 'flex', gap: 1, alignItems: 'center', minWidth: 0 }, children: [(entry.icon || entry.emoji) && (_jsx(SpecMark, { icon: entry.icon, emoji: entry.emoji, size: 14 })), entry.name && entry.kind !== 'request' && (_jsx(Text, { sx: { fontFamily: 'mono', fontWeight: 600, whiteSpace: 'nowrap' }, children: entry.name })), entry.status && (_jsxs(Label, { size: "small", variant: entry.status === 'failed'
|
|
121
|
-
? 'danger'
|
|
122
|
-
: entry.status === 'running'
|
|
123
|
-
? 'attention'
|
|
124
|
-
: 'success', children: [entry.status, ended && entry.endedAt !== undefined
|
|
125
|
-
? ` · ${durationText(entry.endedAt - entry.at)}`
|
|
126
|
-
: ''] })), _jsx(Text, { sx: {
|
|
127
|
-
color: 'fg.muted',
|
|
128
|
-
overflow: 'hidden',
|
|
129
|
-
textOverflow: 'ellipsis',
|
|
130
|
-
whiteSpace: 'nowrap',
|
|
131
|
-
minWidth: 0,
|
|
132
|
-
}, title: entry.summary, children: entry.summary }), entry.bytes > large && (_jsx(Text, { sx: { color: 'fg.muted', whiteSpace: 'nowrap' }, children: formatBytes(entry.bytes) }))] })] }), open && (_jsxs(Box, { "data-inspector-details": "", sx: {
|
|
133
|
-
px: 3,
|
|
134
|
-
py: 2,
|
|
135
|
-
display: 'flex',
|
|
136
|
-
flexDirection: 'column',
|
|
137
|
-
gap: 2,
|
|
138
|
-
bg: 'canvas.subtle',
|
|
139
|
-
}, children: [entry.a2a && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: [
|
|
140
|
-
entry.a2a.method && `method ${entry.a2a.method}`,
|
|
141
|
-
entry.a2a.rpcId !== undefined && `id ${entry.a2a.rpcId}`,
|
|
142
|
-
entry.a2a.taskId && `task ${entry.a2a.taskId}`,
|
|
143
|
-
entry.a2a.contextId && `context ${entry.a2a.contextId}`,
|
|
144
|
-
entry.a2a.state && entry.a2a.state,
|
|
145
|
-
entry.a2a.chunks &&
|
|
146
|
-
entry.a2a.chunks > 1 &&
|
|
147
|
-
`${entry.a2a.chunks} chunks`,
|
|
148
|
-
]
|
|
149
|
-
.filter(Boolean)
|
|
150
|
-
.join(' · ') })), entry.error && (_jsx(Text, { sx: { color: 'danger.fg', fontSize: 0 }, children: entry.error })), entry.payload !== undefined && (_jsx(Payload, { title: entry.kind === 'tool-call' ? 'Arguments' : 'Payload', value: entry.payload, large: large })), entry.result !== undefined && (_jsx(Payload, { title: "Result", value: entry.result, large: large })), entry.events.length > 0 && (_jsx(Payload, { title: "Events", value: entry.events, large: large })), entry.links.length > 0 && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Linked: ", entry.links.join(', ')] }))] }))] }));
|
|
151
|
-
}
|
|
152
|
-
/** Save a session as a JSON file. */
|
|
153
|
-
function download(name, session) {
|
|
154
|
-
const blob = new Blob([JSON.stringify(session, null, 2)], {
|
|
155
|
-
type: 'application/json',
|
|
156
|
-
});
|
|
157
|
-
const url = URL.createObjectURL(blob);
|
|
158
|
-
const link = document.createElement('a');
|
|
159
|
-
link.href = url;
|
|
160
|
-
link.download = `${name}.json`;
|
|
161
|
-
link.click();
|
|
162
|
-
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
4
|
+
import { AGENT_SPAN_ATTRIBUTES, SPAN_SOURCE_LABELS, describeAgentSpan, sourceOfSpan, } from './agentSpans';
|
|
5
|
+
/** The Inspector's filters: where a span comes from, what it does, which agent. */
|
|
6
|
+
export const AGENT_INSPECTOR_FACETS = [
|
|
7
|
+
{
|
|
8
|
+
label: 'Source',
|
|
9
|
+
value: sourceOfSpan,
|
|
10
|
+
name: value => SPAN_SOURCE_LABELS[value] ?? value,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
label: 'Operation',
|
|
14
|
+
value: span => {
|
|
15
|
+
const attributes = span.attributes ?? {};
|
|
16
|
+
const operation = attributes[AGENT_SPAN_ATTRIBUTES.operation] ?? attributes['rpc.method'];
|
|
17
|
+
return operation === undefined ? undefined : String(operation);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{ label: 'Agent', value: span => span.service_name },
|
|
21
|
+
];
|
|
22
|
+
/** A span's mark: its tool's, as the catalogue gives it. */
|
|
23
|
+
function spanMark(span) {
|
|
24
|
+
const icon = span.attributes?.[AGENT_SPAN_ATTRIBUTES.markIcon];
|
|
25
|
+
const emoji = span.attributes?.[AGENT_SPAN_ATTRIBUTES.markEmoji];
|
|
26
|
+
return icon || emoji ? (_jsx(SpecMark, { icon: typeof icon === 'string' ? icon : undefined, emoji: typeof emoji === 'string' ? emoji : undefined, size: 14 })) : null;
|
|
163
27
|
}
|
|
164
28
|
/** The Agent Inspector. */
|
|
165
|
-
export function AgentInspector({
|
|
166
|
-
|
|
167
|
-
const everything = given ?? live;
|
|
168
|
-
const all = useMemo(() => agent
|
|
169
|
-
? everything.filter(entry => isAgentsEntry(entry, agent))
|
|
170
|
-
: everything, [everything, agent]);
|
|
171
|
-
const [held, setHeld] = useState(null);
|
|
172
|
-
const [clearedAt, setClearedAt] = useState(0);
|
|
173
|
-
const [sources, setSources] = useState(new Set());
|
|
174
|
-
const [kinds, setKinds] = useState(new Set());
|
|
175
|
-
const [actors, setActors] = useState(new Set());
|
|
176
|
-
const [open, setOpen] = useState(new Set());
|
|
177
|
-
const recorded = useMemo(() => (clearedAt ? all.filter(entry => entry.at >= clearedAt) : all), [all, clearedAt]);
|
|
178
|
-
const shown = held ?? recorded;
|
|
179
|
-
const waiting = held ? recorded.length - held.length : 0;
|
|
180
|
-
const kindOptions = useMemo(() => [...new Set(recorded.map(entry => entry.kind))].sort(), [recorded]);
|
|
181
|
-
const actorOptions = useMemo(() => [...new Set(recorded.map(entry => entry.actor))].sort(), [recorded]);
|
|
182
|
-
const sourceOptions = useMemo(() => AGENT_INSPECTOR_SOURCES.filter(source => recorded.some(entry => entry.source === source)), [recorded]);
|
|
183
|
-
const rows = useMemo(() => filterEntries(shown, { sources, kinds, actors }), [shown, sources, kinds, actors]);
|
|
184
|
-
const first = shown[0]?.at ?? 0;
|
|
185
|
-
return (_jsxs(Box, { "data-agent-inspector": "", sx: {
|
|
186
|
-
border: '1px solid',
|
|
187
|
-
borderColor: 'border.default',
|
|
188
|
-
borderRadius: 2,
|
|
189
|
-
bg: 'canvas.default',
|
|
190
|
-
color: 'fg.default',
|
|
191
|
-
minWidth: 0,
|
|
192
|
-
}, children: [_jsxs(Box, { role: "toolbar", "aria-label": agent ? `${agent}'s Agent Inspector` : 'Agent Inspector', sx: {
|
|
193
|
-
display: 'flex',
|
|
194
|
-
flexWrap: 'wrap',
|
|
195
|
-
gap: 2,
|
|
196
|
-
alignItems: 'center',
|
|
197
|
-
p: 2,
|
|
198
|
-
borderBottom: '1px solid',
|
|
199
|
-
borderColor: 'border.default',
|
|
200
|
-
}, children: [_jsx(FilterMenu, { label: "Source", options: sourceOptions, selected: sources, onToggle: value => setSources(toggle(sources, value)), onAll: () => setSources(new Set()), name: value => AGENT_INSPECTOR_SOURCE_LABELS[value] }), _jsx(FilterMenu, { label: "Kind", options: kindOptions, selected: kinds, onToggle: value => setKinds(toggle(kinds, value)), onAll: () => setKinds(new Set()), name: value => value }), _jsx(FilterMenu, { label: "Actor", options: actorOptions, selected: actors, onToggle: value => setActors(toggle(actors, value)), onAll: () => setActors(new Set()), name: value => value }), _jsx(Box, { sx: { flex: 1 } }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, "data-inspector-count": "", children: [rows.length === shown.length
|
|
201
|
-
? `${rows.length} ${rows.length === 1 ? 'entry' : 'entries'}`
|
|
202
|
-
: `${rows.length} of ${shown.length}`, waiting > 0 ? ` · ${waiting} new` : ''] }), _jsx(Button, { size: "small", leadingVisual: held ? PlayIcon : PauseIcon, "aria-pressed": held !== null, onClick: () => setHeld(held ? null : recorded), "data-inspector-pause": "", children: held ? 'Resume' : 'Pause' }), _jsx(Button, { size: "small", leadingVisual: TrashIcon, onClick: () => {
|
|
203
|
-
setOpen(new Set());
|
|
204
|
-
setHeld(null);
|
|
205
|
-
// One agent's view of a shared record clears only itself.
|
|
206
|
-
if (sink && !given && !agent) {
|
|
207
|
-
sink.clear();
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
setClearedAt(Date.now());
|
|
211
|
-
}
|
|
212
|
-
}, "data-inspector-clear": "", children: "Clear" }), _jsx(Button, { size: "small", leadingVisual: DownloadIcon, disabled: !recorded.length, onClick: () => download(exportName, exportEntries(recorded)), "data-inspector-export": "", children: "Export" })] }), _jsx(Box, { as: "ol", "aria-label": "Recorded", sx: { m: 0, p: 0, maxHeight, overflowY: 'auto' }, children: rows.length === 0 ? (_jsx(Text, { as: "li", sx: {
|
|
213
|
-
display: 'block',
|
|
214
|
-
p: 3,
|
|
215
|
-
color: 'fg.muted',
|
|
216
|
-
fontSize: 1,
|
|
217
|
-
listStyle: 'none',
|
|
218
|
-
}, children: emptyText })) : (rows.map(entry => (_jsx(Row, { entry: entry, first: first, large: largeBytes, agent: agent, open: open.has(entry.id), onToggle: () => setOpen(toggle(open, entry.id)) }, entry.id)))) })] }));
|
|
29
|
+
export function AgentInspector({ tracer, spans, agent, maxHeight = 420, compact = false, emptyText = 'Nothing recorded yet.', exportName = 'agent-inspector', }) {
|
|
30
|
+
return (_jsx("div", { "data-agent-inspector": agent ?? '', children: _jsx(OtelLiveSpans, { tracer: tracer, spans: spans, service: agent, facets: AGENT_INSPECTOR_FACETS, compact: compact, maxHeight: maxHeight, detailPlacement: "side", emptyText: emptyText, exportName: exportName, label: agent ? `${agent}'s Agent Inspector` : 'Agent Inspector', renderSpanMark: spanMark, describeSpan: describeAgentSpan }) }));
|
|
219
31
|
}
|
|
220
32
|
export default AgentInspector;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Agent Inspector over the page: a large dialog, the inspector loaded
|
|
3
|
-
* only when it opens,
|
|
4
|
-
* closes it.
|
|
3
|
+
* only when it opens, drawing the spans the agent's chat or team records
|
|
4
|
+
* into its tracer. Esc closes it.
|
|
5
5
|
*
|
|
6
6
|
* @module components/inspector/AgentInspectorDialog
|
|
7
7
|
*/
|
|
8
8
|
import type { JSX } from 'react';
|
|
9
|
-
import type {
|
|
9
|
+
import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
|
|
10
10
|
export type AgentInspectorDialogProps = {
|
|
11
|
-
|
|
11
|
+
tracer: OtelLiveTracer | null;
|
|
12
12
|
/** The dialog's title. */
|
|
13
13
|
title?: string;
|
|
14
|
-
/** One agent's own
|
|
14
|
+
/** One agent's own spans (`AgentInspector`'s `agent`); all of them without. */
|
|
15
15
|
agent?: string;
|
|
16
16
|
onClose: () => void;
|
|
17
17
|
};
|
|
18
|
-
export declare function AgentInspectorDialog({
|
|
18
|
+
export declare function AgentInspectorDialog({ tracer, title, agent, onClose, }: AgentInspectorDialogProps): JSX.Element;
|
|
19
19
|
export default AgentInspectorDialog;
|
|
@@ -3,7 +3,7 @@ import { Suspense, lazy } from 'react';
|
|
|
3
3
|
import { Dialog } from '@primer/react';
|
|
4
4
|
import { Text } from '@primer/react';
|
|
5
5
|
const AgentInspector = lazy(() => import('./AgentInspector'));
|
|
6
|
-
export function AgentInspectorDialog({
|
|
7
|
-
return (_jsx(Dialog, { title: title, onClose: onClose, width: "xlarge", height: "large", "data-agent-inspector-dialog": "", children: _jsx(Suspense, { fallback: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading the Agent Inspector\u2026" }), children: _jsx(AgentInspector, {
|
|
6
|
+
export function AgentInspectorDialog({ tracer, title = 'Agent Inspector', agent, onClose, }) {
|
|
7
|
+
return (_jsx(Dialog, { title: title, onClose: onClose, width: "xlarge", height: "large", "data-agent-inspector-dialog": "", children: _jsx(Suspense, { fallback: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading the Agent Inspector\u2026" }), children: _jsx(AgentInspector, { tracer: tracer, agent: agent, maxHeight: "calc(80vh - 140px)", emptyText: "Nothing recorded yet: what the agent does shows here as it does it." }) }) }));
|
|
8
8
|
}
|
|
9
9
|
export default AgentInspectorDialog;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The A2A traffic between two agents, as OpenTelemetry spans: a fetch that
|
|
3
|
+
* hands every request on and records each JSON-RPC request as a client span
|
|
4
|
+
* of the asker's — `a2a <method>`, with the RPC conventions (`rpc.system`
|
|
5
|
+
* `jsonrpc`, `rpc.service` `a2a`, `rpc.method`, `rpc.jsonrpc.request_id`),
|
|
6
|
+
* the agent asked as `peer.service`, the request whole (`a2a.request`) and
|
|
7
|
+
* its words (`a2a.message.text`) — and what came back as its events: a
|
|
8
|
+
* JSON-RPC response, or each server-sent event of a stream (`a2a.task`,
|
|
9
|
+
* `a2a.status_update`, `a2a.artifact_update`, `a2a.message`, `a2a.error`),
|
|
10
|
+
* each with its task, context and state, and the event whole (`a2a.event`).
|
|
11
|
+
* The text chunks of one artifact are one event, their count kept.
|
|
12
|
+
*
|
|
13
|
+
* Any other request (the agent card) is a client span too: `a2a agent card`
|
|
14
|
+
* when it brings one back, its name and skills with it.
|
|
15
|
+
*
|
|
16
|
+
* A peer served by agent-runtimes tells each tool call of its agent on a
|
|
17
|
+
* `working` status (`{tool_call}`, then `{tool_result}`): each is recorded as
|
|
18
|
+
* an `execute_tool` span of the peer's under the request's span, from its
|
|
19
|
+
* start to its end, an MCP call, a skill, codemode's or a tool its runtime
|
|
20
|
+
* runs, by who claims its name (`datalayer.span.origin` `a2a.status`: the
|
|
21
|
+
* page knows of it from the peer's own words).
|
|
22
|
+
*
|
|
23
|
+
* It sits under the A2A SDK (`ClientFactory`'s `JsonRpcTransportFactory`
|
|
24
|
+
* takes a `fetchImpl`): the SDK reads the response it is handed, and this
|
|
25
|
+
* reads a copy of its body. Nothing it records changes what the SDK sees,
|
|
26
|
+
* and a key sent as a header is never recorded.
|
|
27
|
+
*
|
|
28
|
+
* @module components/inspector/a2aSpans
|
|
29
|
+
*/
|
|
30
|
+
import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
|
|
31
|
+
import { type ToolClass } from './agentSpans';
|
|
32
|
+
export type A2ASpansOptions = {
|
|
33
|
+
tracer: OtelLiveTracer;
|
|
34
|
+
/** The agent that asks: `Sales`. */
|
|
35
|
+
asker: string;
|
|
36
|
+
/** The agent asked: `Accounting`. */
|
|
37
|
+
peer: string;
|
|
38
|
+
/**
|
|
39
|
+
* Where a peer's tool call comes from — an MCP server's, a skill, … — and
|
|
40
|
+
* its marks (`classifyToolCall`, or a team's `teamToolClassifier`).
|
|
41
|
+
* Without it, a tool the peer's runtime runs.
|
|
42
|
+
*/
|
|
43
|
+
classifyTool?: (name: string, args?: Record<string, unknown>) => ToolClass;
|
|
44
|
+
};
|
|
45
|
+
/** The text of an A2A 1.0 message's or artifact's parts, as JSON carries them. */
|
|
46
|
+
export declare function partsText(parts: unknown): string;
|
|
47
|
+
/**
|
|
48
|
+
* A fetch that records the A2A traffic it carries as spans into
|
|
49
|
+
* `options.tracer`, and hands the SDK what the network gave.
|
|
50
|
+
*/
|
|
51
|
+
export declare function traceA2AFetch(base: typeof globalThis.fetch, options: A2ASpansOptions): typeof globalThis.fetch;
|