@convex-dev/agent 0.1.16 → 0.1.17

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 CHANGED
@@ -49,7 +49,7 @@ workflows.
49
49
  - [Usage tracking](./docs/usage-tracking.mdx) is easy to set up, enabling usage
50
50
  attribution per-provider, per-model, per-user, per-agent, for billing & more.
51
51
  - [Rate limiting](./docs/rate-limiting.mdx), powered by the
52
- [Rate Limiting Component](https://www.convex.dev/components/rate-limiting),
52
+ [Rate Limiter Component](https://www.convex.dev/components/rate-limiter),
53
53
  helps control the rate at which users can interact with agents and keep you
54
54
  from exceeding your LLM provider's limits.
55
55
 
@@ -0,0 +1,620 @@
1
+ import { type GenericDataModel, type GenericQueryCtx, type ApiFromModules, type GenericActionCtx } from "convex/server";
2
+ import { type AgentComponent, type Agent, type ContextOptions } from "@convex-dev/agent";
3
+ import type { ToolSet } from "ai";
4
+ export type PlaygroundAPI = ApiFromModules<{
5
+ playground: ReturnType<typeof definePlaygroundAPI>;
6
+ }>["playground"];
7
+ export type AgentsFn<DataModel extends GenericDataModel> = (ctx: GenericActionCtx<DataModel> | GenericQueryCtx<DataModel>, args: {
8
+ userId: string | undefined;
9
+ threadId: string | undefined;
10
+ }) => Agent<ToolSet>[] | Promise<Agent<ToolSet>[]>;
11
+ export declare function definePlaygroundAPI<DataModel extends GenericDataModel>(component: AgentComponent, { agents: agentsOrFn, userNameLookup, }: {
12
+ agents: Agent<ToolSet>[] | AgentsFn<DataModel>;
13
+ userNameLookup?: (ctx: GenericQueryCtx<DataModel>, userId: string) => string | Promise<string>;
14
+ }): {
15
+ isApiKeyValid: import("convex/server").RegisteredQuery<"public", {
16
+ apiKey: string;
17
+ }, Promise<boolean>>;
18
+ listUsers: import("convex/server").RegisteredQuery<"public", {
19
+ apiKey: string;
20
+ paginationOpts: {
21
+ id?: number | undefined;
22
+ endCursor?: string | null | undefined;
23
+ maximumRowsRead?: number | undefined;
24
+ maximumBytesRead?: number | undefined;
25
+ numItems: number;
26
+ cursor: string | null;
27
+ };
28
+ }, Promise<{
29
+ page: {
30
+ _id: string;
31
+ name: string;
32
+ }[];
33
+ continueCursor: string;
34
+ isDone: boolean;
35
+ pageStatus?: "SplitRecommended" | "SplitRequired" | null | undefined;
36
+ splitCursor?: string | null | undefined;
37
+ }>>;
38
+ listThreads: import("convex/server").RegisteredQuery<"public", {
39
+ userId?: string | undefined;
40
+ apiKey: string;
41
+ paginationOpts: {
42
+ id?: number | undefined;
43
+ endCursor?: string | null | undefined;
44
+ maximumRowsRead?: number | undefined;
45
+ maximumBytesRead?: number | undefined;
46
+ numItems: number;
47
+ cursor: string | null;
48
+ };
49
+ }, Promise<{
50
+ page: {
51
+ lastAgentName: string | undefined;
52
+ latestMessage: string | undefined;
53
+ lastMessageAt: number;
54
+ _creationTime: number;
55
+ _id: string;
56
+ status: "active" | "archived";
57
+ summary?: string | undefined;
58
+ title?: string | undefined;
59
+ userId?: string | undefined;
60
+ }[];
61
+ continueCursor: string;
62
+ isDone: boolean;
63
+ pageStatus?: "SplitRecommended" | "SplitRequired" | null | undefined;
64
+ splitCursor?: string | null | undefined;
65
+ }>>;
66
+ listMessages: import("convex/server").RegisteredQuery<"public", {
67
+ threadId: string;
68
+ apiKey: string;
69
+ paginationOpts: {
70
+ id?: number | undefined;
71
+ endCursor?: string | null | undefined;
72
+ maximumRowsRead?: number | undefined;
73
+ maximumBytesRead?: number | undefined;
74
+ numItems: number;
75
+ cursor: string | null;
76
+ };
77
+ }, Promise<{
78
+ continueCursor: string;
79
+ isDone: boolean;
80
+ page: {
81
+ _creationTime: number;
82
+ _id: string;
83
+ agentName?: string | undefined;
84
+ embeddingId?: string | undefined;
85
+ error?: string | undefined;
86
+ fileIds?: string[] | undefined;
87
+ finishReason?: "stop" | "length" | "content-filter" | "tool-calls" | "error" | "other" | "unknown" | undefined;
88
+ id?: string | undefined;
89
+ message?: {
90
+ content: string | ({
91
+ providerOptions?: {
92
+ [x: string]: {
93
+ [x: string]: any;
94
+ };
95
+ } | undefined;
96
+ text: string;
97
+ type: "text";
98
+ } | {
99
+ image: string | ArrayBuffer;
100
+ mimeType?: string | undefined;
101
+ providerOptions?: {
102
+ [x: string]: {
103
+ [x: string]: any;
104
+ };
105
+ } | undefined;
106
+ type: "image";
107
+ } | {
108
+ data: string | ArrayBuffer;
109
+ filename?: string | undefined;
110
+ mimeType: string;
111
+ providerOptions?: {
112
+ [x: string]: {
113
+ [x: string]: any;
114
+ };
115
+ } | undefined;
116
+ type: "file";
117
+ })[];
118
+ providerOptions?: {
119
+ [x: string]: {
120
+ [x: string]: any;
121
+ };
122
+ } | undefined;
123
+ role: "user";
124
+ } | {
125
+ content: string | ({
126
+ providerOptions?: {
127
+ [x: string]: {
128
+ [x: string]: any;
129
+ };
130
+ } | undefined;
131
+ text: string;
132
+ type: "text";
133
+ } | {
134
+ data: string | ArrayBuffer;
135
+ filename?: string | undefined;
136
+ mimeType: string;
137
+ providerOptions?: {
138
+ [x: string]: {
139
+ [x: string]: any;
140
+ };
141
+ } | undefined;
142
+ type: "file";
143
+ } | {
144
+ providerOptions?: {
145
+ [x: string]: {
146
+ [x: string]: any;
147
+ };
148
+ } | undefined;
149
+ signature?: string | undefined;
150
+ text: string;
151
+ type: "reasoning";
152
+ } | {
153
+ data: string;
154
+ providerOptions?: {
155
+ [x: string]: {
156
+ [x: string]: any;
157
+ };
158
+ } | undefined;
159
+ type: "redacted-reasoning";
160
+ } | {
161
+ args: any;
162
+ providerOptions?: {
163
+ [x: string]: {
164
+ [x: string]: any;
165
+ };
166
+ } | undefined;
167
+ toolCallId: string;
168
+ toolName: string;
169
+ type: "tool-call";
170
+ })[];
171
+ providerOptions?: {
172
+ [x: string]: {
173
+ [x: string]: any;
174
+ };
175
+ } | undefined;
176
+ role: "assistant";
177
+ } | {
178
+ content: {
179
+ args?: any;
180
+ experimental_content?: ({
181
+ text: string;
182
+ type: "text";
183
+ } | {
184
+ data: string;
185
+ mimeType?: string | undefined;
186
+ type: "image";
187
+ })[] | undefined;
188
+ isError?: boolean | undefined;
189
+ providerOptions?: {
190
+ [x: string]: {
191
+ [x: string]: any;
192
+ };
193
+ } | undefined;
194
+ result: any;
195
+ toolCallId: string;
196
+ toolName: string;
197
+ type: "tool-result";
198
+ }[];
199
+ providerOptions?: {
200
+ [x: string]: {
201
+ [x: string]: any;
202
+ };
203
+ } | undefined;
204
+ role: "tool";
205
+ } | {
206
+ content: string;
207
+ providerOptions?: {
208
+ [x: string]: {
209
+ [x: string]: any;
210
+ };
211
+ } | undefined;
212
+ role: "system";
213
+ } | undefined;
214
+ model?: string | undefined;
215
+ order: number;
216
+ provider?: string | undefined;
217
+ providerMetadata?: {
218
+ [x: string]: {
219
+ [x: string]: any;
220
+ };
221
+ } | undefined;
222
+ providerOptions?: {
223
+ [x: string]: {
224
+ [x: string]: any;
225
+ };
226
+ } | undefined;
227
+ reasoning?: string | undefined;
228
+ reasoningDetails?: ({
229
+ signature?: string | undefined;
230
+ text: string;
231
+ type: "text";
232
+ } | {
233
+ data: string;
234
+ type: "redacted";
235
+ })[] | undefined;
236
+ sources?: {
237
+ id: string;
238
+ providerOptions?: {
239
+ [x: string]: {
240
+ [x: string]: any;
241
+ };
242
+ } | undefined;
243
+ sourceType: "url";
244
+ title?: string | undefined;
245
+ url: string;
246
+ }[] | undefined;
247
+ status: "pending" | "success" | "failed";
248
+ stepOrder: number;
249
+ text?: string | undefined;
250
+ threadId: string;
251
+ tool: boolean;
252
+ usage?: {
253
+ completionTokens: number;
254
+ promptTokens: number;
255
+ totalTokens: number;
256
+ } | undefined;
257
+ userId?: string | undefined;
258
+ warnings?: ({
259
+ details?: string | undefined;
260
+ setting: string;
261
+ type: "unsupported-setting";
262
+ } | {
263
+ details?: string | undefined;
264
+ tool: any;
265
+ type: "unsupported-tool";
266
+ } | {
267
+ message: string;
268
+ type: "other";
269
+ })[] | undefined;
270
+ }[];
271
+ pageStatus?: "SplitRecommended" | "SplitRequired" | null | undefined;
272
+ splitCursor?: string | null | undefined;
273
+ }>>;
274
+ listAgents: import("convex/server").RegisteredQuery<"public", {
275
+ userId?: string | undefined;
276
+ threadId?: string | undefined;
277
+ apiKey: string;
278
+ }, Promise<{
279
+ name: string;
280
+ instructions: string | undefined;
281
+ contextOptions: ContextOptions | undefined;
282
+ storageOptions: import("@convex-dev/agent").StorageOptions | undefined;
283
+ maxSteps: number | undefined;
284
+ maxRetries: number | undefined;
285
+ tools: string[];
286
+ }[]>>;
287
+ createThread: import("convex/server").RegisteredMutation<"public", {
288
+ title?: string | undefined;
289
+ summary?: string | undefined;
290
+ agentName?: string | undefined;
291
+ userId: string;
292
+ apiKey: string;
293
+ }, Promise<{
294
+ threadId: string;
295
+ }>>;
296
+ generateText: import("convex/server").RegisteredAction<"public", {
297
+ system?: string | undefined;
298
+ messages?: ({
299
+ providerOptions?: Record<string, Record<string, any>> | undefined;
300
+ role: "user";
301
+ content: string | ({
302
+ providerOptions?: Record<string, Record<string, any>> | undefined;
303
+ type: "text";
304
+ text: string;
305
+ } | {
306
+ providerOptions?: Record<string, Record<string, any>> | undefined;
307
+ mimeType?: string | undefined;
308
+ type: "image";
309
+ image: string | ArrayBuffer;
310
+ } | {
311
+ providerOptions?: Record<string, Record<string, any>> | undefined;
312
+ filename?: string | undefined;
313
+ type: "file";
314
+ mimeType: string;
315
+ data: string | ArrayBuffer;
316
+ })[];
317
+ } | {
318
+ providerOptions?: Record<string, Record<string, any>> | undefined;
319
+ role: "assistant";
320
+ content: string | ({
321
+ providerOptions?: Record<string, Record<string, any>> | undefined;
322
+ type: "text";
323
+ text: string;
324
+ } | {
325
+ providerOptions?: Record<string, Record<string, any>> | undefined;
326
+ filename?: string | undefined;
327
+ type: "file";
328
+ mimeType: string;
329
+ data: string | ArrayBuffer;
330
+ } | {
331
+ providerOptions?: Record<string, Record<string, any>> | undefined;
332
+ signature?: string | undefined;
333
+ type: "reasoning";
334
+ text: string;
335
+ } | {
336
+ providerOptions?: Record<string, Record<string, any>> | undefined;
337
+ type: "redacted-reasoning";
338
+ data: string;
339
+ } | {
340
+ providerOptions?: Record<string, Record<string, any>> | undefined;
341
+ type: "tool-call";
342
+ toolCallId: string;
343
+ toolName: string;
344
+ args: any;
345
+ })[];
346
+ } | {
347
+ providerOptions?: Record<string, Record<string, any>> | undefined;
348
+ role: "tool";
349
+ content: {
350
+ providerOptions?: Record<string, Record<string, any>> | undefined;
351
+ args?: any;
352
+ experimental_content?: ({
353
+ type: "text";
354
+ text: string;
355
+ } | {
356
+ mimeType?: string | undefined;
357
+ type: "image";
358
+ data: string;
359
+ })[] | undefined;
360
+ isError?: boolean | undefined;
361
+ type: "tool-result";
362
+ toolCallId: string;
363
+ toolName: string;
364
+ result: any;
365
+ }[];
366
+ } | {
367
+ providerOptions?: Record<string, Record<string, any>> | undefined;
368
+ role: "system";
369
+ content: string;
370
+ })[] | undefined;
371
+ prompt?: string | undefined;
372
+ contextOptions?: {
373
+ excludeToolMessages?: boolean | undefined;
374
+ recentMessages?: number | undefined;
375
+ searchOptions?: {
376
+ textSearch?: boolean | undefined;
377
+ vectorSearch?: boolean | undefined;
378
+ vectorScoreThreshold?: number | undefined;
379
+ messageRange?: {
380
+ before: number;
381
+ after: number;
382
+ } | undefined;
383
+ limit: number;
384
+ } | undefined;
385
+ searchOtherThreads?: boolean | undefined;
386
+ } | undefined;
387
+ storageOptions?: {
388
+ saveMessages?: "all" | "none" | "promptAndOutput" | undefined;
389
+ } | undefined;
390
+ userId: string;
391
+ threadId: string;
392
+ agentName: string;
393
+ apiKey: string;
394
+ }, Promise<{
395
+ messageId: string;
396
+ text: string;
397
+ }>>;
398
+ fetchPromptContext: import("convex/server").RegisteredAction<"public", {
399
+ userId?: string | undefined;
400
+ threadId?: string | undefined;
401
+ beforeMessageId?: string | undefined;
402
+ agentName: string;
403
+ messages: ({
404
+ providerOptions?: Record<string, Record<string, any>> | undefined;
405
+ role: "user";
406
+ content: string | ({
407
+ providerOptions?: Record<string, Record<string, any>> | undefined;
408
+ type: "text";
409
+ text: string;
410
+ } | {
411
+ providerOptions?: Record<string, Record<string, any>> | undefined;
412
+ mimeType?: string | undefined;
413
+ type: "image";
414
+ image: string | ArrayBuffer;
415
+ } | {
416
+ providerOptions?: Record<string, Record<string, any>> | undefined;
417
+ filename?: string | undefined;
418
+ type: "file";
419
+ mimeType: string;
420
+ data: string | ArrayBuffer;
421
+ })[];
422
+ } | {
423
+ providerOptions?: Record<string, Record<string, any>> | undefined;
424
+ role: "assistant";
425
+ content: string | ({
426
+ providerOptions?: Record<string, Record<string, any>> | undefined;
427
+ type: "text";
428
+ text: string;
429
+ } | {
430
+ providerOptions?: Record<string, Record<string, any>> | undefined;
431
+ filename?: string | undefined;
432
+ type: "file";
433
+ mimeType: string;
434
+ data: string | ArrayBuffer;
435
+ } | {
436
+ providerOptions?: Record<string, Record<string, any>> | undefined;
437
+ signature?: string | undefined;
438
+ type: "reasoning";
439
+ text: string;
440
+ } | {
441
+ providerOptions?: Record<string, Record<string, any>> | undefined;
442
+ type: "redacted-reasoning";
443
+ data: string;
444
+ } | {
445
+ providerOptions?: Record<string, Record<string, any>> | undefined;
446
+ type: "tool-call";
447
+ toolCallId: string;
448
+ toolName: string;
449
+ args: any;
450
+ })[];
451
+ } | {
452
+ providerOptions?: Record<string, Record<string, any>> | undefined;
453
+ role: "tool";
454
+ content: {
455
+ providerOptions?: Record<string, Record<string, any>> | undefined;
456
+ args?: any;
457
+ experimental_content?: ({
458
+ type: "text";
459
+ text: string;
460
+ } | {
461
+ mimeType?: string | undefined;
462
+ type: "image";
463
+ data: string;
464
+ })[] | undefined;
465
+ isError?: boolean | undefined;
466
+ type: "tool-result";
467
+ toolCallId: string;
468
+ toolName: string;
469
+ result: any;
470
+ }[];
471
+ } | {
472
+ providerOptions?: Record<string, Record<string, any>> | undefined;
473
+ role: "system";
474
+ content: string;
475
+ })[];
476
+ contextOptions: {
477
+ excludeToolMessages?: boolean | undefined;
478
+ recentMessages?: number | undefined;
479
+ searchOptions?: {
480
+ textSearch?: boolean | undefined;
481
+ vectorSearch?: boolean | undefined;
482
+ vectorScoreThreshold?: number | undefined;
483
+ messageRange?: {
484
+ before: number;
485
+ after: number;
486
+ } | undefined;
487
+ limit: number;
488
+ } | undefined;
489
+ searchOtherThreads?: boolean | undefined;
490
+ };
491
+ apiKey: string;
492
+ }, Promise<{
493
+ id?: string | undefined;
494
+ userId?: string | undefined;
495
+ embeddingId?: string | undefined;
496
+ fileIds?: string[] | undefined;
497
+ error?: string | undefined;
498
+ agentName?: string | undefined;
499
+ model?: string | undefined;
500
+ provider?: string | undefined;
501
+ providerOptions?: Record<string, Record<string, any>> | undefined;
502
+ message?: {
503
+ providerOptions?: Record<string, Record<string, any>> | undefined;
504
+ role: "user";
505
+ content: string | ({
506
+ providerOptions?: Record<string, Record<string, any>> | undefined;
507
+ type: "text";
508
+ text: string;
509
+ } | {
510
+ providerOptions?: Record<string, Record<string, any>> | undefined;
511
+ mimeType?: string | undefined;
512
+ type: "image";
513
+ image: string | ArrayBuffer;
514
+ } | {
515
+ providerOptions?: Record<string, Record<string, any>> | undefined;
516
+ filename?: string | undefined;
517
+ type: "file";
518
+ mimeType: string;
519
+ data: string | ArrayBuffer;
520
+ })[];
521
+ } | {
522
+ providerOptions?: Record<string, Record<string, any>> | undefined;
523
+ role: "assistant";
524
+ content: string | ({
525
+ providerOptions?: Record<string, Record<string, any>> | undefined;
526
+ type: "text";
527
+ text: string;
528
+ } | {
529
+ providerOptions?: Record<string, Record<string, any>> | undefined;
530
+ filename?: string | undefined;
531
+ type: "file";
532
+ mimeType: string;
533
+ data: string | ArrayBuffer;
534
+ } | {
535
+ providerOptions?: Record<string, Record<string, any>> | undefined;
536
+ signature?: string | undefined;
537
+ type: "reasoning";
538
+ text: string;
539
+ } | {
540
+ providerOptions?: Record<string, Record<string, any>> | undefined;
541
+ type: "redacted-reasoning";
542
+ data: string;
543
+ } | {
544
+ providerOptions?: Record<string, Record<string, any>> | undefined;
545
+ type: "tool-call";
546
+ toolCallId: string;
547
+ toolName: string;
548
+ args: any;
549
+ })[];
550
+ } | {
551
+ providerOptions?: Record<string, Record<string, any>> | undefined;
552
+ role: "tool";
553
+ content: {
554
+ providerOptions?: Record<string, Record<string, any>> | undefined;
555
+ args?: any;
556
+ experimental_content?: ({
557
+ type: "text";
558
+ text: string;
559
+ } | {
560
+ mimeType?: string | undefined;
561
+ type: "image";
562
+ data: string;
563
+ })[] | undefined;
564
+ isError?: boolean | undefined;
565
+ type: "tool-result";
566
+ toolCallId: string;
567
+ toolName: string;
568
+ result: any;
569
+ }[];
570
+ } | {
571
+ providerOptions?: Record<string, Record<string, any>> | undefined;
572
+ role: "system";
573
+ content: string;
574
+ } | undefined;
575
+ text?: string | undefined;
576
+ reasoning?: string | undefined;
577
+ usage?: {
578
+ promptTokens: number;
579
+ completionTokens: number;
580
+ totalTokens: number;
581
+ } | undefined;
582
+ providerMetadata?: Record<string, Record<string, any>> | undefined;
583
+ sources?: {
584
+ title?: string | undefined;
585
+ providerOptions?: Record<string, Record<string, any>> | undefined;
586
+ id: string;
587
+ sourceType: "url";
588
+ url: string;
589
+ }[] | undefined;
590
+ reasoningDetails?: ({
591
+ signature?: string | undefined;
592
+ type: "text";
593
+ text: string;
594
+ } | {
595
+ type: "redacted";
596
+ data: string;
597
+ })[] | undefined;
598
+ warnings?: ({
599
+ details?: string | undefined;
600
+ type: "unsupported-setting";
601
+ setting: string;
602
+ } | {
603
+ details?: string | undefined;
604
+ type: "unsupported-tool";
605
+ tool: any;
606
+ } | {
607
+ type: "other";
608
+ message: string;
609
+ })[] | undefined;
610
+ finishReason?: "length" | "error" | "other" | "stop" | "content-filter" | "tool-calls" | "unknown" | undefined;
611
+ _id: string;
612
+ _creationTime: number;
613
+ status: "pending" | "success" | "failed";
614
+ order: number;
615
+ threadId: string;
616
+ stepOrder: number;
617
+ tool: boolean;
618
+ }[]>>;
619
+ };
620
+ //# sourceMappingURL=definePlaygroundAPI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definePlaygroundAPI.d.ts","sourceRoot":"","sources":["../../src/client/definePlaygroundAPI.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAGlC,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC;IACzC,UAAU,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;CACpD,CAAC,CAAC,YAAY,CAAC,CAAC;AAEjB,MAAM,MAAM,QAAQ,CAAC,SAAS,SAAS,gBAAgB,IAAI,CACzD,GAAG,EAAE,gBAAgB,CAAC,SAAS,CAAC,GAAG,eAAe,CAAC,SAAS,CAAC,EAC7D,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,KAC/D,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAGlD,wBAAgB,mBAAmB,CAAC,SAAS,SAAS,gBAAgB,EACpE,SAAS,EAAE,cAAc,EACzB,EACE,MAAM,EAAE,UAAU,EAClB,cAAc,GACf,EAAE;IACD,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,CACf,GAAG,EAAE,eAAe,CAAC,SAAS,CAAC,EAC/B,MAAM,EAAE,MAAM,KACX,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiSF"}