@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.
Files changed (171) hide show
  1. package/README.md +248 -0
  2. package/dist/README.md +248 -0
  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/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
  7. package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
  8. package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
  9. package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
  10. package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
  11. package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
  12. package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
  13. package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
  14. package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
  15. package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
  16. package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
  17. package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
  18. package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
  19. package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
  20. package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
  21. package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
  22. package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
  23. package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
  24. package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
  25. package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
  26. package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
  27. package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
  28. package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
  29. package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
  30. package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
  31. package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
  32. package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
  33. package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
  34. package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
  35. package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
  36. package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
  37. package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
  38. package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
  39. package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
  40. package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
  41. package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
  42. package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
  43. package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
  44. package/dist/esm2022/core/copilotkit.service.mjs +430 -0
  45. package/dist/esm2022/core/copilotkit.types.mjs +12 -0
  46. package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
  47. package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
  48. package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
  49. package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
  50. package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +130 -0
  51. package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +266 -0
  52. package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
  53. package/dist/esm2022/index.mjs +70 -0
  54. package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
  55. package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
  56. package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
  57. package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
  58. package/dist/esm2022/lib/utils.mjs +10 -0
  59. package/dist/esm2022/services/resize-observer.service.mjs +152 -0
  60. package/dist/esm2022/services/scroll-position.service.mjs +124 -0
  61. package/dist/esm2022/types/frontend-tool.mjs +2 -0
  62. package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
  63. package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
  64. package/dist/esm2022/utils/agent.utils.mjs +204 -0
  65. package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
  66. package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
  67. package/dist/esm2022/utils/frontend-tool.utils.mjs +228 -0
  68. package/dist/esm2022/utils/human-in-the-loop.utils.mjs +296 -0
  69. package/dist/fesm2022/copilotkitnext-angular.mjs +163 -164
  70. package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
  71. package/dist/styles.css +0 -27
  72. package/package.json +23 -20
  73. package/vitest.config.mts +32 -21
  74. package/.turbo/turbo-build.log +0 -39
  75. package/.turbo/turbo-check-types.log +0 -0
  76. package/.turbo/turbo-test.log +0 -71
  77. package/README-agent-context.md +0 -310
  78. package/ng-package.json +0 -19
  79. package/slots.md +0 -331
  80. package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
  81. package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
  82. package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
  83. package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
  84. package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
  85. package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
  86. package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
  87. package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
  88. package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
  89. package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
  90. package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
  91. package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
  92. package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
  93. package/src/components/chat/copilot-chat-input.component.ts +0 -512
  94. package/src/components/chat/copilot-chat-input.types.ts +0 -148
  95. package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
  96. package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
  97. package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
  98. package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
  99. package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
  100. package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
  101. package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
  102. package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
  103. package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
  104. package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
  105. package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
  106. package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
  107. package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
  108. package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
  109. package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
  110. package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
  111. package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
  112. package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
  113. package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
  114. package/src/components/chat/copilot-chat-view.component.ts +0 -420
  115. package/src/components/chat/copilot-chat-view.types.ts +0 -52
  116. package/src/components/chat/copilot-chat.component.ts +0 -232
  117. package/src/components/copilotkit-tool-render.component.ts +0 -169
  118. package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
  119. package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
  120. package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
  121. package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
  122. package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
  123. package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
  124. package/src/core/copilotkit.providers.ts +0 -59
  125. package/src/core/copilotkit.service.ts +0 -542
  126. package/src/core/copilotkit.types.ts +0 -132
  127. package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
  128. package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
  129. package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
  130. package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
  131. package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
  132. package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
  133. package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
  134. package/src/directives/copilotkit-agent-context.directive.ts +0 -138
  135. package/src/directives/copilotkit-agent.directive.ts +0 -225
  136. package/src/directives/copilotkit-chat-config.directive.ts +0 -241
  137. package/src/directives/copilotkit-config.directive.ts +0 -81
  138. package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
  139. package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
  140. package/src/directives/stick-to-bottom.directive.ts +0 -204
  141. package/src/index.ts +0 -105
  142. package/src/lib/directives/tooltip.directive.ts +0 -292
  143. package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
  144. package/src/lib/slots/copilot-slot.component.ts +0 -135
  145. package/src/lib/slots/index.ts +0 -3
  146. package/src/lib/slots/slot.types.ts +0 -64
  147. package/src/lib/slots/slot.utils.ts +0 -289
  148. package/src/lib/utils.ts +0 -10
  149. package/src/public-api.ts +0 -1
  150. package/src/services/resize-observer.service.ts +0 -181
  151. package/src/services/scroll-position.service.ts +0 -169
  152. package/src/styles/globals.css +0 -266
  153. package/src/styles/index.css +0 -3
  154. package/src/test-setup.ts +0 -15
  155. package/src/testing/index.ts +0 -3
  156. package/src/testing/testing.utils.ts +0 -248
  157. package/src/types/frontend-tool.ts +0 -44
  158. package/src/types/human-in-the-loop.ts +0 -52
  159. package/src/utils/__tests__/agent.utils.spec.ts +0 -234
  160. package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
  161. package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
  162. package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
  163. package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
  164. package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
  165. package/src/utils/agent-context.utils.ts +0 -133
  166. package/src/utils/agent.utils.ts +0 -239
  167. package/src/utils/chat-config.utils.ts +0 -221
  168. package/src/utils/copilotkit.utils.ts +0 -20
  169. package/src/utils/frontend-tool.utils.ts +0 -266
  170. package/src/utils/human-in-the-loop.utils.ts +0 -359
  171. package/tsconfig.spec.json +0 -12
