@agentick/angular 0.0.1
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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/agentick.service.d.ts +210 -0
- package/dist/agentick.service.d.ts.map +1 -0
- package/dist/agentick.service.js +354 -0
- package/dist/agentick.service.js.map +1 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/tentickle.service.d.ts +210 -0
- package/dist/tentickle.service.d.ts.map +1 -0
- package/dist/tentickle.service.js +354 -0
- package/dist/tentickle.service.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
- package/src/agentick.service.spec.ts +133 -0
- package/src/agentick.service.ts +424 -0
- package/src/index.ts +146 -0
- package/src/types.ts +99 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TentickleService - Modern Angular service for Tentickle.
|
|
3
|
+
*
|
|
4
|
+
* Uses Angular signals for reactive state management with RxJS interop.
|
|
5
|
+
*
|
|
6
|
+
* @module @tentickle/angular/service
|
|
7
|
+
*/
|
|
8
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
9
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
10
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
11
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
12
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
13
|
+
};
|
|
14
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
16
|
+
};
|
|
17
|
+
import { Injectable, InjectionToken, computed, signal, inject, } from "@angular/core";
|
|
18
|
+
import { toObservable } from "@angular/core/rxjs-interop";
|
|
19
|
+
import { Observable, Subject, filter, takeUntil } from "rxjs";
|
|
20
|
+
import { createClient, } from "@tentickle/client";
|
|
21
|
+
/**
|
|
22
|
+
* Injection token for Tentickle configuration.
|
|
23
|
+
*/
|
|
24
|
+
export const TENTICKLE_CONFIG = new InjectionToken("TENTICKLE_CONFIG");
|
|
25
|
+
/**
|
|
26
|
+
* Provides TentickleService with configuration at component level.
|
|
27
|
+
*
|
|
28
|
+
* Use this to create isolated service instances for different components,
|
|
29
|
+
* each with their own connection and state.
|
|
30
|
+
*
|
|
31
|
+
* @example Multiple agents in one app
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Each component gets its own TentickleService instance
|
|
34
|
+
*
|
|
35
|
+
* @Component({
|
|
36
|
+
* selector: 'app-support-chat',
|
|
37
|
+
* providers: [provideTentickle({ baseUrl: '/api/support-agent' })],
|
|
38
|
+
* template: `<div>{{ tentickle.text() }}</div>`,
|
|
39
|
+
* })
|
|
40
|
+
* export class SupportChatComponent {
|
|
41
|
+
* tentickle = inject(TentickleService);
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* @Component({
|
|
45
|
+
* selector: 'app-sales-chat',
|
|
46
|
+
* providers: [provideTentickle({ baseUrl: '/api/sales-agent' })],
|
|
47
|
+
* template: `<div>{{ tentickle.text() }}</div>`,
|
|
48
|
+
* })
|
|
49
|
+
* export class SalesChatComponent {
|
|
50
|
+
* tentickle = inject(TentickleService);
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @param config - Configuration for this service instance
|
|
55
|
+
* @returns Provider array to spread into component's providers
|
|
56
|
+
*/
|
|
57
|
+
export function provideTentickle(config) {
|
|
58
|
+
return [{ provide: TENTICKLE_CONFIG, useValue: config }, TentickleService];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Modern Angular service for Tentickle.
|
|
62
|
+
*
|
|
63
|
+
* Uses signals for state, with RxJS observables available for compatibility.
|
|
64
|
+
*
|
|
65
|
+
* @example Standalone setup
|
|
66
|
+
* ```typescript
|
|
67
|
+
* import { TentickleService, TENTICKLE_CONFIG } from '@tentickle/angular';
|
|
68
|
+
*
|
|
69
|
+
* bootstrapApplication(AppComponent, {
|
|
70
|
+
* providers: [
|
|
71
|
+
* { provide: TENTICKLE_CONFIG, useValue: { baseUrl: 'https://api.example.com' } },
|
|
72
|
+
* ],
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example Component with signals
|
|
77
|
+
* ```typescript
|
|
78
|
+
* @Component({
|
|
79
|
+
* template: `
|
|
80
|
+
* @if (tentickle.isConnected()) {
|
|
81
|
+
* <div class="response">
|
|
82
|
+
* {{ tentickle.text() }}
|
|
83
|
+
* @if (tentickle.isStreaming()) {
|
|
84
|
+
* <span class="cursor">|</span>
|
|
85
|
+
* }
|
|
86
|
+
* </div>
|
|
87
|
+
* <input #input />
|
|
88
|
+
* <button (click)="send(input.value)">Send</button>
|
|
89
|
+
* } @else {
|
|
90
|
+
* <p>Connecting...</p>
|
|
91
|
+
* }
|
|
92
|
+
* `,
|
|
93
|
+
* })
|
|
94
|
+
* export class ChatComponent {
|
|
95
|
+
* tentickle = inject(TentickleService);
|
|
96
|
+
*
|
|
97
|
+
* constructor() {
|
|
98
|
+
* this.tentickle.subscribe("conv-123");
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* async send(message: string) {
|
|
102
|
+
* const handle = this.tentickle.send(message);
|
|
103
|
+
* await handle.result;
|
|
104
|
+
* }
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example With RxJS (for compatibility)
|
|
109
|
+
* ```typescript
|
|
110
|
+
* @Component({
|
|
111
|
+
* template: `{{ text$ | async }}`,
|
|
112
|
+
* })
|
|
113
|
+
* export class LegacyComponent {
|
|
114
|
+
* tentickle = inject(TentickleService);
|
|
115
|
+
* text$ = this.tentickle.text$;
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
let TentickleService = class TentickleService {
|
|
120
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
121
|
+
// Constructor
|
|
122
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new TentickleService.
|
|
125
|
+
*
|
|
126
|
+
* @param configOrInjected - Config passed directly (for testing) or undefined to use DI
|
|
127
|
+
*/
|
|
128
|
+
constructor(configOrInjected) {
|
|
129
|
+
this.destroy$ = new Subject();
|
|
130
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
131
|
+
// Signals - Primary State
|
|
132
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
133
|
+
/** Current connection state */
|
|
134
|
+
this.connectionState = signal("disconnected");
|
|
135
|
+
/** Current session ID */
|
|
136
|
+
this.sessionId = signal(undefined);
|
|
137
|
+
/** Connection error, if any */
|
|
138
|
+
this.error = signal(undefined);
|
|
139
|
+
/** Streaming text state from the client */
|
|
140
|
+
this.streamingText = signal({ text: "", isStreaming: false });
|
|
141
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
142
|
+
// Computed Signals - Derived State
|
|
143
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
144
|
+
/** Whether currently connected */
|
|
145
|
+
this.isConnected = computed(() => this.connectionState() === "connected");
|
|
146
|
+
/** Whether currently connecting */
|
|
147
|
+
this.isConnecting = computed(() => this.connectionState() === "connecting");
|
|
148
|
+
/** Current streaming text */
|
|
149
|
+
this.text = computed(() => this.streamingText().text);
|
|
150
|
+
/** Whether currently streaming */
|
|
151
|
+
this.isStreaming = computed(() => this.streamingText().isStreaming);
|
|
152
|
+
/** Subject for raw stream events */
|
|
153
|
+
this.eventsSubject = new Subject();
|
|
154
|
+
/** Observable of all stream events */
|
|
155
|
+
this.events$ = this.eventsSubject.asObservable();
|
|
156
|
+
/** Subject for execution results */
|
|
157
|
+
this.resultSubject = new Subject();
|
|
158
|
+
/** Observable of execution results */
|
|
159
|
+
this.result$ = this.resultSubject.asObservable();
|
|
160
|
+
// Support both direct config (for testing) and DI injection
|
|
161
|
+
let config = configOrInjected;
|
|
162
|
+
if (!config) {
|
|
163
|
+
try {
|
|
164
|
+
config = inject(TENTICKLE_CONFIG, { optional: true }) ?? undefined;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Not in injection context - config must be passed directly
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!config) {
|
|
171
|
+
throw new Error("TentickleService requires TENTICKLE_CONFIG to be provided");
|
|
172
|
+
}
|
|
173
|
+
this.client = createClient(config);
|
|
174
|
+
// Initialize observables from signals
|
|
175
|
+
// Note: toObservable requires injection context, so we create them conditionally
|
|
176
|
+
try {
|
|
177
|
+
this.connectionState$ = toObservable(this.connectionState);
|
|
178
|
+
this.isConnected$ = toObservable(this.isConnected);
|
|
179
|
+
this.streamingText$ = toObservable(this.streamingText);
|
|
180
|
+
this.text$ = toObservable(this.text);
|
|
181
|
+
this.isStreaming$ = toObservable(this.isStreaming);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Not in injection context - create manual observables for testing
|
|
185
|
+
this.connectionState$ = new Observable((subscriber) => {
|
|
186
|
+
subscriber.next(this.connectionState());
|
|
187
|
+
const interval = setInterval(() => {
|
|
188
|
+
subscriber.next(this.connectionState());
|
|
189
|
+
}, 10);
|
|
190
|
+
return () => clearInterval(interval);
|
|
191
|
+
});
|
|
192
|
+
this.isConnected$ = new Observable((subscriber) => {
|
|
193
|
+
subscriber.next(this.isConnected());
|
|
194
|
+
const interval = setInterval(() => {
|
|
195
|
+
subscriber.next(this.isConnected());
|
|
196
|
+
}, 10);
|
|
197
|
+
return () => clearInterval(interval);
|
|
198
|
+
});
|
|
199
|
+
this.streamingText$ = new Observable((subscriber) => {
|
|
200
|
+
subscriber.next(this.streamingText());
|
|
201
|
+
const interval = setInterval(() => {
|
|
202
|
+
subscriber.next(this.streamingText());
|
|
203
|
+
}, 10);
|
|
204
|
+
return () => clearInterval(interval);
|
|
205
|
+
});
|
|
206
|
+
this.text$ = new Observable((subscriber) => {
|
|
207
|
+
subscriber.next(this.text());
|
|
208
|
+
const interval = setInterval(() => {
|
|
209
|
+
subscriber.next(this.text());
|
|
210
|
+
}, 10);
|
|
211
|
+
return () => clearInterval(interval);
|
|
212
|
+
});
|
|
213
|
+
this.isStreaming$ = new Observable((subscriber) => {
|
|
214
|
+
subscriber.next(this.isStreaming());
|
|
215
|
+
const interval = setInterval(() => {
|
|
216
|
+
subscriber.next(this.isStreaming());
|
|
217
|
+
}, 10);
|
|
218
|
+
return () => clearInterval(interval);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
this.setupSubscriptions();
|
|
222
|
+
}
|
|
223
|
+
setupSubscriptions() {
|
|
224
|
+
// Connection state → signal
|
|
225
|
+
this.client.onConnectionChange((state) => {
|
|
226
|
+
this.connectionState.set(state);
|
|
227
|
+
});
|
|
228
|
+
// Streaming text → signal
|
|
229
|
+
this.client.onStreamingText((state) => {
|
|
230
|
+
this.streamingText.set(state);
|
|
231
|
+
});
|
|
232
|
+
// Events → subject (for filtering)
|
|
233
|
+
this.client.onEvent((event) => {
|
|
234
|
+
this.eventsSubject.next(event);
|
|
235
|
+
});
|
|
236
|
+
// Results → subject
|
|
237
|
+
this.client.onEvent((event) => {
|
|
238
|
+
if (event.type === "result") {
|
|
239
|
+
this.resultSubject.next(event.result);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
244
|
+
// Session Access
|
|
245
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
246
|
+
/**
|
|
247
|
+
* Get a cold session accessor.
|
|
248
|
+
*/
|
|
249
|
+
session(sessionId) {
|
|
250
|
+
return this.client.session(sessionId);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Subscribe to a session and make it the active session.
|
|
254
|
+
*/
|
|
255
|
+
subscribe(sessionId) {
|
|
256
|
+
const accessor = this.client.subscribe(sessionId);
|
|
257
|
+
this.currentSession = accessor;
|
|
258
|
+
this.sessionId.set(sessionId);
|
|
259
|
+
return accessor;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Unsubscribe from the active session.
|
|
263
|
+
*/
|
|
264
|
+
unsubscribe() {
|
|
265
|
+
this.currentSession?.unsubscribe();
|
|
266
|
+
this.currentSession = undefined;
|
|
267
|
+
this.sessionId.set(undefined);
|
|
268
|
+
}
|
|
269
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
270
|
+
// Messaging
|
|
271
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
272
|
+
/**
|
|
273
|
+
* Send a message to the session.
|
|
274
|
+
*/
|
|
275
|
+
send(input) {
|
|
276
|
+
if (this.currentSession) {
|
|
277
|
+
return this.currentSession.send(input);
|
|
278
|
+
}
|
|
279
|
+
return this.client.send(input);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Abort the current execution.
|
|
283
|
+
*/
|
|
284
|
+
async abort(reason) {
|
|
285
|
+
if (this.currentSession) {
|
|
286
|
+
await this.currentSession.abort(reason);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const id = this.sessionId();
|
|
290
|
+
if (id) {
|
|
291
|
+
await this.client.abort(id, reason);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Close the active session on the server.
|
|
296
|
+
*/
|
|
297
|
+
async close() {
|
|
298
|
+
if (this.currentSession) {
|
|
299
|
+
await this.currentSession.close();
|
|
300
|
+
this.currentSession = undefined;
|
|
301
|
+
this.sessionId.set(undefined);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Clear the accumulated streaming text.
|
|
306
|
+
*/
|
|
307
|
+
clearStreamingText() {
|
|
308
|
+
this.client.clearStreamingText();
|
|
309
|
+
}
|
|
310
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
311
|
+
// Channels
|
|
312
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
313
|
+
/**
|
|
314
|
+
* Get a channel accessor for custom pub/sub.
|
|
315
|
+
*/
|
|
316
|
+
channel(name) {
|
|
317
|
+
if (!this.currentSession) {
|
|
318
|
+
throw new Error("No active session. Call subscribe(sessionId) first.");
|
|
319
|
+
}
|
|
320
|
+
return this.currentSession.channel(name);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Create an Observable from a channel.
|
|
324
|
+
*/
|
|
325
|
+
channel$(name) {
|
|
326
|
+
return new Observable((subscriber) => {
|
|
327
|
+
const channel = this.channel(name);
|
|
328
|
+
const unsubscribe = channel.subscribe((payload, event) => {
|
|
329
|
+
subscriber.next({ type: event.type, payload });
|
|
330
|
+
});
|
|
331
|
+
return () => unsubscribe();
|
|
332
|
+
}).pipe(takeUntil(this.destroy$));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Filter events by type.
|
|
336
|
+
*/
|
|
337
|
+
eventsOfType(...types) {
|
|
338
|
+
return this.events$.pipe(filter((event) => types.includes(event.type)));
|
|
339
|
+
}
|
|
340
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
341
|
+
// Cleanup
|
|
342
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
343
|
+
ngOnDestroy() {
|
|
344
|
+
this.destroy$.next();
|
|
345
|
+
this.destroy$.complete();
|
|
346
|
+
this.client.destroy();
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
TentickleService = __decorate([
|
|
350
|
+
Injectable({ providedIn: "root" }),
|
|
351
|
+
__metadata("design:paramtypes", [Object])
|
|
352
|
+
], TentickleService);
|
|
353
|
+
export { TentickleService };
|
|
354
|
+
//# sourceMappingURL=tentickle.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tentickle.service.js","sourceRoot":"","sources":["../src/tentickle.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;;;;;;;;;;AAEH,OAAO,EACL,UAAU,EACV,cAAc,EAEd,QAAQ,EACR,MAAM,EACN,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAC9D,OAAO,EACL,YAAY,GAQb,MAAM,mBAAmB,CAAC;AAG3B;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,cAAc,CAAkB,kBAAkB,CAAC,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,OAAO,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAyE3B,6EAA6E;IAC7E,cAAc;IACd,6EAA6E;IAE7E;;;;OAIG;IACH,YAAY,gBAAkC;QAhF7B,aAAQ,GAAG,IAAI,OAAO,EAAQ,CAAC;QAGhD,6EAA6E;QAC7E,0BAA0B;QAC1B,6EAA6E;QAE7E,+BAA+B;QACtB,oBAAe,GAAG,MAAM,CAAkB,cAAc,CAAC,CAAC;QAEnE,yBAAyB;QAChB,cAAS,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;QAE3D,+BAA+B;QACtB,UAAK,GAAG,MAAM,CAAoB,SAAS,CAAC,CAAC;QAEtD,2CAA2C;QAClC,kBAAa,GAAG,MAAM,CAAqB,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAEtF,6EAA6E;QAC7E,mCAAmC;QACnC,6EAA6E;QAE7E,kCAAkC;QACzB,gBAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,WAAW,CAAC,CAAC;QAE9E,mCAAmC;QAC1B,iBAAY,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,YAAY,CAAC,CAAC;QAEhF,6BAA6B;QACpB,SAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC;QAE1D,kCAAkC;QACzB,gBAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,WAAW,CAAC,CAAC;QAqBxE,oCAAoC;QACnB,kBAAa,GAAG,IAAI,OAAO,EAAoC,CAAC;QAEjF,sCAAsC;QAC7B,YAAO,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;QAErD,oCAAoC;QACnB,kBAAa,GAAG,IAAI,OAAO,EAKxC,CAAC;QAEL,sCAAsC;QAC7B,YAAO,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;QAYnD,4DAA4D;QAC5D,IAAI,MAAM,GAAG,gBAAgB,CAAC;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,SAAS,CAAC;YACrE,CAAC;YAAC,MAAM,CAAC;gBACP,4DAA4D;YAC9D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QAEnC,sCAAsC;QACtC,iFAAiF;QACjF,IAAI,CAAC;YACH,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC3D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACnD,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACvD,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,IAAI,CAAC,gBAAgB,GAAG,IAAI,UAAU,CAAkB,CAAC,UAAU,EAAE,EAAE;gBACrE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;gBACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;oBAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;gBAC1C,CAAC,EAAE,EAAE,CAAC,CAAC;gBACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,IAAI,UAAU,CAAU,CAAC,UAAU,EAAE,EAAE;gBACzD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;oBAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACtC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,cAAc,GAAG,IAAI,UAAU,CAAqB,CAAC,UAAU,EAAE,EAAE;gBACtE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;gBACtC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;oBAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;gBACxC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAS,CAAC,UAAU,EAAE,EAAE;gBACjD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC7B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;oBAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC/B,CAAC,EAAE,EAAE,CAAC,CAAC;gBACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,IAAI,UAAU,CAAU,CAAC,UAAU,EAAE,EAAE;gBACzD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;oBAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACtC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAEO,kBAAkB;QACxB,4BAA4B;QAC5B,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE;YACvC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,mCAAmC;QACnC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,oBAAoB;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,6EAA6E;IAC7E,iBAAiB;IACjB,6EAA6E;IAE7E;;OAEG;IACH,OAAO,CAAC,SAAiB;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,SAAiB;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,WAAW;QACT,IAAI,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAE7E;;OAEG;IACH,IAAI,CAAC,KAA6C;QAChD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAY,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAY,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,MAAe;QACzB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACxC,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,EAAE,EAAE,CAAC;YACP,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;IACnC,CAAC;IAED,6EAA6E;IAC7E,WAAW;IACX,6EAA6E;IAE7E;;OAEG;IACH,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,UAAU,CAAqC,CAAC,UAAU,EAAE,EAAE;YACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBACvD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,GAAG,KAA4B;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,6EAA6E;IAC7E,UAAU;IACV,6EAA6E;IAE7E,WAAW;QACT,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF,CAAA;AApSY,gBAAgB;IAD5B,UAAU,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;;GACtB,gBAAgB,CAoS5B"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular integration types for Agentick.
|
|
3
|
+
*
|
|
4
|
+
* @module @agentick/angular/types
|
|
5
|
+
*/
|
|
6
|
+
import type { ClientTransport } from "@agentick/client";
|
|
7
|
+
/**
|
|
8
|
+
* Transport configuration for AgentickService.
|
|
9
|
+
* Can be a built-in transport type or a custom ClientTransport instance.
|
|
10
|
+
*/
|
|
11
|
+
export type TransportConfig = "sse" | "websocket" | "auto" | ClientTransport;
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for AgentickService.
|
|
14
|
+
*/
|
|
15
|
+
export interface AgentickConfig {
|
|
16
|
+
/**
|
|
17
|
+
* Base URL of the Agentick server.
|
|
18
|
+
*/
|
|
19
|
+
baseUrl: string;
|
|
20
|
+
/**
|
|
21
|
+
* Transport to use for communication.
|
|
22
|
+
* - "sse": HTTP/SSE transport (default for http:// and https:// URLs)
|
|
23
|
+
* - "websocket": WebSocket transport (default for ws:// and wss:// URLs)
|
|
24
|
+
* - "auto": Auto-detect based on URL scheme (default)
|
|
25
|
+
* - ClientTransport instance: Use a custom transport (e.g., SharedTransport for multi-tab)
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { createSharedTransport } from '@agentick/client-multiplexer';
|
|
30
|
+
*
|
|
31
|
+
* providers: [
|
|
32
|
+
* {
|
|
33
|
+
* provide: TENTICKLE_CONFIG,
|
|
34
|
+
* useValue: {
|
|
35
|
+
* baseUrl: 'https://api.example.com',
|
|
36
|
+
* transport: createSharedTransport({ baseUrl: 'https://api.example.com' }),
|
|
37
|
+
* },
|
|
38
|
+
* },
|
|
39
|
+
* ]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
transport?: TransportConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Authentication token (adds Authorization: Bearer header).
|
|
45
|
+
*/
|
|
46
|
+
token?: string;
|
|
47
|
+
/**
|
|
48
|
+
* User ID for session metadata.
|
|
49
|
+
*/
|
|
50
|
+
userId?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Custom headers for requests.
|
|
53
|
+
*/
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
/**
|
|
56
|
+
* Custom path configuration.
|
|
57
|
+
*/
|
|
58
|
+
paths?: {
|
|
59
|
+
events?: string;
|
|
60
|
+
send?: string;
|
|
61
|
+
subscribe?: string;
|
|
62
|
+
abort?: string;
|
|
63
|
+
close?: string;
|
|
64
|
+
toolResponse?: string;
|
|
65
|
+
channel?: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Request timeout in milliseconds.
|
|
69
|
+
* @default 30000
|
|
70
|
+
*/
|
|
71
|
+
timeout?: number;
|
|
72
|
+
}
|
|
73
|
+
export type { AgentickClient, ConnectionState, StreamEvent, SessionStreamEvent, ClientExecutionHandle, StreamingTextState, ClientTransport, } from "@agentick/client";
|
|
74
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMxD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,WAAW,GAAG,MAAM,GAAG,eAAe,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IAEF;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,YAAY,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,GAChB,MAAM,kBAAkB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentick/angular",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Angular services and utilities for Agentick applications",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@agentick/client": "0.0.1",
|
|
20
|
+
"@agentick/shared": "0.0.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@angular/core": "^19.0.0",
|
|
24
|
+
"@types/node": "^22.10.5",
|
|
25
|
+
"rxjs": "^7.8.0",
|
|
26
|
+
"typescript": "^5.7.3",
|
|
27
|
+
"vitest": "^3.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
31
|
+
"rxjs": "^7.0.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.build.json",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"clean": "rm -rf dist",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for AgentickService (signals-based)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
6
|
+
import { firstValueFrom } from "rxjs";
|
|
7
|
+
import type { StreamingTextState, SessionStreamEvent } from "@agentick/client";
|
|
8
|
+
|
|
9
|
+
let mockStreamingTextState: StreamingTextState = { text: "", isStreaming: false };
|
|
10
|
+
let mockStreamingTextHandlers = new Set<(state: StreamingTextState) => void>();
|
|
11
|
+
|
|
12
|
+
const emitMockStreamingText = (state: StreamingTextState) => {
|
|
13
|
+
mockStreamingTextState = state;
|
|
14
|
+
for (const handler of mockStreamingTextHandlers) {
|
|
15
|
+
handler(state);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const createMockHandle = (sessionId: string) => ({
|
|
20
|
+
sessionId,
|
|
21
|
+
executionId: "exec-1",
|
|
22
|
+
status: "completed" as const,
|
|
23
|
+
result: Promise.resolve({
|
|
24
|
+
response: "ok",
|
|
25
|
+
outputs: {},
|
|
26
|
+
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
|
|
27
|
+
}),
|
|
28
|
+
abort: vi.fn(),
|
|
29
|
+
queueMessage: vi.fn(),
|
|
30
|
+
submitToolResult: vi.fn(),
|
|
31
|
+
async *[Symbol.asyncIterator]() {},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const mockClient = {
|
|
35
|
+
session: vi.fn((id: string) => ({
|
|
36
|
+
sessionId: id,
|
|
37
|
+
isSubscribed: false,
|
|
38
|
+
subscribe: vi.fn(),
|
|
39
|
+
unsubscribe: vi.fn(),
|
|
40
|
+
send: vi.fn(() => createMockHandle(id)),
|
|
41
|
+
abort: vi.fn(),
|
|
42
|
+
close: vi.fn(),
|
|
43
|
+
onEvent: vi.fn(() => () => {}),
|
|
44
|
+
onResult: vi.fn(() => () => {}),
|
|
45
|
+
onToolConfirmation: vi.fn(() => () => {}),
|
|
46
|
+
channel: vi.fn((name: string) => ({
|
|
47
|
+
name,
|
|
48
|
+
subscribe: vi.fn(() => () => {}),
|
|
49
|
+
publish: vi.fn(async () => {}),
|
|
50
|
+
request: vi.fn(async () => ({})),
|
|
51
|
+
})),
|
|
52
|
+
})),
|
|
53
|
+
subscribe: vi.fn((id: string) => ({
|
|
54
|
+
sessionId: id,
|
|
55
|
+
isSubscribed: true,
|
|
56
|
+
subscribe: vi.fn(),
|
|
57
|
+
unsubscribe: vi.fn(),
|
|
58
|
+
send: vi.fn(() => createMockHandle(id)),
|
|
59
|
+
abort: vi.fn(),
|
|
60
|
+
close: vi.fn(),
|
|
61
|
+
onEvent: vi.fn(() => () => {}),
|
|
62
|
+
onResult: vi.fn(() => () => {}),
|
|
63
|
+
onToolConfirmation: vi.fn(() => () => {}),
|
|
64
|
+
channel: vi.fn(),
|
|
65
|
+
})),
|
|
66
|
+
send: vi.fn(() => createMockHandle("ephemeral")),
|
|
67
|
+
abort: vi.fn(),
|
|
68
|
+
closeSession: vi.fn(),
|
|
69
|
+
destroy: vi.fn(),
|
|
70
|
+
onConnectionChange: vi.fn(() => () => {}),
|
|
71
|
+
onEvent: vi.fn(() => () => {}),
|
|
72
|
+
on: vi.fn(() => () => {}),
|
|
73
|
+
onStreamingText: vi.fn((handler: (state: StreamingTextState) => void) => {
|
|
74
|
+
mockStreamingTextHandlers.add(handler);
|
|
75
|
+
handler(mockStreamingTextState);
|
|
76
|
+
return () => mockStreamingTextHandlers.delete(handler);
|
|
77
|
+
}),
|
|
78
|
+
clearStreamingText: vi.fn(() => {
|
|
79
|
+
emitMockStreamingText({ text: "", isStreaming: false });
|
|
80
|
+
}),
|
|
81
|
+
get streamingText() {
|
|
82
|
+
return mockStreamingTextState;
|
|
83
|
+
},
|
|
84
|
+
get state() {
|
|
85
|
+
return "disconnected" as const;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
vi.mock("@agentick/client", () => ({
|
|
90
|
+
createClient: vi.fn(() => mockClient),
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
import { AgentickService } from "./agentick.service";
|
|
94
|
+
|
|
95
|
+
describe("AgentickService", () => {
|
|
96
|
+
let service: AgentickService;
|
|
97
|
+
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
vi.clearAllMocks();
|
|
100
|
+
mockStreamingTextState = { text: "", isStreaming: false };
|
|
101
|
+
mockStreamingTextHandlers.clear();
|
|
102
|
+
service = new AgentickService({ baseUrl: "https://api.example.com" });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
afterEach(() => {
|
|
106
|
+
service.ngOnDestroy();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("initializes signals", () => {
|
|
110
|
+
expect(service.connectionState()).toBe("disconnected");
|
|
111
|
+
expect(service.sessionId()).toBeUndefined();
|
|
112
|
+
expect(service.streamingText()).toEqual({ text: "", isStreaming: false });
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("subscribes to a session", () => {
|
|
116
|
+
const accessor = service.subscribe("conv-123");
|
|
117
|
+
expect(accessor.sessionId).toBe("conv-123");
|
|
118
|
+
expect(service.sessionId()).toBe("conv-123");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("sends via active session", async () => {
|
|
122
|
+
service.subscribe("conv-123");
|
|
123
|
+
const handle = service.send("Hello");
|
|
124
|
+
const result = await handle.result;
|
|
125
|
+
expect(result.response).toBe("ok");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("streams text updates", async () => {
|
|
129
|
+
emitMockStreamingText({ text: "hello", isStreaming: true });
|
|
130
|
+
const text = await firstValueFrom(service.text$);
|
|
131
|
+
expect(text).toBe("hello");
|
|
132
|
+
});
|
|
133
|
+
});
|