@datalayer/agent-runtimes 1.5.88 → 1.5.89

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.
@@ -5,7 +5,7 @@
5
5
  import { ALPHAVANTAGE_MCP_SERVER_0_0_1, CHART_MCP_SERVER_0_0_1, EARTHDATA_MCP_SERVER_0_0_1, EURUS_MCP_SERVER_0_0_1, FILESYSTEM_MCP_SERVER_0_0_1, GITHUB_MCP_SERVER_0_0_1, GOOGLE_WORKSPACE_MCP_SERVER_0_0_1, HUGGINGFACE_MCP_SERVER_0_0_1, KAGGLE_MCP_SERVER_0_0_1, ODOO_MCP_SERVER_0_0_1, SALESFORCE_MCP_SERVER_0_0_1, SLACK_MCP_SERVER_0_0_1, TAVILY_MCP_SERVER_0_0_1, } from '../mcpServers.js';
6
6
  import { ACCOUNTING_SKILL_SPEC_0_0_1, CRAWL_SKILL_SPEC_0_0_1, EVENTS_SKILL_SPEC_0_0_1, GITHUB_SKILL_SPEC_0_0_1, JOKES_SKILL_SPEC_0_0_1, PDF_SKILL_SPEC_0_0_1, TEXT_SUMMARIZER_SKILL_SPEC_0_0_1, } from '../skills.js';
7
7
  import { DECIDE_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_CREATE_PLAN_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_CURRENT_TIME_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_DISPLAY_RECIPE_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_GENERATE_HAIKU_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_GENERATE_TASK_STEPS_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_GET_WEATHER_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_RENDER_A2UI_SURFACE_BACKEND_TOOL_SPEC_0_0_1, EXAMPLE_UPDATE_PLAN_STEP_BACKEND_TOOL_SPEC_0_0_1, RUNTIME_ECHO_BACKEND_TOOL_SPEC_0_0_1, RUNTIME_SEND_MAIL_BACKEND_TOOL_SPEC_0_0_1, RUNTIME_SENSITIVE_ECHO_BACKEND_TOOL_SPEC_0_0_1, } from '../backendTools.js';
8
- import { DECKS_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_READ_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_FRONTEND_TOOL_SPEC_0_0_1, LEXICAL_DOCUMENT_FRONTEND_TOOL_SPEC_0_0_1, } from '../frontendTools.js';
8
+ import { CELLS_FRONTEND_TOOL_SPEC_0_0_1, DECKS_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_READ_FRONTEND_TOOL_SPEC_0_0_1, JUPYTER_NOTEBOOK_FRONTEND_TOOL_SPEC_0_0_1, LEXICAL_DOCUMENT_FRONTEND_TOOL_SPEC_0_0_1, } from '../frontendTools.js';
9
9
  // ============================================================================
10
10
  // MCP Server Lookup
11
11
  // ============================================================================
