@aws/nx-plugin 0.104.1 → 0.106.0
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/LICENSE-THIRD-PARTY +406 -436
- package/package.json +12 -12
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +21 -21
- package/src/mcp-server/tools/create-workspace-command.js +9 -5
- package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
- package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +438 -0
- package/src/open-api/ts-client/files/client.gen.ts.template +20 -0
- package/src/open-api/utils/codegen-data/languages.js +7 -3
- package/src/open-api/utils/codegen-data/languages.js.map +1 -1
- package/src/open-api/utils/normalise.js +17 -0
- package/src/open-api/utils/normalise.js.map +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +4 -4
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +4 -4
- package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +9 -9
- package/src/py/strands-agent/react-connection/__snapshots__/generator.spec.ts.snap +129 -4
- package/src/py/strands-agent/react-connection/serve-local.js +1 -1
- package/src/py/strands-agent/react-connection/serve-local.js.map +1 -1
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +4 -1
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +3 -1
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/ts/mcp-server/generator.js +1 -0
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/CloudscapeAssistantMessage.tsx.template +71 -0
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/CloudscapeChatInput.tsx.template +65 -0
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/CloudscapeCursor.tsx.template +10 -0
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/CloudscapeUserMessage.tsx.template +42 -0
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/copilot.css.template +128 -0
- package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/index.tsx.template +46 -0
- package/src/ts/react-website/agui/files/{src → common/src}/components/AguiProvider.tsx.template +10 -2
- package/src/ts/react-website/agui/files/default/src/components/copilot/index.tsx.template +5 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnAssistantMessage.tsx.template +71 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnChatInput.tsx.template +117 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnCursor.tsx.template +23 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnUserMessage.tsx.template +49 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/copilot.css.template +116 -0
- package/src/ts/react-website/agui/files/shadcn/src/components/copilot/index.tsx.template +46 -0
- package/src/ts/react-website/agui/generator.d.ts +3 -0
- package/src/ts/react-website/agui/generator.js +28 -1
- package/src/ts/react-website/agui/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +42 -38
- package/src/ts/strands-agent/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/strands-agent/generator.js +1 -0
- package/src/ts/strands-agent/generator.js.map +1 -1
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +1 -1
- package/src/utils/files/common/shadcn/src/components/ui/avatar.tsx.template +53 -0
- package/src/utils/files/common/shadcn/src/components/ui/textarea.tsx.template +18 -0
- package/src/utils/files/website/hooks/sigv4/useSigV4.tsx.template +4 -1
- package/src/utils/versions.d.ts +59 -58
- package/src/utils/versions.js +58 -57
- package/src/utils/versions.js.map +1 -1
- /package/src/ts/react-website/agui/files/{src → common/src}/hooks/useAgui__agentNameClassName__.tsx.template +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
CopilotChatInput,
|
|
4
|
+
type CopilotChatInputProps,
|
|
5
|
+
} from '@copilotkit/react-core/v2';
|
|
6
|
+
import PromptInput from '@cloudscape-design/components/prompt-input';
|
|
7
|
+
|
|
8
|
+
const CloudscapeChatInputImpl = ({
|
|
9
|
+
value,
|
|
10
|
+
onChange,
|
|
11
|
+
onSubmitMessage,
|
|
12
|
+
onStop,
|
|
13
|
+
isRunning,
|
|
14
|
+
autoFocus,
|
|
15
|
+
mode,
|
|
16
|
+
}: CopilotChatInputProps) => {
|
|
17
|
+
const [internalValue, setInternalValue] = useState('');
|
|
18
|
+
const currentValue = value ?? internalValue;
|
|
19
|
+
const disabled = mode === 'processing';
|
|
20
|
+
|
|
21
|
+
const handleChange = (next: string) => {
|
|
22
|
+
onChange?.(next);
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
setInternalValue(next);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleAction = () => {
|
|
29
|
+
if (isRunning) {
|
|
30
|
+
onStop?.();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const trimmed = currentValue.trim();
|
|
34
|
+
if (!trimmed) return;
|
|
35
|
+
onSubmitMessage?.(trimmed);
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
setInternalValue('');
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="copilotkit-cloudscape-input">
|
|
43
|
+
<PromptInput
|
|
44
|
+
value={currentValue}
|
|
45
|
+
onChange={({ detail }) => handleChange(detail.value)}
|
|
46
|
+
onAction={handleAction}
|
|
47
|
+
actionButtonAriaLabel={isRunning ? 'Stop' : 'Send message'}
|
|
48
|
+
actionButtonIconName={isRunning ? 'close' : 'send'}
|
|
49
|
+
ariaLabel="Chat input"
|
|
50
|
+
placeholder="Ask me anything..."
|
|
51
|
+
autoFocus={autoFocus}
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
minRows={2}
|
|
54
|
+
maxRows={6}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const CloudscapeChatInput = Object.assign(
|
|
61
|
+
CloudscapeChatInputImpl,
|
|
62
|
+
CopilotChatInput,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export default CloudscapeChatInput;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CopilotChatMessageView } from '@copilotkit/react-core/v2';
|
|
2
|
+
import LoadingBar from '@cloudscape-design/chat-components/loading-bar';
|
|
3
|
+
|
|
4
|
+
export const CloudscapeCursor: typeof CopilotChatMessageView.Cursor = () => (
|
|
5
|
+
<div aria-label="Generating response" role="status">
|
|
6
|
+
<LoadingBar variant="gen-ai-masked" />
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export default CloudscapeCursor;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CopilotChatUserMessage } from '@copilotkit/react-core/v2';
|
|
2
|
+
import type { CopilotChatUserMessageProps } from '@copilotkit/react-core/v2';
|
|
3
|
+
import ChatBubble from '@cloudscape-design/chat-components/chat-bubble';
|
|
4
|
+
import Avatar from '@cloudscape-design/chat-components/avatar';
|
|
5
|
+
|
|
6
|
+
const flattenContent = (
|
|
7
|
+
content: CopilotChatUserMessageProps['message']['content'],
|
|
8
|
+
): string => {
|
|
9
|
+
if (!content) return '';
|
|
10
|
+
if (typeof content === 'string') return content;
|
|
11
|
+
return content
|
|
12
|
+
.filter(
|
|
13
|
+
(part): part is { type: 'text'; text: string } =>
|
|
14
|
+
!!part &&
|
|
15
|
+
typeof part === 'object' &&
|
|
16
|
+
'type' in part &&
|
|
17
|
+
(part as { type?: unknown }).type === 'text' &&
|
|
18
|
+
'text' in part &&
|
|
19
|
+
typeof (part as { text?: unknown }).text === 'string',
|
|
20
|
+
)
|
|
21
|
+
.map((part) => part.text)
|
|
22
|
+
.join('\n');
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const CloudscapeUserMessageImpl = ({ message }: CopilotChatUserMessageProps) => (
|
|
26
|
+
<ChatBubble
|
|
27
|
+
ariaLabel="Your message"
|
|
28
|
+
type="outgoing"
|
|
29
|
+
avatar={<Avatar ariaLabel="You" tooltipText="You" initials="Me" />}
|
|
30
|
+
>
|
|
31
|
+
<div style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
|
|
32
|
+
{flattenContent(message.content)}
|
|
33
|
+
</div>
|
|
34
|
+
</ChatBubble>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export const CloudscapeUserMessage = Object.assign(
|
|
38
|
+
CloudscapeUserMessageImpl,
|
|
39
|
+
CopilotChatUserMessage,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export default CloudscapeUserMessage;
|
package/src/ts/react-website/agui/files/cloudscape/src/components/copilot/copilot.css.template
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/* Explicit styles for the Streamdown markdown output (CopilotKit emits
|
|
2
|
+
* unprefixed Tailwind utilities that the website's Tailwind build can't see). */
|
|
3
|
+
|
|
4
|
+
.copilotkit-cloudscape-messages {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
gap: 12px;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.copilotkit-cloudscape-input {
|
|
12
|
+
padding: 12px 16px 16px;
|
|
13
|
+
background: var(--awsui-color-background-container-content, #ffffff);
|
|
14
|
+
border-top: 1px solid var(--awsui-color-border-divider-default, #dfe3e6);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.copilotkit-cloudscape-messages [data-streamdown='strong'] {
|
|
18
|
+
font-weight: 600;
|
|
19
|
+
}
|
|
20
|
+
.copilotkit-cloudscape-messages [data-streamdown='emphasis'] {
|
|
21
|
+
font-style: italic;
|
|
22
|
+
}
|
|
23
|
+
.copilotkit-cloudscape-messages [data-streamdown='paragraph'],
|
|
24
|
+
.copilotkit-cloudscape-messages > p {
|
|
25
|
+
margin: 0.5em 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-1'],
|
|
29
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-2'],
|
|
30
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-3'],
|
|
31
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-4'],
|
|
32
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-5'],
|
|
33
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-6'] {
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
line-height: 1.3;
|
|
36
|
+
margin: 0.8em 0 0.4em;
|
|
37
|
+
}
|
|
38
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-1'] {
|
|
39
|
+
font-size: 1.5em;
|
|
40
|
+
}
|
|
41
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-2'] {
|
|
42
|
+
font-size: 1.3em;
|
|
43
|
+
}
|
|
44
|
+
.copilotkit-cloudscape-messages [data-streamdown='heading-3'] {
|
|
45
|
+
font-size: 1.15em;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.copilotkit-cloudscape-messages [data-streamdown='unordered-list'] {
|
|
49
|
+
list-style: disc;
|
|
50
|
+
padding-inline-start: 1.5em;
|
|
51
|
+
margin: 0.5em 0;
|
|
52
|
+
}
|
|
53
|
+
.copilotkit-cloudscape-messages [data-streamdown='ordered-list'] {
|
|
54
|
+
list-style: decimal;
|
|
55
|
+
padding-inline-start: 1.5em;
|
|
56
|
+
margin: 0.5em 0;
|
|
57
|
+
}
|
|
58
|
+
.copilotkit-cloudscape-messages [data-streamdown='list-item'] {
|
|
59
|
+
margin: 0.25em 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.copilotkit-cloudscape-messages [data-streamdown='inline-code'],
|
|
63
|
+
.copilotkit-cloudscape-messages code {
|
|
64
|
+
background: rgba(0, 0, 0, 0.06);
|
|
65
|
+
border-radius: 4px;
|
|
66
|
+
padding: 0.1em 0.35em;
|
|
67
|
+
font-family: var(--font-family-monospace, ui-monospace, monospace);
|
|
68
|
+
font-size: 0.9em;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.copilotkit-cloudscape-messages [data-streamdown='code-block'] {
|
|
72
|
+
background: rgba(0, 0, 0, 0.04);
|
|
73
|
+
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
74
|
+
border-radius: 8px;
|
|
75
|
+
margin: 0.75em 0;
|
|
76
|
+
max-width: 100%;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
}
|
|
79
|
+
.copilotkit-cloudscape-messages [data-streamdown='code-block'] pre {
|
|
80
|
+
margin: 0;
|
|
81
|
+
padding: 12px 16px;
|
|
82
|
+
overflow-x: auto;
|
|
83
|
+
white-space: pre;
|
|
84
|
+
font-family: var(--font-family-monospace, ui-monospace, monospace);
|
|
85
|
+
font-size: 0.85em;
|
|
86
|
+
line-height: 1.5;
|
|
87
|
+
}
|
|
88
|
+
.copilotkit-cloudscape-messages [data-streamdown='code-block'] code {
|
|
89
|
+
background: transparent;
|
|
90
|
+
padding: 0;
|
|
91
|
+
white-space: pre;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.copilotkit-cloudscape-messages [data-streamdown='blockquote'] {
|
|
95
|
+
border-inline-start: 3px solid rgba(0, 0, 0, 0.15);
|
|
96
|
+
margin: 0.5em 0;
|
|
97
|
+
padding-inline-start: 1em;
|
|
98
|
+
color: rgba(0, 0, 0, 0.65);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.copilotkit-cloudscape-messages table[data-streamdown='table-wrapper'] {
|
|
102
|
+
border-collapse: collapse;
|
|
103
|
+
margin: 0.75em 0;
|
|
104
|
+
max-width: 100%;
|
|
105
|
+
overflow-x: auto;
|
|
106
|
+
width: auto;
|
|
107
|
+
}
|
|
108
|
+
.copilotkit-cloudscape-messages table[data-streamdown='table-wrapper'] th,
|
|
109
|
+
.copilotkit-cloudscape-messages table[data-streamdown='table-wrapper'] td {
|
|
110
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
111
|
+
padding: 6px 10px;
|
|
112
|
+
text-align: start;
|
|
113
|
+
}
|
|
114
|
+
.copilotkit-cloudscape-messages table[data-streamdown='table-wrapper'] th {
|
|
115
|
+
background: rgba(0, 0, 0, 0.04);
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.copilotkit-cloudscape-messages [data-streamdown='link'] {
|
|
120
|
+
color: var(--awsui-color-text-link-default, #0972d3);
|
|
121
|
+
text-decoration: underline;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.copilotkit-cloudscape-messages [data-streamdown='horizontal-rule'] {
|
|
125
|
+
border: 0;
|
|
126
|
+
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
|
127
|
+
margin: 1em 0;
|
|
128
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CopilotChat as CopilotChatBase,
|
|
3
|
+
CopilotSidebar as CopilotSidebarBase,
|
|
4
|
+
CopilotPopup as CopilotPopupBase,
|
|
5
|
+
CopilotChatView,
|
|
6
|
+
type CopilotChatProps,
|
|
7
|
+
type CopilotSidebarProps,
|
|
8
|
+
type CopilotPopupProps,
|
|
9
|
+
} from '@copilotkit/react-core/v2';
|
|
10
|
+
import { CloudscapeAssistantMessage } from './CloudscapeAssistantMessage';
|
|
11
|
+
import { CloudscapeUserMessage } from './CloudscapeUserMessage';
|
|
12
|
+
import { CloudscapeChatInput } from './CloudscapeChatInput';
|
|
13
|
+
import { CloudscapeCursor } from './CloudscapeCursor';
|
|
14
|
+
import './copilot.css';
|
|
15
|
+
|
|
16
|
+
const NoopFeather: typeof CopilotChatView.Feather = () => null;
|
|
17
|
+
|
|
18
|
+
export const cloudscapeCopilotTheme = {
|
|
19
|
+
messageView: {
|
|
20
|
+
assistantMessage: CloudscapeAssistantMessage,
|
|
21
|
+
userMessage: CloudscapeUserMessage,
|
|
22
|
+
cursor: CloudscapeCursor,
|
|
23
|
+
className: 'copilotkit-cloudscape-messages',
|
|
24
|
+
},
|
|
25
|
+
input: CloudscapeChatInput,
|
|
26
|
+
scrollView: { feather: NoopFeather },
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export const CopilotChat = (props: CopilotChatProps) => (
|
|
30
|
+
<CopilotChatBase {...cloudscapeCopilotTheme} {...props} />
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const CopilotSidebar = (props: CopilotSidebarProps) => (
|
|
34
|
+
<CopilotSidebarBase {...cloudscapeCopilotTheme} {...props} />
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export const CopilotPopup = (props: CopilotPopupProps) => (
|
|
38
|
+
<CopilotPopupBase {...cloudscapeCopilotTheme} {...props} />
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
CloudscapeAssistantMessage,
|
|
43
|
+
CloudscapeUserMessage,
|
|
44
|
+
CloudscapeChatInput,
|
|
45
|
+
CloudscapeCursor,
|
|
46
|
+
};
|
package/src/ts/react-website/agui/files/{src → common/src}/components/AguiProvider.tsx.template
RENAMED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CopilotKitProvider,
|
|
3
|
+
WildcardToolCallRender,
|
|
4
|
+
} from '@copilotkit/react-core/v2';
|
|
2
5
|
import '@copilotkit/react-core/v2/styles.css';
|
|
3
6
|
import { type FC, type PropsWithChildren, useMemo } from 'react';
|
|
4
7
|
import type { AbstractAgent } from '@ag-ui/client';
|
|
5
8
|
|
|
9
|
+
const renderToolCalls = [WildcardToolCallRender];
|
|
10
|
+
|
|
6
11
|
export const AguiProvider: FC<PropsWithChildren> = ({ children }) => {
|
|
7
12
|
const selfManagedAgents = useMemo<Record<string, AbstractAgent>>(
|
|
8
13
|
() => ({}),
|
|
@@ -10,7 +15,10 @@ export const AguiProvider: FC<PropsWithChildren> = ({ children }) => {
|
|
|
10
15
|
);
|
|
11
16
|
|
|
12
17
|
return (
|
|
13
|
-
<CopilotKitProvider
|
|
18
|
+
<CopilotKitProvider
|
|
19
|
+
selfManagedAgents={selfManagedAgents}
|
|
20
|
+
renderToolCalls={renderToolCalls}
|
|
21
|
+
>
|
|
14
22
|
{children}
|
|
15
23
|
</CopilotKitProvider>
|
|
16
24
|
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CopilotChatAssistantMessage,
|
|
3
|
+
CopilotChatToolCallsView,
|
|
4
|
+
} from '@copilotkit/react-core/v2';
|
|
5
|
+
import type { CopilotChatAssistantMessageProps } from '@copilotkit/react-core/v2';
|
|
6
|
+
import { Copy, Sparkles } from 'lucide-react';
|
|
7
|
+
import {
|
|
8
|
+
Avatar,
|
|
9
|
+
AvatarFallback,
|
|
10
|
+
} from '<%= scopeAlias %>common-shadcn/components/ui/avatar';
|
|
11
|
+
import { Button } from '<%= scopeAlias %>common-shadcn/components/ui/button';
|
|
12
|
+
import { cn } from '<%= scopeAlias %>common-shadcn/lib/utils';
|
|
13
|
+
|
|
14
|
+
const ShadcnAssistantMessageImpl = ({
|
|
15
|
+
message,
|
|
16
|
+
messages,
|
|
17
|
+
}: CopilotChatAssistantMessageProps) => {
|
|
18
|
+
const hasContent = !!(message.content && message.content.trim().length > 0);
|
|
19
|
+
|
|
20
|
+
const handleCopy = () => {
|
|
21
|
+
if (typeof message.content === 'string') {
|
|
22
|
+
void navigator.clipboard?.writeText(message.content);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="group flex items-start gap-3 py-2">
|
|
28
|
+
<Avatar className="bg-primary/10 border-primary/20 mt-0.5 border">
|
|
29
|
+
<AvatarFallback className="bg-transparent">
|
|
30
|
+
<Sparkles className="text-primary size-4" />
|
|
31
|
+
</AvatarFallback>
|
|
32
|
+
</Avatar>
|
|
33
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
34
|
+
<div
|
|
35
|
+
className={cn(
|
|
36
|
+
'bg-muted/60 text-foreground rounded-2xl rounded-tl-sm px-4 py-3',
|
|
37
|
+
'copilotkit-shadcn-markdown',
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
<CopilotChatAssistantMessage.MarkdownRenderer
|
|
41
|
+
content={message.content ?? ''}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
{message.toolCalls && message.toolCalls.length > 0 && (
|
|
45
|
+
<CopilotChatToolCallsView message={message} messages={messages} />
|
|
46
|
+
)}
|
|
47
|
+
{hasContent && (
|
|
48
|
+
<div className="text-muted-foreground flex items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100">
|
|
49
|
+
<Button
|
|
50
|
+
type="button"
|
|
51
|
+
variant="ghost"
|
|
52
|
+
size="icon"
|
|
53
|
+
className="size-7"
|
|
54
|
+
aria-label="Copy message"
|
|
55
|
+
onClick={handleCopy}
|
|
56
|
+
>
|
|
57
|
+
<Copy className="size-3.5" />
|
|
58
|
+
</Button>
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const ShadcnAssistantMessage = Object.assign(
|
|
67
|
+
ShadcnAssistantMessageImpl,
|
|
68
|
+
CopilotChatAssistantMessage,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export default ShadcnAssistantMessage;
|
package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnChatInput.tsx.template
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useRef,
|
|
3
|
+
useState,
|
|
4
|
+
useEffect,
|
|
5
|
+
type KeyboardEvent,
|
|
6
|
+
} from 'react';
|
|
7
|
+
import {
|
|
8
|
+
CopilotChatInput,
|
|
9
|
+
type CopilotChatInputProps,
|
|
10
|
+
} from '@copilotkit/react-core/v2';
|
|
11
|
+
import { ArrowUp, Square } from 'lucide-react';
|
|
12
|
+
import { Button } from '<%= scopeAlias %>common-shadcn/components/ui/button';
|
|
13
|
+
import { Textarea } from '<%= scopeAlias %>common-shadcn/components/ui/textarea';
|
|
14
|
+
import { cn } from '<%= scopeAlias %>common-shadcn/lib/utils';
|
|
15
|
+
|
|
16
|
+
const MAX_ROWS = 8;
|
|
17
|
+
|
|
18
|
+
const ShadcnChatInputImpl = ({
|
|
19
|
+
value,
|
|
20
|
+
onChange,
|
|
21
|
+
onSubmitMessage,
|
|
22
|
+
onStop,
|
|
23
|
+
isRunning,
|
|
24
|
+
autoFocus,
|
|
25
|
+
mode,
|
|
26
|
+
}: CopilotChatInputProps) => {
|
|
27
|
+
const [internalValue, setInternalValue] = useState('');
|
|
28
|
+
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
29
|
+
const currentValue = value ?? internalValue;
|
|
30
|
+
const disabled = mode === 'processing';
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const el = textareaRef.current;
|
|
34
|
+
if (!el) return;
|
|
35
|
+
el.style.height = 'auto';
|
|
36
|
+
const lineHeight = parseFloat(getComputedStyle(el).lineHeight || '20');
|
|
37
|
+
el.style.height = `${Math.min(el.scrollHeight, lineHeight * MAX_ROWS)}px`;
|
|
38
|
+
}, [currentValue]);
|
|
39
|
+
|
|
40
|
+
const setValue = (next: string) => {
|
|
41
|
+
onChange?.(next);
|
|
42
|
+
if (value === undefined) setInternalValue(next);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const submit = () => {
|
|
46
|
+
const trimmed = currentValue.trim();
|
|
47
|
+
if (!trimmed) return;
|
|
48
|
+
onSubmitMessage?.(trimmed);
|
|
49
|
+
if (value === undefined) setInternalValue('');
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
53
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
submit();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="px-4 pb-4 pt-2">
|
|
61
|
+
<div
|
|
62
|
+
className={cn(
|
|
63
|
+
'bg-background border-input focus-within:border-ring focus-within:ring-ring/30',
|
|
64
|
+
'flex items-end gap-2 rounded-3xl border px-3 py-2',
|
|
65
|
+
'shadow-[0_2px_10px_rgba(0,0,0,0.06)]',
|
|
66
|
+
'focus-within:ring-4 transition-[border,box-shadow]',
|
|
67
|
+
)}
|
|
68
|
+
>
|
|
69
|
+
<Textarea
|
|
70
|
+
ref={textareaRef}
|
|
71
|
+
value={currentValue}
|
|
72
|
+
onChange={(event) => setValue(event.target.value)}
|
|
73
|
+
onKeyDown={handleKeyDown}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
autoFocus={autoFocus}
|
|
76
|
+
placeholder="Ask me anything..."
|
|
77
|
+
rows={1}
|
|
78
|
+
className={cn(
|
|
79
|
+
'flex-1 resize-none border-0 bg-transparent p-2 shadow-none',
|
|
80
|
+
'focus-visible:ring-0 focus-visible:ring-offset-0',
|
|
81
|
+
'min-h-0 max-h-48 leading-6',
|
|
82
|
+
)}
|
|
83
|
+
/>
|
|
84
|
+
{isRunning ? (
|
|
85
|
+
<Button
|
|
86
|
+
type="button"
|
|
87
|
+
variant="secondary"
|
|
88
|
+
size="icon"
|
|
89
|
+
onClick={onStop}
|
|
90
|
+
aria-label="Stop"
|
|
91
|
+
className="size-9 rounded-full"
|
|
92
|
+
>
|
|
93
|
+
<Square className="size-4" fill="currentColor" />
|
|
94
|
+
</Button>
|
|
95
|
+
) : (
|
|
96
|
+
<Button
|
|
97
|
+
type="button"
|
|
98
|
+
size="icon"
|
|
99
|
+
onClick={submit}
|
|
100
|
+
disabled={disabled || !currentValue.trim()}
|
|
101
|
+
aria-label="Send message"
|
|
102
|
+
className="size-9 rounded-full"
|
|
103
|
+
>
|
|
104
|
+
<ArrowUp className="size-4" />
|
|
105
|
+
</Button>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const ShadcnChatInput = Object.assign(
|
|
113
|
+
ShadcnChatInputImpl,
|
|
114
|
+
CopilotChatInput,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
export default ShadcnChatInput;
|
package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnCursor.tsx.template
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CopilotChatMessageView } from '@copilotkit/react-core/v2';
|
|
2
|
+
import { cn } from '<%= scopeAlias %>common-shadcn/lib/utils';
|
|
3
|
+
|
|
4
|
+
export const ShadcnCursor: typeof CopilotChatMessageView.Cursor = () => (
|
|
5
|
+
<div
|
|
6
|
+
role="status"
|
|
7
|
+
aria-label="Generating response"
|
|
8
|
+
className="flex items-center gap-1 px-4 py-2"
|
|
9
|
+
>
|
|
10
|
+
{[0, 1, 2].map((i) => (
|
|
11
|
+
<span
|
|
12
|
+
key={i}
|
|
13
|
+
className={cn(
|
|
14
|
+
'bg-muted-foreground/60 size-1.5 rounded-full',
|
|
15
|
+
'animate-bounce',
|
|
16
|
+
)}
|
|
17
|
+
style={{ animationDelay: `${i * 120}ms` }}
|
|
18
|
+
/>
|
|
19
|
+
))}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export default ShadcnCursor;
|
package/src/ts/react-website/agui/files/shadcn/src/components/copilot/ShadcnUserMessage.tsx.template
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CopilotChatUserMessage } from '@copilotkit/react-core/v2';
|
|
2
|
+
import type {
|
|
3
|
+
CopilotChatUserMessageProps,
|
|
4
|
+
UserMessage,
|
|
5
|
+
} from '@copilotkit/react-core/v2';
|
|
6
|
+
import { User } from 'lucide-react';
|
|
7
|
+
import {
|
|
8
|
+
Avatar,
|
|
9
|
+
AvatarFallback,
|
|
10
|
+
} from '<%= scopeAlias %>common-shadcn/components/ui/avatar';
|
|
11
|
+
|
|
12
|
+
const flattenContent = (content: UserMessage['content']): string => {
|
|
13
|
+
if (!content) return '';
|
|
14
|
+
if (typeof content === 'string') return content;
|
|
15
|
+
return content
|
|
16
|
+
.filter(
|
|
17
|
+
(part): part is { type: 'text'; text: string } =>
|
|
18
|
+
!!part &&
|
|
19
|
+
typeof part === 'object' &&
|
|
20
|
+
'type' in part &&
|
|
21
|
+
(part as { type?: unknown }).type === 'text' &&
|
|
22
|
+
'text' in part &&
|
|
23
|
+
typeof (part as { text?: unknown }).text === 'string',
|
|
24
|
+
)
|
|
25
|
+
.map((part) => part.text)
|
|
26
|
+
.join('\n');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ShadcnUserMessageImpl = ({ message }: CopilotChatUserMessageProps) => (
|
|
30
|
+
<div className="flex items-start justify-end gap-3 py-2">
|
|
31
|
+
<div className="flex min-w-0 max-w-[85%] flex-col items-end gap-1.5">
|
|
32
|
+
<div className="bg-primary text-primary-foreground rounded-2xl rounded-tr-sm px-4 py-2.5 whitespace-pre-wrap break-words">
|
|
33
|
+
{flattenContent(message.content)}
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<Avatar className="bg-secondary mt-0.5">
|
|
37
|
+
<AvatarFallback className="bg-transparent">
|
|
38
|
+
<User className="text-secondary-foreground size-4" />
|
|
39
|
+
</AvatarFallback>
|
|
40
|
+
</Avatar>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const ShadcnUserMessage = Object.assign(
|
|
45
|
+
ShadcnUserMessageImpl,
|
|
46
|
+
CopilotChatUserMessage,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export default ShadcnUserMessage;
|