@datalayer/agent-runtimes 1.3.83 → 1.3.85
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/ChatFloating.d.ts +5 -4
- package/lib/chat/ChatFloating.js +8 -6
- package/lib/chat/ChatLanguage.d.ts +17 -0
- package/lib/chat/ChatLanguage.js +29 -0
- package/lib/chat/assistant/AssistantStage.d.ts +4 -4
- package/lib/chat/assistant/AssistantStage.js +4 -2
- package/lib/chat/assistant/BalloonParts.d.ts +2 -1
- package/lib/chat/assistant/BalloonParts.js +12 -5
- package/lib/chat/assistant/BalloonVisual.js +3 -1
- package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
- package/lib/chat/assistant/ConversationBalloon.js +3 -2
- package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
- package/lib/chat/assistant/SpeechBalloon.js +10 -7
- package/lib/chat/assistant/toolLine.d.ts +8 -4
- package/lib/chat/assistant/toolLine.js +13 -9
- package/lib/chat/base/ChatBase.js +30 -11
- package/lib/chat/base/loopElement.d.ts +53 -0
- package/lib/chat/base/loopElement.js +78 -0
- package/lib/chat/base/loopWindow.d.ts +31 -0
- package/lib/chat/base/loopWindow.js +74 -0
- package/lib/chat/display/EmptyState.js +3 -1
- package/lib/chat/index.d.ts +2 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/messages/ChatMessages.js +3 -1
- package/lib/chat/messages/TurnFooter.js +3 -1
- package/lib/chat/prompt/InputPrompt.js +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +3 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
- package/lib/chat/tools/ToolApprovalBanner.js +5 -3
- package/lib/chat/tools/ToolApprovalDialog.js +5 -3
- package/lib/chat/tools/ToolCallDisplay.js +29 -25
- package/lib/chat/words.d.ts +102 -0
- package/lib/chat/words.js +460 -0
- package/lib/components/a2ui/custom/index.d.ts +39 -0
- package/lib/components/a2ui/custom/index.js +95 -0
- package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
- package/lib/components/a2ui/custom/sandbox.js +188 -0
- package/lib/components/a2ui/datalayer/FileUpload.d.ts +10 -2
- package/lib/components/a2ui/datalayer/FileUpload.js +10 -7
- package/lib/components/a2ui/datalayer/Form.d.ts +2 -0
- package/lib/components/a2ui/datalayer/Form.js +9 -2
- package/lib/components/a2ui/datalayer/formWidgets.d.ts +19 -0
- package/lib/components/a2ui/datalayer/formWidgets.js +51 -0
- package/lib/components/a2ui/datalayer/index.d.ts +1 -1
- package/lib/components/a2ui/datalayer/index.js +1 -1
- package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
- package/lib/components/a2ui/datalayer/schema.js +12 -1
- package/lib/components/a2ui/index.d.ts +1 -0
- package/lib/components/a2ui/index.js +1 -0
- package/lib/components/a2ui/visibleWhen.d.ts +12 -1
- package/lib/components/a2ui/visibleWhen.js +24 -3
- package/lib/components/inspector/AgentInspector.d.ts +25 -44
- package/lib/components/inspector/AgentInspector.js +27 -215
- package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
- package/lib/components/inspector/AgentInspectorDialog.js +2 -2
- package/lib/components/inspector/a2aSpans.d.ts +51 -0
- package/lib/components/inspector/a2aSpans.js +373 -0
- package/lib/components/inspector/agentSpans.d.ts +120 -0
- package/lib/components/inspector/agentSpans.js +253 -0
- package/lib/components/inspector/chatSpans.d.ts +36 -0
- package/lib/components/inspector/chatSpans.js +50 -0
- package/lib/components/inspector/classify.d.ts +11 -8
- package/lib/components/inspector/classify.js +23 -24
- package/lib/components/inspector/index.d.ts +7 -7
- package/lib/components/inspector/index.js +7 -7
- package/lib/components/teams/A2ATeamGraph.d.ts +4 -4
- package/lib/components/teams/SceneTranscript.d.ts +29 -0
- package/lib/components/teams/SceneTranscript.js +54 -0
- package/lib/components/teams/SceneView.d.ts +41 -0
- package/lib/components/teams/SceneView.js +28 -0
- package/lib/components/teams/index.d.ts +3 -0
- package/lib/components/teams/index.js +3 -0
- package/lib/components/teams/sceneTranscript.d.ts +74 -0
- package/lib/components/teams/sceneTranscript.js +294 -0
- package/lib/components/teams/teamConnections.d.ts +2 -2
- package/lib/components/teams/teamConnections.js +3 -3
- package/lib/components/teams/useA2ATeam.d.ts +4 -4
- package/lib/components/teams/useA2ATeam.js +50 -46
- package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
- package/lib/examples/AgentA2ATeamExample.js +70 -60
- package/lib/examples/AssistantExample.js +2 -2
- package/lib/loop/apps/AppComposer.d.ts +40 -4
- package/lib/loop/apps/AppComposer.js +194 -19
- package/lib/loop/apps/AppRenderer.d.ts +21 -3
- package/lib/loop/apps/AppRenderer.js +88 -48
- package/lib/loop/apps/appspec.d.ts +13 -1
- package/lib/loop/apps/appspec.js +305 -12
- package/lib/loop/apps/checks.d.ts +14 -0
- package/lib/loop/apps/checks.js +276 -5
- package/lib/loop/apps/composer.d.ts +21 -10
- package/lib/loop/apps/composer.js +41 -8
- package/lib/loop/apps/customComponents.d.ts +41 -0
- package/lib/loop/apps/customComponents.js +260 -0
- package/lib/loop/apps/hostTools.d.ts +8 -1
- package/lib/loop/apps/hostTools.js +9 -0
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/apps/language.d.ts +68 -0
- package/lib/loop/apps/language.js +275 -0
- package/lib/loop/apps/settingsInputs.d.ts +29 -0
- package/lib/loop/apps/settingsInputs.js +147 -0
- package/lib/loop/apps/uploads.d.ts +43 -0
- package/lib/loop/apps/uploads.js +66 -0
- package/lib/loop/core/a2uiComponents.d.ts +10 -0
- package/lib/loop/core/a2uiComponents.js +15 -0
- package/lib/loop/core/index.d.ts +15 -1
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/embed/AppEmbed.d.ts +25 -3
- package/lib/loop/embed/AppEmbed.js +106 -18
- package/lib/loop/embed/element.d.ts +5 -0
- package/lib/loop/embed/element.js +84 -5
- package/lib/loop/embed/embedConfig.d.ts +8 -0
- package/lib/loop/embed/embedConfig.js +18 -0
- package/lib/loop/embed/embedSession.d.ts +14 -0
- package/lib/loop/embed/embedSession.js +34 -0
- package/lib/loop/embed/hostBridge.d.ts +50 -3
- package/lib/loop/embed/hostBridge.js +22 -2
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
- package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
- package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
- package/lib/loop/plugins/app-components/index.d.ts +26 -0
- package/lib/loop/plugins/app-components/index.js +56 -0
- package/lib/loop/plugins/app-elements/AppElements.d.ts +27 -0
- package/lib/loop/plugins/app-elements/AppElements.js +79 -0
- package/lib/loop/plugins/app-elements/index.d.ts +20 -0
- package/lib/loop/plugins/app-elements/index.js +43 -0
- package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
- package/lib/loop/plugins/app-page/AppPage.js +106 -8
- package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
- package/lib/loop/plugins/app-page/appPageModel.js +122 -4
- package/lib/loop/plugins/app-page/index.d.ts +1 -0
- package/lib/loop/plugins/app-page/index.js +1 -0
- package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
- package/lib/loop/plugins/app-page/pageRun.js +111 -0
- package/lib/loop/plugins/assistant/index.js +8 -6
- package/lib/loop/plugins/chat/ChatView.js +16 -6
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/chat/index.js +2 -1
- package/lib/models/PageTag.d.ts +1 -1
- package/lib/protocols/BrowserAgentAdapter.d.ts +8 -6
- package/lib/protocols/BrowserAgentAdapter.js +13 -10
- package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
- package/lib/runtimes/browser/protocol.d.ts +1 -1
- package/lib/specs/actions.js +78 -1
- package/lib/specs/apps.d.ts +5 -0
- package/lib/specs/apps.js +1518 -216
- package/lib/specs/appspecSchema.js +630 -3
- package/lib/specs/teams/teams.d.ts +3 -0
- package/lib/specs/teams/teams.js +249 -0
- package/lib/specs/uiPlugins.js +6 -1
- package/lib/types/agentspecs.d.ts +200 -1
- package/lib/types/chat.d.ts +6 -5
- package/lib/types/teams.d.ts +13 -2
- package/package.json +2 -2
- package/scripts/codegen/generate_apps.py +20 -2
- package/scripts/codegen/generate_teams.py +15 -2
- package/lib/components/inspector/JsonTree.d.ts +0 -24
- package/lib/components/inspector/JsonTree.js +0 -89
- package/lib/components/inspector/a2aInspect.d.ts +0 -56
- package/lib/components/inspector/a2aInspect.js +0 -478
- package/lib/components/inspector/agentInspector.d.ts +0 -179
- package/lib/components/inspector/agentInspector.js +0 -267
- package/lib/components/inspector/chatInspect.d.ts +0 -38
- package/lib/components/inspector/chatInspect.js +0 -65
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an element of an application's code shows (LOOP P-18): in a side
|
|
3
|
+
* panel beside the conversation, or on a page of its own over it. Inline,
|
|
4
|
+
* an element is a message, and the chat draws it as one (P-04).
|
|
5
|
+
*
|
|
6
|
+
* The session API says it with a `CUSTOM` event named `loop.element` —
|
|
7
|
+
* `{id, where, title, shows}`, `shows` the A2UI surface an answer's
|
|
8
|
+
* components are drawn from, or `{id, closed: true}` — which the AG-UI
|
|
9
|
+
* adapter hands on as an `activity`. The chat does not draw it: it keeps
|
|
10
|
+
* what is open here, and whoever draws panels and pages (the `app-elements`
|
|
11
|
+
* plugin) listens. One store per page, as there is one chat per
|
|
12
|
+
* application on it.
|
|
13
|
+
*/
|
|
14
|
+
/** The `CUSTOM` event's name. */
|
|
15
|
+
export declare const LOOP_ELEMENT = "loop.element";
|
|
16
|
+
/** Where an element opens, besides inline. */
|
|
17
|
+
export type LoopElementWhere = 'panel' | 'page';
|
|
18
|
+
/** An element open in a side panel or on a page. */
|
|
19
|
+
export type LoopElement = {
|
|
20
|
+
id: string;
|
|
21
|
+
where: LoopElementWhere;
|
|
22
|
+
title: string;
|
|
23
|
+
/** The surface it draws: what `render_a2ui_surface` returns. */
|
|
24
|
+
shows: unknown;
|
|
25
|
+
};
|
|
26
|
+
/** What an event says: an element opened or changed, or one closed. */
|
|
27
|
+
export type LoopElementChange = LoopElement | {
|
|
28
|
+
id: string;
|
|
29
|
+
closed: true;
|
|
30
|
+
};
|
|
31
|
+
/** The change an activity says, or `null` when it says none. */
|
|
32
|
+
export declare function loopElementChange(activity: {
|
|
33
|
+
type: string;
|
|
34
|
+
data: unknown;
|
|
35
|
+
} | undefined): LoopElementChange | null;
|
|
36
|
+
/**
|
|
37
|
+
* The elements open with a change applied: one opened is added last, one
|
|
38
|
+
* changed is replaced where it is, one closed is taken away.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withLoopElement(open: readonly LoopElement[], change: LoopElementChange): LoopElement[];
|
|
41
|
+
/** The elements open now, in the order they opened. */
|
|
42
|
+
export declare const openLoopElements: () => LoopElement[];
|
|
43
|
+
/** Apply a change, and tell whoever draws them. */
|
|
44
|
+
export declare function applyLoopElement(change: LoopElementChange): void;
|
|
45
|
+
/**
|
|
46
|
+
* Close an element on this screen: the person closed it. The code is not
|
|
47
|
+
* told; it may show it again.
|
|
48
|
+
*/
|
|
49
|
+
export declare const closeLoopElement: (id: string) => void;
|
|
50
|
+
/** Close every element: a new conversation starts with none. */
|
|
51
|
+
export declare function clearLoopElements(): void;
|
|
52
|
+
/** Listen for what is open. Returns the unsubscribe. */
|
|
53
|
+
export declare function onLoopElements(listener: (open: LoopElement[]) => void): () => void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Where an element of an application's code shows (LOOP P-18): in a side
|
|
7
|
+
* panel beside the conversation, or on a page of its own over it. Inline,
|
|
8
|
+
* an element is a message, and the chat draws it as one (P-04).
|
|
9
|
+
*
|
|
10
|
+
* The session API says it with a `CUSTOM` event named `loop.element` —
|
|
11
|
+
* `{id, where, title, shows}`, `shows` the A2UI surface an answer's
|
|
12
|
+
* components are drawn from, or `{id, closed: true}` — which the AG-UI
|
|
13
|
+
* adapter hands on as an `activity`. The chat does not draw it: it keeps
|
|
14
|
+
* what is open here, and whoever draws panels and pages (the `app-elements`
|
|
15
|
+
* plugin) listens. One store per page, as there is one chat per
|
|
16
|
+
* application on it.
|
|
17
|
+
*/
|
|
18
|
+
/** The `CUSTOM` event's name. */
|
|
19
|
+
export const LOOP_ELEMENT = 'loop.element';
|
|
20
|
+
/** The change an activity says, or `null` when it says none. */
|
|
21
|
+
export function loopElementChange(activity) {
|
|
22
|
+
if (!activity || activity.type !== LOOP_ELEMENT)
|
|
23
|
+
return null;
|
|
24
|
+
const data = activity.data;
|
|
25
|
+
if (!data || typeof data.id !== 'string' || !data.id)
|
|
26
|
+
return null;
|
|
27
|
+
if (data.closed === true)
|
|
28
|
+
return { id: data.id, closed: true };
|
|
29
|
+
if (data.where !== 'panel' && data.where !== 'page')
|
|
30
|
+
return null;
|
|
31
|
+
return {
|
|
32
|
+
id: data.id,
|
|
33
|
+
where: data.where,
|
|
34
|
+
title: typeof data.title === 'string' ? data.title : '',
|
|
35
|
+
shows: data.shows ?? null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The elements open with a change applied: one opened is added last, one
|
|
40
|
+
* changed is replaced where it is, one closed is taken away.
|
|
41
|
+
*/
|
|
42
|
+
export function withLoopElement(open, change) {
|
|
43
|
+
if ('closed' in change) {
|
|
44
|
+
return open.filter(element => element.id !== change.id);
|
|
45
|
+
}
|
|
46
|
+
const at = open.findIndex(element => element.id === change.id);
|
|
47
|
+
if (at < 0)
|
|
48
|
+
return [...open, change];
|
|
49
|
+
return open.map((element, index) => (index === at ? change : element));
|
|
50
|
+
}
|
|
51
|
+
let opened = [];
|
|
52
|
+
const listeners = new Set();
|
|
53
|
+
/** The elements open now, in the order they opened. */
|
|
54
|
+
export const openLoopElements = () => opened;
|
|
55
|
+
/** Apply a change, and tell whoever draws them. */
|
|
56
|
+
export function applyLoopElement(change) {
|
|
57
|
+
opened = withLoopElement(opened, change);
|
|
58
|
+
for (const listener of [...listeners])
|
|
59
|
+
listener(opened);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Close an element on this screen: the person closed it. The code is not
|
|
63
|
+
* told; it may show it again.
|
|
64
|
+
*/
|
|
65
|
+
export const closeLoopElement = (id) => applyLoopElement({ id, closed: true });
|
|
66
|
+
/** Close every element: a new conversation starts with none. */
|
|
67
|
+
export function clearLoopElements() {
|
|
68
|
+
opened = [];
|
|
69
|
+
for (const listener of [...listeners])
|
|
70
|
+
listener(opened);
|
|
71
|
+
}
|
|
72
|
+
/** Listen for what is open. Returns the unsubscribe. */
|
|
73
|
+
export function onLoopElements(listener) {
|
|
74
|
+
listeners.add(listener);
|
|
75
|
+
return () => {
|
|
76
|
+
listeners.delete(listener);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window messages (LOOP P-25): what an application's code tells the page it
|
|
3
|
+
* sits in, outside the conversation — ``session.send_window_message(data)``.
|
|
4
|
+
*
|
|
5
|
+
* The session API says it with a `CUSTOM` event named `loop.window` —
|
|
6
|
+
* `{data}` — which the AG-UI adapter hands on as an `activity`. The chat
|
|
7
|
+
* does not draw it: it hands it to whoever listens here — the embed's host
|
|
8
|
+
* bridge, which raises it on the element as its `window-message` event.
|
|
9
|
+
*/
|
|
10
|
+
/** The `CUSTOM` event's name. */
|
|
11
|
+
export declare const LOOP_WINDOW = "loop.window";
|
|
12
|
+
/** What an activity says to the page, or `null` when it is not a window message. */
|
|
13
|
+
export declare function loopWindowMessage(activity: {
|
|
14
|
+
type: string;
|
|
15
|
+
data: unknown;
|
|
16
|
+
} | undefined): {
|
|
17
|
+
data: unknown;
|
|
18
|
+
} | null;
|
|
19
|
+
/** Hand a window message to whoever listens. */
|
|
20
|
+
export declare function tellLoopWindow(data: unknown): void;
|
|
21
|
+
/** Listen for window messages. Returns the unsubscribe. */
|
|
22
|
+
export declare function onLoopWindowMessage(listener: (data: unknown) => void): () => void;
|
|
23
|
+
/**
|
|
24
|
+
* What a turn's stream says to the page — the `loop.window` events of the
|
|
25
|
+
* turn a window message posted by the page ran — and the sentence its
|
|
26
|
+
* `RUN_ERROR` said, if it failed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function windowTurnOf(stream: string): {
|
|
29
|
+
said: unknown[];
|
|
30
|
+
error: string | null;
|
|
31
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Window messages (LOOP P-25): what an application's code tells the page it
|
|
7
|
+
* sits in, outside the conversation — ``session.send_window_message(data)``.
|
|
8
|
+
*
|
|
9
|
+
* The session API says it with a `CUSTOM` event named `loop.window` —
|
|
10
|
+
* `{data}` — which the AG-UI adapter hands on as an `activity`. The chat
|
|
11
|
+
* does not draw it: it hands it to whoever listens here — the embed's host
|
|
12
|
+
* bridge, which raises it on the element as its `window-message` event.
|
|
13
|
+
*/
|
|
14
|
+
/** The `CUSTOM` event's name. */
|
|
15
|
+
export const LOOP_WINDOW = 'loop.window';
|
|
16
|
+
/** What an activity says to the page, or `null` when it is not a window message. */
|
|
17
|
+
export function loopWindowMessage(activity) {
|
|
18
|
+
if (!activity || activity.type !== LOOP_WINDOW)
|
|
19
|
+
return null;
|
|
20
|
+
const said = activity.data;
|
|
21
|
+
if (!said || typeof said !== 'object' || !('data' in said))
|
|
22
|
+
return null;
|
|
23
|
+
return { data: said.data };
|
|
24
|
+
}
|
|
25
|
+
const listeners = new Set();
|
|
26
|
+
/** Hand a window message to whoever listens. */
|
|
27
|
+
export function tellLoopWindow(data) {
|
|
28
|
+
for (const listener of [...listeners])
|
|
29
|
+
listener(data);
|
|
30
|
+
}
|
|
31
|
+
/** Listen for window messages. Returns the unsubscribe. */
|
|
32
|
+
export function onLoopWindowMessage(listener) {
|
|
33
|
+
listeners.add(listener);
|
|
34
|
+
return () => {
|
|
35
|
+
listeners.delete(listener);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What a turn's stream says to the page — the `loop.window` events of the
|
|
40
|
+
* turn a window message posted by the page ran — and the sentence its
|
|
41
|
+
* `RUN_ERROR` said, if it failed.
|
|
42
|
+
*/
|
|
43
|
+
export function windowTurnOf(stream) {
|
|
44
|
+
const said = [];
|
|
45
|
+
let error = null;
|
|
46
|
+
for (const block of stream.split('\n\n')) {
|
|
47
|
+
const data = block
|
|
48
|
+
.split('\n')
|
|
49
|
+
.filter(line => line.startsWith('data:'))
|
|
50
|
+
.map(line => line.slice('data:'.length).trim())
|
|
51
|
+
.join('');
|
|
52
|
+
if (!data)
|
|
53
|
+
continue;
|
|
54
|
+
let event;
|
|
55
|
+
try {
|
|
56
|
+
event = JSON.parse(data);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (event.type === 'RUN_ERROR') {
|
|
62
|
+
error = String(event.message ?? 'The turn failed.');
|
|
63
|
+
}
|
|
64
|
+
else if (event.type === 'CUSTOM') {
|
|
65
|
+
const message = loopWindowMessage({
|
|
66
|
+
type: String(event.name),
|
|
67
|
+
data: event.value,
|
|
68
|
+
});
|
|
69
|
+
if (message)
|
|
70
|
+
said.push(message.data);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { said, error };
|
|
74
|
+
}
|
|
@@ -3,6 +3,7 @@ import { Text, LabelGroup, Label, Truncate, ThemeProvider, } from '@primer/react
|
|
|
3
3
|
import { Box } from '@datalayer/primer-addons';
|
|
4
4
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
5
5
|
import { groupSuggestions } from './groupSuggestions';
|
|
6
|
+
import { useChatWords } from '../ChatLanguage';
|
|
6
7
|
export { groupSuggestions } from './groupSuggestions';
|
|
7
8
|
/**
|
|
8
9
|
* How wide a suggestion chip stands, in pixels — fixed, not a cap.
|
|
@@ -21,6 +22,7 @@ export const SUGGESTION_CHIP_WIDTH = 140;
|
|
|
21
22
|
// Component
|
|
22
23
|
// ---------------------------------------------------------------------------
|
|
23
24
|
export function ChatEmptyState({ emptyState, brandIcon, description, suggestions, onSuggestionSubmit, onSuggestionFill, submitOnSuggestionClick = true, }) {
|
|
25
|
+
const chatText = useChatWords();
|
|
24
26
|
// Custom render takes precedence
|
|
25
27
|
if (emptyState?.render) {
|
|
26
28
|
return _jsx(_Fragment, { children: emptyState.render() });
|
|
@@ -107,7 +109,7 @@ export function ChatEmptyState({ emptyState, brandIcon, description, suggestions
|
|
|
107
109
|
}, children: section.title }), section.subtitle ? (_jsx(Text, { sx: { fontSize: level === 0 ? 1 : 0 }, children: section.subtitle })) : null, (() => {
|
|
108
110
|
const own = (suggestions ?? []).filter(suggestion => suggestion.group === section.group);
|
|
109
111
|
return own.length > 0 ? chips(own) : null;
|
|
110
|
-
})()] }, section.group)))) : (_jsxs(_Fragment, { children: [emptyState?.icon || brandIcon || _jsx(AiAgentIcon, { colored: true, size: 48 }), _jsx(Text, { sx: { fontSize: 2 }, children: emptyState?.title ||
|
|
112
|
+
})()] }, section.group)))) : (_jsxs(_Fragment, { children: [emptyState?.icon || brandIcon || _jsx(AiAgentIcon, { colored: true, size: 48 }), _jsx(Text, { sx: { fontSize: 2 }, children: emptyState?.title || chatText.startConversation }), (emptyState?.subtitle || description) && (_jsx(Text, { sx: { fontSize: 1 }, children: emptyState?.subtitle || description }))] })), blocks.map(block => (_jsxs(Box, { sx: {
|
|
111
113
|
display: 'flex',
|
|
112
114
|
flexDirection: 'column',
|
|
113
115
|
alignItems: 'center',
|
package/lib/chat/index.d.ts
CHANGED
|
@@ -70,3 +70,5 @@ export { ChatFloating, type ChatFloatingProps } from './ChatFloating';
|
|
|
70
70
|
export { ChatInline, type ChatInlineProps, type ChatInlineProtocolConfig, } from './ChatInline';
|
|
71
71
|
export { AgentRuntimeChat, type AgentRuntimeChatProps, } from '../agents/AgentRuntimeChat';
|
|
72
72
|
export * from './EphemeralSurfaceControl';
|
|
73
|
+
export { ChatLanguage, useChatLanguage, useChatWords } from './ChatLanguage';
|
|
74
|
+
export { CHAT_WORDS, ENGLISH_CHAT_WORDS, chatLanguage, chatWords, type AroundName, type ChatWords, } from './words';
|
package/lib/chat/index.js
CHANGED
|
@@ -85,3 +85,6 @@ export { ChatInline, } from './ChatInline';
|
|
|
85
85
|
// Generic full-page chat surface for a live agent runtime (with launching state)
|
|
86
86
|
export { AgentRuntimeChat, } from '../agents/AgentRuntimeChat';
|
|
87
87
|
export * from './EphemeralSurfaceControl';
|
|
88
|
+
// The chat's own words in the person's language (LOOP P-26)
|
|
89
|
+
export { ChatLanguage, useChatLanguage, useChatWords } from './ChatLanguage';
|
|
90
|
+
export { CHAT_WORDS, ENGLISH_CHAT_WORDS, chatLanguage, chatWords, } from './words';
|
|
@@ -15,10 +15,12 @@ import { Box, useThemeStore, getColorPalette } from '@datalayer/primer-addons';
|
|
|
15
15
|
import { PersonIcon, ToolsIcon } from '@primer/octicons-react';
|
|
16
16
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
17
17
|
import { useChatMessages, useChatUIPluginRegistry, } from '../../stores/chatStore';
|
|
18
|
+
import { useChatWords } from '../ChatLanguage';
|
|
18
19
|
/**
|
|
19
20
|
* Chat Messages component
|
|
20
21
|
*/
|
|
21
22
|
export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps = true, showAvatars = true, autoScroll = true, className, uiPluginRegistry: uiPluginRegistryProp, }) {
|
|
23
|
+
const chatText = useChatWords();
|
|
22
24
|
const messages = useChatMessages();
|
|
23
25
|
const storeUIPluginRegistry = useChatUIPluginRegistry();
|
|
24
26
|
const uiPluginRegistry = uiPluginRegistryProp ?? storeUIPluginRegistry;
|
|
@@ -97,7 +99,7 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
97
99
|
height: '100%',
|
|
98
100
|
p: 4,
|
|
99
101
|
color: 'fg.muted',
|
|
100
|
-
}, children: [_jsx(AiAgentIcon, { colored: true, size: 48 }), _jsx(Text, { sx: { mt: 3, fontSize: 2 }, children:
|
|
102
|
+
}, children: [_jsx(AiAgentIcon, { colored: true, size: 48 }), _jsx(Text, { sx: { mt: 3, fontSize: 2 }, children: chatText.startConversation }), _jsx(Text, { sx: { mt: 1, fontSize: 1 }, children: chatText.sendToBegin })] }));
|
|
101
103
|
}
|
|
102
104
|
return (_jsx(Box, { ref: containerRef, className: className, sx: {
|
|
103
105
|
flex: 1,
|
|
@@ -4,7 +4,9 @@ import { IconButton, Text } from '@primer/react';
|
|
|
4
4
|
import { Box } from '@datalayer/primer-addons';
|
|
5
5
|
import { CheckIcon, CopyIcon, TrashIcon } from '@primer/octicons-react';
|
|
6
6
|
import { formatTokenCount } from '../../utils';
|
|
7
|
+
import { useChatWords } from '../ChatLanguage';
|
|
7
8
|
export function TurnFooter({ usage, live, latest, padding, onCopy, onRemove, }) {
|
|
9
|
+
const chatText = useChatWords();
|
|
8
10
|
const [copied, setCopied] = useState(false);
|
|
9
11
|
const copiedTimer = useRef(null);
|
|
10
12
|
useEffect(() => () => {
|
|
@@ -70,6 +72,6 @@ export function TurnFooter({ usage, live, latest, padding, onCopy, onRemove, })
|
|
|
70
72
|
'&:hover [data-turn-actions], &:focus-within [data-turn-actions]': {
|
|
71
73
|
opacity: 1,
|
|
72
74
|
},
|
|
73
|
-
}, children: [record && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', flexShrink: 0 }, children: [_jsx(Text, { as: "span", sx: { fontWeight: 'semibold', color: 'fg.default', fontSize: 0 }, children: formatTokenCount(record.contextTokens) }), ' / ', formatTokenCount(record.contextWindow), ' ctx · turn ', formatTokenCount(record.inputTokens), _jsx(Text, { as: "span", sx: { color: 'success.fg', fontSize: 0 }, children: '▲' }), ' ', formatTokenCount(record.outputTokens), _jsx(Text, { as: "span", sx: { color: 'attention.fg', fontSize: 0 }, children: '▼' })] })), !live && (_jsxs(Box, { "data-turn-actions": "", sx: { display: 'flex', alignItems: 'center' }, children: [_jsx(IconButton, { "data-turn-copy": "", icon: copied ? CheckIcon : CopyIcon, "aria-label":
|
|
75
|
+
}, children: [record && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', flexShrink: 0 }, children: [_jsx(Text, { as: "span", sx: { fontWeight: 'semibold', color: 'fg.default', fontSize: 0 }, children: formatTokenCount(record.contextTokens) }), ' / ', formatTokenCount(record.contextWindow), ' ctx · turn ', formatTokenCount(record.inputTokens), _jsx(Text, { as: "span", sx: { color: 'success.fg', fontSize: 0 }, children: '▲' }), ' ', formatTokenCount(record.outputTokens), _jsx(Text, { as: "span", sx: { color: 'attention.fg', fontSize: 0 }, children: '▼' })] })), !live && (_jsxs(Box, { "data-turn-actions": "", sx: { display: 'flex', alignItems: 'center' }, children: [_jsx(IconButton, { "data-turn-copy": "", icon: copied ? CheckIcon : CopyIcon, "aria-label": chatText.copyTurn, size: "small", variant: "invisible", onClick: () => void handleCopy() }), _jsx(IconButton, { "data-turn-remove": "", icon: TrashIcon, "aria-label": chatText.removeTurn, size: "small", variant: "invisible", onClick: onRemove })] }))] }));
|
|
74
76
|
}
|
|
75
77
|
export default TurnFooter;
|
|
@@ -22,6 +22,7 @@ import { SkillsStatusIndicator } from '../indicators/SkillsStatusIndicator';
|
|
|
22
22
|
const ContextPie = lazy(() => import('../usage/ContextPie').then(module => ({
|
|
23
23
|
default: module.ContextPie,
|
|
24
24
|
})));
|
|
25
|
+
import { useChatWords } from '../ChatLanguage';
|
|
25
26
|
/* Shared, so a defaulted prop is the same object on every render: a fresh
|
|
26
27
|
`new Map()` per render is a new dependency for anything memoising on it. */
|
|
27
28
|
const EMPTY_TOOL_MAP = new Map();
|
|
@@ -30,6 +31,7 @@ const EMPTY_ID_SET = new Set();
|
|
|
30
31
|
// Component
|
|
31
32
|
// ---------------------------------------------------------------------------
|
|
32
33
|
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, }) {
|
|
34
|
+
const chatText = useChatWords();
|
|
33
35
|
const isKernelBusy = kernelStatus === 'busy';
|
|
34
36
|
/*
|
|
35
37
|
* Each menu is offered when it is switched on *and* has something behind it.
|
|
@@ -111,7 +113,7 @@ export function InputPrompt({ input, setInput, isLoading, kernelStatus, connecti
|
|
|
111
113
|
it. Both, rather than either: a host contributing its own controls
|
|
112
114
|
should not lose the one control that says who is being addressed.
|
|
113
115
|
*/
|
|
114
|
-
headerContent: inlineAgents || headerContent ? (_jsxs(_Fragment, { children: [inlineAgents ? (_jsx(InlineAgentsMenu, { agents: agents, selectedAgentId: selectedAgentId, onSelectAgent: onSelectAgent })) : null, headerContent] })) : undefined, placeholder: placeholder ||
|
|
116
|
+
headerContent: inlineAgents || headerContent ? (_jsxs(_Fragment, { children: [inlineAgents ? (_jsx(InlineAgentsMenu, { agents: agents, selectedAgentId: selectedAgentId, onSelectAgent: onSelectAgent })) : null, headerContent] })) : undefined, placeholder: placeholder || chatText.typeMessage, typingSuggestions: typingSuggestions, isLoading: isLoading, isKernelBusy: isKernelBusy, disabled: disableInputPrompt, readOnly: !connectionConfirmed, onSend: onSend, onStop: onStop, autoFocus: autoFocus, focusTrigger: (focusTrigger ?? 0) + pickedFocus, padding: padding, value: input, onChange: setInput, footerRightContent: _jsxs(_Fragment, { children: [_jsx(McpStatusIndicator, { apiBase: apiBase, authToken: authToken, data: mcpStatusData }), _jsx(SkillsStatusIndicator, { skillsCount: skills.length, enabledCount: enabledSkills.size, loading: skillsLoading })] }) }), _jsx(BelowPromptHeader, { disabled: disableInputPrompt, stacks: showTokenUsage
|
|
115
117
|
? [
|
|
116
118
|
{
|
|
117
119
|
id: 'context-usage',
|
|
@@ -29,6 +29,7 @@ import { MentionNode } from './plugins/MentionNode';
|
|
|
29
29
|
import { Box } from '@datalayer/primer-addons';
|
|
30
30
|
import { AgentMentionPlugin, } from './plugins/AgentMentionPlugin';
|
|
31
31
|
import { CommandPlugin, PROMPT_COMMANDS, } from './plugins/CommandPlugin';
|
|
32
|
+
import { useChatWords } from '../ChatLanguage';
|
|
32
33
|
// ---- Lexical extension (plain-text only) ---------------------------------
|
|
33
34
|
// Module scope on purpose: the composer rebuilds the editor whenever this
|
|
34
35
|
// reference changes.
|
|
@@ -266,6 +267,7 @@ function ReadOnlyPlugin({ readOnly }) {
|
|
|
266
267
|
return null;
|
|
267
268
|
}
|
|
268
269
|
export function InputPromptLexical({ value, onChange, placeholder = 'Ask anything…', disabled = false, readOnly = false, onSubmit, onHistory, autoFocus = false, focusSignal, mentionableAgents, promptCommands, }) {
|
|
270
|
+
const chatText = useChatWords();
|
|
269
271
|
return (_jsx(Box, { sx: {
|
|
270
272
|
/*
|
|
271
273
|
The placeholder is positioned against this box.
|
|
@@ -313,7 +315,7 @@ export function InputPromptLexical({ value, onChange, placeholder = 'Ask anythin
|
|
|
313
315
|
fontSize: 1,
|
|
314
316
|
pointerEvents: 'none',
|
|
315
317
|
userSelect: 'none',
|
|
316
|
-
}, children: placeholder }), "aria-placeholder": placeholder, className: "input-prompt-lexical-content", "aria-label":
|
|
318
|
+
}, children: placeholder }), "aria-placeholder": placeholder, className: "input-prompt-lexical-content", "aria-label": chatText.messageInput, style: {
|
|
317
319
|
outline: 'none',
|
|
318
320
|
minHeight: 32,
|
|
319
321
|
maxHeight: 120,
|
|
@@ -3,7 +3,9 @@ import { IconButton } from '@primer/react';
|
|
|
3
3
|
import { Box } from '@datalayer/primer-addons';
|
|
4
4
|
import { PaperAirplaneIcon, SquareCircleIcon, PauseIcon, } from '@primer/octicons-react';
|
|
5
5
|
import { PromptStacks } from '../stack';
|
|
6
|
+
import { useChatWords } from '../../ChatLanguage';
|
|
6
7
|
export function InPromptFooter({ stacks, children, rightContent, isLoading = false, sendDisabled = false, isKernelBusy = false, onSend, onStop, }) {
|
|
8
|
+
const chatText = useChatWords();
|
|
7
9
|
return (_jsxs(_Fragment, { children: [stacks && stacks.length > 0 ? _jsx(PromptStacks, { stacks: stacks }) : null, _jsxs(Box, { "data-prompt-stack": "controls", sx: {
|
|
8
10
|
display: 'flex',
|
|
9
11
|
alignItems: 'center',
|
|
@@ -11,6 +13,6 @@ export function InPromptFooter({ stacks, children, rightContent, isLoading = fal
|
|
|
11
13
|
px: 2,
|
|
12
14
|
pt: 1,
|
|
13
15
|
pb: 2,
|
|
14
|
-
}, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2, flex: 1 }, children: children }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [rightContent, isLoading ? (_jsx(IconButton, { icon: SquareCircleIcon, "aria-label":
|
|
16
|
+
}, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2, flex: 1 }, children: children }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [rightContent, isLoading ? (_jsx(IconButton, { icon: SquareCircleIcon, "aria-label": chatText.stop, "data-prompt-action": "stop", onClick: onStop, size: "small", variant: "invisible" })) : isKernelBusy ? (_jsx(IconButton, { icon: PauseIcon, "aria-label": chatText.pauseKernelBusy, onClick: onStop, size: "small", variant: "invisible", disabled: !onStop })) : (_jsx(IconButton, { icon: PaperAirplaneIcon, "aria-label": chatText.send, onClick: onSend, disabled: sendDisabled, size: "small", variant: "invisible" }))] })] })] }));
|
|
15
17
|
}
|
|
16
18
|
export default InPromptFooter;
|
|
@@ -15,10 +15,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
15
15
|
import { useState } from 'react';
|
|
16
16
|
import { Box, Button, Text, CounterLabel } from '@primer/react';
|
|
17
17
|
import { ShieldCheckIcon, AlertIcon, CheckIcon, XIcon, } from '@primer/octicons-react';
|
|
18
|
+
import { useChatWords } from '../ChatLanguage';
|
|
18
19
|
/**
|
|
19
20
|
* Persistent banner for tool approval notifications.
|
|
20
21
|
*/
|
|
21
22
|
export function ToolApprovalBanner({ pendingApprovals, onReview, onApproveAll, onDismiss, collapsible = true, }) {
|
|
23
|
+
const chatText = useChatWords();
|
|
22
24
|
const [collapsed, setCollapsed] = useState(false);
|
|
23
25
|
if (pendingApprovals.length === 0) {
|
|
24
26
|
return null;
|
|
@@ -34,7 +36,7 @@ export function ToolApprovalBanner({ pendingApprovals, onReview, onApproveAll, o
|
|
|
34
36
|
borderBottom: '1px solid',
|
|
35
37
|
borderColor: 'attention.muted',
|
|
36
38
|
cursor: 'pointer',
|
|
37
|
-
}, onClick: () => setCollapsed(false), children: [_jsx(ShieldCheckIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children:
|
|
39
|
+
}, onClick: () => setCollapsed(false), children: [_jsx(ShieldCheckIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: chatText.toolApprovalsPending }), _jsx(CounterLabel, { children: pendingApprovals.length })] }));
|
|
38
40
|
}
|
|
39
41
|
return (_jsxs(Box, { sx: {
|
|
40
42
|
borderBottom: '1px solid',
|
|
@@ -46,7 +48,7 @@ export function ToolApprovalBanner({ pendingApprovals, onReview, onApproveAll, o
|
|
|
46
48
|
justifyContent: 'space-between',
|
|
47
49
|
px: 3,
|
|
48
50
|
py: 2,
|
|
49
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(AlertIcon, { size: 16 }),
|
|
51
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(AlertIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: chatText.approvalsPending(pendingApprovals.length) })] }), _jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [onApproveAll && pendingApprovals.length >= 1 && (_jsx(Button, { size: "small", variant: "primary", leadingVisual: CheckIcon, onClick: onApproveAll, children: chatText.approveAll })), collapsible && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setCollapsed(true), children: chatText.collapse })), onDismiss && (_jsx(Button, { size: "small", variant: "invisible", leadingVisual: XIcon, onClick: onDismiss, "aria-label": chatText.dismiss }))] })] }), _jsx(Box, { sx: { px: 3, pb: 2 }, children: pendingApprovals.map(approval => (_jsxs(Box, { sx: {
|
|
50
52
|
display: 'flex',
|
|
51
53
|
alignItems: 'center',
|
|
52
54
|
justifyContent: 'space-between',
|
|
@@ -57,6 +59,6 @@ export function ToolApprovalBanner({ pendingApprovals, onReview, onApproveAll, o
|
|
|
57
59
|
borderRadius: 2,
|
|
58
60
|
border: '1px solid',
|
|
59
61
|
borderColor: 'border.default',
|
|
60
|
-
}, children: [_jsxs(Box, { children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: approval.toolName }), approval.toolDescription && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 0, ml: 2 }, children: approval.toolDescription }))] }), _jsx(Button, { size: "small", variant: "default", onClick: () => onReview(approval), children:
|
|
62
|
+
}, children: [_jsxs(Box, { children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: approval.toolName }), approval.toolDescription && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 0, ml: 2 }, children: approval.toolDescription }))] }), _jsx(Button, { size: "small", variant: "default", onClick: () => onReview(approval), children: chatText.review })] }, approval.id))) })] }));
|
|
61
63
|
}
|
|
62
64
|
export default ToolApprovalBanner;
|
|
@@ -13,10 +13,12 @@ import { useCallback, useState } from 'react';
|
|
|
13
13
|
import { Box, Button, Text, Heading, FormControl, Checkbox, } from '@primer/react';
|
|
14
14
|
import { Dialog } from '@primer/react/experimental';
|
|
15
15
|
import { AlertIcon, ToolsIcon, CheckIcon, XIcon } from '@primer/octicons-react';
|
|
16
|
+
import { useChatWords } from '../ChatLanguage';
|
|
16
17
|
/**
|
|
17
18
|
* Tool Approval Dialog component
|
|
18
19
|
*/
|
|
19
20
|
export function ToolApprovalDialog({ isOpen, toolName, toolDescription, args, onApprove, onDeny, onClose, showRememberChoice = true, }) {
|
|
21
|
+
const chatText = useChatWords();
|
|
20
22
|
const [rememberChoice, setRememberChoice] = useState(false);
|
|
21
23
|
const handleApprove = useCallback(() => {
|
|
22
24
|
onApprove(rememberChoice);
|
|
@@ -27,12 +29,12 @@ export function ToolApprovalDialog({ isOpen, toolName, toolDescription, args, on
|
|
|
27
29
|
if (!isOpen) {
|
|
28
30
|
return null;
|
|
29
31
|
}
|
|
30
|
-
return (_jsxs(Dialog, { onClose: onClose, "aria-labelledby": "tool-approval-title", children: [_jsx(Dialog.Header, { children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(AlertIcon, { size: 16 }),
|
|
32
|
+
return (_jsxs(Dialog, { onClose: onClose, "aria-labelledby": "tool-approval-title", children: [_jsx(Dialog.Header, { children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(AlertIcon, { size: 16 }), chatText.approvalTitle] }) }), _jsxs(Box, { sx: { p: 3 }, children: [_jsxs(Box, { sx: { mb: 3 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2, mb: 2 }, children: [_jsx(ToolsIcon, { size: 20 }), _jsx(Heading, { as: "h4", sx: { fontSize: 2 }, children: toolName })] }), toolDescription && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: toolDescription }))] }), _jsxs(Box, { sx: { mb: 3 }, children: [_jsx(Text, { sx: {
|
|
31
33
|
fontWeight: 'semibold',
|
|
32
34
|
fontSize: 1,
|
|
33
35
|
mb: 2,
|
|
34
36
|
display: 'block',
|
|
35
|
-
}, children:
|
|
37
|
+
}, children: chatText.arguments }), _jsx(Box, { as: "pre", sx: {
|
|
36
38
|
p: 3,
|
|
37
39
|
bg: 'canvas.subtle',
|
|
38
40
|
borderRadius: 2,
|
|
@@ -48,7 +50,7 @@ export function ToolApprovalDialog({ isOpen, toolName, toolDescription, args, on
|
|
|
48
50
|
border: '1px solid',
|
|
49
51
|
borderColor: 'attention.muted',
|
|
50
52
|
mb: 3,
|
|
51
|
-
}, children: _jsx(Text, { sx: { fontSize: 1 }, children:
|
|
53
|
+
}, children: _jsx(Text, { sx: { fontSize: 1 }, children: chatText.approvalWarning }) }), showRememberChoice && (_jsxs(FormControl, { sx: { mb: 3 }, children: [_jsx(Checkbox, { checked: rememberChoice, onChange: e => setRememberChoice(e.target.checked) }), _jsx(FormControl.Label, { children: chatText.rememberChoice })] })), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', gap: 2 }, children: [_jsx(Button, { variant: "danger", onClick: handleDeny, leadingVisual: XIcon, children: chatText.deny }), _jsx(Button, { variant: "primary", onClick: handleApprove, leadingVisual: CheckIcon, children: chatText.approve })] })] })] }));
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* Hook to manage tool approval dialog state
|