@copilotkitnext/angular 0.0.2 → 0.0.5

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.
Files changed (173) hide show
  1. package/README.md +3 -3
  2. package/dist/README.md +3 -3
  3. package/dist/components/chat/copilot-chat-assistant-message.component.d.ts +10 -10
  4. package/dist/components/chat/copilot-chat-message-view.component.d.ts +42 -42
  5. package/dist/components/chat/copilot-chat-view.component.d.ts +14 -14
  6. package/dist/core/copilotkit.providers.d.ts +1 -1
  7. package/dist/core/copilotkit.service.d.ts +5 -5
  8. package/dist/core/copilotkit.types.d.ts +8 -10
  9. package/dist/directives/copilotkit-frontend-tool.directive.d.ts +1 -1
  10. package/dist/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
  11. package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
  12. package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
  13. package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
  14. package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
  15. package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
  16. package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
  17. package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
  18. package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
  19. package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
  20. package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
  21. package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
  22. package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
  23. package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
  24. package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
  25. package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
  26. package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
  27. package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
  28. package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
  29. package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
  30. package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
  31. package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
  32. package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
  33. package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
  34. package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
  35. package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
  36. package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
  37. package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
  38. package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
  39. package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
  40. package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
  41. package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
  42. package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
  43. package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
  44. package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
  45. package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
  46. package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
  47. package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
  48. package/dist/esm2022/core/copilotkit.service.mjs +426 -0
  49. package/dist/esm2022/core/copilotkit.types.mjs +13 -0
  50. package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
  51. package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
  52. package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
  53. package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
  54. package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +128 -0
  55. package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +265 -0
  56. package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
  57. package/dist/esm2022/index.mjs +70 -0
  58. package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
  59. package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
  60. package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
  61. package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
  62. package/dist/esm2022/lib/utils.mjs +10 -0
  63. package/dist/esm2022/services/resize-observer.service.mjs +152 -0
  64. package/dist/esm2022/services/scroll-position.service.mjs +124 -0
  65. package/dist/esm2022/types/frontend-tool.mjs +2 -0
  66. package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
  67. package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
  68. package/dist/esm2022/utils/agent.utils.mjs +204 -0
  69. package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
  70. package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
  71. package/dist/esm2022/utils/frontend-tool.utils.mjs +224 -0
  72. package/dist/esm2022/utils/human-in-the-loop.utils.mjs +293 -0
  73. package/dist/fesm2022/copilotkitnext-angular.mjs +174 -187
  74. package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
  75. package/dist/utils/frontend-tool.utils.d.ts +1 -1
  76. package/package.json +23 -20
  77. package/vitest.config.mts +32 -21
  78. package/.turbo/turbo-build.log +0 -38
  79. package/.turbo/turbo-check-types.log +0 -0
  80. package/.turbo/turbo-test.log +0 -71
  81. package/ng-package.json +0 -19
  82. package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
  83. package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
  84. package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
  85. package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
  86. package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
  87. package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
  88. package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
  89. package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
  90. package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
  91. package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
  92. package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
  93. package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
  94. package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
  95. package/src/components/chat/copilot-chat-input.component.ts +0 -512
  96. package/src/components/chat/copilot-chat-input.types.ts +0 -148
  97. package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
  98. package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
  99. package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
  100. package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
  101. package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
  102. package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
  103. package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
  104. package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
  105. package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
  106. package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
  107. package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
  108. package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
  109. package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
  110. package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
  111. package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
  112. package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
  113. package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
  114. package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
  115. package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
  116. package/src/components/chat/copilot-chat-view.component.ts +0 -420
  117. package/src/components/chat/copilot-chat-view.types.ts +0 -52
  118. package/src/components/chat/copilot-chat.component.ts +0 -232
  119. package/src/components/copilotkit-tool-render.component.ts +0 -169
  120. package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
  121. package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
  122. package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
  123. package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
  124. package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
  125. package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
  126. package/src/core/copilotkit.providers.ts +0 -59
  127. package/src/core/copilotkit.service.ts +0 -542
  128. package/src/core/copilotkit.types.ts +0 -132
  129. package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
  130. package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
  131. package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
  132. package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
  133. package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
  134. package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
  135. package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
  136. package/src/directives/copilotkit-agent-context.directive.ts +0 -138
  137. package/src/directives/copilotkit-agent.directive.ts +0 -225
  138. package/src/directives/copilotkit-chat-config.directive.ts +0 -241
  139. package/src/directives/copilotkit-config.directive.ts +0 -81
  140. package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
  141. package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
  142. package/src/directives/stick-to-bottom.directive.ts +0 -204
  143. package/src/index.ts +0 -105
  144. package/src/lib/directives/tooltip.directive.ts +0 -292
  145. package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
  146. package/src/lib/slots/copilot-slot.component.ts +0 -135
  147. package/src/lib/slots/index.ts +0 -3
  148. package/src/lib/slots/slot.types.ts +0 -64
  149. package/src/lib/slots/slot.utils.ts +0 -289
  150. package/src/lib/utils.ts +0 -10
  151. package/src/public-api.ts +0 -1
  152. package/src/services/resize-observer.service.ts +0 -181
  153. package/src/services/scroll-position.service.ts +0 -169
  154. package/src/styles/globals.css +0 -266
  155. package/src/styles/index.css +0 -3
  156. package/src/test-setup.ts +0 -15
  157. package/src/testing/index.ts +0 -3
  158. package/src/testing/testing.utils.ts +0 -248
  159. package/src/types/frontend-tool.ts +0 -44
  160. package/src/types/human-in-the-loop.ts +0 -52
  161. package/src/utils/__tests__/agent.utils.spec.ts +0 -234
  162. package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
  163. package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
  164. package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
  165. package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
  166. package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
  167. package/src/utils/agent-context.utils.ts +0 -133
  168. package/src/utils/agent.utils.ts +0 -239
  169. package/src/utils/chat-config.utils.ts +0 -221
  170. package/src/utils/copilotkit.utils.ts +0 -20
  171. package/src/utils/frontend-tool.utils.ts +0 -266
  172. package/src/utils/human-in-the-loop.utils.ts +0 -359
  173. package/tsconfig.spec.json +0 -12
