@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,261 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- ViewContainerRef,
5
- ComponentRef,
6
- inject,
7
- ViewChild,
8
- AfterViewInit,
9
- OnChanges,
10
- SimpleChanges,
11
- TemplateRef,
12
- Type,
13
- ChangeDetectionStrategy,
14
- signal,
15
- computed,
16
- OnDestroy,
17
- } from "@angular/core";
18
- import { CommonModule } from "@angular/common";
19
- import type {
20
- AssistantMessage,
21
- Message,
22
- ToolCall,
23
- ToolMessage,
24
- } from "@ag-ui/core";
25
- import { ToolCallStatus } from "@copilotkitnext/core";
26
- import { CopilotKitService } from "../../core/copilotkit.service";
27
- import { partialJSONParse } from "@copilotkitnext/shared";
28
- import type {
29
- ToolCallProps,
30
- ToolCallRender,
31
- } from "../../core/copilotkit.types";
32
-
33
- /**
34
- * Component for rendering all tool calls for an assistant message.
35
- * This component iterates through the message's tool calls and renders each one
36
- * using the registered render functions in CopilotKitService.
37
- */
38
- @Component({
39
- selector: "copilot-chat-tool-calls-view",
40
- standalone: true,
41
- imports: [CommonModule],
42
- changeDetection: ChangeDetectionStrategy.OnPush,
43
- template: `
44
- @for (toolCall of message?.toolCalls ?? []; track toolCall.id) {
45
- <ng-container>
46
- <ng-container #dynamicContainer></ng-container>
47
- <ng-container *ngIf="getTemplateForToolCall(toolCall) as templateData">
48
- <ng-container
49
- *ngTemplateOutlet="
50
- templateData.template;
51
- context: templateData.context
52
- "
53
- ></ng-container>
54
- </ng-container>
55
- </ng-container>
56
- }
57
- `,
58
- })
59
- export class CopilotChatToolCallsViewComponent
60
- implements AfterViewInit, OnChanges, OnDestroy
61
- {
62
- @Input({ required: true }) message!: AssistantMessage;
63
- @Input() messages: Message[] = [];
64
- @Input() isLoading = false;
65
-
66
- @ViewChild("dynamicContainer", { read: ViewContainerRef })
67
- private container?: ViewContainerRef;
68
-
69
- private copilotkit: CopilotKitService | null = inject(CopilotKitService, {
70
- optional: true,
71
- });
72
- private componentRefs: Map<string, ComponentRef<any>> = new Map();
73
- private templateCache: Map<
74
- string,
75
- { template: TemplateRef<any>; context: any }
76
- > = new Map();
77
-
78
- // Signals for reactive state
79
- private messageSignal = signal<AssistantMessage | null>(null);
80
- private messagesSignal = signal<Message[]>([]);
81
- private isLoadingSignal = signal(false);
82
-
83
- ngAfterViewInit(): void {
84
- this.renderAllToolCalls();
85
- }
86
-
87
- ngOnChanges(changes: SimpleChanges): void {
88
- if (changes["message"]) {
89
- this.messageSignal.set(this.message);
90
- }
91
- if (changes["messages"]) {
92
- this.messagesSignal.set(this.messages);
93
- }
94
- if (changes["isLoading"]) {
95
- this.isLoadingSignal.set(this.isLoading);
96
- }
97
-
98
- this.renderAllToolCalls();
99
- }
100
-
101
- ngOnDestroy(): void {
102
- // Clean up all component refs
103
- this.componentRefs.forEach((ref) => ref.destroy());
104
- this.componentRefs.clear();
105
- this.templateCache.clear();
106
- }
107
-
108
- getTemplateForToolCall(
109
- toolCall: ToolCall
110
- ): { template: TemplateRef<any>; context: any } | null {
111
- return this.templateCache.get(toolCall.id) || null;
112
- }
113
-
114
- private renderAllToolCalls(): void {
115
- const message = this.messageSignal();
116
- if (!message || !message.toolCalls || message.toolCalls.length === 0) {
117
- return;
118
- }
119
-
120
- // Clear existing renders
121
- this.componentRefs.forEach((ref) => ref.destroy());
122
- this.componentRefs.clear();
123
- this.templateCache.clear();
124
-
125
- if (!this.copilotkit || !this.container) {
126
- return;
127
- }
128
-
129
- const messages = this.messagesSignal();
130
- const isLoading = this.isLoadingSignal();
131
-
132
- // Render each tool call
133
- message.toolCalls.forEach((toolCall) => {
134
- const toolMessage = messages.find(
135
- (m) =>
136
- m.role === "tool" && (m as ToolMessage).toolCallId === toolCall.id
137
- ) as ToolMessage | undefined;
138
-
139
- this.renderSingleToolCall(toolCall, toolMessage, isLoading);
140
- });
141
- }
142
-
143
- private renderSingleToolCall(
144
- toolCall: ToolCall,
145
- toolMessage: ToolMessage | undefined,
146
- isLoading: boolean
147
- ): void {
148
- if (!this.copilotkit) {
149
- return;
150
- }
151
-
152
- // Get current render tool calls
153
- const currentRenderToolCalls = this.copilotkit.currentRenderToolCalls();
154
-
155
- // Find the render config for this tool call by name
156
- // Also check for wildcard (*) renders if no exact match
157
- const renderConfig =
158
- currentRenderToolCalls.find(
159
- (rc: ToolCallRender) => rc.name === toolCall.function.name
160
- ) || currentRenderToolCalls.find((rc: ToolCallRender) => rc.name === "*");
161
-
162
- if (!renderConfig) {
163
- return;
164
- }
165
-
166
- // Parse the arguments if they're a string
167
- const args = partialJSONParse(toolCall.function.arguments);
168
-
169
- // Determine status
170
- let status: ToolCallStatus;
171
- if (toolMessage) {
172
- status = ToolCallStatus.Complete;
173
- } else if (isLoading) {
174
- status = ToolCallStatus.InProgress;
175
- } else {
176
- status = ToolCallStatus.Complete;
177
- }
178
-
179
- // Create props based on status - use discriminated union properly
180
- let props: ToolCallProps;
181
- if (status === ToolCallStatus.InProgress) {
182
- props = {
183
- name: toolCall.function.name,
184
- description: "",
185
- args: args, // Partial args for InProgress
186
- status: ToolCallStatus.InProgress,
187
- result: undefined,
188
- };
189
- } else {
190
- // Complete status
191
- props = {
192
- name: toolCall.function.name,
193
- description: "",
194
- args: args, // Full args for Complete
195
- status: ToolCallStatus.Complete,
196
- result: toolMessage?.content || "",
197
- };
198
- }
199
-
200
- // Check if render is a Component class or TemplateRef
201
- if (this.isComponentClass(renderConfig.render)) {
202
- // Create component dynamically
203
- this.renderComponent(toolCall.id, renderConfig.render, props);
204
- } else if (this.isTemplateRef(renderConfig.render)) {
205
- // Use template
206
- this.renderTemplate(toolCall.id, renderConfig.render, props);
207
- }
208
- }
209
-
210
- private renderComponent(
211
- toolCallId: string,
212
- componentClass: Type<any>,
213
- props: ToolCallProps
214
- ): void {
215
- if (!this.container) {
216
- return;
217
- }
218
-
219
- // Create the component
220
- const componentRef = this.container.createComponent(componentClass);
221
- this.componentRefs.set(toolCallId, componentRef);
222
-
223
- // Set inputs on the component
224
- for (const [key, value] of Object.entries(props)) {
225
- try {
226
- componentRef.setInput(key, value);
227
- } catch (e) {
228
- // Input might not exist on the component, which is fine
229
- }
230
- }
231
-
232
- // Trigger change detection
233
- componentRef.changeDetectorRef.detectChanges();
234
- }
235
-
236
- private renderTemplate(
237
- toolCallId: string,
238
- template: TemplateRef<any>,
239
- props: ToolCallProps
240
- ): void {
241
- this.templateCache.set(toolCallId, {
242
- template,
243
- context: {
244
- $implicit: props,
245
- name: props.name,
246
- description: props.description,
247
- args: props.args,
248
- status: props.status,
249
- result: props.result,
250
- },
251
- });
252
- }
253
-
254
- private isComponentClass(value: any): value is Type<any> {
255
- return typeof value === "function" && value.prototype;
256
- }
257
-
258
- private isTemplateRef(value: any): value is TemplateRef<any> {
259
- return value instanceof TemplateRef;
260
- }
261
- }
@@ -1,35 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- signal,
5
- computed,
6
- ChangeDetectionStrategy,
7
- ViewEncapsulation
8
- } from '@angular/core';
9
- import { CommonModule } from '@angular/common';
10
- import { cn } from '../../lib/utils';
11
-
12
- @Component({
13
- selector: 'div[copilotChatToolbar]',
14
- standalone: true,
15
- imports: [CommonModule],
16
- changeDetection: ChangeDetectionStrategy.OnPush,
17
- encapsulation: ViewEncapsulation.None,
18
- host: {
19
- '[class]': 'computedClass()'
20
- },
21
- template: `<ng-content></ng-content>`,
22
- styles: []
23
- })
24
- export class CopilotChatToolbarComponent {
25
- @Input() set inputClass(val: string | undefined) {
26
- this.customClass.set(val);
27
- }
28
-
29
- customClass = signal<string | undefined>(undefined);
30
-
31
- computedClass = computed(() => {
32
- const baseClasses = 'w-full h-[60px] bg-transparent flex items-center justify-between';
33
- return cn(baseClasses, this.customClass());
34
- });
35
- }
@@ -1,185 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- signal,
5
- computed,
6
- inject,
7
- ChangeDetectionStrategy,
8
- ViewEncapsulation
9
- } from '@angular/core';
10
- import { CommonModule } from '@angular/common';
11
- import { CdkMenuModule } from '@angular/cdk/menu';
12
- import { OverlayModule } from '@angular/cdk/overlay';
13
- import { LucideAngularModule, Settings2, ChevronRight } from 'lucide-angular';
14
- import { CopilotChatConfigurationService } from '../../core/chat-configuration/chat-configuration.service';
15
- import type { ToolsMenuItem } from './copilot-chat-input.types';
16
- import { cn } from '../../lib/utils';
17
-
18
- @Component({
19
- selector: 'copilot-chat-tools-menu',
20
- standalone: true,
21
- imports: [
22
- CommonModule,
23
- CdkMenuModule,
24
- OverlayModule,
25
- LucideAngularModule
26
- ],
27
- changeDetection: ChangeDetectionStrategy.OnPush,
28
- encapsulation: ViewEncapsulation.None,
29
- template: `
30
- @if (hasItems()) {
31
- <button
32
- type="button"
33
- [disabled]="disabled()"
34
- [class]="buttonClass()"
35
- [cdkMenuTriggerFor]="menu"
36
- >
37
- <lucide-angular [img]="Settings2Icon" [size]="18"></lucide-angular>
38
- <span class="text-sm font-normal">{{ label() }}</span>
39
- </button>
40
-
41
- <ng-template #menu>
42
- <div class="min-w-[200px] bg-white dark:bg-[#1F1F1F] border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-1"
43
- cdkMenu>
44
- @for (item of toolsMenu(); track $index) {
45
- @if (item === '-') {
46
- <div class="h-px bg-gray-200 dark:bg-gray-700 my-1"></div>
47
- } @else if (isMenuItem(item)) {
48
- @if (item.items && item.items.length > 0) {
49
- <!-- Submenu trigger -->
50
- <button
51
- type="button"
52
- class="w-full px-3 py-2 text-left bg-transparent border-none rounded hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer text-sm flex items-center justify-between"
53
- [cdkMenuTriggerFor]="submenu"
54
- cdkMenuItem
55
- >
56
- {{ item.label }}
57
- <lucide-angular [img]="ChevronRightIcon" [size]="12" class="ml-auto"></lucide-angular>
58
- </button>
59
-
60
- <!-- Submenu template -->
61
- <ng-template #submenu>
62
- <div class="min-w-[200px] bg-white dark:bg-[#1F1F1F] border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg p-1"
63
- cdkMenu>
64
- @for (subItem of item.items; track $index) {
65
- @if (subItem === '-') {
66
- <div class="h-px bg-gray-200 dark:bg-gray-700 my-1"></div>
67
- } @else if (isMenuItem(subItem)) {
68
- <button
69
- type="button"
70
- class="w-full px-3 py-2 text-left bg-transparent border-none rounded hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer text-sm"
71
- (click)="handleItemClick(subItem)"
72
- cdkMenuItem
73
- >
74
- {{ subItem.label }}
75
- </button>
76
- }
77
- }
78
- </div>
79
- </ng-template>
80
- } @else {
81
- <!-- Regular menu item -->
82
- <button
83
- type="button"
84
- class="w-full px-3 py-2 text-left bg-transparent border-none rounded hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer text-sm"
85
- (click)="handleItemClick(item)"
86
- cdkMenuItem
87
- >
88
- {{ item.label }}
89
- </button>
90
- }
91
- }
92
- }
93
- </div>
94
- </ng-template>
95
- }
96
- `,
97
- styles: [`
98
- /* CDK Overlay styles for positioning */
99
- .cdk-overlay-pane {
100
- position: absolute;
101
- pointer-events: auto;
102
- z-index: 1000;
103
- }
104
-
105
- /* Ensure menu appears above other content */
106
- .cdk-overlay-container {
107
- position: fixed;
108
- z-index: 1000;
109
- }
110
-
111
- /* Menu animation */
112
- [cdkMenu] {
113
- animation: menuFadeIn 0.15s ease-out;
114
- }
115
-
116
- @keyframes menuFadeIn {
117
- from {
118
- opacity: 0;
119
- transform: translateY(4px);
120
- }
121
- to {
122
- opacity: 1;
123
- transform: translateY(0);
124
- }
125
- }
126
- `]
127
- })
128
- export class CopilotChatToolsMenuComponent {
129
- readonly Settings2Icon = Settings2;
130
- readonly ChevronRightIcon = ChevronRight;
131
-
132
- @Input() set inputToolsMenu(val: (ToolsMenuItem | '-')[] | undefined) {
133
- this.toolsMenu.set(val || []);
134
- }
135
- @Input() set inputDisabled(val: boolean | undefined) {
136
- this.disabled.set(val || false);
137
- }
138
- @Input() set inputClass(val: string | undefined) {
139
- this.customClass.set(val);
140
- }
141
-
142
- private chatConfig = inject(CopilotChatConfigurationService);
143
-
144
- toolsMenu = signal<(ToolsMenuItem | '-')[]>([]);
145
- disabled = signal<boolean>(false);
146
- customClass = signal<string | undefined>(undefined);
147
-
148
- hasItems = computed(() => this.toolsMenu().length > 0);
149
-
150
- label = computed(() => this.chatConfig.labels().chatInputToolbarToolsButtonLabel);
151
-
152
- buttonClass = computed(() => {
153
- const baseClasses = cn(
154
- // Base button styles
155
- 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium',
156
- 'transition-all disabled:pointer-events-none disabled:opacity-50',
157
- 'shrink-0 outline-none',
158
- 'focus-visible:ring-[3px]',
159
- // chatInputToolbarSecondary variant
160
- 'cursor-pointer',
161
- 'bg-transparent text-[#444444]',
162
- 'dark:text-white dark:border-[#404040]',
163
- 'transition-colors',
164
- 'focus:outline-none',
165
- 'hover:bg-[#f8f8f8] hover:text-[#333333]',
166
- 'dark:hover:bg-[#404040] dark:hover:text-[#FFFFFF]',
167
- 'disabled:cursor-not-allowed disabled:opacity-50',
168
- 'disabled:hover:bg-transparent disabled:hover:text-[#444444]',
169
- 'dark:disabled:hover:bg-transparent dark:disabled:hover:text-[#CCCCCC]',
170
- // Size
171
- 'h-9 px-3 gap-2 font-normal'
172
- );
173
- return cn(baseClasses, this.customClass());
174
- });
175
-
176
- isMenuItem(item: any): item is ToolsMenuItem {
177
- return item && typeof item === 'object' && 'label' in item;
178
- }
179
-
180
- handleItemClick(item: ToolsMenuItem): void {
181
- if (item.action) {
182
- item.action();
183
- }
184
- }
185
- }
@@ -1,121 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- Output,
5
- EventEmitter,
6
- ChangeDetectionStrategy,
7
- ViewEncapsulation,
8
- computed,
9
- signal
10
- } from '@angular/core';
11
- import { CommonModule } from '@angular/common';
12
- import { LucideAngularModule, ChevronLeft, ChevronRight } from 'lucide-angular';
13
- import {
14
- type UserMessage,
15
- type CopilotChatUserMessageOnSwitchToBranchProps
16
- } from './copilot-chat-user-message.types';
17
- import { cn } from '../../lib/utils';
18
-
19
- @Component({
20
- selector: 'copilot-chat-user-message-branch-navigation',
21
- standalone: true,
22
- imports: [CommonModule, LucideAngularModule],
23
- changeDetection: ChangeDetectionStrategy.OnPush,
24
- encapsulation: ViewEncapsulation.None,
25
- template: `
26
- @if (showNavigation()) {
27
- <div [class]="computedClass()">
28
- <button
29
- type="button"
30
- [class]="buttonClass"
31
- [disabled]="!canGoPrev()"
32
- (click)="handlePrevious()">
33
- <lucide-angular [img]="ChevronLeftIcon" [size]="20"></lucide-angular>
34
- </button>
35
- <span class="text-sm text-muted-foreground px-0 font-medium">
36
- {{ currentBranchSignal() + 1 }}/{{ numberOfBranchesSignal() }}
37
- </span>
38
- <button
39
- type="button"
40
- [class]="buttonClass"
41
- [disabled]="!canGoNext()"
42
- (click)="handleNext()">
43
- <lucide-angular [img]="ChevronRightIcon" [size]="20"></lucide-angular>
44
- </button>
45
- </div>
46
- }
47
- `
48
- })
49
- export class CopilotChatUserMessageBranchNavigationComponent {
50
- @Input() set currentBranch(val: number) {
51
- this.currentBranchSignal.set(val);
52
- }
53
- @Input() set numberOfBranches(val: number) {
54
- this.numberOfBranchesSignal.set(val);
55
- }
56
- @Input() message!: UserMessage;
57
- @Input() inputClass?: string;
58
- @Output() switchToBranch = new EventEmitter<CopilotChatUserMessageOnSwitchToBranchProps>();
59
-
60
- readonly ChevronLeftIcon = ChevronLeft;
61
- readonly ChevronRightIcon = ChevronRight;
62
-
63
- currentBranchSignal = signal(0);
64
- numberOfBranchesSignal = signal(1);
65
-
66
- readonly buttonClass = cn(
67
- // Flex centering
68
- 'inline-flex items-center justify-center',
69
- // Cursor
70
- 'cursor-pointer',
71
- // Background and text
72
- 'p-0 text-[rgb(93,93,93)] hover:bg-[#E8E8E8]',
73
- // Dark mode
74
- 'dark:text-[rgb(243,243,243)] dark:hover:bg-[#303030]',
75
- // Shape and sizing
76
- 'h-6 w-6 rounded-md',
77
- // Interactions
78
- 'transition-colors',
79
- // Disabled state
80
- 'disabled:opacity-50 disabled:cursor-not-allowed'
81
- );
82
-
83
- showNavigation = computed(() => {
84
- const branches = this.numberOfBranchesSignal();
85
- return branches > 1;
86
- });
87
-
88
- canGoPrev = computed(() => {
89
- return this.currentBranchSignal() > 0;
90
- });
91
-
92
- canGoNext = computed(() => {
93
- return this.currentBranchSignal() < this.numberOfBranchesSignal() - 1;
94
- });
95
-
96
- computedClass = computed(() => {
97
- return cn('flex items-center gap-1', this.inputClass);
98
- });
99
-
100
- handlePrevious(): void {
101
- if (this.canGoPrev()) {
102
- const newIndex = this.currentBranchSignal() - 1;
103
- this.switchToBranch.emit({
104
- branchIndex: newIndex,
105
- numberOfBranches: this.numberOfBranchesSignal(),
106
- message: this.message
107
- });
108
- }
109
- }
110
-
111
- handleNext(): void {
112
- if (this.canGoNext()) {
113
- const newIndex = this.currentBranchSignal() + 1;
114
- this.switchToBranch.emit({
115
- branchIndex: newIndex,
116
- numberOfBranches: this.numberOfBranchesSignal(),
117
- message: this.message
118
- });
119
- }
120
- }
121
- }