@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,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
- }