@@ -100,6 +100,8 @@ const TOOL_MAP = {
100
100
  * Map frontend tool IDs to FrontendToolSpec objects.
101
101
  */
102
102
  const FRONTEND_TOOL_MAP = {
103
+ 'cells:0.0.1': CELLS_FRONTEND_TOOL_SPEC_0_0_1,
104
+ cells: CELLS_FRONTEND_TOOL_SPEC_0_0_1,
103
105
  'decks:0.0.1': DECKS_FRONTEND_TOOL_SPEC_0_0_1,
104
106
  decks: DECKS_FRONTEND_TOOL_SPEC_0_0_1,
105
107
  'jupyter-notebook-edit:0.0.1': JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1,
@@ -3997,7 +3999,7 @@ export const EXAMPLE_OUTPUT_AGENTSPEC_0_0_1 = {
3997
3999
  id: 'example-output',
3998
4000
  version: '0.0.1',
3999
4001
  name: 'Example Output Agent',
4000
- description: `Demonstrates structured response rendering (table, json, chart, and file) for the AgentOutputsExample side panel, which detects the block in each answer and renders it.`,
4002
+ description: `Demonstrates structured response rendering (table, json, chart, spreadsheet and file) for the AgentOutputsExample side panel, which detects the block in each answer and renders it; a spreadsheet is drawn with Datalayer Cells, in the chat and in the panel, and charted on the grid through the Cells frontend tools.`,
4001
4003
  tags: ['workflow', 'visualization', 'automation'],
4002
4004
  domain: undefined,
4003
4005
  enabled: false,
@@ -4006,7 +4008,7 @@ export const EXAMPLE_OUTPUT_AGENTSPEC_0_0_1 = {
4006
4008
  skills: [].filter(Boolean),
4007
4009
  backendTools: [],
4008
4010
  disableToolApprovals: true,
4009
- frontendTools: [],
4011
+ frontendTools: [FRONTEND_TOOL_MAP['cells:0.0.1']],
4010
4012
  environmentName: 'ai-agents-env',
4011
4013
  icon: 'table',
4012
4014
  emoji: '📦',
@@ -4025,23 +4027,43 @@ export const EXAMPLE_OUTPUT_AGENTSPEC_0_0_1 = {
4025
4027
  summary: 'Sales chart',
4026
4028
  },
4027
4029
  {
4028
- text: 'Create a CSV file named sales.csv with sample sales for the last 7 days, in a ```csv fenced block whose first line is `# filename: sales.csv`.',
4029
- summary: 'CSV file',
4030
+ text: 'Give me a spreadsheet of twelve months of sales by region (North, South, Online), with a Month column, as one ```csv fenced block whose first line is `# filename: sales.csv`.',
4031
+ summary: 'Sales spreadsheet',
4032
+ },
4033
+ {
4034
+ text: 'Chart the sales spreadsheet: a column chart of the three regions by month, titled Sales by region, inserted on the grid below the data.',
4035
+ summary: 'Chart the spreadsheet',
4036
+ },
4037
+ {
4038
+ text: 'Create a YAML file named config.yaml for a small web service (name, port, log level and two routes), in a ```yaml fenced block whose first line is `# filename: config.yaml`.',
4039
+ summary: 'YAML file',
4030
4040
  },
4031
4041
  ],
4032
- welcomeMessage: 'Example output agent ready. Ask for a TABLE, JSON, a CHART or a FILE and I will answer with exactly one structured output block.',
4042
+ welcomeMessage: 'Example output agent ready. Ask for a TABLE, JSON, a CHART, a SPREADSHEET or a FILE and I will answer with exactly one structured output block; once a spreadsheet is shown, ask me to chart it on its grid.',
4033
4043
  welcomeNotebook: undefined,
4034
4044
  welcomeDocument: undefined,
4035
4045
  sandboxVariant: 'jupyter-server',
4036
4046
  harness: 'pydantic-ai',
4037
4047
  systemPrompt: `You are the Example Output Agent.
4038
- The user may request one of exactly four output modes: TABLE, JSON, CHART, or FILE. For each response, emit exactly one mode and nothing else: no prose before or after the block. Answer from what you know: do not run code or call tools to produce the block.
4048
+ The user may request one of exactly six output modes: TABLE, JSON, CHART, SPREADSHEET, FILE or SHEET CHART. For the first five, emit exactly one mode and nothing else: no prose before or after the block. Answer from what you know: do not run code or call tools to produce the block.
4039
4049
  Formatting rules: - TABLE: Return one GitHub-flavored markdown table, one row per line,
4040
4050
  never several rows joined on a single line.
4041
4051
  - JSON: Return exactly one fenced \`\`\`json code block. - CHART: Return exactly one fenced \`\`\`json code block whose first line is
4042
4052
  "// chart" and whose remaining body is valid ECharts option JSON.
4053
+ - SPREADSHEET: Return exactly one fenced \`\`\`csv code block whose first
4054
+ line is "# filename: <name>.csv", then a header row, then one row per
4055
+ line, comma-separated, numbers without thousands separators or units.
4043
4056
  - FILE: Return exactly one fenced code block whose info string is a file
4044
- extension, and whose first line is "# filename: <name.ext>".
4057
+ extension other than csv or tsv, and whose first line is
4058
+ "# filename: <name.ext>".
4059
+ - SHEET CHART: when asked to chart, plot or graph the spreadsheet already
4060
+ shown (the last SPREADSHEET answer), do not write a block: work on the
4061
+ grid with the Cells tools. Call cells_read_range with no range to find
4062
+ the data, then cells_insert_chart over that range (headers included) with
4063
+ the type and title asked for, at the first column two rows below the
4064
+ data (for data in A1:D13, at A15), unless told where. Answer in one short
4065
+ sentence naming the chart and its range. If the tools say no grid is
4066
+ shown, ask for the spreadsheet first.
4045
4067
 
4046
4068
  If mode is ambiguous, default to JSON.`,
4047
4069
  systemPromptCodemodeAddons: undefined,
@@ -7,6 +7,7 @@
7
7
  * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
8
8
  */
9
9
  import type { FrontendToolSpec } from '../types';
10
+ export declare const CELLS_FRONTEND_TOOL_SPEC_0_0_1: FrontendToolSpec;
10
11
  export declare const DECKS_FRONTEND_TOOL_SPEC_0_0_1: FrontendToolSpec;
11
12
  export declare const JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1: FrontendToolSpec;
12
13
  export declare const JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1: FrontendToolSpec;
@@ -5,6 +5,23 @@
5
5
  // ============================================================================
6
6
  // Frontend Tool Definitions
7
7
  // ============================================================================
8
+ export const CELLS_FRONTEND_TOOL_SPEC_0_0_1 = {
9
+ id: 'cells',
10
+ version: '0.0.1',
11
+ name: 'Cells',
12
+ description: "Read and write the spreadsheet on the person's screen, and chart it — the grid drawn by Datalayer Cells.",
13
+ tags: ['frontend', 'cells', 'spreadsheets'],
14
+ enabled: true,
15
+ toolset: [
16
+ 'cells_read_range',
17
+ 'cells_write_range',
18
+ 'cells_insert_chart',
19
+ 'cells_list_charts',
20
+ 'cells_select_range',
21
+ ],
22
+ icon: '@primer/octicons-react:table',
23
+ emoji: '🧮',
24
+ };
8
25
  export const DECKS_FRONTEND_TOOL_SPEC_0_0_1 = {
9
26
  id: 'decks',
10
27
  version: '0.0.1',
@@ -101,6 +118,7 @@ export const LEXICAL_DOCUMENT_FRONTEND_TOOL_SPEC_0_0_1 = {
101
118
  // Frontend Tool Catalog
102
119
  // ============================================================================
103
120
  export const FRONTEND_TOOL_CATALOG = {
121
+ cells: CELLS_FRONTEND_TOOL_SPEC_0_0_1,
104
122
  decks: DECKS_FRONTEND_TOOL_SPEC_0_0_1,
105
123
  'jupyter-notebook-edit': JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1,
106
124
  'jupyter-notebook-propose': JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1,
@@ -44,16 +44,10 @@ export const DATALAYER_MCP_SERVER_0_0_1 = {
44
44
  description: 'Read, edit and run Jupyter notebooks on Datalayer, with sandboxes and data',
45
45
  icon: '@datalayer/icons-react:datalayer',
46
46
  emoji: '🚀',
47
- url: '',
48
- command: 'npx',
49
- args: [
50
- '-y',
51
- 'mcp-remote',
52
- 'https://mcp.datalayer.run/mcp',
53
- '--header',
54
- 'Authorization: Bearer ${DATALAYER_API_KEY}',
55
- ],
56
- transport: 'stdio',
47
+ url: 'https://mcp.datalayer.run/mcp',
48
+ args: [],
49
+ headers: { Authorization: 'Bearer ${DATALAYER_API_KEY}' },
50
+ transport: 'streamable-http',
57
51
  enabled: false,
58
52
  isAvailable: false,
59
53
  tools: [],
@@ -66,16 +60,10 @@ export const EARTHDATA_MCP_SERVER_0_0_1 = {
66
60
  description: 'Access NASA Earthdata search and metadata capabilities',
67
61
  icon: '@datalayer/icons-react:globe-americas',
68
62
  emoji: '🌍',
69
- url: '',
70
- command: 'npx',
71
- args: [
72
- '-y',
73
- 'mcp-remote',
74
- 'https://mcp.datalayer.run/mcp?only=earthdata',
75
- '--header',
76
- 'Authorization: Bearer ${DATALAYER_API_KEY}',
77
- ],
78
- transport: 'stdio',
63
+ url: 'https://mcp.datalayer.run/mcp?only=earthdata',
64
+ args: [],
65
+ headers: { Authorization: 'Bearer ${DATALAYER_API_KEY}' },
66
+ transport: 'streamable-http',
79
67
  enabled: true,
80
68
  isAvailable: false,
81
69
  tools: [],
@@ -165,16 +153,10 @@ export const HUGGINGFACE_MCP_SERVER_0_0_1 = {
165
153
  description: 'Hugging Face models, datasets, spaces, and papers access',
166
154
  icon: '@primer/octicons-react:hubot',
167
155
  emoji: '🤗',
168
- url: '',
169
- command: 'npx',
170
- args: [
171
- '-y',
172
- 'mcp-remote',
173
- 'https://huggingface.co/mcp',
174
- '--header',
175
- 'Authorization: Bearer ${HF_TOKEN}',
176
- ],
177
- transport: 'stdio',
156
+ url: 'https://huggingface.co/mcp',
157
+ args: [],
158
+ headers: { Authorization: 'Bearer ${HF_TOKEN}' },
159
+ transport: 'streamable-http',
178
160
  enabled: false,
179
161
  isAvailable: false,
180
162
  tools: [],
@@ -187,16 +169,10 @@ export const KAGGLE_MCP_SERVER_0_0_1 = {
187
169
  description: 'Kaggle datasets, models, competitions, and notebooks access',
188
170
  icon: '@datalayer/icons-react:kaggle',
189
171
  emoji: '🏆',
190
- url: '',
191
- command: 'npx',
192
- args: [
193
- '-y',
194
- 'mcp-remote',
195
- 'https://www.kaggle.com/mcp',
196
- '--header',
197
- 'Authorization: Bearer ${KAGGLE_API_TOKEN}',
198
- ],
199
- transport: 'stdio',
172
+ url: 'https://www.kaggle.com/mcp',
173
+ args: [],
174
+ headers: { Authorization: 'Bearer ${KAGGLE_API_TOKEN}' },
175
+ transport: 'streamable-http',
200
176
  enabled: false,
201
177
  isAvailable: false,
202
178
  tools: [],
@@ -209,16 +185,10 @@ export const ODOO_ACCOUNTING_MCP_SERVER_0_0_1 = {
209
185
  description: "An accountant's day in Odoo — invoices, bills, journal entries, reconciliations, bank lines and tax returns — through the Datalayer MCP server",
210
186
  icon: '@datalayer/icons-react:odoo',
211
187
  emoji: '🧮',
212
- url: '',
213
- command: 'npx',
214
- args: [
215
- '-y',
216
- 'mcp-remote',
217
- 'https://mcp.datalayer.run/mcp?only=odoo-accounting',
218
- '--header',
219
- 'Authorization: Bearer ${DATALAYER_API_KEY}',
220
- ],
221
- transport: 'stdio',
188
+ url: 'https://mcp.datalayer.run/mcp?only=odoo-accounting',
189
+ args: [],
190
+ headers: { Authorization: 'Bearer ${DATALAYER_API_KEY}' },
191
+ transport: 'streamable-http',
222
192
  enabled: false,
223
193
  isAvailable: false,
224
194
  tools: [],
@@ -29,13 +29,15 @@ export interface MCPServer {
29
29
  enabled: boolean;
30
30
  /** List of available tools */
31
31
  tools: MCPServerTool[];
32
- /** Command to run the MCP server (e.g., 'npx', 'uvx') */
32
+ /** Command to run a local MCP server (e.g., 'npx', 'uvx'); a remote one names none and is reached at `url` */
33
33
  command?: string;
34
34
  /** Command arguments for the MCP server */
35
35
  args: string[];
36
+ /** The headers a remote server is sent with every request, `${VAR}` expanded as it starts: the bearer among them */
37
+ headers?: Record<string, string>;
36
38
  /** Whether the server is available (based on tool discovery) */
37
39
  isAvailable: boolean;
38
- /** Transport type: 'stdio', 'http', or 'streamable-http' for a server its command runs as a local HTTP process at `url` */
40
+ /** Transport type: 'stdio', 'http', or 'streamable-http' — a remote server reached at `url` with its `headers` when it has no `command`, a command run as a local HTTP process at `url` when it has one */
39
41
  transport: 'stdio' | 'http' | 'streamable-http';
40
42
  /** Environment variables required by this server (e.g., API keys) */
41
43
  requiredEnvVars?: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.88",
3
+ "version": "1.5.89",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -154,6 +154,7 @@
154
154
  "@anthropic-ai/sdk": "^0.52.0",
155
155
  "@datalayer/agent-teams": "^1.0.0",
156
156
  "@datalayer/core": "^1.2.18",
157
+ "@datalayer/cells": "^1.0.0",
157
158
  "@datalayer/decks": "^1.0.4",
158
159
  "@datalayer/design": "^1.0.10",
159
160
  "@datalayer/icons-react": "^1.0.16",
@@ -105,6 +105,11 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
105
105
  icon = f'"{spec.get("icon")}"' if spec.get("icon") else "None"
106
106
  emoji = f'"{spec.get("emoji")}"' if spec.get("emoji") else "None"
107
107
 
108
+ # A remote server names no command: it is reached at its url with its
109
+ # headers (`transport: streamable-http`, the Datalayer gateway's
110
+ # toolsets). A local one names the command that runs it.
111
+ command = f'"{spec["command"]}"' if spec.get("command") else "None"
112
+
108
113
  lines.extend(
109
114
  [
110
115
  f"{const_name} = MCPServer(",
@@ -114,17 +119,26 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
114
119
  f' description="{spec["description"]}",',
115
120
  f" icon={icon},",
116
121
  f" emoji={emoji},",
117
- f' command="{spec["command"]}",',
122
+ f" command={command},",
118
123
  f" args={args_formatted},",
119
124
  f' transport="{spec.get("transport", "stdio")}",',
120
125
  f" enabled={spec.get('enabled', False)},",
121
126
  " tools=[],",
122
127
  ]
123
128
  )
124
- # A server its command runs as a local HTTP process: where it is
125
- # reached (W-02, `google-workspace`).
129
+ # Where an HTTP server is reached: a remote one is connected to there
130
+ # (`odoo-accounting`), a local one's command listens there (W-02,
131
+ # `google-workspace`).
126
132
  if spec.get("url"):
127
133
  lines.append(f' url="{spec["url"]}",')
134
+ # The headers a remote server is sent with every request, their
135
+ # `${VAR}` expanded as it starts (the bearer among them).
136
+ headers = spec.get("headers") or {}
137
+ if headers:
138
+ lines.append(" headers={")
139
+ for key, value in headers.items():
140
+ lines.append(f' "{key}": "{value}",')
141
+ lines.append(" },")
128
142
 
129
143
  # Add env field if present
130
144
  if env_formatted:
@@ -285,8 +299,20 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
285
299
  f" icon: {icon},",
286
300
  f" emoji: {emoji},",
287
301
  f" url: '{spec.get('url', '')}',",
288
- f" command: '{spec['command']}',",
302
+ *([f" command: '{spec['command']}',"] if spec.get("command") else []),
289
303
  f" args: {args_formatted},",
304
+ *(
305
+ [
306
+ " headers: {"
307
+ + ", ".join(
308
+ f"'{key}': '{value}'"
309
+ for key, value in (spec.get("headers") or {}).items()
310
+ )
311
+ + "},"
312
+ ]
313
+ if spec.get("headers")
314
+ else []
315
+ ),
290
316
  f" transport: '{spec.get('transport', 'stdio')}',",
291
317
  f" enabled: {str(spec.get('enabled', False)).lower()},",
292
318
  " isAvailable: false,",