@applica-software-guru/persona-sdk 0.1.106 → 0.1.108

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.
@@ -7,7 +7,7 @@ export type LanguageCode = 'en-US' | 'it-IT' | 'es-ES' | 'fr-FR' | 'de-DE' | 'pt
7
7
 
8
8
  export type SynthesizerName = 'gcloud' | 'elevenlabs' | 'gtts' | 'openai';
9
9
 
10
- export type TranscriberName = 'gcloud' | 'deepgram' | 'vosk';
10
+ export type TranscriberName = 'gcloud' | 'deepgram' | 'elevenlabs' | 'vosk';
11
11
 
12
12
 
13
13
  export type ToolType = 'remote' | 'local';
@@ -93,13 +93,34 @@ export interface SynthesizerConfiguration {
93
93
  stability?: number;
94
94
  style?: number;
95
95
  voiceInstructions?: string;
96
+ /**
97
+ * Solo ElevenLabs, 0-4. Valori alti riducono la latenza ma dal 4 il
98
+ * normalizzatore del testo viene disattivato e numeri e date vengono
99
+ * pronunciati male.
100
+ */
101
+ optimizeStreamingLatency?: number;
96
102
  }
97
103
 
104
+ export type CommitStrategy = 'vad' | 'manual';
105
+
98
106
  export interface TranscriberConfiguration {
99
107
  enabled?: boolean;
100
108
  transcriberName?: TranscriberName;
101
109
  languageCode?: LanguageCode;
102
110
  sampleRateHertz?: number;
111
+ /**
112
+ * Secondi di silenzio dopo i quali il turno dell'utente è considerato
113
+ * concluso: è il parametro con più impatto sulla latenza percepita, perché
114
+ * l'agente non inizia a elaborare prima che scada. Valori bassi rendono la
115
+ * conversazione reattiva ma spezzano le pause di pensiero in due turni.
116
+ */
117
+ silenceDurationThreshold?: number;
118
+ /** Solo ElevenLabs Scribe. */
119
+ modelId?: string;
120
+ commitStrategy?: CommitStrategy;
121
+ keyterms?: string[];
122
+ secondaryLanguages?: string[];
123
+ filterBackgroundAudio?: boolean;
103
124
  }
104
125
 
