@datalayer/agent-runtimes 1.3.25 → 1.3.28

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 (43) hide show
  1. package/lib/chat/messages/ChatMessages.d.ts +4 -4
  2. package/lib/chat/messages/ChatMessages.js +17 -17
  3. package/lib/config/AgentConfiguration.js +1 -1
  4. package/lib/examples/example-selector.js +1 -1
  5. package/lib/loop/apps/AppRenderer.d.ts +8 -1
  6. package/lib/loop/apps/AppRenderer.js +10 -2
  7. package/lib/loop/apps/checks.d.ts +6 -1
  8. package/lib/loop/apps/checks.js +17 -0
  9. package/lib/loop/embed/LoopEmbed.js +14 -1
  10. package/lib/loop/plugins/chat/ChatView.js +40 -6
  11. package/lib/loop/plugins/chat/Presence.d.ts +9 -0
  12. package/lib/loop/plugins/chat/Presence.js +57 -0
  13. package/lib/loop/plugins/chat/index.d.ts +27 -0
  14. package/lib/loop/plugins/chat/presenceStatus.d.ts +26 -0
  15. package/lib/loop/plugins/chat/presenceStatus.js +28 -0
  16. package/lib/loop/presets.d.ts +5 -1
  17. package/lib/loop/presets.js +4 -2
  18. package/lib/protocols/A2AAdapter.d.ts +1 -1
  19. package/lib/specs/uiPlugins.d.ts +6 -1
  20. package/lib/specs/uiPlugins.js +471 -0
  21. package/lib/stores/chatStore.d.ts +11 -11
  22. package/lib/stores/chatStore.js +34 -34
  23. package/lib/stores/index.d.ts +1 -1
  24. package/lib/stores/index.js +1 -1
  25. package/lib/types/agentspecs.d.ts +33 -0
  26. package/lib/types/index.d.ts +1 -1
  27. package/lib/types/index.js +1 -1
  28. package/lib/types/{extensions.d.ts → uiPlugins.d.ts} +49 -49
  29. package/lib/types/{extensions.js → uiPlugins.js} +8 -8
  30. package/lib/{extensions/A2UIExtension.d.ts → ui-plugins/A2UIPlugin.d.ts} +7 -7
  31. package/lib/{extensions/A2UIExtension.js → ui-plugins/A2UIPlugin.js} +4 -4
  32. package/lib/{extensions/MCPUIExtension.d.ts → ui-plugins/MCPUIPlugin.d.ts} +9 -9
  33. package/lib/{extensions/MCPUIExtension.js → ui-plugins/MCPUIPlugin.js} +6 -6
  34. package/lib/ui-plugins/UIPluginRegistry.d.ts +65 -0
  35. package/lib/{extensions/ExtensionRegistry.js → ui-plugins/UIPluginRegistry.js} +32 -32
  36. package/lib/ui-plugins/index.d.ts +9 -0
  37. package/lib/ui-plugins/index.js +12 -0
  38. package/package.json +1 -1
  39. package/scripts/codegen/generate_agents.py +6 -6
  40. package/scripts/codegen/generate_ui_plugins.py +64 -4
  41. package/lib/extensions/ExtensionRegistry.d.ts +0 -65
  42. package/lib/extensions/index.d.ts +0 -9
  43. package/lib/extensions/index.js +0 -12
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * UI plugin exports for the chat: how an agent's answer becomes an interface (A2UI, MCP UI).
7
+ *
8
+ * @module components/uiPlugins
9
+ */
10
+ export { UIPluginRegistry } from './UIPluginRegistry';
11
+ export { createA2UIRenderer, A2UIPluginImpl, } from './A2UIPlugin';
12
+ export { createMCPUIRenderer, MCPUIPluginImpl, } from './MCPUIPlugin';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.3.25",
3
+ "version": "1.3.28",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -455,8 +455,8 @@ from agent_runtimes.types import (
455
455
  protocol_val = spec.get("protocol")
456
456
  protocol_str = f'"{protocol_val}"' if protocol_val else "None"
457
457
  delegable_str = _fmt_py_delegable(spec.get("delegable", []))
458
- ui_ext = spec.get("ui_plugin") or spec.get("ui_extension")
459
- ui_ext_str = f'"{ui_ext}"' if ui_ext else "None"
458
+ ui_plugin = spec.get("ui_plugin")
459
+ ui_plugin_str = f'"{ui_plugin}"' if ui_plugin else "None"
460
460
  trigger_val = spec.get("trigger")
461
461
  model_cfg = spec.get("model_config")
462
462
  mcp_srv_tools = spec.get("mcp_server_tools")
@@ -567,7 +567,7 @@ from agent_runtimes.types import (
567
567
  goal={goal_str},
568
568
  delegable={delegable_str},
569
569
  protocol={protocol_str},
570
- ui_plugin={ui_ext_str},
570
+ ui_plugin={ui_plugin_str},
571
571
  trigger={_fmt_py_literal(trigger_val)},
572
572
  model_configuration={_fmt_py_literal(model_cfg)},
573
573
  mcp_server_tools={_fmt_py_literal(mcp_srv_tools)},
@@ -1075,8 +1075,8 @@ const FRONTEND_TOOL_MAP: Record<string, any> = {
1075
1075
  protocol_val = spec.get("protocol")
1076
1076
  protocol_ts = f"'{protocol_val}'" if protocol_val else "undefined"
1077
1077
  delegable_ts = _fmt_ts_delegable(spec.get("delegable", []))
1078
- ui_ext = spec.get("ui_plugin") or spec.get("ui_extension")
1079
- ui_ext_ts = f"'{ui_ext}'" if ui_ext else "undefined"
1078
+ ui_plugin = spec.get("ui_plugin")
1079
+ ui_plugin_ts = f"'{ui_plugin}'" if ui_plugin else "undefined"
1080
1080
  trigger_val = spec.get("trigger")
1081
1081
  model_cfg = spec.get("model_config")
1082
1082
  mcp_srv_tools = spec.get("mcp_server_tools")
@@ -1135,7 +1135,7 @@ const FRONTEND_TOOL_MAP: Record<string, any> = {
1135
1135
  goal: {goal_ts},
1136
1136
  delegable: {delegable_ts},
1137
1137
  protocol: {protocol_ts},
1138
- uiPlugin: {ui_ext_ts},
1138
+ uiPlugin: {ui_plugin_ts},
1139
1139
  trigger: {_fmt_ts_literal(trigger_val)},
1140
1140
  modelConfig: {_fmt_ts_literal(model_cfg)},
1141
1141
  mcpServerTools: {_fmt_ts_literal(mcp_srv_tools)},
@@ -8,7 +8,7 @@ Generate Python and TypeScript code from YAML UI-plugin specifications.
8
8
  A UI plugin is how an agent's answer becomes an interface rather than text —
9
9
  a protocol the host knows how to render (A2UI, MCP Apps, MCP UI). One YAML per
10
10
  plugin under ``agentspecs/ui-plugins``; an agent spec's ``ui_plugin`` names
11
- one. They were called UI extensions before agentspecs 0.0.11.
11
+ one. A plugin hosts the visual components it renders (LOOP C-13).
12
12
 
13
13
  Usage:
14
14
  python generate_ui_plugins.py \\
@@ -18,6 +18,7 @@ Usage:
18
18
  """
19
19
 
20
20
  import argparse
21
+ import json
21
22
  import sys
22
23
  from pathlib import Path
23
24
  from typing import Any
@@ -53,6 +54,25 @@ def _ts(value: str) -> str:
53
54
  return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"
54
55
 
55
56
 
57
+ def _py_component(component: dict[str, Any]) -> str:
58
+ """A component as the Python that builds it."""
59
+ bindings = component.get("bindings")
60
+ return (
61
+ "ComponentSpec("
62
+ f"id={_py(component['id'])}, name={json.dumps(component['name'], ensure_ascii=False)}, "
63
+ f"description={json.dumps(component['description'].strip(), ensure_ascii=False)}, "
64
+ f"category={_py(component['category'])}, emoji={json.dumps(component['emoji'], ensure_ascii=False)}, "
65
+ f"standard={bool(component['standard'])}, "
66
+ f"properties={component.get('properties')!r}, "
67
+ + (
68
+ f"bindings=ComponentBindingsSpec(shows={bindings['shows']!r}, sends={bindings['sends']!r}), "
69
+ if bindings
70
+ else "bindings=None, "
71
+ )
72
+ + f"events={component.get('events') or []!r}, example={component.get('example')!r})"
73
+ )
74
+
75
+
56
76
  def generate_python_code(specs: list[dict[str, Any]]) -> str:
57
77
  """Generate Python code from UI-plugin specifications."""
58
78
  lines = [
@@ -69,8 +89,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
69
89
  "",
70
90
  "from typing import Dict",
71
91
  "",
72
- "from agent_runtimes.types import UIPluginSpec",
73
- "",
92
+ "from agent_runtimes.types import ComponentBindingsSpec, ComponentSpec, UIPluginSpec",
74
93
  "",
75
94
  "# " + "=" * 76,
76
95
  "# UI Plugin Definitions",
@@ -88,6 +107,10 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
88
107
  f" description={_py(str(spec.get('description', '')).strip())},",
89
108
  f" docs_url={_py(str(spec.get('docs_url', '')))},",
90
109
  f" enabled={bool(spec.get('enabled', True))},",
110
+ f" catalog={_py(str(spec.get('catalog', '')))},",
111
+ " components=[",
112
+ *[f" {_py_component(c)}," for c in spec.get("components") or []],
113
+ " ],",
91
114
  ")",
92
115
  "",
93
116
  ]
@@ -119,6 +142,25 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
119
142
  "def list_ui_plugins() -> list[UIPluginSpec]:",
120
143
  " return list(UI_PLUGIN_CATALOGUE.values())",
121
144
  "",
145
+ "",
146
+ "#: The visual components the enabled UI plugins render, by the name a",
147
+ "#: surface gives them (LOOP C-13).",
148
+ "COMPONENT_CATALOGUE: Dict[str, ComponentSpec] = {",
149
+ " component.id: component",
150
+ " for plugin in UI_PLUGIN_CATALOGUE.values()",
151
+ " if plugin.enabled",
152
+ " for component in plugin.components",
153
+ "}",
154
+ "",
155
+ "",
156
+ "def get_component(name: str) -> ComponentSpec | None:",
157
+ ' """The component a layout names, or None."""',
158
+ " return COMPONENT_CATALOGUE.get(name)",
159
+ "",
160
+ "",
161
+ "def list_components() -> list[ComponentSpec]:",
162
+ " return list(COMPONENT_CATALOGUE.values())",
163
+ "",
122
164
  ]
123
165
  )
124
166
  return "\n".join(lines)
@@ -141,7 +183,7 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
141
183
  " * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.",
142
184
  " */",
143
185
  "",
144
- "import type { UIPluginSpec } from '../types/agentspecs';",
186
+ "import type { ComponentSpec, UIPluginSpec } from '../types/agentspecs';",
145
187
  "",
146
188
  ]
147
189
  for spec in specs:
@@ -155,6 +197,8 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
155
197
  f" description: {_ts(str(spec.get('description', '')).strip())},",
156
198
  f" docsUrl: {_ts(str(spec.get('docs_url', '')))},",
157
199
  f" enabled: {'true' if spec.get('enabled', True) else 'false'},",
200
+ f" catalog: {_ts(str(spec.get('catalog', '')))},",
201
+ f" components: {json.dumps([{**c, 'events': c.get('events', [])} for c in spec.get('components') or []], indent=2, ensure_ascii=False)},",
158
202
  "};",
159
203
  "",
160
204
  ]
@@ -177,6 +221,22 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
177
221
  " return Object.values(UI_PLUGIN_CATALOGUE);",
178
222
  "}",
179
223
  "",
224
+ "/** The visual components the enabled UI plugins render, by the name a surface gives them (LOOP C-13). */",
225
+ "export const COMPONENT_CATALOGUE: Record<string, ComponentSpec> = Object.fromEntries(",
226
+ " Object.values(UI_PLUGIN_CATALOGUE)",
227
+ " .filter(plugin => plugin.enabled)",
228
+ " .flatMap(plugin => plugin.components.map(component => [component.id, component])),",
229
+ ");",
230
+ "",
231
+ "/** The component a layout names, or undefined. */",
232
+ "export function getComponent(name: string): ComponentSpec | undefined {",
233
+ " return COMPONENT_CATALOGUE[name];",
234
+ "}",
235
+ "",
236
+ "export function listComponents(): ComponentSpec[] {",
237
+ " return Object.values(COMPONENT_CATALOGUE);",
238
+ "}",
239
+ "",
180
240
  ]
181
241
  )
182
242
  return "\n".join(lines)
@@ -1,65 +0,0 @@
1
- /**
2
- * Extension registry for chat component.
3
- * Manages custom renderers and extension points.
4
- *
5
- * @module components/extensions/ExtensionRegistry
6
- */
7
- import type { ChatExtension, MessageRendererExtension, ActivityRendererExtension, ToolUIExtension, ProtocolEventExtension, PanelExtension } from '../types/extensions';
8
- /** Internal extension type for registry organization */
9
- export type InternalExtensionType = 'message-renderer' | 'activity-renderer' | 'tool-ui' | 'protocol-event' | 'panel';
10
- /**
11
- * Extension registry class
12
- */
13
- export declare class ExtensionRegistry {
14
- private extensions;
15
- private byType;
16
- constructor();
17
- /**
18
- * Register an extension
19
- */
20
- register(extension: ChatExtension): void;
21
- /**
22
- * Unregister an extension
23
- */
24
- unregister(extensionName: string): void;
25
- /**
26
- * Get an extension by name
27
- */
28
- get<T extends ChatExtension>(extensionName: string): T | undefined;
29
- /**
30
- * Get all extensions of a specific type
31
- */
32
- getByType<T extends ChatExtension>(type: InternalExtensionType): T[];
33
- /**
34
- * Get all registered extensions
35
- */
36
- getAll(): ChatExtension[];
37
- /**
38
- * Check if an extension is registered
39
- */
40
- has(extensionName: string): boolean;
41
- /**
42
- * Get message renderers
43
- */
44
- getMessageRenderers(): MessageRendererExtension[];
45
- /**
46
- * Get activity renderer for a specific activity type
47
- */
48
- getActivityRenderer(activityType: string): ActivityRendererExtension | undefined;
49
- /**
50
- * Get tool UI for a specific tool
51
- */
52
- getToolUI(toolName: string): ToolUIExtension | undefined;
53
- /**
54
- * Get all panels
55
- */
56
- getPanels(): PanelExtension[];
57
- /**
58
- * Get protocol event handlers for an event type
59
- */
60
- getProtocolEventHandlers(eventType: string): ProtocolEventExtension[];
61
- /**
62
- * Clear all extensions
63
- */
64
- clear(): void;
65
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Extension exports for chat component.
3
- *
4
- * @module components/extensions
5
- */
6
- export { ExtensionRegistry } from './ExtensionRegistry';
7
- export type { InternalExtensionType } from './ExtensionRegistry';
8
- export { createA2UIRenderer, A2UIExtensionImpl, type A2UIMessage, } from './A2UIExtension';
9
- export { createMCPUIRenderer, MCPUIExtensionImpl, type MCPUIMessage, type MCPUIResource, } from './MCPUIExtension';
@@ -1,12 +0,0 @@
1
- /*
2
- * Copyright (c) 2025-2026 Datalayer, Inc.
3
- * Distributed under the terms of the Modified BSD License.
4
- */
5
- /**
6
- * Extension exports for chat component.
7
- *
8
- * @module components/extensions
9
- */
10
- export { ExtensionRegistry } from './ExtensionRegistry';
11
- export { createA2UIRenderer, A2UIExtensionImpl, } from './A2UIExtension';
12
- export { createMCPUIRenderer, MCPUIExtensionImpl, } from './MCPUIExtension';