@datalayer/agent-runtimes 1.3.80 → 1.3.82
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/AssistantStage.d.ts +9 -4
- package/lib/chat/assistant/AssistantStage.js +18 -6
- package/lib/chat/assistant/SpeechBalloon.js +16 -1
- package/lib/chat/assistant/SpriteCharacter.d.ts +25 -3
- package/lib/chat/assistant/SpriteCharacter.js +68 -3
- package/lib/chat/assistant/formats/acf.d.ts +56 -0
- package/lib/chat/assistant/formats/acf.js +317 -0
- package/lib/chat/assistant/formats/acs.d.ts +85 -7
- package/lib/chat/assistant/formats/acs.js +111 -39
- package/lib/chat/assistant/formats/files.d.ts +6 -2
- package/lib/chat/assistant/formats/files.js +18 -4
- package/lib/chat/assistant/formats/index.d.ts +6 -3
- package/lib/chat/assistant/formats/index.js +4 -2
- package/lib/chat/assistant/formats/types.d.ts +14 -0
- package/lib/chat/assistant/state.d.ts +2 -0
- package/lib/chat/assistant/state.js +9 -0
- package/lib/chat/base/ChatBase.js +47 -4
- package/lib/chat/base/loopStep.d.ts +40 -0
- package/lib/chat/base/loopStep.js +73 -0
- 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/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 +119 -2
- package/lib/loop/apps/checks.js +161 -1
- package/lib/loop/apps/composer.d.ts +37 -0
- package/lib/loop/apps/composer.js +61 -0
- package/lib/loop/apps/hostTools.d.ts +17 -0
- package/lib/loop/apps/hostTools.js +20 -0
- package/lib/loop/apps/index.d.ts +2 -0
- package/lib/loop/apps/index.js +2 -0
- package/lib/loop/apps/rules.d.ts +22 -1
- package/lib/loop/apps/rules.js +49 -1
- package/lib/loop/core/index.d.ts +31 -0
- package/lib/loop/core/index.js +22 -0
- package/lib/loop/embed/AppEmbed.d.ts +100 -6
- package/lib/loop/embed/AppEmbed.js +172 -27
- package/lib/loop/embed/LoopEmbed.js +2 -0
- package/lib/loop/embed/element.js +58 -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/embed/hostBridge.d.ts +79 -0
- package/lib/loop/embed/hostBridge.js +104 -0
- package/lib/loop/index.d.ts +5 -3
- package/lib/loop/index.js +6 -3
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.d.ts +5 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +7 -1
- package/lib/loop/plugins/a2ui-surface/index.d.ts +1 -1
- package/lib/loop/plugins/a2ui-surface/index.js +4 -4
- package/lib/loop/plugins/a2ui-surface/toolResult.d.ts +27 -0
- package/lib/loop/plugins/a2ui-surface/toolResult.js +22 -0
- 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/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 -25
- package/lib/specs/apps.js +50 -8
- package/lib/specs/appspecSchema.js +258 -0
- package/lib/types/agentspecs.d.ts +86 -0
- 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 +7 -0
- 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
|
@@ -61,6 +61,7 @@ import { useNotebookTools } from '../../tools/adapters/agent-runtimes/notebookHo
|
|
|
61
61
|
import { useAgentInspectorSink } from '../../components/inspector/agentInspector';
|
|
62
62
|
import { chatInspectorRecorder, } from '../../components/inspector/chatInspect';
|
|
63
63
|
import { loopMessageChange, speakerOf, withLoopMessage } from './loopMessage';
|
|
64
|
+
import { loopStepOf, withLoopStep } from './loopStep';
|
|
64
65
|
// Tracks pending prompts already auto-sent for a given conversation scope.
|
|
65
66
|
// This prevents layout-driven unmount/remount cycles from re-sending prompts.
|
|
66
67
|
const sentPendingPromptKeys = new Set();
|
|
@@ -510,7 +511,7 @@ export function ChatBase(props) {
|
|
|
510
511
|
// ---------------------------------------------------------------------------
|
|
511
512
|
// ChatBaseInner — contains all actual logic
|
|
512
513
|
// ---------------------------------------------------------------------------
|
|
513
|
-
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,
|
|
514
515
|
// Mode selection
|
|
515
516
|
useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, onSendReady, onLoadingChange, onContextSnapshot, enableStreaming = false,
|
|
516
517
|
// Extended props
|
|
@@ -520,7 +521,7 @@ onToolCallStart, onToolCallComplete, inspector: inspectorGiven,
|
|
|
520
521
|
// Identity/Authorization props
|
|
521
522
|
onAuthorizationRequired: _onAuthorizationRequired, connectedIdentities,
|
|
522
523
|
// Conversation persistence
|
|
523
|
-
runtimeId, historyEndpoint, historyAuthToken: _historyAuthToken,
|
|
524
|
+
runtimeId, thread, historyEndpoint, historyAuthToken: _historyAuthToken,
|
|
524
525
|
// Pending prompt
|
|
525
526
|
pendingPrompt, contextSnapshot: externalContextSnapshot, mcpStatusData, sandboxStatusData,
|
|
526
527
|
// Tool approval banner
|
|
@@ -1573,7 +1574,20 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1573
1574
|
const suppressAssistantTextForToolOnlyRef = useRef(false);
|
|
1574
1575
|
const hideMessagesAfterToolUIRef = useRef(hideMessagesAfterToolUI);
|
|
1575
1576
|
hideMessagesAfterToolUIRef.current = hideMessagesAfterToolUI;
|
|
1576
|
-
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
|
+
}, []);
|
|
1577
1591
|
const messagesContainerRef = useRef(null);
|
|
1578
1592
|
const messagesEndRef = useRef(null);
|
|
1579
1593
|
const inputRef = useRef(null);
|
|
@@ -2131,6 +2145,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2131
2145
|
// Set when the next load must come from a fresh snapshot, not the one in
|
|
2132
2146
|
// the store: what the store holds is the transcript before the change.
|
|
2133
2147
|
const freshSnapshotRef = useRef(false);
|
|
2148
|
+
// The given thread drawn, by its id: once.
|
|
2149
|
+
const threadSeededRef = useRef(null);
|
|
2134
2150
|
useEffect(() => {
|
|
2135
2151
|
if (historyScopeId !== prevHistoryScopeRef.current) {
|
|
2136
2152
|
if (historyScopeId) {
|
|
@@ -2144,6 +2160,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2144
2160
|
}
|
|
2145
2161
|
if (!historyScopeId)
|
|
2146
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
|
+
}
|
|
2147
2181
|
if (historyVersion !== historyVersionRef.current) {
|
|
2148
2182
|
historyVersionRef.current = historyVersion;
|
|
2149
2183
|
if (historyVersion > 0) {
|
|
@@ -2684,6 +2718,12 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2684
2718
|
}
|
|
2685
2719
|
break;
|
|
2686
2720
|
case 'activity': {
|
|
2721
|
+
// A step of an application's code, drawn as it runs (LOOP P-16).
|
|
2722
|
+
const step = loopStepOf(event.activity);
|
|
2723
|
+
if (step) {
|
|
2724
|
+
setDisplayItems(prev => withLoopStep(prev, step));
|
|
2725
|
+
break;
|
|
2726
|
+
}
|
|
2687
2727
|
// An application's code changed a message it sent: its author
|
|
2688
2728
|
// said, or the message taken away (LOOP P-15).
|
|
2689
2729
|
const change = loopMessageChange(event.activity);
|
|
@@ -3004,6 +3044,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3004
3044
|
console.warn('[ChatBase] frontendTools count:', frontendTools?.length ?? 0, 'toolsForRequest:', toolsForRequest.map(t => t.name));
|
|
3005
3045
|
const enabledMcpToolNames = getEnabledMcpToolNames();
|
|
3006
3046
|
const enabledSkillIds = getEnabledSkillIds();
|
|
3047
|
+
// The thread is opened by this run: its host keeps it (D-13).
|
|
3048
|
+
noteThreadStarted();
|
|
3007
3049
|
await adapterRef.current.sendMessage(userMessage, {
|
|
3008
3050
|
threadId: threadIdRef.current,
|
|
3009
3051
|
messages: allMessages,
|
|
@@ -3051,6 +3093,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3051
3093
|
enableStreaming,
|
|
3052
3094
|
getEnabledMcpToolNames,
|
|
3053
3095
|
getEnabledSkillIds,
|
|
3096
|
+
noteThreadStarted,
|
|
3054
3097
|
]);
|
|
3055
3098
|
// Send pending prompt once history loaded and adapter/handler available
|
|
3056
3099
|
useEffect(() => {
|
|
@@ -3620,7 +3663,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3620
3663
|
somebody typing, and what they would have typed is the message the
|
|
3621
3664
|
chip sends, not the label on it.
|
|
3622
3665
|
*/
|
|
3623
|
-
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,
|
|
3624
3667
|
// The runtime's memory of what was sent to this agent, for the arrow
|
|
3625
3668
|
// keys — part of the same initial state as the models and tools.
|
|
3626
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,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A step of an application's code, shown in the conversation as it runs
|
|
3
|
+
* (LOOP P-16): the chain of thought.
|
|
4
|
+
*
|
|
5
|
+
* AG-UI's `STEP_STARTED` and `STEP_FINISHED` carry a step's name only; the
|
|
6
|
+
* session API says the step whole beside them, with a `CUSTOM` event named
|
|
7
|
+
* `loop.step` — `{id, name, kind, parent_id, input, output, error,
|
|
8
|
+
* started_at, ended_at}` — which the AG-UI adapter hands on as an
|
|
9
|
+
* `activity`. A step is drawn as the chat draws a tool call: one row,
|
|
10
|
+
* collapsed, its input and output inside, running until it ends; a nested
|
|
11
|
+
* step says the step it is in.
|
|
12
|
+
*/
|
|
13
|
+
import type { DisplayItem, ToolCallMessage } from '../../types/chat';
|
|
14
|
+
/** The `CUSTOM` event's name. */
|
|
15
|
+
export declare const LOOP_STEP = "loop.step";
|
|
16
|
+
/** A step, as the event says it. */
|
|
17
|
+
export type LoopStep = {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
kind: string;
|
|
21
|
+
parentId: string | null;
|
|
22
|
+
input: unknown;
|
|
23
|
+
output: unknown;
|
|
24
|
+
error: string;
|
|
25
|
+
ended: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** The step an activity says, or `null` when it says none. */
|
|
28
|
+
export declare function loopStepOf(activity: {
|
|
29
|
+
type: string;
|
|
30
|
+
data: unknown;
|
|
31
|
+
} | undefined): LoopStep | null;
|
|
32
|
+
/** The id of the row a step is drawn as. */
|
|
33
|
+
export declare const stepCallId: (id: string) => string;
|
|
34
|
+
/** A step as the row the chat draws a tool call as. */
|
|
35
|
+
export declare function stepItem(step: LoopStep, inside?: string): ToolCallMessage;
|
|
36
|
+
/**
|
|
37
|
+
* The conversation with the step drawn: its row changed in place when it is
|
|
38
|
+
* there (a step ending), else added after the rest.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withLoopStep(items: DisplayItem[], step: LoopStep): DisplayItem[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/** The `CUSTOM` event's name. */
|
|
6
|
+
export const LOOP_STEP = 'loop.step';
|
|
7
|
+
/** The step an activity says, or `null` when it says none. */
|
|
8
|
+
export function loopStepOf(activity) {
|
|
9
|
+
if (!activity || activity.type !== LOOP_STEP)
|
|
10
|
+
return null;
|
|
11
|
+
const data = activity.data;
|
|
12
|
+
if (!data ||
|
|
13
|
+
typeof data.id !== 'string' ||
|
|
14
|
+
!data.id ||
|
|
15
|
+
typeof data.name !== 'string') {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
id: data.id,
|
|
20
|
+
name: data.name,
|
|
21
|
+
kind: typeof data.kind === 'string' ? data.kind : 'run',
|
|
22
|
+
parentId: typeof data.parent_id === 'string' && data.parent_id
|
|
23
|
+
? data.parent_id
|
|
24
|
+
: null,
|
|
25
|
+
input: data.input ?? null,
|
|
26
|
+
output: data.output ?? null,
|
|
27
|
+
error: typeof data.error === 'string' ? data.error : '',
|
|
28
|
+
ended: typeof data.ended_at === 'string' && data.ended_at !== '',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** The id of the row a step is drawn as. */
|
|
32
|
+
export const stepCallId = (id) => `step-${id}`;
|
|
33
|
+
/** A step as the row the chat draws a tool call as. */
|
|
34
|
+
export function stepItem(step, inside) {
|
|
35
|
+
const callId = stepCallId(step.id);
|
|
36
|
+
const kind = `${step.kind} step`;
|
|
37
|
+
return {
|
|
38
|
+
id: callId,
|
|
39
|
+
type: 'tool-call',
|
|
40
|
+
toolCallId: callId,
|
|
41
|
+
toolName: step.name,
|
|
42
|
+
args: {
|
|
43
|
+
kind: step.kind,
|
|
44
|
+
...(step.input !== null ? { input: step.input } : {}),
|
|
45
|
+
},
|
|
46
|
+
...(step.ended && !step.error && step.output !== null
|
|
47
|
+
? { result: step.output }
|
|
48
|
+
: {}),
|
|
49
|
+
status: !step.ended ? 'executing' : step.error ? 'error' : 'complete',
|
|
50
|
+
...(step.error ? { error: step.error } : {}),
|
|
51
|
+
summary: inside ? `${kind}, inside ${inside}` : kind,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The conversation with the step drawn: its row changed in place when it is
|
|
56
|
+
* there (a step ending), else added after the rest.
|
|
57
|
+
*/
|
|
58
|
+
export function withLoopStep(items, step) {
|
|
59
|
+
const parent = step.parentId
|
|
60
|
+
? items.find(item => 'toolCallId' in item &&
|
|
61
|
+
item.toolCallId === stepCallId(step.parentId))
|
|
62
|
+
: undefined;
|
|
63
|
+
const row = stepItem(step, parent && 'toolName' in parent ? parent.toolName : undefined);
|
|
64
|
+
let found = false;
|
|
65
|
+
const changed = items.map(item => {
|
|
66
|
+
if ('toolCallId' in item && item.toolCallId === row.toolCallId) {
|
|
67
|
+
found = true;
|
|
68
|
+
return row;
|
|
69
|
+
}
|
|
70
|
+
return item;
|
|
71
|
+
});
|
|
72
|
+
return found ? changed : [...items, row];
|
|
73
|
+
}
|
|
@@ -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;
|
|
@@ -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}`,
|