@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.
Files changed (162) hide show
  1. package/lib/chat/ChatFloating.d.ts +5 -4
  2. package/lib/chat/ChatFloating.js +8 -6
  3. package/lib/chat/ChatLanguage.d.ts +17 -0
  4. package/lib/chat/ChatLanguage.js +29 -0
  5. package/lib/chat/assistant/AssistantStage.d.ts +4 -4
  6. package/lib/chat/assistant/AssistantStage.js +4 -2
  7. package/lib/chat/assistant/BalloonParts.d.ts +2 -1
  8. package/lib/chat/assistant/BalloonParts.js +12 -5
  9. package/lib/chat/assistant/BalloonVisual.js +3 -1
  10. package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
  11. package/lib/chat/assistant/ConversationBalloon.js +3 -2
  12. package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
  13. package/lib/chat/assistant/SpeechBalloon.js +10 -7
  14. package/lib/chat/assistant/toolLine.d.ts +8 -4
  15. package/lib/chat/assistant/toolLine.js +13 -9
  16. package/lib/chat/base/ChatBase.js +14 -11
  17. package/lib/chat/display/EmptyState.js +3 -1
  18. package/lib/chat/index.d.ts +2 -0
  19. package/lib/chat/index.js +3 -0
  20. package/lib/chat/messages/ChatMessages.js +3 -1
  21. package/lib/chat/messages/TurnFooter.js +3 -1
  22. package/lib/chat/prompt/InputPrompt.js +3 -1
  23. package/lib/chat/prompt/InputPromptLexical.js +3 -1
  24. package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
  25. package/lib/chat/tools/ToolApprovalBanner.js +5 -3
  26. package/lib/chat/tools/ToolApprovalDialog.js +5 -3
  27. package/lib/chat/tools/ToolCallDisplay.js +29 -25
  28. package/lib/chat/words.d.ts +102 -0
  29. package/lib/chat/words.js +460 -0
  30. package/lib/components/a2ui/custom/index.d.ts +39 -0
  31. package/lib/components/a2ui/custom/index.js +95 -0
  32. package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
  33. package/lib/components/a2ui/custom/sandbox.js +188 -0
  34. package/lib/components/a2ui/datalayer/index.d.ts +1 -1
  35. package/lib/components/a2ui/datalayer/index.js +1 -1
  36. package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
  37. package/lib/components/a2ui/datalayer/schema.js +12 -1
  38. package/lib/components/a2ui/index.d.ts +1 -0
  39. package/lib/components/a2ui/index.js +1 -0
  40. package/lib/components/a2ui/visibleWhen.d.ts +12 -1
  41. package/lib/components/a2ui/visibleWhen.js +24 -3
  42. package/lib/components/inspector/AgentInspector.d.ts +25 -44
  43. package/lib/components/inspector/AgentInspector.js +27 -215
  44. package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
  45. package/lib/components/inspector/AgentInspectorDialog.js +2 -2
  46. package/lib/components/inspector/a2aSpans.d.ts +51 -0
  47. package/lib/components/inspector/a2aSpans.js +373 -0
  48. package/lib/components/inspector/agentSpans.d.ts +120 -0
  49. package/lib/components/inspector/agentSpans.js +253 -0
  50. package/lib/components/inspector/chatSpans.d.ts +36 -0
  51. package/lib/components/inspector/chatSpans.js +50 -0
  52. package/lib/components/inspector/classify.d.ts +11 -8
  53. package/lib/components/inspector/classify.js +23 -24
  54. package/lib/components/inspector/index.d.ts +7 -7
  55. package/lib/components/inspector/index.js +7 -7
  56. package/lib/components/teams/A2ATeamGraph.d.ts +117 -22
  57. package/lib/components/teams/A2ATeamGraph.js +217 -97
  58. package/lib/components/teams/SceneTranscript.d.ts +29 -0
  59. package/lib/components/teams/SceneTranscript.js +54 -0
  60. package/lib/components/teams/SceneView.d.ts +41 -0
  61. package/lib/components/teams/SceneView.js +28 -0
  62. package/lib/components/teams/index.d.ts +4 -0
  63. package/lib/components/teams/index.js +4 -0
  64. package/lib/components/teams/sceneStage.d.ts +120 -0
  65. package/lib/components/teams/sceneStage.js +170 -0
  66. package/lib/components/teams/sceneTranscript.d.ts +74 -0
  67. package/lib/components/teams/sceneTranscript.js +294 -0
  68. package/lib/components/teams/teamConnections.d.ts +2 -2
  69. package/lib/components/teams/teamConnections.js +3 -3
  70. package/lib/components/teams/useA2ATeam.d.ts +94 -22
  71. package/lib/components/teams/useA2ATeam.js +356 -140
  72. package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
  73. package/lib/examples/AgentA2ATeamExample.js +70 -60
  74. package/lib/examples/AssistantExample.js +2 -2
  75. package/lib/examples/ScenesExample.d.ts +26 -0
  76. package/lib/examples/ScenesExample.js +241 -0
  77. package/lib/examples/example-selector.js +1 -0
  78. package/lib/examples/exampleGroups.js +3 -0
  79. package/lib/examples/index.d.ts +1 -0
  80. package/lib/examples/index.js +1 -0
  81. package/lib/examples/main.js +4 -0
  82. package/lib/loop/apps/AppComposer.d.ts +2 -1
  83. package/lib/loop/apps/AppComposer.js +6 -3
  84. package/lib/loop/apps/AppRenderer.d.ts +2 -1
  85. package/lib/loop/apps/AppRenderer.js +34 -25
  86. package/lib/loop/apps/appspec.d.ts +11 -1
  87. package/lib/loop/apps/appspec.js +115 -1
  88. package/lib/loop/apps/checks.d.ts +8 -0
  89. package/lib/loop/apps/checks.js +106 -4
  90. package/lib/loop/apps/customComponents.d.ts +41 -0
  91. package/lib/loop/apps/customComponents.js +260 -0
  92. package/lib/loop/apps/hostTools.d.ts +8 -1
  93. package/lib/loop/apps/hostTools.js +9 -0
  94. package/lib/loop/apps/index.d.ts +1 -0
  95. package/lib/loop/apps/index.js +1 -0
  96. package/lib/loop/core/a2uiComponents.d.ts +10 -0
  97. package/lib/loop/core/a2uiComponents.js +15 -0
  98. package/lib/loop/core/index.d.ts +1 -0
  99. package/lib/loop/core/index.js +3 -0
  100. package/lib/loop/embed/AppEmbed.d.ts +11 -3
  101. package/lib/loop/embed/AppEmbed.js +42 -16
  102. package/lib/loop/embed/element.d.ts +5 -0
  103. package/lib/loop/embed/element.js +61 -5
  104. package/lib/loop/embed/embedConfig.d.ts +8 -0
  105. package/lib/loop/embed/embedConfig.js +18 -0
  106. package/lib/loop/embed/hostBridge.d.ts +28 -2
  107. package/lib/loop/embed/hostBridge.js +22 -2
  108. package/lib/loop/index.d.ts +4 -3
  109. package/lib/loop/index.js +4 -3
  110. package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
  111. package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
  112. package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
  113. package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
  114. package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
  115. package/lib/loop/plugins/app-components/index.d.ts +26 -0
  116. package/lib/loop/plugins/app-components/index.js +56 -0
  117. package/lib/loop/plugins/app-elements/AppElements.js +4 -1
  118. package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
  119. package/lib/loop/plugins/app-page/AppPage.js +106 -8
  120. package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
  121. package/lib/loop/plugins/app-page/appPageModel.js +120 -4
  122. package/lib/loop/plugins/app-page/index.d.ts +1 -0
  123. package/lib/loop/plugins/app-page/index.js +1 -0
  124. package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
  125. package/lib/loop/plugins/app-page/pageRun.js +111 -0
  126. package/lib/loop/plugins/assistant/index.js +8 -6
  127. package/lib/loop/plugins/chat/ChatView.js +6 -4
  128. package/lib/loop/plugins/chat/index.d.ts +1 -1
  129. package/lib/loop/plugins/chat/index.js +2 -1
  130. package/lib/models/PageTag.d.ts +1 -1
  131. package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
  132. package/lib/specs/actions.js +78 -1
  133. package/lib/specs/apps.d.ts +5 -0
  134. package/lib/specs/apps.js +1384 -231
  135. package/lib/specs/appspecSchema.js +191 -1
  136. package/lib/specs/index.d.ts +1 -0
  137. package/lib/specs/index.js +1 -0
  138. package/lib/specs/mcpServers.js +8 -2
  139. package/lib/specs/scenes.d.ts +21 -0
  140. package/lib/specs/scenes.js +1191 -0
  141. package/lib/specs/teams/teams.d.ts +3 -0
  142. package/lib/specs/teams/teams.js +249 -0
  143. package/lib/types/agentspecs.d.ts +70 -0
  144. package/lib/types/chat.d.ts +6 -5
  145. package/lib/types/index.d.ts +1 -0
  146. package/lib/types/index.js +1 -0
  147. package/lib/types/scenes.d.ts +207 -0
  148. package/lib/types/scenes.js +5 -0
  149. package/lib/types/teams.d.ts +13 -2
  150. package/package.json +4 -4
  151. package/scripts/codegen/generate_agents.py +1 -0
  152. package/scripts/codegen/generate_apps.py +4 -2
  153. package/scripts/codegen/generate_scenes.py +301 -0
  154. package/scripts/codegen/generate_teams.py +15 -2
  155. package/lib/components/inspector/JsonTree.d.ts +0 -24
  156. package/lib/components/inspector/JsonTree.js +0 -89
  157. package/lib/components/inspector/a2aInspect.d.ts +0 -56
  158. package/lib/components/inspector/a2aInspect.js +0 -478
  159. package/lib/components/inspector/agentInspector.d.ts +0 -179
  160. package/lib/components/inspector/agentInspector.js +0 -267
  161. package/lib/components/inspector/chatInspect.d.ts +0 -38
  162. package/lib/components/inspector/chatInspect.js +0 -65
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The transcript of a scene, drawn (LOOP A-06): the lines
3
+ * {@link transcriptOfSpans} or {@link transcriptOfRecord} built, each with
4
+ * its time, who speaks or acts and to whom, and the words or the tool —
5
+ * and *Copy as text*, which copies them with their times
6
+ * ({@link transcriptText}).
7
+ *
8
+ * @module components/teams/SceneTranscript
9
+ */
10
+ import type { JSX } from 'react';
11
+ import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
12
+ import { type SceneTranscriptLine, type SceneTranscriptMember } from './sceneTranscript';
13
+ /** The transcript of a tracer's spans, kept current as they change. */
14
+ export declare function useSceneTranscript(tracer: OtelLiveTracer | null | undefined, members: readonly SceneTranscriptMember[]): SceneTranscriptLine[];
15
+ export type SceneTranscriptProps = {
16
+ /** The lines, in order. */
17
+ lines: readonly SceneTranscriptLine[];
18
+ /** What is said while there is no line yet. */
19
+ emptyText?: string;
20
+ /** How tall it grows before it scrolls, in pixels. */
21
+ maxHeight?: number;
22
+ /** Whether *Copy as text* is offered (it is, when there is a line). */
23
+ copy?: boolean;
24
+ /** The clipboard: `navigator.clipboard.writeText` unless a test gives one. */
25
+ writeText?: (text: string) => Promise<void>;
26
+ };
27
+ /** The transcript as a list of lines, newest last, with *Copy as text*. */
28
+ export declare function SceneTranscript({ lines, emptyText, maxHeight, copy, writeText, }: SceneTranscriptProps): JSX.Element;
29
+ export default SceneTranscript;
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from 'react';
3
+ import { Button, Text } from '@primer/react';
4
+ import { Box } from '@datalayer/primer-addons';
5
+ import { useOtelLiveSpans } from '@datalayer/core/lib/otel/live';
6
+ import { lineHeading, timeText, transcriptOfSpans, transcriptText, } from './sceneTranscript';
7
+ /** The transcript of a tracer's spans, kept current as they change. */
8
+ export function useSceneTranscript(tracer, members) {
9
+ const spans = useOtelLiveSpans(tracer);
10
+ return useMemo(() => transcriptOfSpans(spans, members), [spans, members]);
11
+ }
12
+ /** How long *Copied* stays, in milliseconds. */
13
+ const COPIED_MS = 1500;
14
+ /** The transcript as a list of lines, newest last, with *Copy as text*. */
15
+ export function SceneTranscript({ lines, emptyText = 'What the scene says and does shows here, line by line.', maxHeight, copy = true, writeText, }) {
16
+ const [copied, setCopied] = useState(false);
17
+ const onCopy = async () => {
18
+ const write = writeText ??
19
+ (text => globalThis.navigator?.clipboard?.writeText(text) ?? Promise.resolve());
20
+ try {
21
+ await write(transcriptText(lines));
22
+ setCopied(true);
23
+ setTimeout(() => setCopied(false), COPIED_MS);
24
+ }
25
+ catch {
26
+ // The clipboard refused: nothing to say but the text, still on screen.
27
+ }
28
+ };
29
+ return (_jsxs(Box, { "data-scene-transcript": "", "data-scene-lines": lines.length, children: [lines.length === 0 ? (_jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: emptyText })) : (_jsx(Box, { as: "ol", "aria-label": "Transcript", sx: {
30
+ listStyle: 'none',
31
+ m: 0,
32
+ p: 0,
33
+ fontSize: 1,
34
+ ...(maxHeight ? { maxHeight, overflowY: 'auto' } : {}),
35
+ }, children: lines.map(line => (_jsxs(Box, { as: "li", "data-transcript-line": line.kind, "data-transcript-from": line.from, "data-transcript-to": line.to, "aria-busy": line.open ? 'true' : undefined, sx: {
36
+ display: 'grid',
37
+ gridTemplateColumns: 'auto 1fr',
38
+ gap: 2,
39
+ py: 1,
40
+ borderBottom: '1px solid',
41
+ borderColor: 'border.muted',
42
+ opacity: line.open ? 0.75 : 1,
43
+ }, children: [_jsx(Text, { as: "time", sx: {
44
+ color: 'fg.muted',
45
+ fontFamily: 'mono',
46
+ fontSize: 0,
47
+ pt: '2px',
48
+ whiteSpace: 'nowrap',
49
+ }, dateTime: new Date(line.at).toISOString(), children: timeText(line.at) }), _jsxs(Box, { sx: { minWidth: 0, overflowWrap: 'anywhere' }, children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsxs(Text, { sx: {
50
+ fontFamily: line.kind === 'called' ? 'mono' : undefined,
51
+ color: line.failed ? 'danger.fg' : undefined,
52
+ }, children: [line.text, line.open ? '…' : '', line.failed ? ' (failed)' : ''] })] })] }, line.key))) })), copy && lines.length > 0 && (_jsx(Box, { sx: { mt: 2 }, children: _jsx(Button, { size: "small", onClick: () => void onCopy(), "data-transcript-copy": "", children: copied ? 'Copied' : 'Copy as text' }) }))] }));
53
+ }
54
+ export default SceneTranscript;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * A scene on a page: its graph (`A2ATeamGraph`) and its transcript
3
+ * ({@link SceneTranscript}), one shown at a time behind a *Graph · Transcript*
4
+ * toggle (LOOP A-06). The graph stays mounted while the transcript shows, so
5
+ * that what its members were doing is still there when it comes back.
6
+ *
7
+ * The lines come from the Agent Inspector's tracer the graph's members
8
+ * record into (`tracer`, with the `members` to name them), or are given
9
+ * (`lines`: a finished run's, from its record).
10
+ *
11
+ * @module components/teams/SceneView
12
+ */
13
+ import type { JSX, ReactNode } from 'react';
14
+ import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
15
+ import type { SceneTranscriptLine, SceneTranscriptMember } from './sceneTranscript';
16
+ /** Which of the two the scene shows. */
17
+ export type SceneViewChoice = 'graph' | 'transcript';
18
+ export type SceneViewProps = {
19
+ /** The graph: an `A2ATeamGraph`, or whatever draws the scene. */
20
+ children: ReactNode;
21
+ /** The members, to name the spans' services and their connections. */
22
+ members?: readonly SceneTranscriptMember[];
23
+ /** The tracer the members record into: the transcript is read from it. */
24
+ tracer?: OtelLiveTracer | null;
25
+ /** The lines, given: a finished run's. Wins over `tracer`. */
26
+ lines?: readonly SceneTranscriptLine[];
27
+ /** What shows first: the graph unless said. */
28
+ defaultView?: SceneViewChoice;
29
+ /** The choice, held by the page; with `onViewChange`. */
30
+ view?: SceneViewChoice;
31
+ onViewChange?: (view: SceneViewChoice) => void;
32
+ /** What the transcript says while there is no line yet. */
33
+ emptyText?: string;
34
+ /** How tall the transcript grows before it scrolls, in pixels. */
35
+ maxHeight?: number;
36
+ /** Something of the page's beside the toggle: a clock, a line. */
37
+ aside?: ReactNode;
38
+ };
39
+ /** The graph and the transcript of a scene, behind a *Graph · Transcript* toggle. */
40
+ export declare function SceneView({ children, members, tracer, lines, defaultView, view, onViewChange, emptyText, maxHeight, aside, }: SceneViewProps): JSX.Element;
41
+ export default SceneView;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { SegmentedControl } from '@primer/react';
4
+ import { Box } from '@datalayer/primer-addons';
5
+ import { SceneTranscript, useSceneTranscript } from './SceneTranscript';
6
+ const NO_MEMBERS = [];
7
+ /** The graph and the transcript of a scene, behind a *Graph · Transcript* toggle. */
8
+ export function SceneView({ children, members = NO_MEMBERS, tracer, lines, defaultView = 'graph', view, onViewChange, emptyText, maxHeight = 360, aside, }) {
9
+ const [own, setOwn] = useState(defaultView);
10
+ const shown = view ?? own;
11
+ const choose = (next) => {
12
+ setOwn(next);
13
+ onViewChange?.(next);
14
+ };
15
+ const live = useSceneTranscript(lines ? null : tracer, members);
16
+ const transcript = lines ?? live;
17
+ return (_jsxs(Box, { "data-scene-view": shown, children: [_jsxs(Box, { sx: {
18
+ display: 'flex',
19
+ alignItems: 'center',
20
+ justifyContent: 'space-between',
21
+ gap: 2,
22
+ flexWrap: 'wrap',
23
+ mb: 2,
24
+ }, children: [_jsxs(SegmentedControl, { "aria-label": "Scene view", size: "small", children: [_jsx(SegmentedControl.Button, { selected: shown === 'graph', onClick: () => choose('graph'), "data-scene-choice": "graph", children: "Graph" }), _jsx(SegmentedControl.Button, { selected: shown === 'transcript', onClick: () => choose('transcript'), "data-scene-choice": "transcript", children: transcript.length
25
+ ? `Transcript (${transcript.length})`
26
+ : 'Transcript' })] }), aside] }), _jsx(Box, { hidden: shown !== 'graph', "data-scene-graph": "", children: children }), shown === 'transcript' && (_jsx(SceneTranscript, { lines: transcript, emptyText: emptyText, maxHeight: maxHeight }))] }));
27
+ }
28
+ export default SceneView;
@@ -13,3 +13,7 @@ export * from './usePeerSandbox';
13
13
  export * from './A2ATeamGraph';
14
14
  export * from './TeamNotebook';
15
15
  export * from './NotebookPreview';
16
+ export * from './sceneTranscript';
17
+ export * from './SceneTranscript';
18
+ export * from './SceneView';
19
+ export * from './sceneStage';
@@ -17,3 +17,7 @@ export * from './usePeerSandbox';
17
17
  export * from './A2ATeamGraph';
18
18
  export * from './TeamNotebook';
19
19
  export * from './NotebookPreview';
20
+ export * from './sceneTranscript';
21
+ export * from './SceneTranscript';
22
+ export * from './SceneView';
23
+ export * from './sceneStage';
@@ -0,0 +1,120 @@
1
+ /**
2
+ * A scene as a page stages it (LOOP A-13, A-15), read from the scene spec
3
+ * and its team: who is on stage and where each one stands, who asks whom
4
+ * over A2A, what the entry suggests, and where the members on a runtime are
5
+ * reached when the scene plays against local servers.
6
+ *
7
+ * Pure, so the examples app, the landing and the tests read a scene the
8
+ * same way.
9
+ *
10
+ * @module components/teams/sceneStage
11
+ */
12
+ import type { AppSpec } from '../../types/agentspecs';
13
+ import type { SceneCastMemberSpec, SceneSpec } from '../../types/scenes';
14
+ import type { TeamSpec } from '../../types/teams';
15
+ /** Who talks to whom over A2A: an edge of the team's graph. */
16
+ export type A2ATeamLink = {
17
+ /** The member that asks, by its id. */
18
+ from: string;
19
+ /** The member asked. */
20
+ to: string;
21
+ };
22
+ /** A reference without its version: `accounting:0.0.1` is `accounting`. */
23
+ export declare function refId(ref: string): string;
24
+ /** The application a cast member is, from the catalogue, or undefined. */
25
+ export declare function appOfMember(member: Pick<SceneCastMemberSpec, 'app'>): AppSpec | undefined;
26
+ /**
27
+ * The links of a team over A2A, in the order its members say them: each
28
+ * member's `talks_to … over: a2a`. A link to a server (over `mcp`) is a
29
+ * connection, drawn under the member, not an edge between members.
30
+ */
31
+ export declare function teamLinksOf(team: Pick<TeamSpec, 'agents'> | Pick<SceneSpec, 'cast'>): A2ATeamLink[];
32
+ /** A suggestion the entry offers: a label on its chip, and what is sent. */
33
+ export type SceneSuggestion = {
34
+ label: string;
35
+ prompt: string;
36
+ };
37
+ /**
38
+ * The entry's suggestions: the script's cues, each labelled by the starter
39
+ * of the entry's Appspec that says the same words, or by its first words.
40
+ * Without a scene, the starters themselves.
41
+ */
42
+ export declare function sceneCuesOf(scene: Pick<SceneSpec, 'script'> | undefined, starters: readonly {
43
+ label: string;
44
+ message: string;
45
+ }[]): SceneSuggestion[];
46
+ /** One member of a scene, as a page stages it. */
47
+ export type SceneStageMember = {
48
+ /** Its id in the cast. */
49
+ id: string;
50
+ /** The application it is. */
51
+ app: AppSpec;
52
+ cast: SceneCastMemberSpec;
53
+ /** Whether it is the member the audience talks to. */
54
+ entry: boolean;
55
+ /** Where its loop turns. */
56
+ runsIn: 'browser' | 'runtime';
57
+ /** The variable its address is read from, when it runs on a runtime. */
58
+ addressVariable?: string;
59
+ /** Where it stands: fractions of the box, from the stage directions. */
60
+ position?: {
61
+ x: number;
62
+ y: number;
63
+ };
64
+ /** What its application needs that is not set up, in sentences. */
65
+ setup: string[];
66
+ };
67
+ /** A scene as a page stages it. */
68
+ export type SceneStage = {
69
+ scene: SceneSpec;
70
+ entry: SceneStageMember;
71
+ /** The members the entry asks over A2A, in the cast's order. */
72
+ peers: SceneStageMember[];
73
+ /** Every member, the entry first. */
74
+ members: SceneStageMember[];
75
+ /** The edges between members: the team's `talks_to` over A2A. */
76
+ links: A2ATeamLink[];
77
+ /** Where each member stands, by its id. */
78
+ positions: Record<string, {
79
+ x: number;
80
+ y: number;
81
+ }>;
82
+ /** Whose balloon opens first. */
83
+ opensFirst: string;
84
+ /** What the audience is told: the line under the title. */
85
+ assumes: string;
86
+ };
87
+ /**
88
+ * Read a scene's stage: its members with their applications, who the entry
89
+ * is and whom it asks, the links, the positions. Refused when a cast member
90
+ * is an application the catalogue does not have, or the entry is not in the
91
+ * cast: a page cannot stage what it cannot draw.
92
+ */
93
+ export declare function sceneStageOf(scene: SceneSpec): SceneStage;
94
+ /** The port the examples serve Accounting on, as `npm run examples` starts it. */
95
+ export declare const ACCOUNTING_PORT = 8767;
96
+ /** The first port `serve_scenes.py` starts a runtime on for the other members. */
97
+ export declare const SCENE_PORTS_FROM = 8768;
98
+ /**
99
+ * The members on a runtime across the catalogue's scenes, each once, in
100
+ * the catalogue's order (a scene's cast in its order): what
101
+ * `examples/sales-accounting-a2a/serve_scenes.py` serves, in that order.
102
+ */
103
+ export declare function sceneRuntimeMembers(scenes?: readonly SceneSpec[]): string[];
104
+ /**
105
+ * The port each runtime member is served on locally: Accounting on
106
+ * {@link ACCOUNTING_PORT}, the others from {@link SCENE_PORTS_FROM} on, in
107
+ * the order of {@link sceneRuntimeMembers}. `serve_scenes.py` gives the
108
+ * same ports by the same rule.
109
+ */
110
+ export declare function sceneRuntimePorts(scenes?: readonly SceneSpec[]): Record<string, number>;
111
+ /** The variable the examples read a member's local address from: `VITE_A2A_CHANGE_DETECTION_URL`. */
112
+ export declare function sceneAddressVariable(appId: string): string;
113
+ /** Where a member is served over A2A on a local runtime at `port`. */
114
+ export declare function localA2AUrl(appId: string, port: number): string;
115
+ /**
116
+ * Where a member on a runtime is reached by the examples: its variable
117
+ * (`VITE_A2A_<MEMBER>_URL`) when set in `env`, else the local runtime
118
+ * `serve_scenes.py` serves it on.
119
+ */
120
+ export declare function sceneMemberUrl(appId: string, env: Record<string, string | undefined>, ports?: Record<string, number>): string;
@@ -0,0 +1,170 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { APP_CATALOGUE } from '../../specs/apps';
6
+ import { listSceneSpecs } from '../../specs/scenes';
7
+ /** A reference without its version: `accounting:0.0.1` is `accounting`. */
8
+ export function refId(ref) {
9
+ const at = ref.lastIndexOf(':');
10
+ return at > 0 && ref.slice(at + 1).includes('.') ? ref.slice(0, at) : ref;
11
+ }
12
+ /** The application a cast member is, from the catalogue, or undefined. */
13
+ export function appOfMember(member) {
14
+ const id = refId(member.app);
15
+ return id && Object.prototype.hasOwnProperty.call(APP_CATALOGUE, id)
16
+ ? APP_CATALOGUE[id]
17
+ : undefined;
18
+ }
19
+ /**
20
+ * The links of a team over A2A, in the order its members say them: each
21
+ * member's `talks_to … over: a2a`. A link to a server (over `mcp`) is a
22
+ * connection, drawn under the member, not an edge between members.
23
+ */
24
+ export function teamLinksOf(team) {
25
+ const members = 'cast' in team
26
+ ? team.cast.map(member => ({
27
+ id: member.member,
28
+ talksTo: member.talksTo,
29
+ }))
30
+ : team.agents;
31
+ return members.flatMap(member => (member.talksTo ?? [])
32
+ .filter(link => link.over === 'a2a')
33
+ .map(link => ({ from: member.id, to: link.member })));
34
+ }
35
+ /**
36
+ * The entry's suggestions: the script's cues, each labelled by the starter
37
+ * of the entry's Appspec that says the same words, or by its first words.
38
+ * Without a scene, the starters themselves.
39
+ */
40
+ export function sceneCuesOf(scene, starters) {
41
+ const fromStarters = starters.map(starter => ({
42
+ label: starter.label,
43
+ prompt: starter.message,
44
+ }));
45
+ if (!scene) {
46
+ return fromStarters;
47
+ }
48
+ return scene.script
49
+ .map(beat => beat.cue.say.trim())
50
+ .filter(Boolean)
51
+ .map(prompt => ({
52
+ label: fromStarters.find(starter => starter.prompt === prompt)?.label ??
53
+ prompt.split(/\s+/).slice(0, 4).join(' '),
54
+ prompt,
55
+ }));
56
+ }
57
+ /**
58
+ * Read a scene's stage: its members with their applications, who the entry
59
+ * is and whom it asks, the links, the positions. Refused when a cast member
60
+ * is an application the catalogue does not have, or the entry is not in the
61
+ * cast: a page cannot stage what it cannot draw.
62
+ */
63
+ export function sceneStageOf(scene) {
64
+ const members = scene.cast
65
+ .filter(member => member.app)
66
+ .map((member) => {
67
+ const app = appOfMember(member);
68
+ if (!app) {
69
+ throw new Error(`The scene ${scene.id} casts ${member.member} as ${member.app}, which the catalogue does not have.`);
70
+ }
71
+ const position = scene.stage.positions[member.member];
72
+ const variable = scene.deployment.addresses[member.member];
73
+ return {
74
+ id: member.member,
75
+ app,
76
+ cast: member,
77
+ entry: member.member === scene.entry,
78
+ runsIn: member.runsIn ?? 'runtime',
79
+ ...(variable ? { addressVariable: variable } : {}),
80
+ ...(position ? { position } : {}),
81
+ setup: app.setup ?? [],
82
+ };
83
+ });
84
+ const entry = members.find(member => member.entry);
85
+ if (!entry) {
86
+ throw new Error(`The scene ${scene.id} says its entry is ${scene.entry}, which is not in its cast.`);
87
+ }
88
+ const links = teamLinksOf(scene);
89
+ const asked = links
90
+ .filter(link => link.from === entry.id)
91
+ .map(link => link.to);
92
+ const peers = members.filter(member => !member.entry && asked.includes(member.id));
93
+ return {
94
+ scene,
95
+ entry,
96
+ peers,
97
+ members: [entry, ...members.filter(member => !member.entry)],
98
+ links,
99
+ positions: scene.stage.positions,
100
+ opensFirst: scene.stage.opensFirst || entry.id,
101
+ assumes: scene.setting.assumes,
102
+ };
103
+ }
104
+ /** The port the examples serve Accounting on, as `npm run examples` starts it. */
105
+ export const ACCOUNTING_PORT = 8767;
106
+ /** The first port `serve_scenes.py` starts a runtime on for the other members. */
107
+ export const SCENE_PORTS_FROM = 8768;
108
+ /**
109
+ * The members on a runtime across the catalogue's scenes, each once, in
110
+ * the catalogue's order (a scene's cast in its order): what
111
+ * `examples/sales-accounting-a2a/serve_scenes.py` serves, in that order.
112
+ */
113
+ export function sceneRuntimeMembers(scenes = listSceneSpecs()) {
114
+ const seen = [];
115
+ for (const scene of scenes) {
116
+ for (const member of scene.cast) {
117
+ const id = refId(member.app);
118
+ if (id &&
119
+ (member.runsIn ?? 'runtime') === 'runtime' &&
120
+ !seen.includes(id)) {
121
+ seen.push(id);
122
+ }
123
+ }
124
+ }
125
+ return seen;
126
+ }
127
+ /**
128
+ * The port each runtime member is served on locally: Accounting on
129
+ * {@link ACCOUNTING_PORT}, the others from {@link SCENE_PORTS_FROM} on, in
130
+ * the order of {@link sceneRuntimeMembers}. `serve_scenes.py` gives the
131
+ * same ports by the same rule.
132
+ */
133
+ export function sceneRuntimePorts(scenes = listSceneSpecs()) {
134
+ const ports = {};
135
+ let next = SCENE_PORTS_FROM;
136
+ for (const id of sceneRuntimeMembers(scenes)) {
137
+ if (id === 'accounting') {
138
+ ports[id] = ACCOUNTING_PORT;
139
+ }
140
+ else {
141
+ ports[id] = next;
142
+ next += 1;
143
+ }
144
+ }
145
+ return ports;
146
+ }
147
+ /** The variable the examples read a member's local address from: `VITE_A2A_CHANGE_DETECTION_URL`. */
148
+ export function sceneAddressVariable(appId) {
149
+ return `VITE_A2A_${appId.replace(/-/g, '_').toUpperCase()}_URL`;
150
+ }
151
+ /** Where a member is served over A2A on a local runtime at `port`. */
152
+ export function localA2AUrl(appId, port) {
153
+ return `http://127.0.0.1:${port}/api/v1/a2a/agents/${appId}`;
154
+ }
155
+ /**
156
+ * Where a member on a runtime is reached by the examples: its variable
157
+ * (`VITE_A2A_<MEMBER>_URL`) when set in `env`, else the local runtime
158
+ * `serve_scenes.py` serves it on.
159
+ */
160
+ export function sceneMemberUrl(appId, env, ports = sceneRuntimePorts()) {
161
+ const port = ports[appId];
162
+ const set = env[sceneAddressVariable(appId)];
163
+ if (set) {
164
+ return set;
165
+ }
166
+ if (port === undefined) {
167
+ throw new Error(`${appId} runs on no local runtime the examples serve: set ${sceneAddressVariable(appId)}.`);
168
+ }
169
+ return localA2AUrl(appId, port);
170
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The transcript of a scene (LOOP A-06): what happens in it, as lines, in
3
+ * the order it happened — *Sales: …*, *Sales → Accounting: …*,
4
+ * *Accounting → Odoo: odoo_accounting_aged_balance* — each with its time.
5
+ *
6
+ * One source, read two ways. Live, the lines are read from the OpenTelemetry
7
+ * spans the Agent Inspector reads (core's live tracer): a turn is an
8
+ * `invoke_agent` span (what the person asked, what the agent answered), a
9
+ * tool call an `execute_tool` span (the member and, for an MCP call, the
10
+ * server it reaches: a connection of the member's), and a request to
11
+ * another member an `a2a` span (who asked whom, in what words, and what came
12
+ * back as its events). Once a run is over, the same lines are read from its
13
+ * record (`RecordEntry`: a `turn`, a `tool_call`), the session's entries as
14
+ * ai-agents kept them.
15
+ *
16
+ * Pure: spans or entries in, lines out, so that a test reads a scripted
17
+ * scene and a page draws a live one the same way ({@link SceneTranscript}).
18
+ *
19
+ * @module components/teams/sceneTranscript
20
+ */
21
+ import type { OtelSpan } from '@datalayer/core/lib/otel/types';
22
+ import type { RecordEntry } from '../../loop/apps/records';
23
+ import { type A2ATeamConnection } from './a2aTeamFlow';
24
+ /** A member of the scene, as the transcript names it. */
25
+ export type SceneTranscriptMember = {
26
+ /** Its id in the team: `accounting`. */
27
+ id: string;
28
+ /** Its name, the service its spans are done by: `Accounting`. */
29
+ name: string;
30
+ /** The MCP servers it reaches: a call to one of their tools is `Member → Server: tool`. */
31
+ connections?: readonly A2ATeamConnection[];
32
+ };
33
+ /** What a line is: words said, a question asked, a tool called. */
34
+ export type SceneTranscriptKind = 'said' | 'asked' | 'called';
35
+ /** One line of the transcript. */
36
+ export type SceneTranscriptLine = {
37
+ /** Stable, for a list: the span's or the entry's id, and which of its lines. */
38
+ key: string;
39
+ /** When, in milliseconds since the epoch. */
40
+ at: number;
41
+ /** Who speaks or acts: a member's name, or the person ({@link PERSON}). */
42
+ from: string;
43
+ /** Who is asked or called: a member, or a server (`Odoo`); none when words are said to all. */
44
+ to?: string;
45
+ kind: SceneTranscriptKind;
46
+ /** The words, or the tool's name. */
47
+ text: string;
48
+ /** Still happening: the call runs, the answer has not come. */
49
+ open?: boolean;
50
+ /** It failed: the span's status, the task's state. */
51
+ failed?: boolean;
52
+ };
53
+ /** The person in the scene, as the transcript names them. */
54
+ export declare const PERSON = "You";
55
+ /**
56
+ * The transcript of a scene from the spans recorded while it works (the
57
+ * Agent Inspector's, one tracer for every member).
58
+ */
59
+ export declare function transcriptOfSpans(spans: readonly OtelSpan[], members: readonly SceneTranscriptMember[]): SceneTranscriptLine[];
60
+ /**
61
+ * The transcript of one member's run once it is over, from its record: a
62
+ * `turn` is what the person asked and what it answered, a `tool_call` what
63
+ * it called in between. The calls of a turn are recorded before the turn
64
+ * itself (at its close), so the question is placed where the turn began.
65
+ */
66
+ export declare function transcriptOfRecord(entries: readonly RecordEntry[], member: SceneTranscriptMember): SceneTranscriptLine[];
67
+ /** A line's time, as a clock reads it: `14:03:27`. */
68
+ export declare function timeText(at: number): string;
69
+ /** Who a line is from and to: `Sales`, `Sales → Accounting`, `Accounting → Odoo`. */
70
+ export declare function lineHeading(line: Pick<SceneTranscriptLine, 'from' | 'to' | 'kind'>): string;
71
+ /** A line in words: `Sales → Accounting: Which invoices are open?`. */
72
+ export declare function lineText(line: SceneTranscriptLine): string;
73
+ /** The transcript as text, one line each with its time: what *Copy as text* copies. */
74
+ export declare function transcriptText(lines: readonly SceneTranscriptLine[]): string;