@datalayer/agent-runtimes 1.3.54 → 1.3.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chat/base/ChatBase.js +8 -3
- package/lib/chat/index.d.ts +1 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/marks/SpecMark.d.ts +46 -0
- package/lib/chat/marks/SpecMark.js +90 -0
- package/lib/chat/marks/iconRef.d.ts +29 -0
- package/lib/chat/marks/iconRef.js +40 -0
- package/lib/chat/marks/index.d.ts +8 -0
- package/lib/chat/marks/index.js +12 -0
- package/lib/chat/marks/toolMarks.d.ts +43 -0
- package/lib/chat/marks/toolMarks.js +110 -0
- package/lib/chat/messages/ChatMessageList.d.ts +8 -1
- package/lib/chat/messages/ChatMessageList.js +11 -18
- package/lib/chat/parts/ToolPart.js +6 -1
- package/lib/chat/prompt/InputPrompt.d.ts +4 -1
- package/lib/chat/prompt/InputPrompt.js +2 -2
- package/lib/chat/prompt/menus/SkillsMenu.js +2 -1
- package/lib/chat/prompt/menus/ToolsMenu.d.ts +3 -1
- package/lib/chat/prompt/menus/ToolsMenu.js +25 -9
- package/lib/chat/tools/ToolCallDisplay.d.ts +8 -1
- package/lib/chat/tools/ToolCallDisplay.js +3 -2
- package/lib/examples/AgentStrategyExample.d.ts +12 -0
- package/lib/examples/{AgentLoopExample.js → AgentStrategyExample.js} +62 -62
- package/lib/examples/example-selector.js +1 -1
- package/lib/examples/index.d.ts +1 -1
- package/lib/examples/index.js +1 -1
- package/lib/examples/main.js +3 -3
- package/lib/loop/plugins/chat/ChatView.js +7 -5
- package/lib/specs/actions.js +56 -0
- package/lib/specs/frontendTools.js +6 -6
- package/lib/specs/index.d.ts +1 -1
- package/lib/specs/index.js +1 -1
- package/lib/specs/mcpServers.d.ts +1 -0
- package/lib/specs/mcpServers.js +39 -16
- package/lib/specs/skills.js +7 -7
- package/lib/specs/strategies.d.ts +34 -0
- package/lib/specs/{loops.js → strategies.js} +30 -30
- package/lib/specs/tools.js +21 -21
- package/lib/types/chat.d.ts +4 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +1 -1
- package/lib/types/mcp.d.ts +2 -2
- package/lib/types/skills.d.ts +2 -2
- package/lib/types/{loops.d.ts → strategies.d.ts} +17 -17
- package/lib/types/tools.d.ts +4 -4
- package/package.json +1 -1
- package/scripts/codegen/agentspecs_clone.py +5 -3
- package/scripts/codegen/generate_agents.py +1 -1
- package/scripts/codegen/generate_frontend_tools.py +2 -0
- package/scripts/codegen/generate_mcp_servers.py +2 -0
- package/scripts/codegen/generate_skills.py +2 -0
- package/scripts/codegen/{generate_loops.py → generate_strategies.py} +81 -81
- package/scripts/codegen/generate_tools.py +2 -0
- package/scripts/codegen/marks.py +33 -0
- package/lib/examples/AgentLoopExample.d.ts +0 -12
- package/lib/specs/loops.d.ts +0 -34
- /package/lib/types/{loops.js → strategies.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BuiltinTool, MCPServerConfig } from '../../../types';
|
|
2
|
-
export declare function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, availableTools, }: {
|
|
2
|
+
export declare function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, availableTools, availableFrontendTools, }: {
|
|
3
3
|
codemodeEnabled: boolean;
|
|
4
4
|
onToggleCodemode?: (enabled: boolean) => void | Promise<void>;
|
|
5
5
|
mcpServers: MCPServerConfig[];
|
|
@@ -10,4 +10,6 @@ export declare function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServer
|
|
|
10
10
|
approvedMcpTools: Map<string, Set<string>>;
|
|
11
11
|
onToggleMcpToolApproval: (serverId: string, toolName: string) => void;
|
|
12
12
|
availableTools: BuiltinTool[];
|
|
13
|
+
/** The frontend tools: the ones the page runs for the agent. */
|
|
14
|
+
availableFrontendTools?: BuiltinTool[];
|
|
13
15
|
}): import("react").JSX.Element;
|
|
@@ -4,14 +4,20 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
|
-
* What the agent may call:
|
|
7
|
+
* What the agent may call: the runtime's tools, the frontend tools (the ones
|
|
8
|
+
* the page runs), MCP servers, and codemode — each drawn with its mark.
|
|
8
9
|
*
|
|
9
10
|
* @module chat/prompt/menus/ToolsMenu
|
|
10
11
|
*/
|
|
11
12
|
import { Text, Button, ActionMenu, ActionList, ToggleSwitch, Tooltip, } from '@primer/react';
|
|
12
13
|
import { Box } from '@datalayer/primer-addons';
|
|
13
14
|
import { ToolsIcon } from '@primer/octicons-react';
|
|
14
|
-
|
|
15
|
+
import { SpecMark, hasMark, marksOfFrontendTool, marksOfMcpServer, marksOfRuntimeTool, } from '../../marks';
|
|
16
|
+
/** A tool's mark, as the leading visual of its row. */
|
|
17
|
+
function LeadingMark({ marks }) {
|
|
18
|
+
return hasMark(marks) ? (_jsx(ActionList.LeadingVisual, { children: _jsx(SpecMark, { icon: marks.icon, emoji: marks.emoji, size: 16 }) })) : null;
|
|
19
|
+
}
|
|
20
|
+
export function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, availableTools, availableFrontendTools = [], }) {
|
|
15
21
|
const hasUsableMcpServers = mcpServers.some(server => server.isAvailable);
|
|
16
22
|
/*
|
|
17
23
|
* A count, not a word.
|
|
@@ -23,12 +29,17 @@ export function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabl
|
|
|
23
29
|
*/
|
|
24
30
|
const summary = [
|
|
25
31
|
`${availableTools.length} tool${availableTools.length === 1 ? '' : 's'}`,
|
|
32
|
+
availableFrontendTools.length > 0
|
|
33
|
+
? `${availableFrontendTools.length} frontend tool${availableFrontendTools.length === 1 ? '' : 's'}`
|
|
34
|
+
: null,
|
|
26
35
|
enabledMcpToolCount > 0 ? `${enabledMcpToolCount} MCP enabled` : null,
|
|
27
36
|
hasUsableMcpServers ? null : 'no MCP server available',
|
|
28
37
|
]
|
|
29
38
|
.filter(Boolean)
|
|
30
39
|
.join(' · ');
|
|
31
|
-
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Tooltip, { text: `Tools — ${summary}`, direction: "n", children: _jsx(Button, { type: "button", variant: "invisible", size: "small", "aria-label": `Tools — ${summary}`, leadingVisual: ToolsIcon, children: _jsx(Text, { sx: { fontSize: 0 }, children: availableTools.length +
|
|
40
|
+
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Tooltip, { text: `Tools — ${summary}`, direction: "n", children: _jsx(Button, { type: "button", variant: "invisible", size: "small", "aria-label": `Tools — ${summary}`, leadingVisual: ToolsIcon, children: _jsx(Text, { sx: { fontSize: 0 }, children: availableTools.length +
|
|
41
|
+
availableFrontendTools.length +
|
|
42
|
+
enabledMcpToolCount }) }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start", width: "large", children: _jsx(Box, { sx: { maxHeight: '60vh', overflowY: 'auto' }, children: _jsxs(ActionList, { children: [_jsx(ActionList.Group, { title: "Codemode", children: _jsxs(Box, { sx: {
|
|
32
43
|
display: 'flex',
|
|
33
44
|
alignItems: 'center',
|
|
34
45
|
justifyContent: 'space-between',
|
|
@@ -43,12 +54,13 @@ export function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabl
|
|
|
43
54
|
if (onToggleCodemode) {
|
|
44
55
|
void onToggleCodemode(!codemodeEnabled);
|
|
45
56
|
}
|
|
46
|
-
}, "aria-labelledby": "toggle-codemode" })] }) }), availableTools.length > 0 ? (_jsx(ActionList.Group, { title: "Tools", children: availableTools.map(tool => (_jsx(ActionList.Item, { disabled: true, children: tool.name }, tool.id))) })) : null, mcpServers.length > 0 && hasUsableMcpServers ? (mcpServers.map(server => {
|
|
57
|
+
}, "aria-labelledby": "toggle-codemode" })] }) }), availableTools.length > 0 ? (_jsx(ActionList.Group, { title: "Tools", children: availableTools.map(tool => (_jsxs(ActionList.Item, { disabled: true, children: [_jsx(LeadingMark, { marks: marksOfRuntimeTool(tool.name) }), tool.name] }, tool.id))) })) : null, availableFrontendTools.length > 0 ? (_jsx(ActionList.Group, { title: "Frontend tools", children: availableFrontendTools.map(tool => (_jsxs(ActionList.Item, { disabled: true, children: [_jsx(LeadingMark, { marks: marksOfFrontendTool(tool.name) }), tool.name] }, tool.id))) })) : null, mcpServers.length > 0 && hasUsableMcpServers ? (mcpServers.map(server => {
|
|
47
58
|
const serverTools = enabledMcpTools.get(server.id);
|
|
48
59
|
const allToolNames = server.tools.map(t => t.name);
|
|
49
60
|
const enabledCount = serverTools?.size ?? 0;
|
|
50
61
|
const allEnabled = enabledCount === allToolNames.length &&
|
|
51
62
|
allToolNames.length > 0;
|
|
63
|
+
const serverMarks = marksOfMcpServer(server);
|
|
52
64
|
return (_jsxs(ActionList.Group, { title: `${server.name}${server.isAvailable ? '' : ' (unavailable)'}`, children: [server.isAvailable && server.tools.length > 0 && (_jsxs(Box, { sx: {
|
|
53
65
|
display: 'flex',
|
|
54
66
|
alignItems: 'center',
|
|
@@ -57,11 +69,15 @@ export function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabl
|
|
|
57
69
|
py: 2,
|
|
58
70
|
borderBottom: '1px solid',
|
|
59
71
|
borderColor: 'border.muted',
|
|
60
|
-
}, children: [_jsxs(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}, children: [
|
|
72
|
+
}, children: [_jsxs(Box, { sx: {
|
|
73
|
+
display: 'flex',
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
gap: 2,
|
|
76
|
+
}, children: [hasMark(serverMarks) && (_jsx(SpecMark, { icon: serverMarks.icon, emoji: serverMarks.emoji, size: 16 })), _jsxs(Text, { id: `toggle-all-${server.id}`, sx: {
|
|
77
|
+
fontSize: 0,
|
|
78
|
+
fontWeight: 'semibold',
|
|
79
|
+
color: 'fg.muted',
|
|
80
|
+
}, children: ["Enable all (", enabledCount, "/", allToolNames.length, ")"] })] }), _jsx(ToggleSwitch, { size: "small", checked: allEnabled, onClick: () => onToggleAllMcpServerTools(server.id, allToolNames, !allEnabled), "aria-labelledby": `toggle-all-${server.id}` })] })), server.isAvailable && server.tools.length > 0 ? (server.tools.map(tool => {
|
|
65
81
|
const isEnabled = serverTools?.has(tool.name) ?? false;
|
|
66
82
|
const serverApproved = approvedMcpTools.get(server.id);
|
|
67
83
|
// Tools default to NOT approved — user must explicitly
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import type { CodeError, ExecutionResult, DisplayToolCallStatus } from '../../types';
|
|
9
|
+
import { type Marks } from '../marks';
|
|
9
10
|
/**
|
|
10
11
|
* Error type classification for display purposes
|
|
11
12
|
*/
|
|
@@ -43,6 +44,12 @@ export interface ToolCallDisplayProps {
|
|
|
43
44
|
onDeny?: () => void;
|
|
44
45
|
/** Loading state for approval actions */
|
|
45
46
|
approvalLoading?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The marks of whoever the tool belongs to — its MCP server, skill,
|
|
49
|
+
* frontend tool set or runtime tool spec — drawn before its name: the
|
|
50
|
+
* icon, else the emoji, else nothing.
|
|
51
|
+
*/
|
|
52
|
+
marks?: Marks | null;
|
|
46
53
|
}
|
|
47
54
|
/**
|
|
48
55
|
* ToolCallDisplay component - Default display for tool calls in chat
|
|
@@ -54,5 +61,5 @@ export interface ToolCallDisplayProps {
|
|
|
54
61
|
* - Color-coded status indicators
|
|
55
62
|
* - Rich error display distinguishing execution errors from code errors
|
|
56
63
|
*/
|
|
57
|
-
export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading, }: ToolCallDisplayProps): React.JSX.Element;
|
|
64
|
+
export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading, marks, }: ToolCallDisplayProps): React.JSX.Element;
|
|
58
65
|
export default ToolCallDisplay;
|
|
@@ -13,6 +13,7 @@ import { useEffect, useState } from 'react';
|
|
|
13
13
|
import { Button, Text } from '@primer/react';
|
|
14
14
|
import { Box } from '@datalayer/primer-addons';
|
|
15
15
|
import { ChevronDownIcon, ChevronRightIcon, ToolsIcon, CheckCircleIcon, XCircleIcon, ClockIcon, AlertIcon, } from '@primer/octicons-react';
|
|
16
|
+
import { SpecMark, hasMark } from '../marks';
|
|
16
17
|
/**
|
|
17
18
|
* Get status icon and color based on tool call status
|
|
18
19
|
*/
|
|
@@ -124,7 +125,7 @@ function getArgsSummary(args) {
|
|
|
124
125
|
* - Color-coded status indicators
|
|
125
126
|
* - Rich error display distinguishing execution errors from code errors
|
|
126
127
|
*/
|
|
127
|
-
export function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired = false, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading = false, }) {
|
|
128
|
+
export function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired = false, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading = false, marks, }) {
|
|
128
129
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
129
130
|
// Determine effective exit code from props or execution result
|
|
130
131
|
const effectiveExitCode = exitCode ?? executionResult?.exit_code;
|
|
@@ -189,7 +190,7 @@ export function ToolCallDisplay({ toolCallId, toolName, args, result, status, er
|
|
|
189
190
|
'&:hover': {
|
|
190
191
|
backgroundColor: 'neutral.muted',
|
|
191
192
|
},
|
|
192
|
-
}, children: [_jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0 }, children: isExpanded ? (_jsx(ChevronDownIcon, { size: 16 })) : (_jsx(ChevronRightIcon, { size: 16 })) }), _jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0 }, children: _jsx(
|
|
193
|
+
}, children: [_jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0 }, children: isExpanded ? (_jsx(ChevronDownIcon, { size: 16 })) : (_jsx(ChevronRightIcon, { size: 16 })) }), hasMark(marks) && (_jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0, display: 'flex' }, children: _jsx(SpecMark, { icon: marks?.icon, emoji: marks?.emoji, size: 16 }) })), _jsx(Text, { sx: {
|
|
193
194
|
fontWeight: 'semibold',
|
|
194
195
|
fontSize: 1,
|
|
195
196
|
color: 'fg.default',
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ServiceManager } from '@jupyterlab/services';
|
|
2
|
+
interface AgentStrategyExampleInnerProps {
|
|
3
|
+
serviceManager?: ServiceManager.IManager;
|
|
4
|
+
}
|
|
5
|
+
export declare function AgentStrategyExampleInner({ serviceManager, }: AgentStrategyExampleInnerProps): import("react").JSX.Element;
|
|
6
|
+
/**
|
|
7
|
+
* Main example component with Jupyter provider wrapper.
|
|
8
|
+
*/
|
|
9
|
+
export declare function AgentStrategyExample({ serviceManager, }: {
|
|
10
|
+
serviceManager?: ServiceManager.IManager;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export default AgentStrategyExample;
|
|
@@ -4,27 +4,27 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* AgentStrategyExample - Define and launch an agent reasoning *strategy*.
|
|
8
8
|
*
|
|
9
|
-
* This example demonstrates the
|
|
9
|
+
* This example demonstrates the control-loop paradigm (observe → think → act →
|
|
10
10
|
* evaluate) instead of one-shot prompting. It is fully driven by the generic
|
|
11
|
-
*
|
|
11
|
+
* strategy specifications defined in agentspecs (`src/specs/strategies.ts`):
|
|
12
12
|
*
|
|
13
|
-
* - Pick any
|
|
14
|
-
* Human-in-the-Loop). The list is read from the
|
|
15
|
-
* new YAML
|
|
16
|
-
* - The agent's system prompt is composed generically from the selected
|
|
13
|
+
* - Pick any strategy spec (Data Analysis, Plan/Execute/Critic, OODA,
|
|
14
|
+
* Human-in-the-Loop). The list is read from the strategy catalogue, so adding a
|
|
15
|
+
* new YAML strategy spec automatically makes it available here.
|
|
16
|
+
* - The agent's system prompt is composed generically from the selected strategy's
|
|
17
17
|
* objective, phases, constraints, termination policy and human settings — no
|
|
18
|
-
*
|
|
19
|
-
* - The agent then runs the
|
|
20
|
-
*
|
|
18
|
+
* strategy-specific code.
|
|
19
|
+
* - The agent then runs the strategy against a live Jupyter notebook, where the
|
|
20
|
+
* strategy state (dataframes, charts, intermediate results) lives outside the
|
|
21
21
|
* model so each iteration stays small and focused.
|
|
22
22
|
*
|
|
23
23
|
* To run this example:
|
|
24
24
|
* 1. Start the agent-runtimes server.
|
|
25
25
|
* 2. Select this example from the header dropdown (Agent group).
|
|
26
26
|
*
|
|
27
|
-
* @module examples/
|
|
27
|
+
* @module examples/AgentStrategyExample
|
|
28
28
|
*/
|
|
29
29
|
import { useMemo, useState } from 'react';
|
|
30
30
|
import { Box } from '@datalayer/primer-addons';
|
|
@@ -32,40 +32,40 @@ import { Notebook } from '@datalayer/jupyter-react';
|
|
|
32
32
|
import { useNotebookTools } from '../tools/adapters/agent-runtimes/notebookHooks';
|
|
33
33
|
import { ThemedJupyterProvider, ThemedProvider } from './utils/themedProvider';
|
|
34
34
|
import { ChatSidebar } from '../chat';
|
|
35
|
-
import {
|
|
35
|
+
import { listStrategies, getStrategy, DEFAULT_STRATEGY } from '../specs';
|
|
36
36
|
import { useExampleJupyterAgent } from './hooks/useExampleJupyterAgent';
|
|
37
37
|
import MatplotlibNotebook from './utils/notebooks/Matplotlib.ipynb.json';
|
|
38
38
|
import { ExampleNotebookToolbar } from './utils/notebookToolbarItems';
|
|
39
39
|
// Fixed notebook ID
|
|
40
|
-
const NOTEBOOK_ID = 'agent-
|
|
41
|
-
// Use the imported Matplotlib notebook as the working surface for the
|
|
40
|
+
const NOTEBOOK_ID = 'agent-strategy-example';
|
|
41
|
+
// Use the imported Matplotlib notebook as the working surface for the strategy.
|
|
42
42
|
const NOTEBOOK_CONTENT = MatplotlibNotebook;
|
|
43
43
|
// Default configuration
|
|
44
|
-
const DEFAULT_AGENT_ID = import.meta.env.VITE_AGENT_ID || '
|
|
44
|
+
const DEFAULT_AGENT_ID = import.meta.env.VITE_AGENT_ID || 'strategy-agent-runtime-example';
|
|
45
45
|
/**
|
|
46
|
-
* Compose an agent system prompt generically from a
|
|
46
|
+
* Compose an agent system prompt generically from a strategy specification.
|
|
47
47
|
*
|
|
48
|
-
* This is intentionally spec-driven: every field comes from the
|
|
49
|
-
* the same code drives any
|
|
48
|
+
* This is intentionally spec-driven: every field comes from the strategy YAML, so
|
|
49
|
+
* the same code drives any strategy (data analysis, plan/execute/critic, OODA, ...).
|
|
50
50
|
*/
|
|
51
|
-
function
|
|
51
|
+
function buildStrategySystemPrompt(strategy) {
|
|
52
52
|
const lines = [];
|
|
53
|
-
lines.push(`You are an agent that operates as a control
|
|
54
|
-
lines.push(`
|
|
55
|
-
if (
|
|
56
|
-
lines.push(`Objective: ${
|
|
53
|
+
lines.push(`You are an agent that operates as a control loop rather than answering in a single prompt.`);
|
|
54
|
+
lines.push(`Strategy: ${strategy.name} (${strategy.strategy}).`);
|
|
55
|
+
if (strategy.objective) {
|
|
56
|
+
lines.push(`Objective: ${strategy.objective}`);
|
|
57
57
|
}
|
|
58
|
-
if (
|
|
59
|
-
lines.push(`Each iteration, execute these phases in order: ${
|
|
58
|
+
if (strategy.phases?.length) {
|
|
59
|
+
lines.push(`Each iteration, execute these phases in order: ${strategy.phases.join(' → ')}. ` +
|
|
60
60
|
`Decide the single best next action each iteration; do not try to solve everything at once.`);
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
63
|
-
lines.push(`Constraints you must respect:\n${
|
|
62
|
+
if (strategy.constraints?.length) {
|
|
63
|
+
lines.push(`Constraints you must respect:\n${strategy.constraints
|
|
64
64
|
.map(c => `- ${c}`)
|
|
65
65
|
.join('\n')}`);
|
|
66
66
|
}
|
|
67
|
-
if (
|
|
68
|
-
const t =
|
|
67
|
+
if (strategy.termination) {
|
|
68
|
+
const t = strategy.termination;
|
|
69
69
|
lines.push(`Termination: stop after at most ${t.maxIterations} iterations, or when the goal is reached.`);
|
|
70
70
|
if (t.successCriteria?.length) {
|
|
71
71
|
lines.push(`Success criteria:\n${t.successCriteria.map(s => `- ${s}`).join('\n')}`);
|
|
@@ -74,13 +74,13 @@ function buildLoopSystemPrompt(loop) {
|
|
|
74
74
|
lines.push(`If blocked: ${t.onBlocked}.`);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
if (
|
|
78
|
-
lines.push(`Human-in-the-loop: mode "${
|
|
79
|
-
(
|
|
80
|
-
? `; request explicit approval before: ${
|
|
77
|
+
if (strategy.human && strategy.human.mode !== 'none') {
|
|
78
|
+
lines.push(`Human-in-the-loop: mode "${strategy.human.mode}"` +
|
|
79
|
+
(strategy.human.approvalRequired
|
|
80
|
+
? `; request explicit approval before: ${strategy.human.approvalFor.join(', ') || 'sensitive actions'}.`
|
|
81
81
|
: '.'));
|
|
82
82
|
}
|
|
83
|
-
lines.push(`Keep
|
|
83
|
+
lines.push(`Keep strategy state (dataframes, charts, intermediate results) in the notebook/runtime, not in the prompt. ` +
|
|
84
84
|
`For notebook operations, always use the notebook frontend tools (runCell, readAllCells, readCell, insertCell, updateCell, deleteCells) so actions happen in the live notebook UI. ` +
|
|
85
85
|
`Use executeCodeInNotebook only for temporary inspection code that should not modify notebook cells.`);
|
|
86
86
|
return lines.join('\n\n');
|
|
@@ -108,9 +108,9 @@ function NotebookUI({ serviceManager }) {
|
|
|
108
108
|
return (_jsx(ThemedJupyterProvider, { children: _jsx(Notebook, { nbformat: NOTEBOOK_CONTENT, id: NOTEBOOK_ID, Toolbar: ExampleNotebookToolbar, serviceManager: serviceManager, height: "100%", cellSidebarMargin: 120, startDefaultKernel: true }) }));
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* A compact, read-only summary of the selected
|
|
111
|
+
* A compact, read-only summary of the selected strategy specification.
|
|
112
112
|
*/
|
|
113
|
-
function
|
|
113
|
+
function StrategySummary({ strategy }) {
|
|
114
114
|
return (_jsxs(Box, { sx: {
|
|
115
115
|
mt: 2,
|
|
116
116
|
p: 2,
|
|
@@ -119,7 +119,7 @@ function LoopSummary({ loop }) {
|
|
|
119
119
|
borderRadius: 2,
|
|
120
120
|
bg: 'canvas.default',
|
|
121
121
|
fontSize: 0,
|
|
122
|
-
}, children: [_jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 2, mb: 1 }, children:
|
|
122
|
+
}, children: [_jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 2, mb: 1 }, children: strategy.phases.map((phase, index) => (_jsxs(Box, { sx: {
|
|
123
123
|
display: 'flex',
|
|
124
124
|
alignItems: 'center',
|
|
125
125
|
gap: 1,
|
|
@@ -129,21 +129,21 @@ function LoopSummary({ loop }) {
|
|
|
129
129
|
bg: 'neutral.muted',
|
|
130
130
|
color: 'fg.default',
|
|
131
131
|
fontWeight: 'bold',
|
|
132
|
-
}, children: [index + 1, ". ", phase] }, phase))) }),
|
|
132
|
+
}, children: [index + 1, ". ", phase] }, phase))) }), strategy.objective && (_jsxs(Box, { sx: { color: 'fg.muted' }, children: [_jsx("strong", { children: "Objective:" }), " ", strategy.objective] })), strategy.termination && (_jsxs(Box, { sx: { color: 'fg.muted', mt: 1 }, children: [_jsx("strong", { children: "Max iterations:" }), " ", strategy.termination.maxIterations, ' ', "\u00B7 ", _jsx("strong", { children: "On blocked:" }), " ", strategy.termination.onBlocked] }))] }));
|
|
133
133
|
}
|
|
134
|
-
export function
|
|
135
|
-
// All available
|
|
136
|
-
const
|
|
137
|
-
const [
|
|
138
|
-
const
|
|
139
|
-
const systemPrompt = useMemo(() =>
|
|
134
|
+
export function AgentStrategyExampleInner({ serviceManager, }) {
|
|
135
|
+
// All available strategies come from the generated strategy catalogue.
|
|
136
|
+
const strategies = useMemo(() => listStrategies(), []);
|
|
137
|
+
const [selectedStrategyId, setSelectedStrategyId] = useState(DEFAULT_STRATEGY);
|
|
138
|
+
const selectedStrategy = useMemo(() => getStrategy(selectedStrategyId) ?? strategies[0], [selectedStrategyId, strategies]);
|
|
139
|
+
const systemPrompt = useMemo(() => buildStrategySystemPrompt(selectedStrategy), [selectedStrategy]);
|
|
140
140
|
// The tools. Which of the chat and the harness runs them depends on
|
|
141
|
-
// where the
|
|
141
|
+
// where the strategy turns, and the hook decides that.
|
|
142
142
|
const tools = useNotebookTools(NOTEBOOK_ID);
|
|
143
143
|
const { agentReady, protocol: protocolConfig, chatFrontendTools, error, unavailableReason, createAttempted, } = useExampleJupyterAgent({
|
|
144
|
-
exampleId: '
|
|
144
|
+
exampleId: 'AgentStrategyExample',
|
|
145
145
|
agentName: DEFAULT_AGENT_ID,
|
|
146
|
-
description: `
|
|
146
|
+
description: `Strategy agent (${selectedStrategy.name}) for AgentStrategyExample`,
|
|
147
147
|
systemPrompt,
|
|
148
148
|
serviceManager,
|
|
149
149
|
frontendTools: tools,
|
|
@@ -153,16 +153,16 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
153
153
|
// The example's own agent, not merely the runtime: on the cloud target the
|
|
154
154
|
// runtime is ready before this agent has been registered on it.
|
|
155
155
|
const effectiveReady = agentReady;
|
|
156
|
-
const
|
|
156
|
+
const isStrategySelectorDisabled = createAttempted;
|
|
157
157
|
// Get notebook tools for ChatSidebar
|
|
158
158
|
// Build Vercel AI protocol config
|
|
159
|
-
// Chat suggestions derived from the selected
|
|
159
|
+
// Chat suggestions derived from the selected strategy.
|
|
160
160
|
const suggestions = useMemo(() => [
|
|
161
161
|
{
|
|
162
|
-
title: `${
|
|
163
|
-
message:
|
|
164
|
-
? `Run the ${
|
|
165
|
-
: `Run the ${
|
|
162
|
+
title: `${selectedStrategy.emoji} Run the strategy`,
|
|
163
|
+
message: selectedStrategy.objective
|
|
164
|
+
? `Run the ${selectedStrategy.name}. ${selectedStrategy.objective}`
|
|
165
|
+
: `Run the ${selectedStrategy.name} against the data in this notebook.`,
|
|
166
166
|
},
|
|
167
167
|
{
|
|
168
168
|
title: '🔁 Next iteration',
|
|
@@ -176,7 +176,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
176
176
|
title: '📊 Summarize findings',
|
|
177
177
|
message: 'Summarize the key findings and produce a final, decision-oriented report.',
|
|
178
178
|
},
|
|
179
|
-
], [
|
|
179
|
+
], [selectedStrategy]);
|
|
180
180
|
return (_jsx(_Fragment, { children: _jsxs(Box, { sx: {
|
|
181
181
|
// The wrapper is the viewport, not the window: it sits below the
|
|
182
182
|
// header and beside the sidebar, so viewport units size this box to
|
|
@@ -204,9 +204,9 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
204
204
|
justifyContent: 'space-between',
|
|
205
205
|
gap: 3,
|
|
206
206
|
flexWrap: 'wrap',
|
|
207
|
-
}, children: [_jsxs(Box, { children: [_jsxs("h1", { style: { margin: 0, fontSize: '1.5rem' }, children: [
|
|
208
|
-
? '
|
|
209
|
-
: 'Choose a
|
|
207
|
+
}, children: [_jsxs(Box, { children: [_jsxs("h1", { style: { margin: 0, fontSize: '1.5rem' }, children: [selectedStrategy.emoji, " Agent Strategy Example"] }), _jsx("p", { style: { margin: '8px 0 0', color: 'var(--fgColor-muted)' }, children: "Define and launch an agent reasoning strategy \u2014 observe, think, act, evaluate \u2014 over a live notebook." })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, title: isStrategySelectorDisabled
|
|
208
|
+
? 'Strategy selector is temporarily disabled while launching the agent'
|
|
209
|
+
: 'Choose a strategy', children: [_jsx(Box, { as: "label", sx: { fontSize: 1, fontWeight: 'bold' }, children: "Strategy" }), _jsx(Box, { as: "select", value: selectedStrategyId, onChange: (e) => setSelectedStrategyId(e.target.value), disabled: isStrategySelectorDisabled, "aria-label": "Strategy specification", sx: {
|
|
210
210
|
px: 2,
|
|
211
211
|
py: '6px',
|
|
212
212
|
fontSize: 1,
|
|
@@ -215,7 +215,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
215
215
|
borderColor: 'border.default',
|
|
216
216
|
bg: 'canvas.default',
|
|
217
217
|
color: 'fg.default',
|
|
218
|
-
}, children:
|
|
218
|
+
}, children: strategies.map(strategy => (_jsxs("option", { value: strategy.id, children: [strategy.emoji, " ", strategy.name] }, strategy.id))) })] })] }), _jsx(StrategySummary, { strategy: selectedStrategy })] }), _jsx(Box, { sx: {
|
|
219
219
|
flex: 1,
|
|
220
220
|
display: 'flex',
|
|
221
221
|
overflow: 'hidden',
|
|
@@ -227,7 +227,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
227
227
|
borderColor: 'border.default',
|
|
228
228
|
borderRadius: 2,
|
|
229
229
|
overflow: 'hidden',
|
|
230
|
-
}, children: _jsx(NotebookUI, { serviceManager: serviceManager }) }) })] }), effectiveReady && (_jsx(ChatSidebar, { title: `${
|
|
230
|
+
}, children: _jsx(NotebookUI, { serviceManager: serviceManager }) }) })] }), effectiveReady && (_jsx(ChatSidebar, { title: `${selectedStrategy.emoji} ${selectedStrategy.name}`, protocol: protocolConfig, position: "right", width: 400, clickOutsideToClose: false, showNewChatButton: true, showClearButton: true, showSettingsButton: true, defaultOpen: true, panelProps: {
|
|
231
231
|
protocol: protocolConfig,
|
|
232
232
|
frontendTools: chatFrontendTools,
|
|
233
233
|
useStore: false,
|
|
@@ -250,7 +250,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
250
250
|
/**
|
|
251
251
|
* Main example component with Jupyter provider wrapper.
|
|
252
252
|
*/
|
|
253
|
-
export function
|
|
254
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
253
|
+
export function AgentStrategyExample({ serviceManager, }) {
|
|
254
|
+
return (_jsx(ThemedProvider, { children: _jsx(AgentStrategyExampleInner, { serviceManager: serviceManager }) }));
|
|
255
255
|
}
|
|
256
|
-
export default
|
|
256
|
+
export default AgentStrategyExample;
|
|
@@ -111,7 +111,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
111
111
|
// `owns-sandbox-control`: the shell is pinned to the browser sandbox, so
|
|
112
112
|
// the page's selector would offer three targets it cannot move to.
|
|
113
113
|
['example', 'loop', 'shell', 'prompt', 'editors', 'owns-sandbox-control']),
|
|
114
|
-
makeEntry('
|
|
114
|
+
makeEntry('AgentStrategyExample', () => import('./AgentStrategyExample'), 'Define and launch an agent reasoning strategy (a control loop: observe/think/act/evaluate) over a live notebook, driven by generic strategy specs.', ['example', 'agent', 'strategy', 'notebook', 'agentspecs']),
|
|
115
115
|
makeEntry('AgentToolApprovalsExample', () => import('./AgentToolApprovalsExample'), 'Tool approval workflows and manual decisions.'),
|
|
116
116
|
makeEntry('AgentMemoryExample', () => import('./AgentMemoryExample'), 'Memory-aware conversation and retrieval example.'),
|
|
117
117
|
makeEntry('AgentSkillsExample', () => import('./AgentSkillsExample'), 'Skills discovery, execution, and monitoring example.'),
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
|
28
28
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
29
29
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
|
30
30
|
export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
|
|
31
|
-
export { default as
|
|
31
|
+
export { default as AgentStrategyExample } from './AgentStrategyExample';
|
|
32
32
|
export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
|
|
33
33
|
export { default as AgentMemoryExample } from './AgentMemoryExample';
|
|
34
34
|
export { default as AgentOtelExample } from './AgentOtelExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -34,7 +34,7 @@ export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
|
34
34
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
35
35
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
|
36
36
|
export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
|
|
37
|
-
export { default as
|
|
37
|
+
export { default as AgentStrategyExample } from './AgentStrategyExample';
|
|
38
38
|
export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
|
|
39
39
|
export { default as AgentMemoryExample } from './AgentMemoryExample';
|
|
40
40
|
export { default as AgentOtelExample } from './AgentOtelExample';
|
package/lib/examples/main.js
CHANGED
|
@@ -86,7 +86,7 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
86
86
|
]);
|
|
87
87
|
const getExampleGroup = (id) => {
|
|
88
88
|
if (id === 'AgentspecsExample' ||
|
|
89
|
-
id === '
|
|
89
|
+
id === 'AgentStrategyExample' ||
|
|
90
90
|
id === 'LoopWorkspaceExample' ||
|
|
91
91
|
id === 'LoopShellExample' ||
|
|
92
92
|
id === 'DecksAgent') {
|
|
@@ -1068,12 +1068,12 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
|
|
|
1068
1068
|
for (const [groupName, examples] of groups) {
|
|
1069
1069
|
examples.sort((left, right) => {
|
|
1070
1070
|
if (groupName === 'Loop') {
|
|
1071
|
-
// The shells first, most naked first; then the
|
|
1071
|
+
// The shells first, most naked first; then the strategy that drives a
|
|
1072
1072
|
// notebook; then the library of specs behind them all.
|
|
1073
1073
|
const LOOP_ORDER = [
|
|
1074
1074
|
'LoopShellExample',
|
|
1075
1075
|
'LoopWorkspaceExample',
|
|
1076
|
-
'
|
|
1076
|
+
'AgentStrategyExample',
|
|
1077
1077
|
'AgentspecsExample',
|
|
1078
1078
|
];
|
|
1079
1079
|
const loopOrder = (id) => {
|
|
@@ -1288,12 +1288,13 @@ export default function ChatView({ workspace }) {
|
|
|
1288
1288
|
const offeredTools = useMemo(() => {
|
|
1289
1289
|
const fromServer = configQuery.data?.builtinTools ?? [];
|
|
1290
1290
|
const seen = new Set(fromServer.map(tool => tool.name));
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1291
|
+
// The runtime's, and the frontend tools this page runs: named apart.
|
|
1292
|
+
return {
|
|
1293
|
+
runtime: fromServer,
|
|
1294
|
+
frontend: agentTools
|
|
1294
1295
|
.filter(tool => !seen.has(tool.name))
|
|
1295
1296
|
.map(tool => ({ id: tool.name, name: tool.name })),
|
|
1296
|
-
|
|
1297
|
+
};
|
|
1297
1298
|
}, [configQuery.data?.builtinTools, agentTools]);
|
|
1298
1299
|
/* Which skills are on, as the runtime last reported them. Derived rather
|
|
1299
1300
|
than held: the source of truth is the agent, and a local copy would drift
|
|
@@ -1423,7 +1424,8 @@ export default function ChatView({ workspace }) {
|
|
|
1423
1424
|
selectedModel: activeModel,
|
|
1424
1425
|
onModelSelect: model => void selectModel(model),
|
|
1425
1426
|
showToolsMenu: !presence,
|
|
1426
|
-
availableTools: offeredTools,
|
|
1427
|
+
availableTools: offeredTools.runtime,
|
|
1428
|
+
availableFrontendTools: offeredTools.frontend,
|
|
1427
1429
|
mcpServers: configQuery.data?.mcpServers ?? [],
|
|
1428
1430
|
// Live from the host example, when one feeds it: the footer's MCP status
|
|
1429
1431
|
// indicator. (Codemode surfaces through the toggle below, not a blob.)
|
package/lib/specs/actions.js
CHANGED
|
@@ -547,6 +547,62 @@ export const SERVER_ACTIONS = {
|
|
|
547
547
|
tools: {},
|
|
548
548
|
conditions: {},
|
|
549
549
|
},
|
|
550
|
+
'odoo-accounting': {
|
|
551
|
+
checked: '2026-10-05',
|
|
552
|
+
default: [],
|
|
553
|
+
tools: {
|
|
554
|
+
odoo_accounting_list_invoices: ['read'],
|
|
555
|
+
odoo_accounting_get_invoice: ['read'],
|
|
556
|
+
odoo_accounting_list_journal_entries: ['read'],
|
|
557
|
+
odoo_accounting_list_open_balances: ['read'],
|
|
558
|
+
odoo_accounting_list_accounts: ['read'],
|
|
559
|
+
odoo_accounting_list_journals: ['read'],
|
|
560
|
+
odoo_accounting_get_journal_entry: ['read'],
|
|
561
|
+
odoo_accounting_trial_balance: ['read'],
|
|
562
|
+
odoo_accounting_general_ledger: ['read'],
|
|
563
|
+
odoo_accounting_create_draft_invoice: ['write'],
|
|
564
|
+
odoo_accounting_post_invoice: ['write'],
|
|
565
|
+
odoo_accounting_create_draft_journal_entry: ['write'],
|
|
566
|
+
odoo_accounting_post_journal_entry: ['write'],
|
|
567
|
+
odoo_accounting_list_partners: ['read'],
|
|
568
|
+
odoo_accounting_partner_ledger: ['read'],
|
|
569
|
+
odoo_accounting_aged_balance: ['read'],
|
|
570
|
+
odoo_accounting_list_taxes: ['read'],
|
|
571
|
+
odoo_accounting_list_assets: ['read'],
|
|
572
|
+
odoo_accounting_get_asset: ['read'],
|
|
573
|
+
odoo_accounting_reconcile_lines: ['write'],
|
|
574
|
+
odoo_accounting_unreconcile_lines: ['write'],
|
|
575
|
+
odoo_accounting_bank_status: ['read'],
|
|
576
|
+
odoo_accounting_list_bank_lines: ['read'],
|
|
577
|
+
odoo_accounting_get_bank_line: ['read'],
|
|
578
|
+
odoo_accounting_suggest_bank_matches: ['read'],
|
|
579
|
+
odoo_accounting_suggest_reconciliations: ['read'],
|
|
580
|
+
odoo_accounting_explain_account_balance: ['read'],
|
|
581
|
+
odoo_accounting_list_bank_feeds: ['read'],
|
|
582
|
+
odoo_accounting_list_currency_rates: ['read'],
|
|
583
|
+
odoo_accounting_get_lock_dates: ['read'],
|
|
584
|
+
odoo_accounting_book_bank_line: ['write'],
|
|
585
|
+
odoo_accounting_match_bank_line: ['write'],
|
|
586
|
+
odoo_accounting_reset_bank_line: ['write'],
|
|
587
|
+
odoo_accounting_remove_duplicate_bank_lines: ['delete'],
|
|
588
|
+
odoo_accounting_link_bank_feed: ['write'],
|
|
589
|
+
odoo_accounting_create_vendor_bill: ['write'],
|
|
590
|
+
odoo_accounting_create_customer_invoice: ['write'],
|
|
591
|
+
odoo_accounting_set_currency_rates: ['write'],
|
|
592
|
+
odoo_accounting_set_lock_date: ['write'],
|
|
593
|
+
odoo_accounting_create_matching_model: ['write'],
|
|
594
|
+
odoo_accounting_get_tax_settings: ['read'],
|
|
595
|
+
odoo_accounting_list_tax_returns: ['read'],
|
|
596
|
+
odoo_accounting_get_tax_return: ['read'],
|
|
597
|
+
odoo_accounting_tax_grids: ['read'],
|
|
598
|
+
odoo_accounting_list_tax_grid_lines: ['read'],
|
|
599
|
+
odoo_accounting_check_tax_period: ['read'],
|
|
600
|
+
odoo_accounting_list_untagged_tax_lines: ['read'],
|
|
601
|
+
odoo_accounting_set_tax_periodicity: ['write'],
|
|
602
|
+
odoo_accounting_set_tax_grids: ['write'],
|
|
603
|
+
},
|
|
604
|
+
conditions: {},
|
|
605
|
+
},
|
|
550
606
|
salesforce: {
|
|
551
607
|
default: [],
|
|
552
608
|
tools: {},
|
|
@@ -32,7 +32,7 @@ export const DECKS_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
32
32
|
'decks_present',
|
|
33
33
|
'decks_print',
|
|
34
34
|
],
|
|
35
|
-
icon: 'project',
|
|
35
|
+
icon: '@primer/octicons-react:project',
|
|
36
36
|
emoji: '🃏',
|
|
37
37
|
};
|
|
38
38
|
export const JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
@@ -50,7 +50,7 @@ export const JUPYTER_NOTEBOOK_EDIT_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
50
50
|
'runCell',
|
|
51
51
|
'executeCode',
|
|
52
52
|
],
|
|
53
|
-
icon: '
|
|
53
|
+
icon: '@datalayer/icons-react:jupyter',
|
|
54
54
|
emoji: '📓',
|
|
55
55
|
};
|
|
56
56
|
export const JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
@@ -61,7 +61,7 @@ export const JUPYTER_NOTEBOOK_PROPOSE_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
61
61
|
tags: ['frontend', 'notebook', 'propose'],
|
|
62
62
|
enabled: true,
|
|
63
63
|
toolset: ['readCell', 'readAllCells', 'proposeCellUpdate', 'runCell'],
|
|
64
|
-
icon: '
|
|
64
|
+
icon: '@datalayer/icons-react:jupyter',
|
|
65
65
|
emoji: '📓',
|
|
66
66
|
};
|
|
67
67
|
export const JUPYTER_NOTEBOOK_READ_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
@@ -72,7 +72,7 @@ export const JUPYTER_NOTEBOOK_READ_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
72
72
|
tags: ['frontend', 'notebook', 'read'],
|
|
73
73
|
enabled: true,
|
|
74
74
|
toolset: ['readCell', 'readAllCells'],
|
|
75
|
-
icon: '
|
|
75
|
+
icon: '@datalayer/icons-react:jupyter',
|
|
76
76
|
emoji: '📓',
|
|
77
77
|
};
|
|
78
78
|
export const JUPYTER_NOTEBOOK_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
@@ -83,7 +83,7 @@ export const JUPYTER_NOTEBOOK_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
83
83
|
tags: ['frontend', 'notebook', 'jupyter-server'],
|
|
84
84
|
enabled: true,
|
|
85
85
|
toolset: 'all',
|
|
86
|
-
icon: '
|
|
86
|
+
icon: '@datalayer/icons-react:jupyter',
|
|
87
87
|
emoji: '📓',
|
|
88
88
|
};
|
|
89
89
|
export const LEXICAL_DOCUMENT_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
@@ -94,7 +94,7 @@ export const LEXICAL_DOCUMENT_FRONTEND_TOOL_SPEC_0_0_1 = {
|
|
|
94
94
|
tags: ['frontend', 'document', 'lexical', 'drawing', 'diagram'],
|
|
95
95
|
enabled: true,
|
|
96
96
|
toolset: 'all',
|
|
97
|
-
icon: 'file',
|
|
97
|
+
icon: '@primer/octicons-react:file',
|
|
98
98
|
emoji: '📄',
|
|
99
99
|
};
|
|
100
100
|
// ============================================================================
|