@copilotkitnext/angular 0.0.2 → 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 (168) 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/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/package.json +21 -18
  72. package/vitest.config.mts +32 -21
  73. package/.turbo/turbo-build.log +0 -38
  74. package/.turbo/turbo-check-types.log +0 -0
  75. package/.turbo/turbo-test.log +0 -71
  76. package/ng-package.json +0 -19
  77. package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
  78. package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
  79. package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
  80. package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
  81. package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
  82. package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
  83. package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
  84. package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
  85. package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
  86. package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
  87. package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
  88. package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
  89. package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
  90. package/src/components/chat/copilot-chat-input.component.ts +0 -512
  91. package/src/components/chat/copilot-chat-input.types.ts +0 -148
  92. package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
  93. package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
  94. package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
  95. package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
  96. package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
  97. package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
  98. package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
  99. package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
  100. package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
  101. package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
  102. package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
  103. package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
  104. package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
  105. package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
  106. package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
  107. package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
  108. package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
  109. package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
  110. package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
  111. package/src/components/chat/copilot-chat-view.component.ts +0 -420
  112. package/src/components/chat/copilot-chat-view.types.ts +0 -52
  113. package/src/components/chat/copilot-chat.component.ts +0 -232
  114. package/src/components/copilotkit-tool-render.component.ts +0 -169
  115. package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
  116. package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
  117. package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
  118. package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
  119. package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
  120. package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
  121. package/src/core/copilotkit.providers.ts +0 -59
  122. package/src/core/copilotkit.service.ts +0 -542
  123. package/src/core/copilotkit.types.ts +0 -132
  124. package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
  125. package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
  126. package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
  127. package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
  128. package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
  129. package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
  130. package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
  131. package/src/directives/copilotkit-agent-context.directive.ts +0 -138
  132. package/src/directives/copilotkit-agent.directive.ts +0 -225
  133. package/src/directives/copilotkit-chat-config.directive.ts +0 -241
  134. package/src/directives/copilotkit-config.directive.ts +0 -81
  135. package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
  136. package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
  137. package/src/directives/stick-to-bottom.directive.ts +0 -204
  138. package/src/index.ts +0 -105
  139. package/src/lib/directives/tooltip.directive.ts +0 -292
  140. package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
  141. package/src/lib/slots/copilot-slot.component.ts +0 -135
  142. package/src/lib/slots/index.ts +0 -3
  143. package/src/lib/slots/slot.types.ts +0 -64
  144. package/src/lib/slots/slot.utils.ts +0 -289
  145. package/src/lib/utils.ts +0 -10
  146. package/src/public-api.ts +0 -1
  147. package/src/services/resize-observer.service.ts +0 -181
  148. package/src/services/scroll-position.service.ts +0 -169
  149. package/src/styles/globals.css +0 -266
  150. package/src/styles/index.css +0 -3
  151. package/src/test-setup.ts +0 -15
  152. package/src/testing/index.ts +0 -3
  153. package/src/testing/testing.utils.ts +0 -248
  154. package/src/types/frontend-tool.ts +0 -44
  155. package/src/types/human-in-the-loop.ts +0 -52
  156. package/src/utils/__tests__/agent.utils.spec.ts +0 -234
  157. package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
  158. package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
  159. package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
  160. package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
  161. package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
  162. package/src/utils/agent-context.utils.ts +0 -133
  163. package/src/utils/agent.utils.ts +0 -239
  164. package/src/utils/chat-config.utils.ts +0 -221
  165. package/src/utils/copilotkit.utils.ts +0 -20
  166. package/src/utils/frontend-tool.utils.ts +0 -266
  167. package/src/utils/human-in-the-loop.utils.ts +0 -359
  168. 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
- }