105
126
  export interface KnowledgeConfiguration {
@@ -149,6 +170,69 @@ export interface WakeupConfiguration {
149
170
  sleepDelaySeconds?: number;
150
171
  }
151
172
 
173
+ export type ThinkingFillerMode = 'sound' | 'words';
174
+
175
+ /**
176
+ * Riempitivo emesso quando l'agente è occupato e muto.
177
+ *
178
+ * Copre due momenti che per l'utente sono lo stesso silenzio: la chiamata di uno
179
+ * strumento e la fase di ragionamento del modello. Non scatta se l'agente ha già
180
+ * detto qualcosa prima di occuparsi.
181
+ */
182
+ export interface ThinkingFillerConfiguration {
183
+ enabled?: boolean;
184
+ /** `sound` è il tono breve, `words` una frase parlata scelta a caso. */
185
+ mode?: ThinkingFillerMode;
186
+ words?: string[];
187
+ /** Attesa prima di emettere: le attese rapide non producono niente. */
188
+ delaySeconds?: number;
189
+ /** Distanza minima tra due riempitivi, condivisa col backchannel. */
190
+ throttleSeconds?: number;
191
+ /**
192
+ * Se emettere il riempitivo anche mentre il modello ragiona. Disattivo per
193
+ * default: con modelli che ragionano a ogni turno può diventare invadente.
194
+ */
195
+ onReasoning?: boolean;
196
+ }
197
+
198
+ export type BackchannelMode = 'static' | 'llm';
199
+
200
+ /**
201
+ * Riempitivi vocali emessi mentre l'utente sta ancora parlando.
202
+ *
203
+ * Due modalità con compromessi diversi:
204
+ * - `static`: una parola scelta a caso dalla lista. Le clip sono
205
+ * pre-sintetizzate e in cache, quindi la latenza aggiunta è zero.
206
+ * - `llm`: un modello veloce genera la frase seguendo `instructions`. Più
207
+ * pertinente, ma la prima volta che produce un testo nuovo si paga LLM più
208
+ * TTS; se non è pronto in tempo si ripiega su una parola della lista.
209
+ *
210
+ * Richiede un synthesizer con sintesi one-shot (gcloud o elevenlabs).
211
+ */
212
+ export interface BackchannelConfiguration {
213
+ enabled?: boolean;
214
+ mode?: BackchannelMode;
215
+ /** Lista per `static`, e fallback per `llm` quando il modello tarda. */
216
+ words?: string[];
217
+ /** Solo `llm`: cosa deve generare il modello. */
218
+ instructions?: string;
219
+ /** Tetto sulle parole generate, per non parlare sopra l'utente. */
220
+ maxGeneratedWords?: number;
221
+ /** Parlato continuo richiesto prima di intervenire. */
222
+ minSpeechSeconds?: number;
223
+ maxPerUserTurn?: number;
224
+ partialFreshnessSeconds?: number;
225
+ agentSilenceSeconds?: number;
226
+ throttleSeconds?: number;
227
+ /**
228
+ * Modello usato dalla modalità `llm`. Va scelto piccolo e veloce: sta nel
229
+ * percorso critico di un riempitivo che deve arrivare entro un secondo.
230
+ */
231
+ model?: ModelConfiguration;
232
+ llmTimeoutSeconds?: number;
233
+ prewarm?: boolean;
234
+ }
235
+
152
236
  export interface TelegramConfiguration {
153
237
  enabled?: boolean;
154
238
  botToken?: string;
@@ -286,6 +370,8 @@ export interface Agent {
286
370
  initialMessageMode?: "processed" | "static";
287
371
  knowledge?: KnowledgeConfiguration;
288
372
  wakeup?: WakeupConfiguration;
373
+ backchannel?: BackchannelConfiguration;
374
+ thinkingFiller?: ThinkingFillerConfiguration;
289
375
  telegram?: TelegramConfiguration;
290
376
  whatsapp?: WhatsAppConfiguration;
291
377
  collaboration?: CollaborationConfiguration;
@@ -317,6 +403,8 @@ export interface AgentCreateRequest {
317
403
  initialMessageMode?: "processed" | "static";
318
404
  knowledge?: KnowledgeConfiguration;
319
405
  wakeup?: WakeupConfiguration;
406
+ backchannel?: BackchannelConfiguration;
407
+ thinkingFiller?: ThinkingFillerConfiguration;
320
408
  telegram?: TelegramConfiguration;
321
409
  whatsapp?: WhatsAppConfiguration;
322
410
  collaboration?: CollaborationConfiguration;
package/src/index.ts CHANGED
@@ -39,6 +39,11 @@ export type {
39
39
  Variable,
40
40
  VariableSource,
41
41
  WakeupConfiguration,
42
+ BackchannelConfiguration,
43
+ BackchannelMode,
44
+ ThinkingFillerConfiguration,
45
+ ThinkingFillerMode,
46
+ CommitStrategy,
42
47
  WhatsAppConfiguration,
43
48
  Tool,
44
49
  ToolType,
@@ -151,7 +156,16 @@ export type {
151
156
  export { MissionsApi } from './missions/missions-api';
152
157
  export type { Mission, MissionStatus } from './missions/types';
153
158
  export { ServicePricesApi } from './service-prices/service-prices-api';
154
- export type { ServicePrice } from './service-prices/types';
159
+ export type {
160
+ ServicePrice,
161
+ ServicePriceListParams,
162
+ ServicePricePricingStatus,
163
+ ServicePriceSort,
164
+ ServicePriceSortField,
165
+ ServicePriceStats,
166
+ ServicePriceStatsParams,
167
+ ServicePriceUnit,
168
+ } from './service-prices/types';
155
169
  export { MarkupRulesApi } from './markup-rules/markup-rules-api';
156
170
  export type { MarkupRule } from './markup-rules/types';
157
171
  export { ProvidersApi } from './providers/providers-api';
@@ -1,20 +1,29 @@
1
1
  import { HttpApi } from '../http-api';
2
2
  import { Paginated } from '../paginated';
3
3
  import { AuthenticationProvider } from '../auth/authentication-provider';
4
- import { ServicePrice } from './types';
4
+ import { ServicePrice, ServicePriceListParams, ServicePriceStats, ServicePriceStatsParams } from './types';
5
5
 
6
6
  export class ServicePricesApi extends HttpApi {
7
7
  constructor(baseUrl: string, auth: string | AuthenticationProvider) {
8
8
  super(baseUrl, auth);
9
9
  }
10
10
 
11
- async list(keyword?: string | null, page?: number, size?: number, extraParams?: Record<string, string>): Promise<Paginated<ServicePrice>> {
11
+ async list(
12
+ keyword?: string | null,
13
+ page?: number,
14
+ size?: number,
15
+ extraParams?: ServicePriceListParams
16
+ ): Promise<Paginated<ServicePrice>> {
12
17
  const { page: p, size: s } = this.normalizePageParams(page, size);
13
18
  const params: Record<string, unknown> = { page: p, size: s, ...extraParams };
14
19
  if (keyword) params.keyword = keyword;
15
20
  return this.httpGet<Paginated<ServicePrice>>('/service-prices', params);
16
21
  }
17
22
 
23
+ async getStats(params: ServicePriceStatsParams = {}): Promise<ServicePriceStats> {
24
+ return this.httpGet<ServicePriceStats>('/service-prices/stats', { ...params });
25
+ }
26
+
18
27
  async get(id: string): Promise<ServicePrice> {
19
28
  return this.httpGet<ServicePrice>('/service-prices/' + id);
20
29
  }
@@ -5,3 +5,27 @@ export interface ServicePrice {
5
5
  unit?: string;
6
6
  fixedPrice?: number;
7
7
  }
8
+
9
+ export type ServicePriceUnit = 'seconds' | 'tokens' | 'characters' | 'pages' | 'calls';
10
+ export type ServicePricePricingStatus = 'priced' | 'unpriced' | 'withFixedPrice';
11
+ export type ServicePriceSortField = 'service' | 'cost' | 'unit' | 'fixedPrice';
12
+ export type ServicePriceSort = `${ServicePriceSortField},${'asc' | 'desc'}`;
13
+
14
+ export interface ServicePriceListParams {
15
+ sort?: ServicePriceSort;
16
+ unit?: ServicePriceUnit;
17
+ pricingStatus?: ServicePricePricingStatus;
18
+ [key: string]: string | undefined;
19
+ }
20
+
21
+ export interface ServicePriceStatsParams {
22
+ keyword?: string | null;
23
+ unit?: ServicePriceUnit;
24
+ }
25
+
26
+ export interface ServicePriceStats {
27
+ total: number;
28
+ priced: number;
29
+ unpriced: number;
30
+ withFixedPrice: number;
31
+ }
@@ -0,0 +1,69 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { ServicePricesApi } from '../dist/bundle.es.js';
5
+
6
+ function jsonResponse(body) {
7
+ return new Response(JSON.stringify(body), {
8
+ status: 200,
9
+ headers: { 'Content-Type': 'application/json' },
10
+ });
11
+ }
12
+
13
+ test('service price list forwards typed sort and filters', async (context) => {
14
+ const originalFetch = globalThis.fetch;
15
+ context.after(() => {
16
+ globalThis.fetch = originalFetch;
17
+ });
18
+
19
+ let requestUrl;
20
+ globalThis.fetch = async (url) => {
21
+ requestUrl = new URL(url);
22
+ return jsonResponse({ items: [], total: 0, page: 2, size: 10 });
23
+ };
24
+
25
+ const api = new ServicePricesApi('https://example.test', 'api-key');
26
+ await api.list('openai', 2, 10, {
27
+ sort: 'cost,desc',
28
+ unit: 'tokens',
29
+ pricingStatus: 'unpriced',
30
+ });
31
+
32
+ assert.equal(requestUrl.pathname, '/service-prices');
33
+ assert.deepEqual(Object.fromEntries(requestUrl.searchParams), {
34
+ page: '2',
35
+ size: '10',
36
+ sort: 'cost,desc',
37
+ unit: 'tokens',
38
+ pricingStatus: 'unpriced',
39
+ keyword: 'openai',
40
+ });
41
+ });
42
+
43
+ test('service price stats forwards its filters and returns KPI values', async (context) => {
44
+ const originalFetch = globalThis.fetch;
45
+ context.after(() => {
46
+ globalThis.fetch = originalFetch;
47
+ });
48
+
49
+ let requestUrl;
50
+ globalThis.fetch = async (url) => {
51
+ requestUrl = new URL(url);
52
+ return jsonResponse({ total: 10, priced: 7, unpriced: 3, withFixedPrice: 2 });
53
+ };
54
+
55
+ const api = new ServicePricesApi('https://example.test', 'api-key');
56
+ const stats = await api.getStats({ keyword: 'model', unit: 'tokens' });
57
+
58
+ assert.equal(requestUrl.pathname, '/service-prices/stats');
59
+ assert.deepEqual(Object.fromEntries(requestUrl.searchParams), {
60
+ keyword: 'model',
61
+ unit: 'tokens',
62
+ });
63
+ assert.deepEqual(stats, {
64
+ total: 10,
65
+ priced: 7,
66
+ unpriced: 3,
67
+ withFixedPrice: 2,
68
+ });
69
+ });