@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,253 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * What agents do in the page, as OpenTelemetry spans: the record the Agent
7
+ * Inspector reads. A turn is an `invoke_agent` span, each tool call an
8
+ * `execute_tool` span under it — the GenAI semantic conventions the runtime's
9
+ * own spans follow (pydantic-ai's): `gen_ai.operation.name`,
10
+ * `gen_ai.agent.name`, `gen_ai.request.model`, `gen_ai.tool.name`,
11
+ * `gen_ai.tool.call.id`, `gen_ai.tool.call.arguments` and `.result` (JSON
12
+ * text), `gen_ai.input.messages` and `gen_ai.output.messages`, the
13
+ * `gen_ai.usage.*` tokens. An agent is a service: `service.name` is its name.
14
+ *
15
+ * Where a tool comes from — an MCP server, the page (a frontend tool), a
16
+ * skill, codemode, the runtime — no convention says: `datalayer.tool.kind`
17
+ * does, beside `gen_ai.tool.type`, with the tool's marks
18
+ * (`datalayer.mark.icon`, `datalayer.mark.emoji`).
19
+ *
20
+ * The tracer is core's (`createOtelLiveTracer`): one a page, shared by its
21
+ * chats and its team (`AgentInspectorProvider`, or the `inspector` prop).
22
+ *
23
+ * @module components/inspector/agentSpans
24
+ */
25
+ import { createContext, createElement, useContext, useState, } from 'react';
26
+ import { createOtelLiveTracer, } from '@datalayer/core/lib/otel/live';
27
+ /** The attributes the record uses: the GenAI conventions, and a few of Datalayer's. */
28
+ export const AGENT_SPAN_ATTRIBUTES = {
29
+ operation: 'gen_ai.operation.name',
30
+ agentName: 'gen_ai.agent.name',
31
+ conversationId: 'gen_ai.conversation.id',
32
+ requestModel: 'gen_ai.request.model',
33
+ inputMessages: 'gen_ai.input.messages',
34
+ outputMessages: 'gen_ai.output.messages',
35
+ inputTokens: 'gen_ai.usage.input_tokens',
36
+ outputTokens: 'gen_ai.usage.output_tokens',
37
+ toolName: 'gen_ai.tool.name',
38
+ toolCallId: 'gen_ai.tool.call.id',
39
+ toolArguments: 'gen_ai.tool.call.arguments',
40
+ toolResult: 'gen_ai.tool.call.result',
41
+ toolType: 'gen_ai.tool.type',
42
+ /** `mcp`, `frontend`, `skill`, `codemode`, `runtime`. */
43
+ toolKind: 'datalayer.tool.kind',
44
+ markIcon: 'datalayer.mark.icon',
45
+ markEmoji: 'datalayer.mark.emoji',
46
+ /** How the page knows of a span another process did: `a2a.status`. */
47
+ origin: 'datalayer.span.origin',
48
+ errorType: 'error.type',
49
+ };
50
+ const A = AGENT_SPAN_ATTRIBUTES;
51
+ /** Every kind, in the order the filters list them. */
52
+ export const AGENT_TOOL_KINDS = [
53
+ 'mcp',
54
+ 'frontend',
55
+ 'skill',
56
+ 'codemode',
57
+ 'runtime',
58
+ ];
59
+ /** A value as an attribute carries it: JSON text. */
60
+ export function jsonAttribute(value) {
61
+ if (value === undefined) {
62
+ return undefined;
63
+ }
64
+ try {
65
+ return JSON.stringify(value);
66
+ }
67
+ catch {
68
+ return String(value);
69
+ }
70
+ }
71
+ /** A line short enough for a row. */
72
+ export function shortLine(text, length = 160) {
73
+ const flat = text.replace(/\s+/g, ' ').trim();
74
+ return flat.length > length ? `${flat.slice(0, length - 1)}…` : flat;
75
+ }
76
+ /** A call's arguments, in a few words: `kind=customer, limit=100`. */
77
+ export function argumentsLine(args, length = 100) {
78
+ if (!args || typeof args !== 'object') {
79
+ return args === undefined ? '' : shortLine(String(args), length);
80
+ }
81
+ const parts = Object.entries(args).map(([key, value]) => `${key}=${typeof value === 'string' ? value : JSON.stringify(value)}`);
82
+ return shortLine(parts.join(', '), length);
83
+ }
84
+ /** A message in the GenAI conventions' shape: its role and its text part. */
85
+ function messages(role, text) {
86
+ return JSON.stringify([{ role, parts: [{ type: 'text', content: text }] }]);
87
+ }
88
+ /** A turn of an agent: from the question to the answer. */
89
+ export function startAgentTurn(tracer, turn) {
90
+ return tracer.startSpan(`invoke_agent ${turn.agent}`, {
91
+ serviceName: turn.agent,
92
+ parent: null,
93
+ attributes: {
94
+ [A.operation]: 'invoke_agent',
95
+ [A.agentName]: turn.agent,
96
+ [A.requestModel]: turn.model || undefined,
97
+ [A.conversationId]: turn.conversationId,
98
+ [A.inputMessages]: messages('user', turn.prompt),
99
+ },
100
+ });
101
+ }
102
+ /** End a turn: its answer, its tokens, or its error. */
103
+ export function endAgentTurn(span, outcome) {
104
+ const usage = outcome.usage;
105
+ span.setAttributes({
106
+ [A.outputMessages]: outcome.text
107
+ ? messages('assistant', outcome.text)
108
+ : undefined,
109
+ [A.inputTokens]: usage?.inputTokens ?? usage?.promptTokens,
110
+ [A.outputTokens]: usage?.outputTokens ?? usage?.completionTokens,
111
+ });
112
+ if (outcome.error) {
113
+ span.setAttribute(A.errorType, 'error');
114
+ span.recordException(new Error(outcome.error));
115
+ }
116
+ else {
117
+ span.setStatus('OK');
118
+ }
119
+ span.end();
120
+ }
121
+ /** `gen_ai.tool.type` for a kind: an MCP server's tool is an extension. */
122
+ function toolType(kind) {
123
+ return kind === 'mcp' ? 'extension' : 'function';
124
+ }
125
+ /** A tool call: its name, id, arguments, kind and marks. */
126
+ export function startToolCall(tracer, call) {
127
+ return tracer.startSpan(`execute_tool ${call.name}`, {
128
+ serviceName: call.agent,
129
+ ...(call.parent ? { parent: call.parent } : {}),
130
+ attributes: {
131
+ [A.operation]: 'execute_tool',
132
+ [A.agentName]: call.agent,
133
+ [A.toolName]: call.name,
134
+ [A.toolCallId]: call.id,
135
+ [A.toolArguments]: jsonAttribute(call.args ?? {}),
136
+ [A.toolType]: toolType(call.tool.kind),
137
+ [A.toolKind]: call.tool.kind,
138
+ [A.markIcon]: call.tool.icon,
139
+ [A.markEmoji]: call.tool.emoji,
140
+ [A.origin]: call.origin,
141
+ },
142
+ });
143
+ }
144
+ /** End a tool call: its result, or its error. */
145
+ export function endToolCall(span, outcome) {
146
+ span.setAttribute(A.toolResult, jsonAttribute(outcome.result));
147
+ if (outcome.error) {
148
+ span.setAttribute(A.errorType, 'tool_error');
149
+ span.recordException(new Error(outcome.error));
150
+ }
151
+ else {
152
+ span.setStatus('OK');
153
+ }
154
+ span.end();
155
+ }
156
+ /** Where a span comes from, for the Inspector's *Source* filter. */
157
+ export function sourceOfSpan(span) {
158
+ const attributes = span.attributes ?? {};
159
+ if (attributes[A.toolKind]) {
160
+ return String(attributes[A.toolKind]);
161
+ }
162
+ if (attributes['rpc.service'] === 'a2a' ||
163
+ span.span_name.startsWith('a2a ')) {
164
+ return 'a2a';
165
+ }
166
+ if (attributes[A.operation] === 'invoke_agent') {
167
+ return 'model';
168
+ }
169
+ return undefined;
170
+ }
171
+ /** A source, in words. */
172
+ export const SPAN_SOURCE_LABELS = {
173
+ a2a: 'A2A',
174
+ mcp: 'MCP',
175
+ frontend: 'Frontend tool',
176
+ skill: 'Skill',
177
+ codemode: 'Codemode',
178
+ runtime: 'Runtime tool',
179
+ model: 'Model',
180
+ };
181
+ /** The text of the first message of a GenAI messages attribute. */
182
+ function messageText(value) {
183
+ if (typeof value !== 'string') {
184
+ return '';
185
+ }
186
+ try {
187
+ const parsed = JSON.parse(value);
188
+ return (parsed[0]?.parts ?? [])
189
+ .map(part => (typeof part.content === 'string' ? part.content : ''))
190
+ .join('');
191
+ }
192
+ catch {
193
+ return '';
194
+ }
195
+ }
196
+ /** One line that says what a span carried: a call's arguments, a turn's question and answer, a message's words. */
197
+ export function describeAgentSpan(span) {
198
+ const attributes = span.attributes ?? {};
199
+ const operation = attributes[A.operation];
200
+ if (operation === 'execute_tool') {
201
+ let args;
202
+ try {
203
+ args = JSON.parse(String(attributes[A.toolArguments] ?? '{}'));
204
+ }
205
+ catch {
206
+ args = attributes[A.toolArguments];
207
+ }
208
+ return argumentsLine(args) || undefined;
209
+ }
210
+ if (operation === 'invoke_agent') {
211
+ const asked = messageText(attributes[A.inputMessages]);
212
+ const said = messageText(attributes[A.outputMessages]);
213
+ const input = Number(attributes[A.inputTokens] ?? 0);
214
+ const output = Number(attributes[A.outputTokens] ?? 0);
215
+ const tokens = input + output ? ` · ${input + output} tokens` : '';
216
+ return (shortLine(said ? `${shortLine(asked, 60)} → ${said}` : asked) + tokens);
217
+ }
218
+ const text = attributes['a2a.message.text'];
219
+ const state = attributes['a2a.task.state'];
220
+ const words = [
221
+ typeof state === 'string' ? stateWord(state) : '',
222
+ typeof text === 'string' ? shortLine(text) : '',
223
+ ].filter(Boolean);
224
+ if (words.length) {
225
+ return words.join(' · ');
226
+ }
227
+ const skills = attributes['a2a.agent.skills'];
228
+ return Array.isArray(skills) ? skills.join(', ') : undefined;
229
+ }
230
+ /** `TASK_STATE_WORKING` is `working`. */
231
+ export function stateWord(state) {
232
+ return typeof state === 'string'
233
+ ? state
234
+ .replace(/^TASK_STATE_/, '')
235
+ .toLowerCase()
236
+ .replace(/_/g, ' ')
237
+ : '';
238
+ }
239
+ /** A tracer for a page, made once (or the one given). */
240
+ export function useAgentInspector(given) {
241
+ const [own] = useState(() => given ?? createOtelLiveTracer({ serviceName: 'Agent' }));
242
+ return { tracer: given ?? own };
243
+ }
244
+ /** The tracer the chats under it record into. */
245
+ export const AgentInspectorContext = createContext(null);
246
+ /** The tracer of the nearest {@link AgentInspectorProvider}, if any. */
247
+ export function useAgentInspectorTracer() {
248
+ return useContext(AgentInspectorContext);
249
+ }
250
+ /** Every chat under it records what its agent does into `tracer`. */
251
+ export function AgentInspectorProvider({ tracer, children, }) {
252
+ return createElement(AgentInspectorContext.Provider, { value: tracer }, children);
253
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * A chat's agent, as OpenTelemetry spans: each turn an `invoke_agent` span
3
+ * (the prompt, the answer, the tokens), each tool call an `execute_tool` span
4
+ * under it from its start to its end — an MCP server's, a skill, a frontend
5
+ * tool the page runs, codemode's, a tool the runtime runs — whatever
6
+ * transport the chat speaks (AG-UI, Vercel AI, A2A, the in-browser harness):
7
+ * `ChatBase` tells it what its adapter told.
8
+ *
9
+ * @module components/inspector/chatSpans
10
+ */
11
+ import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
12
+ import type { MarkedMcpServer } from '../../chat/marks/toolMarks';
13
+ import { type TurnUsage } from './agentSpans';
14
+ export type ChatSpanRecorder = {
15
+ turnStarted: (prompt: string, model?: string) => void;
16
+ turnEnded: (outcome: {
17
+ text?: string;
18
+ usage?: TurnUsage;
19
+ error?: string;
20
+ }) => void;
21
+ toolStarted: (call: {
22
+ id: string;
23
+ name: string;
24
+ args: Record<string, unknown>;
25
+ }) => void;
26
+ toolEnded: (id: string, outcome: {
27
+ result?: unknown;
28
+ error?: string;
29
+ }) => void;
30
+ };
31
+ /** A recorder for one chat's agent (`agent`) into `tracer`. */
32
+ export declare function chatSpanRecorder(tracer: OtelLiveTracer, agent: () => string, options?: {
33
+ /** The page's own tools, by name: frontend tools. */
34
+ frontendTools?: () => readonly string[];
35
+ mcpServers?: () => readonly MarkedMcpServer[];
36
+ }): ChatSpanRecorder;
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { endAgentTurn, endToolCall, startAgentTurn, startToolCall, } from './agentSpans';
6
+ import { classifyToolCall } from './classify';
7
+ /** A recorder for one chat's agent (`agent`) into `tracer`. */
8
+ export function chatSpanRecorder(tracer, agent, options = {}) {
9
+ let turn;
10
+ const tools = new Map();
11
+ return {
12
+ turnStarted(prompt, model) {
13
+ turn = startAgentTurn(tracer, { agent: agent(), prompt, model });
14
+ },
15
+ turnEnded(outcome) {
16
+ if (!turn) {
17
+ return;
18
+ }
19
+ endAgentTurn(turn, outcome);
20
+ turn = undefined;
21
+ },
22
+ toolStarted({ id, name, args }) {
23
+ const known = tools.get(id);
24
+ if (known) {
25
+ // Arguments that stream in: the latest whole.
26
+ known.setAttribute('gen_ai.tool.call.arguments', JSON.stringify(args ?? {}));
27
+ return;
28
+ }
29
+ tools.set(id, startToolCall(tracer, {
30
+ agent: agent(),
31
+ name,
32
+ id,
33
+ args,
34
+ tool: classifyToolCall(name, args, {
35
+ frontendTools: options.frontendTools?.(),
36
+ mcpServers: options.mcpServers?.(),
37
+ }),
38
+ ...(turn ? { parent: turn.context } : {}),
39
+ }));
40
+ },
41
+ toolEnded(id, outcome) {
42
+ const span = tools.get(id);
43
+ if (!span) {
44
+ return;
45
+ }
46
+ tools.delete(id);
47
+ endToolCall(span, outcome);
48
+ },
49
+ };
50
+ }
@@ -1,19 +1,22 @@
1
1
  /**
2
- * Where a tool call comes from, for the Agent Inspector, by what the
3
- * catalogue says of its name. Apart from the record itself, which a page can
4
- * keep without loading the catalogues.
2
+ * Where a tool call comes from, for its span (`datalayer.tool.kind`), by
3
+ * what the catalogue says of its name. Apart from the spans themselves,
4
+ * which a page can record without loading the catalogues.
5
5
  *
6
6
  * @module components/inspector/classify
7
7
  */
8
8
  import { type MarkedMcpServer } from '../../chat/marks/toolMarks';
9
- import type { AgentInspectorSource, ToolClass } from './agentInspector';
9
+ import type { AgentToolKind, ToolClass } from './agentSpans';
10
+ /** The tools codemode exposes in place of the MCP tools it reaches. */
11
+ export declare const CODEMODE_TOOLS: ReadonlySet<string>;
10
12
  /**
11
- * Where a tool call comes from, by who claims its name: a skill, one of
12
- * `mcpServers`, a frontend tool (the catalogue's, or one of `frontendTools`),
13
- * a runtime tool; otherwise `fallback` — a tool the runtime runs.
13
+ * Where a tool call comes from, by who claims its name: a frontend tool
14
+ * (one of `frontendTools`), a skill, one of `mcpServers`, a frontend tool of
15
+ * the catalogue, a runtime tool, codemode's; otherwise `fallback` — a tool
16
+ * the runtime runs.
14
17
  */
15
18
  export declare function classifyToolCall(name: string, args?: Record<string, unknown>, options?: {
16
19
  mcpServers?: readonly MarkedMcpServer[];
17
20
  frontendTools?: readonly string[];
18
- fallback?: AgentInspectorSource;
21
+ fallback?: AgentToolKind;
19
22
  }): ToolClass;
@@ -3,39 +3,38 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  /**
6
- * Where a tool call comes from, for the Agent Inspector, by what the
7
- * catalogue says of its name. Apart from the record itself, which a page can
8
- * keep without loading the catalogues.
6
+ * Where a tool call comes from, for its span (`datalayer.tool.kind`), by
7
+ * what the catalogue says of its name. Apart from the spans themselves,
8
+ * which a page can record without loading the catalogues.
9
9
  *
10
10
  * @module components/inspector/classify
11
11
  */
12
12
  import { marksOfToolCall, } from '../../chat/marks/toolMarks';
13
+ /** The tools codemode exposes in place of the MCP tools it reaches. */
14
+ export const CODEMODE_TOOLS = new Set([
15
+ 'list_servers',
16
+ 'list_tool_names',
17
+ 'search_tools',
18
+ 'get_tool_details',
19
+ 'execute_code',
20
+ ]);
13
21
  /**
14
- * Where a tool call comes from, by who claims its name: a skill, one of
15
- * `mcpServers`, a frontend tool (the catalogue's, or one of `frontendTools`),
16
- * a runtime tool; otherwise `fallback` — a tool the runtime runs.
22
+ * Where a tool call comes from, by who claims its name: a frontend tool
23
+ * (one of `frontendTools`), a skill, one of `mcpServers`, a frontend tool of
24
+ * the catalogue, a runtime tool, codemode's; otherwise `fallback` — a tool
25
+ * the runtime runs.
17
26
  */
18
27
  export function classifyToolCall(name, args, options = {}) {
19
- if (options.frontendTools?.includes(name)) {
20
- const marks = marksOfToolCall(name, args, options.mcpServers);
21
- return {
22
- source: 'frontend-tool',
23
- ...(marks?.icon ? { icon: marks.icon } : {}),
24
- ...(marks?.emoji ? { emoji: marks.emoji } : {}),
25
- };
26
- }
27
28
  const marks = marksOfToolCall(name, args, options.mcpServers);
28
- const source = marks?.kind === 'skill'
29
- ? 'skill'
30
- : marks?.kind === 'mcp'
31
- ? 'mcp'
32
- : marks?.kind === 'frontend'
33
- ? 'frontend-tool'
34
- : marks?.kind === 'runtime'
35
- ? 'backend-tool'
36
- : (options.fallback ?? 'backend-tool');
29
+ const kind = options.frontendTools?.includes(name)
30
+ ? 'frontend'
31
+ : marks?.kind
32
+ ? marks.kind
33
+ : CODEMODE_TOOLS.has(name)
34
+ ? 'codemode'
35
+ : (options.fallback ?? 'runtime');
37
36
  return {
38
- source,
37
+ kind,
39
38
  ...(marks?.icon ? { icon: marks.icon } : {}),
40
39
  ...(marks?.emoji ? { emoji: marks.emoji } : {}),
41
40
  };
@@ -1,14 +1,14 @@
1
1
  /**
2
- * The Agent Inspector: what agents do — A2A traffic, MCP calls, skills,
3
- * frontend and backend tools, model turns, approvals — recorded into a sink
4
- * and drawn as rows that unfold to their payloads.
2
+ * The Agent Inspector: what agents do — model turns, tool calls (MCP,
3
+ * frontend, skills, codemode, runtime), A2A requests and what came back —
4
+ * recorded as OpenTelemetry spans in the page's tracer (core's
5
+ * `createOtelLiveTracer`) and drawn by core's OTEL view (`OtelLiveSpans`).
5
6
  *
6
7
  * @module components/inspector
7
8
  */
8
- export * from './agentInspector';
9
+ export * from './agentSpans';
9
10
  export * from './classify';
10
- export * from './chatInspect';
11
- export * from './a2aInspect';
12
- export * from './JsonTree';
11
+ export * from './chatSpans';
12
+ export * from './a2aSpans';
13
13
  export * from './AgentInspector';
14
14
  export * from './AgentInspectorDialog';
@@ -3,16 +3,16 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  /**
6
- * The Agent Inspector: what agents do — A2A traffic, MCP calls, skills,
7
- * frontend and backend tools, model turns, approvals — recorded into a sink
8
- * and drawn as rows that unfold to their payloads.
6
+ * The Agent Inspector: what agents do — model turns, tool calls (MCP,
7
+ * frontend, skills, codemode, runtime), A2A requests and what came back —
8
+ * recorded as OpenTelemetry spans in the page's tracer (core's
9
+ * `createOtelLiveTracer`) and drawn by core's OTEL view (`OtelLiveSpans`).
9
10
  *
10
11
  * @module components/inspector
11
12
  */
12
- export * from './agentInspector';
13
+ export * from './agentSpans';
13
14
  export * from './classify';
14
- export * from './chatInspect';
15
- export * from './a2aInspect';
16
- export * from './JsonTree';
15
+ export * from './chatSpans';
16
+ export * from './a2aSpans';
17
17
  export * from './AgentInspector';
18
18
  export * from './AgentInspectorDialog';