@theia/ai-chat-ui 1.72.0-next.21 → 1.72.0-next.29
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/browser/chat-input-widget.js +1 -1
- package/lib/browser/chat-input-widget.js.map +1 -1
- package/lib/browser/chat-input-widget.spec.d.ts +2 -0
- package/lib/browser/chat-input-widget.spec.d.ts.map +1 -0
- package/lib/browser/chat-input-widget.spec.js +64 -0
- package/lib/browser/chat-input-widget.spec.js.map +1 -0
- package/lib/browser/chat-response-renderer/delegation-tool-renderer.d.ts +2 -1
- package/lib/browser/chat-response-renderer/delegation-tool-renderer.d.ts.map +1 -1
- package/lib/browser/chat-response-renderer/delegation-tool-renderer.js +14 -1
- package/lib/browser/chat-response-renderer/delegation-tool-renderer.js.map +1 -1
- package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts +10 -0
- package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts.map +1 -1
- package/lib/browser/chat-response-renderer/markdown-part-renderer.js +11 -6
- package/lib/browser/chat-response-renderer/markdown-part-renderer.js.map +1 -1
- package/lib/browser/chat-response-renderer/tool-confirmation.d.ts +6 -2
- package/lib/browser/chat-response-renderer/tool-confirmation.d.ts.map +1 -1
- package/lib/browser/chat-response-renderer/tool-confirmation.js +30 -8
- package/lib/browser/chat-response-renderer/tool-confirmation.js.map +1 -1
- package/lib/browser/chat-response-renderer/tool-confirmation.spec.js +60 -1
- package/lib/browser/chat-response-renderer/tool-confirmation.spec.js.map +1 -1
- package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts.map +1 -1
- package/lib/browser/chat-response-renderer/toolcall-part-renderer.js +5 -9
- package/lib/browser/chat-response-renderer/toolcall-part-renderer.js.map +1 -1
- package/package.json +11 -11
- package/src/browser/chat-input-widget.spec.ts +74 -0
- package/src/browser/chat-input-widget.tsx +1 -1
- package/src/browser/chat-response-renderer/delegation-tool-renderer.tsx +14 -7
- package/src/browser/chat-response-renderer/markdown-part-renderer.tsx +16 -7
- package/src/browser/chat-response-renderer/tool-confirmation.spec.ts +79 -3
- package/src/browser/chat-response-renderer/tool-confirmation.tsx +60 -10
- package/src/browser/chat-response-renderer/toolcall-part-renderer.tsx +8 -8
- package/src/browser/style/index.css +78 -68
|
@@ -26,7 +26,7 @@ import { ResponseNode } from '../chat-tree-view';
|
|
|
26
26
|
import { SubChatWidgetFactory } from '../chat-tree-view/sub-chat-widget';
|
|
27
27
|
import { withToolCallConfirmation } from './tool-confirmation';
|
|
28
28
|
import { extractJsonStringField } from './toolcall-utils';
|
|
29
|
-
import { CompositeTreeNode, ContextMenuRenderer } from '@theia/core/lib/browser';
|
|
29
|
+
import { CompositeTreeNode, ContextMenuRenderer, OpenerService } from '@theia/core/lib/browser';
|
|
30
30
|
import { ContributionProvider, DisposableCollection, nls } from '@theia/core';
|
|
31
31
|
import * as React from '@theia/core/shared/react';
|
|
32
32
|
|
|
@@ -51,6 +51,9 @@ export class DelegationToolRenderer implements ChatResponsePartRenderer<ToolCall
|
|
|
51
51
|
@inject(ContextMenuRenderer)
|
|
52
52
|
protected contextMenuRenderer: ContextMenuRenderer;
|
|
53
53
|
|
|
54
|
+
@inject(OpenerService)
|
|
55
|
+
protected openerService: OpenerService;
|
|
56
|
+
|
|
54
57
|
@inject(ContributionProvider) @named(ChatResponsePartRenderer)
|
|
55
58
|
protected chatResponsePartRenderers: ContributionProvider<ChatResponsePartRenderer<ChatResponseContent>>;
|
|
56
59
|
|
|
@@ -100,12 +103,16 @@ export class DelegationToolRenderer implements ChatResponsePartRenderer<ToolCall
|
|
|
100
103
|
subChatWidgetFactory={this.subChatWidgetFactory}
|
|
101
104
|
contextMenuRenderer={this.contextMenuRenderer}
|
|
102
105
|
chatResponsePartRenderers={this.chatResponsePartRenderers}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
toolConfirmation={{
|
|
107
|
+
response,
|
|
108
|
+
confirmationMode,
|
|
109
|
+
toolConfirmationManager: this.toolConfirmationManager,
|
|
110
|
+
toolRequest,
|
|
111
|
+
chatId,
|
|
112
|
+
requestCanceled: parentNode.response.isCanceled,
|
|
113
|
+
contextMenuRenderer: this.contextMenuRenderer,
|
|
114
|
+
openerService: this.openerService
|
|
115
|
+
}}
|
|
109
116
|
/>;
|
|
110
117
|
}
|
|
111
118
|
}
|
|
@@ -30,6 +30,21 @@ import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
|
|
|
30
30
|
import { OpenerService, open } from '@theia/core/lib/browser';
|
|
31
31
|
import { URI } from '@theia/core';
|
|
32
32
|
|
|
33
|
+
export interface MarkdownRenderProps {
|
|
34
|
+
text: string | MarkdownString;
|
|
35
|
+
openerService: OpenerService;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Renders the given markdown via {@link useMarkdownRendering} into a `<div>`.
|
|
41
|
+
* Shared component for use across chat response renderers.
|
|
42
|
+
*/
|
|
43
|
+
export const MarkdownRender: React.FC<MarkdownRenderProps> = ({ text, openerService, className }) => {
|
|
44
|
+
const ref = useMarkdownRendering(text, openerService);
|
|
45
|
+
return <div className={className} ref={ref}></div>;
|
|
46
|
+
};
|
|
47
|
+
|
|
33
48
|
@injectable()
|
|
34
49
|
export class MarkdownPartRenderer implements ChatResponsePartRenderer<MarkdownChatResponseContent | InformationalChatResponseContent> {
|
|
35
50
|
@inject(OpenerService) protected readonly openerService: OpenerService;
|
|
@@ -51,16 +66,10 @@ export class MarkdownPartRenderer implements ChatResponsePartRenderer<MarkdownCh
|
|
|
51
66
|
return null;
|
|
52
67
|
}
|
|
53
68
|
|
|
54
|
-
return <MarkdownRender
|
|
69
|
+
return <MarkdownRender text={response.content} openerService={this.openerService} />;
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
72
|
|
|
58
|
-
const MarkdownRender = ({ response, openerService }: { response: MarkdownChatResponseContent | InformationalChatResponseContent; openerService: OpenerService }) => {
|
|
59
|
-
const ref = useMarkdownRendering(response.content, openerService);
|
|
60
|
-
|
|
61
|
-
return <div ref={ref}></div>;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
73
|
export interface DeclaredEventsEventListenerObject extends EventListenerObject {
|
|
65
74
|
handledEvents?: (keyof HTMLElementEventMap)[];
|
|
66
75
|
}
|
|
@@ -14,12 +14,31 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
+
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
18
|
+
|
|
19
|
+
let disableJSDOM = enableJSDOM();
|
|
20
|
+
|
|
17
21
|
import { expect } from 'chai';
|
|
18
|
-
import { ContextMenuRenderer } from '@theia/core/lib/browser';
|
|
22
|
+
import { ContextMenuRenderer, OpenerService } from '@theia/core/lib/browser';
|
|
19
23
|
import { ToolCallChatResponseContent } from '@theia/ai-chat/lib/common';
|
|
20
|
-
import {
|
|
24
|
+
import { ToolConfirmationMode as ToolConfirmationPreferenceMode } from '@theia/ai-chat/lib/common/chat-tool-preferences';
|
|
25
|
+
import { ToolConfirmationManager } from '@theia/ai-chat/lib/browser/chat-tool-preference-bindings';
|
|
26
|
+
import { flushSync } from '@theia/core/shared/react-dom';
|
|
27
|
+
import { createRoot } from '@theia/core/shared/react-dom/client';
|
|
28
|
+
import * as React from '@theia/core/shared/react';
|
|
29
|
+
import {
|
|
30
|
+
ConfirmationScope,
|
|
31
|
+
CountdownTimerProps,
|
|
32
|
+
ToolConfirmationCallbacks,
|
|
33
|
+
ToolConfirmationActionsProps,
|
|
34
|
+
ToolConfirmationProps,
|
|
35
|
+
withToolCallConfirmation
|
|
36
|
+
} from './tool-confirmation';
|
|
21
37
|
|
|
22
38
|
const mockContextMenuRenderer = {} as ContextMenuRenderer;
|
|
39
|
+
const mockOpenerService = {} as OpenerService;
|
|
40
|
+
|
|
41
|
+
disableJSDOM();
|
|
23
42
|
|
|
24
43
|
describe('Tool Confirmation Types', () => {
|
|
25
44
|
describe('ConfirmationScope', () => {
|
|
@@ -109,15 +128,72 @@ describe('Tool Confirmation Types', () => {
|
|
|
109
128
|
});
|
|
110
129
|
});
|
|
111
130
|
|
|
131
|
+
describe('withToolCallConfirmation', () => {
|
|
132
|
+
before(() => {
|
|
133
|
+
disableJSDOM = enableJSDOM();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
after(() => {
|
|
137
|
+
disableJSDOM();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should pass opener service through to the wrapped component', () => {
|
|
141
|
+
const Wrapped: React.FC<{ openerService: OpenerService }> = ({ openerService }) =>
|
|
142
|
+
React.createElement('span', undefined, openerService === mockOpenerService ? 'passed' : 'missing');
|
|
143
|
+
const WrappedWithConfirmation = withToolCallConfirmation(Wrapped);
|
|
144
|
+
const container = document.createElement('div');
|
|
145
|
+
const root = createRoot(container);
|
|
146
|
+
const response = {
|
|
147
|
+
kind: 'toolCall',
|
|
148
|
+
id: 'test',
|
|
149
|
+
name: 'test',
|
|
150
|
+
finished: true,
|
|
151
|
+
confirmed: Promise.resolve(true),
|
|
152
|
+
needsUserConfirmation: Promise.resolve(),
|
|
153
|
+
confirm: () => { },
|
|
154
|
+
deny: () => { }
|
|
155
|
+
} as ToolCallChatResponseContent;
|
|
156
|
+
|
|
157
|
+
flushSync(() => root.render(React.createElement(WrappedWithConfirmation, {
|
|
158
|
+
openerService: mockOpenerService,
|
|
159
|
+
toolConfirmation: {
|
|
160
|
+
response,
|
|
161
|
+
confirmationMode: ToolConfirmationPreferenceMode.CONFIRM,
|
|
162
|
+
toolConfirmationManager: {} as ToolConfirmationManager,
|
|
163
|
+
chatId: 'test-chat',
|
|
164
|
+
requestCanceled: false,
|
|
165
|
+
contextMenuRenderer: mockContextMenuRenderer,
|
|
166
|
+
openerService: mockOpenerService
|
|
167
|
+
}
|
|
168
|
+
})));
|
|
169
|
+
|
|
170
|
+
expect(container.textContent).to.equal('passed');
|
|
171
|
+
root.unmount();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
112
175
|
describe('ToolConfirmationProps', () => {
|
|
113
176
|
it('should pick toolRequest from ToolConfirmationCallbacks', () => {
|
|
114
177
|
const props: ToolConfirmationProps = {
|
|
115
178
|
response: { kind: 'toolCall', id: 'test', name: 'test' } as ToolConfirmationProps['response'],
|
|
116
179
|
onAllow: () => { },
|
|
117
180
|
onDeny: () => { },
|
|
118
|
-
contextMenuRenderer: mockContextMenuRenderer
|
|
181
|
+
contextMenuRenderer: mockContextMenuRenderer,
|
|
182
|
+
openerService: mockOpenerService
|
|
119
183
|
};
|
|
120
184
|
expect(props.toolRequest).to.be.undefined;
|
|
121
185
|
});
|
|
186
|
+
|
|
187
|
+
it('should accept response arguments with an opener service', () => {
|
|
188
|
+
const props: ToolConfirmationProps = {
|
|
189
|
+
response: { kind: 'toolCall', id: 'test', name: 'test', arguments: '{"foo":"bar"}' } as ToolConfirmationProps['response'],
|
|
190
|
+
onAllow: () => { },
|
|
191
|
+
onDeny: () => { },
|
|
192
|
+
contextMenuRenderer: mockContextMenuRenderer,
|
|
193
|
+
openerService: mockOpenerService
|
|
194
|
+
};
|
|
195
|
+
expect(props.response.arguments).to.equal('{"foo":"bar"}');
|
|
196
|
+
expect(props.openerService).to.equal(mockOpenerService);
|
|
197
|
+
});
|
|
122
198
|
});
|
|
123
199
|
});
|
|
@@ -16,13 +16,15 @@
|
|
|
16
16
|
|
|
17
17
|
import * as React from '@theia/core/shared/react';
|
|
18
18
|
import { nls } from '@theia/core/lib/common/nls';
|
|
19
|
-
import { codicon, ContextMenuRenderer } from '@theia/core/lib/browser';
|
|
19
|
+
import { codicon, ContextMenuRenderer, OpenerService } from '@theia/core/lib/browser';
|
|
20
20
|
import { ToolCallChatResponseContent } from '@theia/ai-chat/lib/common';
|
|
21
21
|
import { ToolRequest } from '@theia/ai-core';
|
|
22
22
|
import { CommandMenu, ContextExpressionMatcher, MenuPath } from '@theia/core/lib/common/menu';
|
|
23
23
|
import { GroupImpl } from '@theia/core/lib/browser/menu/composite-menu-node';
|
|
24
24
|
import { ToolConfirmationMode as ToolConfirmationPreferenceMode } from '@theia/ai-chat/lib/common/chat-tool-preferences';
|
|
25
25
|
import { ToolConfirmationManager } from '@theia/ai-chat/lib/browser/chat-tool-preference-bindings';
|
|
26
|
+
import { MarkdownRender } from './markdown-part-renderer';
|
|
27
|
+
import { condenseArguments, formatArgsForTooltip } from './toolcall-utils';
|
|
26
28
|
|
|
27
29
|
export interface CountdownTimerProps {
|
|
28
30
|
response: ToolCallChatResponseContent;
|
|
@@ -430,9 +432,10 @@ export interface ToolConfirmationProps extends Pick<ToolConfirmationCallbacks, '
|
|
|
430
432
|
onAllow: (scope?: ConfirmationScope) => void;
|
|
431
433
|
onDeny: (scope?: ConfirmationScope, reason?: string) => void;
|
|
432
434
|
contextMenuRenderer: ContextMenuRenderer;
|
|
435
|
+
openerService: OpenerService;
|
|
433
436
|
}
|
|
434
437
|
|
|
435
|
-
export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({ response, toolRequest, onAllow, onDeny, contextMenuRenderer }) => {
|
|
438
|
+
export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({ response, toolRequest, onAllow, onDeny, contextMenuRenderer, openerService }) => {
|
|
436
439
|
const [state, setState] = React.useState<ToolConfirmationState>('waiting');
|
|
437
440
|
|
|
438
441
|
const handleAllow = React.useCallback((scope: ConfirmationScope) => {
|
|
@@ -461,16 +464,30 @@ export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({ response, to
|
|
|
461
464
|
);
|
|
462
465
|
}
|
|
463
466
|
|
|
467
|
+
const toolNameContent = (
|
|
468
|
+
<>
|
|
469
|
+
<span className="label">{nls.localizeByDefault('Tool')}:</span>
|
|
470
|
+
<span className="value">{response.name}</span>
|
|
471
|
+
</>
|
|
472
|
+
);
|
|
473
|
+
|
|
464
474
|
return (
|
|
465
475
|
<div className="theia-tool-confirmation">
|
|
466
476
|
<div className="theia-tool-confirmation-header">
|
|
467
477
|
<span className={codicon('shield')}></span> {nls.localize('theia/ai/chat-ui/toolconfirmation/header', 'Confirm Tool Execution')}
|
|
468
478
|
</div>
|
|
469
479
|
<div className="theia-tool-confirmation-info">
|
|
470
|
-
|
|
471
|
-
<
|
|
472
|
-
|
|
473
|
-
|
|
480
|
+
{toolRequest?.description ? (
|
|
481
|
+
<details className="theia-tool-confirmation-name">
|
|
482
|
+
<summary>{toolNameContent}</summary>
|
|
483
|
+
<div className="theia-tool-confirmation-description">
|
|
484
|
+
{toolRequest.description}
|
|
485
|
+
</div>
|
|
486
|
+
</details>
|
|
487
|
+
) : (
|
|
488
|
+
<div className="theia-tool-confirmation-name">{toolNameContent}</div>
|
|
489
|
+
)}
|
|
490
|
+
<ToolArgsDisplay args={response.arguments} openerService={openerService} />
|
|
474
491
|
</div>
|
|
475
492
|
<ToolConfirmationActions
|
|
476
493
|
toolName={response.name ?? 'unknown'}
|
|
@@ -484,6 +501,33 @@ export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({ response, to
|
|
|
484
501
|
);
|
|
485
502
|
};
|
|
486
503
|
|
|
504
|
+
interface ToolArgsDisplayProps {
|
|
505
|
+
args: string | undefined;
|
|
506
|
+
openerService: OpenerService;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const ToolArgsDisplay: React.FC<ToolArgsDisplayProps> = ({ args, openerService }) => {
|
|
510
|
+
const trimmedArgs = args?.trim();
|
|
511
|
+
if (!trimmedArgs || trimmedArgs === '{}') {
|
|
512
|
+
// eslint-disable-next-line no-null/no-null
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
const summaryLabel = condenseArguments(trimmedArgs) ?? '\u2026';
|
|
516
|
+
return (
|
|
517
|
+
<details className="theia-tool-confirmation-args">
|
|
518
|
+
<summary>
|
|
519
|
+
<span className="label">{nls.localizeByDefault('Arguments')}:</span>
|
|
520
|
+
<span className="theia-tool-confirmation-args-summary">{summaryLabel}</span>
|
|
521
|
+
</summary>
|
|
522
|
+
<MarkdownRender
|
|
523
|
+
text={formatArgsForTooltip(trimmedArgs)}
|
|
524
|
+
openerService={openerService}
|
|
525
|
+
className="theia-tool-confirmation-args-content"
|
|
526
|
+
/>
|
|
527
|
+
</details>
|
|
528
|
+
);
|
|
529
|
+
};
|
|
530
|
+
|
|
487
531
|
export interface WithToolCallConfirmationProps {
|
|
488
532
|
response: ToolCallChatResponseContent;
|
|
489
533
|
confirmationMode: ToolConfirmationPreferenceMode;
|
|
@@ -494,12 +538,17 @@ export interface WithToolCallConfirmationProps {
|
|
|
494
538
|
showArgsTooltip?: (response: ToolCallChatResponseContent, target: HTMLElement | undefined) => void;
|
|
495
539
|
requestCanceled: boolean;
|
|
496
540
|
contextMenuRenderer: ContextMenuRenderer;
|
|
541
|
+
openerService: OpenerService;
|
|
497
542
|
}
|
|
498
543
|
|
|
499
544
|
export function withToolCallConfirmation<P extends object>(
|
|
500
545
|
WrappedComponent: React.ComponentType<P>
|
|
501
|
-
): React.FC<P & WithToolCallConfirmationProps> {
|
|
502
|
-
const WithConfirmation: React.FC<P & WithToolCallConfirmationProps> = props => {
|
|
546
|
+
): React.FC<P & { toolConfirmation: WithToolCallConfirmationProps }> {
|
|
547
|
+
const WithConfirmation: React.FC<P & { toolConfirmation: WithToolCallConfirmationProps }> = props => {
|
|
548
|
+
const {
|
|
549
|
+
toolConfirmation,
|
|
550
|
+
...componentProps
|
|
551
|
+
} = props;
|
|
503
552
|
const {
|
|
504
553
|
response,
|
|
505
554
|
confirmationMode,
|
|
@@ -510,8 +559,8 @@ export function withToolCallConfirmation<P extends object>(
|
|
|
510
559
|
showArgsTooltip,
|
|
511
560
|
requestCanceled,
|
|
512
561
|
contextMenuRenderer,
|
|
513
|
-
|
|
514
|
-
} =
|
|
562
|
+
openerService
|
|
563
|
+
} = toolConfirmation;
|
|
515
564
|
|
|
516
565
|
const { confirmationState } = useToolConfirmationState(response, confirmationMode);
|
|
517
566
|
const pendingRef = React.useRef<HTMLElement | undefined>(undefined);
|
|
@@ -572,6 +621,7 @@ export function withToolCallConfirmation<P extends object>(
|
|
|
572
621
|
onAllow={handleAllow}
|
|
573
622
|
onDeny={handleDeny}
|
|
574
623
|
contextMenuRenderer={contextMenuRenderer}
|
|
624
|
+
openerService={openerService}
|
|
575
625
|
/>
|
|
576
626
|
);
|
|
577
627
|
}
|
|
@@ -24,7 +24,7 @@ import * as React from '@theia/core/shared/react';
|
|
|
24
24
|
import { createConfirmationHandlers, ToolConfirmation, useToolConfirmationState } from './tool-confirmation';
|
|
25
25
|
import { ToolConfirmationMode } from '@theia/ai-chat/lib/common/chat-tool-preferences';
|
|
26
26
|
import { ResponseNode } from '../chat-tree-view';
|
|
27
|
-
import {
|
|
27
|
+
import { MarkdownRender } from './markdown-part-renderer';
|
|
28
28
|
import { ToolCallResult, ToolInvocationRegistry, ToolRequest } from '@theia/ai-core';
|
|
29
29
|
import { ToolConfirmationManager } from '@theia/ai-chat/lib/browser/chat-tool-preference-bindings';
|
|
30
30
|
import { condenseArguments, formatArgsForTooltip } from './toolcall-utils';
|
|
@@ -67,6 +67,7 @@ export class ToolCallPartRenderer implements ChatResponsePartRenderer<ToolCallCh
|
|
|
67
67
|
onAllow={handleAllow}
|
|
68
68
|
onDeny={handleDeny}
|
|
69
69
|
contextMenuRenderer={this.contextMenuRenderer}
|
|
70
|
+
openerService={this.openerService}
|
|
70
71
|
/>;
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -84,7 +85,8 @@ export class ToolCallPartRenderer implements ChatResponsePartRenderer<ToolCallCh
|
|
|
84
85
|
showArgsTooltip={this.showArgsTooltip.bind(this)}
|
|
85
86
|
responseRenderer={this.renderResult.bind(this)}
|
|
86
87
|
requestCanceled={parentNode.response.isCanceled}
|
|
87
|
-
contextMenuRenderer={this.contextMenuRenderer}
|
|
88
|
+
contextMenuRenderer={this.contextMenuRenderer}
|
|
89
|
+
openerService={this.openerService} />;
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
protected renderResult(response: ToolCallChatResponseContent): ReactNode {
|
|
@@ -185,6 +187,7 @@ interface ToolCallContentProps {
|
|
|
185
187
|
responseRenderer: (response: ToolCallChatResponseContent) => ReactNode | undefined;
|
|
186
188
|
requestCanceled: boolean;
|
|
187
189
|
contextMenuRenderer: ContextMenuRenderer;
|
|
190
|
+
openerService: OpenerService;
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
/**
|
|
@@ -200,7 +203,8 @@ const ToolCallContent: React.FC<ToolCallContentProps> = ({
|
|
|
200
203
|
getArgumentsLabel,
|
|
201
204
|
requestCanceled,
|
|
202
205
|
showArgsTooltip,
|
|
203
|
-
contextMenuRenderer
|
|
206
|
+
contextMenuRenderer,
|
|
207
|
+
openerService
|
|
204
208
|
}) => {
|
|
205
209
|
const { confirmationState, rejectionReason } = useToolConfirmationState(response, confirmationMode);
|
|
206
210
|
const summaryRef = React.useRef<HTMLElement | undefined>(undefined);
|
|
@@ -290,14 +294,10 @@ const ToolCallContent: React.FC<ToolCallContentProps> = ({
|
|
|
290
294
|
onAllow={handleAllow}
|
|
291
295
|
onDeny={handleDeny}
|
|
292
296
|
contextMenuRenderer={contextMenuRenderer}
|
|
297
|
+
openerService={openerService}
|
|
293
298
|
/>
|
|
294
299
|
</span>
|
|
295
300
|
)}
|
|
296
301
|
</div>
|
|
297
302
|
);
|
|
298
303
|
};
|
|
299
|
-
|
|
300
|
-
const MarkdownRender = ({ text, openerService }: { text: string; openerService: OpenerService }) => {
|
|
301
|
-
const ref = useMarkdownRendering(text, openerService);
|
|
302
|
-
return <div ref={ref}></div>;
|
|
303
|
-
};
|
|
@@ -50,6 +50,7 @@ div:last-child>.theia-ChatNode {
|
|
|
50
50
|
|
|
51
51
|
.theia-ChatNodeHeader .theia-ChatContentInProgress {
|
|
52
52
|
color: var(--theia-disabledForeground);
|
|
53
|
+
white-space: nowrap;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
.theia-ChatNodeHeader .theia-ChatContentInProgress-Cancel {
|
|
@@ -82,6 +83,9 @@ div:last-child>.theia-ChatNode {
|
|
|
82
83
|
.theia-ChatNodeHeader .theia-ChatContentInProgress::after {
|
|
83
84
|
content: "";
|
|
84
85
|
animation: dots 1s steps(1, end) infinite;
|
|
86
|
+
display: inline-block;
|
|
87
|
+
width: 3ch;
|
|
88
|
+
text-align: left;
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
.theia-ChatNode .codicon {
|
|
@@ -984,6 +988,7 @@ div:last-child>.theia-ChatNode {
|
|
|
984
988
|
border-radius: 4px;
|
|
985
989
|
background-color: var(--theia-editorWidget-background);
|
|
986
990
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.14);
|
|
991
|
+
cursor: default;
|
|
987
992
|
}
|
|
988
993
|
|
|
989
994
|
.theia-tool-confirmation-header {
|
|
@@ -1010,19 +1015,65 @@ div:last-child>.theia-ChatNode {
|
|
|
1010
1015
|
margin-right: 6px;
|
|
1011
1016
|
}
|
|
1012
1017
|
|
|
1013
|
-
.theia-tool-confirmation-
|
|
1014
|
-
margin: 6px 0;
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1018
|
+
.theia-tool-confirmation-description {
|
|
1019
|
+
margin: 6px 0 8px 0;
|
|
1020
|
+
color: var(--theia-descriptionForeground);
|
|
1021
|
+
font-weight: normal;
|
|
1022
|
+
max-height: 200px;
|
|
1023
|
+
overflow: auto;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
details.theia-tool-confirmation-name>summary,
|
|
1027
|
+
details.theia-tool-confirmation-args>summary {
|
|
1028
|
+
cursor: pointer;
|
|
1029
|
+
user-select: none;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
details.theia-tool-confirmation-name>summary::marker,
|
|
1033
|
+
details.theia-tool-confirmation-args>summary::marker {
|
|
1034
|
+
color: var(--theia-button-background);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.theia-tool-confirmation-args-summary {
|
|
1038
|
+
color: var(--theia-descriptionForeground);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
.theia-tool-confirmation-args-content {
|
|
1042
|
+
margin: var(--theia-ui-padding) 0;
|
|
1043
|
+
padding: var(--theia-ui-padding) calc(var(--theia-ui-padding) * 2);
|
|
1044
|
+
max-height: 200px;
|
|
1019
1045
|
overflow: auto;
|
|
1020
1046
|
}
|
|
1021
1047
|
|
|
1048
|
+
.theia-tool-confirmation-args-content p {
|
|
1049
|
+
margin: var(--theia-ui-padding) 0;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.theia-tool-confirmation-args-content pre {
|
|
1053
|
+
margin: var(--theia-ui-padding) 0;
|
|
1054
|
+
padding: var(--theia-ui-padding) calc(var(--theia-ui-padding) * 2);
|
|
1055
|
+
background-color: var(--theia-textCodeBlock-background);
|
|
1056
|
+
border-radius: 3px;
|
|
1057
|
+
white-space: pre-wrap;
|
|
1058
|
+
word-break: break-word;
|
|
1059
|
+
font-weight: normal;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
.theia-tool-confirmation-args-content code {
|
|
1063
|
+
word-break: break-word;
|
|
1064
|
+
font-weight: normal;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.theia-tool-confirmation-args-content hr {
|
|
1068
|
+
border-top: 1px solid var(--theia-editorHoverWidgetInternalBorder);
|
|
1069
|
+
border-bottom: 0;
|
|
1070
|
+
margin: var(--theia-ui-padding) 0;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1022
1073
|
.theia-tool-confirmation-actions {
|
|
1023
1074
|
display: flex;
|
|
1024
1075
|
justify-content: flex-end;
|
|
1025
|
-
gap:
|
|
1076
|
+
gap: 8px;
|
|
1026
1077
|
}
|
|
1027
1078
|
|
|
1028
1079
|
.theia-tool-confirmation-split-button {
|
|
@@ -1080,69 +1131,24 @@ div:last-child>.theia-ChatNode {
|
|
|
1080
1131
|
|
|
1081
1132
|
.theia-tool-confirmation-status {
|
|
1082
1133
|
margin: 10px 0;
|
|
1083
|
-
padding:
|
|
1134
|
+
padding: 8px;
|
|
1084
1135
|
border: 1px solid var(--theia-dropdown-border);
|
|
1085
1136
|
border-radius: 4px;
|
|
1086
1137
|
background-color: var(--theia-editorWidget-background);
|
|
1087
1138
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.14);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
.theia-tool-confirmation-header {
|
|
1091
|
-
font-weight: bold;
|
|
1092
|
-
margin-bottom: 8px;
|
|
1093
|
-
color: var(--theia-foreground);
|
|
1094
|
-
display: flex;
|
|
1095
|
-
align-items: center;
|
|
1096
|
-
gap: 6px;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
.theia-tool-confirmation-info {
|
|
1100
|
-
margin-bottom: 12px;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
.theia-tool-confirmation-name,
|
|
1104
|
-
.theia-tool-confirmation-args {
|
|
1105
|
-
margin-bottom: 4px;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
.theia-tool-confirmation-name .label,
|
|
1109
|
-
.theia-tool-confirmation-args .label {
|
|
1110
|
-
font-weight: bold;
|
|
1111
|
-
margin-right: 6px;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
.theia-tool-confirmation-args pre.value {
|
|
1115
|
-
margin: 6px 0;
|
|
1116
|
-
padding: 8px;
|
|
1117
|
-
background-color: var(--theia-editor-background);
|
|
1118
|
-
border-radius: 3px;
|
|
1119
|
-
max-height: 150px;
|
|
1120
|
-
overflow: auto;
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
.theia-tool-confirmation-actions {
|
|
1124
|
-
display: flex;
|
|
1125
|
-
justify-content: flex-end;
|
|
1126
|
-
gap: 8px;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
.theia-tool-confirmation-status {
|
|
1130
|
-
padding: 8px;
|
|
1131
|
-
margin: 10px 0;
|
|
1132
|
-
border-radius: 4px;
|
|
1133
1139
|
display: flex;
|
|
1134
1140
|
align-items: center;
|
|
1135
1141
|
gap: 6px;
|
|
1136
1142
|
}
|
|
1137
1143
|
|
|
1138
|
-
.theia-tool-confirmation-status.
|
|
1139
|
-
|
|
1140
|
-
color: var(--theia-
|
|
1144
|
+
.theia-tool-confirmation-status.allowed {
|
|
1145
|
+
border-color: var(--theia-successBackground);
|
|
1146
|
+
color: var(--theia-successBackground);
|
|
1141
1147
|
}
|
|
1142
1148
|
|
|
1143
1149
|
.theia-tool-confirmation-status.denied {
|
|
1144
|
-
|
|
1145
|
-
color: var(--theia-
|
|
1150
|
+
border-color: var(--theia-errorBackground);
|
|
1151
|
+
color: var(--theia-errorBackground);
|
|
1146
1152
|
}
|
|
1147
1153
|
|
|
1148
1154
|
.theia-toolCall-denied,
|
|
@@ -1593,38 +1599,42 @@ div:last-child>.theia-ChatNode {
|
|
|
1593
1599
|
}
|
|
1594
1600
|
|
|
1595
1601
|
/* Scrollable hover for large tool call arguments */
|
|
1596
|
-
.theia-hover.toolcall-args-hover
|
|
1602
|
+
.theia-hover.toolcall-args-hover>div {
|
|
1597
1603
|
max-height: 400px;
|
|
1598
1604
|
max-width: 600px;
|
|
1599
1605
|
overflow-y: auto;
|
|
1600
1606
|
overflow-x: hidden;
|
|
1601
1607
|
}
|
|
1602
1608
|
|
|
1603
|
-
/* Code blocks inside tool call hovers: constrain and scroll.
|
|
1604
|
-
|
|
1605
|
-
not as <pre> elements, so we target both structures. */
|
|
1606
|
-
.theia-hover.toolcall-args-hover div.rendered-markdown pre,
|
|
1607
|
-
.theia-hover.toolcall-args-hover div.rendered-markdown div[data-code] {
|
|
1609
|
+
/* Code blocks inside tool call hovers: constrain and scroll. */
|
|
1610
|
+
.theia-hover.toolcall-args-hover pre {
|
|
1608
1611
|
max-height: 200px;
|
|
1609
1612
|
overflow: auto;
|
|
1610
|
-
white-space: pre;
|
|
1613
|
+
white-space: pre-wrap;
|
|
1614
|
+
word-break: break-word;
|
|
1611
1615
|
margin: var(--theia-ui-padding) 0;
|
|
1612
1616
|
padding: var(--theia-ui-padding) calc(var(--theia-ui-padding) * 2);
|
|
1613
1617
|
border-radius: 3px;
|
|
1614
1618
|
background-color: var(--theia-textCodeBlock-background);
|
|
1615
1619
|
}
|
|
1616
1620
|
|
|
1621
|
+
/* Reset code background inside pre to avoid double semi-transparent layers
|
|
1622
|
+
(.theia-hover code in hover-service.css sets the same background) */
|
|
1623
|
+
.theia-hover.toolcall-args-hover pre code {
|
|
1624
|
+
background-color: transparent;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1617
1627
|
/* Inline code styling */
|
|
1618
|
-
.theia-hover.toolcall-args-hover
|
|
1628
|
+
.theia-hover.toolcall-args-hover code:not(pre code) {
|
|
1619
1629
|
padding: 1px var(--theia-ui-padding);
|
|
1620
1630
|
border-radius: 3px;
|
|
1621
1631
|
background-color: var(--theia-textCodeBlock-background);
|
|
1622
1632
|
word-break: break-all;
|
|
1623
|
-
font-family: var(--theia-
|
|
1633
|
+
font-family: var(--theia-code-font-family);
|
|
1624
1634
|
}
|
|
1625
1635
|
|
|
1626
1636
|
/* Spacing between arg sections - uses internal border like hover-service.css */
|
|
1627
|
-
.theia-hover.toolcall-args-hover
|
|
1637
|
+
.theia-hover.toolcall-args-hover hr {
|
|
1628
1638
|
border-top: 1px solid var(--theia-editorHoverWidgetInternalBorder);
|
|
1629
1639
|
border-bottom: 0;
|
|
1630
1640
|
margin: var(--theia-ui-padding) 0;
|