@datalayer/agent-runtimes 0.0.10 → 0.0.12
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/README.md +2 -2
- package/lib/Agent.d.ts +29 -0
- package/lib/Agent.js +131 -0
- package/lib/AgentLexical.d.ts +34 -0
- package/lib/AgentLexical.js +296 -0
- package/lib/AgentNotebook.d.ts +19 -0
- package/lib/AgentNotebook.js +192 -0
- package/lib/agent-lexical-main.d.ts +1 -0
- package/lib/agent-lexical-main.js +11 -0
- package/lib/agent-main.d.ts +1 -0
- package/lib/agent-main.js +11 -0
- package/lib/agent-notebook-main.d.ts +1 -0
- package/lib/agent-notebook-main.js +12 -0
- package/lib/components/AgentConfiguration.d.ts +33 -21
- package/lib/components/AgentConfiguration.js +76 -21
- package/lib/components/chat/components/AgentDetails.d.ts +3 -1
- package/lib/components/chat/components/AgentDetails.js +164 -6
- package/lib/components/chat/components/Chat.d.ts +29 -3
- package/lib/components/chat/components/Chat.js +64 -59
- package/lib/components/chat/components/ChatFloating.d.ts +34 -12
- package/lib/components/chat/components/ChatFloating.js +54 -21
- package/lib/components/chat/components/ChatInline.d.ts +5 -1
- package/lib/components/chat/components/ChatInline.js +8 -1
- package/lib/components/chat/components/ChatSidebar.d.ts +6 -1
- package/lib/components/chat/components/ChatSidebar.js +2 -2
- package/lib/components/chat/components/ChatStandalone.d.ts +6 -1
- package/lib/components/chat/components/ChatStandalone.js +2 -2
- package/lib/components/chat/components/ContextDistribution.js +2 -2
- package/lib/components/chat/components/ContextInspector.js +4 -2
- package/lib/components/chat/components/ContextPanel.js +1 -6
- package/lib/components/chat/components/base/ChatBase.d.ts +49 -8
- package/lib/components/chat/components/base/ChatBase.js +544 -149
- package/lib/components/chat/components/base/InputPrompt.d.ts +42 -0
- package/lib/components/chat/components/base/InputPrompt.js +131 -0
- package/lib/components/chat/components/index.d.ts +3 -3
- package/lib/components/chat/components/index.js +1 -1
- package/lib/components/chat/components/parts/ReasoningPart.js +2 -4
- package/lib/components/chat/components/parts/TextPart.js +2 -70
- package/lib/components/chat/components/styles/streamdownStyles.d.ts +23 -0
- package/lib/components/chat/components/styles/streamdownStyles.js +319 -0
- package/lib/components/chat/index.d.ts +1 -1
- package/lib/components/chat/index.js +1 -1
- package/lib/components/chat/inference/DatalayerInferenceProvider.js +16 -12
- package/lib/components/chat/inference/SelfHostedInferenceProvider.js +16 -12
- package/lib/components/chat/protocols/AGUIAdapter.d.ts +10 -3
- package/lib/components/chat/protocols/AGUIAdapter.js +123 -44
- package/lib/components/chat/types/tool.d.ts +5 -2
- package/lib/components/index.d.ts +2 -19
- package/lib/components/index.js +1 -10
- package/lib/config/index.d.ts +0 -3
- package/lib/config/index.js +0 -3
- package/lib/examples/A2UiRestaurantExample.js +1 -1
- package/lib/examples/AgentRuntimeChatExample.d.ts +15 -0
- package/lib/examples/AgentRuntimeChatExample.js +126 -0
- package/lib/examples/{AgentSpaceFormExample.d.ts → AgentRuntimeFormExample.d.ts} +3 -3
- package/lib/examples/{AgentSpaceFormExample.js → AgentRuntimeFormExample.js} +61 -17
- package/lib/examples/AgentRuntimeLexicalExample.js +6 -3
- package/lib/examples/AgentRuntimeLexicalSidebarExample.js +8 -1
- package/lib/examples/AgentRuntimeNotebookExample.js +6 -5
- package/lib/examples/CopilotKitNotebookExample.js +2 -2
- package/lib/examples/JupyterNotebookExample.js +2 -2
- package/lib/{components → examples/components}/Header.d.ts +2 -1
- package/lib/{components → examples/components}/HeaderControls.js +1 -1
- package/lib/{components → examples/components}/LexicalEditor.d.ts +6 -1
- package/lib/{components → examples/components}/LexicalEditor.js +4 -4
- package/lib/{components → examples/components}/MainContent.d.ts +1 -1
- package/lib/{components → examples/components}/MainContent.js +7 -5
- package/lib/examples/components/index.d.ts +16 -0
- package/lib/examples/components/index.js +13 -0
- package/lib/examples/example-selector.js +2 -1
- package/lib/examples/index.d.ts +1 -1
- package/lib/examples/index.js +1 -1
- package/lib/examples/main.js +2 -2
- package/lib/examples/stores/examplesStore.d.ts +2 -23
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -0
- package/lib/lexical/ChatInlinePlugin.d.ts +13 -2
- package/lib/lexical/ChatInlinePlugin.js +41 -179
- package/lib/lexical/index.d.ts +1 -0
- package/lib/lexical/index.js +1 -0
- package/lib/lexical/useChatInlineToolbarItems.d.ts +28 -0
- package/lib/lexical/useChatInlineToolbarItems.js +163 -0
- package/lib/runtime/useAgentRuntime.d.ts +1 -1
- package/lib/runtime/useAgentRuntime.js +1 -1
- package/lib/specs/agents/codeai/agents.d.ts +28 -0
- package/lib/specs/agents/codeai/agents.js +151 -0
- package/lib/specs/agents/codeai/index.d.ts +1 -0
- package/lib/specs/agents/codeai/index.js +5 -0
- package/lib/{config → specs/agents/codemode-paper}/agents.d.ts +4 -6
- package/lib/specs/agents/codemode-paper/agents.js +308 -0
- package/lib/specs/agents/codemode-paper/index.d.ts +1 -0
- package/lib/specs/agents/codemode-paper/index.js +5 -0
- package/lib/specs/agents/datalayer-ai/agents.d.ts +31 -0
- package/lib/{config → specs/agents/datalayer-ai}/agents.js +42 -184
- package/lib/specs/agents/datalayer-ai/index.d.ts +1 -0
- package/lib/specs/agents/datalayer-ai/index.js +5 -0
- package/lib/specs/agents/index.d.ts +21 -0
- package/lib/specs/agents/index.js +47 -0
- package/lib/specs/envvars.d.ts +29 -0
- package/lib/specs/envvars.js +125 -0
- package/lib/specs/index.d.ts +5 -0
- package/lib/specs/index.js +9 -0
- package/lib/{config → specs}/mcpServers.d.ts +2 -1
- package/lib/{config → specs}/mcpServers.js +47 -1
- package/lib/specs/models.d.ts +68 -0
- package/lib/specs/models.js +239 -0
- package/lib/{config → specs}/skills.d.ts +2 -0
- package/lib/{config → specs}/skills.js +6 -0
- package/lib/state/substates/AIAgentState.d.ts +0 -1
- package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.d.ts +11 -22
- package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +5 -5
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -6
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +4 -4
- package/lib/tools/adapters/agent-runtimes/notebookHooks.d.ts +6 -6
- package/lib/tools/adapters/agent-runtimes/notebookHooks.js +4 -4
- package/lib/{types.d.ts → types/Types.d.ts} +42 -8
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/package.json +11 -5
- package/scripts/codegen/generate_agents.py +608 -157
- package/scripts/codegen/generate_envvars.py +302 -0
- package/scripts/codegen/generate_mcp_servers.py +33 -21
- package/scripts/codegen/generate_models.py +486 -0
- package/scripts/codegen/generate_skills.py +21 -8
- package/style/primer-primitives.css +22 -0
- package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +0 -37
- package/lib/components/chat/components/elements/ChatInputPrompt.js +0 -150
- /package/lib/{components → examples/components}/FooterMetrics.d.ts +0 -0
- /package/lib/{components → examples/components}/FooterMetrics.js +0 -0
- /package/lib/{components → examples/components}/Header.js +0 -0
- /package/lib/{components → examples/components}/HeaderControls.d.ts +0 -0
- /package/lib/{components → examples/components}/MockFileBrowser.d.ts +0 -0
- /package/lib/{components → examples/components}/MockFileBrowser.js +0 -0
- /package/lib/{components → examples/components}/SessionTabs.d.ts +0 -0
- /package/lib/{components → examples/components}/SessionTabs.js +0 -0
- /package/lib/{components → examples/components}/TimeTravel.d.ts +0 -0
- /package/lib/{components → examples/components}/TimeTravel.js +0 -0
- /package/lib/{types.js → types/Types.js} +0 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://github.com/sponsors/datalayer)
|
|
10
10
|
|
|
11
|
-
# 🤖 Agent Runtimes
|
|
11
|
+
# 🤖 🚀 Agent Runtimes
|
|
12
12
|
|
|
13
13
|
[](https://github.com/datalayer/agent-runtimes/actions/workflows/build.yml)
|
|
14
14
|
[](https://app.netlify.com/projects/agent-runtimes/deploys)
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
**Agent Runtimes** is a unified platform for deploying, managing, and interacting with AI agents across multiple protocols and frameworks. It provides both a Python server for hosting agents and React components for seamless integration into web and desktop applications.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## What is Agent Runtimes?
|
|
20
20
|
|
|
21
21
|
Agent Runtimes solves the complexity of deploying AI agents by providing:
|
|
22
22
|
|
package/lib/Agent.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent
|
|
3
|
+
*
|
|
4
|
+
* Standalone chat interface served at /static/agent.html.
|
|
5
|
+
* Connects to the agent-runtimes AG-UI endpoint.
|
|
6
|
+
*
|
|
7
|
+
* The page is opened by codeai with a URL like:
|
|
8
|
+
* http://127.0.0.1:<port>/static/agent.html?agentId=<id>
|
|
9
|
+
*
|
|
10
|
+
* On mount it ensures the agent exists — creating it automatically
|
|
11
|
+
* if it doesn't — then renders the unified Chat component.
|
|
12
|
+
*
|
|
13
|
+
* Uses the unified Chat component which handles:
|
|
14
|
+
* - AG-UI protocol configuration
|
|
15
|
+
* - AgentDetails panel (via showInformation)
|
|
16
|
+
* - Conversation history persistence
|
|
17
|
+
* - Model/tools/skills selectors
|
|
18
|
+
* - Error and loading states
|
|
19
|
+
*/
|
|
20
|
+
import React from 'react';
|
|
21
|
+
import '../style/primer-primitives.css';
|
|
22
|
+
/**
|
|
23
|
+
* Agent component — full-page chat interface.
|
|
24
|
+
*
|
|
25
|
+
* Reads the `agentId` query-string parameter, waits for the agent
|
|
26
|
+
* to be available, then renders the Chat.
|
|
27
|
+
*/
|
|
28
|
+
export declare const Agent: React.FC;
|
|
29
|
+
export default Agent;
|
package/lib/Agent.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Agent
|
|
8
|
+
*
|
|
9
|
+
* Standalone chat interface served at /static/agent.html.
|
|
10
|
+
* Connects to the agent-runtimes AG-UI endpoint.
|
|
11
|
+
*
|
|
12
|
+
* The page is opened by codeai with a URL like:
|
|
13
|
+
* http://127.0.0.1:<port>/static/agent.html?agentId=<id>
|
|
14
|
+
*
|
|
15
|
+
* On mount it ensures the agent exists — creating it automatically
|
|
16
|
+
* if it doesn't — then renders the unified Chat component.
|
|
17
|
+
*
|
|
18
|
+
* Uses the unified Chat component which handles:
|
|
19
|
+
* - AG-UI protocol configuration
|
|
20
|
+
* - AgentDetails panel (via showInformation)
|
|
21
|
+
* - Conversation history persistence
|
|
22
|
+
* - Model/tools/skills selectors
|
|
23
|
+
* - Error and loading states
|
|
24
|
+
*/
|
|
25
|
+
import { useEffect, useState } from 'react';
|
|
26
|
+
import { Text, Spinner } from '@primer/react';
|
|
27
|
+
import { AlertIcon } from '@primer/octicons-react';
|
|
28
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
29
|
+
import { DatalayerThemeProvider } from '@datalayer/core';
|
|
30
|
+
import { Chat } from './components/chat';
|
|
31
|
+
import { DEFAULT_MODEL } from './specs';
|
|
32
|
+
import '../style/primer-primitives.css';
|
|
33
|
+
setupPrimerPortals();
|
|
34
|
+
const BASE_URL = window.location.origin;
|
|
35
|
+
function getAgentId() {
|
|
36
|
+
const params = new URLSearchParams(window.location.search);
|
|
37
|
+
return params.get('agentId') || 'default';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Agent component — full-page chat interface.
|
|
41
|
+
*
|
|
42
|
+
* Reads the `agentId` query-string parameter, waits for the agent
|
|
43
|
+
* to be available, then renders the Chat.
|
|
44
|
+
*/
|
|
45
|
+
export const Agent = () => {
|
|
46
|
+
const [agentId] = useState(getAgentId);
|
|
47
|
+
const [isReady, setIsReady] = useState(false);
|
|
48
|
+
const [error, setError] = useState(null);
|
|
49
|
+
// Ensure the agent exists on mount — create it if it doesn't
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
let cancelled = false;
|
|
52
|
+
const ensureAgent = async () => {
|
|
53
|
+
try {
|
|
54
|
+
// First check if the agent already exists
|
|
55
|
+
const getResp = await fetch(`${BASE_URL}/api/v1/agents/${encodeURIComponent(agentId)}`);
|
|
56
|
+
if (getResp.ok) {
|
|
57
|
+
if (!cancelled)
|
|
58
|
+
setIsReady(true);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Agent doesn't exist — create it
|
|
62
|
+
const createResp = await fetch(`${BASE_URL}/api/v1/agents`, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: { 'Content-Type': 'application/json' },
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
name: agentId,
|
|
67
|
+
description: 'Agent created by Agent page',
|
|
68
|
+
agent_library: 'pydantic-ai',
|
|
69
|
+
transport: 'ag-ui',
|
|
70
|
+
model: DEFAULT_MODEL,
|
|
71
|
+
system_prompt: 'You are a helpful AI assistant. You can help with code, explanations, and data analysis.',
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
if (createResp.ok || createResp.status === 400) {
|
|
75
|
+
// 400 means agent already exists (race condition), which is fine
|
|
76
|
+
if (!cancelled)
|
|
77
|
+
setIsReady(true);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const errorData = await createResp.json().catch(() => ({}));
|
|
81
|
+
throw new Error(errorData.detail || `Failed to create agent: ${createResp.status}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (!cancelled) {
|
|
86
|
+
setError(err instanceof Error ? err.message : 'Failed to reach agent');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
ensureAgent();
|
|
91
|
+
return () => {
|
|
92
|
+
cancelled = true;
|
|
93
|
+
};
|
|
94
|
+
}, [agentId]);
|
|
95
|
+
// Loading state while verifying agent
|
|
96
|
+
if (!isReady && !error) {
|
|
97
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
|
|
98
|
+
display: 'flex',
|
|
99
|
+
flexDirection: 'column',
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
height: '100vh',
|
|
103
|
+
gap: 3,
|
|
104
|
+
bg: 'canvas.default',
|
|
105
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: ["Connecting to agent ", agentId, "..."] })] }) }));
|
|
106
|
+
}
|
|
107
|
+
// Error state
|
|
108
|
+
if (error) {
|
|
109
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
|
|
110
|
+
display: 'flex',
|
|
111
|
+
flexDirection: 'column',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
justifyContent: 'center',
|
|
114
|
+
height: '100vh',
|
|
115
|
+
gap: 3,
|
|
116
|
+
bg: 'canvas.default',
|
|
117
|
+
}, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: "Failed to connect to agent" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: error })] }) }));
|
|
118
|
+
}
|
|
119
|
+
// Agent is ready — render the Chat component
|
|
120
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsx(Chat, { transport: "ag-ui", baseUrl: BASE_URL, agentId: agentId, title: "Agent", placeholder: "Send a message...", description: "Chat with the agent", showHeader: true, height: '100vh', showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, runtimeId: agentId, historyEndpoint: `${BASE_URL}/api/v1/history`, suggestions: [
|
|
121
|
+
{
|
|
122
|
+
title: 'Hello',
|
|
123
|
+
message: 'Hello, what can you do?',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
title: 'Help',
|
|
127
|
+
message: 'What tools do you have available?',
|
|
128
|
+
},
|
|
129
|
+
], submitOnSuggestionClick: true }) }));
|
|
130
|
+
};
|
|
131
|
+
export default Agent;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentLexical
|
|
3
|
+
*
|
|
4
|
+
* Standalone Lexical editor + chat interface served at /static/agent-lexical.html.
|
|
5
|
+
* Connects to the agent-runtimes AG-UI endpoint and provides a Lexical
|
|
6
|
+
* rich-text editor alongside the Chat component with lexical tools registered.
|
|
7
|
+
*
|
|
8
|
+
* The page is opened by codeai with a URL like:
|
|
9
|
+
* http://127.0.0.1:<port>/static/agent-lexical.html?agentId=<id>
|
|
10
|
+
*
|
|
11
|
+
* Query parameters:
|
|
12
|
+
* - agentId: the agent identifier (required, set by codeai)
|
|
13
|
+
* - jupyterBaseUrl: base URL for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
14
|
+
* - jupyterToken: token for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
15
|
+
*/
|
|
16
|
+
import 'prismjs';
|
|
17
|
+
import 'prismjs/components/prism-clike';
|
|
18
|
+
import 'prismjs/components/prism-javascript';
|
|
19
|
+
import 'prismjs/components/prism-markup';
|
|
20
|
+
import 'prismjs/components/prism-markdown';
|
|
21
|
+
import 'prismjs/components/prism-c';
|
|
22
|
+
import 'prismjs/components/prism-css';
|
|
23
|
+
import 'prismjs/components/prism-objectivec';
|
|
24
|
+
import 'prismjs/components/prism-sql';
|
|
25
|
+
import 'prismjs/components/prism-python';
|
|
26
|
+
import 'prismjs/components/prism-rust';
|
|
27
|
+
import 'prismjs/components/prism-swift';
|
|
28
|
+
import React from 'react';
|
|
29
|
+
import '@datalayer/jupyter-lexical/style/index.css';
|
|
30
|
+
import './examples/lexical/lexical-theme.css';
|
|
31
|
+
import '@datalayer/jupyter-lexical/style/modal-overrides.css';
|
|
32
|
+
import '../style/primer-primitives.css';
|
|
33
|
+
export declare const AgentLexical: React.FC;
|
|
34
|
+
export default AgentLexical;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* AgentLexical
|
|
8
|
+
*
|
|
9
|
+
* Standalone Lexical editor + chat interface served at /static/agent-lexical.html.
|
|
10
|
+
* Connects to the agent-runtimes AG-UI endpoint and provides a Lexical
|
|
11
|
+
* rich-text editor alongside the Chat component with lexical tools registered.
|
|
12
|
+
*
|
|
13
|
+
* The page is opened by codeai with a URL like:
|
|
14
|
+
* http://127.0.0.1:<port>/static/agent-lexical.html?agentId=<id>
|
|
15
|
+
*
|
|
16
|
+
* Query parameters:
|
|
17
|
+
* - agentId: the agent identifier (required, set by codeai)
|
|
18
|
+
* - jupyterBaseUrl: base URL for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
19
|
+
* - jupyterToken: token for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
20
|
+
*/
|
|
21
|
+
import 'prismjs';
|
|
22
|
+
import 'prismjs/components/prism-clike';
|
|
23
|
+
import 'prismjs/components/prism-javascript';
|
|
24
|
+
import 'prismjs/components/prism-markup';
|
|
25
|
+
import 'prismjs/components/prism-markdown';
|
|
26
|
+
import 'prismjs/components/prism-c';
|
|
27
|
+
import 'prismjs/components/prism-css';
|
|
28
|
+
import 'prismjs/components/prism-objectivec';
|
|
29
|
+
import 'prismjs/components/prism-sql';
|
|
30
|
+
import 'prismjs/components/prism-python';
|
|
31
|
+
import 'prismjs/components/prism-rust';
|
|
32
|
+
import 'prismjs/components/prism-swift';
|
|
33
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
34
|
+
import { $getRoot, $createParagraphNode } from 'lexical';
|
|
35
|
+
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
|
36
|
+
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
|
37
|
+
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
|
38
|
+
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
|
39
|
+
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
40
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
41
|
+
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
|
|
42
|
+
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
|
|
43
|
+
import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';
|
|
44
|
+
import { TRANSFORMERS } from '@lexical/markdown';
|
|
45
|
+
import { registerCodeHighlighting } from '@lexical/code';
|
|
46
|
+
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
|
|
47
|
+
import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin';
|
|
48
|
+
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
|
|
49
|
+
import { Text, Spinner } from '@primer/react';
|
|
50
|
+
import { AlertIcon } from '@primer/octicons-react';
|
|
51
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
52
|
+
import { DatalayerThemeProvider } from '@datalayer/core';
|
|
53
|
+
import { JupyterReactTheme, loadJupyterConfig, createServerSettings, getJupyterServerUrl, getJupyterServerToken, setJupyterServerUrl, setJupyterServerToken, useJupyter, } from '@datalayer/jupyter-react';
|
|
54
|
+
import { ComponentPickerMenuPlugin, JupyterCellPlugin, JupyterInputOutputPlugin, DraggableBlockPlugin, ImagesPlugin, HorizontalRulePlugin, EquationsPlugin, YouTubePlugin, ExcalidrawPlugin, CollapsiblePlugin, AutoLinkPlugin, AutoEmbedPlugin, LexicalConfigProvider, LexicalStatePlugin, FloatingTextFormatToolbarPlugin, CodeActionMenuPlugin, ListMaxIndentLevelPlugin, TableCellResizerPlugin, TablePlugin, } from '@datalayer/jupyter-lexical';
|
|
55
|
+
import { ServiceManager } from '@jupyterlab/services';
|
|
56
|
+
import { Chat } from './components/chat';
|
|
57
|
+
import { ChatInlinePlugin } from './lexical/ChatInlinePlugin';
|
|
58
|
+
import { useChatInlineToolbarItems } from './lexical/useChatInlineToolbarItems';
|
|
59
|
+
import { useLexicalTools } from './tools/adapters/agent-runtimes/lexicalHooks';
|
|
60
|
+
import { editorConfig } from './examples/lexical/editorConfig';
|
|
61
|
+
import { DEFAULT_MODEL } from './specs';
|
|
62
|
+
import '@datalayer/jupyter-lexical/style/index.css';
|
|
63
|
+
import './examples/lexical/lexical-theme.css';
|
|
64
|
+
import '@datalayer/jupyter-lexical/style/modal-overrides.css';
|
|
65
|
+
import '../style/primer-primitives.css';
|
|
66
|
+
setupPrimerPortals();
|
|
67
|
+
const BASE_URL = window.location.origin;
|
|
68
|
+
const LEXICAL_ID = 'agent-lexical';
|
|
69
|
+
function getQueryParam(name) {
|
|
70
|
+
return new URLSearchParams(window.location.search).get(name);
|
|
71
|
+
}
|
|
72
|
+
function getAgentId() {
|
|
73
|
+
return getQueryParam('agentId') || 'default';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Initialise Jupyter configuration.
|
|
77
|
+
*
|
|
78
|
+
* Priority:
|
|
79
|
+
* 1. Query parameters (jupyterBaseUrl / jupyterToken)
|
|
80
|
+
* 2. <script id="jupyter-config-data"> block in the HTML page
|
|
81
|
+
*/
|
|
82
|
+
function initJupyterConfig() {
|
|
83
|
+
loadJupyterConfig();
|
|
84
|
+
const qBaseUrl = getQueryParam('jupyterBaseUrl');
|
|
85
|
+
const qToken = getQueryParam('jupyterToken');
|
|
86
|
+
if (qBaseUrl)
|
|
87
|
+
setJupyterServerUrl(qBaseUrl);
|
|
88
|
+
if (qToken)
|
|
89
|
+
setJupyterServerToken(qToken);
|
|
90
|
+
const el = document.getElementById('jupyter-config-data');
|
|
91
|
+
if (el?.textContent) {
|
|
92
|
+
try {
|
|
93
|
+
const cfg = JSON.parse(el.textContent);
|
|
94
|
+
if (!qBaseUrl && cfg.baseUrl)
|
|
95
|
+
setJupyterServerUrl(cfg.baseUrl);
|
|
96
|
+
if (!qToken && cfg.token)
|
|
97
|
+
setJupyterServerToken(cfg.token);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// ignore
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// ─── Lexical plugins ────────────────────────────────────────────────────────
|
|
105
|
+
/**
|
|
106
|
+
* Lexical plugin for loading initial content into the editor.
|
|
107
|
+
*/
|
|
108
|
+
function LoadContentPlugin({ content }) {
|
|
109
|
+
const [editor] = useLexicalComposerContext();
|
|
110
|
+
const isFirstRender = useRef(true);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!content || !isFirstRender.current) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
isFirstRender.current = false;
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(content);
|
|
118
|
+
if (parsed && typeof parsed === 'object' && parsed.root) {
|
|
119
|
+
const editorState = editor.parseEditorState(content);
|
|
120
|
+
editor.setEditorState(editorState, { tag: 'history-merge' });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
throw new Error('Invalid Lexical editor state format');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
editor.update(() => {
|
|
128
|
+
const root = $getRoot();
|
|
129
|
+
root.clear();
|
|
130
|
+
const paragraph = $createParagraphNode();
|
|
131
|
+
root.append(paragraph);
|
|
132
|
+
}, { tag: 'history-merge' });
|
|
133
|
+
}
|
|
134
|
+
}, [content, editor]);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
function CodeHighlightPlugin() {
|
|
138
|
+
const [editor] = useLexicalComposerContext();
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
return registerCodeHighlighting(editor);
|
|
141
|
+
}, [editor]);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
function KernelPluginsInner() {
|
|
145
|
+
const { defaultKernel } = useJupyter();
|
|
146
|
+
return (_jsxs(_Fragment, { children: [_jsx(ComponentPickerMenuPlugin, { kernel: defaultKernel }), _jsx(JupyterInputOutputPlugin, { kernel: defaultKernel })] }));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Plugin that captures lexical tools and passes them to parent.
|
|
150
|
+
* Must be rendered inside LexicalConfigProvider context.
|
|
151
|
+
*/
|
|
152
|
+
function LexicalToolsPlugin({ onToolsReady, }) {
|
|
153
|
+
const tools = useLexicalTools(LEXICAL_ID);
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
onToolsReady(tools);
|
|
156
|
+
}, [tools, onToolsReady]);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const LexicalPanel = React.memo(function LexicalPanel({ serviceManager, onToolsReady, }) {
|
|
160
|
+
const [floatingAnchorElem, setFloatingAnchorElem] = useState(null);
|
|
161
|
+
const [_isLinkEditMode, setIsLinkEditMode] = useState(false);
|
|
162
|
+
const { toolbarItems, isAiOpen, pendingPrompt, clearPendingPrompt, closeAi } = useChatInlineToolbarItems();
|
|
163
|
+
const onRef = (_floatingAnchorElem) => {
|
|
164
|
+
if (_floatingAnchorElem !== null) {
|
|
165
|
+
setFloatingAnchorElem(_floatingAnchorElem);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const handleChange = useCallback((_editorState) => {
|
|
169
|
+
// onChange handler
|
|
170
|
+
}, []);
|
|
171
|
+
const agentId = getAgentId();
|
|
172
|
+
const agUiEndpoint = `${BASE_URL}/api/v1/ag-ui/${encodeURIComponent(agentId)}/`;
|
|
173
|
+
return (_jsx(Box, { sx: {
|
|
174
|
+
flex: 1,
|
|
175
|
+
display: 'flex',
|
|
176
|
+
flexDirection: 'column',
|
|
177
|
+
overflow: 'auto',
|
|
178
|
+
borderRight: '1px solid',
|
|
179
|
+
borderColor: 'border.default',
|
|
180
|
+
}, children: _jsx(Box, { sx: { padding: 3 }, children: _jsxs(LexicalConfigProvider, { lexicalId: LEXICAL_ID, serviceManager: serviceManager, children: [_jsx(LexicalToolsPlugin, { onToolsReady: onToolsReady }), _jsx(LexicalComposer, { initialConfig: editorConfig, children: _jsxs("div", { className: "lexical-editor-inner", ref: onRef, children: [_jsx(LexicalStatePlugin, {}), _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "lexical-editor-content", "aria-label": "Lexical Editor" }), ErrorBoundary: LexicalErrorBoundary }), _jsx(OnChangePlugin, { onChange: handleChange }), _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(CheckListPlugin, {}), _jsx(LinkPlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS }), _jsx(LoadContentPlugin, {}), _jsx(CodeHighlightPlugin, {}), _jsx(ImagesPlugin, { captionsEnabled: false }), _jsx(HorizontalRulePlugin, {}), _jsx(EquationsPlugin, {}), _jsx(YouTubePlugin, {}), _jsx(ExcalidrawPlugin, {}), _jsx(CollapsiblePlugin, {}), _jsx(AutoEmbedPlugin, {}), _jsx(TablePlugin, {}), _jsx(TableCellResizerPlugin, {}), _jsx(JupyterCellPlugin, {}), _jsx(JupyterReactTheme, { children: _jsx(KernelPluginsInner, {}) }), floatingAnchorElem && (_jsxs(_Fragment, { children: [_jsx(DraggableBlockPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem, setIsLinkEditMode: setIsLinkEditMode, extraItems: toolbarItems }), _jsx(CodeActionMenuPlugin, { anchorElem: floatingAnchorElem })] })), _jsx(ChatInlinePlugin, { protocol: {
|
|
181
|
+
type: 'ag-ui',
|
|
182
|
+
endpoint: agUiEndpoint,
|
|
183
|
+
}, isOpen: isAiOpen, onClose: closeAi, pendingPrompt: pendingPrompt, onPendingPromptConsumed: clearPendingPrompt })] }) })] }) }) }));
|
|
184
|
+
});
|
|
185
|
+
const ChatPanel = ({ agentId, tools }) => {
|
|
186
|
+
return (_jsx(Box, { sx: {
|
|
187
|
+
width: '420px',
|
|
188
|
+
minWidth: '320px',
|
|
189
|
+
display: 'flex',
|
|
190
|
+
flexDirection: 'column',
|
|
191
|
+
overflow: 'hidden',
|
|
192
|
+
}, children: _jsx(Chat, { transport: "ag-ui", baseUrl: BASE_URL, agentId: agentId, title: "Agent Lexical", placeholder: "Ask about the document...", description: "Chat with the agent to manipulate the document", showHeader: true, height: "100vh", showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, frontendTools: tools, autoFocus: true, runtimeId: agentId, historyEndpoint: `${BASE_URL}/api/v1/history`, suggestions: [
|
|
193
|
+
{
|
|
194
|
+
title: 'Insert heading',
|
|
195
|
+
message: 'Insert a heading that says "Welcome"',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
title: 'Add code block',
|
|
199
|
+
message: 'Add a Python code block with a hello world example',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
title: 'Create list',
|
|
203
|
+
message: 'Create a bullet list with three items about Jupyter',
|
|
204
|
+
},
|
|
205
|
+
], submitOnSuggestionClick: true }) }));
|
|
206
|
+
};
|
|
207
|
+
// ─── Main component ─────────────────────────────────────────────────────────
|
|
208
|
+
export const AgentLexical = () => {
|
|
209
|
+
const [agentId] = useState(getAgentId);
|
|
210
|
+
const [isReady, setIsReady] = useState(false);
|
|
211
|
+
const [error, setError] = useState(null);
|
|
212
|
+
const [serviceManager, setServiceManager] = useState(null);
|
|
213
|
+
const [tools, setTools] = useState([]);
|
|
214
|
+
const handleToolsReady = useCallback((newTools) => {
|
|
215
|
+
setTools(newTools);
|
|
216
|
+
}, []);
|
|
217
|
+
// Verify the agent exists AND initialise the Jupyter service manager
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
let cancelled = false;
|
|
220
|
+
const init = async () => {
|
|
221
|
+
try {
|
|
222
|
+
// 1. Ensure agent exists — create if missing
|
|
223
|
+
const getResp = await fetch(`${BASE_URL}/api/v1/agents/${encodeURIComponent(agentId)}`);
|
|
224
|
+
if (!getResp.ok) {
|
|
225
|
+
const createResp = await fetch(`${BASE_URL}/api/v1/agents`, {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
headers: { 'Content-Type': 'application/json' },
|
|
228
|
+
body: JSON.stringify({
|
|
229
|
+
name: agentId,
|
|
230
|
+
description: 'Agent created by Agent Lexical page',
|
|
231
|
+
agent_library: 'pydantic-ai',
|
|
232
|
+
transport: 'ag-ui',
|
|
233
|
+
model: DEFAULT_MODEL,
|
|
234
|
+
system_prompt: 'You are a helpful AI assistant that helps users work with documents. You can help with writing, editing, and formatting content.',
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
if (!createResp.ok && createResp.status !== 400) {
|
|
238
|
+
const d = await createResp.json().catch(() => ({}));
|
|
239
|
+
throw new Error(d.detail || `Failed to create agent: ${createResp.status}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// 2. Initialise Jupyter
|
|
243
|
+
initJupyterConfig();
|
|
244
|
+
const serverSettings = createServerSettings(getJupyterServerUrl(), getJupyterServerToken());
|
|
245
|
+
const manager = new ServiceManager({ serverSettings });
|
|
246
|
+
await manager.ready;
|
|
247
|
+
if (!cancelled) {
|
|
248
|
+
setServiceManager(manager);
|
|
249
|
+
setIsReady(true);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
if (!cancelled) {
|
|
254
|
+
setError(err instanceof Error ? err.message : 'Failed to initialise');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
init();
|
|
259
|
+
return () => {
|
|
260
|
+
cancelled = true;
|
|
261
|
+
};
|
|
262
|
+
}, [agentId]);
|
|
263
|
+
// Loading
|
|
264
|
+
if (!isReady && !error) {
|
|
265
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
|
|
266
|
+
display: 'flex',
|
|
267
|
+
flexDirection: 'column',
|
|
268
|
+
alignItems: 'center',
|
|
269
|
+
justifyContent: 'center',
|
|
270
|
+
height: '100vh',
|
|
271
|
+
gap: 3,
|
|
272
|
+
bg: 'canvas.default',
|
|
273
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: ["Connecting to agent ", agentId, "\u2026"] })] }) }));
|
|
274
|
+
}
|
|
275
|
+
// Error
|
|
276
|
+
if (error) {
|
|
277
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
|
|
278
|
+
display: 'flex',
|
|
279
|
+
flexDirection: 'column',
|
|
280
|
+
alignItems: 'center',
|
|
281
|
+
justifyContent: 'center',
|
|
282
|
+
height: '100vh',
|
|
283
|
+
gap: 3,
|
|
284
|
+
bg: 'canvas.default',
|
|
285
|
+
}, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: "Failed to connect" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: error })] }) }));
|
|
286
|
+
}
|
|
287
|
+
// Ready — lexical editor + chat side-by-side
|
|
288
|
+
return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
|
|
289
|
+
display: 'flex',
|
|
290
|
+
height: '100vh',
|
|
291
|
+
width: '100vw',
|
|
292
|
+
overflow: 'hidden',
|
|
293
|
+
bg: 'canvas.default',
|
|
294
|
+
}, children: [serviceManager && (_jsx(LexicalPanel, { serviceManager: serviceManager, onToolsReady: handleToolsReady })), _jsx(ChatPanel, { agentId: agentId, tools: tools })] }) }));
|
|
295
|
+
};
|
|
296
|
+
export default AgentLexical;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentNotebook
|
|
3
|
+
*
|
|
4
|
+
* Standalone notebook + chat interface served at /static/agent-notebook.html.
|
|
5
|
+
* Connects to the agent-runtimes AG-UI endpoint and provides a Jupyter
|
|
6
|
+
* notebook alongside the Chat component with notebook tools registered.
|
|
7
|
+
*
|
|
8
|
+
* The page is opened by codeai with a URL like:
|
|
9
|
+
* http://127.0.0.1:<port>/static/agent-notebook.html?agentId=<id>
|
|
10
|
+
*
|
|
11
|
+
* Query parameters:
|
|
12
|
+
* - agentId: the agent identifier (required, set by codeai)
|
|
13
|
+
* - jupyterBaseUrl: base URL for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
14
|
+
* - jupyterToken: token for the Jupyter server (optional, falls back to jupyter-config-data)
|
|
15
|
+
*/
|
|
16
|
+
import React from 'react';
|
|
17
|
+
import '../style/primer-primitives.css';
|
|
18
|
+
export declare const AgentNotebook: React.FC;
|
|
19
|
+
export default AgentNotebook;
|