@copilotkitnext/angular 0.0.1 → 0.0.4
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/README.md +248 -0
- package/dist/README.md +248 -0
- package/dist/components/chat/copilot-chat-assistant-message.component.d.ts +10 -10
- package/dist/components/chat/copilot-chat-message-view.component.d.ts +42 -42
- package/dist/components/chat/copilot-chat-view.component.d.ts +14 -14
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
- package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
- package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
- package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
- package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
- package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
- package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
- package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
- package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
- package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
- package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
- package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
- package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
- package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
- package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
- package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
- package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
- package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
- package/dist/esm2022/core/copilotkit.service.mjs +430 -0
- package/dist/esm2022/core/copilotkit.types.mjs +12 -0
- package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
- package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
- package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
- package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
- package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +130 -0
- package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +266 -0
- package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
- package/dist/esm2022/index.mjs +70 -0
- package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
- package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
- package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
- package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
- package/dist/esm2022/lib/utils.mjs +10 -0
- package/dist/esm2022/services/resize-observer.service.mjs +152 -0
- package/dist/esm2022/services/scroll-position.service.mjs +124 -0
- package/dist/esm2022/types/frontend-tool.mjs +2 -0
- package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
- package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
- package/dist/esm2022/utils/agent.utils.mjs +204 -0
- package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
- package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
- package/dist/esm2022/utils/frontend-tool.utils.mjs +228 -0
- package/dist/esm2022/utils/human-in-the-loop.utils.mjs +296 -0
- package/dist/fesm2022/copilotkitnext-angular.mjs +163 -164
- package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
- package/dist/styles.css +0 -27
- package/package.json +23 -20
- package/vitest.config.mts +32 -21
- package/.turbo/turbo-build.log +0 -39
- package/.turbo/turbo-check-types.log +0 -0
- package/.turbo/turbo-test.log +0 -71
- package/README-agent-context.md +0 -310
- package/ng-package.json +0 -19
- package/slots.md +0 -331
- package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
- package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
- package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
- package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
- package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
- package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
- package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
- package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
- package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
- package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
- package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
- package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
- package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
- package/src/components/chat/copilot-chat-input.component.ts +0 -512
- package/src/components/chat/copilot-chat-input.types.ts +0 -148
- package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
- package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
- package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
- package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
- package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
- package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
- package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
- package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
- package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
- package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
- package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
- package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
- package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
- package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
- package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
- package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
- package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
- package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
- package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
- package/src/components/chat/copilot-chat-view.component.ts +0 -420
- package/src/components/chat/copilot-chat-view.types.ts +0 -52
- package/src/components/chat/copilot-chat.component.ts +0 -232
- package/src/components/copilotkit-tool-render.component.ts +0 -169
- package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
- package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
- package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
- package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
- package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
- package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
- package/src/core/copilotkit.providers.ts +0 -59
- package/src/core/copilotkit.service.ts +0 -542
- package/src/core/copilotkit.types.ts +0 -132
- package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
- package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
- package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
- package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
- package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
- package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
- package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
- package/src/directives/copilotkit-agent-context.directive.ts +0 -138
- package/src/directives/copilotkit-agent.directive.ts +0 -225
- package/src/directives/copilotkit-chat-config.directive.ts +0 -241
- package/src/directives/copilotkit-config.directive.ts +0 -81
- package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
- package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
- package/src/directives/stick-to-bottom.directive.ts +0 -204
- package/src/index.ts +0 -105
- package/src/lib/directives/tooltip.directive.ts +0 -292
- package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
- package/src/lib/slots/copilot-slot.component.ts +0 -135
- package/src/lib/slots/index.ts +0 -3
- package/src/lib/slots/slot.types.ts +0 -64
- package/src/lib/slots/slot.utils.ts +0 -289
- package/src/lib/utils.ts +0 -10
- package/src/public-api.ts +0 -1
- package/src/services/resize-observer.service.ts +0 -181
- package/src/services/scroll-position.service.ts +0 -169
- package/src/styles/globals.css +0 -266
- package/src/styles/index.css +0 -3
- package/src/test-setup.ts +0 -15
- package/src/testing/index.ts +0 -3
- package/src/testing/testing.utils.ts +0 -248
- package/src/types/frontend-tool.ts +0 -44
- package/src/types/human-in-the-loop.ts +0 -52
- package/src/utils/__tests__/agent.utils.spec.ts +0 -234
- package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
- package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
- package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
- package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
- package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
- package/src/utils/agent-context.utils.ts +0 -133
- package/src/utils/agent.utils.ts +0 -239
- package/src/utils/chat-config.utils.ts +0 -221
- package/src/utils/copilotkit.utils.ts +0 -20
- package/src/utils/frontend-tool.utils.ts +0 -266
- package/src/utils/human-in-the-loop.utils.ts +0 -359
- package/tsconfig.spec.json +0 -12
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
ChangeDetectionStrategy,
|
|
5
|
-
ViewEncapsulation,
|
|
6
|
-
computed,
|
|
7
|
-
signal,
|
|
8
|
-
OnInit,
|
|
9
|
-
OnChanges
|
|
10
|
-
} from '@angular/core';
|
|
11
|
-
import { CommonModule } from '@angular/common';
|
|
12
|
-
import { cn } from '../../lib/utils';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Cursor component that matches the React implementation exactly.
|
|
16
|
-
* Shows a pulsing dot animation to indicate activity.
|
|
17
|
-
*/
|
|
18
|
-
@Component({
|
|
19
|
-
selector: 'copilot-chat-message-view-cursor',
|
|
20
|
-
standalone: true,
|
|
21
|
-
imports: [CommonModule],
|
|
22
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
23
|
-
encapsulation: ViewEncapsulation.None,
|
|
24
|
-
template: `
|
|
25
|
-
<div
|
|
26
|
-
[class]="computedClass()"
|
|
27
|
-
></div>
|
|
28
|
-
`
|
|
29
|
-
})
|
|
30
|
-
export class CopilotChatMessageViewCursorComponent implements OnInit, OnChanges {
|
|
31
|
-
@Input() inputClass?: string;
|
|
32
|
-
|
|
33
|
-
// Signal for reactive class updates
|
|
34
|
-
private inputClassSignal = signal<string | undefined>(undefined);
|
|
35
|
-
|
|
36
|
-
// Computed class that matches React exactly: w-[11px] h-[11px] rounded-full bg-foreground animate-pulse-cursor ml-1
|
|
37
|
-
computedClass = computed(() =>
|
|
38
|
-
cn(
|
|
39
|
-
'w-[11px] h-[11px] rounded-full bg-foreground animate-pulse-cursor ml-1',
|
|
40
|
-
this.inputClassSignal()
|
|
41
|
-
)
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
ngOnInit() {
|
|
45
|
-
this.inputClassSignal.set(this.inputClass);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
ngOnChanges() {
|
|
49
|
-
this.inputClassSignal.set(this.inputClass);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
Output,
|
|
5
|
-
EventEmitter,
|
|
6
|
-
ContentChild,
|
|
7
|
-
TemplateRef,
|
|
8
|
-
Type,
|
|
9
|
-
ChangeDetectionStrategy,
|
|
10
|
-
ViewEncapsulation,
|
|
11
|
-
signal,
|
|
12
|
-
computed,
|
|
13
|
-
OnInit,
|
|
14
|
-
OnChanges
|
|
15
|
-
} from '@angular/core';
|
|
16
|
-
import { CommonModule } from '@angular/common';
|
|
17
|
-
import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
|
|
18
|
-
import type { Message } from '@ag-ui/core';
|
|
19
|
-
import { CopilotChatAssistantMessageComponent } from './copilot-chat-assistant-message.component';
|
|
20
|
-
import { CopilotChatUserMessageComponent } from './copilot-chat-user-message.component';
|
|
21
|
-
import { CopilotChatMessageViewCursorComponent } from './copilot-chat-message-view-cursor.component';
|
|
22
|
-
import { cn } from '../../lib/utils';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* CopilotChatMessageView component - Angular port of the React component.
|
|
26
|
-
* Renders a list of chat messages with support for custom slots and layouts.
|
|
27
|
-
* DOM structure and Tailwind classes match the React implementation exactly.
|
|
28
|
-
*/
|
|
29
|
-
@Component({
|
|
30
|
-
selector: 'copilot-chat-message-view',
|
|
31
|
-
standalone: true,
|
|
32
|
-
imports: [
|
|
33
|
-
CommonModule,
|
|
34
|
-
CopilotSlotComponent,
|
|
35
|
-
CopilotChatAssistantMessageComponent,
|
|
36
|
-
CopilotChatUserMessageComponent,
|
|
37
|
-
CopilotChatMessageViewCursorComponent
|
|
38
|
-
],
|
|
39
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
40
|
-
encapsulation: ViewEncapsulation.None,
|
|
41
|
-
template: `
|
|
42
|
-
<!-- Custom layout template support (render prop pattern) -->
|
|
43
|
-
@if (customLayoutTemplate) {
|
|
44
|
-
<ng-container *ngTemplateOutlet="customLayoutTemplate; context: layoutContext()"></ng-container>
|
|
45
|
-
} @else {
|
|
46
|
-
<!-- Default layout - exact React DOM structure: div with "flex flex-col" classes -->
|
|
47
|
-
<div [class]="computedClass()">
|
|
48
|
-
<!-- Message iteration - simplified without tool calls -->
|
|
49
|
-
@for (message of messagesSignal(); track trackByMessageId($index, message)) {
|
|
50
|
-
@if (message && message.role === 'assistant') {
|
|
51
|
-
<!-- Assistant message with slot support -->
|
|
52
|
-
@if (assistantMessageComponent || assistantMessageTemplate) {
|
|
53
|
-
<copilot-slot
|
|
54
|
-
[slot]="assistantMessageTemplate || assistantMessageComponent"
|
|
55
|
-
[context]="mergeAssistantProps(message)"
|
|
56
|
-
[defaultComponent]="defaultAssistantComponent">
|
|
57
|
-
</copilot-slot>
|
|
58
|
-
} @else {
|
|
59
|
-
<copilot-chat-assistant-message
|
|
60
|
-
[message]="message"
|
|
61
|
-
[messages]="messagesSignal()"
|
|
62
|
-
[isLoading]="isLoadingSignal()"
|
|
63
|
-
[inputClass]="assistantMessageClass"
|
|
64
|
-
(thumbsUp)="handleAssistantThumbsUp($event)"
|
|
65
|
-
(thumbsDown)="handleAssistantThumbsDown($event)"
|
|
66
|
-
(readAloud)="handleAssistantReadAloud($event)"
|
|
67
|
-
(regenerate)="handleAssistantRegenerate($event)">
|
|
68
|
-
</copilot-chat-assistant-message>
|
|
69
|
-
}
|
|
70
|
-
} @else if (message && message.role === 'user') {
|
|
71
|
-
<!-- User message with slot support -->
|
|
72
|
-
@if (userMessageComponent || userMessageTemplate) {
|
|
73
|
-
<copilot-slot
|
|
74
|
-
[slot]="userMessageTemplate || userMessageComponent"
|
|
75
|
-
[context]="mergeUserProps(message)"
|
|
76
|
-
[defaultComponent]="defaultUserComponent">
|
|
77
|
-
</copilot-slot>
|
|
78
|
-
} @else {
|
|
79
|
-
<copilot-chat-user-message
|
|
80
|
-
[message]="message"
|
|
81
|
-
[inputClass]="userMessageClass">
|
|
82
|
-
</copilot-chat-user-message>
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
<!-- Cursor - exactly like React's conditional rendering -->
|
|
88
|
-
@if (showCursor) {
|
|
89
|
-
@if (cursorComponent || cursorTemplate) {
|
|
90
|
-
<copilot-slot
|
|
91
|
-
[slot]="cursorTemplate || cursorComponent"
|
|
92
|
-
[context]="{ inputClass: cursorClass }"
|
|
93
|
-
[defaultComponent]="defaultCursorComponent">
|
|
94
|
-
</copilot-slot>
|
|
95
|
-
} @else {
|
|
96
|
-
<copilot-chat-message-view-cursor
|
|
97
|
-
[inputClass]="cursorClass">
|
|
98
|
-
</copilot-chat-message-view-cursor>
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
</div>
|
|
102
|
-
}
|
|
103
|
-
`
|
|
104
|
-
})
|
|
105
|
-
export class CopilotChatMessageViewComponent implements OnInit, OnChanges {
|
|
106
|
-
// Core inputs matching React props
|
|
107
|
-
@Input() messages: Message[] = [];
|
|
108
|
-
@Input() showCursor = false;
|
|
109
|
-
@Input() isLoading = false;
|
|
110
|
-
@Input() inputClass?: string;
|
|
111
|
-
|
|
112
|
-
// Handler availability handled via DI service
|
|
113
|
-
|
|
114
|
-
// Assistant message slot inputs
|
|
115
|
-
@Input() assistantMessageComponent?: Type<any>;
|
|
116
|
-
@Input() assistantMessageTemplate?: TemplateRef<any>;
|
|
117
|
-
@Input() assistantMessageClass?: string;
|
|
118
|
-
|
|
119
|
-
// User message slot inputs
|
|
120
|
-
@Input() userMessageComponent?: Type<any>;
|
|
121
|
-
@Input() userMessageTemplate?: TemplateRef<any>;
|
|
122
|
-
@Input() userMessageClass?: string;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// Cursor slot inputs
|
|
126
|
-
@Input() cursorComponent?: Type<any>;
|
|
127
|
-
@Input() cursorTemplate?: TemplateRef<any>;
|
|
128
|
-
@Input() cursorClass?: string;
|
|
129
|
-
|
|
130
|
-
// Custom layout template (render prop pattern)
|
|
131
|
-
@ContentChild('customLayout') customLayoutTemplate?: TemplateRef<any>;
|
|
132
|
-
|
|
133
|
-
// Output events (bubbled from child components)
|
|
134
|
-
@Output() assistantMessageThumbsUp = new EventEmitter<{ message: Message }>();
|
|
135
|
-
@Output() assistantMessageThumbsDown = new EventEmitter<{ message: Message }>();
|
|
136
|
-
@Output() assistantMessageReadAloud = new EventEmitter<{ message: Message }>();
|
|
137
|
-
@Output() assistantMessageRegenerate = new EventEmitter<{ message: Message }>();
|
|
138
|
-
@Output() userMessageCopy = new EventEmitter<{ message: Message }>();
|
|
139
|
-
@Output() userMessageEdit = new EventEmitter<{ message: Message }>();
|
|
140
|
-
|
|
141
|
-
// Default components for slots
|
|
142
|
-
protected readonly defaultAssistantComponent = CopilotChatAssistantMessageComponent;
|
|
143
|
-
protected readonly defaultUserComponent = CopilotChatUserMessageComponent;
|
|
144
|
-
protected readonly defaultCursorComponent = CopilotChatMessageViewCursorComponent;
|
|
145
|
-
|
|
146
|
-
// Signals for reactive updates
|
|
147
|
-
protected messagesSignal = signal<Message[]>([]);
|
|
148
|
-
protected showCursorSignal = signal(false);
|
|
149
|
-
protected isLoadingSignal = signal(false);
|
|
150
|
-
protected inputClassSignal = signal<string | undefined>(undefined);
|
|
151
|
-
|
|
152
|
-
// Computed class matching React: twMerge("flex flex-col", className)
|
|
153
|
-
computedClass = computed(() =>
|
|
154
|
-
cn('flex flex-col', this.inputClassSignal())
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// Layout context for custom templates (render prop pattern)
|
|
159
|
-
layoutContext = computed(() => ({
|
|
160
|
-
isLoading: this.isLoadingSignal(),
|
|
161
|
-
messages: this.messagesSignal(),
|
|
162
|
-
showCursor: this.showCursorSignal(),
|
|
163
|
-
messageElements: this.messagesSignal().filter(m => m && (m.role === 'assistant' || m.role === 'user'))
|
|
164
|
-
}));
|
|
165
|
-
|
|
166
|
-
// Slot resolution computed signals
|
|
167
|
-
assistantMessageSlot = computed(() =>
|
|
168
|
-
this.assistantMessageComponent || this.assistantMessageClass
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
userMessageSlot = computed(() =>
|
|
172
|
-
this.userMessageComponent || this.userMessageClass
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
cursorSlot = computed(() =>
|
|
176
|
-
this.cursorComponent || this.cursorClass
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
// Props merging helpers
|
|
180
|
-
mergeAssistantProps(message: Message) {
|
|
181
|
-
return {
|
|
182
|
-
message,
|
|
183
|
-
messages: this.messagesSignal(),
|
|
184
|
-
isLoading: this.isLoadingSignal(),
|
|
185
|
-
inputClass: this.assistantMessageClass
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
mergeUserProps(message: Message) {
|
|
190
|
-
return {
|
|
191
|
-
message,
|
|
192
|
-
inputClass: this.userMessageClass
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// TrackBy function for performance optimization
|
|
197
|
-
trackByMessageId(index: number, message: Message): string {
|
|
198
|
-
return message?.id || `index-${index}`;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Lifecycle hooks
|
|
202
|
-
ngOnInit() {
|
|
203
|
-
// Initialize signals with input values
|
|
204
|
-
this.messagesSignal.set(this.messages);
|
|
205
|
-
this.showCursorSignal.set(this.showCursor);
|
|
206
|
-
this.isLoadingSignal.set(this.isLoading);
|
|
207
|
-
this.inputClassSignal.set(this.inputClass);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
ngOnChanges() {
|
|
211
|
-
this.messagesSignal.set(this.messages);
|
|
212
|
-
this.showCursorSignal.set(this.showCursor);
|
|
213
|
-
this.isLoadingSignal.set(this.isLoading);
|
|
214
|
-
this.inputClassSignal.set(this.inputClass);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Event handlers - just pass them through
|
|
218
|
-
handleAssistantThumbsUp(event: { message: Message }): void {
|
|
219
|
-
this.assistantMessageThumbsUp.emit(event);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
handleAssistantThumbsDown(event: { message: Message }): void {
|
|
223
|
-
this.assistantMessageThumbsDown.emit(event);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
handleAssistantReadAloud(event: { message: Message }): void {
|
|
227
|
-
this.assistantMessageReadAloud.emit(event);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
handleAssistantRegenerate(event: { message: Message }): void {
|
|
231
|
-
this.assistantMessageRegenerate.emit(event);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Message } from '@ag-ui/client';
|
|
2
|
-
import { Type, TemplateRef } from '@angular/core';
|
|
3
|
-
|
|
4
|
-
// Context interfaces for template slots
|
|
5
|
-
export interface MessageViewContext {
|
|
6
|
-
showCursor: boolean;
|
|
7
|
-
messages: Message[];
|
|
8
|
-
messageElements: any[]; // Will be populated with rendered elements
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
12
|
-
export interface CursorContext {
|
|
13
|
-
// Empty for now, can be extended if needed
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Component input props interface
|
|
17
|
-
export interface CopilotChatMessageViewProps {
|
|
18
|
-
messages?: Message[];
|
|
19
|
-
showCursor?: boolean;
|
|
20
|
-
inputClass?: string;
|
|
21
|
-
|
|
22
|
-
// Assistant message slots
|
|
23
|
-
assistantMessageComponent?: Type<any>;
|
|
24
|
-
assistantMessageTemplate?: TemplateRef<any>;
|
|
25
|
-
assistantMessageClass?: string;
|
|
26
|
-
|
|
27
|
-
// User message slots
|
|
28
|
-
userMessageComponent?: Type<any>;
|
|
29
|
-
userMessageTemplate?: TemplateRef<any>;
|
|
30
|
-
userMessageClass?: string;
|
|
31
|
-
|
|
32
|
-
// Cursor slots
|
|
33
|
-
cursorComponent?: Type<any>;
|
|
34
|
-
cursorTemplate?: TemplateRef<any>;
|
|
35
|
-
cursorClass?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Re-export for convenience
|
|
39
|
-
export type { Message };
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
Output,
|
|
5
|
-
EventEmitter,
|
|
6
|
-
ElementRef,
|
|
7
|
-
AfterViewInit,
|
|
8
|
-
OnChanges,
|
|
9
|
-
SimpleChanges,
|
|
10
|
-
signal,
|
|
11
|
-
computed,
|
|
12
|
-
effect,
|
|
13
|
-
inject,
|
|
14
|
-
ChangeDetectionStrategy,
|
|
15
|
-
ViewEncapsulation
|
|
16
|
-
} from '@angular/core';
|
|
17
|
-
import { CopilotChatConfigurationService } from '../../core/chat-configuration/chat-configuration.service';
|
|
18
|
-
import { cn } from '../../lib/utils';
|
|
19
|
-
|
|
20
|
-
@Component({
|
|
21
|
-
selector: 'textarea[copilotChatTextarea]',
|
|
22
|
-
standalone: true,
|
|
23
|
-
imports: [],
|
|
24
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
|
-
encapsulation: ViewEncapsulation.None,
|
|
26
|
-
host: {
|
|
27
|
-
'[value]': 'value()',
|
|
28
|
-
'[placeholder]': 'placeholder()',
|
|
29
|
-
'[disabled]': 'disabled()',
|
|
30
|
-
'[class]': 'computedClass()',
|
|
31
|
-
'[style.max-height.px]': 'maxHeight()',
|
|
32
|
-
'[style.overflow]': "'auto'",
|
|
33
|
-
'[style.resize]': "'none'",
|
|
34
|
-
'(input)': 'onInput($event)',
|
|
35
|
-
'(keydown)': 'onKeyDown($event)',
|
|
36
|
-
'[attr.rows]': '1'
|
|
37
|
-
},
|
|
38
|
-
template: '',
|
|
39
|
-
styles: []
|
|
40
|
-
})
|
|
41
|
-
export class CopilotChatTextareaComponent implements AfterViewInit, OnChanges {
|
|
42
|
-
private elementRef = inject(ElementRef<HTMLTextAreaElement>);
|
|
43
|
-
get textareaRef() { return this.elementRef; }
|
|
44
|
-
|
|
45
|
-
@Input() set inputValue(val: string | undefined) {
|
|
46
|
-
this.value.set(val || '');
|
|
47
|
-
}
|
|
48
|
-
@Input() set inputPlaceholder(val: string | undefined) {
|
|
49
|
-
this.customPlaceholder.set(val);
|
|
50
|
-
}
|
|
51
|
-
@Input() set inputMaxRows(val: number | undefined) {
|
|
52
|
-
this.maxRows.set(val || 5);
|
|
53
|
-
}
|
|
54
|
-
@Input() set inputAutoFocus(val: boolean | undefined) {
|
|
55
|
-
this.autoFocus.set(val ?? true);
|
|
56
|
-
}
|
|
57
|
-
@Input() set inputDisabled(val: boolean | undefined) {
|
|
58
|
-
this.disabled.set(val || false);
|
|
59
|
-
}
|
|
60
|
-
@Input() set inputClass(val: string | undefined) {
|
|
61
|
-
this.customClass.set(val);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@Output() valueChange = new EventEmitter<string>();
|
|
65
|
-
@Output() keyDown = new EventEmitter<KeyboardEvent>();
|
|
66
|
-
|
|
67
|
-
private chatConfig = inject(CopilotChatConfigurationService);
|
|
68
|
-
|
|
69
|
-
// Signals for reactive state
|
|
70
|
-
value = signal<string>('');
|
|
71
|
-
customPlaceholder = signal<string | undefined>(undefined);
|
|
72
|
-
maxRows = signal<number>(5);
|
|
73
|
-
autoFocus = signal<boolean>(true);
|
|
74
|
-
disabled = signal<boolean>(false);
|
|
75
|
-
customClass = signal<string | undefined>(undefined);
|
|
76
|
-
maxHeight = signal<number>(0);
|
|
77
|
-
|
|
78
|
-
// Computed values
|
|
79
|
-
placeholder = computed(() => {
|
|
80
|
-
return this.customPlaceholder() || this.chatConfig.labels().chatInputPlaceholder;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
computedClass = computed(() => {
|
|
84
|
-
const baseClasses = cn(
|
|
85
|
-
// Layout and sizing
|
|
86
|
-
'w-full p-5 pb-0',
|
|
87
|
-
// Behavior
|
|
88
|
-
'outline-none resize-none',
|
|
89
|
-
// Background
|
|
90
|
-
'bg-transparent',
|
|
91
|
-
// Typography
|
|
92
|
-
'antialiased font-regular leading-relaxed text-[16px]',
|
|
93
|
-
// Placeholder styles
|
|
94
|
-
'placeholder:text-[#00000077] dark:placeholder:text-[#fffc]'
|
|
95
|
-
);
|
|
96
|
-
return cn(baseClasses, this.customClass());
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
constructor() {
|
|
100
|
-
// Effect to sync value with chat configuration if available
|
|
101
|
-
effect(() => {
|
|
102
|
-
const configValue = this.chatConfig.inputValue();
|
|
103
|
-
if (configValue !== undefined && !this.customPlaceholder()) {
|
|
104
|
-
this.value.set(configValue);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
ngAfterViewInit(): void {
|
|
110
|
-
this.calculateMaxHeight();
|
|
111
|
-
this.adjustHeight();
|
|
112
|
-
|
|
113
|
-
if (this.autoFocus()) {
|
|
114
|
-
setTimeout(() => {
|
|
115
|
-
this.elementRef.nativeElement.focus();
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
ngOnChanges(changes: SimpleChanges): void {
|
|
121
|
-
if (changes['inputMaxRows']) {
|
|
122
|
-
this.calculateMaxHeight();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
onInput(event: Event): void {
|
|
127
|
-
const textarea = event.target as HTMLTextAreaElement;
|
|
128
|
-
const newValue = textarea.value;
|
|
129
|
-
|
|
130
|
-
this.value.set(newValue);
|
|
131
|
-
this.valueChange.emit(newValue);
|
|
132
|
-
|
|
133
|
-
// Update chat configuration if available
|
|
134
|
-
if (this.chatConfig) {
|
|
135
|
-
this.chatConfig.setInputValue(newValue);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
this.adjustHeight();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
onKeyDown(event: KeyboardEvent): void {
|
|
142
|
-
// Check for Enter key without Shift
|
|
143
|
-
if (event.key === 'Enter' && !event.shiftKey) {
|
|
144
|
-
event.preventDefault();
|
|
145
|
-
this.keyDown.emit(event);
|
|
146
|
-
} else {
|
|
147
|
-
this.keyDown.emit(event);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private calculateMaxHeight(): void {
|
|
152
|
-
const textarea = this.elementRef.nativeElement;
|
|
153
|
-
const maxRowsValue = this.maxRows();
|
|
154
|
-
|
|
155
|
-
// Save current value
|
|
156
|
-
const currentValue = textarea.value;
|
|
157
|
-
|
|
158
|
-
// Clear content to measure single row height
|
|
159
|
-
textarea.value = '';
|
|
160
|
-
textarea.style.height = 'auto';
|
|
161
|
-
|
|
162
|
-
// Get computed styles to account for padding
|
|
163
|
-
const computedStyle = window.getComputedStyle(textarea);
|
|
164
|
-
const paddingTop = parseFloat(computedStyle.paddingTop);
|
|
165
|
-
const paddingBottom = parseFloat(computedStyle.paddingBottom);
|
|
166
|
-
|
|
167
|
-
// Calculate actual content height (without padding)
|
|
168
|
-
const contentHeight = textarea.scrollHeight - paddingTop - paddingBottom;
|
|
169
|
-
|
|
170
|
-
// Calculate max height: content height for maxRows + padding
|
|
171
|
-
const calculatedMaxHeight = contentHeight * maxRowsValue + paddingTop + paddingBottom;
|
|
172
|
-
this.maxHeight.set(calculatedMaxHeight);
|
|
173
|
-
|
|
174
|
-
// Restore original value
|
|
175
|
-
textarea.value = currentValue;
|
|
176
|
-
|
|
177
|
-
// Adjust height after calculating maxHeight
|
|
178
|
-
if (currentValue) {
|
|
179
|
-
this.adjustHeight();
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private adjustHeight(): void {
|
|
184
|
-
const textarea = this.elementRef.nativeElement;
|
|
185
|
-
const maxHeightValue = this.maxHeight();
|
|
186
|
-
|
|
187
|
-
if (maxHeightValue > 0) {
|
|
188
|
-
textarea.style.height = 'auto';
|
|
189
|
-
textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeightValue)}px`;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Public method to focus the textarea
|
|
195
|
-
*/
|
|
196
|
-
focus(): void {
|
|
197
|
-
this.elementRef.nativeElement.focus();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Public method to get current value
|
|
202
|
-
*/
|
|
203
|
-
getValue(): string {
|
|
204
|
-
return this.value();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Public method to set value programmatically
|
|
209
|
-
*/
|
|
210
|
-
setValue(value: string): void {
|
|
211
|
-
this.value.set(value);
|
|
212
|
-
this.valueChange.emit(value);
|
|
213
|
-
|
|
214
|
-
if (this.chatConfig) {
|
|
215
|
-
this.chatConfig.setInputValue(value);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
setTimeout(() => this.adjustHeight());
|
|
219
|
-
}
|
|
220
|
-
}
|