@copilotkitnext/angular 0.0.1 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -0
- package/dist/README.md +248 -0
- 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/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 +430 -0
- package/dist/esm2022/core/copilotkit.types.mjs +12 -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 +130 -0
- package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +266 -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 +228 -0
- package/dist/esm2022/utils/human-in-the-loop.utils.mjs +296 -0
- package/dist/fesm2022/copilotkitnext-angular.mjs +163 -164
- package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
- package/dist/styles.css +0 -27
- package/package.json +23 -20
- package/vitest.config.mts +32 -21
- package/.turbo/turbo-build.log +0 -39
- package/.turbo/turbo-check-types.log +0 -0
- package/.turbo/turbo-test.log +0 -71
- package/README-agent-context.md +0 -310
- package/ng-package.json +0 -19
- package/slots.md +0 -331
- 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,420 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
Output,
|
|
5
|
-
EventEmitter,
|
|
6
|
-
ContentChild,
|
|
7
|
-
TemplateRef,
|
|
8
|
-
Type,
|
|
9
|
-
ViewChild,
|
|
10
|
-
ElementRef,
|
|
11
|
-
ChangeDetectionStrategy,
|
|
12
|
-
ChangeDetectorRef,
|
|
13
|
-
ViewEncapsulation,
|
|
14
|
-
signal,
|
|
15
|
-
computed,
|
|
16
|
-
OnInit,
|
|
17
|
-
OnChanges,
|
|
18
|
-
OnDestroy,
|
|
19
|
-
AfterViewInit,
|
|
20
|
-
ViewContainerRef,
|
|
21
|
-
effect
|
|
22
|
-
} from '@angular/core';
|
|
23
|
-
import { CommonModule } from '@angular/common';
|
|
24
|
-
import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
|
|
25
|
-
import { CopilotChatMessageViewComponent } from './copilot-chat-message-view.component';
|
|
26
|
-
import { CopilotChatInputComponent } from './copilot-chat-input.component';
|
|
27
|
-
import { CopilotChatViewScrollViewComponent } from './copilot-chat-view-scroll-view.component';
|
|
28
|
-
import { CopilotChatViewScrollToBottomButtonComponent } from './copilot-chat-view-scroll-to-bottom-button.component';
|
|
29
|
-
import { CopilotChatViewFeatherComponent } from './copilot-chat-view-feather.component';
|
|
30
|
-
import { CopilotChatViewInputContainerComponent } from './copilot-chat-view-input-container.component';
|
|
31
|
-
import { CopilotChatViewDisclaimerComponent } from './copilot-chat-view-disclaimer.component';
|
|
32
|
-
import { Message } from '@ag-ui/client';
|
|
33
|
-
import { cn } from '../../lib/utils';
|
|
34
|
-
import { ResizeObserverService } from '../../services/resize-observer.service';
|
|
35
|
-
import { CopilotChatViewHandlersService } from './copilot-chat-view-handlers.service';
|
|
36
|
-
import { Subject } from 'rxjs';
|
|
37
|
-
import { takeUntil } from 'rxjs/operators';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* CopilotChatView component - Angular port of the React component.
|
|
41
|
-
* A complete chat interface with message feed and input components.
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```html
|
|
45
|
-
* <copilot-chat-view
|
|
46
|
-
* [messages]="messages"
|
|
47
|
-
* [autoScroll]="true"
|
|
48
|
-
* [messageViewProps]="{ assistantMessage: { onThumbsUp: handleThumbsUp } }">
|
|
49
|
-
* </copilot-chat-view>
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
@Component({
|
|
53
|
-
selector: 'copilot-chat-view',
|
|
54
|
-
standalone: true,
|
|
55
|
-
imports: [
|
|
56
|
-
CommonModule,
|
|
57
|
-
CopilotSlotComponent,
|
|
58
|
-
CopilotChatMessageViewComponent,
|
|
59
|
-
CopilotChatInputComponent,
|
|
60
|
-
CopilotChatViewScrollViewComponent,
|
|
61
|
-
CopilotChatViewScrollToBottomButtonComponent,
|
|
62
|
-
CopilotChatViewFeatherComponent,
|
|
63
|
-
CopilotChatViewInputContainerComponent,
|
|
64
|
-
CopilotChatViewDisclaimerComponent
|
|
65
|
-
],
|
|
66
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
67
|
-
encapsulation: ViewEncapsulation.None,
|
|
68
|
-
providers: [ResizeObserverService, CopilotChatViewHandlersService],
|
|
69
|
-
template: `
|
|
70
|
-
<!-- Custom layout template support (render prop pattern) -->
|
|
71
|
-
@if (customLayoutTemplate) {
|
|
72
|
-
<ng-container *ngTemplateOutlet="customLayoutTemplate; context: layoutContext()"></ng-container>
|
|
73
|
-
} @else {
|
|
74
|
-
<!-- Default layout - exact React DOM structure -->
|
|
75
|
-
<div [class]="computedClass()">
|
|
76
|
-
<!-- ScrollView -->
|
|
77
|
-
<copilot-chat-view-scroll-view
|
|
78
|
-
[autoScroll]="autoScrollSignal()"
|
|
79
|
-
[inputContainerHeight]="inputContainerHeight()"
|
|
80
|
-
[isResizing]="isResizing()"
|
|
81
|
-
[messages]="messagesSignal()"
|
|
82
|
-
[messageView]="messageViewSlot()"
|
|
83
|
-
[messageViewClass]="messageViewClass"
|
|
84
|
-
[scrollToBottomButton]="scrollToBottomButtonSlot()"
|
|
85
|
-
[scrollToBottomButtonClass]="scrollToBottomButtonClass"
|
|
86
|
-
[showCursor]="showCursorSignal()"
|
|
87
|
-
(assistantMessageThumbsUp)="assistantMessageThumbsUp.emit($event)"
|
|
88
|
-
(assistantMessageThumbsDown)="assistantMessageThumbsDown.emit($event)"
|
|
89
|
-
(assistantMessageReadAloud)="assistantMessageReadAloud.emit($event)"
|
|
90
|
-
(assistantMessageRegenerate)="assistantMessageRegenerate.emit($event)"
|
|
91
|
-
(userMessageCopy)="userMessageCopy.emit($event)"
|
|
92
|
-
(userMessageEdit)="userMessageEdit.emit($event)">
|
|
93
|
-
</copilot-chat-view-scroll-view>
|
|
94
|
-
|
|
95
|
-
<!-- Feather effect -->
|
|
96
|
-
<copilot-slot
|
|
97
|
-
[slot]="featherSlot()"
|
|
98
|
-
[context]="{ inputClass: featherClass }"
|
|
99
|
-
[defaultComponent]="defaultFeatherComponent">
|
|
100
|
-
</copilot-slot>
|
|
101
|
-
|
|
102
|
-
<!-- Input container -->
|
|
103
|
-
<copilot-slot
|
|
104
|
-
#inputContainerSlotRef
|
|
105
|
-
[slot]="inputContainerSlot()"
|
|
106
|
-
[context]="inputContainerContext()"
|
|
107
|
-
[defaultComponent]="defaultInputContainerComponent">
|
|
108
|
-
</copilot-slot>
|
|
109
|
-
</div>
|
|
110
|
-
}
|
|
111
|
-
`
|
|
112
|
-
})
|
|
113
|
-
export class CopilotChatViewComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
|
|
114
|
-
// Core inputs matching React props
|
|
115
|
-
@Input() messages: Message[] = [];
|
|
116
|
-
@Input() autoScroll: boolean = true;
|
|
117
|
-
@Input() showCursor: boolean = false;
|
|
118
|
-
|
|
119
|
-
// MessageView slot inputs
|
|
120
|
-
@Input() messageViewComponent?: Type<any>;
|
|
121
|
-
@Input() messageViewTemplate?: TemplateRef<any>;
|
|
122
|
-
@Input() messageViewClass?: string;
|
|
123
|
-
|
|
124
|
-
// ScrollView slot inputs
|
|
125
|
-
@Input() scrollViewComponent?: Type<any>;
|
|
126
|
-
@Input() scrollViewTemplate?: TemplateRef<any>;
|
|
127
|
-
@Input() scrollViewClass?: string;
|
|
128
|
-
|
|
129
|
-
// ScrollToBottomButton slot inputs
|
|
130
|
-
@Input() scrollToBottomButtonComponent?: Type<any>;
|
|
131
|
-
@Input() scrollToBottomButtonTemplate?: TemplateRef<any>;
|
|
132
|
-
@Input() scrollToBottomButtonClass?: string;
|
|
133
|
-
|
|
134
|
-
// Input slot inputs
|
|
135
|
-
@Input() inputComponent?: Type<any>;
|
|
136
|
-
@Input() inputTemplate?: TemplateRef<any>;
|
|
137
|
-
|
|
138
|
-
// InputContainer slot inputs
|
|
139
|
-
@Input() inputContainerComponent?: Type<any>;
|
|
140
|
-
@Input() inputContainerTemplate?: TemplateRef<any>;
|
|
141
|
-
@Input() inputContainerClass?: string;
|
|
142
|
-
|
|
143
|
-
// Feather slot inputs
|
|
144
|
-
@Input() featherComponent?: Type<any>;
|
|
145
|
-
@Input() featherTemplate?: TemplateRef<any>;
|
|
146
|
-
@Input() featherClass?: string;
|
|
147
|
-
|
|
148
|
-
// Disclaimer slot inputs
|
|
149
|
-
@Input() disclaimerComponent?: Type<any>;
|
|
150
|
-
@Input() disclaimerTemplate?: TemplateRef<any>;
|
|
151
|
-
@Input() disclaimerClass?: string;
|
|
152
|
-
@Input() disclaimerText?: string;
|
|
153
|
-
|
|
154
|
-
// Custom layout template (render prop pattern)
|
|
155
|
-
@ContentChild('customLayout') customLayoutTemplate?: TemplateRef<any>;
|
|
156
|
-
|
|
157
|
-
// Named template slots for deep customization
|
|
158
|
-
@ContentChild('sendButton') sendButtonTemplate?: TemplateRef<any>;
|
|
159
|
-
@ContentChild('toolbar') toolbarTemplate?: TemplateRef<any>;
|
|
160
|
-
@ContentChild('textArea') textAreaTemplate?: TemplateRef<any>;
|
|
161
|
-
@ContentChild('audioRecorder') audioRecorderTemplate?: TemplateRef<any>;
|
|
162
|
-
@ContentChild('assistantMessageMarkdownRenderer') assistantMessageMarkdownRendererTemplate?: TemplateRef<any>;
|
|
163
|
-
@ContentChild('thumbsUpButton') thumbsUpButtonTemplate?: TemplateRef<any>;
|
|
164
|
-
@ContentChild('thumbsDownButton') thumbsDownButtonTemplate?: TemplateRef<any>;
|
|
165
|
-
@ContentChild('readAloudButton') readAloudButtonTemplate?: TemplateRef<any>;
|
|
166
|
-
@ContentChild('regenerateButton') regenerateButtonTemplate?: TemplateRef<any>;
|
|
167
|
-
|
|
168
|
-
// Output events for assistant message actions (bubbled from child components)
|
|
169
|
-
@Output() assistantMessageThumbsUp = new EventEmitter<{ message: Message }>();
|
|
170
|
-
@Output() assistantMessageThumbsDown = new EventEmitter<{ message: Message }>();
|
|
171
|
-
@Output() assistantMessageReadAloud = new EventEmitter<{ message: Message }>();
|
|
172
|
-
@Output() assistantMessageRegenerate = new EventEmitter<{ message: Message }>();
|
|
173
|
-
|
|
174
|
-
// Output events for user message actions (if applicable)
|
|
175
|
-
@Output() userMessageCopy = new EventEmitter<{ message: Message }>();
|
|
176
|
-
@Output() userMessageEdit = new EventEmitter<{ message: Message }>();
|
|
177
|
-
|
|
178
|
-
// ViewChild references
|
|
179
|
-
@ViewChild('inputContainerSlotRef', { read: ElementRef }) inputContainerSlotRef?: ElementRef;
|
|
180
|
-
|
|
181
|
-
// Default components for slots
|
|
182
|
-
protected readonly defaultScrollViewComponent = CopilotChatViewScrollViewComponent;
|
|
183
|
-
protected readonly defaultScrollToBottomButtonComponent = CopilotChatViewScrollToBottomButtonComponent;
|
|
184
|
-
protected readonly defaultInputContainerComponent = CopilotChatViewInputContainerComponent;
|
|
185
|
-
protected readonly defaultFeatherComponent = CopilotChatViewFeatherComponent;
|
|
186
|
-
protected readonly defaultDisclaimerComponent = CopilotChatViewDisclaimerComponent;
|
|
187
|
-
|
|
188
|
-
// Signals for reactive state
|
|
189
|
-
protected messagesSignal = signal<Message[]>([]);
|
|
190
|
-
protected autoScrollSignal = signal(true);
|
|
191
|
-
protected showCursorSignal = signal(false);
|
|
192
|
-
protected disclaimerTextSignal = signal<string | undefined>(undefined);
|
|
193
|
-
protected disclaimerClassSignal = signal<string | undefined>(undefined);
|
|
194
|
-
protected inputContainerHeight = signal<number>(0);
|
|
195
|
-
protected isResizing = signal<boolean>(false);
|
|
196
|
-
protected contentPaddingBottom = computed(() => this.inputContainerHeight() + 32);
|
|
197
|
-
|
|
198
|
-
// Computed signals
|
|
199
|
-
protected computedClass = computed(() => cn('relative h-full'));
|
|
200
|
-
|
|
201
|
-
// Slot resolution computed signals
|
|
202
|
-
protected messageViewSlot = computed(() =>
|
|
203
|
-
this.messageViewTemplate || this.messageViewComponent
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
protected scrollViewSlot = computed(() =>
|
|
207
|
-
this.scrollViewTemplate || this.scrollViewComponent
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
protected scrollToBottomButtonSlot = computed(() =>
|
|
211
|
-
this.scrollToBottomButtonTemplate || this.scrollToBottomButtonComponent
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
protected inputSlot = computed(() =>
|
|
215
|
-
this.inputTemplate || this.inputComponent
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
protected inputContainerSlot = computed(() =>
|
|
219
|
-
this.inputContainerTemplate || this.inputContainerComponent
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
protected featherSlot = computed(() =>
|
|
223
|
-
this.featherTemplate || this.featherComponent
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
protected disclaimerSlot = computed(() =>
|
|
227
|
-
this.disclaimerTemplate || this.disclaimerComponent
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
// Context objects for slots
|
|
231
|
-
protected scrollViewContext = computed(() => ({
|
|
232
|
-
autoScroll: this.autoScrollSignal(),
|
|
233
|
-
scrollToBottomButton: this.scrollToBottomButtonSlot(),
|
|
234
|
-
scrollToBottomButtonClass: this.scrollToBottomButtonClass,
|
|
235
|
-
inputContainerHeight: this.inputContainerHeight(),
|
|
236
|
-
isResizing: this.isResizing(),
|
|
237
|
-
messages: this.messagesSignal(),
|
|
238
|
-
messageView: this.messageViewSlot(),
|
|
239
|
-
messageViewClass: this.messageViewClass
|
|
240
|
-
}));
|
|
241
|
-
|
|
242
|
-
// Removed scrollViewPropsComputed - no longer needed
|
|
243
|
-
|
|
244
|
-
protected inputContainerContext = computed(() => ({
|
|
245
|
-
input: this.inputSlot(),
|
|
246
|
-
disclaimer: this.disclaimerSlot(),
|
|
247
|
-
disclaimerText: this.disclaimerTextSignal(),
|
|
248
|
-
disclaimerClass: this.disclaimerClassSignal(),
|
|
249
|
-
inputContainerClass: this.inputContainerClass
|
|
250
|
-
}));
|
|
251
|
-
|
|
252
|
-
// Removed inputContainerPropsComputed - no longer needed
|
|
253
|
-
|
|
254
|
-
// Layout context for custom templates (render prop pattern)
|
|
255
|
-
protected layoutContext = computed(() => ({
|
|
256
|
-
messageView: this.messageViewSlot(),
|
|
257
|
-
input: this.inputSlot(),
|
|
258
|
-
scrollView: this.scrollViewSlot(),
|
|
259
|
-
scrollToBottomButton: this.scrollToBottomButtonSlot(),
|
|
260
|
-
feather: this.featherSlot(),
|
|
261
|
-
inputContainer: this.inputContainerSlot(),
|
|
262
|
-
disclaimer: this.disclaimerSlot()
|
|
263
|
-
}));
|
|
264
|
-
|
|
265
|
-
private destroy$ = new Subject<void>();
|
|
266
|
-
private resizeTimeoutRef?: number;
|
|
267
|
-
|
|
268
|
-
constructor(
|
|
269
|
-
private resizeObserverService: ResizeObserverService,
|
|
270
|
-
private cdr: ChangeDetectorRef,
|
|
271
|
-
private handlers: CopilotChatViewHandlersService
|
|
272
|
-
) {
|
|
273
|
-
// Set up effect to handle resize state timeout
|
|
274
|
-
effect(() => {
|
|
275
|
-
const resizing = this.isResizing();
|
|
276
|
-
if (resizing && this.resizeTimeoutRef) {
|
|
277
|
-
clearTimeout(this.resizeTimeoutRef);
|
|
278
|
-
this.resizeTimeoutRef = undefined;
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
ngOnInit(): void {
|
|
284
|
-
// Initialize signals with input values
|
|
285
|
-
this.messagesSignal.set(this.messages);
|
|
286
|
-
this.autoScrollSignal.set(this.autoScroll);
|
|
287
|
-
this.showCursorSignal.set(this.showCursor);
|
|
288
|
-
this.disclaimerTextSignal.set(this.disclaimerText);
|
|
289
|
-
this.disclaimerClassSignal.set(this.disclaimerClass);
|
|
290
|
-
|
|
291
|
-
// Initialize handler availability in the view-scoped service
|
|
292
|
-
this.handlers.hasAssistantThumbsUpHandler.set(this.assistantMessageThumbsUp.observed);
|
|
293
|
-
this.handlers.hasAssistantThumbsDownHandler.set(this.assistantMessageThumbsDown.observed);
|
|
294
|
-
this.handlers.hasAssistantReadAloudHandler.set(this.assistantMessageReadAloud.observed);
|
|
295
|
-
this.handlers.hasAssistantRegenerateHandler.set(this.assistantMessageRegenerate.observed);
|
|
296
|
-
this.handlers.hasUserCopyHandler.set(this.userMessageCopy.observed);
|
|
297
|
-
this.handlers.hasUserEditHandler.set(this.userMessageEdit.observed);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
ngOnChanges(): void {
|
|
301
|
-
// Update signals when inputs change
|
|
302
|
-
this.messagesSignal.set(this.messages);
|
|
303
|
-
this.autoScrollSignal.set(this.autoScroll);
|
|
304
|
-
this.showCursorSignal.set(this.showCursor);
|
|
305
|
-
this.disclaimerTextSignal.set(this.disclaimerText);
|
|
306
|
-
this.disclaimerClassSignal.set(this.disclaimerClass);
|
|
307
|
-
|
|
308
|
-
// Keep handler availability in sync
|
|
309
|
-
this.handlers.hasAssistantThumbsUpHandler.set(this.assistantMessageThumbsUp.observed);
|
|
310
|
-
this.handlers.hasAssistantThumbsDownHandler.set(this.assistantMessageThumbsDown.observed);
|
|
311
|
-
this.handlers.hasAssistantReadAloudHandler.set(this.assistantMessageReadAloud.observed);
|
|
312
|
-
this.handlers.hasAssistantRegenerateHandler.set(this.assistantMessageRegenerate.observed);
|
|
313
|
-
this.handlers.hasUserCopyHandler.set(this.userMessageCopy.observed);
|
|
314
|
-
this.handlers.hasUserEditHandler.set(this.userMessageEdit.observed);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
ngAfterViewInit(): void {
|
|
318
|
-
// Don't set a default height - measure it dynamically
|
|
319
|
-
|
|
320
|
-
// Set up input container height monitoring
|
|
321
|
-
const measureAndObserve = () => {
|
|
322
|
-
if (!this.inputContainerSlotRef || !this.inputContainerSlotRef.nativeElement) {
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// The slot ref points to the copilot-slot element
|
|
327
|
-
// We need to find the actual input container component inside it
|
|
328
|
-
const slotElement = this.inputContainerSlotRef.nativeElement;
|
|
329
|
-
const componentElement = slotElement.querySelector('copilot-chat-view-input-container');
|
|
330
|
-
|
|
331
|
-
if (!componentElement) {
|
|
332
|
-
return false;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Look for the absolute positioned div that contains the input
|
|
336
|
-
let innerDiv = componentElement.querySelector('div.absolute') as HTMLElement;
|
|
337
|
-
|
|
338
|
-
// If not found by class, try first child
|
|
339
|
-
if (!innerDiv) {
|
|
340
|
-
innerDiv = componentElement.firstElementChild as HTMLElement;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (!innerDiv) {
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Measure the actual height
|
|
348
|
-
const measuredHeight = innerDiv.offsetHeight;
|
|
349
|
-
|
|
350
|
-
if (measuredHeight === 0) {
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Success! Set the initial height
|
|
355
|
-
this.inputContainerHeight.set(measuredHeight);
|
|
356
|
-
this.cdr.detectChanges();
|
|
357
|
-
|
|
358
|
-
// Create an ElementRef wrapper for ResizeObserver
|
|
359
|
-
const innerDivRef = new ElementRef(innerDiv);
|
|
360
|
-
|
|
361
|
-
// Set up ResizeObserver to track changes
|
|
362
|
-
this.resizeObserverService.observeElement(innerDivRef, 0, 250)
|
|
363
|
-
.pipe(takeUntil(this.destroy$))
|
|
364
|
-
.subscribe(state => {
|
|
365
|
-
const newHeight = state.height;
|
|
366
|
-
|
|
367
|
-
if (newHeight !== this.inputContainerHeight() && newHeight > 0) {
|
|
368
|
-
this.inputContainerHeight.set(newHeight);
|
|
369
|
-
this.isResizing.set(true);
|
|
370
|
-
this.cdr.detectChanges();
|
|
371
|
-
|
|
372
|
-
// Clear existing timeout
|
|
373
|
-
if (this.resizeTimeoutRef) {
|
|
374
|
-
clearTimeout(this.resizeTimeoutRef);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Set isResizing to false after a short delay
|
|
378
|
-
this.resizeTimeoutRef = window.setTimeout(() => {
|
|
379
|
-
this.isResizing.set(false);
|
|
380
|
-
this.resizeTimeoutRef = undefined;
|
|
381
|
-
this.cdr.detectChanges();
|
|
382
|
-
}, 250);
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
return true;
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
// Try to measure immediately
|
|
390
|
-
if (!measureAndObserve()) {
|
|
391
|
-
// If failed, retry with increasing delays
|
|
392
|
-
let attempts = 0;
|
|
393
|
-
const maxAttempts = 10;
|
|
394
|
-
|
|
395
|
-
const retry = () => {
|
|
396
|
-
attempts++;
|
|
397
|
-
if (measureAndObserve()) {
|
|
398
|
-
// Successfully measured
|
|
399
|
-
} else if (attempts < maxAttempts) {
|
|
400
|
-
// Exponential backoff: 50ms, 100ms, 200ms, 400ms, etc.
|
|
401
|
-
const delay = 50 * Math.pow(2, Math.min(attempts - 1, 4));
|
|
402
|
-
setTimeout(retry, delay);
|
|
403
|
-
} else {
|
|
404
|
-
// Failed to measure after max attempts
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
// Start retry with first delay
|
|
409
|
-
setTimeout(retry, 50);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
ngOnDestroy(): void {
|
|
414
|
-
if (this.resizeTimeoutRef) {
|
|
415
|
-
clearTimeout(this.resizeTimeoutRef);
|
|
416
|
-
}
|
|
417
|
-
this.destroy$.next();
|
|
418
|
-
this.destroy$.complete();
|
|
419
|
-
}
|
|
420
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Type, TemplateRef } from '@angular/core';
|
|
2
|
-
import { Message } from '@ag-ui/client';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Props for CopilotChatView component
|
|
6
|
-
*/
|
|
7
|
-
export interface CopilotChatViewProps {
|
|
8
|
-
messages?: Message[];
|
|
9
|
-
autoScroll?: boolean;
|
|
10
|
-
|
|
11
|
-
// Slot configurations
|
|
12
|
-
messageViewComponent?: Type<any>;
|
|
13
|
-
messageViewTemplate?: TemplateRef<any>;
|
|
14
|
-
messageViewClass?: string;
|
|
15
|
-
|
|
16
|
-
scrollViewComponent?: Type<any>;
|
|
17
|
-
scrollViewTemplate?: TemplateRef<any>;
|
|
18
|
-
scrollViewClass?: string;
|
|
19
|
-
|
|
20
|
-
scrollToBottomButtonComponent?: Type<any>;
|
|
21
|
-
scrollToBottomButtonTemplate?: TemplateRef<any>;
|
|
22
|
-
scrollToBottomButtonClass?: string;
|
|
23
|
-
|
|
24
|
-
inputComponent?: Type<any>;
|
|
25
|
-
inputTemplate?: TemplateRef<any>;
|
|
26
|
-
|
|
27
|
-
inputContainerComponent?: Type<any>;
|
|
28
|
-
inputContainerTemplate?: TemplateRef<any>;
|
|
29
|
-
inputContainerClass?: string;
|
|
30
|
-
|
|
31
|
-
featherComponent?: Type<any>;
|
|
32
|
-
featherTemplate?: TemplateRef<any>;
|
|
33
|
-
featherClass?: string;
|
|
34
|
-
|
|
35
|
-
disclaimerComponent?: Type<any>;
|
|
36
|
-
disclaimerTemplate?: TemplateRef<any>;
|
|
37
|
-
disclaimerClass?: string;
|
|
38
|
-
disclaimerText?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Context for custom layout template
|
|
43
|
-
*/
|
|
44
|
-
export interface CopilotChatViewLayoutContext {
|
|
45
|
-
messageView: any;
|
|
46
|
-
input: any;
|
|
47
|
-
scrollView: any;
|
|
48
|
-
scrollToBottomButton: any;
|
|
49
|
-
feather: any;
|
|
50
|
-
inputContainer: any;
|
|
51
|
-
disclaimer: any;
|
|
52
|
-
}
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
Input,
|
|
4
|
-
OnInit,
|
|
5
|
-
OnChanges,
|
|
6
|
-
OnDestroy,
|
|
7
|
-
SimpleChanges,
|
|
8
|
-
ChangeDetectionStrategy,
|
|
9
|
-
ViewEncapsulation,
|
|
10
|
-
signal,
|
|
11
|
-
effect,
|
|
12
|
-
ChangeDetectorRef,
|
|
13
|
-
Signal,
|
|
14
|
-
Injector,
|
|
15
|
-
runInInjectionContext,
|
|
16
|
-
Optional,
|
|
17
|
-
SkipSelf,
|
|
18
|
-
} from "@angular/core";
|
|
19
|
-
import { CommonModule } from "@angular/common";
|
|
20
|
-
import { CopilotChatViewComponent } from "./copilot-chat-view.component";
|
|
21
|
-
import { CopilotChatConfigurationService } from "../../core/chat-configuration/chat-configuration.service";
|
|
22
|
-
import {
|
|
23
|
-
COPILOT_CHAT_INITIAL_CONFIG,
|
|
24
|
-
CopilotChatConfiguration,
|
|
25
|
-
} from "../../core/chat-configuration/chat-configuration.types";
|
|
26
|
-
import { watchAgent } from "../../utils/agent.utils";
|
|
27
|
-
import { AgentWatchResult } from "../../core/copilotkit.types";
|
|
28
|
-
import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkitnext/shared";
|
|
29
|
-
import { Message, AbstractAgent } from "@ag-ui/client";
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* CopilotChat component - Angular equivalent of React's <CopilotChat>
|
|
33
|
-
* Provides a complete chat interface that wires an agent to the chat view
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```html
|
|
37
|
-
* <copilot-chat [agentId]="'default'" [threadId]="'abc123'"></copilot-chat>
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
@Component({
|
|
41
|
-
selector: "copilot-chat",
|
|
42
|
-
standalone: true,
|
|
43
|
-
imports: [CommonModule, CopilotChatViewComponent],
|
|
44
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
45
|
-
encapsulation: ViewEncapsulation.None,
|
|
46
|
-
providers: [
|
|
47
|
-
{
|
|
48
|
-
provide: CopilotChatConfigurationService,
|
|
49
|
-
deps: [
|
|
50
|
-
[new Optional(), new SkipSelf(), CopilotChatConfigurationService],
|
|
51
|
-
[new Optional(), COPILOT_CHAT_INITIAL_CONFIG],
|
|
52
|
-
],
|
|
53
|
-
useFactory: (
|
|
54
|
-
parent: CopilotChatConfigurationService | null,
|
|
55
|
-
initial: CopilotChatConfiguration | null
|
|
56
|
-
) => parent ?? new CopilotChatConfigurationService(initial ?? null),
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
template: `
|
|
60
|
-
<copilot-chat-view
|
|
61
|
-
[messages]="messages()"
|
|
62
|
-
[autoScroll]="true"
|
|
63
|
-
[messageViewClass]="'w-full'"
|
|
64
|
-
[showCursor]="showCursor()"
|
|
65
|
-
>
|
|
66
|
-
</copilot-chat-view>
|
|
67
|
-
`,
|
|
68
|
-
})
|
|
69
|
-
export class CopilotChatComponent implements OnInit, OnChanges, OnDestroy {
|
|
70
|
-
@Input() agentId?: string;
|
|
71
|
-
@Input() threadId?: string;
|
|
72
|
-
|
|
73
|
-
constructor(
|
|
74
|
-
@Optional() private chatConfig: CopilotChatConfigurationService | null,
|
|
75
|
-
private cdr: ChangeDetectorRef,
|
|
76
|
-
private injector: Injector
|
|
77
|
-
) {
|
|
78
|
-
// Create initial watcher once (constructor is a safe injection context)
|
|
79
|
-
const initialId = this.agentId ?? DEFAULT_AGENT_ID;
|
|
80
|
-
this.createWatcher(initialId);
|
|
81
|
-
|
|
82
|
-
// Connect once when agent becomes available
|
|
83
|
-
effect(() => {
|
|
84
|
-
const a = this.agent();
|
|
85
|
-
if (!a) return;
|
|
86
|
-
// Apply thread id when agent is available
|
|
87
|
-
a.threadId = this.threadId || this.generatedThreadId;
|
|
88
|
-
if (!this.hasConnectedOnce) {
|
|
89
|
-
this.hasConnectedOnce = true;
|
|
90
|
-
this.connectToAgent(a);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Signals from watchAgent - using direct references instead of assignment
|
|
96
|
-
protected agent: Signal<AbstractAgent | undefined> = signal<
|
|
97
|
-
AbstractAgent | undefined
|
|
98
|
-
>(undefined).asReadonly() as unknown as Signal<AbstractAgent | undefined>;
|
|
99
|
-
protected messages: Signal<Message[]> = signal<Message[]>(
|
|
100
|
-
[]
|
|
101
|
-
).asReadonly() as unknown as Signal<Message[]>;
|
|
102
|
-
protected isRunning: Signal<boolean> = signal<boolean>(
|
|
103
|
-
false
|
|
104
|
-
).asReadonly() as unknown as Signal<boolean>;
|
|
105
|
-
protected showCursor = signal<boolean>(false);
|
|
106
|
-
|
|
107
|
-
private generatedThreadId: string = randomUUID();
|
|
108
|
-
private agentWatcher?: AgentWatchResult;
|
|
109
|
-
private hasConnectedOnce = false;
|
|
110
|
-
private lastAgentId?: string;
|
|
111
|
-
|
|
112
|
-
ngOnInit(): void {
|
|
113
|
-
this.setupChatHandlers();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
ngOnChanges(changes: SimpleChanges): void {
|
|
117
|
-
if (changes["agentId"] && !changes["agentId"].firstChange) {
|
|
118
|
-
const newId = this.agentId ?? DEFAULT_AGENT_ID;
|
|
119
|
-
this.createWatcher(newId);
|
|
120
|
-
}
|
|
121
|
-
if (changes["threadId"] && !changes["threadId"].firstChange) {
|
|
122
|
-
const a = this.agent();
|
|
123
|
-
if (a) {
|
|
124
|
-
a.threadId = this.threadId || this.generatedThreadId;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private async connectToAgent(agent: AbstractAgent): Promise<void> {
|
|
130
|
-
if (!agent) return;
|
|
131
|
-
|
|
132
|
-
this.showCursor.set(true);
|
|
133
|
-
this.cdr.markForCheck();
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await agent.runAgent(
|
|
137
|
-
{ forwardedProps: { __copilotkitConnect: true } },
|
|
138
|
-
{
|
|
139
|
-
onTextMessageStartEvent: () => {
|
|
140
|
-
this.showCursor.set(false);
|
|
141
|
-
this.cdr.detectChanges();
|
|
142
|
-
},
|
|
143
|
-
onToolCallStartEvent: () => {
|
|
144
|
-
this.showCursor.set(false);
|
|
145
|
-
this.cdr.detectChanges();
|
|
146
|
-
},
|
|
147
|
-
}
|
|
148
|
-
);
|
|
149
|
-
this.showCursor.set(false);
|
|
150
|
-
this.cdr.markForCheck();
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.error("Failed to connect to agent:", error);
|
|
153
|
-
this.showCursor.set(false);
|
|
154
|
-
this.cdr.markForCheck();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private setupChatHandlers(): void {
|
|
159
|
-
if (!this.chatConfig) return;
|
|
160
|
-
|
|
161
|
-
// Handle input submission
|
|
162
|
-
this.chatConfig.setSubmitHandler(async (value: string) => {
|
|
163
|
-
const agent = this.agent();
|
|
164
|
-
if (!agent || !value.trim()) return;
|
|
165
|
-
|
|
166
|
-
// Add user message
|
|
167
|
-
const userMessage: Message = {
|
|
168
|
-
id: randomUUID(),
|
|
169
|
-
role: "user",
|
|
170
|
-
content: value,
|
|
171
|
-
};
|
|
172
|
-
agent.addMessage(userMessage);
|
|
173
|
-
|
|
174
|
-
// Clear the input
|
|
175
|
-
this.chatConfig!.setInputValue("");
|
|
176
|
-
|
|
177
|
-
// Show cursor while processing
|
|
178
|
-
this.showCursor.set(true);
|
|
179
|
-
this.cdr.markForCheck();
|
|
180
|
-
|
|
181
|
-
// Run the agent with named subscriber callbacks
|
|
182
|
-
try {
|
|
183
|
-
await agent.runAgent(
|
|
184
|
-
{},
|
|
185
|
-
{
|
|
186
|
-
onTextMessageStartEvent: () => {
|
|
187
|
-
this.showCursor.set(false);
|
|
188
|
-
this.cdr.detectChanges();
|
|
189
|
-
},
|
|
190
|
-
onToolCallStartEvent: () => {
|
|
191
|
-
this.showCursor.set(false);
|
|
192
|
-
this.cdr.detectChanges();
|
|
193
|
-
},
|
|
194
|
-
}
|
|
195
|
-
);
|
|
196
|
-
} catch (error) {
|
|
197
|
-
console.error("Agent run error:", error);
|
|
198
|
-
} finally {
|
|
199
|
-
this.showCursor.set(false);
|
|
200
|
-
this.cdr.markForCheck();
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Handle input value changes (optional)
|
|
205
|
-
this.chatConfig.setChangeHandler(() => {
|
|
206
|
-
// Keep input state if needed
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
ngOnDestroy(): void {
|
|
211
|
-
if (this.agentWatcher?.unsubscribe) {
|
|
212
|
-
this.agentWatcher.unsubscribe();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private createWatcher(desiredAgentId: string) {
|
|
217
|
-
// Tear down previous watcher if it exists
|
|
218
|
-
if (this.agentWatcher?.unsubscribe) {
|
|
219
|
-
this.agentWatcher.unsubscribe();
|
|
220
|
-
this.agentWatcher = undefined;
|
|
221
|
-
}
|
|
222
|
-
// Setup watcher for desired agent - ensure injection context
|
|
223
|
-
this.agentWatcher = runInInjectionContext(this.injector, () =>
|
|
224
|
-
watchAgent({ agentId: desiredAgentId })
|
|
225
|
-
);
|
|
226
|
-
this.agent = this.agentWatcher.agent;
|
|
227
|
-
this.messages = this.agentWatcher.messages;
|
|
228
|
-
this.isRunning = this.agentWatcher.isRunning;
|
|
229
|
-
this.hasConnectedOnce = false;
|
|
230
|
-
this.lastAgentId = desiredAgentId;
|
|
231
|
-
}
|
|
232
|
-
}
|