@datalayer/agent-runtimes 1.0.19 → 1.0.21
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 +11 -3
- package/lib/AgentNode.js +141 -40
- package/lib/App.js +2 -2
- package/lib/agent-node/AgentNodeGallery.js +188 -25
- package/lib/api/runtimes/runtimes.d.ts +57 -0
- package/lib/api/runtimes/runtimes.js +55 -1
- package/lib/chat/Chat.d.ts +1 -1
- package/lib/chat/Chat.js +2 -2
- package/lib/chat/base/ChatBase.js +50 -13
- package/lib/chat/document/EphemeralDocument.d.ts +5 -1
- package/lib/chat/document/EphemeralDocument.js +7 -5
- package/lib/chat/header/ChatHeaderBase.d.ts +3 -1
- package/lib/chat/header/ChatHeaderBase.js +5 -3
- package/lib/chat/messages/ChatMessageList.d.ts +19 -0
- package/lib/chat/messages/ChatMessageList.js +180 -9
- package/lib/chat/notebook/EphemeralNotebook.d.ts +5 -1
- package/lib/chat/notebook/EphemeralNotebook.js +9 -6
- package/lib/chat/prompt/InputPrompt.js +1 -1
- package/lib/chat/tools/SubagentActivity.d.ts +20 -0
- package/lib/chat/tools/SubagentActivity.js +154 -0
- package/lib/chat/tools/index.d.ts +1 -0
- package/lib/chat/tools/index.js +1 -0
- package/lib/chat/usage/TokenUsageBar.js +3 -3
- package/lib/client/AgentRuntimesClient.d.ts +5 -0
- package/lib/client/AgentsMixin.js +3 -1
- package/lib/client/mixins/RuntimesMixin.d.ts +12 -0
- package/lib/client/mixins/RuntimesMixin.js +24 -1
- package/lib/components/AgentSummary.d.ts +1 -0
- package/lib/components/AgentSummary.js +66 -10
- package/lib/components/runtimes/RuntimePickerBase.js +64 -29
- package/lib/components/runtimes/RuntimePickerCell.js +1 -1
- package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
- package/lib/components/runtimes/RuntimeSimplePicker.js +3 -2
- package/lib/components/runtimes/RuntimeUtils.js +2 -2
- package/lib/context/GraphFlowChart.js +1 -1
- package/lib/context/TokenUsageChart.js +1 -1
- package/lib/context/TurnGraphChart.js +2 -2
- package/lib/examples/A2UiAgentExample.js +4 -4
- package/lib/examples/A2UiComponentsGalleryExample.js +3 -3
- package/lib/examples/A2UiContactCardExample.js +3 -3
- package/lib/examples/A2UiRestaurantExample.js +2 -2
- package/lib/examples/A2UiViewerExample.js +3 -3
- package/lib/examples/AgUiAgenticExample.js +3 -3
- package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
- package/lib/examples/AgUiHaikuGenUiExample.js +3 -3
- package/lib/examples/AgUiHumanInTheLoopExample.js +5 -5
- package/lib/examples/AgUiSharedStateExample.js +3 -3
- package/lib/examples/AgUiToolsBasedGenUiExample.js +7 -5
- package/lib/examples/AgentCheckpointsExample.js +6 -5
- package/lib/examples/{AgentSandboxExample.d.ts → AgentCodeSandboxExample.d.ts} +4 -4
- package/lib/examples/{AgentSandboxExample.js → AgentCodeSandboxExample.js} +10 -9
- package/lib/examples/AgentCodeSandboxesExample.js +2 -2
- package/lib/examples/AgentCodemodeExample.js +3 -3
- package/lib/examples/AgentCompactionExample.d.ts +12 -0
- package/lib/examples/AgentCompactionExample.js +244 -0
- package/lib/examples/AgentEvalsExample.js +10 -20
- package/lib/examples/AgentGuardrailsExample.js +2 -2
- package/lib/examples/AgentHooksExample.js +1 -1
- package/lib/examples/AgentInferenceProviderExample.js +6 -8
- package/lib/examples/AgentLoopExample.js +3 -3
- package/lib/examples/AgentMCPExample.js +3 -3
- package/lib/examples/AgentMemoryExample.d.ts +4 -2
- package/lib/examples/AgentMemoryExample.js +93 -10
- package/lib/examples/AgentMonitoringExample.js +2 -2
- package/lib/examples/AgentNotificationsExample.js +1 -1
- package/lib/examples/AgentOtelExample.d.ts +2 -3
- package/lib/examples/AgentOtelExample.js +7 -12
- package/lib/examples/AgentOutputsExample.js +5 -5
- package/lib/examples/AgentParametersExample.js +3 -3
- package/lib/examples/AgentSkillsExample.js +4 -4
- package/lib/examples/AgentSubagentsExample.d.ts +2 -2
- package/lib/examples/AgentSubagentsExample.js +43 -34
- package/lib/examples/AgentToolApprovalsExample.js +1 -1
- package/lib/examples/AgentTriggersExample.js +9 -11
- package/lib/examples/AgentspecsExample.js +13 -5
- package/lib/examples/CellExample.d.ts +6 -0
- package/lib/examples/CellExample.js +84 -0
- package/lib/examples/ChatCustomExample.js +1 -1
- package/lib/examples/ChatExample.js +1 -1
- package/lib/examples/ChatStandaloneExample.js +2 -2
- package/lib/examples/HomeExample.js +29 -28
- package/lib/examples/Lexical2Example.js +2 -2
- package/lib/examples/LexicalAgentExample.js +1 -1
- package/lib/examples/LexicalAgentSidebarExample.js +2 -2
- package/lib/examples/NotebookAgentSidebarExample.d.ts +1 -1
- package/lib/examples/NotebookAgentSidebarExample.js +5 -4
- package/lib/examples/NotebookCollaborationExample.js +3 -3
- package/lib/examples/NotebookExample.js +2 -2
- package/lib/examples/components/ExampleWrapper.js +5 -0
- package/lib/examples/components/Header.js +2 -2
- package/lib/examples/components/HeaderControls.js +1 -1
- package/lib/examples/components/LexicalEditor.js +1 -1
- package/lib/examples/components/MainContent.js +1 -1
- package/lib/examples/components/MockFileBrowser.js +8 -8
- package/lib/examples/components/TimeTravel.js +1 -1
- package/lib/examples/components/haiku/HaikuDisplay.js +2 -2
- package/lib/examples/example-selector.js +4 -3
- package/lib/examples/hooks/useExampleAgentRuntime.js +11 -1
- package/lib/examples/hooks/useExampleAgentRuntimes.d.ts +7 -0
- package/lib/examples/hooks/useExampleAgentRuntimes.js +82 -0
- package/lib/examples/index.d.ts +2 -1
- package/lib/examples/index.js +2 -1
- package/lib/examples/main.js +359 -46
- package/lib/examples/utils/agentSummaryStore.d.ts +17 -0
- package/lib/examples/utils/themedProvider.js +32 -2
- package/lib/examples/utils/useExampleAgentRuntimesUrl.js +2 -1
- package/lib/examples2/NotebookMutationsKernel.js +6 -3
- package/lib/examples2/NotebookMutationsServiceManager.js +6 -3
- package/lib/examples2/ReactRouterExample.js +5 -5
- package/lib/examples2/main.js +38 -0
- package/lib/hooks/useAIAgentsWebSocket.js +35 -0
- package/lib/hooks/useAgentRuntimes.d.ts +22 -0
- package/lib/hooks/useAgentRuntimes.js +192 -5
- package/lib/hooks/useCheckpoints.js +2 -2
- package/lib/hooks/useToolApprovals.d.ts +10 -4
- package/lib/hooks/useToolApprovals.js +11 -5
- package/lib/models/Runtime.d.ts +10 -8
- package/lib/models/RuntimeDTO.d.ts +5 -3
- package/lib/models/RuntimeDTO.js +3 -3
- package/lib/runtimes/actions.js +3 -1
- package/lib/runtimes/apis.d.ts +7 -0
- package/lib/specs/agents/agents.d.ts +51 -0
- package/lib/specs/agents/agents.js +3389 -94
- package/lib/specs/models.d.ts +2 -0
- package/lib/specs/models.js +37 -0
- package/lib/stores/agentRuntimeStore.d.ts +32 -1
- package/lib/stores/agentRuntimeStore.js +65 -1
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/types/agents.d.ts +9 -3
- package/lib/types/agentspecs.d.ts +2 -0
- package/lib/types/chat.d.ts +12 -0
- package/lib/types/models.d.ts +5 -0
- package/lib/types/stream.d.ts +58 -1
- package/package.json +4 -4
- package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
- package/scripts/codegen/generate_agents.py +7 -0
- package/scripts/codegen/generate_models.py +22 -9
- package/scripts/gen_workers.py +340 -0
- package/lib/examples/CellSimpleExample.d.ts +0 -6
- package/lib/examples/CellSimpleExample.js +0 -20
|
@@ -5,8 +5,76 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
*/
|
|
6
6
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
import { Box, Button, Heading, Label, Spinner, Text, TextInput, } from '@primer/react';
|
|
8
|
-
import { CheckCircleFillIcon, RocketIcon } from '@primer/octicons-react';
|
|
9
|
-
const GRID_TEMPLATE = ['1fr', '1fr 1fr', '
|
|
8
|
+
import { AgentIcon, BeakerIcon, BookIcon, BugIcon, CheckCircleFillIcon, CloudIcon, CodeIcon, CopilotIcon, CpuIcon, DatabaseIcon, DependabotIcon, EyeIcon, FileIcon, GearIcon, GitBranchIcon, GlobeIcon, GraphIcon, HeartIcon, HomeIcon, IssueOpenedIcon, LightBulbIcon, LinkIcon, MailIcon, MegaphoneIcon, NoteIcon, PackageIcon, PencilIcon, PeopleIcon, PlayIcon, PlugIcon, PulseIcon, RocketIcon, SearchIcon, ShareIcon, ShieldCheckIcon, ShieldIcon, SparklesFillIcon, SquirrelIcon, StarIcon, SyncIcon, TableIcon, TagIcon, TelescopeIcon, TerminalIcon, ToolsIcon, ZapIcon, } from '@primer/octicons-react';
|
|
9
|
+
const GRID_TEMPLATE = ['1fr', '1fr 1fr', 'repeat(5, minmax(0, 1fr))'];
|
|
10
|
+
const ICON_REGISTRY = {
|
|
11
|
+
// Primary agentspec icon values.
|
|
12
|
+
agent: AgentIcon,
|
|
13
|
+
database: DatabaseIcon,
|
|
14
|
+
globe: GlobeIcon,
|
|
15
|
+
'git-branch': GitBranchIcon,
|
|
16
|
+
'trending-up': GraphIcon,
|
|
17
|
+
'share-2': ShareIcon,
|
|
18
|
+
// Additional mappings used across the agentspec catalog.
|
|
19
|
+
rocket: RocketIcon,
|
|
20
|
+
sparkles: SparklesFillIcon,
|
|
21
|
+
search: SearchIcon,
|
|
22
|
+
code: CodeIcon,
|
|
23
|
+
cpu: CpuIcon,
|
|
24
|
+
beaker: BeakerIcon,
|
|
25
|
+
book: BookIcon,
|
|
26
|
+
bug: BugIcon,
|
|
27
|
+
cloud: CloudIcon,
|
|
28
|
+
copilot: CopilotIcon,
|
|
29
|
+
dependabot: DependabotIcon,
|
|
30
|
+
eye: EyeIcon,
|
|
31
|
+
file: FileIcon,
|
|
32
|
+
gear: GearIcon,
|
|
33
|
+
graph: GraphIcon,
|
|
34
|
+
heart: HeartIcon,
|
|
35
|
+
home: HomeIcon,
|
|
36
|
+
lightbulb: LightBulbIcon,
|
|
37
|
+
link: LinkIcon,
|
|
38
|
+
mail: MailIcon,
|
|
39
|
+
megaphone: MegaphoneIcon,
|
|
40
|
+
note: NoteIcon,
|
|
41
|
+
package: PackageIcon,
|
|
42
|
+
pencil: PencilIcon,
|
|
43
|
+
people: PeopleIcon,
|
|
44
|
+
play: PlayIcon,
|
|
45
|
+
plug: PlugIcon,
|
|
46
|
+
pulse: PulseIcon,
|
|
47
|
+
'issue-opened': IssueOpenedIcon,
|
|
48
|
+
shield: ShieldIcon,
|
|
49
|
+
'shield-check': ShieldCheckIcon,
|
|
50
|
+
squirrel: SquirrelIcon,
|
|
51
|
+
star: StarIcon,
|
|
52
|
+
sync: SyncIcon,
|
|
53
|
+
table: TableIcon,
|
|
54
|
+
tag: TagIcon,
|
|
55
|
+
telescope: TelescopeIcon,
|
|
56
|
+
terminal: TerminalIcon,
|
|
57
|
+
tools: ToolsIcon,
|
|
58
|
+
zap: ZapIcon,
|
|
59
|
+
};
|
|
60
|
+
const DEFAULT_ICON = SparklesFillIcon;
|
|
61
|
+
function hashString(value) {
|
|
62
|
+
let hash = 0;
|
|
63
|
+
for (let i = 0; i < value.length; i++) {
|
|
64
|
+
hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
|
|
65
|
+
}
|
|
66
|
+
return Math.abs(hash);
|
|
67
|
+
}
|
|
68
|
+
function resolveAgentspecIcon(iconId, seed) {
|
|
69
|
+
if (iconId) {
|
|
70
|
+
return ICON_REGISTRY[iconId] || DEFAULT_ICON;
|
|
71
|
+
}
|
|
72
|
+
const iconValues = Object.values(ICON_REGISTRY);
|
|
73
|
+
if (iconValues.length === 0) {
|
|
74
|
+
return DEFAULT_ICON;
|
|
75
|
+
}
|
|
76
|
+
return iconValues[hashString(seed) % iconValues.length];
|
|
77
|
+
}
|
|
10
78
|
/**
|
|
11
79
|
* URL (optionally with `?token=`) of the LOCAL Jupyter server that the node's
|
|
12
80
|
* agents should use as their `jupyter` code sandbox. This mirrors
|
|
@@ -136,6 +204,23 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
136
204
|
}, [running, normalizedActiveAgentId]);
|
|
137
205
|
// An "active" agent must be both configured and currently running.
|
|
138
206
|
const hasActiveAgent = Boolean(normalizedActiveAgentId && activeAgent);
|
|
207
|
+
const activeAgentSpec = useMemo(() => {
|
|
208
|
+
if (!activeAgent) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const directSpecId = String(activeAgent.agent_spec_id || '').trim();
|
|
212
|
+
if (directSpecId) {
|
|
213
|
+
const directMatch = specs.find(spec => spec.id === directSpecId);
|
|
214
|
+
if (directMatch) {
|
|
215
|
+
return directMatch;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const nameCandidate = String(activeAgent.name || '').trim();
|
|
219
|
+
if (!nameCandidate) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return specs.find(spec => spec.id === nameCandidate) || null;
|
|
223
|
+
}, [activeAgent, specs]);
|
|
139
224
|
const normalizedSearch = search.trim().toLowerCase();
|
|
140
225
|
const filteredSpecs = useMemo(() => {
|
|
141
226
|
if (!normalizedSearch) {
|
|
@@ -251,7 +336,9 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
251
336
|
if (!recreateResponse.ok) {
|
|
252
337
|
throw new Error(`Failed to launch agent (${recreateResponse.status})`);
|
|
253
338
|
}
|
|
254
|
-
const recreatePayload = await recreateResponse
|
|
339
|
+
const recreatePayload = await recreateResponse
|
|
340
|
+
.json()
|
|
341
|
+
.catch(() => null);
|
|
255
342
|
agentId =
|
|
256
343
|
recreatePayload?.agent_id ||
|
|
257
344
|
recreatePayload?.id ||
|
|
@@ -298,7 +385,9 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
298
385
|
if (!recreateResponse.ok) {
|
|
299
386
|
throw new Error(`Failed to recreate agent with spec (${recreateResponse.status})`);
|
|
300
387
|
}
|
|
301
|
-
const recreatePayload = await recreateResponse
|
|
388
|
+
const recreatePayload = await recreateResponse
|
|
389
|
+
.json()
|
|
390
|
+
.catch(() => null);
|
|
302
391
|
agentId =
|
|
303
392
|
recreatePayload?.agent_id ||
|
|
304
393
|
recreatePayload?.id ||
|
|
@@ -364,11 +453,19 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
364
453
|
finally {
|
|
365
454
|
setTerminating(false);
|
|
366
455
|
}
|
|
367
|
-
}, [
|
|
456
|
+
}, [
|
|
457
|
+
authHeaders,
|
|
458
|
+
baseUrl,
|
|
459
|
+
normalizedActiveAgentId,
|
|
460
|
+
onTerminated,
|
|
461
|
+
onLaunchError,
|
|
462
|
+
]);
|
|
368
463
|
if (loading) {
|
|
369
464
|
return (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', py: 6 }, children: _jsx(Spinner, { size: "large" }) }));
|
|
370
465
|
}
|
|
371
|
-
return (_jsxs(Box, { children: [_jsxs(Box, { sx: { mb: 3 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children:
|
|
466
|
+
return (_jsxs(Box, { children: [_jsxs(Box, { sx: { mb: 3 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: hasActiveAgent ? 'Running agent' : 'Choose an agent' }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: hasActiveAgent
|
|
467
|
+
? 'Your node is currently running an active agent. You can terminate it to go back to the gallery.'
|
|
468
|
+
: 'Pick an agent from the gallery to launch it on this node. The active agent handles prompts sent directly to the node and through the Datalayer platform.' })] }), error && (_jsx(Box, { sx: {
|
|
372
469
|
mb: 3,
|
|
373
470
|
p: 2,
|
|
374
471
|
borderRadius: 2,
|
|
@@ -378,13 +475,31 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
378
475
|
}, children: error })), hasActiveAgent ? (_jsxs(Box, { sx: {
|
|
379
476
|
p: 4,
|
|
380
477
|
border: '1px solid',
|
|
381
|
-
borderColor: '
|
|
478
|
+
borderColor: 'accent.muted',
|
|
382
479
|
borderRadius: 2,
|
|
383
|
-
bg: '
|
|
480
|
+
bg: 'accent.subtle',
|
|
384
481
|
display: 'flex',
|
|
385
482
|
flexDirection: 'column',
|
|
386
483
|
gap: 3,
|
|
387
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsxs(Label, { variant: "
|
|
484
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsxs(Label, { variant: "secondary", sx: {
|
|
485
|
+
display: 'inline-flex',
|
|
486
|
+
alignItems: 'center',
|
|
487
|
+
gap: 1,
|
|
488
|
+
color: 'accent.fg',
|
|
489
|
+
}, children: [_jsx(CheckCircleFillIcon, { size: 12 }), "Active agent"] }), _jsx(Text, { sx: { fontWeight: 600 }, children: activeAgent?.name ||
|
|
490
|
+
activeAgent?.agent_spec_id ||
|
|
491
|
+
normalizedActiveAgentId })] }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Chat is enabled while an active agent is running on this node. Terminate it to return to the agent cards picker." }), activeAgentSpec && (_jsxs(Box, { sx: {
|
|
492
|
+
p: 3,
|
|
493
|
+
border: '1px solid',
|
|
494
|
+
borderColor: 'border.default',
|
|
495
|
+
borderRadius: 2,
|
|
496
|
+
bg: 'canvas.default',
|
|
497
|
+
display: 'flex',
|
|
498
|
+
flexDirection: 'column',
|
|
499
|
+
gap: 2,
|
|
500
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Label, { size: "small", variant: "accent", children: "Spec" }), _jsx(Text, { sx: { fontWeight: 600 }, children: activeAgentSpec.name || activeAgentSpec.id }), activeAgentSpec.version && (_jsxs(Label, { size: "small", variant: "secondary", children: ["v", activeAgentSpec.version] }))] }), activeAgentSpec.description && (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: activeAgentSpec.description })), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [_jsxs(Label, { size: "small", variant: "secondary", children: ["id: ", activeAgentSpec.id] }), activeAgentSpec.model && (_jsxs(Label, { size: "small", variant: "secondary", children: ["model: ", activeAgentSpec.model] })), activeAgentSpec.inference_provider && (_jsxs(Label, { size: "small", variant: "secondary", children: ["provider: ", activeAgentSpec.inference_provider] })), Array.isArray(activeAgentSpec.tags)
|
|
501
|
+
? activeAgentSpec.tags.map(tag => (_jsx(Label, { size: "small", variant: "secondary", children: tag }, tag)))
|
|
502
|
+
: null] })] })), _jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-start' }, children: _jsx(Button, { variant: "danger", disabled: terminating, onClick: () => void terminateActiveAgent(), children: terminating ? 'Terminating…' : 'Terminate' }) })] })) : specs.length === 0 ? (_jsx(Box, { sx: {
|
|
388
503
|
p: 4,
|
|
389
504
|
textAlign: 'center',
|
|
390
505
|
border: '1px solid',
|
|
@@ -396,22 +511,57 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
396
511
|
gridTemplateColumns: GRID_TEMPLATE,
|
|
397
512
|
gap: 3,
|
|
398
513
|
}, children: filteredSpecs.map(spec => {
|
|
399
|
-
const
|
|
400
|
-
|
|
514
|
+
const IconComponent = resolveAgentspecIcon(spec.icon, spec.name || spec.id);
|
|
515
|
+
const isActive = !!activeAgentId && runningBySpec.get(spec.id) === activeAgentId;
|
|
401
516
|
const isLaunching = launchingId === spec.id;
|
|
402
517
|
const isRunning = runningBySpec.has(spec.id);
|
|
403
|
-
|
|
518
|
+
const launchLabel = isActive
|
|
519
|
+
? 'Open chat'
|
|
520
|
+
: isLaunching
|
|
521
|
+
? 'Launching…'
|
|
522
|
+
: isRunning
|
|
523
|
+
? 'Set active'
|
|
524
|
+
: 'Launch';
|
|
525
|
+
return (_jsxs(Box, { role: "button", tabIndex: isLaunching ? -1 : 0, onClick: () => {
|
|
526
|
+
if (!isLaunching) {
|
|
527
|
+
void launch(spec);
|
|
528
|
+
}
|
|
529
|
+
}, onKeyDown: event => {
|
|
530
|
+
if ((event.key === 'Enter' || event.key === ' ') &&
|
|
531
|
+
!isLaunching) {
|
|
532
|
+
event.preventDefault();
|
|
533
|
+
void launch(spec);
|
|
534
|
+
}
|
|
535
|
+
}, "aria-label": `${launchLabel} ${spec.name || spec.id}`, "aria-busy": isLaunching, "aria-disabled": isLaunching, sx: {
|
|
404
536
|
display: 'flex',
|
|
405
537
|
flexDirection: 'column',
|
|
538
|
+
textAlign: 'left',
|
|
539
|
+
cursor: isLaunching ? 'progress' : 'pointer',
|
|
406
540
|
p: 3,
|
|
407
541
|
border: '1px solid',
|
|
408
|
-
borderColor: isActive
|
|
542
|
+
borderColor: isActive
|
|
543
|
+
? 'success.emphasis'
|
|
544
|
+
: 'border.default',
|
|
409
545
|
borderRadius: 2,
|
|
410
546
|
bg: 'canvas.default',
|
|
411
|
-
|
|
412
|
-
|
|
547
|
+
// Hover feedback is border + shadow only. No transform: a
|
|
548
|
+
// transform here promotes the card to its own layer and makes
|
|
549
|
+
// the line-clamped description re-rasterize (per-paragraph
|
|
550
|
+
// motion artifact).
|
|
551
|
+
transition: 'box-shadow 180ms ease, border-color 180ms ease',
|
|
552
|
+
'&:hover': {
|
|
413
553
|
boxShadow: 'shadow.medium',
|
|
414
|
-
|
|
554
|
+
borderColor: isActive
|
|
555
|
+
? 'success.emphasis'
|
|
556
|
+
: 'accent.emphasis',
|
|
557
|
+
},
|
|
558
|
+
'&:focus-visible': {
|
|
559
|
+
outline: '2px solid',
|
|
560
|
+
outlineColor: 'accent.fg',
|
|
561
|
+
outlineOffset: '2px',
|
|
562
|
+
},
|
|
563
|
+
'&[aria-disabled="true"]': {
|
|
564
|
+
opacity: 0.8,
|
|
415
565
|
},
|
|
416
566
|
}, children: [_jsxs(Box, { sx: {
|
|
417
567
|
display: 'flex',
|
|
@@ -427,13 +577,17 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
427
577
|
borderRadius: 2,
|
|
428
578
|
fontSize: 3,
|
|
429
579
|
bg: 'canvas.subtle',
|
|
430
|
-
}, children: spec.emoji
|
|
580
|
+
}, children: spec.emoji ? (_jsx(Text, { sx: { fontSize: 3, lineHeight: 1 }, children: spec.emoji })) : (_jsx(IconComponent, { size: 20 })) }), _jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsx(Heading, { as: "h3", sx: {
|
|
431
581
|
fontSize: 2,
|
|
432
582
|
mb: 0,
|
|
433
583
|
overflow: 'hidden',
|
|
434
584
|
textOverflow: 'ellipsis',
|
|
435
585
|
whiteSpace: 'nowrap',
|
|
436
|
-
}, children: spec.name || spec.id }), spec.version && (_jsxs(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: ["v", spec.version] }))] }), isActive && (_jsxs(Label, { variant: "success", sx: {
|
|
586
|
+
}, children: spec.name || spec.id }), spec.version && (_jsxs(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: ["v", spec.version] }))] }), isActive && (_jsxs(Label, { variant: "success", sx: {
|
|
587
|
+
display: 'inline-flex',
|
|
588
|
+
alignItems: 'center',
|
|
589
|
+
gap: 1,
|
|
590
|
+
}, children: [_jsx(CheckCircleFillIcon, { size: 12 }), "Active"] }))] }), spec.description && (_jsx(Text, { sx: {
|
|
437
591
|
color: 'fg.muted',
|
|
438
592
|
fontSize: 1,
|
|
439
593
|
mb: 2,
|
|
@@ -446,13 +600,22 @@ export function AgentNodeGallery({ baseUrl, token, activeAgentId, onLaunched, on
|
|
|
446
600
|
flexWrap: 'wrap',
|
|
447
601
|
gap: 1,
|
|
448
602
|
mb: 3,
|
|
449
|
-
}, children: spec.tags.slice(0, 4).map(tag => (_jsx(Label, { size: "small", variant: "secondary", children: tag }, tag))) })), _jsx(Box, { sx: { mt: 'auto', pt: 1 }, children:
|
|
450
|
-
|
|
451
|
-
:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
603
|
+
}, children: spec.tags.slice(0, 4).map(tag => (_jsx(Label, { size: "small", variant: "secondary", children: tag }, tag))) })), _jsx(Box, { sx: { mt: 'auto', pt: 1 }, children: _jsxs(Box, { as: "span", sx: {
|
|
604
|
+
display: 'inline-flex',
|
|
605
|
+
alignItems: 'center',
|
|
606
|
+
gap: 1,
|
|
607
|
+
px: 2,
|
|
608
|
+
py: 1,
|
|
609
|
+
borderRadius: 2,
|
|
610
|
+
border: '1px solid',
|
|
611
|
+
borderColor: isActive
|
|
612
|
+
? 'border.default'
|
|
613
|
+
: 'accent.muted',
|
|
614
|
+
bg: isActive ? 'canvas.subtle' : 'accent.subtle',
|
|
615
|
+
color: isActive ? 'fg.default' : 'accent.fg',
|
|
616
|
+
fontSize: 1,
|
|
617
|
+
fontWeight: 600,
|
|
618
|
+
}, children: [_jsx(IconComponent, { size: 14 }), launchLabel] }) })] }, spec.id));
|
|
456
619
|
}) }), filteredSpecs.length === 0 && (_jsx(Box, { sx: {
|
|
457
620
|
mt: 3,
|
|
458
621
|
p: 3,
|
|
@@ -120,6 +120,63 @@ export interface ResumeRuntimeBody {
|
|
|
120
120
|
/** Additional metadata */
|
|
121
121
|
metadata?: Record<string, any>;
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Persisted memory record returned by ``/api/runtimes/v1/memories``.
|
|
125
|
+
*/
|
|
126
|
+
export interface RuntimeMemory {
|
|
127
|
+
id: string;
|
|
128
|
+
memory?: string | null;
|
|
129
|
+
hash?: string | null;
|
|
130
|
+
user_id?: string | null;
|
|
131
|
+
agent_id?: string | null;
|
|
132
|
+
run_id?: string | null;
|
|
133
|
+
actor_id?: string | null;
|
|
134
|
+
role?: string | null;
|
|
135
|
+
scope?: string | null;
|
|
136
|
+
created_at?: string | null;
|
|
137
|
+
updated_at?: string | null;
|
|
138
|
+
metadata?: Record<string, any>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Response payload for listing persisted runtime memories.
|
|
142
|
+
*/
|
|
143
|
+
export interface ListRuntimeMemoriesResponse {
|
|
144
|
+
success: boolean;
|
|
145
|
+
message?: string;
|
|
146
|
+
count: number;
|
|
147
|
+
limit: number;
|
|
148
|
+
offset: number;
|
|
149
|
+
user_id?: string;
|
|
150
|
+
memories: RuntimeMemory[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Response payload for fetching one persisted memory.
|
|
154
|
+
*/
|
|
155
|
+
export interface GetRuntimeMemoryResponse {
|
|
156
|
+
success: boolean;
|
|
157
|
+
message?: string;
|
|
158
|
+
memory: RuntimeMemory;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Query options for listing persisted runtime memories.
|
|
162
|
+
*/
|
|
163
|
+
export interface ListRuntimeMemoriesOptions {
|
|
164
|
+
userId?: string;
|
|
165
|
+
agentId?: string;
|
|
166
|
+
limit?: number;
|
|
167
|
+
offset?: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* List persisted memories from the runtimes API.
|
|
171
|
+
*
|
|
172
|
+
* Non-admin callers are automatically scoped to their own personal account by
|
|
173
|
+
* the backend, even when ``userId`` is omitted.
|
|
174
|
+
*/
|
|
175
|
+
export declare const listRuntimeMemories: (token: string, options?: ListRuntimeMemoriesOptions, baseUrl?: string) => Promise<ListRuntimeMemoriesResponse>;
|
|
176
|
+
/**
|
|
177
|
+
* Fetch one persisted memory by id from the runtimes API.
|
|
178
|
+
*/
|
|
179
|
+
export declare const getRuntimeMemory: (token: string, memoryId: string, baseUrl?: string) => Promise<GetRuntimeMemoryResponse>;
|
|
123
180
|
/**
|
|
124
181
|
* Resume a paused runtime by restoring from a checkpoint (async).
|
|
125
182
|
*
|
|
@@ -39,7 +39,7 @@ export const createRuntime = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.
|
|
|
39
39
|
const responseData = error.response.data || {};
|
|
40
40
|
if (status === 404) {
|
|
41
41
|
// Environment not found
|
|
42
|
-
throw new Error(`Environment '${data.
|
|
42
|
+
throw new Error(`Environment '${data.environment?.name || ''}' not found. ${responseData.message || 'Please check the environment name and try again.'}`);
|
|
43
43
|
}
|
|
44
44
|
else if (status === 503) {
|
|
45
45
|
// No runtime available
|
|
@@ -203,6 +203,60 @@ export const pauseRuntime = async (token, podName, baseUrl = DEFAULT_SERVICE_URL
|
|
|
203
203
|
...(body ? { body } : {}),
|
|
204
204
|
});
|
|
205
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* List persisted memories from the runtimes API.
|
|
208
|
+
*
|
|
209
|
+
* Non-admin callers are automatically scoped to their own personal account by
|
|
210
|
+
* the backend, even when ``userId`` is omitted.
|
|
211
|
+
*/
|
|
212
|
+
export const listRuntimeMemories = async (token, options = {}, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
|
|
213
|
+
validateToken(token);
|
|
214
|
+
const query = new URLSearchParams();
|
|
215
|
+
if (options.userId?.trim()) {
|
|
216
|
+
query.set('user_id', options.userId.trim());
|
|
217
|
+
}
|
|
218
|
+
if (options.agentId?.trim()) {
|
|
219
|
+
query.set('agent_id', options.agentId.trim());
|
|
220
|
+
}
|
|
221
|
+
if (typeof options.limit === 'number' && Number.isFinite(options.limit)) {
|
|
222
|
+
query.set('limit', String(Math.max(1, Math.min(1000, Math.floor(options.limit)))));
|
|
223
|
+
}
|
|
224
|
+
if (typeof options.offset === 'number' && Number.isFinite(options.offset)) {
|
|
225
|
+
query.set('offset', String(Math.max(0, Math.floor(options.offset))));
|
|
226
|
+
}
|
|
227
|
+
const qs = query.toString();
|
|
228
|
+
const response = await requestDatalayerAPI({
|
|
229
|
+
url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/memories${qs ? `?${qs}` : ''}`,
|
|
230
|
+
method: 'GET',
|
|
231
|
+
token,
|
|
232
|
+
});
|
|
233
|
+
return {
|
|
234
|
+
success: Boolean(response?.success),
|
|
235
|
+
message: response?.message,
|
|
236
|
+
count: Number(response?.count ?? 0),
|
|
237
|
+
limit: Number(response?.limit ?? options.limit ?? 100),
|
|
238
|
+
offset: Number(response?.offset ?? options.offset ?? 0),
|
|
239
|
+
user_id: response?.user_id,
|
|
240
|
+
memories: Array.isArray(response?.memories) ? response.memories : [],
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* Fetch one persisted memory by id from the runtimes API.
|
|
245
|
+
*/
|
|
246
|
+
export const getRuntimeMemory = async (token, memoryId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
|
|
247
|
+
validateToken(token);
|
|
248
|
+
validateRequiredString(memoryId, 'Memory id');
|
|
249
|
+
const response = await requestDatalayerAPI({
|
|
250
|
+
url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/memories/${encodeURIComponent(memoryId)}`,
|
|
251
|
+
method: 'GET',
|
|
252
|
+
token,
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
success: Boolean(response?.success),
|
|
256
|
+
message: response?.message,
|
|
257
|
+
memory: response?.memory,
|
|
258
|
+
};
|
|
259
|
+
};
|
|
206
260
|
/**
|
|
207
261
|
* Resume a paused runtime by restoring from a checkpoint (async).
|
|
208
262
|
*
|
package/lib/chat/Chat.d.ts
CHANGED
|
@@ -107,5 +107,5 @@ export interface ChatProps extends ChatCommonProps {
|
|
|
107
107
|
* />
|
|
108
108
|
* ```
|
|
109
109
|
*/
|
|
110
|
-
export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
110
|
+
export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
111
111
|
export default Chat;
|
package/lib/chat/Chat.js
CHANGED
|
@@ -136,7 +136,7 @@ function getProtocolType(protocol) {
|
|
|
136
136
|
* />
|
|
137
137
|
* ```
|
|
138
138
|
*/
|
|
139
|
-
export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
|
|
139
|
+
export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
|
|
140
140
|
const resolvedAgentId = typeof agentId === 'string' && agentId.trim().length > 0
|
|
141
141
|
? agentId.trim()
|
|
142
142
|
: 'default';
|
|
@@ -364,6 +364,6 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
|
|
|
364
364
|
? 'attention.fg'
|
|
365
365
|
: 'danger.fg',
|
|
366
366
|
flex: 1,
|
|
367
|
-
}, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
|
|
367
|
+
}, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelIndicatorPlacement: kernelIndicatorPlacement, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, themeVariant: themeVariant, colorMode: colorMode, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
|
|
368
368
|
}
|
|
369
369
|
export default Chat;
|
|
@@ -112,12 +112,14 @@ const ThemedJupyterReactTheme = JupyterReactTheme;
|
|
|
112
112
|
* chat height/flex chain is preserved); CSS custom properties and inherited
|
|
113
113
|
* properties (color, font) still cascade through it.
|
|
114
114
|
*/
|
|
115
|
-
function ThemedChatBoundary({ children }) {
|
|
116
|
-
const
|
|
117
|
-
const
|
|
115
|
+
function ThemedChatBoundary({ children, themeVariant, colorMode, }) {
|
|
116
|
+
const storeColorMode = useThemeStore(s => s.colorMode);
|
|
117
|
+
const storeThemeVariant = useThemeStore(s => s.theme);
|
|
118
|
+
const resolvedColorMode = colorMode ?? storeColorMode;
|
|
119
|
+
const resolvedThemeVariant = themeVariant ?? storeThemeVariant;
|
|
118
120
|
const systemMode = useSystemColorMode();
|
|
119
|
-
const themeConfig = getThemeConfig(
|
|
120
|
-
const resolvedMode =
|
|
121
|
+
const themeConfig = getThemeConfig(resolvedThemeVariant);
|
|
122
|
+
const resolvedMode = resolvedColorMode === 'auto' ? systemMode : resolvedColorMode;
|
|
121
123
|
const modeStyles = resolvedMode === 'dark'
|
|
122
124
|
? themeConfig.themeStyles.dark
|
|
123
125
|
: themeConfig.themeStyles.light;
|
|
@@ -432,7 +434,7 @@ function parseApprovedMcpToolsByServer(mcpStatusData) {
|
|
|
432
434
|
* ChatBase component — Universal chat panel supporting store, protocol, and custom modes.
|
|
433
435
|
*/
|
|
434
436
|
export function ChatBase(props) {
|
|
435
|
-
const { agentRuntimeConfig, protocol: protocolProp, useStore: useStoreMode = true, disableInternalJupyterTheme = false, } = props;
|
|
437
|
+
const { agentRuntimeConfig, protocol: protocolProp, useStore: useStoreMode = true, disableInternalJupyterTheme = false, themeVariant, colorMode, } = props;
|
|
436
438
|
// Resolve protocol: string Protocol overrides type in agentRuntimeConfig or
|
|
437
439
|
// is combined with a full ProtocolConfig object.
|
|
438
440
|
const protocolType = typeof protocolProp === 'string' ? protocolProp : undefined;
|
|
@@ -459,7 +461,7 @@ export function ChatBase(props) {
|
|
|
459
461
|
useStore: effectiveUseStoreMode,
|
|
460
462
|
};
|
|
461
463
|
const content = _jsx(ChatBaseInner, { ...innerProps });
|
|
462
|
-
const wrappedContent = disableInternalJupyterTheme ? (content) : (_jsx(ThemedChatBoundary, { children: content }));
|
|
464
|
+
const wrappedContent = disableInternalJupyterTheme ? (content) : (_jsx(ThemedChatBoundary, { themeVariant: themeVariant, colorMode: colorMode, children: content }));
|
|
463
465
|
if (!existingQueryClient) {
|
|
464
466
|
return (_jsx(QueryClientProvider, { client: internalQueryClient, children: wrappedContent }));
|
|
465
467
|
}
|
|
@@ -468,7 +470,7 @@ export function ChatBase(props) {
|
|
|
468
470
|
// ---------------------------------------------------------------------------
|
|
469
471
|
// ChatBaseInner — contains all actual logic
|
|
470
472
|
// ---------------------------------------------------------------------------
|
|
471
|
-
function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, autoConnect = true, codemodeEnabled = false, onToggleCodemode, initialModel, availableModels, mcpServers, initialSkills: _initialSkills, className, loadingState, headerActions, kernelIndicatorState, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, chatViewMode, onChatViewModeChange,
|
|
473
|
+
function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, autoConnect = true, codemodeEnabled = false, onToggleCodemode, initialModel, availableModels, mcpServers, initialSkills: _initialSkills, className, loadingState, headerActions, kernelIndicatorState, kernelIndicatorPlacement = 'left', kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, chatViewMode, onChatViewModeChange,
|
|
472
474
|
// Mode selection
|
|
473
475
|
useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, enableStreaming = false,
|
|
474
476
|
// Extended props
|
|
@@ -883,6 +885,10 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
883
885
|
requestAiAgentsApprovalHistory,
|
|
884
886
|
sendAiAgentsApprovalDecision,
|
|
885
887
|
]);
|
|
888
|
+
// Assigned once `applyServerApprovalDecision` is defined below. A ref lets the
|
|
889
|
+
// ai-agents approval WS effect (declared earlier) drive the deferred-run
|
|
890
|
+
// continuation without re-subscribing when the callback identity changes.
|
|
891
|
+
const applyServerApprovalDecisionRef = useRef(null);
|
|
886
892
|
const reconcileResolvedApprovalInStore = useCallback((approval) => {
|
|
887
893
|
const state = agentRuntimeStore.getState();
|
|
888
894
|
const removalIds = new Set([approval.id]);
|
|
@@ -988,7 +994,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
988
994
|
}
|
|
989
995
|
const state = agentRuntimeStore.getState();
|
|
990
996
|
for (const record of records) {
|
|
991
|
-
|
|
997
|
+
let approval = normalizeApprovalPayload(record);
|
|
998
|
+
// SaaS-resolved events (tool_approval_approved/rejected) can arrive
|
|
999
|
+
// with only {approvalId, status} and no tool_name/tool_args. Recover
|
|
1000
|
+
// the full envelope from the store (populated by the earlier pending
|
|
1001
|
+
// event) so the card clears AND the deferred run can resume.
|
|
1002
|
+
if (!approval) {
|
|
1003
|
+
const rawId = (typeof record.id === 'string' && record.id) ||
|
|
1004
|
+
(typeof record.approval_id === 'string' && record.approval_id) ||
|
|
1005
|
+
(typeof record.approvalId === 'string' && record.approvalId) ||
|
|
1006
|
+
'';
|
|
1007
|
+
const rawStatus = (typeof record.status === 'string' && record.status) || '';
|
|
1008
|
+
if (rawId && rawStatus && rawStatus !== 'pending') {
|
|
1009
|
+
const stored = state.approvals.find(a => a.id === rawId);
|
|
1010
|
+
if (stored) {
|
|
1011
|
+
approval = { ...stored, status: rawStatus };
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
992
1015
|
if (!approval) {
|
|
993
1016
|
continue;
|
|
994
1017
|
}
|
|
@@ -1018,6 +1041,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1018
1041
|
}
|
|
1019
1042
|
else {
|
|
1020
1043
|
reconcileResolvedApprovalInStore(scopedApproval);
|
|
1044
|
+
// Resume the deferred tool call when the decision was made on
|
|
1045
|
+
// another surface (e.g. the SaaS Tool Approvals UI). Without this
|
|
1046
|
+
// the pending card clears but pydantic-ai never receives the
|
|
1047
|
+
// client continuation and the run stays parked.
|
|
1048
|
+
applyServerApprovalDecisionRef.current?.(scopedApproval, scopedApproval.status === 'approved', scopedApproval.note ?? undefined);
|
|
1021
1049
|
}
|
|
1022
1050
|
}
|
|
1023
1051
|
}
|
|
@@ -1259,13 +1287,16 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1259
1287
|
});
|
|
1260
1288
|
return true;
|
|
1261
1289
|
}, [activeAgentId]);
|
|
1290
|
+
applyServerApprovalDecisionRef.current = applyServerApprovalDecision;
|
|
1262
1291
|
// ---- Agent-runtime WebSocket (monitoring stream) ----
|
|
1263
1292
|
// Derive the bare base URL from configEndpoint or protocol.endpoint.
|
|
1293
|
+
const isAgentNodeTunnelAgUi = Boolean(protocol?.endpoint &&
|
|
1294
|
+
/\/api\/runtimes\/v1\/agent-nodes\/[^/]+\/ag-ui\/?$/.test(protocol.endpoint));
|
|
1264
1295
|
const wsBaseUrl = protocol?.configEndpoint
|
|
1265
1296
|
? protocol.configEndpoint.replace(/\/api\/v1\/(config|configure)\/?$/, '')
|
|
1266
1297
|
: (protocol?.endpoint?.replace(/\/api\/v1\/.*$/, '') ?? '');
|
|
1267
1298
|
useAgentRuntimeWebSocket({
|
|
1268
|
-
enabled: !!protocol && !!wsBaseUrl,
|
|
1299
|
+
enabled: !!protocol && !!wsBaseUrl && !isAgentNodeTunnelAgUi,
|
|
1269
1300
|
baseUrl: wsBaseUrl,
|
|
1270
1301
|
authToken: protocol?.authToken,
|
|
1271
1302
|
agentId: protocol?.agentId,
|
|
@@ -2440,7 +2471,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2440
2471
|
pendingPromptSentRef.current = pendingPromptKey;
|
|
2441
2472
|
return;
|
|
2442
2473
|
}
|
|
2443
|
-
|
|
2474
|
+
// Do not block prompt replay forever when runtime history cannot be fetched
|
|
2475
|
+
// (e.g. websocket not connected yet/anymore). In that case we fall back to
|
|
2476
|
+
// submitting once the adapter is ready.
|
|
2477
|
+
const canProceedWithoutHistory = !historyScopeId || wsState !== 'connected';
|
|
2478
|
+
if (!historyLoaded && !canProceedWithoutHistory)
|
|
2444
2479
|
return;
|
|
2445
2480
|
if (!adapterReady && !onSendMessage)
|
|
2446
2481
|
return;
|
|
@@ -2453,6 +2488,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2453
2488
|
pendingPrompt,
|
|
2454
2489
|
pendingPromptKey,
|
|
2455
2490
|
historyLoaded,
|
|
2491
|
+
historyScopeId,
|
|
2492
|
+
wsState,
|
|
2456
2493
|
adapterReady,
|
|
2457
2494
|
handleSend,
|
|
2458
2495
|
onSendMessage,
|
|
@@ -2849,7 +2886,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2849
2886
|
// no ephemeral notebook is shown) or INSIDE the chat body column (when the
|
|
2850
2887
|
// notebook is visible) so the header always follows the chat body across all
|
|
2851
2888
|
// view modes (docked sidebar, floating popup, floating-small).
|
|
2852
|
-
const chatHeaderElement = showHeader ? (_jsx(ChatBaseHeader, { title: title, subtitle: subtitle, brandIcon: brandIcon, headerContent: headerContent, headerActions: headerActions, showInformation: showInformation, onInformationClick: onInformationClick, padding: padding, kernelIndicatorState: kernelIndicatorState, runtimeStatus: sandboxStatusData ?? sandboxStatusQuery.data, kernel: notebookVisible
|
|
2889
|
+
const chatHeaderElement = showHeader ? (_jsx(ChatBaseHeader, { title: title, subtitle: subtitle, brandIcon: brandIcon, headerContent: headerContent, headerActions: headerActions, showInformation: showInformation, onInformationClick: onInformationClick, padding: padding, kernelIndicatorState: kernelIndicatorState, kernelIndicatorPlacement: kernelIndicatorPlacement, runtimeStatus: sandboxStatusData ?? sandboxStatusQuery.data, kernel: notebookVisible
|
|
2853
2890
|
? (notebookKernel ?? kernel)
|
|
2854
2891
|
: documentVisible
|
|
2855
2892
|
? (documentKernel ?? kernel)
|
|
@@ -2900,7 +2937,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2900
2937
|
borderRight: '1px solid',
|
|
2901
2938
|
borderColor: 'border.default',
|
|
2902
2939
|
}),
|
|
2903
|
-
}, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
|
|
2940
|
+
}, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
|
|
2904
2941
|
? {
|
|
2905
2942
|
position: 'absolute',
|
|
2906
2943
|
right: 16,
|