@datalayer/agent-runtimes 1.3.81 → 1.3.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chat/assistant/SpeechBalloon.js +16 -1
- package/lib/chat/base/ChatBase.js +40 -4
- package/lib/chat/indicators/McpStatusIndicator.d.ts +1 -1
- package/lib/chat/indicators/McpStatusIndicator.js +13 -6
- package/lib/chat/indicators/SkillsStatusIndicator.d.ts +1 -1
- package/lib/chat/indicators/SkillsStatusIndicator.js +7 -3
- package/lib/chat/prompt/InputPrompt.d.ts +4 -1
- package/lib/chat/prompt/InputPrompt.js +2 -2
- package/lib/chat/prompt/InputPromptBase.d.ts +4 -1
- package/lib/chat/prompt/InputPromptBase.js +2 -2
- package/lib/chat/prompt/InputPromptLexical.d.ts +7 -1
- package/lib/chat/prompt/InputPromptLexical.js +5 -3
- package/lib/components/a2ui/datalayer/Form.js +19 -2
- package/lib/components/teams/index.d.ts +1 -0
- package/lib/components/teams/index.js +1 -0
- package/lib/components/teams/usePeerSandbox.d.ts +13 -0
- package/lib/components/teams/usePeerSandbox.js +59 -0
- package/lib/examples/AgentA2ATeamExample.js +7 -2
- package/lib/loop/apps/AppComposer.d.ts +31 -0
- package/lib/loop/apps/AppComposer.js +67 -0
- package/lib/loop/apps/AppRenderer.d.ts +16 -5
- package/lib/loop/apps/AppRenderer.js +49 -16
- package/lib/loop/apps/appspec.d.ts +8 -1
- package/lib/loop/apps/appspec.js +88 -23
- package/lib/loop/apps/checks.js +125 -8
- package/lib/loop/apps/composer.d.ts +37 -0
- package/lib/loop/apps/composer.js +61 -0
- package/lib/loop/apps/index.d.ts +2 -0
- package/lib/loop/apps/index.js +2 -0
- package/lib/loop/core/index.d.ts +31 -0
- package/lib/loop/core/index.js +22 -0
- package/lib/loop/embed/AppEmbed.d.ts +46 -7
- package/lib/loop/embed/AppEmbed.js +108 -26
- package/lib/loop/embed/LoopEmbed.js +2 -0
- package/lib/loop/embed/element.js +19 -5
- package/lib/loop/embed/embedConfig.d.ts +10 -1
- package/lib/loop/embed/embedConfig.js +12 -1
- package/lib/loop/embed/embedSession.d.ts +79 -0
- package/lib/loop/embed/embedSession.js +136 -0
- package/lib/loop/embed/embedTheme.d.ts +12 -9
- package/lib/loop/embed/embedTheme.js +32 -22
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/agent-capacity/index.d.ts +3 -1
- package/lib/loop/plugins/agent-capacity/index.js +2 -1
- package/lib/loop/plugins/app-page/appPageModel.d.ts +14 -5
- package/lib/loop/plugins/app-page/appPageModel.js +80 -88
- package/lib/loop/plugins/chat/ChatView.js +31 -4
- package/lib/loop/plugins/chat/index.d.ts +6 -1
- package/lib/loop/presets.d.ts +3 -1
- package/lib/loop/presets.js +2 -1
- package/lib/loop/shell/LoopWorkspace.js +3 -0
- package/lib/protocols/BrowserAgentAdapter.d.ts +18 -0
- package/lib/protocols/BrowserAgentAdapter.js +35 -2
- package/lib/runtimes/__tests__/fixtures/accounting-agent-card.json +8 -0
- package/lib/runtimes/browser/a2aPeer.d.ts +11 -0
- package/lib/runtimes/browser/a2aPeer.js +15 -1
- package/lib/runtimes/browser/protocol.d.ts +3 -0
- package/lib/runtimes/browser/protocol.js +2 -1
- package/lib/specs/agents/agents.js +6 -3
- package/lib/specs/apps.js +216 -176
- package/lib/specs/appspecSchema.js +205 -84
- package/lib/specs/cogs.js +3 -2
- package/lib/types/agentspecs.d.ts +92 -7
- package/lib/types/chat.d.ts +29 -1
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +4 -2
- package/scripts/codegen/generate_apps.py +0 -1
- package/scripts/codegen/generate_backend_tools.py +4 -12
- package/scripts/codegen/generate_cogs.py +3 -1
- package/scripts/codegen/generate_ui_plugins.py +22 -9
- package/scripts/voice/transcribe.mjs +29 -21
|
@@ -132,7 +132,22 @@ export function SpeechBalloon({ text, more = false, onOpen, above, side = 'above
|
|
|
132
132
|
borderColor: current ? 'accent.muted' : 'border.default',
|
|
133
133
|
transform: side === 'above' ? 'rotate(45deg)' : 'rotate(225deg)',
|
|
134
134
|
},
|
|
135
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [current && !approval ? (
|
|
135
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [current && !approval ? (
|
|
136
|
+
// Not a <button>: the body draws the chat's tool card, a button of
|
|
137
|
+
// its own, and a click on that card is the card's alone.
|
|
138
|
+
_jsx(Box, { role: "button", tabIndex: 0, "data-balloon-peek": "", onClick: (event) => {
|
|
139
|
+
const inner = event.target.closest('button');
|
|
140
|
+
if (inner && event.currentTarget.contains(inner)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
onOpen();
|
|
144
|
+
}, onKeyDown: (event) => {
|
|
145
|
+
if (event.target === event.currentTarget &&
|
|
146
|
+
(event.key === 'Enter' || event.key === ' ')) {
|
|
147
|
+
event.preventDefault();
|
|
148
|
+
onOpen();
|
|
149
|
+
}
|
|
150
|
+
}, sx: {
|
|
136
151
|
flex: 1,
|
|
137
152
|
minWidth: 0,
|
|
138
153
|
m: 0,
|
|
@@ -511,7 +511,7 @@ export function ChatBase(props) {
|
|
|
511
511
|
// ---------------------------------------------------------------------------
|
|
512
512
|
// ChatBaseInner — contains all actual logic
|
|
513
513
|
// ---------------------------------------------------------------------------
|
|
514
|
-
function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showContextRing = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, promptVariant, mentionableAgents: mentionableAgentsProp, showAgentsMenu = true, agents: agentsProp, selectedAgentId, onSelectAgent, disabled: disabledProp, disableReason: disableReasonProp, 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, disabledViewModes,
|
|
514
|
+
function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showContextRing = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, promptVariant, mentionableAgents: mentionableAgentsProp, promptCommands, showAgentsMenu = true, agents: agentsProp, selectedAgentId, onSelectAgent, disabled: disabledProp, disableReason: disableReasonProp, 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, disabledViewModes,
|
|
515
515
|
// Mode selection
|
|
516
516
|
useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, onSendReady, onLoadingChange, onContextSnapshot, enableStreaming = false,
|
|
517
517
|
// Extended props
|
|
@@ -521,7 +521,7 @@ onToolCallStart, onToolCallComplete, inspector: inspectorGiven,
|
|
|
521
521
|
// Identity/Authorization props
|
|
522
522
|
onAuthorizationRequired: _onAuthorizationRequired, connectedIdentities,
|
|
523
523
|
// Conversation persistence
|
|
524
|
-
runtimeId, historyEndpoint, historyAuthToken: _historyAuthToken,
|
|
524
|
+
runtimeId, thread, historyEndpoint, historyAuthToken: _historyAuthToken,
|
|
525
525
|
// Pending prompt
|
|
526
526
|
pendingPrompt, contextSnapshot: externalContextSnapshot, mcpStatusData, sandboxStatusData,
|
|
527
527
|
// Tool approval banner
|
|
@@ -1574,7 +1574,20 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1574
1574
|
const suppressAssistantTextForToolOnlyRef = useRef(false);
|
|
1575
1575
|
const hideMessagesAfterToolUIRef = useRef(hideMessagesAfterToolUI);
|
|
1576
1576
|
hideMessagesAfterToolUIRef.current = hideMessagesAfterToolUI;
|
|
1577
|
-
const threadIdRef = useRef(generateMessageId());
|
|
1577
|
+
const threadIdRef = useRef(thread?.id || generateMessageId());
|
|
1578
|
+
/*
|
|
1579
|
+
* The thread a host gave, kept as it was given at mount (LOOP D-13), and
|
|
1580
|
+
* told when a message is first sent on a thread: the host keeps it.
|
|
1581
|
+
*/
|
|
1582
|
+
const threadGivenRef = useRef(thread);
|
|
1583
|
+
const threadStartedRef = useRef(thread?.messages.length ? thread.id : null);
|
|
1584
|
+
const noteThreadStarted = useCallback(() => {
|
|
1585
|
+
const id = threadIdRef.current;
|
|
1586
|
+
if (threadStartedRef.current !== id) {
|
|
1587
|
+
threadStartedRef.current = id;
|
|
1588
|
+
threadGivenRef.current?.onStarted?.(id);
|
|
1589
|
+
}
|
|
1590
|
+
}, []);
|
|
1578
1591
|
const messagesContainerRef = useRef(null);
|
|
1579
1592
|
const messagesEndRef = useRef(null);
|
|
1580
1593
|
const inputRef = useRef(null);
|
|
@@ -2132,6 +2145,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2132
2145
|
// Set when the next load must come from a fresh snapshot, not the one in
|
|
2133
2146
|
// the store: what the store holds is the transcript before the change.
|
|
2134
2147
|
const freshSnapshotRef = useRef(false);
|
|
2148
|
+
// The given thread drawn, by its id: once.
|
|
2149
|
+
const threadSeededRef = useRef(null);
|
|
2135
2150
|
useEffect(() => {
|
|
2136
2151
|
if (historyScopeId !== prevHistoryScopeRef.current) {
|
|
2137
2152
|
if (historyScopeId) {
|
|
@@ -2145,6 +2160,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2145
2160
|
}
|
|
2146
2161
|
if (!historyScopeId)
|
|
2147
2162
|
return;
|
|
2163
|
+
/*
|
|
2164
|
+
* A thread the host gave (LOOP D-13): its session's conversation, drawn
|
|
2165
|
+
* once, and never replaced by the runtime's snapshot, which is its
|
|
2166
|
+
* agent's — every session's — not this one's.
|
|
2167
|
+
*/
|
|
2168
|
+
const given = threadGivenRef.current;
|
|
2169
|
+
if (given) {
|
|
2170
|
+
if (threadSeededRef.current !== given.id) {
|
|
2171
|
+
threadSeededRef.current = given.id;
|
|
2172
|
+
useConversationStore
|
|
2173
|
+
.getState()
|
|
2174
|
+
.setMessages(historyScopeId, given.messages);
|
|
2175
|
+
setDisplayItems(convertHistoryToDisplayItems(given.messages));
|
|
2176
|
+
useConversationStore.getState().markFetched(historyScopeId);
|
|
2177
|
+
setHistoryLoaded(true);
|
|
2178
|
+
}
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2148
2181
|
if (historyVersion !== historyVersionRef.current) {
|
|
2149
2182
|
historyVersionRef.current = historyVersion;
|
|
2150
2183
|
if (historyVersion > 0) {
|
|
@@ -3011,6 +3044,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3011
3044
|
console.warn('[ChatBase] frontendTools count:', frontendTools?.length ?? 0, 'toolsForRequest:', toolsForRequest.map(t => t.name));
|
|
3012
3045
|
const enabledMcpToolNames = getEnabledMcpToolNames();
|
|
3013
3046
|
const enabledSkillIds = getEnabledSkillIds();
|
|
3047
|
+
// The thread is opened by this run: its host keeps it (D-13).
|
|
3048
|
+
noteThreadStarted();
|
|
3014
3049
|
await adapterRef.current.sendMessage(userMessage, {
|
|
3015
3050
|
threadId: threadIdRef.current,
|
|
3016
3051
|
messages: allMessages,
|
|
@@ -3058,6 +3093,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3058
3093
|
enableStreaming,
|
|
3059
3094
|
getEnabledMcpToolNames,
|
|
3060
3095
|
getEnabledSkillIds,
|
|
3096
|
+
noteThreadStarted,
|
|
3061
3097
|
]);
|
|
3062
3098
|
// Send pending prompt once history loaded and adapter/handler available
|
|
3063
3099
|
useEffect(() => {
|
|
@@ -3627,7 +3663,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3627
3663
|
somebody typing, and what they would have typed is the message the
|
|
3628
3664
|
chip sends, not the label on it.
|
|
3629
3665
|
*/
|
|
3630
|
-
typingSuggestions: resolvedSuggestions?.map(item => item.message || item.title), autoFocus: autoFocus, focusTrigger: focusTrigger, padding: padding, onSend: () => handleSend(), onStop: handleStop, disableInputPrompt: disableInputPrompt || disabled || !!overlay || launching, promptVariant: promptVariant, mentionableAgents: mentionableAgents,
|
|
3666
|
+
typingSuggestions: resolvedSuggestions?.map(item => item.message || item.title), autoFocus: autoFocus, focusTrigger: focusTrigger, padding: padding, onSend: () => handleSend(), onStop: handleStop, disableInputPrompt: disableInputPrompt || disabled || !!overlay || launching, promptVariant: promptVariant, mentionableAgents: mentionableAgents, promptCommands: promptCommands,
|
|
3631
3667
|
// The runtime's memory of what was sent to this agent, for the arrow
|
|
3632
3668
|
// keys — part of the same initial state as the models and tools.
|
|
3633
3669
|
promptHistory: configQuery.data?.promptHistory, showTokenUsage: showTokenUsage, showContextRing: showContextRing, agentUsage: agentUsage, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, isA2AProtocol: isA2AProtocol, showAgentsMenu: showAgentsMenu, agents: footerAgents, selectedAgentId: selectedAgentId ?? footerAgents[0]?.id, onSelectAgent: onSelectAgent, hasConfigData: !!configQuery.data, hasSkillsData: !!skillsQuery.data,
|
|
@@ -8,5 +8,5 @@ export interface McpStatusIndicatorProps {
|
|
|
8
8
|
/** @deprecated — Only used when `data` is not provided. */
|
|
9
9
|
authToken?: string;
|
|
10
10
|
}
|
|
11
|
-
export declare function McpStatusIndicator({ data: wsData, apiBase, authToken, }: McpStatusIndicatorProps): import("react").JSX.Element;
|
|
11
|
+
export declare function McpStatusIndicator({ data: wsData, apiBase, authToken, }: McpStatusIndicatorProps): import("react").JSX.Element | null;
|
|
12
12
|
export default McpStatusIndicator;
|
|
@@ -10,7 +10,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
10
10
|
*
|
|
11
11
|
* Aggregate logic
|
|
12
12
|
* ───────────────
|
|
13
|
-
* - no servers array / empty → "none" (
|
|
13
|
+
* - no servers array / empty → "none" (not drawn: nothing to report)
|
|
14
14
|
* - any server "starting" → "starting" (amber, pulsing)
|
|
15
15
|
* - any server "failed" → "failed" (red)
|
|
16
16
|
* - all servers "started" → "started" (green)
|
|
@@ -35,8 +35,6 @@ function deriveAggregate(servers) {
|
|
|
35
35
|
return 'not_started';
|
|
36
36
|
}
|
|
37
37
|
function buildTooltipText(aggregate, servers) {
|
|
38
|
-
if (aggregate === 'none')
|
|
39
|
-
return 'No MCP Server defined';
|
|
40
38
|
const lines = [MCP_STATUS_LABELS[aggregate]];
|
|
41
39
|
for (const s of servers) {
|
|
42
40
|
let detail = `• ${s.id}: ${s.status}`;
|
|
@@ -75,9 +73,17 @@ export function McpStatusIndicator({ data: wsData, apiBase, authToken, }) {
|
|
|
75
73
|
const servers = effectiveData?.servers ?? [];
|
|
76
74
|
const aggregate = useMemo(() => deriveAggregate(servers), [servers]);
|
|
77
75
|
const tooltipText = useMemo(() => buildTooltipText(aggregate, servers), [aggregate, servers]);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
/*
|
|
77
|
+
* Nothing drawn when the agent has no MCP server (LOOP H-21): a control
|
|
78
|
+
* that only says so was read out as *No MCP Server defined* in every
|
|
79
|
+
* composer, an in-page agent's and an application's alike. When there are
|
|
80
|
+
* some, it is named by their state, and the tooltip — its description —
|
|
81
|
+
* lists them.
|
|
82
|
+
*/
|
|
83
|
+
if (aggregate === 'none') {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return (_jsx(Tooltip, { text: tooltipText, direction: "n", children: _jsx("button", { type: "button", "aria-label": MCP_STATUS_LABELS[aggregate], style: {
|
|
81
87
|
display: 'inline-flex',
|
|
82
88
|
alignItems: 'center',
|
|
83
89
|
justifyContent: 'center',
|
|
@@ -98,6 +104,7 @@ export function McpStatusIndicator({ data: wsData, apiBase, authToken, }) {
|
|
|
98
104
|
...(aggregate === 'starting' && {
|
|
99
105
|
animation: 'mcp-pulse 1.5s ease-in-out infinite',
|
|
100
106
|
}),
|
|
107
|
+
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
|
|
101
108
|
} }) }) }));
|
|
102
109
|
}
|
|
103
110
|
export default McpStatusIndicator;
|
|
@@ -3,5 +3,5 @@ export interface SkillsStatusIndicatorProps {
|
|
|
3
3
|
enabledCount: number;
|
|
4
4
|
loading?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export declare function SkillsStatusIndicator({ skillsCount, enabledCount, loading, }: SkillsStatusIndicatorProps): import("react").JSX.Element;
|
|
6
|
+
export declare function SkillsStatusIndicator({ skillsCount, enabledCount, loading, }: SkillsStatusIndicatorProps): import("react").JSX.Element | null;
|
|
7
7
|
export default SkillsStatusIndicator;
|
|
@@ -7,7 +7,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
7
7
|
* SkillsStatusIndicator — Round status dot representing skill state.
|
|
8
8
|
*
|
|
9
9
|
* Aggregate logic:
|
|
10
|
-
* - no skills configured -> none (
|
|
10
|
+
* - no skills configured -> none (not drawn)
|
|
11
11
|
* - skills loading -> loading (amber, pulsing)
|
|
12
12
|
* - some enabled -> active (green)
|
|
13
13
|
* - none enabled -> inactive (gray)
|
|
@@ -48,8 +48,6 @@ function deriveAggregate(skillsCount, enabledCount, loading) {
|
|
|
48
48
|
return 'inactive';
|
|
49
49
|
}
|
|
50
50
|
function buildTooltip(aggregate, skillsCount, enabledCount) {
|
|
51
|
-
if (aggregate === 'none')
|
|
52
|
-
return 'No Skills defined';
|
|
53
51
|
if (aggregate === 'loading') {
|
|
54
52
|
return `Skills loading (${enabledCount}/${skillsCount} enabled)`;
|
|
55
53
|
}
|
|
@@ -62,6 +60,11 @@ export function SkillsStatusIndicator({ skillsCount, enabledCount, loading = fal
|
|
|
62
60
|
useInjectKeyframes();
|
|
63
61
|
const aggregate = useMemo(() => deriveAggregate(skillsCount, enabledCount, loading), [skillsCount, enabledCount, loading]);
|
|
64
62
|
const tooltipText = useMemo(() => buildTooltip(aggregate, skillsCount, enabledCount), [aggregate, skillsCount, enabledCount]);
|
|
63
|
+
// Nothing drawn when the agent has no skill (LOOP H-21): a control that
|
|
64
|
+
// only says so was read out as *No Skills defined* in every composer.
|
|
65
|
+
if (aggregate === 'none') {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
65
68
|
return (_jsx(Tooltip, { text: tooltipText, direction: "n", children: _jsx("button", { type: "button", "aria-label": tooltipText, style: {
|
|
66
69
|
display: 'inline-flex',
|
|
67
70
|
alignItems: 'center',
|
|
@@ -83,6 +86,7 @@ export function SkillsStatusIndicator({ skillsCount, enabledCount, loading = fal
|
|
|
83
86
|
...(aggregate === 'loading' && {
|
|
84
87
|
animation: 'skills-pulse 1.5s ease-in-out infinite',
|
|
85
88
|
}),
|
|
89
|
+
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
|
|
86
90
|
} }) }) }));
|
|
87
91
|
}
|
|
88
92
|
export default SkillsStatusIndicator;
|
|
@@ -14,6 +14,7 @@ import type { BuiltinTool, ContextSnapshotData, MCPServerConfig, McpToolsetsStat
|
|
|
14
14
|
import { type InputPromptVariant } from './InputPromptBase';
|
|
15
15
|
import type { PromptSuggestion } from './menus/SuggestionsMenu';
|
|
16
16
|
import type { MentionableAgent } from './plugins/AgentMentionPlugin';
|
|
17
|
+
import type { PromptCommand } from './plugins/CommandPlugin';
|
|
17
18
|
/** One agent the footer may offer. */
|
|
18
19
|
import type { FooterAgent } from '../../types/chat';
|
|
19
20
|
import type { Decisions } from '../base/modelChoice';
|
|
@@ -111,6 +112,8 @@ export interface InputPromptProps {
|
|
|
111
112
|
promptVariant?: InputPromptVariant;
|
|
112
113
|
/** Agents the prompt may address by typing `@`. Lexical only. */
|
|
113
114
|
mentionableAgents?: MentionableAgent[];
|
|
115
|
+
/** Commands listed while `/` is typed, before the prompt's own (LOOP P-19). Lexical only. */
|
|
116
|
+
promptCommands?: PromptCommand[];
|
|
114
117
|
/**
|
|
115
118
|
* What was sent to this agent before this page loaded, oldest first.
|
|
116
119
|
*
|
|
@@ -223,4 +226,4 @@ export interface InputPromptProps {
|
|
|
223
226
|
/** Pre-fetched MCP status from WebSocket — bypasses REST polling */
|
|
224
227
|
mcpStatusData?: McpToolsetsStatusResponse | null;
|
|
225
228
|
}
|
|
226
|
-
export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, availableFrontendTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
|
|
229
|
+
export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, availableFrontendTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
|
|
@@ -29,7 +29,7 @@ const EMPTY_ID_SET = new Set();
|
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Component
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
|
-
export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], decisions, selectedModel = '', onModelSelect = () => { }, availableTools = [], availableFrontendTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
|
|
32
|
+
export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], decisions, selectedModel = '', onModelSelect = () => { }, availableTools = [], availableFrontendTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
|
|
33
33
|
const isKernelBusy = kernelStatus === 'busy';
|
|
34
34
|
/*
|
|
35
35
|
* Each menu is offered when it is switched on *and* has something behind it.
|
|
@@ -105,7 +105,7 @@ export function InputPrompt({ input, setInput, isLoading, kernelStatus, connecti
|
|
|
105
105
|
* from the start; this shows it.
|
|
106
106
|
*/
|
|
107
107
|
const hasContext = Boolean(agentUsage && !agentUsage.error);
|
|
108
|
-
const body = (_jsxs(Box, { children: [leadingPanel, _jsx(InputPromptBase, { variant: promptVariant, mentionableAgents: mentionableAgents, promptHistory: promptHistory,
|
|
108
|
+
const body = (_jsxs(Box, { children: [leadingPanel, _jsx(InputPromptBase, { variant: promptVariant, mentionableAgents: mentionableAgents, promptCommands: promptCommands, promptHistory: promptHistory,
|
|
109
109
|
/*
|
|
110
110
|
Whatever the host puts inside the prompt, and the agent chip beside
|
|
111
111
|
it. Both, rather than either: a host contributing its own controls
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import type { ReactNode } from 'react';
|
|
18
18
|
import type { PromptStack } from './stack';
|
|
19
19
|
import type { MentionableAgent } from './plugins/AgentMentionPlugin';
|
|
20
|
+
import type { PromptCommand } from './plugins/CommandPlugin';
|
|
20
21
|
/** Input variant type. */
|
|
21
22
|
export type InputPromptVariant = 'text' | 'lexical';
|
|
22
23
|
/**
|
|
@@ -75,6 +76,8 @@ export interface InputPromptBaseProps {
|
|
|
75
76
|
* suggestion a person cannot see is worse than none.
|
|
76
77
|
*/
|
|
77
78
|
mentionableAgents?: MentionableAgent[];
|
|
79
|
+
/** Commands listed while `/` is typed, before the prompt's own (LOOP P-19). Lexical only. */
|
|
80
|
+
promptCommands?: PromptCommand[];
|
|
78
81
|
/**
|
|
79
82
|
* What was sent to this agent before this composer mounted, oldest first.
|
|
80
83
|
*
|
|
@@ -108,5 +111,5 @@ export interface InputPromptBaseProps {
|
|
|
108
111
|
/**
|
|
109
112
|
* InputPromptBase — the editor, its header and its footer with header, input area, and footer.
|
|
110
113
|
*/
|
|
111
|
-
export declare function InputPromptBase({ variant, placeholder, typingSuggestions, isLoading, isKernelBusy, onSend, onStop, autoFocus, focusTrigger, showBorderTop, showBackground, padding, disabled, readOnly, mentionableAgents, promptHistory, sx, value: controlledValue, onChange: controlledOnChange, headerContent, headerStacks, footerContent, footerStacks, footerRightContent, }: InputPromptBaseProps): import("react").JSX.Element;
|
|
114
|
+
export declare function InputPromptBase({ variant, placeholder, typingSuggestions, isLoading, isKernelBusy, onSend, onStop, autoFocus, focusTrigger, showBorderTop, showBackground, padding, disabled, readOnly, mentionableAgents, promptCommands, promptHistory, sx, value: controlledValue, onChange: controlledOnChange, headerContent, headerStacks, footerContent, footerStacks, footerRightContent, }: InputPromptBaseProps): import("react").JSX.Element;
|
|
112
115
|
export default InputPromptBase;
|
|
@@ -10,7 +10,7 @@ import { usePromptHistory } from './promptHistory';
|
|
|
10
10
|
/**
|
|
11
11
|
* InputPromptBase — the editor, its header and its footer with header, input area, and footer.
|
|
12
12
|
*/
|
|
13
|
-
export function InputPromptBase({ variant = 'lexical', placeholder = 'Ask anything…', typingSuggestions, isLoading = false, isKernelBusy = false, onSend, onStop, autoFocus = false, focusTrigger, showBorderTop = true, showBackground = true, padding = 3, disabled = false, readOnly = false, mentionableAgents, promptHistory, sx, value: controlledValue, onChange: controlledOnChange, headerContent, headerStacks, footerContent, footerStacks, footerRightContent, }) {
|
|
13
|
+
export function InputPromptBase({ variant = 'lexical', placeholder = 'Ask anything…', typingSuggestions, isLoading = false, isKernelBusy = false, onSend, onStop, autoFocus = false, focusTrigger, showBorderTop = true, showBackground = true, padding = 3, disabled = false, readOnly = false, mentionableAgents, promptCommands, promptHistory, sx, value: controlledValue, onChange: controlledOnChange, headerContent, headerStacks, footerContent, footerStacks, footerRightContent, }) {
|
|
14
14
|
// ---- Controlled / uncontrolled state -----------------------------------
|
|
15
15
|
const [internalInput, setInternalInput] = useState('');
|
|
16
16
|
const input = controlledValue !== undefined ? controlledValue : internalInput;
|
|
@@ -221,6 +221,6 @@ export function InputPromptBase({ variant = 'lexical', placeholder = 'Ask anythi
|
|
|
221
221
|
borderColor: 'accent.fg',
|
|
222
222
|
boxShadow: (t) => `0 0 0 1px ${t?.colors?.accent?.fg ?? '#16A085'}`,
|
|
223
223
|
},
|
|
224
|
-
}, children: [_jsx(InPromptHeader, { stacks: headerStacks, children: headerContent }), variant === 'lexical' ? (_jsx(InputPromptLexical, { value: input, onChange: handleChange, placeholder: animatedPlaceholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, onHistory: navigateHistory, autoFocus: autoFocus, focusSignal: lexicalFocusSignal, mentionableAgents: mentionableAgents })) : (_jsx(InputPromptText, { value: input, onChange: handleChange, placeholder: animatedPlaceholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, onHistory: navigateHistory, inputRef: inputRef })), _jsx(InPromptFooter, { stacks: footerStacks, isLoading: isLoading, isKernelBusy: isKernelBusy, sendDisabled: !input.trim() || disabled || readOnly, onSend: handleSend, onStop: handleStop, rightContent: footerRightContent, children: footerContent })] }) }) }));
|
|
224
|
+
}, children: [_jsx(InPromptHeader, { stacks: headerStacks, children: headerContent }), variant === 'lexical' ? (_jsx(InputPromptLexical, { value: input, onChange: handleChange, placeholder: animatedPlaceholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, onHistory: navigateHistory, autoFocus: autoFocus, focusSignal: lexicalFocusSignal, mentionableAgents: mentionableAgents, promptCommands: promptCommands })) : (_jsx(InputPromptText, { value: input, onChange: handleChange, placeholder: animatedPlaceholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, onHistory: navigateHistory, inputRef: inputRef })), _jsx(InPromptFooter, { stacks: footerStacks, isLoading: isLoading, isKernelBusy: isKernelBusy, sendDisabled: !input.trim() || disabled || readOnly, onSend: handleSend, onStop: handleStop, rightContent: footerRightContent, children: footerContent })] }) }) }));
|
|
225
225
|
}
|
|
226
226
|
export default InputPromptBase;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type MentionableAgent } from './plugins/AgentMentionPlugin';
|
|
2
|
+
import { type PromptCommand } from './plugins/CommandPlugin';
|
|
2
3
|
import type { HistoryDirection } from './promptHistory';
|
|
3
4
|
export interface InputPromptLexicalProps {
|
|
4
5
|
/** Current input value */
|
|
@@ -30,6 +31,11 @@ export interface InputPromptLexicalProps {
|
|
|
30
31
|
* choose between, and a menu on every `@` would be in the way.
|
|
31
32
|
*/
|
|
32
33
|
mentionableAgents?: MentionableAgent[];
|
|
34
|
+
/**
|
|
35
|
+
* Commands listed while `/` is typed, before the prompt's own: an
|
|
36
|
+
* application's (LOOP P-19).
|
|
37
|
+
*/
|
|
38
|
+
promptCommands?: PromptCommand[];
|
|
33
39
|
}
|
|
34
|
-
export declare function InputPromptLexical({ value, onChange, placeholder, disabled, readOnly, onSubmit, onHistory, autoFocus, focusSignal, mentionableAgents, }: InputPromptLexicalProps): import("react").JSX.Element;
|
|
40
|
+
export declare function InputPromptLexical({ value, onChange, placeholder, disabled, readOnly, onSubmit, onHistory, autoFocus, focusSignal, mentionableAgents, promptCommands, }: InputPromptLexicalProps): import("react").JSX.Element;
|
|
35
41
|
export default InputPromptLexical;
|
|
@@ -28,7 +28,7 @@ import { PlainTextExtension } from '@lexical/plain-text';
|
|
|
28
28
|
import { MentionNode } from './plugins/MentionNode';
|
|
29
29
|
import { Box } from '@datalayer/primer-addons';
|
|
30
30
|
import { AgentMentionPlugin, } from './plugins/AgentMentionPlugin';
|
|
31
|
-
import { CommandPlugin, PROMPT_COMMANDS } from './plugins/CommandPlugin';
|
|
31
|
+
import { CommandPlugin, PROMPT_COMMANDS, } from './plugins/CommandPlugin';
|
|
32
32
|
// ---- Lexical extension (plain-text only) ---------------------------------
|
|
33
33
|
// Module scope on purpose: the composer rebuilds the editor whenever this
|
|
34
34
|
// reference changes.
|
|
@@ -265,7 +265,7 @@ function ReadOnlyPlugin({ readOnly }) {
|
|
|
265
265
|
}, [editor, readOnly]);
|
|
266
266
|
return null;
|
|
267
267
|
}
|
|
268
|
-
export function InputPromptLexical({ value, onChange, placeholder = 'Ask anything…', disabled = false, readOnly = false, onSubmit, onHistory, autoFocus = false, focusSignal, mentionableAgents, }) {
|
|
268
|
+
export function InputPromptLexical({ value, onChange, placeholder = 'Ask anything…', disabled = false, readOnly = false, onSubmit, onHistory, autoFocus = false, focusSignal, mentionableAgents, promptCommands, }) {
|
|
269
269
|
return (_jsx(Box, { sx: {
|
|
270
270
|
/*
|
|
271
271
|
The placeholder is positioned against this box.
|
|
@@ -321,6 +321,8 @@ export function InputPromptLexical({ value, onChange, placeholder = 'Ask anythin
|
|
|
321
321
|
fontSize: 14,
|
|
322
322
|
lineHeight: '1.5',
|
|
323
323
|
padding: '2px 0',
|
|
324
|
-
} }), _jsx(SyncPlugin, { value: value, onChange: onChange }), _jsx(ReadOnlyPlugin, { readOnly: readOnly || disabled }), _jsx(EnterSubmitPlugin, { onSubmit: onSubmit, disabled: disabled, readOnly: readOnly }), _jsx(AutoFocusPlugin, { autoFocus: autoFocus, focusSignal: focusSignal }), _jsx(CommandPlugin, { commands:
|
|
324
|
+
} }), _jsx(SyncPlugin, { value: value, onChange: onChange }), _jsx(ReadOnlyPlugin, { readOnly: readOnly || disabled }), _jsx(EnterSubmitPlugin, { onSubmit: onSubmit, disabled: disabled, readOnly: readOnly }), _jsx(AutoFocusPlugin, { autoFocus: autoFocus, focusSignal: focusSignal }), _jsx(CommandPlugin, { commands: promptCommands?.length
|
|
325
|
+
? [...promptCommands, ...PROMPT_COMMANDS]
|
|
326
|
+
: PROMPT_COMMANDS }), mentionableAgents?.length ? (_jsx(AgentMentionPlugin, { agents: mentionableAgents })) : null, _jsx(HistoryPlugin, { onHistory: onHistory, disabled: disabled, readOnly: readOnly })] }) }));
|
|
325
327
|
}
|
|
326
328
|
export default InputPromptLexical;
|
|
@@ -12,6 +12,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
12
12
|
* its action is dispatched, so the action's context reads them. A form the
|
|
13
13
|
* schema refuses says why beside each field and sends nothing.
|
|
14
14
|
*
|
|
15
|
+
* A form without an action is a set of settings (C-16) — an application's
|
|
16
|
+
* `interface.settings` drawn beside its conversation: no button, its values
|
|
17
|
+
* written where `values` points as they are filled, for the next run to take;
|
|
18
|
+
* the runtime checks them against the same schema.
|
|
19
|
+
*
|
|
15
20
|
* @module components/a2ui/datalayer/Form
|
|
16
21
|
*/
|
|
17
22
|
import { useEffect, useMemo, useState } from 'react';
|
|
@@ -34,11 +39,23 @@ export function FormView({ props }) {
|
|
|
34
39
|
useEffect(() => {
|
|
35
40
|
setLocal(JSON.parse(shownKey));
|
|
36
41
|
}, [shownKey]);
|
|
37
|
-
|
|
42
|
+
// Without an action, nothing is sent: no button, the values written as filled.
|
|
43
|
+
const live = action === undefined;
|
|
44
|
+
const uiSchema = useMemo(() => ({
|
|
45
|
+
'ui:submitButtonOptions': live
|
|
46
|
+
? { norender: true }
|
|
47
|
+
: { submitText: submitLabel },
|
|
48
|
+
}), [live, submitLabel]);
|
|
38
49
|
const problem = schema.type !== undefined && schema.type !== 'object'
|
|
39
50
|
? 'Its fields are not an object schema: a form asks for several named values.'
|
|
40
51
|
: null;
|
|
41
|
-
return (_jsx(BlockFrame, { title: title, label: "Form", weight: props.weight, testId: "a2ui-form", children: problem ? (_jsx(Problem, { children: problem })) : (_jsx(SchemaForm, { schema: schema, uiSchema: uiSchema, formData: values, validator: validator, liveValidate: touched, onBlur: () => setTouched(true), onError: () => setTouched(true), showErrorList: false, onChange: event =>
|
|
52
|
+
return (_jsx(BlockFrame, { title: title, label: "Form", weight: props.weight, testId: "a2ui-form", children: problem ? (_jsx(Problem, { children: problem })) : (_jsx(SchemaForm, { schema: schema, uiSchema: uiSchema, formData: values, validator: validator, liveValidate: touched, onBlur: () => setTouched(true), onError: () => setTouched(true), showErrorList: false, onChange: event => {
|
|
53
|
+
const filled = (event.formData ?? {});
|
|
54
|
+
setLocal(filled);
|
|
55
|
+
if (live) {
|
|
56
|
+
setValues(filled);
|
|
57
|
+
}
|
|
58
|
+
}, onSubmit: event => {
|
|
42
59
|
setValues((event.formData ?? {}));
|
|
43
60
|
action?.();
|
|
44
61
|
} })) }));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AssistantSandbox } from '../../chat/assistant/assistantDetails';
|
|
2
|
+
/**
|
|
3
|
+
* The runtime an A2A address is served from: its base, before
|
|
4
|
+
* `/api/v1/a2a/agents/<id>`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runtimeBaseOfA2AUrl(url: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* The sandbox of the runtime a peer answers from, read again each time
|
|
9
|
+
* `refresh` changes (when a turn ends, it may have started one). Until the
|
|
10
|
+
* runtime says, or when it does not answer, the peer's sandbox is offered
|
|
11
|
+
* as not running, with the runtime it would be on.
|
|
12
|
+
*/
|
|
13
|
+
export declare function usePeerSandbox(a2aUrl: string, refresh?: unknown): AssistantSandbox;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A peer's code sandbox, for its *Code Sandbox Details…*: the codemode
|
|
7
|
+
* sandbox of the runtime it is served from, as that runtime reports it.
|
|
8
|
+
*
|
|
9
|
+
* @module components/teams/usePeerSandbox
|
|
10
|
+
*/
|
|
11
|
+
import { useEffect, useState } from 'react';
|
|
12
|
+
import { assistantSandboxOf, } from '../../chat/assistant/assistantDetails';
|
|
13
|
+
/**
|
|
14
|
+
* The runtime an A2A address is served from: its base, before
|
|
15
|
+
* `/api/v1/a2a/agents/<id>`.
|
|
16
|
+
*/
|
|
17
|
+
export function runtimeBaseOfA2AUrl(url) {
|
|
18
|
+
return url
|
|
19
|
+
.replace(/\/api\/v1\/a2a\/agents\/[^/]+\/?$/, '')
|
|
20
|
+
.replace(/\/+$/, '');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The sandbox of the runtime a peer answers from, read again each time
|
|
24
|
+
* `refresh` changes (when a turn ends, it may have started one). Until the
|
|
25
|
+
* runtime says, or when it does not answer, the peer's sandbox is offered
|
|
26
|
+
* as not running, with the runtime it would be on.
|
|
27
|
+
*/
|
|
28
|
+
export function usePeerSandbox(a2aUrl, refresh) {
|
|
29
|
+
const serverUrl = runtimeBaseOfA2AUrl(a2aUrl);
|
|
30
|
+
const [sandbox, setSandbox] = useState({
|
|
31
|
+
kind: 'runtime',
|
|
32
|
+
status: 'not running',
|
|
33
|
+
serverUrl,
|
|
34
|
+
});
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
let current = true;
|
|
37
|
+
fetch(`${serverUrl}/api/v1/configure/codemode/status`)
|
|
38
|
+
.then(response => (response.ok ? response.json() : null))
|
|
39
|
+
.then((status) => {
|
|
40
|
+
if (!current) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setSandbox(assistantSandboxOf(status?.sandbox, { serverUrl }) ?? {
|
|
44
|
+
kind: 'runtime',
|
|
45
|
+
status: 'not running',
|
|
46
|
+
serverUrl,
|
|
47
|
+
});
|
|
48
|
+
})
|
|
49
|
+
.catch(() => {
|
|
50
|
+
if (current) {
|
|
51
|
+
setSandbox({ kind: 'runtime', status: 'unreachable', serverUrl });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
current = false;
|
|
56
|
+
};
|
|
57
|
+
}, [serverUrl, refresh]);
|
|
58
|
+
return sandbox;
|
|
59
|
+
}
|
|
@@ -10,7 +10,7 @@ import { useExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
|
|
|
10
10
|
import { useBrowserInference } from '../hooks/useBrowserInference';
|
|
11
11
|
import { readJwtClaims, tokenLifetimeMs, useAnonymousSessionStore, } from '../runtimes/browser/anonymousToken';
|
|
12
12
|
import { connectA2APeer } from '../runtimes/browser/a2aPeer';
|
|
13
|
-
import { A2ATeamGraph, NOTEBOOK_AND_WORDS, teamConnectionsOf, teamToolClassifier, useA2ATeam, } from '../components/teams';
|
|
13
|
+
import { A2ATeamGraph, NOTEBOOK_AND_WORDS, teamConnectionsOf, teamToolClassifier, useA2ATeam, usePeerSandbox, } from '../components/teams';
|
|
14
14
|
import { ACCOUNTING_APP_0_0_1, SALES_APP_0_0_1 } from '../specs/apps';
|
|
15
15
|
import { AgentInspector, classifyToolCall, inspectA2AFetch, useAgentInspector, } from '../components/inspector';
|
|
16
16
|
import { SALES_AND_ACCOUNTING_TEAM_SPEC_0_0_1 } from '../specs/teams/teams';
|
|
@@ -89,6 +89,9 @@ function AgentA2ATeam() {
|
|
|
89
89
|
accept: NOTEBOOK_AND_WORDS,
|
|
90
90
|
inspector,
|
|
91
91
|
});
|
|
92
|
+
// Accounting works in codemode: its sandbox, on the runtime it answers
|
|
93
|
+
// from, read again when a turn ends.
|
|
94
|
+
const accountingSandbox = usePeerSandbox(accountingUrl, team.busy);
|
|
92
95
|
// Sales' starters, in its balloon while it waits for a question.
|
|
93
96
|
const suggestions = useMemo(() => (SALES.interface.starters ?? []).map(starter => ({
|
|
94
97
|
label: starter.label,
|
|
@@ -142,7 +145,8 @@ function AgentA2ATeam() {
|
|
|
142
145
|
}, peer: {
|
|
143
146
|
id: ACCOUNTING.id,
|
|
144
147
|
name: ACCOUNTING.name,
|
|
145
|
-
|
|
148
|
+
// Its face as its card says it, once it is reached.
|
|
149
|
+
emoji: peer?.face?.emoji ?? ACCOUNTING.emoji,
|
|
146
150
|
character: ACCOUNTING.interface.assistant ?? 'wizard',
|
|
147
151
|
where: accountingWhere,
|
|
148
152
|
persona: team.peerPersona,
|
|
@@ -150,6 +154,7 @@ function AgentA2ATeam() {
|
|
|
150
154
|
history: team.peerHistory,
|
|
151
155
|
connections: ACCOUNTING_CONNECTIONS,
|
|
152
156
|
inspector,
|
|
157
|
+
sandbox: accountingSandbox,
|
|
153
158
|
about: {
|
|
154
159
|
name: ACCOUNTING.name,
|
|
155
160
|
spec: `${ACCOUNTING.id}:${ACCOUNTING.version}`,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An application's commands and modes in the composer (LOOP P-19).
|
|
3
|
+
*
|
|
4
|
+
* - Each of its **commands** is a workspace command (`LoopCommand`), listed
|
|
5
|
+
* in the composer's `/` menu (`composer`): picking it writes `/<name> `,
|
|
6
|
+
* and sending runs it — its prompt goes to the agent, the words typed
|
|
7
|
+
* after it in place of `{input}`.
|
|
8
|
+
* - Its **modes** are switches beside the composer (`LoopSlots.promptAction`),
|
|
9
|
+
* one menu each; the option picked goes with every run as
|
|
10
|
+
* `forwardedProps.loop.modes` (`LoopRunProps`), and the runtime tells the
|
|
11
|
+
* agent its instructions, on the model it names, for that run.
|
|
12
|
+
*
|
|
13
|
+
* @module loop/apps/AppComposer
|
|
14
|
+
*/
|
|
15
|
+
import type { JSX } from 'react';
|
|
16
|
+
import type { AppSpec } from '../../types/agentspecs';
|
|
17
|
+
/** The plugin's name, before the application's id. */
|
|
18
|
+
export declare const APP_COMPOSER_PLUGIN_NAME = "@datalayer/loop-plugin-app-composer";
|
|
19
|
+
/**
|
|
20
|
+
* The plugin that puts an application's commands in the composer's `/` menu
|
|
21
|
+
* and its modes beside the composer. Nothing for an application with
|
|
22
|
+
* neither: its plugin contributes nothing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function defineAppComposerPlugin(app: AppSpec): import("@datalayer/reactor").ReactorPlugin<Record<string, never>, unknown, {
|
|
25
|
+
components: {
|
|
26
|
+
id: string;
|
|
27
|
+
slot: "loop.promptAction";
|
|
28
|
+
order: number;
|
|
29
|
+
Component: () => JSX.Element | null;
|
|
30
|
+
}[];
|
|
31
|
+
}>;
|