@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,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentickService - Modern Angular service for Agentick.
|
|
3
|
+
*
|
|
4
|
+
* Uses Angular signals for reactive state management with RxJS interop.
|
|
5
|
+
*
|
|
6
|
+
* @module @agentick/angular/service
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
Injectable,
|
|
11
|
+
InjectionToken,
|
|
12
|
+
type OnDestroy,
|
|
13
|
+
computed,
|
|
14
|
+
signal,
|
|
15
|
+
inject,
|
|
16
|
+
} from "@angular/core";
|
|
17
|
+
import { toObservable } from "@angular/core/rxjs-interop";
|
|
18
|
+
import { Observable, Subject, filter, takeUntil } from "rxjs";
|
|
19
|
+
import {
|
|
20
|
+
createClient,
|
|
21
|
+
type AgentickClient,
|
|
22
|
+
type ConnectionState,
|
|
23
|
+
type StreamEvent,
|
|
24
|
+
type StreamingTextState,
|
|
25
|
+
type SessionStreamEvent,
|
|
26
|
+
type SessionAccessor,
|
|
27
|
+
type ClientExecutionHandle,
|
|
28
|
+
} from "@agentick/client";
|
|
29
|
+
import type { AgentickConfig } from "./types";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Injection token for Agentick configuration.
|
|
33
|
+
*/
|
|
34
|
+
export const TENTICKLE_CONFIG = new InjectionToken<AgentickConfig>("TENTICKLE_CONFIG");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Provides AgentickService with configuration at component level.
|
|
38
|
+
*
|
|
39
|
+
* Use this to create isolated service instances for different components,
|
|
40
|
+
* each with their own connection and state.
|
|
41
|
+
*
|
|
42
|
+
* @example Multiple agents in one app
|
|
43
|
+
* ```typescript
|
|
44
|
+
* // Each component gets its own AgentickService instance
|
|
45
|
+
*
|
|
46
|
+
* @Component({
|
|
47
|
+
* selector: 'app-support-chat',
|
|
48
|
+
* providers: [provideAgentick({ baseUrl: '/api/support-agent' })],
|
|
49
|
+
* template: `<div>{{ agentick.text() }}</div>`,
|
|
50
|
+
* })
|
|
51
|
+
* export class SupportChatComponent {
|
|
52
|
+
* agentick = inject(AgentickService);
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* @Component({
|
|
56
|
+
* selector: 'app-sales-chat',
|
|
57
|
+
* providers: [provideAgentick({ baseUrl: '/api/sales-agent' })],
|
|
58
|
+
* template: `<div>{{ agentick.text() }}</div>`,
|
|
59
|
+
* })
|
|
60
|
+
* export class SalesChatComponent {
|
|
61
|
+
* agentick = inject(AgentickService);
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @param config - Configuration for this service instance
|
|
66
|
+
* @returns Provider array to spread into component's providers
|
|
67
|
+
*/
|
|
68
|
+
export function provideAgentick(config: AgentickConfig) {
|
|
69
|
+
return [{ provide: TENTICKLE_CONFIG, useValue: config }, AgentickService];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Modern Angular service for Agentick.
|
|
74
|
+
*
|
|
75
|
+
* Uses signals for state, with RxJS observables available for compatibility.
|
|
76
|
+
*
|
|
77
|
+
* @example Standalone setup
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import { AgentickService, TENTICKLE_CONFIG } from '@agentick/angular';
|
|
80
|
+
*
|
|
81
|
+
* bootstrapApplication(AppComponent, {
|
|
82
|
+
* providers: [
|
|
83
|
+
* { provide: TENTICKLE_CONFIG, useValue: { baseUrl: 'https://api.example.com' } },
|
|
84
|
+
* ],
|
|
85
|
+
* });
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example Component with signals
|
|
89
|
+
* ```typescript
|
|
90
|
+
* @Component({
|
|
91
|
+
* template: `
|
|
92
|
+
* @if (agentick.isConnected()) {
|
|
93
|
+
* <div class="response">
|
|
94
|
+
* {{ agentick.text() }}
|
|
95
|
+
* @if (agentick.isStreaming()) {
|
|
96
|
+
* <span class="cursor">|</span>
|
|
97
|
+
* }
|
|
98
|
+
* </div>
|
|
99
|
+
* <input #input />
|
|
100
|
+
* <button (click)="send(input.value)">Send</button>
|
|
101
|
+
* } @else {
|
|
102
|
+
* <p>Connecting...</p>
|
|
103
|
+
* }
|
|
104
|
+
* `,
|
|
105
|
+
* })
|
|
106
|
+
* export class ChatComponent {
|
|
107
|
+
* agentick = inject(AgentickService);
|
|
108
|
+
*
|
|
109
|
+
* constructor() {
|
|
110
|
+
* this.agentick.subscribe("conv-123");
|
|
111
|
+
* }
|
|
112
|
+
*
|
|
113
|
+
* async send(message: string) {
|
|
114
|
+
* const handle = this.agentick.send(message);
|
|
115
|
+
* await handle.result;
|
|
116
|
+
* }
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @example With RxJS (for compatibility)
|
|
121
|
+
* ```typescript
|
|
122
|
+
* @Component({
|
|
123
|
+
* template: `{{ text$ | async }}`,
|
|
124
|
+
* })
|
|
125
|
+
* export class LegacyComponent {
|
|
126
|
+
* agentick = inject(AgentickService);
|
|
127
|
+
* text$ = this.agentick.text$;
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
@Injectable({ providedIn: "root" })
|
|
132
|
+
export class AgentickService implements OnDestroy {
|
|
133
|
+
private readonly client: AgentickClient;
|
|
134
|
+
private readonly destroy$ = new Subject<void>();
|
|
135
|
+
private currentSession?: SessionAccessor;
|
|
136
|
+
|
|
137
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
138
|
+
// Signals - Primary State
|
|
139
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
140
|
+
|
|
141
|
+
/** Current connection state */
|
|
142
|
+
readonly connectionState = signal<ConnectionState>("disconnected");
|
|
143
|
+
|
|
144
|
+
/** Current session ID */
|
|
145
|
+
readonly sessionId = signal<string | undefined>(undefined);
|
|
146
|
+
|
|
147
|
+
/** Connection error, if any */
|
|
148
|
+
readonly error = signal<Error | undefined>(undefined);
|
|
149
|
+
|
|
150
|
+
/** Streaming text state from the client */
|
|
151
|
+
readonly streamingText = signal<StreamingTextState>({ text: "", isStreaming: false });
|
|
152
|
+
|
|
153
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
154
|
+
// Computed Signals - Derived State
|
|
155
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
156
|
+
|
|
157
|
+
/** Whether currently connected */
|
|
158
|
+
readonly isConnected = computed(() => this.connectionState() === "connected");
|
|
159
|
+
|
|
160
|
+
/** Whether currently connecting */
|
|
161
|
+
readonly isConnecting = computed(() => this.connectionState() === "connecting");
|
|
162
|
+
|
|
163
|
+
/** Current streaming text */
|
|
164
|
+
readonly text = computed(() => this.streamingText().text);
|
|
165
|
+
|
|
166
|
+
/** Whether currently streaming */
|
|
167
|
+
readonly isStreaming = computed(() => this.streamingText().isStreaming);
|
|
168
|
+
|
|
169
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
170
|
+
// RxJS Observables - For Compatibility
|
|
171
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
172
|
+
|
|
173
|
+
/** Observable of connection state (for RxJS users) */
|
|
174
|
+
readonly connectionState$: Observable<ConnectionState>;
|
|
175
|
+
|
|
176
|
+
/** Observable of whether connected (for RxJS users) */
|
|
177
|
+
readonly isConnected$: Observable<boolean>;
|
|
178
|
+
|
|
179
|
+
/** Observable of streaming text state (for RxJS users) */
|
|
180
|
+
readonly streamingText$: Observable<StreamingTextState>;
|
|
181
|
+
|
|
182
|
+
/** Observable of just the text (for RxJS users) */
|
|
183
|
+
readonly text$: Observable<string>;
|
|
184
|
+
|
|
185
|
+
/** Observable of whether streaming (for RxJS users) */
|
|
186
|
+
readonly isStreaming$: Observable<boolean>;
|
|
187
|
+
|
|
188
|
+
/** Subject for raw stream events */
|
|
189
|
+
private readonly eventsSubject = new Subject<StreamEvent | SessionStreamEvent>();
|
|
190
|
+
|
|
191
|
+
/** Observable of all stream events */
|
|
192
|
+
readonly events$ = this.eventsSubject.asObservable();
|
|
193
|
+
|
|
194
|
+
/** Subject for execution results */
|
|
195
|
+
private readonly resultSubject = new Subject<{
|
|
196
|
+
response: string;
|
|
197
|
+
outputs: Record<string, unknown>;
|
|
198
|
+
usage: { inputTokens: number; outputTokens: number; totalTokens: number };
|
|
199
|
+
stopReason?: string;
|
|
200
|
+
}>();
|
|
201
|
+
|
|
202
|
+
/** Observable of execution results */
|
|
203
|
+
readonly result$ = this.resultSubject.asObservable();
|
|
204
|
+
|
|
205
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
206
|
+
// Constructor
|
|
207
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Creates a new AgentickService.
|
|
211
|
+
*
|
|
212
|
+
* @param configOrInjected - Config passed directly (for testing) or undefined to use DI
|
|
213
|
+
*/
|
|
214
|
+
constructor(configOrInjected?: AgentickConfig) {
|
|
215
|
+
// Support both direct config (for testing) and DI injection
|
|
216
|
+
let config = configOrInjected;
|
|
217
|
+
if (!config) {
|
|
218
|
+
try {
|
|
219
|
+
config = inject(TENTICKLE_CONFIG, { optional: true }) ?? undefined;
|
|
220
|
+
} catch {
|
|
221
|
+
// Not in injection context - config must be passed directly
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!config) {
|
|
226
|
+
throw new Error("AgentickService requires TENTICKLE_CONFIG to be provided");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.client = createClient(config);
|
|
230
|
+
|
|
231
|
+
// Initialize observables from signals
|
|
232
|
+
// Note: toObservable requires injection context, so we create them conditionally
|
|
233
|
+
try {
|
|
234
|
+
this.connectionState$ = toObservable(this.connectionState);
|
|
235
|
+
this.isConnected$ = toObservable(this.isConnected);
|
|
236
|
+
this.streamingText$ = toObservable(this.streamingText);
|
|
237
|
+
this.text$ = toObservable(this.text);
|
|
238
|
+
this.isStreaming$ = toObservable(this.isStreaming);
|
|
239
|
+
} catch {
|
|
240
|
+
// Not in injection context - create manual observables for testing
|
|
241
|
+
this.connectionState$ = new Observable<ConnectionState>((subscriber) => {
|
|
242
|
+
subscriber.next(this.connectionState());
|
|
243
|
+
const interval = setInterval(() => {
|
|
244
|
+
subscriber.next(this.connectionState());
|
|
245
|
+
}, 10);
|
|
246
|
+
return () => clearInterval(interval);
|
|
247
|
+
});
|
|
248
|
+
this.isConnected$ = new Observable<boolean>((subscriber) => {
|
|
249
|
+
subscriber.next(this.isConnected());
|
|
250
|
+
const interval = setInterval(() => {
|
|
251
|
+
subscriber.next(this.isConnected());
|
|
252
|
+
}, 10);
|
|
253
|
+
return () => clearInterval(interval);
|
|
254
|
+
});
|
|
255
|
+
this.streamingText$ = new Observable<StreamingTextState>((subscriber) => {
|
|
256
|
+
subscriber.next(this.streamingText());
|
|
257
|
+
const interval = setInterval(() => {
|
|
258
|
+
subscriber.next(this.streamingText());
|
|
259
|
+
}, 10);
|
|
260
|
+
return () => clearInterval(interval);
|
|
261
|
+
});
|
|
262
|
+
this.text$ = new Observable<string>((subscriber) => {
|
|
263
|
+
subscriber.next(this.text());
|
|
264
|
+
const interval = setInterval(() => {
|
|
265
|
+
subscriber.next(this.text());
|
|
266
|
+
}, 10);
|
|
267
|
+
return () => clearInterval(interval);
|
|
268
|
+
});
|
|
269
|
+
this.isStreaming$ = new Observable<boolean>((subscriber) => {
|
|
270
|
+
subscriber.next(this.isStreaming());
|
|
271
|
+
const interval = setInterval(() => {
|
|
272
|
+
subscriber.next(this.isStreaming());
|
|
273
|
+
}, 10);
|
|
274
|
+
return () => clearInterval(interval);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.setupSubscriptions();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private setupSubscriptions(): void {
|
|
282
|
+
// Connection state → signal
|
|
283
|
+
this.client.onConnectionChange((state) => {
|
|
284
|
+
this.connectionState.set(state);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Streaming text → signal
|
|
288
|
+
this.client.onStreamingText((state) => {
|
|
289
|
+
this.streamingText.set(state);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Events → subject (for filtering)
|
|
293
|
+
this.client.onEvent((event) => {
|
|
294
|
+
this.eventsSubject.next(event);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Results → subject
|
|
298
|
+
this.client.onEvent((event) => {
|
|
299
|
+
if (event.type === "result") {
|
|
300
|
+
this.resultSubject.next(event.result);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
306
|
+
// Session Access
|
|
307
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Get a cold session accessor.
|
|
311
|
+
*/
|
|
312
|
+
session(sessionId: string): SessionAccessor {
|
|
313
|
+
return this.client.session(sessionId);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Subscribe to a session and make it the active session.
|
|
318
|
+
*/
|
|
319
|
+
subscribe(sessionId: string): SessionAccessor {
|
|
320
|
+
const accessor = this.client.subscribe(sessionId);
|
|
321
|
+
this.currentSession = accessor;
|
|
322
|
+
this.sessionId.set(sessionId);
|
|
323
|
+
return accessor;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Unsubscribe from the active session.
|
|
328
|
+
*/
|
|
329
|
+
unsubscribe(): void {
|
|
330
|
+
this.currentSession?.unsubscribe();
|
|
331
|
+
this.currentSession = undefined;
|
|
332
|
+
this.sessionId.set(undefined);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
336
|
+
// Messaging
|
|
337
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Send a message to the session.
|
|
341
|
+
*/
|
|
342
|
+
send(input: Parameters<AgentickClient["send"]>[0]): ClientExecutionHandle {
|
|
343
|
+
if (this.currentSession) {
|
|
344
|
+
return this.currentSession.send(input as any);
|
|
345
|
+
}
|
|
346
|
+
return this.client.send(input as any);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Abort the current execution.
|
|
351
|
+
*/
|
|
352
|
+
async abort(reason?: string): Promise<void> {
|
|
353
|
+
if (this.currentSession) {
|
|
354
|
+
await this.currentSession.abort(reason);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const id = this.sessionId();
|
|
358
|
+
if (id) {
|
|
359
|
+
await this.client.abort(id, reason);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Close the active session on the server.
|
|
365
|
+
*/
|
|
366
|
+
async close(): Promise<void> {
|
|
367
|
+
if (this.currentSession) {
|
|
368
|
+
await this.currentSession.close();
|
|
369
|
+
this.currentSession = undefined;
|
|
370
|
+
this.sessionId.set(undefined);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Clear the accumulated streaming text.
|
|
376
|
+
*/
|
|
377
|
+
clearStreamingText(): void {
|
|
378
|
+
this.client.clearStreamingText();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
382
|
+
// Channels
|
|
383
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get a channel accessor for custom pub/sub.
|
|
387
|
+
*/
|
|
388
|
+
channel(name: string) {
|
|
389
|
+
if (!this.currentSession) {
|
|
390
|
+
throw new Error("No active session. Call subscribe(sessionId) first.");
|
|
391
|
+
}
|
|
392
|
+
return this.currentSession.channel(name);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Create an Observable from a channel.
|
|
397
|
+
*/
|
|
398
|
+
channel$(name: string): Observable<{ type: string; payload: unknown }> {
|
|
399
|
+
return new Observable<{ type: string; payload: unknown }>((subscriber) => {
|
|
400
|
+
const channel = this.channel(name);
|
|
401
|
+
const unsubscribe = channel.subscribe((payload, event) => {
|
|
402
|
+
subscriber.next({ type: event.type, payload });
|
|
403
|
+
});
|
|
404
|
+
return () => unsubscribe();
|
|
405
|
+
}).pipe(takeUntil(this.destroy$));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Filter events by type.
|
|
410
|
+
*/
|
|
411
|
+
eventsOfType(...types: StreamEvent["type"][]): Observable<StreamEvent> {
|
|
412
|
+
return this.events$.pipe(filter((event) => types.includes(event.type)));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
416
|
+
// Cleanup
|
|
417
|
+
// ══════════════════════════════════════════════════════════════════════════
|
|
418
|
+
|
|
419
|
+
ngOnDestroy(): void {
|
|
420
|
+
this.destroy$.next();
|
|
421
|
+
this.destroy$.complete();
|
|
422
|
+
this.client.destroy();
|
|
423
|
+
}
|
|
424
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentick/angular - Modern Angular bindings for Agentick
|
|
3
|
+
*
|
|
4
|
+
* Uses Angular signals for reactive state with RxJS interop for compatibility.
|
|
5
|
+
*
|
|
6
|
+
* @example Standalone setup
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { TENTICKLE_CONFIG } from '@agentick/angular';
|
|
9
|
+
*
|
|
10
|
+
* bootstrapApplication(AppComponent, {
|
|
11
|
+
* providers: [
|
|
12
|
+
* { provide: TENTICKLE_CONFIG, useValue: { baseUrl: 'https://api.example.com' } },
|
|
13
|
+
* ],
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example Component with signals (recommended)
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { Component, inject } from '@angular/core';
|
|
20
|
+
* import { AgentickService } from '@agentick/angular';
|
|
21
|
+
*
|
|
22
|
+
* @Component({
|
|
23
|
+
* selector: 'app-chat',
|
|
24
|
+
* standalone: true,
|
|
25
|
+
* template: `
|
|
26
|
+
* <div class="response">
|
|
27
|
+
* {{ agentick.text() }}
|
|
28
|
+
* @if (agentick.isStreaming()) {
|
|
29
|
+
* <span class="cursor">|</span>
|
|
30
|
+
* }
|
|
31
|
+
* </div>
|
|
32
|
+
* <input #input />
|
|
33
|
+
* <button (click)="send(input.value); input.value = ''">Send</button>
|
|
34
|
+
* `,
|
|
35
|
+
* })
|
|
36
|
+
* export class ChatComponent {
|
|
37
|
+
* agentick = inject(AgentickService);
|
|
38
|
+
*
|
|
39
|
+
* constructor() {
|
|
40
|
+
* this.agentick.subscribe("conv-123");
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* async send(message: string) {
|
|
44
|
+
* const handle = this.agentick.send(message);
|
|
45
|
+
* await handle.result;
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example With RxJS (for legacy or complex reactive flows)
|
|
51
|
+
* ```typescript
|
|
52
|
+
* @Component({
|
|
53
|
+
* template: `
|
|
54
|
+
* <div>{{ text$ | async }}</div>
|
|
55
|
+
* `,
|
|
56
|
+
* })
|
|
57
|
+
* export class LegacyComponent {
|
|
58
|
+
* agentick = inject(AgentickService);
|
|
59
|
+
* text$ = this.agentick.text$;
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example Multiple agents with separate instances
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { provideAgentick, AgentickService } from '@agentick/angular';
|
|
66
|
+
*
|
|
67
|
+
* // Each component gets its own service instance
|
|
68
|
+
* @Component({
|
|
69
|
+
* selector: 'app-support-chat',
|
|
70
|
+
* standalone: true,
|
|
71
|
+
* providers: [provideAgentick({ baseUrl: '/api/support-agent' })],
|
|
72
|
+
* template: `<div>{{ agentick.text() }}</div>`,
|
|
73
|
+
* })
|
|
74
|
+
* export class SupportChatComponent {
|
|
75
|
+
* agentick = inject(AgentickService);
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* @Component({
|
|
79
|
+
* selector: 'app-sales-chat',
|
|
80
|
+
* standalone: true,
|
|
81
|
+
* providers: [provideAgentick({ baseUrl: '/api/sales-agent' })],
|
|
82
|
+
* template: `<div>{{ agentick.text() }}</div>`,
|
|
83
|
+
* })
|
|
84
|
+
* export class SalesChatComponent {
|
|
85
|
+
* agentick = inject(AgentickService);
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* ## Signals (Primary API)
|
|
90
|
+
*
|
|
91
|
+
* | Signal | Type | Description |
|
|
92
|
+
* |--------|------|-------------|
|
|
93
|
+
* | `connectionState()` | `ConnectionState` | Connection state |
|
|
94
|
+
* | `sessionId()` | `string \| undefined` | Active session ID |
|
|
95
|
+
* | `streamingText()` | `StreamingTextState` | Text + isStreaming |
|
|
96
|
+
* | `text()` | `string` | Just the text (computed) |
|
|
97
|
+
* | `isStreaming()` | `boolean` | Whether streaming (computed) |
|
|
98
|
+
*
|
|
99
|
+
* ## RxJS Observables (Compatibility)
|
|
100
|
+
*
|
|
101
|
+
* | Observable | Type | Description |
|
|
102
|
+
* |------------|------|-------------|
|
|
103
|
+
* | `connectionState$` | `ConnectionState` | Connection state |
|
|
104
|
+
* | `isConnected$` | `boolean` | Whether connected |
|
|
105
|
+
* | `streamingText$` | `StreamingTextState` | Text + isStreaming |
|
|
106
|
+
* | `text$` | `string` | Just the text |
|
|
107
|
+
* | `isStreaming$` | `boolean` | Whether streaming |
|
|
108
|
+
* | `events$` | `StreamEvent | SessionStreamEvent` | All stream events |
|
|
109
|
+
* | `result$` | `Result` | Execution results |
|
|
110
|
+
*
|
|
111
|
+
* ## Methods
|
|
112
|
+
*
|
|
113
|
+
* | Method | Description |
|
|
114
|
+
* |--------|-------------|
|
|
115
|
+
* | `session(sessionId)` | Get cold accessor |
|
|
116
|
+
* | `subscribe(sessionId)` | Subscribe (hot) |
|
|
117
|
+
* | `unsubscribe()` | Unsubscribe active session |
|
|
118
|
+
* | `send(input)` | Send message |
|
|
119
|
+
* | `abort(reason?)` | Abort execution |
|
|
120
|
+
* | `close()` | Close active session |
|
|
121
|
+
* | `channel(name)` | Get channel accessor |
|
|
122
|
+
* | `channel$(name)` | Get channel as Observable |
|
|
123
|
+
* | `eventsOfType(...types)` | Filter events by type |
|
|
124
|
+
* | `clearStreamingText()` | Clear accumulated text |
|
|
125
|
+
*
|
|
126
|
+
* @module @agentick/angular
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
// Service, token, and provider factory
|
|
130
|
+
export { AgentickService, TENTICKLE_CONFIG, provideAgentick } from "./agentick.service";
|
|
131
|
+
|
|
132
|
+
// Types
|
|
133
|
+
export type {
|
|
134
|
+
AgentickConfig,
|
|
135
|
+
TransportConfig,
|
|
136
|
+
AgentickClient,
|
|
137
|
+
ConnectionState,
|
|
138
|
+
StreamEvent,
|
|
139
|
+
SessionStreamEvent,
|
|
140
|
+
ClientExecutionHandle,
|
|
141
|
+
StreamingTextState,
|
|
142
|
+
ClientTransport,
|
|
143
|
+
} from "./types";
|
|
144
|
+
|
|
145
|
+
// Re-export createClient for advanced usage
|
|
146
|
+
export { createClient } from "@agentick/client";
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular integration types for Agentick.
|
|
3
|
+
*
|
|
4
|
+
* @module @agentick/angular/types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ClientTransport } from "@agentick/client";
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Configuration Types
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Transport configuration for AgentickService.
|
|
15
|
+
* Can be a built-in transport type or a custom ClientTransport instance.
|
|
16
|
+
*/
|
|
17
|
+
export type TransportConfig = "sse" | "websocket" | "auto" | ClientTransport;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for AgentickService.
|
|
21
|
+
*/
|
|
22
|
+
export interface AgentickConfig {
|
|
23
|
+
/**
|
|
24
|
+
* Base URL of the Agentick server.
|
|
25
|
+
*/
|
|
26
|
+
baseUrl: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Transport to use for communication.
|
|
30
|
+
* - "sse": HTTP/SSE transport (default for http:// and https:// URLs)
|
|
31
|
+
* - "websocket": WebSocket transport (default for ws:// and wss:// URLs)
|
|
32
|
+
* - "auto": Auto-detect based on URL scheme (default)
|
|
33
|
+
* - ClientTransport instance: Use a custom transport (e.g., SharedTransport for multi-tab)
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { createSharedTransport } from '@agentick/client-multiplexer';
|
|
38
|
+
*
|
|
39
|
+
* providers: [
|
|
40
|
+
* {
|
|
41
|
+
* provide: TENTICKLE_CONFIG,
|
|
42
|
+
* useValue: {
|
|
43
|
+
* baseUrl: 'https://api.example.com',
|
|
44
|
+
* transport: createSharedTransport({ baseUrl: 'https://api.example.com' }),
|
|
45
|
+
* },
|
|
46
|
+
* },
|
|
47
|
+
* ]
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
transport?: TransportConfig;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Authentication token (adds Authorization: Bearer header).
|
|
54
|
+
*/
|
|
55
|
+
token?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* User ID for session metadata.
|
|
59
|
+
*/
|
|
60
|
+
userId?: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Custom headers for requests.
|
|
64
|
+
*/
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Custom path configuration.
|
|
69
|
+
*/
|
|
70
|
+
paths?: {
|
|
71
|
+
events?: string;
|
|
72
|
+
send?: string;
|
|
73
|
+
subscribe?: string;
|
|
74
|
+
abort?: string;
|
|
75
|
+
close?: string;
|
|
76
|
+
toolResponse?: string;
|
|
77
|
+
channel?: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Request timeout in milliseconds.
|
|
82
|
+
* @default 30000
|
|
83
|
+
*/
|
|
84
|
+
timeout?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ============================================================================
|
|
88
|
+
// Re-exports
|
|
89
|
+
// ============================================================================
|
|
90
|
+
|
|
91
|
+
export type {
|
|
92
|
+
AgentickClient,
|
|
93
|
+
ConnectionState,
|
|
94
|
+
StreamEvent,
|
|
95
|
+
SessionStreamEvent,
|
|
96
|
+
ClientExecutionHandle,
|
|
97
|
+
StreamingTextState,
|
|
98
|
+
ClientTransport,
|
|
99
|
+
} from "@agentick/client";
|