@datalayer/agent-runtimes 1.0.4 → 1.0.6
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 +182 -1
- package/lib/AgentNode.d.ts +3 -0
- package/lib/AgentNode.js +676 -0
- package/lib/App.js +1 -1
- package/lib/agent-node/themeStore.d.ts +3 -0
- package/lib/agent-node/themeStore.js +156 -0
- package/lib/agent-node-main.d.ts +1 -0
- package/lib/agent-node-main.js +14 -0
- package/lib/agents/AgentDetails.d.ts +22 -1
- package/lib/agents/AgentDetails.js +34 -47
- package/lib/api/index.d.ts +0 -1
- package/lib/api/index.js +4 -2
- package/lib/chat/Chat.d.ts +5 -106
- package/lib/chat/Chat.js +20 -14
- package/lib/chat/ChatFloating.d.ts +7 -140
- package/lib/chat/ChatFloating.js +3 -3
- package/lib/chat/ChatPopupStandalone.d.ts +8 -47
- package/lib/chat/ChatPopupStandalone.js +3 -3
- package/lib/chat/ChatSidebar.d.ts +4 -69
- package/lib/chat/ChatSidebar.js +83 -51
- package/lib/chat/ChatStandalone.d.ts +4 -54
- package/lib/chat/ChatStandalone.js +3 -3
- package/lib/chat/base/ChatBase.js +1414 -174
- package/lib/chat/display/FloatingBrandButton.js +8 -1
- package/lib/chat/header/ChatHeader.d.ts +3 -1
- package/lib/chat/header/ChatHeader.js +15 -12
- package/lib/chat/header/ChatHeaderBase.d.ts +30 -5
- package/lib/chat/header/ChatHeaderBase.js +41 -16
- package/lib/chat/indicators/McpStatusIndicator.d.ts +7 -4
- package/lib/chat/indicators/McpStatusIndicator.js +7 -32
- package/lib/chat/indicators/SandboxStatusIndicator.d.ts +4 -1
- package/lib/chat/indicators/SandboxStatusIndicator.js +91 -56
- package/lib/chat/indicators/SkillsStatusIndicator.d.ts +7 -0
- package/lib/chat/indicators/SkillsStatusIndicator.js +88 -0
- package/lib/chat/indicators/index.d.ts +1 -0
- package/lib/chat/indicators/index.js +1 -0
- package/lib/chat/messages/ChatMessageList.d.ts +1 -1
- package/lib/chat/messages/ChatMessageList.js +154 -114
- package/lib/chat/messages/ChatMessages.js +6 -2
- package/lib/chat/prompt/InputFooter.d.ts +21 -6
- package/lib/chat/prompt/InputFooter.js +76 -20
- package/lib/chat/prompt/InputPrompt.d.ts +5 -1
- package/lib/chat/prompt/InputPrompt.js +4 -4
- package/lib/chat/prompt/InputPromptFooter.d.ts +3 -1
- package/lib/chat/prompt/InputPromptFooter.js +3 -3
- package/lib/chat/prompt/InputPromptLexical.d.ts +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +12 -5
- package/lib/chat/prompt/InputPromptText.d.ts +3 -1
- package/lib/chat/prompt/InputPromptText.js +2 -2
- package/lib/chat/tools/ToolApprovalBanner.js +1 -1
- package/lib/chat/tools/ToolCallDisplay.d.ts +3 -1
- package/lib/chat/tools/ToolCallDisplay.js +2 -2
- package/lib/chat/usage/TokenUsageBar.js +20 -2
- package/lib/client/AgentRuntimesClientContext.d.ts +53 -0
- package/lib/client/AgentRuntimesClientContext.js +55 -0
- package/lib/client/AgentsMixin.d.ts +0 -18
- package/lib/client/AgentsMixin.js +20 -30
- package/lib/client/IAgentRuntimesClient.d.ts +215 -0
- package/lib/client/IAgentRuntimesClient.js +5 -0
- package/lib/client/SdkAgentRuntimesClient.d.ts +151 -0
- package/lib/client/SdkAgentRuntimesClient.js +134 -0
- package/lib/client/index.d.ts +4 -1
- package/lib/client/index.js +3 -1
- package/lib/components/NotificationEventCard.js +5 -1
- package/lib/config/AgentConfiguration.d.ts +22 -0
- package/lib/config/AgentConfiguration.js +319 -64
- package/lib/context/ContextDistribution.d.ts +3 -1
- package/lib/context/ContextDistribution.js +8 -27
- package/lib/context/ContextInspector.d.ts +3 -1
- package/lib/context/ContextInspector.js +19 -67
- package/lib/context/ContextPanel.d.ts +3 -1
- package/lib/context/ContextPanel.js +104 -64
- package/lib/context/ContextUsage.d.ts +3 -1
- package/lib/context/ContextUsage.js +3 -3
- package/lib/context/CostTracker.d.ts +9 -3
- package/lib/context/CostTracker.js +26 -47
- package/lib/context/CostUsageChart.d.ts +12 -0
- package/lib/context/CostUsageChart.js +378 -0
- package/lib/context/GraphFlowChart.d.ts +16 -0
- package/lib/context/GraphFlowChart.js +182 -0
- package/lib/context/TokenUsageChart.d.ts +8 -1
- package/lib/context/TokenUsageChart.js +349 -211
- package/lib/context/TurnGraphChart.d.ts +39 -0
- package/lib/context/TurnGraphChart.js +538 -0
- package/lib/context/otelWsPool.d.ts +20 -0
- package/lib/context/otelWsPool.js +69 -0
- package/lib/examples/A2UiComponentGalleryExample.d.ts +0 -17
- package/lib/examples/A2UiComponentGalleryExample.js +315 -522
- package/lib/examples/A2UiContactCardExample.d.ts +0 -18
- package/lib/examples/A2UiContactCardExample.js +154 -411
- package/lib/examples/A2UiRestaurantExample.d.ts +0 -30
- package/lib/examples/A2UiRestaurantExample.js +114 -212
- package/lib/examples/A2UiViewerExample.d.ts +0 -18
- package/lib/examples/A2UiViewerExample.js +283 -532
- package/lib/examples/AgUiBackendToolRenderingExample.js +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.d.ts +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.js +1 -1
- package/lib/examples/AgUiSharedStateExample.js +2 -1
- package/lib/examples/AgentCheckpointsExample.js +14 -28
- package/lib/examples/AgentCodemodeExample.d.ts +4 -6
- package/lib/examples/AgentCodemodeExample.js +603 -169
- package/lib/examples/AgentEvalsExample.js +339 -53
- package/lib/examples/AgentGuardrailsExample.js +383 -66
- package/lib/examples/AgentHooksExample.d.ts +3 -0
- package/lib/examples/AgentHooksExample.js +122 -0
- package/lib/examples/AgentInferenceProviderExample.d.ts +3 -0
- package/lib/examples/AgentInferenceProviderExample.js +329 -0
- package/lib/examples/AgentMCPExample.d.ts +3 -0
- package/lib/examples/AgentMCPExample.js +481 -0
- package/lib/examples/AgentMemoryExample.d.ts +1 -2
- package/lib/examples/AgentMemoryExample.js +78 -33
- package/lib/examples/AgentMonitoringExample.js +261 -200
- package/lib/examples/AgentNotificationsExample.d.ts +1 -2
- package/lib/examples/AgentNotificationsExample.js +114 -33
- package/lib/examples/AgentOtelExample.js +32 -42
- package/lib/examples/AgentOutputsExample.d.ts +11 -6
- package/lib/examples/AgentOutputsExample.js +433 -81
- package/lib/examples/AgentParametersExample.d.ts +3 -0
- package/lib/examples/AgentParametersExample.js +248 -0
- package/lib/examples/AgentSandboxExample.d.ts +3 -3
- package/lib/examples/AgentSandboxExample.js +74 -45
- package/lib/examples/AgentSkillsExample.js +95 -103
- package/lib/examples/AgentSubagentsExample.d.ts +14 -0
- package/lib/examples/AgentSubagentsExample.js +228 -0
- package/lib/examples/AgentToolApprovalsExample.js +49 -561
- package/lib/examples/AgentTriggersExample.js +823 -569
- package/lib/examples/{AgentspecExample.d.ts → AgentspecsExample.d.ts} +2 -2
- package/lib/examples/AgentspecsExample.js +1096 -0
- package/lib/examples/ChatCustomExample.js +16 -28
- package/lib/examples/ChatExample.js +13 -29
- package/lib/examples/CopilotKitLexicalExample.js +2 -1
- package/lib/examples/CopilotKitNotebookExample.js +2 -1
- package/lib/examples/HomeExample.d.ts +15 -0
- package/lib/examples/HomeExample.js +77 -0
- package/lib/examples/Lexical2Example.js +4 -2
- package/lib/examples/{LexicalExample.d.ts → LexicalAgentExample.d.ts} +4 -4
- package/lib/examples/{LexicalExample.js → LexicalAgentExample.js} +66 -17
- package/lib/examples/{LexicalSidebarExample.d.ts → LexicalAgentSidebarExample.d.ts} +5 -5
- package/lib/examples/LexicalAgentSidebarExample.js +261 -0
- package/lib/examples/NotebookAgentExample.d.ts +9 -0
- package/lib/examples/NotebookAgentExample.js +192 -0
- package/lib/examples/{NotebookSidebarExample.d.ts → NotebookAgentSidebarExample.d.ts} +2 -2
- package/lib/examples/NotebookAgentSidebarExample.js +221 -0
- package/lib/examples/{DatalayerNotebookExample.d.ts → NotebookCollaborationExample.d.ts} +4 -4
- package/lib/examples/{DatalayerNotebookExample.js → NotebookCollaborationExample.js} +3 -3
- package/lib/examples/NotebookExample.d.ts +4 -7
- package/lib/examples/NotebookExample.js +14 -146
- package/lib/examples/components/AuthRequiredView.d.ts +6 -0
- package/lib/examples/components/AuthRequiredView.js +33 -0
- package/lib/examples/components/ExampleWrapper.d.ts +9 -3
- package/lib/examples/components/ExampleWrapper.js +45 -9
- package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.js +1 -1
- package/lib/examples/components/index.d.ts +3 -0
- package/lib/examples/components/index.js +4 -0
- package/lib/examples/{ag-ui → components}/weather/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/weather/index.js +1 -1
- package/lib/examples/example-selector.d.ts +17 -4
- package/lib/examples/example-selector.js +108 -41
- package/lib/examples/index.d.ts +10 -6
- package/lib/examples/index.js +10 -6
- package/lib/examples/lexical/initial-content.json +6 -6
- package/lib/examples/main.js +257 -27
- package/lib/examples/utils/a2ui.d.ts +18 -0
- package/lib/examples/utils/a2ui.js +69 -0
- package/lib/examples/utils/a2uiMarkdownProvider.d.ts +7 -0
- package/lib/examples/utils/a2uiMarkdownProvider.js +9 -0
- package/lib/examples/utils/agentId.d.ts +18 -0
- package/lib/examples/utils/agentId.js +54 -0
- package/lib/examples/utils/agents/earthquake-detector.json +11 -11
- package/lib/examples/utils/agents/sales-forecaster.json +11 -11
- package/lib/examples/utils/agents/social-post-generator.json +11 -11
- package/lib/examples/utils/agents/stock-market.json +11 -11
- package/lib/examples/utils/examplesStore.js +82 -27
- package/lib/examples/utils/useExampleAgentRuntimesUrl.d.ts +5 -0
- package/lib/examples/utils/useExampleAgentRuntimesUrl.js +19 -0
- package/lib/hooks/index.d.ts +8 -8
- package/lib/hooks/index.js +7 -7
- package/lib/hooks/useA2A.d.ts +2 -3
- package/lib/hooks/useAIAgentsWebSocket.d.ts +43 -4
- package/lib/hooks/useAIAgentsWebSocket.js +153 -12
- package/lib/hooks/useAcp.d.ts +1 -2
- package/lib/hooks/useAgUi.d.ts +1 -1
- package/lib/hooks/{useAgents.d.ts → useAgentRuntimes.d.ts} +70 -4
- package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +237 -32
- package/lib/hooks/useAgentsCatalog.js +1 -1
- package/lib/hooks/useAgentsService.d.ts +2 -2
- package/lib/hooks/useAgentsService.js +7 -7
- package/lib/hooks/useCheckpoints.js +1 -1
- package/lib/hooks/useConfig.d.ts +4 -1
- package/lib/hooks/useConfig.js +10 -3
- package/lib/hooks/useContextSnapshot.d.ts +9 -4
- package/lib/hooks/useContextSnapshot.js +9 -37
- package/lib/hooks/useMonitoring.js +3 -0
- package/lib/hooks/useSandbox.d.ts +20 -8
- package/lib/hooks/useSandbox.js +105 -40
- package/lib/hooks/useSkills.d.ts +23 -5
- package/lib/hooks/useSkills.js +94 -39
- package/lib/hooks/useToolApprovals.d.ts +60 -36
- package/lib/hooks/useToolApprovals.js +318 -69
- package/lib/hooks/useVercelAI.d.ts +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -0
- package/lib/inference/index.d.ts +0 -1
- package/lib/middleware/index.d.ts +0 -1
- package/lib/protocols/AGUIAdapter.js +6 -0
- package/lib/protocols/VercelAIAdapter.d.ts +7 -0
- package/lib/protocols/VercelAIAdapter.js +59 -7
- package/lib/specs/agents/agents.d.ts +21 -4
- package/lib/specs/agents/agents.js +2879 -316
- package/lib/specs/agents/index.js +3 -1
- package/lib/specs/benchmarks.d.ts +20 -0
- package/lib/specs/benchmarks.js +205 -0
- package/lib/specs/envvars.js +27 -20
- package/lib/specs/evals.d.ts +10 -9
- package/lib/specs/evals.js +128 -88
- package/lib/specs/events.d.ts +3 -10
- package/lib/specs/events.js +127 -84
- package/lib/specs/frontendTools.js +2 -2
- package/lib/specs/guardrails.d.ts +0 -7
- package/lib/specs/guardrails.js +240 -159
- package/lib/specs/mcpServers.js +35 -6
- package/lib/specs/memory.d.ts +0 -2
- package/lib/specs/memory.js +4 -17
- package/lib/specs/models.d.ts +0 -2
- package/lib/specs/models.js +20 -15
- package/lib/specs/notifications.js +102 -18
- package/lib/specs/outputs.js +15 -9
- package/lib/specs/personas.d.ts +41 -0
- package/lib/specs/personas.js +168 -0
- package/lib/specs/skills.d.ts +1 -1
- package/lib/specs/skills.js +23 -23
- package/lib/specs/teams/index.js +3 -1
- package/lib/specs/teams/teams.js +468 -348
- package/lib/specs/tools.js +4 -4
- package/lib/specs/triggers.js +61 -11
- package/lib/stores/agentRuntimeStore.d.ts +208 -0
- package/lib/stores/agentRuntimeStore.js +650 -0
- package/lib/stores/conversationStore.js +2 -2
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/tools/adapters/copilotkit/lexicalHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/lexicalHooks.js +1 -3
- package/lib/tools/adapters/copilotkit/notebookHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -3
- package/lib/tools/index.d.ts +0 -2
- package/lib/tools/index.js +0 -1
- package/lib/types/agents-lifecycle.d.ts +18 -0
- package/lib/types/agents.d.ts +6 -0
- package/lib/types/agentspecs.d.ts +54 -1
- package/lib/types/benchmarks.d.ts +43 -0
- package/lib/types/benchmarks.js +5 -0
- package/lib/types/chat.d.ts +325 -8
- package/lib/types/context.d.ts +27 -0
- package/lib/types/cost.d.ts +2 -2
- package/lib/types/evals.d.ts +26 -17
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +3 -0
- package/lib/types/mcp.d.ts +8 -0
- package/lib/types/models.d.ts +2 -2
- package/lib/types/personas.d.ts +25 -0
- package/lib/types/personas.js +5 -0
- package/lib/types/skills.d.ts +43 -1
- package/lib/types/stream.d.ts +110 -0
- package/lib/types/stream.js +36 -0
- package/lib/utils/utils.d.ts +9 -5
- package/lib/utils/utils.js +9 -5
- package/package.json +19 -11
- package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_benchmarks.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_events.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
- package/scripts/codegen/generate_agents.py +187 -45
- package/scripts/codegen/generate_benchmarks.py +441 -0
- package/scripts/codegen/generate_evals.py +94 -16
- package/scripts/codegen/generate_events.py +35 -14
- package/scripts/codegen/generate_personas.py +319 -0
- package/scripts/codegen/generate_skills.py +9 -9
- package/scripts/sync-jupyter.sh +26 -7
- package/lib/api/tool-approvals.d.ts +0 -62
- package/lib/api/tool-approvals.js +0 -145
- package/lib/examples/AgentspecExample.js +0 -705
- package/lib/examples/LexicalSidebarExample.js +0 -163
- package/lib/examples/NotebookSidebarExample.js +0 -119
- package/lib/examples/NotebookSimpleExample.d.ts +0 -6
- package/lib/examples/NotebookSimpleExample.js +0 -22
- package/lib/examples/ag-ui/index.d.ts +0 -10
- package/lib/examples/ag-ui/index.js +0 -16
- package/lib/hooks/useAgentsRegistry.d.ts +0 -10
- package/lib/hooks/useAgentsRegistry.js +0 -20
- package/lib/stores/agentsStore.d.ts +0 -123
- package/lib/stores/agentsStore.js +0 -270
- /package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.js +0 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { type ReactNode, type RefObject } from 'react';
|
|
8
8
|
import type { DisplayItem, AvatarConfig, RenderToolResult } from '../../types/chat';
|
|
9
9
|
export interface ToolApprovalConfig {
|
|
10
|
-
/** Base API URL for the agent runtime (e.g., http://localhost:8765/api/v1) */
|
|
10
|
+
/** Base API URL for the agent runtime (e.g., `http://localhost:8765/api/v1`). */
|
|
11
11
|
apiBaseUrl: string;
|
|
12
12
|
/** Auth token for API calls */
|
|
13
13
|
authToken?: string;
|
|
@@ -9,138 +9,177 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
9
9
|
*
|
|
10
10
|
* @module chat/messages/MessageList
|
|
11
11
|
*/
|
|
12
|
-
import { useState,
|
|
12
|
+
import { useState, useCallback, useMemo, } from 'react';
|
|
13
13
|
import { Text } from '@primer/react';
|
|
14
14
|
import { Box } from '@datalayer/primer-addons';
|
|
15
15
|
import { Streamdown } from 'streamdown';
|
|
16
16
|
import { streamdownMarkdownStyles, streamdownCodeBlockStyles, } from '../styles/streamdownStyles';
|
|
17
17
|
import { ToolCallDisplay } from '../tools/ToolCallDisplay';
|
|
18
18
|
import { isToolCallMessage, getMessageText } from '../../utils';
|
|
19
|
+
import { useAgentRuntimeStore } from '../../stores/agentRuntimeStore';
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
|
-
//
|
|
21
|
+
// Normalize helper
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
|
-
function
|
|
23
|
+
function normalizeName(name) {
|
|
24
|
+
return name
|
|
25
|
+
.replace(/:[0-9]+\.[0-9]+\.[0-9]+.*$/, '')
|
|
26
|
+
.replace(/[-_]/g, '')
|
|
27
|
+
.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Expand a single-line markdown table (rows joined with `||`) into one row
|
|
31
|
+
* per line so a markdown renderer can produce a real HTML table. Idempotent:
|
|
32
|
+
* any pre-existing `|\n|` boundaries are unaffected.
|
|
33
|
+
*/
|
|
34
|
+
function expandCompactMarkdownTableBody(body) {
|
|
35
|
+
if (!body)
|
|
36
|
+
return body;
|
|
37
|
+
if (!/\|\s*[-:| ]{3,}\|/.test(body))
|
|
38
|
+
return body;
|
|
39
|
+
if (!body.includes('||'))
|
|
40
|
+
return body;
|
|
41
|
+
return body.replace(/\|\|/g, '|\n|');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Pre-process assistant text for Streamdown:
|
|
45
|
+
* - Unwrap ```markdown / ```md fenced blocks so tables render as HTML
|
|
46
|
+
* instead of as a code block.
|
|
47
|
+
* - Inside any fenced block (or top-level body), expand compact one-line
|
|
48
|
+
* markdown tables.
|
|
49
|
+
*/
|
|
50
|
+
function normalizeAssistantMarkdown(text) {
|
|
51
|
+
if (!text)
|
|
52
|
+
return text;
|
|
53
|
+
// Unwrap explicit ```markdown / ```md fences and expand compact tables.
|
|
54
|
+
let out = text.replace(/```(markdown|md)\s*\n([\s\S]*?)```/gi, (_match, _lang, body) => {
|
|
55
|
+
const expanded = expandCompactMarkdownTableBody(body.trim());
|
|
56
|
+
return `\n\n${expanded}\n\n`;
|
|
57
|
+
});
|
|
58
|
+
// Also expand compact tables inside other fenced blocks that happen to
|
|
59
|
+
// carry a markdown table (e.g. bare ``` fences).
|
|
60
|
+
out = out.replace(/```([a-zA-Z0-9_+-]*)\n([\s\S]*?)```/g, (match, lang, body) => {
|
|
61
|
+
const expanded = expandCompactMarkdownTableBody(body);
|
|
62
|
+
if (expanded === body)
|
|
63
|
+
return match;
|
|
64
|
+
// If we expanded an unlabeled fence containing a real markdown table,
|
|
65
|
+
// unwrap it so it renders as a table.
|
|
66
|
+
if (!lang || /^(text|plain)$/i.test(lang)) {
|
|
67
|
+
return `\n\n${expanded.trim()}\n\n`;
|
|
68
|
+
}
|
|
69
|
+
return `\`\`\`${lang}\n${expanded}\`\`\``;
|
|
70
|
+
});
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// DefaultToolCallRenderer — reads approvals from the Zustand store,
|
|
75
|
+
// sends decisions over the shared WebSocket (no REST polling).
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
function DefaultToolCallRenderer({ item, onRespond, }) {
|
|
23
78
|
const resultObject = item.result && typeof item.result === 'object'
|
|
24
79
|
? item.result
|
|
25
80
|
: undefined;
|
|
26
81
|
// Detect pending approval from tool result (pydantic-deferred mode)
|
|
27
82
|
const isPendingFromResult = item.status === 'inProgress' && resultObject?.pending_approval === true;
|
|
83
|
+
// Extract the approval_id carried in the tool result by the adapter.
|
|
84
|
+
// This is always available when the SSE stream contained a
|
|
85
|
+
// `tool-approval-request` event, even when the Zustand store has not been
|
|
86
|
+
// populated (e.g. no monitoring WS open).
|
|
87
|
+
const resultApprovalId = typeof resultObject?.approval_id === 'string'
|
|
88
|
+
? resultObject.approval_id
|
|
89
|
+
: undefined;
|
|
28
90
|
// In ai-agents-wrapper mode, the server blocks waiting for approval and
|
|
29
91
|
// never sends a tool-result with pending_approval. The tool stays in
|
|
30
|
-
// 'executing' status.
|
|
31
|
-
// a pending approval record exists for this tool.
|
|
92
|
+
// 'executing' status.
|
|
32
93
|
const isExecuting = item.status === 'executing';
|
|
33
|
-
const [matchedApprovalId, setMatchedApprovalId] = useState(null);
|
|
34
94
|
const [decision, setDecision] = useState();
|
|
35
|
-
const
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!
|
|
95
|
+
const normalizedToolName = useMemo(() => normalizeName(item.toolName), [item.toolName]);
|
|
96
|
+
// Skill tools (`run_skill_script`, `load_skill`, `read_skill_resource`) are
|
|
97
|
+
// gated by the server under a synthetic approval ``tool_name`` of the form
|
|
98
|
+
// ``skill:<skill_id>`` (see ``SkillsGuardrailCapability._request_skill_approval``).
|
|
99
|
+
// Capture the skill id carried in the tool-call arguments so we can match
|
|
100
|
+
// the inline approval button against that synthetic approval entry.
|
|
101
|
+
const skillApprovalKey = useMemo(() => {
|
|
102
|
+
const SKILL_TOOLS = new Set([
|
|
103
|
+
'run_skill_script',
|
|
104
|
+
'load_skill',
|
|
105
|
+
'read_skill_resource',
|
|
106
|
+
]);
|
|
107
|
+
if (!SKILL_TOOLS.has(item.toolName))
|
|
108
|
+
return null;
|
|
109
|
+
const a = (item.args ?? {});
|
|
110
|
+
const raw = a.skill_name ?? a.skill ?? a.name;
|
|
111
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
112
|
+
return null;
|
|
113
|
+
// Strip optional ``<name>:<version>`` suffix to the base skill id.
|
|
114
|
+
const base = raw.split(':', 1)[0] || raw;
|
|
115
|
+
return `skill:${base}`.toLowerCase();
|
|
116
|
+
}, [item.toolName, item.args]);
|
|
117
|
+
// Read pending approvals from the Zustand store (fed by the agent-runtime WS).
|
|
118
|
+
const approvals = useAgentRuntimeStore(s => s.approvals);
|
|
119
|
+
// Prefer an exact match by approval id (when present in SSE tool result).
|
|
120
|
+
const matchedByResultId = useMemo(() => {
|
|
121
|
+
if (!resultApprovalId)
|
|
122
|
+
return null;
|
|
123
|
+
return approvals.find(a => a.id === resultApprovalId) ?? null;
|
|
124
|
+
}, [approvals, resultApprovalId]);
|
|
125
|
+
// Match the synthetic ``skill:<id>`` approval for skill tool calls. This
|
|
126
|
+
// runs whenever the tool call is a skill tool so the inline Approve/Deny
|
|
127
|
+
// buttons surface even when the server is blocked in
|
|
128
|
+
// ``ToolApprovalManager.request_and_wait`` (status stays ``executing`` and
|
|
129
|
+
// no ``pending_approval=True`` result is ever emitted).
|
|
130
|
+
const matchedBySkill = useMemo(() => {
|
|
131
|
+
if (!skillApprovalKey)
|
|
132
|
+
return null;
|
|
133
|
+
return (approvals.find(a => a.tool_name?.toLowerCase() === skillApprovalKey) ??
|
|
134
|
+
null);
|
|
135
|
+
}, [approvals, skillApprovalKey]);
|
|
136
|
+
// Fallback to matching by tool name for inline approval flows that don't
|
|
137
|
+
// always provide approval_id in the tool result payload.
|
|
138
|
+
const matchedByName = useMemo(() => {
|
|
139
|
+
if (!isPendingFromResult && !isExecuting)
|
|
140
|
+
return null;
|
|
141
|
+
return (approvals.find(a => normalizeName(a.tool_name) === normalizedToolName) ??
|
|
142
|
+
null);
|
|
143
|
+
}, [approvals, normalizedToolName, isPendingFromResult, isExecuting]);
|
|
144
|
+
const matchedApproval = matchedByResultId ?? matchedBySkill ?? matchedByName;
|
|
145
|
+
// Prefer the store-matched approval id, fall back to the id from the tool
|
|
146
|
+
// result (SSE path). This ensures the approve/deny buttons work even when
|
|
147
|
+
// the monitoring WS is not connected.
|
|
148
|
+
const effectiveApprovalId = matchedApproval?.id ?? resultApprovalId ?? null;
|
|
149
|
+
// Reflect approval decisions that happened outside this card (e.g. sidebar).
|
|
150
|
+
const externalDecision = matchedApproval?.status === 'approved'
|
|
151
|
+
? 'approved'
|
|
152
|
+
: matchedApproval?.status === 'rejected'
|
|
153
|
+
? 'denied'
|
|
154
|
+
: undefined;
|
|
155
|
+
const makeDecision = useCallback((action) => {
|
|
156
|
+
if (!effectiveApprovalId)
|
|
48
157
|
return;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return;
|
|
61
|
-
const data = await res.json();
|
|
62
|
-
const approvals = Array.isArray(data)
|
|
63
|
-
? data
|
|
64
|
-
: (data.approvals ??
|
|
65
|
-
data.requests ??
|
|
66
|
-
[]);
|
|
67
|
-
// Match by normalized tool name
|
|
68
|
-
const match = approvals.find(a => {
|
|
69
|
-
const aNormalized = String(a.tool_name || '')
|
|
70
|
-
.replace(/:[0-9]+\.[0-9]+\.[0-9]+.*$/, '')
|
|
71
|
-
.replace(/[-_]/g, '')
|
|
72
|
-
.toLowerCase();
|
|
73
|
-
return aNormalized === normalizedToolName && a.status === 'pending';
|
|
74
|
-
});
|
|
75
|
-
if (match && !cancelled) {
|
|
76
|
-
setMatchedApprovalId(match.id);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
// Retry on next interval
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
poll();
|
|
84
|
-
const interval = setInterval(poll, 3000);
|
|
85
|
-
return () => {
|
|
86
|
-
cancelled = true;
|
|
87
|
-
clearInterval(interval);
|
|
88
|
-
};
|
|
89
|
-
}, [
|
|
90
|
-
shouldPoll,
|
|
91
|
-
approvalConfig?.apiBaseUrl,
|
|
92
|
-
approvalConfig?.authToken,
|
|
93
|
-
normalizedToolName,
|
|
94
|
-
]);
|
|
95
|
-
const makeDecision = useCallback(async (action) => {
|
|
96
|
-
if (!matchedApprovalId || !approvalConfig?.apiBaseUrl)
|
|
97
|
-
return;
|
|
98
|
-
setLoading(true);
|
|
99
|
-
try {
|
|
100
|
-
const headers = {
|
|
101
|
-
'Content-Type': 'application/json',
|
|
102
|
-
};
|
|
103
|
-
if (approvalConfig.authToken) {
|
|
104
|
-
headers['Authorization'] = `Bearer ${approvalConfig.authToken}`;
|
|
105
|
-
}
|
|
106
|
-
const res = await fetch(`${approvalConfig.apiBaseUrl}/tool-approvals/${matchedApprovalId}/${action}`, {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
headers,
|
|
109
|
-
body: JSON.stringify({}),
|
|
110
|
-
});
|
|
111
|
-
if (res.ok) {
|
|
112
|
-
setDecision(action === 'approve' ? 'approved' : 'denied');
|
|
113
|
-
onRespond({
|
|
114
|
-
type: 'tool-approval-decision',
|
|
115
|
-
approved: action === 'approve',
|
|
116
|
-
approvalId: matchedApprovalId,
|
|
117
|
-
toolName: item.toolName,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// Allow retry
|
|
123
|
-
}
|
|
124
|
-
finally {
|
|
125
|
-
setLoading(false);
|
|
126
|
-
}
|
|
127
|
-
}, [
|
|
128
|
-
matchedApprovalId,
|
|
129
|
-
approvalConfig?.apiBaseUrl,
|
|
130
|
-
approvalConfig?.authToken,
|
|
131
|
-
onRespond,
|
|
132
|
-
item.toolCallId,
|
|
133
|
-
item.toolName,
|
|
134
|
-
]);
|
|
158
|
+
const approved = action === 'approve';
|
|
159
|
+
// Use ONLY the adapter continuation path (SSE/POST). Sending both WS and
|
|
160
|
+
// continuation decisions can trigger duplicate approval cycles.
|
|
161
|
+
setDecision(approved ? 'approved' : 'denied');
|
|
162
|
+
onRespond({
|
|
163
|
+
type: 'tool-approval-decision',
|
|
164
|
+
approved,
|
|
165
|
+
approvalId: effectiveApprovalId,
|
|
166
|
+
toolName: item.toolName,
|
|
167
|
+
});
|
|
168
|
+
}, [effectiveApprovalId, onRespond, item.toolName]);
|
|
135
169
|
// Show approval UI when we have a confirmed pending approval (from result
|
|
136
|
-
// or discovered via
|
|
137
|
-
const hasApproval = isPendingFromResult || !!
|
|
138
|
-
const approvalState = decision || (hasApproval ? 'pending' : undefined);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
?
|
|
143
|
-
: undefined
|
|
170
|
+
// or discovered via the store) or after a decision has been made.
|
|
171
|
+
const hasApproval = isPendingFromResult || !!effectiveApprovalId || !!externalDecision;
|
|
172
|
+
const approvalState = decision || externalDecision || (hasApproval ? 'pending' : undefined);
|
|
173
|
+
const approvalDecisionSource = decision
|
|
174
|
+
? 'inline'
|
|
175
|
+
: externalDecision
|
|
176
|
+
? 'external'
|
|
177
|
+
: undefined;
|
|
178
|
+
return (_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode, approvalRequired: hasApproval, approvalState: approvalState, approvalDecisionSource: approvalDecisionSource, onApprove: effectiveApprovalId && !decision && !externalDecision
|
|
179
|
+
? () => makeDecision('approve')
|
|
180
|
+
: undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
|
|
181
|
+
? () => makeDecision('reject')
|
|
182
|
+
: undefined, approvalLoading: false }));
|
|
144
183
|
}
|
|
145
184
|
// ---------------------------------------------------------------------------
|
|
146
185
|
// Component
|
|
@@ -271,6 +310,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
|
|
|
271
310
|
: avatarConfig.assistantAvatar })), _jsx(Box, { sx: {
|
|
272
311
|
maxWidth: '85%',
|
|
273
312
|
p: 2,
|
|
313
|
+
overflowX: 'auto',
|
|
274
314
|
borderRadius: 2,
|
|
275
315
|
backgroundColor: isUser ? 'accent.emphasis' : 'canvas.subtle',
|
|
276
316
|
// Use primary-button text token for better contrast when
|
|
@@ -283,7 +323,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
|
|
|
283
323
|
fontSize: 1,
|
|
284
324
|
whiteSpace: 'pre-wrap',
|
|
285
325
|
wordBreak: 'break-word',
|
|
286
|
-
}, children: getMessageText(message) })) : (_jsx(Box, { sx: streamdownMarkdownStyles, children: _jsx(Streamdown, { children: getMessageText(message) || (isStreaming ? '...' : '') }) })) })] }) }, message.id));
|
|
326
|
+
}, children: getMessageText(message) })) : (_jsx(Box, { sx: streamdownMarkdownStyles, children: _jsx(Streamdown, { children: normalizeAssistantMarkdown(getMessageText(message) || (isStreaming ? '...' : '')) }) })) })] }) }, message.id));
|
|
287
327
|
}), showLoadingIndicator && (isLoading || isStreaming) && (_jsx(Box, { sx: {
|
|
288
328
|
display: 'flex',
|
|
289
329
|
alignItems: 'flex-start',
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
*/
|
|
12
12
|
import { useRef, useEffect } from 'react';
|
|
13
13
|
import { Text, RelativeTime } from '@primer/react';
|
|
14
|
-
import { Box } from '@datalayer/primer-addons';
|
|
14
|
+
import { Box, useThemeStore, getColorPalette } from '@datalayer/primer-addons';
|
|
15
15
|
import { PersonIcon, ToolsIcon } from '@primer/octicons-react';
|
|
16
16
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
17
17
|
import { useChatMessages, useChatExtensionRegistry, } from '../../stores/chatStore';
|
|
@@ -24,6 +24,10 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
24
24
|
const extensionRegistry = extensionRegistryProp ?? storeExtensionRegistry;
|
|
25
25
|
const containerRef = useRef(null);
|
|
26
26
|
const lastMessageRef = useRef(null);
|
|
27
|
+
// Resolve a light color from the current user theme palette so the
|
|
28
|
+
// assistant icon contrasts the saturated `accent.emphasis` avatar bg.
|
|
29
|
+
const { theme, colorMode } = useThemeStore();
|
|
30
|
+
const assistantIconColor = getColorPalette(theme, colorMode).primary;
|
|
27
31
|
// Auto-scroll to bottom on new messages
|
|
28
32
|
useEffect(() => {
|
|
29
33
|
if (autoScroll && lastMessageRef.current) {
|
|
@@ -73,7 +77,7 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
73
77
|
color: message.role === 'user'
|
|
74
78
|
? 'fg.default'
|
|
75
79
|
: 'var(--button-primary-fgColor-rest, var(--fgColor-onEmphasis))',
|
|
76
|
-
}, children: message.role === 'user' ? (_jsx(PersonIcon, { size: 16 })) : message.role === 'assistant' ? (_jsx(AiAgentIcon, { size: 16 })) : (_jsx(ToolsIcon, { size: 16 })) }) })), _jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsxs(Box, { sx: {
|
|
80
|
+
}, children: message.role === 'user' ? (_jsx(PersonIcon, { size: 16 })) : message.role === 'assistant' ? (_jsx(AiAgentIcon, { size: 16, color: assistantIconColor })) : (_jsx(ToolsIcon, { size: 16 })) }) })), _jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsxs(Box, { sx: {
|
|
77
81
|
display: 'flex',
|
|
78
82
|
alignItems: 'center',
|
|
79
83
|
gap: 2,
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { KernelMessage } from '@jupyterlab/services';
|
|
2
|
+
import type { BuiltinTool, ContextSnapshotData, MCPServerConfig, McpToolsetsStatusResponse, ModelConfig, SkillInfo } from '../../types';
|
|
2
3
|
export interface InputToolbarProps {
|
|
3
4
|
input: string;
|
|
4
5
|
setInput: (value: string) => void;
|
|
5
6
|
isLoading: boolean;
|
|
7
|
+
kernelStatus?: KernelMessage.Status;
|
|
8
|
+
connectionConfirmed: boolean;
|
|
6
9
|
placeholder?: string;
|
|
7
10
|
autoFocus: boolean;
|
|
8
11
|
focusTrigger?: number;
|
|
9
12
|
padding: number;
|
|
10
13
|
onSend: () => void;
|
|
11
14
|
onStop: () => void;
|
|
15
|
+
disableInputPrompt?: boolean;
|
|
12
16
|
showTokenUsage: boolean;
|
|
13
17
|
agentUsage?: ContextSnapshotData;
|
|
14
18
|
showModelSelector: boolean;
|
|
15
19
|
showToolsMenu: boolean;
|
|
16
20
|
showSkillsMenu: boolean;
|
|
17
21
|
codemodeEnabled: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Optional callback invoked when the user toggles codemode from the Tools
|
|
24
|
+
* menu. When omitted the toggle renders as read-only.
|
|
25
|
+
*/
|
|
26
|
+
onToggleCodemode?: (enabled: boolean) => void | Promise<void>;
|
|
18
27
|
isA2AProtocol: boolean;
|
|
19
28
|
hasConfigData: boolean;
|
|
20
29
|
hasSkillsData: boolean;
|
|
@@ -28,16 +37,22 @@ export interface InputToolbarProps {
|
|
|
28
37
|
enabledMcpToolCount: number;
|
|
29
38
|
onToggleMcpTool: (serverId: string, toolName: string) => void;
|
|
30
39
|
onToggleAllMcpServerTools: (serverId: string, toolNames: string[], enable: boolean) => void;
|
|
40
|
+
/** Approved MCP tools per server (default: all tools approved) */
|
|
41
|
+
approvedMcpTools: Map<string, Set<string>>;
|
|
42
|
+
onToggleMcpToolApproval: (serverId: string, toolName: string) => void;
|
|
31
43
|
skills: SkillInfo[];
|
|
32
44
|
skillsLoading: boolean;
|
|
33
45
|
enabledSkills: Set<string>;
|
|
34
46
|
onToggleSkill: (skillId: string) => void;
|
|
35
47
|
onToggleAllSkills: (skillIds: string[], enable: boolean) => void;
|
|
36
|
-
/**
|
|
48
|
+
/** Approved skills set (default: all skills approved) */
|
|
49
|
+
approvedSkills: Set<string>;
|
|
50
|
+
onToggleSkillApproval: (skillId: string) => void;
|
|
51
|
+
/** API base URL passed to MCP indicator */
|
|
37
52
|
apiBase?: string;
|
|
38
|
-
/** Auth token passed to MCP
|
|
53
|
+
/** Auth token passed to MCP indicator */
|
|
39
54
|
authToken?: string;
|
|
40
|
-
/**
|
|
41
|
-
|
|
55
|
+
/** Pre-fetched MCP status from WebSocket — bypasses REST polling */
|
|
56
|
+
mcpStatusData?: McpToolsetsStatusResponse | null;
|
|
42
57
|
}
|
|
43
|
-
export declare function InputToolbar({ input, setInput, isLoading, placeholder, autoFocus, focusTrigger, padding, onSend, onStop, showTokenUsage, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, codemodeEnabled, isA2AProtocol, hasConfigData, hasSkillsData, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, apiBase, authToken,
|
|
58
|
+
export declare function InputToolbar({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, autoFocus, focusTrigger, padding, onSend, onStop, disableInputPrompt, showTokenUsage, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -17,30 +17,49 @@ import { ToolsIcon, BriefcaseIcon, AiModelIcon } from '@primer/octicons-react';
|
|
|
17
17
|
import { InputPrompt } from './InputPrompt';
|
|
18
18
|
import { TokenUsageBar } from '../usage/TokenUsageBar';
|
|
19
19
|
import { McpStatusIndicator } from '../indicators/McpStatusIndicator';
|
|
20
|
-
import {
|
|
20
|
+
import { SkillsStatusIndicator } from '../indicators/SkillsStatusIndicator';
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
// Component
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
|
-
export function InputToolbar({ input, setInput, isLoading, placeholder, autoFocus, focusTrigger, padding, onSend, onStop, showTokenUsage, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, codemodeEnabled, isA2AProtocol, hasConfigData, hasSkillsData, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, apiBase, authToken,
|
|
24
|
+
export function InputToolbar({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, autoFocus, focusTrigger, padding, onSend, onStop, disableInputPrompt = false, showTokenUsage, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }) {
|
|
25
|
+
const isKernelBusy = kernelStatus === 'busy';
|
|
26
|
+
const showSelectorsBar = showModelSelector || showToolsMenu || showSkillsMenu;
|
|
27
|
+
const hasSelectorsContent = hasConfigData || hasSkillsData;
|
|
25
28
|
// Show token usage when we have valid context data
|
|
26
|
-
const hasContext = agentUsage && !agentUsage.error && agentUsage.totalTokens > 0;
|
|
27
|
-
return (_jsxs(Box, { children: [_jsx(InputPrompt, { placeholder: placeholder || 'Type a message...', isLoading: isLoading, onSend: onSend, onStop: onStop, autoFocus: autoFocus, focusTrigger: focusTrigger, padding: padding, value: input, onChange: setInput, footerRightContent: _jsxs(_Fragment, { children: [_jsx(
|
|
28
|
-
(hasConfigData || hasSkillsData) && (_jsxs(Box, { sx: {
|
|
29
|
+
const hasContext = Boolean(agentUsage && !agentUsage.error && agentUsage.totalTokens > 0);
|
|
30
|
+
return (_jsxs(Box, { children: [_jsx(InputPrompt, { placeholder: placeholder || 'Type a message...', isLoading: isLoading, isKernelBusy: isKernelBusy, disabled: disableInputPrompt, readOnly: !connectionConfirmed, onSend: onSend, onStop: onStop, autoFocus: autoFocus, focusTrigger: focusTrigger, padding: padding, value: input, onChange: setInput, footerRightContent: _jsxs(_Fragment, { children: [_jsx(McpStatusIndicator, { apiBase: apiBase, authToken: authToken, data: mcpStatusData }), _jsx(SkillsStatusIndicator, { skillsCount: skills.length, enabledCount: enabledSkills.size, loading: skillsLoading })] }) }), showTokenUsage && (_jsx(Box, { sx: { minHeight: hasContext && agentUsage ? 28 : 8 }, children: hasContext && agentUsage ? (_jsx(TokenUsageBar, { agentUsage: agentUsage, padding: padding })) : null })), showSelectorsBar && (_jsx(Box, { sx: {
|
|
29
31
|
display: 'flex',
|
|
30
32
|
gap: 2,
|
|
31
33
|
px: padding,
|
|
32
|
-
py:
|
|
34
|
+
py: 0.5,
|
|
35
|
+
minHeight: 36,
|
|
33
36
|
borderTop: '1px solid',
|
|
34
37
|
borderColor: 'border.default',
|
|
35
38
|
alignItems: 'center',
|
|
36
39
|
bg: 'canvas.subtle',
|
|
37
|
-
}, children: [showToolsMenu && (_jsx(ToolsMenu, { codemodeEnabled: codemodeEnabled, mcpServers: mcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: enabledMcpToolCount, onToggleMcpTool: onToggleMcpTool, onToggleAllMcpServerTools: onToggleAllMcpServerTools, availableTools: availableTools })), showSkillsMenu && (_jsx(SkillsMenu, { skills: skills, skillsLoading: skillsLoading, enabledSkills: enabledSkills, onToggleSkill: onToggleSkill, onToggleAllSkills: onToggleAllSkills })), showModelSelector && models.length > 0 && selectedModel && (_jsx(ModelSelector, { models: models, selectedModel: selectedModel, onModelSelect: onModelSelect, isA2AProtocol: isA2AProtocol }))] }))] }));
|
|
40
|
+
}, children: hasSelectorsContent ? (_jsxs(_Fragment, { children: [showToolsMenu && (_jsx(ToolsMenu, { codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, mcpServers: mcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: enabledMcpToolCount, onToggleMcpTool: onToggleMcpTool, onToggleAllMcpServerTools: onToggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: onToggleMcpToolApproval, availableTools: availableTools })), showSkillsMenu && (_jsx(SkillsMenu, { skills: skills, skillsLoading: skillsLoading, enabledSkills: enabledSkills, onToggleSkill: onToggleSkill, onToggleAllSkills: onToggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: onToggleSkillApproval })), showModelSelector && models.length > 0 && selectedModel && (_jsx(ModelSelector, { models: models, selectedModel: selectedModel, onModelSelect: onModelSelect, isA2AProtocol: isA2AProtocol }))] })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Loading controls..." })) }))] }));
|
|
38
41
|
}
|
|
39
42
|
// ---------------------------------------------------------------------------
|
|
40
43
|
// ToolsMenu (private sub-component)
|
|
41
44
|
// ---------------------------------------------------------------------------
|
|
42
|
-
function ToolsMenu({ codemodeEnabled, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, availableTools, }) {
|
|
43
|
-
|
|
45
|
+
function ToolsMenu({ codemodeEnabled, onToggleCodemode, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, availableTools: _availableTools, }) {
|
|
46
|
+
const hasUsableMcpServers = mcpServers.some(server => server.isAvailable);
|
|
47
|
+
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: ToolsIcon, children: _jsxs(Text, { sx: { fontSize: 0 }, children: ["Tools", enabledMcpToolCount > 0 && ` (${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: {
|
|
48
|
+
display: 'flex',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
justifyContent: 'space-between',
|
|
51
|
+
px: 3,
|
|
52
|
+
py: 2,
|
|
53
|
+
borderBottom: '1px solid',
|
|
54
|
+
borderColor: 'border.muted',
|
|
55
|
+
gap: 2,
|
|
56
|
+
}, children: [_jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { id: "toggle-codemode", sx: { fontWeight: 'semibold', display: 'block' }, children: "Enable Codemode" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: codemodeEnabled
|
|
57
|
+
? 'MCP tools accessible via meta-tools (search_tools, execute_code).'
|
|
58
|
+
: 'Expose MCP tools directly to the model.' })] }), _jsx(ToggleSwitch, { size: "small", checked: codemodeEnabled, disabled: !onToggleCodemode, onClick: () => {
|
|
59
|
+
if (onToggleCodemode) {
|
|
60
|
+
void onToggleCodemode(!codemodeEnabled);
|
|
61
|
+
}
|
|
62
|
+
}, "aria-labelledby": "toggle-codemode" })] }) }), mcpServers.length > 0 && hasUsableMcpServers ? (mcpServers.map(server => {
|
|
44
63
|
const serverTools = enabledMcpTools.get(server.id);
|
|
45
64
|
const allToolNames = server.tools.map(t => t.name);
|
|
46
65
|
const enabledCount = serverTools?.size ?? 0;
|
|
@@ -60,6 +79,10 @@ function ToolsMenu({ codemodeEnabled, mcpServers, enabledMcpTools, enabledMcpToo
|
|
|
60
79
|
color: 'fg.muted',
|
|
61
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 => {
|
|
62
81
|
const isEnabled = serverTools?.has(tool.name) ?? false;
|
|
82
|
+
const serverApproved = approvedMcpTools.get(server.id);
|
|
83
|
+
// Tools default to NOT approved — user must explicitly
|
|
84
|
+
// approve each one (matches the Skills approval UX).
|
|
85
|
+
const isApproved = serverApproved?.has(tool.name) ?? false;
|
|
63
86
|
return (_jsxs(Box, { sx: {
|
|
64
87
|
display: 'flex',
|
|
65
88
|
alignItems: 'center',
|
|
@@ -76,20 +99,29 @@ function ToolsMenu({ codemodeEnabled, mcpServers, enabledMcpTools, enabledMcpToo
|
|
|
76
99
|
overflow: 'hidden',
|
|
77
100
|
textOverflow: 'ellipsis',
|
|
78
101
|
whiteSpace: 'nowrap',
|
|
79
|
-
}, children: tool.description }))] }),
|
|
102
|
+
}, children: tool.description }))] }), _jsxs(Box, { sx: {
|
|
103
|
+
display: 'flex',
|
|
104
|
+
alignItems: 'center',
|
|
105
|
+
gap: 3,
|
|
106
|
+
}, children: [_jsxs(Box, { sx: {
|
|
107
|
+
display: 'flex',
|
|
108
|
+
flexDirection: 'column',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
gap: '2px',
|
|
111
|
+
}, children: [_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted' }, children: "Enabled" }), _jsx(ToggleSwitch, { size: "small", checked: isEnabled, onClick: () => onToggleMcpTool(server.id, tool.name), "aria-labelledby": `toggle-tool-${server.id}-${tool.name}` })] }), _jsxs(Box, { sx: {
|
|
112
|
+
display: 'flex',
|
|
113
|
+
flexDirection: 'column',
|
|
114
|
+
alignItems: 'center',
|
|
115
|
+
gap: '2px',
|
|
116
|
+
}, children: [_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted' }, children: "Approved" }), _jsx(ToggleSwitch, { size: "small", checked: isApproved, onClick: () => onToggleMcpToolApproval(server.id, tool.name), "aria-labelledby": `toggle-tool-${server.id}-${tool.name}` })] })] })] }, `${server.id}-${tool.name}`));
|
|
80
117
|
})) : server.isAvailable ? (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No tools discovered" }) })) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "Server unavailable" }) }))] }, server.id));
|
|
81
|
-
})) : (_jsx(ActionList.Group, { title: "
|
|
82
|
-
width: 8,
|
|
83
|
-
height: 8,
|
|
84
|
-
borderRadius: '50%',
|
|
85
|
-
backgroundColor: 'success.emphasis',
|
|
86
|
-
} }) }), tool.name] }, tool.id)))) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No tools available" }) })) }))] }) }) })] }));
|
|
118
|
+
})) : (_jsx(ActionList.Group, { title: "No MCP Servers", children: _jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No MCP Servers" }) }) }))] }) }) })] }));
|
|
87
119
|
}
|
|
88
120
|
// ---------------------------------------------------------------------------
|
|
89
121
|
// SkillsMenu (private sub-component)
|
|
90
122
|
// ---------------------------------------------------------------------------
|
|
91
|
-
function SkillsMenu({ skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, }) {
|
|
92
|
-
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: BriefcaseIcon, children: _jsxs(Text, { sx: { fontSize: 0 }, children: ["Skills",
|
|
123
|
+
function SkillsMenu({ skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, }) {
|
|
124
|
+
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: BriefcaseIcon, children: _jsxs(Text, { sx: { fontSize: 0 }, children: ["Skills", skills.length > 0 && ` (${skills.length})`] }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start", width: "large", children: _jsx(Box, { sx: { maxHeight: '60vh', overflowY: 'auto' }, children: _jsx(ActionList, { children: skillsLoading ? (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading skills..." }) })) : skills.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
93
125
|
display: 'flex',
|
|
94
126
|
alignItems: 'center',
|
|
95
127
|
justifyContent: 'space-between',
|
|
@@ -110,14 +142,38 @@ function SkillsMenu({ skills, skillsLoading, enabledSkills, onToggleSkill, onTog
|
|
|
110
142
|
'&:hover': {
|
|
111
143
|
backgroundColor: 'canvas.subtle',
|
|
112
144
|
},
|
|
113
|
-
}, children: [_jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { id: `toggle-skill-${skill.id}`, sx: { fontWeight: 'semibold' }, children: skill.name }), skill.
|
|
145
|
+
}, children: [_jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Text, { id: `toggle-skill-${skill.id}`, sx: { fontWeight: 'semibold' }, children: skill.name }), skill.status && (_jsx(Text, { sx: {
|
|
146
|
+
fontSize: '10px',
|
|
147
|
+
px: 1,
|
|
148
|
+
borderRadius: 2,
|
|
149
|
+
bg: skill.status === 'loaded'
|
|
150
|
+
? 'success.subtle'
|
|
151
|
+
: skill.status === 'enabled'
|
|
152
|
+
? 'attention.subtle'
|
|
153
|
+
: 'neutral.subtle',
|
|
154
|
+
color: skill.status === 'loaded'
|
|
155
|
+
? 'success.fg'
|
|
156
|
+
: skill.status === 'enabled'
|
|
157
|
+
? 'attention.fg'
|
|
158
|
+
: 'fg.muted',
|
|
159
|
+
}, children: skill.status }))] }), skill.description && (_jsx(Text, { sx: {
|
|
114
160
|
display: 'block',
|
|
115
161
|
fontSize: 0,
|
|
116
162
|
color: 'fg.muted',
|
|
117
163
|
overflow: 'hidden',
|
|
118
164
|
textOverflow: 'ellipsis',
|
|
119
165
|
whiteSpace: 'nowrap',
|
|
120
|
-
}, children: skill.description }))] }),
|
|
166
|
+
}, children: skill.description }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsxs(Box, { sx: {
|
|
167
|
+
display: 'flex',
|
|
168
|
+
flexDirection: 'column',
|
|
169
|
+
alignItems: 'center',
|
|
170
|
+
gap: '2px',
|
|
171
|
+
}, children: [_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted' }, children: "Enabled" }), _jsx(ToggleSwitch, { size: "small", checked: enabledSkills.has(skill.id), onClick: () => onToggleSkill(skill.id), "aria-labelledby": `toggle-skill-${skill.id}` })] }), _jsxs(Box, { sx: {
|
|
172
|
+
display: 'flex',
|
|
173
|
+
flexDirection: 'column',
|
|
174
|
+
alignItems: 'center',
|
|
175
|
+
gap: '2px',
|
|
176
|
+
}, children: [_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted' }, children: "Approved" }), _jsx(ToggleSwitch, { size: "small", checked: approvedSkills.has(skill.id), onClick: () => onToggleSkillApproval(skill.id), "aria-labelledby": `toggle-skill-${skill.id}` })] })] })] }, skill.id)))] })) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No skills available" }) })) }) }) })] }));
|
|
121
177
|
}
|
|
122
178
|
// ---------------------------------------------------------------------------
|
|
123
179
|
// ModelSelector (private sub-component)
|
|
@@ -24,6 +24,8 @@ export interface InputPromptProps {
|
|
|
24
24
|
placeholder?: string;
|
|
25
25
|
/** Whether the agent is loading / streaming */
|
|
26
26
|
isLoading?: boolean;
|
|
27
|
+
/** Whether the connected kernel is currently busy */
|
|
28
|
+
isKernelBusy?: boolean;
|
|
27
29
|
/** Callback when a message is submitted */
|
|
28
30
|
onSend: (message: string) => void;
|
|
29
31
|
/** Callback when the stop button is clicked */
|
|
@@ -40,6 +42,8 @@ export interface InputPromptProps {
|
|
|
40
42
|
padding?: number;
|
|
41
43
|
/** Whether the prompt is disabled */
|
|
42
44
|
disabled?: boolean;
|
|
45
|
+
/** Whether the prompt is read-only */
|
|
46
|
+
readOnly?: boolean;
|
|
43
47
|
/** Additional sx props for the outer container */
|
|
44
48
|
sx?: Record<string, unknown>;
|
|
45
49
|
/** Controlled input value (external state) */
|
|
@@ -56,5 +60,5 @@ export interface InputPromptProps {
|
|
|
56
60
|
/**
|
|
57
61
|
* InputPrompt — Integrated chat input with header, input area, and footer.
|
|
58
62
|
*/
|
|
59
|
-
export declare function InputPrompt({ variant, placeholder, isLoading, onSend, onStop, autoFocus, focusTrigger, showBorderTop, showBackground, padding, disabled, sx, value: controlledValue, onChange: controlledOnChange, headerContent, footerContent, footerRightContent, }: InputPromptProps): import("react/jsx-runtime").JSX.Element;
|
|
63
|
+
export declare function InputPrompt({ variant, placeholder, isLoading, isKernelBusy, onSend, onStop, autoFocus, focusTrigger, showBorderTop, showBackground, padding, disabled, readOnly, sx, value: controlledValue, onChange: controlledOnChange, headerContent, footerContent, footerRightContent, }: InputPromptProps): import("react/jsx-runtime").JSX.Element;
|
|
60
64
|
export default InputPrompt;
|