@@ -1,420 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- Output,
5
- EventEmitter,
6
- ContentChild,
7
- TemplateRef,
8
- Type,
9
- ViewChild,
10
- ElementRef,
11
- ChangeDetectionStrategy,
12
- ChangeDetectorRef,
13
- ViewEncapsulation,
14
- signal,
15
- computed,
16
- OnInit,
17
- OnChanges,
18
- OnDestroy,
19
- AfterViewInit,
20
- ViewContainerRef,
21
- effect
22
- } from '@angular/core';
23
- import { CommonModule } from '@angular/common';
24
- import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
25
- import { CopilotChatMessageViewComponent } from './copilot-chat-message-view.component';
26
- import { CopilotChatInputComponent } from './copilot-chat-input.component';
27
- import { CopilotChatViewScrollViewComponent } from './copilot-chat-view-scroll-view.component';
28
- import { CopilotChatViewScrollToBottomButtonComponent } from './copilot-chat-view-scroll-to-bottom-button.component';
29
- import { CopilotChatViewFeatherComponent } from './copilot-chat-view-feather.component';
30
- import { CopilotChatViewInputContainerComponent } from './copilot-chat-view-input-container.component';
31
- import { CopilotChatViewDisclaimerComponent } from './copilot-chat-view-disclaimer.component';
32
- import { Message } from '@ag-ui/client';
33
- import { cn } from '../../lib/utils';
34
- import { ResizeObserverService } from '../../services/resize-observer.service';
35
- import { CopilotChatViewHandlersService } from './copilot-chat-view-handlers.service';
36
- import { Subject } from 'rxjs';
37
- import { takeUntil } from 'rxjs/operators';
38
-
39
- /**
40
- * CopilotChatView component - Angular port of the React component.
41
- * A complete chat interface with message feed and input components.
42
- *
43
- * @example
44
- * ```html
45
- * <copilot-chat-view
46
- * [messages]="messages"
47
- * [autoScroll]="true"
48
- * [messageViewProps]="{ assistantMessage: { onThumbsUp: handleThumbsUp } }">
49
- * </copilot-chat-view>
50
- * ```
51
- */
52
- @Component({
53
- selector: 'copilot-chat-view',
54
- standalone: true,
55
- imports: [
56
- CommonModule,
57
- CopilotSlotComponent,
58
- CopilotChatMessageViewComponent,
59
- CopilotChatInputComponent,
60
- CopilotChatViewScrollViewComponent,
61
- CopilotChatViewScrollToBottomButtonComponent,
62
- CopilotChatViewFeatherComponent,
63
- CopilotChatViewInputContainerComponent,
64
- CopilotChatViewDisclaimerComponent
65
- ],
66
- changeDetection: ChangeDetectionStrategy.OnPush,
67
- encapsulation: ViewEncapsulation.None,
68
- providers: [ResizeObserverService, CopilotChatViewHandlersService],
69
- template: `
70
- <!-- Custom layout template support (render prop pattern) -->
71
- @if (customLayoutTemplate) {
72
- <ng-container *ngTemplateOutlet="customLayoutTemplate; context: layoutContext()"></ng-container>
73
- } @else {
74
- <!-- Default layout - exact React DOM structure -->
75
- <div [class]="computedClass()">
76
- <!-- ScrollView -->
77
- <copilot-chat-view-scroll-view
78
- [autoScroll]="autoScrollSignal()"
79
- [inputContainerHeight]="inputContainerHeight()"
80
- [isResizing]="isResizing()"
81
- [messages]="messagesSignal()"
82
- [messageView]="messageViewSlot()"
83
- [messageViewClass]="messageViewClass"
84
- [scrollToBottomButton]="scrollToBottomButtonSlot()"
85
- [scrollToBottomButtonClass]="scrollToBottomButtonClass"
86
- [showCursor]="showCursorSignal()"
87
- (assistantMessageThumbsUp)="assistantMessageThumbsUp.emit($event)"
88
- (assistantMessageThumbsDown)="assistantMessageThumbsDown.emit($event)"
89
- (assistantMessageReadAloud)="assistantMessageReadAloud.emit($event)"
90
- (assistantMessageRegenerate)="assistantMessageRegenerate.emit($event)"
91
- (userMessageCopy)="userMessageCopy.emit($event)"
92
- (userMessageEdit)="userMessageEdit.emit($event)">
93
- </copilot-chat-view-scroll-view>
94
-
95
- <!-- Feather effect -->
96
- <copilot-slot
97
- [slot]="featherSlot()"
98
- [context]="{ inputClass: featherClass }"
99
- [defaultComponent]="defaultFeatherComponent">
100
- </copilot-slot>
101
-
102
- <!-- Input container -->
103
- <copilot-slot
104
- #inputContainerSlotRef
105
- [slot]="inputContainerSlot()"
106
- [context]="inputContainerContext()"
107
- [defaultComponent]="defaultInputContainerComponent">
108
- </copilot-slot>
109
- </div>
110
- }
111
- `
112
- })
113
- export class CopilotChatViewComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
114
- // Core inputs matching React props
115
- @Input() messages: Message[] = [];
116
- @Input() autoScroll: boolean = true;
117
- @Input() showCursor: boolean = false;
118
-
119
- // MessageView slot inputs
120
- @Input() messageViewComponent?: Type<any>;
121
- @Input() messageViewTemplate?: TemplateRef<any>;
122
- @Input() messageViewClass?: string;
123
-
124
- // ScrollView slot inputs
125
- @Input() scrollViewComponent?: Type<any>;
126
- @Input() scrollViewTemplate?: TemplateRef<any>;
127
- @Input() scrollViewClass?: string;
128
-
129
- // ScrollToBottomButton slot inputs
130
- @Input() scrollToBottomButtonComponent?: Type<any>;
131
- @Input() scrollToBottomButtonTemplate?: TemplateRef<any>;
132
- @Input() scrollToBottomButtonClass?: string;
133
-
134
- // Input slot inputs
135
- @Input() inputComponent?: Type<any>;
136
- @Input() inputTemplate?: TemplateRef<any>;
137
-
138
- // InputContainer slot inputs
139
- @Input() inputContainerComponent?: Type<any>;
140
- @Input() inputContainerTemplate?: TemplateRef<any>;
141
- @Input() inputContainerClass?: string;
142
-
143
- // Feather slot inputs
144
- @Input() featherComponent?: Type<any>;
145
- @Input() featherTemplate?: TemplateRef<any>;
146
- @Input() featherClass?: string;
147
-
148
- // Disclaimer slot inputs
149
- @Input() disclaimerComponent?: Type<any>;
150
- @Input() disclaimerTemplate?: TemplateRef<any>;
151
- @Input() disclaimerClass?: string;
152
- @Input() disclaimerText?: string;
153
-
154
- // Custom layout template (render prop pattern)
155
- @ContentChild('customLayout') customLayoutTemplate?: TemplateRef<any>;
156
-
157
- // Named template slots for deep customization
158
- @ContentChild('sendButton') sendButtonTemplate?: TemplateRef<any>;
159
- @ContentChild('toolbar') toolbarTemplate?: TemplateRef<any>;
160
- @ContentChild('textArea') textAreaTemplate?: TemplateRef<any>;
161
- @ContentChild('audioRecorder') audioRecorderTemplate?: TemplateRef<any>;
162
- @ContentChild('assistantMessageMarkdownRenderer') assistantMessageMarkdownRendererTemplate?: TemplateRef<any>;
163
- @ContentChild('thumbsUpButton') thumbsUpButtonTemplate?: TemplateRef<any>;
164
- @ContentChild('thumbsDownButton') thumbsDownButtonTemplate?: TemplateRef<any>;
165
- @ContentChild('readAloudButton') readAloudButtonTemplate?: TemplateRef<any>;
166
- @ContentChild('regenerateButton') regenerateButtonTemplate?: TemplateRef<any>;
167
-
168
- // Output events for assistant message actions (bubbled from child components)
169
- @Output() assistantMessageThumbsUp = new EventEmitter<{ message: Message }>();
170
- @Output() assistantMessageThumbsDown = new EventEmitter<{ message: Message }>();
171
- @Output() assistantMessageReadAloud = new EventEmitter<{ message: Message }>();
172
- @Output() assistantMessageRegenerate = new EventEmitter<{ message: Message }>();
173
-
174
- // Output events for user message actions (if applicable)
175
- @Output() userMessageCopy = new EventEmitter<{ message: Message }>();
176
- @Output() userMessageEdit = new EventEmitter<{ message: Message }>();
177
-
178
- // ViewChild references
179
- @ViewChild('inputContainerSlotRef', { read: ElementRef }) inputContainerSlotRef?: ElementRef;
180
-
181
- // Default components for slots
182
- protected readonly defaultScrollViewComponent = CopilotChatViewScrollViewComponent;
183
- protected readonly defaultScrollToBottomButtonComponent = CopilotChatViewScrollToBottomButtonComponent;
184
- protected readonly defaultInputContainerComponent = CopilotChatViewInputContainerComponent;
185
- protected readonly defaultFeatherComponent = CopilotChatViewFeatherComponent;
186
- protected readonly defaultDisclaimerComponent = CopilotChatViewDisclaimerComponent;
187
-
188
- // Signals for reactive state
189
- protected messagesSignal = signal<Message[]>([]);
190
- protected autoScrollSignal = signal(true);
191
- protected showCursorSignal = signal(false);
192
- protected disclaimerTextSignal = signal<string | undefined>(undefined);
193
- protected disclaimerClassSignal = signal<string | undefined>(undefined);
194
- protected inputContainerHeight = signal<number>(0);
195
- protected isResizing = signal<boolean>(false);
196
- protected contentPaddingBottom = computed(() => this.inputContainerHeight() + 32);
197
-
198
- // Computed signals
199
- protected computedClass = computed(() => cn('relative h-full'));
200
-
201
- // Slot resolution computed signals
202
- protected messageViewSlot = computed(() =>
203
- this.messageViewTemplate || this.messageViewComponent
204
- );
205
-
206
- protected scrollViewSlot = computed(() =>
207
- this.scrollViewTemplate || this.scrollViewComponent
208
- );
209
-
210
- protected scrollToBottomButtonSlot = computed(() =>
211
- this.scrollToBottomButtonTemplate || this.scrollToBottomButtonComponent
212
- );
213
-
214
- protected inputSlot = computed(() =>
215
- this.inputTemplate || this.inputComponent
216
- );
217
-
218
- protected inputContainerSlot = computed(() =>
219
- this.inputContainerTemplate || this.inputContainerComponent
220
- );
221
-
222
- protected featherSlot = computed(() =>
223
- this.featherTemplate || this.featherComponent
224
- );
225
-
226
- protected disclaimerSlot = computed(() =>
227
- this.disclaimerTemplate || this.disclaimerComponent
228
- );
229
-
230
- // Context objects for slots
231
- protected scrollViewContext = computed(() => ({
232
- autoScroll: this.autoScrollSignal(),
233
- scrollToBottomButton: this.scrollToBottomButtonSlot(),
234
- scrollToBottomButtonClass: this.scrollToBottomButtonClass,
235
- inputContainerHeight: this.inputContainerHeight(),
236
- isResizing: this.isResizing(),
237
- messages: this.messagesSignal(),
238
- messageView: this.messageViewSlot(),
239
- messageViewClass: this.messageViewClass
240
- }));
241
-
242
- // Removed scrollViewPropsComputed - no longer needed
243
-
244
- protected inputContainerContext = computed(() => ({
245
- input: this.inputSlot(),
246
- disclaimer: this.disclaimerSlot(),
247
- disclaimerText: this.disclaimerTextSignal(),
248
- disclaimerClass: this.disclaimerClassSignal(),
249
- inputContainerClass: this.inputContainerClass
250
- }));
251
-
252
- // Removed inputContainerPropsComputed - no longer needed
253
-
254
- // Layout context for custom templates (render prop pattern)
255
- protected layoutContext = computed(() => ({
256
- messageView: this.messageViewSlot(),
257
- input: this.inputSlot(),
258
- scrollView: this.scrollViewSlot(),
259
- scrollToBottomButton: this.scrollToBottomButtonSlot(),
260
- feather: this.featherSlot(),
261
- inputContainer: this.inputContainerSlot(),
262
- disclaimer: this.disclaimerSlot()
263
- }));
264
-
265
- private destroy$ = new Subject<void>();
266
- private resizeTimeoutRef?: number;
267
-
268
- constructor(
269
- private resizeObserverService: ResizeObserverService,
270
- private cdr: ChangeDetectorRef,
271
- private handlers: CopilotChatViewHandlersService
272
- ) {
273
- // Set up effect to handle resize state timeout
274
- effect(() => {
275
- const resizing = this.isResizing();
276
- if (resizing && this.resizeTimeoutRef) {
277
- clearTimeout(this.resizeTimeoutRef);
278
- this.resizeTimeoutRef = undefined;
279
- }
280
- });
281
- }
282
-
283
- ngOnInit(): void {
284
- // Initialize signals with input values
285
- this.messagesSignal.set(this.messages);
286
- this.autoScrollSignal.set(this.autoScroll);
287
- this.showCursorSignal.set(this.showCursor);
288
- this.disclaimerTextSignal.set(this.disclaimerText);
289
- this.disclaimerClassSignal.set(this.disclaimerClass);
290
-
291
- // Initialize handler availability in the view-scoped service
292
- this.handlers.hasAssistantThumbsUpHandler.set(this.assistantMessageThumbsUp.observed);
293
- this.handlers.hasAssistantThumbsDownHandler.set(this.assistantMessageThumbsDown.observed);
294
- this.handlers.hasAssistantReadAloudHandler.set(this.assistantMessageReadAloud.observed);
295
- this.handlers.hasAssistantRegenerateHandler.set(this.assistantMessageRegenerate.observed);
296
- this.handlers.hasUserCopyHandler.set(this.userMessageCopy.observed);
297
- this.handlers.hasUserEditHandler.set(this.userMessageEdit.observed);
298
- }
299
-
300
- ngOnChanges(): void {
301
- // Update signals when inputs change
302
- this.messagesSignal.set(this.messages);
303
- this.autoScrollSignal.set(this.autoScroll);
304
- this.showCursorSignal.set(this.showCursor);
305
- this.disclaimerTextSignal.set(this.disclaimerText);
306
- this.disclaimerClassSignal.set(this.disclaimerClass);
307
-
308
- // Keep handler availability in sync
309
- this.handlers.hasAssistantThumbsUpHandler.set(this.assistantMessageThumbsUp.observed);
310
- this.handlers.hasAssistantThumbsDownHandler.set(this.assistantMessageThumbsDown.observed);
311
- this.handlers.hasAssistantReadAloudHandler.set(this.assistantMessageReadAloud.observed);
312
- this.handlers.hasAssistantRegenerateHandler.set(this.assistantMessageRegenerate.observed);
313
- this.handlers.hasUserCopyHandler.set(this.userMessageCopy.observed);
314
- this.handlers.hasUserEditHandler.set(this.userMessageEdit.observed);
315
- }
316
-
317
- ngAfterViewInit(): void {
318
- // Don't set a default height - measure it dynamically
319
-
320
- // Set up input container height monitoring
321
- const measureAndObserve = () => {
322
- if (!this.inputContainerSlotRef || !this.inputContainerSlotRef.nativeElement) {
323
- return false;
324
- }
325
-
326
- // The slot ref points to the copilot-slot element
327
- // We need to find the actual input container component inside it
328
- const slotElement = this.inputContainerSlotRef.nativeElement;
329
- const componentElement = slotElement.querySelector('copilot-chat-view-input-container');
330
-
331
- if (!componentElement) {
332
- return false;
333
- }
334
-
335
- // Look for the absolute positioned div that contains the input
336
- let innerDiv = componentElement.querySelector('div.absolute') as HTMLElement;
337
-
338
- // If not found by class, try first child
339
- if (!innerDiv) {
340
- innerDiv = componentElement.firstElementChild as HTMLElement;
341
- }
342
-
343
- if (!innerDiv) {
344
- return false;
345
- }
346
-
347
- // Measure the actual height
348
- const measuredHeight = innerDiv.offsetHeight;
349
-
350
- if (measuredHeight === 0) {
351
- return false;
352
- }
353
-
354
- // Success! Set the initial height
355
- this.inputContainerHeight.set(measuredHeight);
356
- this.cdr.detectChanges();
357
-
358
- // Create an ElementRef wrapper for ResizeObserver
359
- const innerDivRef = new ElementRef(innerDiv);
360
-
361
- // Set up ResizeObserver to track changes
362
- this.resizeObserverService.observeElement(innerDivRef, 0, 250)
363
- .pipe(takeUntil(this.destroy$))
364
- .subscribe(state => {
365
- const newHeight = state.height;
366
-
367
- if (newHeight !== this.inputContainerHeight() && newHeight > 0) {
368
- this.inputContainerHeight.set(newHeight);
369
- this.isResizing.set(true);
370
- this.cdr.detectChanges();
371
-
372
- // Clear existing timeout
373
- if (this.resizeTimeoutRef) {
374
- clearTimeout(this.resizeTimeoutRef);
375
- }
376
-
377
- // Set isResizing to false after a short delay
378
- this.resizeTimeoutRef = window.setTimeout(() => {
379
- this.isResizing.set(false);
380
- this.resizeTimeoutRef = undefined;
381
- this.cdr.detectChanges();
382
- }, 250);
383
- }
384
- });
385
-
386
- return true;
387
- };
388
-
389
- // Try to measure immediately
390
- if (!measureAndObserve()) {
391
- // If failed, retry with increasing delays
392
- let attempts = 0;
393
- const maxAttempts = 10;
394
-
395
- const retry = () => {
396
- attempts++;
397
- if (measureAndObserve()) {
398
- // Successfully measured
399
- } else if (attempts < maxAttempts) {
400
- // Exponential backoff: 50ms, 100ms, 200ms, 400ms, etc.
401
- const delay = 50 * Math.pow(2, Math.min(attempts - 1, 4));
402
- setTimeout(retry, delay);
403
- } else {
404
- // Failed to measure after max attempts
405
- }
406
- };
407
-
408
- // Start retry with first delay
409
- setTimeout(retry, 50);
410
- }
411
- }
412
-
413
- ngOnDestroy(): void {
414
- if (this.resizeTimeoutRef) {
415
- clearTimeout(this.resizeTimeoutRef);
416
- }
417
- this.destroy$.next();
418
- this.destroy$.complete();
419
- }
420
- }
@@ -1,52 +0,0 @@
1
- import { Type, TemplateRef } from '@angular/core';
2
- import { Message } from '@ag-ui/client';
3
-
4
- /**
5
- * Props for CopilotChatView component
6
- */
7
- export interface CopilotChatViewProps {
8
- messages?: Message[];
9
- autoScroll?: boolean;
10
-
11
- // Slot configurations
12
- messageViewComponent?: Type<any>;
13
- messageViewTemplate?: TemplateRef<any>;
14
- messageViewClass?: string;
15
-
16
- scrollViewComponent?: Type<any>;
17
- scrollViewTemplate?: TemplateRef<any>;
18
- scrollViewClass?: string;
19
-
20
- scrollToBottomButtonComponent?: Type<any>;
21
- scrollToBottomButtonTemplate?: TemplateRef<any>;
22
- scrollToBottomButtonClass?: string;
23
-
24
- inputComponent?: Type<any>;
25
- inputTemplate?: TemplateRef<any>;
26
-
27
- inputContainerComponent?: Type<any>;
28
- inputContainerTemplate?: TemplateRef<any>;
29
- inputContainerClass?: string;
30
-
31
- featherComponent?: Type<any>;
32
- featherTemplate?: TemplateRef<any>;
33
- featherClass?: string;
34
-
35
- disclaimerComponent?: Type<any>;
36
- disclaimerTemplate?: TemplateRef<any>;
37
- disclaimerClass?: string;
38
- disclaimerText?: string;
39
- }
40
-
41
- /**
42
- * Context for custom layout template
43
- */
44
- export interface CopilotChatViewLayoutContext {
45
- messageView: any;
46
- input: any;
47
- scrollView: any;
48
- scrollToBottomButton: any;
49
- feather: any;
50
- inputContainer: any;
51
- disclaimer: any;
52
- }
@@ -1,232 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- OnInit,
5
- OnChanges,
6
- OnDestroy,
7
- SimpleChanges,
8
- ChangeDetectionStrategy,
9
- ViewEncapsulation,
10
- signal,
11
- effect,
12
- ChangeDetectorRef,
13
- Signal,
14
- Injector,
15
- runInInjectionContext,
16
- Optional,
17
- SkipSelf,
18
- } from "@angular/core";
19
- import { CommonModule } from "@angular/common";
20
- import { CopilotChatViewComponent } from "./copilot-chat-view.component";
21
- import { CopilotChatConfigurationService } from "../../core/chat-configuration/chat-configuration.service";
22
- import {
23
- COPILOT_CHAT_INITIAL_CONFIG,
24
- CopilotChatConfiguration,
25
- } from "../../core/chat-configuration/chat-configuration.types";
26
- import { watchAgent } from "../../utils/agent.utils";
27
- import { AgentWatchResult } from "../../core/copilotkit.types";
28
- import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkitnext/shared";
29
- import { Message, AbstractAgent } from "@ag-ui/client";
30
-
31
- /**
32
- * CopilotChat component - Angular equivalent of React's <CopilotChat>
33
- * Provides a complete chat interface that wires an agent to the chat view
34
- *
35
- * @example
36
- * ```html
37
- * <copilot-chat [agentId]="'default'" [threadId]="'abc123'"></copilot-chat>
38
- * ```
39
- */
40
- @Component({
41
- selector: "copilot-chat",
42
- standalone: true,
43
- imports: [CommonModule, CopilotChatViewComponent],
44
- changeDetection: ChangeDetectionStrategy.OnPush,
45
- encapsulation: ViewEncapsulation.None,
46
- providers: [
47
- {
48
- provide: CopilotChatConfigurationService,
49
- deps: [
50
- [new Optional(), new SkipSelf(), CopilotChatConfigurationService],
51
- [new Optional(), COPILOT_CHAT_INITIAL_CONFIG],
52
- ],
53
- useFactory: (
54
- parent: CopilotChatConfigurationService | null,
55
- initial: CopilotChatConfiguration | null
56
- ) => parent ?? new CopilotChatConfigurationService(initial ?? null),
57
- },
58
- ],
59
- template: `
60
- <copilot-chat-view
61
- [messages]="messages()"
62
- [autoScroll]="true"
63
- [messageViewClass]="'w-full'"
64
- [showCursor]="showCursor()"
65
- >
66
- </copilot-chat-view>
67
- `,
68
- })
69
- export class CopilotChatComponent implements OnInit, OnChanges, OnDestroy {
70
- @Input() agentId?: string;
71
- @Input() threadId?: string;
72
-
73
- constructor(
74
- @Optional() private chatConfig: CopilotChatConfigurationService | null,
75
- private cdr: ChangeDetectorRef,
76
- private injector: Injector
77
- ) {
78
- // Create initial watcher once (constructor is a safe injection context)
79
- const initialId = this.agentId ?? DEFAULT_AGENT_ID;
80
- this.createWatcher(initialId);
81
-
82
- // Connect once when agent becomes available
83
- effect(() => {
84
- const a = this.agent();
85
- if (!a) return;
86
- // Apply thread id when agent is available
87
- a.threadId = this.threadId || this.generatedThreadId;
88
- if (!this.hasConnectedOnce) {
89
- this.hasConnectedOnce = true;
90
- this.connectToAgent(a);
91
- }
92
- });
93
- }
94
-
95
- // Signals from watchAgent - using direct references instead of assignment
96
- protected agent: Signal<AbstractAgent | undefined> = signal<
97
- AbstractAgent | undefined
98
- >(undefined).asReadonly() as unknown as Signal<AbstractAgent | undefined>;
99
- protected messages: Signal<Message[]> = signal<Message[]>(
100
- []
101
- ).asReadonly() as unknown as Signal<Message[]>;
102
- protected isRunning: Signal<boolean> = signal<boolean>(
103
- false
104
- ).asReadonly() as unknown as Signal<boolean>;
105
- protected showCursor = signal<boolean>(false);
106
-
107
- private generatedThreadId: string = randomUUID();
108
- private agentWatcher?: AgentWatchResult;
109
- private hasConnectedOnce = false;
110
- private lastAgentId?: string;
111
-
112
- ngOnInit(): void {
113
- this.setupChatHandlers();
114
- }
115
-
116
- ngOnChanges(changes: SimpleChanges): void {
117
- if (changes["agentId"] && !changes["agentId"].firstChange) {
118
- const newId = this.agentId ?? DEFAULT_AGENT_ID;
119
- this.createWatcher(newId);
120
- }
121
- if (changes["threadId"] && !changes["threadId"].firstChange) {
122
- const a = this.agent();
123
- if (a) {
124
- a.threadId = this.threadId || this.generatedThreadId;
125
- }
126
- }
127
- }
128
-
129
- private async connectToAgent(agent: AbstractAgent): Promise<void> {
130
- if (!agent) return;
131
-
132
- this.showCursor.set(true);
133
- this.cdr.markForCheck();
134
-
135
- try {
136
- await agent.runAgent(
137
- { forwardedProps: { __copilotkitConnect: true } },
138
- {
139
- onTextMessageStartEvent: () => {
140
- this.showCursor.set(false);
141
- this.cdr.detectChanges();
142
- },
143
- onToolCallStartEvent: () => {
144
- this.showCursor.set(false);
145
- this.cdr.detectChanges();
146
- },
147
- }
148
- );
149
- this.showCursor.set(false);
150
- this.cdr.markForCheck();
151
- } catch (error) {
152
- console.error("Failed to connect to agent:", error);
153
- this.showCursor.set(false);
154
- this.cdr.markForCheck();
155
- }
156
- }
157
-
158
- private setupChatHandlers(): void {
159
- if (!this.chatConfig) return;
160
-
161
- // Handle input submission
162
- this.chatConfig.setSubmitHandler(async (value: string) => {
163
- const agent = this.agent();
164
- if (!agent || !value.trim()) return;
165
-
166
- // Add user message
167
- const userMessage: Message = {
168
- id: randomUUID(),
169
- role: "user",
170
- content: value,
171
- };
172
- agent.addMessage(userMessage);
173
-
174
- // Clear the input
175
- this.chatConfig!.setInputValue("");
176
-
177
- // Show cursor while processing
178
- this.showCursor.set(true);
179
- this.cdr.markForCheck();
180
-
181
- // Run the agent with named subscriber callbacks
182
- try {
183
- await agent.runAgent(
184
- {},
185
- {
186
- onTextMessageStartEvent: () => {
187
- this.showCursor.set(false);
188
- this.cdr.detectChanges();
189
- },
190
- onToolCallStartEvent: () => {
191
- this.showCursor.set(false);
192
- this.cdr.detectChanges();
193
- },
194
- }
195
- );
196
- } catch (error) {
197
- console.error("Agent run error:", error);
198
- } finally {
199
- this.showCursor.set(false);
200
- this.cdr.markForCheck();
201
- }
202
- });
203
-
204
- // Handle input value changes (optional)
205
- this.chatConfig.setChangeHandler(() => {
206
- // Keep input state if needed
207
- });
208
- }
209
-
210
- ngOnDestroy(): void {
211
- if (this.agentWatcher?.unsubscribe) {
212
- this.agentWatcher.unsubscribe();
213
- }
214
- }
215
-
216
- private createWatcher(desiredAgentId: string) {
217
- // Tear down previous watcher if it exists
218
- if (this.agentWatcher?.unsubscribe) {
219
- this.agentWatcher.unsubscribe();
220
- this.agentWatcher = undefined;
221
- }
222
- // Setup watcher for desired agent - ensure injection context
223
- this.agentWatcher = runInInjectionContext(this.injector, () =>
224
- watchAgent({ agentId: desiredAgentId })
225
- );
226
- this.agent = this.agentWatcher.agent;
227
- this.messages = this.agentWatcher.messages;
228
- this.isRunning = this.agentWatcher.isRunning;
229
- this.hasConnectedOnce = false;
230
- this.lastAgentId = desiredAgentId;
231
- }
232
- }