@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.
- package/README.md +3 -3
- package/dist/README.md +3 -3
- package/dist/components/chat/copilot-chat-assistant-message.component.d.ts +10 -10
- package/dist/components/chat/copilot-chat-message-view.component.d.ts +42 -42
- package/dist/components/chat/copilot-chat-view.component.d.ts +14 -14
- package/dist/core/copilotkit.providers.d.ts +1 -1
- package/dist/core/copilotkit.service.d.ts +5 -5
- package/dist/core/copilotkit.types.d.ts +8 -10
- package/dist/directives/copilotkit-frontend-tool.directive.d.ts +1 -1
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
- package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
- package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
- package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
- package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
- package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
- package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
- package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
- package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
- package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
- package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
- package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
- package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
- package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
- package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
- package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
- package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
- package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
- package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
- package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
- package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
- package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
- package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
- package/dist/esm2022/core/copilotkit.service.mjs +426 -0
- package/dist/esm2022/core/copilotkit.types.mjs +13 -0
- package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
- package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
- package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
- package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
- package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +128 -0
- package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +265 -0
- package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
- package/dist/esm2022/index.mjs +70 -0
- package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
- package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
- package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
- package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
- package/dist/esm2022/lib/utils.mjs +10 -0
- package/dist/esm2022/services/resize-observer.service.mjs +152 -0
- package/dist/esm2022/services/scroll-position.service.mjs +124 -0
- package/dist/esm2022/types/frontend-tool.mjs +2 -0
- package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
- package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
- package/dist/esm2022/utils/agent.utils.mjs +204 -0
- package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
- package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
- package/dist/esm2022/utils/frontend-tool.utils.mjs +224 -0
- package/dist/esm2022/utils/human-in-the-loop.utils.mjs +293 -0
- package/dist/fesm2022/copilotkitnext-angular.mjs +174 -187
- package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
- package/dist/utils/frontend-tool.utils.d.ts +1 -1
- package/package.json +23 -20
- package/vitest.config.mts +32 -21
- package/.turbo/turbo-build.log +0 -38
- package/.turbo/turbo-check-types.log +0 -0
- package/.turbo/turbo-test.log +0 -71
- package/ng-package.json +0 -19
- package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
- package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
- package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
- package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
- package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
- package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
- package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
- package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
- package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
- package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
- package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
- package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
- package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
- package/src/components/chat/copilot-chat-input.component.ts +0 -512
- package/src/components/chat/copilot-chat-input.types.ts +0 -148
- package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
- package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
- package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
- package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
- package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
- package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
- package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
- package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
- package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
- package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
- package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
- package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
- package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
- package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
- package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
- package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
- package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
- package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
- package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
- package/src/components/chat/copilot-chat-view.component.ts +0 -420
- package/src/components/chat/copilot-chat-view.types.ts +0 -52
- package/src/components/chat/copilot-chat.component.ts +0 -232
- package/src/components/copilotkit-tool-render.component.ts +0 -169
- package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
- package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
- package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
- package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
- package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
- package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
- package/src/core/copilotkit.providers.ts +0 -59
- package/src/core/copilotkit.service.ts +0 -542
- package/src/core/copilotkit.types.ts +0 -132
- package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
- package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
- package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
- package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
- package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
- package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
- package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
- package/src/directives/copilotkit-agent-context.directive.ts +0 -138
- package/src/directives/copilotkit-agent.directive.ts +0 -225
- package/src/directives/copilotkit-chat-config.directive.ts +0 -241
- package/src/directives/copilotkit-config.directive.ts +0 -81
- package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
- package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
- package/src/directives/stick-to-bottom.directive.ts +0 -204
- package/src/index.ts +0 -105
- package/src/lib/directives/tooltip.directive.ts +0 -292
- package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
- package/src/lib/slots/copilot-slot.component.ts +0 -135
- package/src/lib/slots/index.ts +0 -3
- package/src/lib/slots/slot.types.ts +0 -64
- package/src/lib/slots/slot.utils.ts +0 -289
- package/src/lib/utils.ts +0 -10
- package/src/public-api.ts +0 -1
- package/src/services/resize-observer.service.ts +0 -181
- package/src/services/scroll-position.service.ts +0 -169
- package/src/styles/globals.css +0 -266
- package/src/styles/index.css +0 -3
- package/src/test-setup.ts +0 -15
- package/src/testing/index.ts +0 -3
- package/src/testing/testing.utils.ts +0 -248
- package/src/types/frontend-tool.ts +0 -44
- package/src/types/human-in-the-loop.ts +0 -52
- package/src/utils/__tests__/agent.utils.spec.ts +0 -234
- package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
- package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
- package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
- package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
- package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
- package/src/utils/agent-context.utils.ts +0 -133
- package/src/utils/agent.utils.ts +0 -239
- package/src/utils/chat-config.utils.ts +0 -221
- package/src/utils/copilotkit.utils.ts +0 -20
- package/src/utils/frontend-tool.utils.ts +0 -266
- package/src/utils/human-in-the-loop.utils.ts +0 -359
- 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
|
-
}
|