@@ -1,452 +0,0 @@
1
- import { Component, TemplateRef, ViewChild } from "@angular/core";
2
- import { TestBed } from "@angular/core/testing";
3
- import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
4
- import { CopilotKitHumanInTheLoopDirective } from "../copilotkit-human-in-the-loop.directive";
5
- import { CopilotKitService } from "../../core/copilotkit.service";
6
- import { provideCopilotKit } from "../../core/copilotkit.providers";
7
- import { z } from "zod";
8
- import { By } from "@angular/platform-browser";
9
-
10
- // Mock CopilotKitCore
11
- const mockCopilotKitCore = {
12
- addTool: vi.fn(() => "tool-id-123"),
13
- removeTool: vi.fn(),
14
- setRuntimeUrl: vi.fn(),
15
- setHeaders: vi.fn(),
16
- setProperties: vi.fn(),
17
- setAgents: vi.fn(),
18
- getAgent: vi.fn(),
19
- subscribe: vi.fn(() => vi.fn()),
20
- };
21
-
22
- vi.mock("@copilotkitnext/core", () => ({
23
- CopilotKitCore: vi.fn().mockImplementation(() => mockCopilotKitCore),
24
- ToolCallStatus: {
25
- InProgress: "inProgress",
26
- Executing: "executing",
27
- Complete: "complete",
28
- },
29
- }));
30
-
31
- // Test approval component
32
- @Component({
33
- selector: "test-approval",
34
- template: `
35
- <div class="approval-dialog">
36
- <p>{{ action }}</p>
37
- <button class="approve-btn">Approve</button>
38
- <button class="reject-btn">Reject</button>
39
- </div>
40
- `,
41
- standalone: true,
42
- })
43
- class TestApprovalComponent {
44
- action = "";
45
- respond?: (result: unknown) => Promise<void>;
46
- }
47
-
48
- describe("CopilotKitHumanInTheLoopDirective", () => {
49
- let service: CopilotKitService;
50
-
51
- beforeEach(() => {
52
- TestBed.configureTestingModule({
53
- providers: [provideCopilotKit({})],
54
- });
55
-
56
- service = TestBed.inject(CopilotKitService);
57
- vi.clearAllMocks();
58
- });
59
-
60
- afterEach(() => {
61
- vi.clearAllMocks();
62
- });
63
-
64
- describe("Basic Usage", () => {
65
- it("should register tool when directive is applied", () => {
66
- @Component({
67
- template: `
68
- <div
69
- copilotkitHumanInTheLoop
70
- [name]="'requireApproval'"
71
- [description]="'Requires user approval'"
72
- [parameters]="parametersSchema"
73
- [render]="approvalComponent"
74
- ></div>
75
- `,
76
- standalone: true,
77
- imports: [CopilotKitHumanInTheLoopDirective],
78
- })
79
- class TestComponent {
80
- parametersSchema = z.object({ action: z.string() });
81
- approvalComponent = TestApprovalComponent;
82
- }
83
-
84
- const fixture = TestBed.createComponent(TestComponent);
85
- fixture.detectChanges();
86
-
87
- expect(mockCopilotKitCore.addTool).toHaveBeenCalled();
88
- const addToolCall = mockCopilotKitCore.addTool.mock.calls[0][0];
89
- expect(addToolCall.name).toBe("requireApproval");
90
- expect(addToolCall.description).toBe("Requires user approval");
91
- expect(typeof addToolCall.handler).toBe("function");
92
- });
93
-
94
- it("should support config object input", () => {
95
- @Component({
96
- template: ` <div [copilotkitHumanInTheLoop]="config"></div> `,
97
- standalone: true,
98
- imports: [CopilotKitHumanInTheLoopDirective],
99
- })
100
- class TestComponent {
101
- config = {
102
- name: "requireApproval",
103
- description: "Requires user approval",
104
- parameters: z.object({ action: z.string() }),
105
- render: TestApprovalComponent,
106
- };
107
- }
108
-
109
- const fixture = TestBed.createComponent(TestComponent);
110
- fixture.detectChanges();
111
-
112
- expect(mockCopilotKitCore.addTool).toHaveBeenCalled();
113
- const addToolCall = mockCopilotKitCore.addTool.mock.calls[0][0];
114
- expect(addToolCall.name).toBe("requireApproval");
115
- });
116
-
117
- it("should not register when enabled is false", () => {
118
- @Component({
119
- template: `
120
- <div
121
- copilotkitHumanInTheLoop
122
- [name]="'requireApproval'"
123
- [description]="'Requires user approval'"
124
- [parameters]="parametersSchema"
125
- [render]="approvalComponent"
126
- [enabled]="false"
127
- ></div>
128
- `,
129
- standalone: true,
130
- imports: [CopilotKitHumanInTheLoopDirective],
131
- })
132
- class TestComponent {
133
- parametersSchema = z.object({ action: z.string() });
134
- approvalComponent = TestApprovalComponent;
135
- }
136
-
137
- const fixture = TestBed.createComponent(TestComponent);
138
- fixture.detectChanges();
139
-
140
- expect(mockCopilotKitCore.addTool).not.toHaveBeenCalled();
141
- });
142
- });
143
-
144
- describe("Event Emissions", () => {
145
- it("should emit statusChange events", () => {
146
- let statusChanges: string[] = [];
147
-
148
- @Component({
149
- template: `
150
- <div
151
- copilotkitHumanInTheLoop
152
- [name]="'requireApproval'"
153
- [description]="'Requires user approval'"
154
- [parameters]="parametersSchema"
155
- [render]="approvalComponent"
156
- (statusChange)="onStatusChange($event)"
157
- ></div>
158
- `,
159
- standalone: true,
160
- imports: [CopilotKitHumanInTheLoopDirective],
161
- })
162
- class TestComponent {
163
- parametersSchema = z.object({ action: z.string() });
164
- approvalComponent = TestApprovalComponent;
165
-
166
- onStatusChange(status: string) {
167
- statusChanges.push(status);
168
- }
169
- }
170
-
171
- const fixture = TestBed.createComponent(TestComponent);
172
- fixture.detectChanges();
173
-
174
- // Get the directive instance
175
- const directiveEl = fixture.debugElement.query(
176
- By.directive(CopilotKitHumanInTheLoopDirective)
177
- );
178
- const directive = directiveEl.injector.get(
179
- CopilotKitHumanInTheLoopDirective
180
- );
181
-
182
- // Initial status should be 'inProgress'
183
- expect(directive.status).toBe("inProgress");
184
-
185
- // Get the handler and call it to trigger status change
186
- const addToolCall = mockCopilotKitCore.addTool.mock.calls[0][0];
187
- const handler = addToolCall.handler;
188
-
189
- // This should change status to 'executing'
190
- handler({ action: "delete" });
191
-
192
- // Note: We can't easily test the async behavior without more complex setup
193
- });
194
-
195
- it("should emit executionStarted when handler is called", () => {
196
- let executionArgs: any;
197
-
198
- @Component({
199
- template: `
200
- <div
201
- copilotkitHumanInTheLoop
202
- [name]="'requireApproval'"
203
- [description]="'Requires user approval'"
204
- [parameters]="parametersSchema"
205
- [render]="approvalComponent"
206
- (executionStarted)="onExecutionStarted($event)"
207
- ></div>
208
- `,
209
- standalone: true,
210
- imports: [CopilotKitHumanInTheLoopDirective],
211
- })
212
- class TestComponent {
213
- parametersSchema = z.object({ action: z.string() });
214
- approvalComponent = TestApprovalComponent;
215
-
216
- onExecutionStarted(args: any) {
217
- executionArgs = args;
218
- }
219
- }
220
-
221
- const fixture = TestBed.createComponent(TestComponent);
222
- fixture.detectChanges();
223
-
224
- // Get the handler and call it
225
- const addToolCall = mockCopilotKitCore.addTool.mock.calls[0][0];
226
- const handler = addToolCall.handler;
227
-
228
- handler({ action: "delete" });
229
-
230
- expect(executionArgs).toEqual({ action: "delete" });
231
- });
232
-
233
- it("should support two-way binding for status", () => {
234
- @Component({
235
- template: `
236
- <div
237
- copilotkitHumanInTheLoop
238
- [name]="'requireApproval'"
239
- [description]="'Requires user approval'"
240
- [parameters]="parametersSchema"
241
- [render]="approvalComponent"
242
- [(status)]="currentStatus"
243
- ></div>
244
- `,
245
- standalone: true,
246
- imports: [CopilotKitHumanInTheLoopDirective],
247
- })
248
- class TestComponent {
249
- parametersSchema = z.object({ action: z.string() });
250
- approvalComponent = TestApprovalComponent;
251
- currentStatus = "inProgress";
252
- }
253
-
254
- const fixture = TestBed.createComponent(TestComponent);
255
- fixture.detectChanges();
256
-
257
- expect(fixture.componentInstance.currentStatus).toBe("inProgress");
258
-
259
- // Note: Testing two-way binding fully would require triggering status changes
260
- });
261
- });
262
-
263
- describe("Template Support", () => {
264
- it("should work with template ref", () => {
265
- @Component({
266
- template: `
267
- <div
268
- copilotkitHumanInTheLoop
269
- [name]="'requireApproval'"
270
- [description]="'Requires user approval'"
271
- [parameters]="parametersSchema"
272
- [render]="approvalTemplate"
273
- ></div>
274
-
275
- <ng-template #approvalTemplate let-props>
276
- <div class="template-approval">
277
- <p>{{ props.args.action }}</p>
278
- <button *ngIf="props.respond">Approve</button>
279
- </div>
280
- </ng-template>
281
- `,
282
- standalone: true,
283
- imports: [CopilotKitHumanInTheLoopDirective],
284
- })
285
- class TestComponent {
286
- @ViewChild("approvalTemplate", { static: true })
287
- approvalTemplate!: TemplateRef<any>;
288
- parametersSchema = z.object({ action: z.string() });
289
- }
290
-
291
- const fixture = TestBed.createComponent(TestComponent);
292
- fixture.detectChanges();
293
-
294
- expect(mockCopilotKitCore.addTool).toHaveBeenCalled();
295
- const addToolCall = mockCopilotKitCore.addTool.mock.calls[0][0];
296
- expect(addToolCall.name).toBe("requireApproval");
297
- });
298
- });
299
-
300
- describe("Dynamic Updates", () => {
301
- it("should re-register tool when inputs change", () => {
302
- @Component({
303
- template: `
304
- <div
305
- copilotkitHumanInTheLoop
306
- [name]="toolName"
307
- [description]="description"
308
- [parameters]="parametersSchema"
309
- [render]="approvalComponent"
310
- ></div>
311
- `,
312
- standalone: true,
313
- imports: [CopilotKitHumanInTheLoopDirective],
314
- })
315
- class TestComponent {
316
- toolName = "requireApproval";
317
- description = "Requires user approval";
318
- parametersSchema = z.object({ action: z.string() });
319
- approvalComponent = TestApprovalComponent;
320
- }
321
-
322
- const fixture = TestBed.createComponent(TestComponent);
323
- fixture.detectChanges();
324
-
325
- expect(mockCopilotKitCore.addTool).toHaveBeenCalledTimes(1);
326
-
327
- // Change the name
328
- fixture.componentInstance.toolName = "requireConfirmation";
329
- fixture.detectChanges();
330
-
331
- // Should remove old tool and add new one
332
- expect(mockCopilotKitCore.removeTool).toHaveBeenCalledWith(
333
- "requireApproval"
334
- );
335
- expect(mockCopilotKitCore.addTool).toHaveBeenCalledTimes(2);
336
-
337
- const secondCall = mockCopilotKitCore.addTool.mock.calls[1][0];
338
- expect(secondCall.name).toBe("requireConfirmation");
339
- });
340
-
341
- it("should handle enabling/disabling", () => {
342
- @Component({
343
- template: `
344
- <div
345
- copilotkitHumanInTheLoop
346
- [name]="'requireApproval'"
347
- [description]="'Requires user approval'"
348
- [parameters]="parametersSchema"
349
- [render]="approvalComponent"
350
- [enabled]="isEnabled"
351
- ></div>
352
- `,
353
- standalone: true,
354
- imports: [CopilotKitHumanInTheLoopDirective],
355
- })
356
- class TestComponent {
357
- parametersSchema = z.object({ action: z.string() });
358
- approvalComponent = TestApprovalComponent;
359
- isEnabled = true;
360
- }
361
-
362
- const fixture = TestBed.createComponent(TestComponent);
363
- fixture.detectChanges();
364
-
365
- expect(mockCopilotKitCore.addTool).toHaveBeenCalledTimes(1);
366
-
367
- // Disable the tool
368
- fixture.componentInstance.isEnabled = false;
369
- fixture.detectChanges();
370
-
371
- expect(mockCopilotKitCore.removeTool).toHaveBeenCalledWith(
372
- "requireApproval"
373
- );
374
-
375
- // Re-enable the tool
376
- fixture.componentInstance.isEnabled = true;
377
- fixture.detectChanges();
378
-
379
- expect(mockCopilotKitCore.addTool).toHaveBeenCalledTimes(2);
380
- });
381
- });
382
-
383
- describe("Cleanup", () => {
384
- it("should unregister tool on destroy", () => {
385
- @Component({
386
- template: `
387
- <div
388
- copilotkitHumanInTheLoop
389
- [name]="'requireApproval'"
390
- [description]="'Requires user approval'"
391
- [parameters]="parametersSchema"
392
- [render]="approvalComponent"
393
- ></div>
394
- `,
395
- standalone: true,
396
- imports: [CopilotKitHumanInTheLoopDirective],
397
- })
398
- class TestComponent {
399
- parametersSchema = z.object({ action: z.string() });
400
- approvalComponent = TestApprovalComponent;
401
- }
402
-
403
- const fixture = TestBed.createComponent(TestComponent);
404
- fixture.detectChanges();
405
-
406
- const unregisterSpy = vi.spyOn(service, "unregisterToolRender");
407
-
408
- fixture.destroy();
409
-
410
- expect(mockCopilotKitCore.removeTool).toHaveBeenCalledWith(
411
- "requireApproval"
412
- );
413
- expect(unregisterSpy).toHaveBeenCalledWith("requireApproval");
414
- });
415
- });
416
-
417
- describe("Respond Method", () => {
418
- it("should provide respond method on directive", () => {
419
- @Component({
420
- template: `
421
- <div
422
- copilotkitHumanInTheLoop
423
- [name]="'requireApproval'"
424
- [description]="'Requires user approval'"
425
- [parameters]="parametersSchema"
426
- [render]="approvalComponent"
427
- ></div>
428
- `,
429
- standalone: true,
430
- imports: [CopilotKitHumanInTheLoopDirective],
431
- })
432
- class TestComponent {
433
- parametersSchema = z.object({ action: z.string() });
434
- approvalComponent = TestApprovalComponent;
435
- }
436
-
437
- const fixture = TestBed.createComponent(TestComponent);
438
- fixture.detectChanges();
439
-
440
- const directiveEl = fixture.debugElement.query(
441
- By.directive(CopilotKitHumanInTheLoopDirective)
442
- );
443
- const directive = directiveEl.injector.get(
444
- CopilotKitHumanInTheLoopDirective
445
- );
446
-
447
- expect(typeof directive.respond).toBe("function");
448
-
449
- // Note: Testing the actual response would require more complex async setup
450
- });
451
- });
452
- });
@@ -1,138 +0,0 @@
1
- import {
2
- Directive,
3
- Input,
4
- OnInit,
5
- OnChanges,
6
- OnDestroy,
7
- SimpleChanges,
8
- Inject,
9
- } from "@angular/core";
10
- import { CopilotKitService } from "../core/copilotkit.service";
11
- import type { Context } from "@ag-ui/client";
12
-
13
- /**
14
- * Directive to manage agent context in CopilotKit.
15
- * Automatically adds context on init, updates on changes, and removes on destroy.
16
- *
17
- * @example
18
- * ```html
19
- * <!-- With separate inputs -->
20
- * <div copilotkitAgentContext
21
- * [description]="'User preferences'"
22
- * [value]="userSettings">
23
- * </div>
24
- *
25
- * <!-- With context object -->
26
- * <div [copilotkitAgentContext]="contextObject">
27
- * </div>
28
- *
29
- * <!-- With dynamic values -->
30
- * <div copilotkitAgentContext
31
- * description="Form state"
32
- * [value]="formData$ | async">
33
- * </div>
34
- * ```
35
- */
36
- @Directive({
37
- selector: "[copilotkitAgentContext]",
38
- standalone: true,
39
- })
40
- export class CopilotKitAgentContextDirective
41
- implements OnInit, OnChanges, OnDestroy
42
- {
43
- private contextId?: string;
44
-
45
- constructor(
46
- @Inject(CopilotKitService) private readonly copilotkit: CopilotKitService
47
- ) {}
48
-
49
- /**
50
- * Context object containing both description and value.
51
- * If provided, this takes precedence over individual inputs.
52
- */
53
- @Input("copilotkitAgentContext") context?: Context;
54
-
55
- /**
56
- * Description of the context.
57
- * Used when context object is not provided.
58
- */
59
- @Input() description?: string;
60
-
61
- /**
62
- * Value of the context.
63
- * Used when context object is not provided.
64
- */
65
- @Input() value?: any;
66
-
67
- ngOnInit(): void {
68
- this.addContext();
69
- }
70
-
71
- ngOnChanges(changes: SimpleChanges): void {
72
- // Check if any relevant input has changed
73
- const hasContextChange = "context" in changes;
74
- const hasDescriptionChange = "description" in changes;
75
- const hasValueChange = "value" in changes;
76
-
77
- if (hasContextChange || hasDescriptionChange || hasValueChange) {
78
- // Skip the first change as ngOnInit handles initial setup
79
- if (this.contextId) {
80
- this.updateContext();
81
- }
82
- }
83
- }
84
-
85
- ngOnDestroy(): void {
86
- this.removeContext();
87
- }
88
-
89
- /**
90
- * Adds the context to CopilotKit
91
- */
92
- private addContext(): void {
93
- const contextToAdd = this.getContext();
94
-
95
- if (contextToAdd) {
96
- this.contextId = this.copilotkit.copilotkit.addContext(contextToAdd);
97
- }
98
- }
99
-
100
- /**
101
- * Updates the context by removing the old one and adding a new one
102
- */
103
- private updateContext(): void {
104
- this.removeContext();
105
- this.addContext();
106
- }
107
-
108
- /**
109
- * Removes the current context from CopilotKit
110
- */
111
- private removeContext(): void {
112
- if (this.contextId) {
113
- this.copilotkit.copilotkit.removeContext(this.contextId);
114
- this.contextId = undefined;
115
- }
116
- }
117
-
118
- /**
119
- * Gets the context object from inputs
120
- */
121
- private getContext(): Context | null {
122
- // If context object is provided, use it
123
- if (this.context) {
124
- return this.context;
125
- }
126
-
127
- // Otherwise, build from individual inputs
128
- // Note: null is a valid value, but undefined means not set
129
- if (this.description !== undefined && this.value !== undefined) {
130
- return {
131
- description: this.description,
132
- value: this.value,
133
- };
134
- }
135
-
136
- return null;
137
- }
138
- }