@absolutejs/voice 0.0.22-beta.518 → 0.0.22-beta.519

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/dist/index.js CHANGED
@@ -3769,7 +3769,8 @@ var setTurnResult = (session, turnId, input) => {
3769
3769
  session.turns = session.turns.map((turn) => turn.id === turnId ? {
3770
3770
  ...turn,
3771
3771
  assistantText: input.assistantText ?? turn.assistantText,
3772
- result: input.result ?? turn.result
3772
+ result: input.result ?? turn.result,
3773
+ citations: input.citations && input.citations.length > 0 ? [...input.citations] : turn.citations
3773
3774
  } : turn);
3774
3775
  };
3775
3776
  var ensureCallLifecycleState = (session) => {
@@ -5157,6 +5158,7 @@ var createVoiceSession = (options) => {
5157
5158
  });
5158
5159
  const output = {
5159
5160
  assistantText: committedOutput?.assistantText,
5161
+ citations: committedOutput?.citations,
5160
5162
  complete: committedOutput?.complete,
5161
5163
  escalate: committedOutput?.escalate,
5162
5164
  noAnswer: committedOutput?.noAnswer,
@@ -5164,6 +5166,12 @@ var createVoiceSession = (options) => {
5164
5166
  transfer: committedOutput?.transfer,
5165
5167
  voicemail: committedOutput?.voicemail
5166
5168
  };
5169
+ if (output.citations && output.citations.length > 0) {
5170
+ const turnCitations = output.citations;
5171
+ await writeSession((currentSession) => {
5172
+ setTurnResult(currentSession, turn.id, { citations: turnCitations });
5173
+ });
5174
+ }
5167
5175
  if (output?.assistantText) {
5168
5176
  const assistantTextStartedAt = Date.now();
5169
5177
  await writeSession((currentSession) => {
@@ -8733,6 +8741,159 @@ var assertVoiceCampaignDialerProofEvidence = (report, input = {}) => {
8733
8741
  }
8734
8742
  return assertion;
8735
8743
  };
8744
+ // src/ragTool.ts
8745
+ var extractVoiceRAGCitations = (toolResults, toolName = "searchKnowledgeBase") => {
8746
+ const out = [];
8747
+ for (const entry of toolResults) {
8748
+ if (entry.toolName !== toolName) {
8749
+ continue;
8750
+ }
8751
+ const result = entry.result;
8752
+ const citations = result?.citations;
8753
+ if (!Array.isArray(citations)) {
8754
+ continue;
8755
+ }
8756
+ for (const citation of citations) {
8757
+ out.push({
8758
+ chunkId: citation.chunkId,
8759
+ score: citation.score,
8760
+ source: citation.source,
8761
+ title: citation.title
8762
+ });
8763
+ }
8764
+ }
8765
+ return out;
8766
+ };
8767
+ var DEFAULT_TOOL_NAME = "searchKnowledgeBase";
8768
+ var DEFAULT_DESCRIPTION = "Search the knowledge base and return short grounded citations. Use this whenever the caller asks a question that may be answered by indexed reference material.";
8769
+ var DEFAULT_TOP_K = 6;
8770
+ var DEFAULT_MAX_TOP_K = 20;
8771
+ var DEFAULT_MAX_CHUNK_CHARS = 320;
8772
+ var truncate = (value, limit) => {
8773
+ if (limit <= 0 || value.length <= limit)
8774
+ return value;
8775
+ return `${value.slice(0, Math.max(0, limit - 1)).trimEnd()}\u2026`;
8776
+ };
8777
+ var formatScore = (score) => {
8778
+ if (!Number.isFinite(score))
8779
+ return "n/a";
8780
+ return score.toFixed(3);
8781
+ };
8782
+ var buildDefaultCitationMessage = (citations, args, maxChunkChars) => {
8783
+ if (citations.length === 0) {
8784
+ return `No knowledge base results for "${args.query}".`;
8785
+ }
8786
+ const lines = citations.map((citation, index) => {
8787
+ const label = citation.title ?? citation.source ?? citation.chunkId;
8788
+ const text = truncate(citation.chunkText, maxChunkChars);
8789
+ return `${String(index + 1)}. ${label} (score ${formatScore(citation.score)}): ${text}`;
8790
+ });
8791
+ return [
8792
+ `Knowledge base results for "${args.query}":`,
8793
+ ...lines
8794
+ ].join(`
8795
+ `);
8796
+ };
8797
+ var filterAllowedFilterKeys = (filter, allowedKeys) => {
8798
+ if (!filter)
8799
+ return;
8800
+ if (!allowedKeys)
8801
+ return filter;
8802
+ const allowed = new Set(allowedKeys);
8803
+ const entries = Object.entries(filter).filter(([key]) => allowed.has(key));
8804
+ if (entries.length === 0)
8805
+ return;
8806
+ return Object.fromEntries(entries);
8807
+ };
8808
+ var mergeFilters = (...filters) => {
8809
+ const present = filters.filter((entry) => entry !== undefined);
8810
+ if (present.length === 0)
8811
+ return;
8812
+ return Object.assign({}, ...present);
8813
+ };
8814
+ var buildVoiceRAGToolParameters = (options) => {
8815
+ if (options.parameters)
8816
+ return options.parameters;
8817
+ const defaultTopK = options.topK ?? DEFAULT_TOP_K;
8818
+ const maxTopK = options.maxTopK ?? DEFAULT_MAX_TOP_K;
8819
+ const properties = {
8820
+ query: {
8821
+ description: "Natural-language question to look up in the knowledge base.",
8822
+ type: "string"
8823
+ },
8824
+ topK: {
8825
+ default: defaultTopK,
8826
+ description: `How many citations to return (1-${String(maxTopK)}).`,
8827
+ maximum: maxTopK,
8828
+ minimum: 1,
8829
+ type: "integer"
8830
+ }
8831
+ };
8832
+ if (options.allowedFilterKeys && options.allowedFilterKeys.length > 0) {
8833
+ properties.filter = {
8834
+ additionalProperties: false,
8835
+ description: "Optional metadata filter. Only keys listed here are honored: " + options.allowedFilterKeys.join(", "),
8836
+ properties: Object.fromEntries(options.allowedFilterKeys.map((key) => [key, {}])),
8837
+ type: "object"
8838
+ };
8839
+ }
8840
+ return {
8841
+ additionalProperties: false,
8842
+ properties,
8843
+ required: ["query"],
8844
+ type: "object"
8845
+ };
8846
+ };
8847
+ var createVoiceRAGTool = (collection, options = {}) => {
8848
+ const name = options.name ?? DEFAULT_TOOL_NAME;
8849
+ const description = options.description ?? DEFAULT_DESCRIPTION;
8850
+ const defaultTopK = options.topK ?? DEFAULT_TOP_K;
8851
+ const maxTopK = options.maxTopK ?? DEFAULT_MAX_TOP_K;
8852
+ const maxChunkChars = options.maxChunkChars ?? DEFAULT_MAX_CHUNK_CHARS;
8853
+ const parameters = buildVoiceRAGToolParameters(options);
8854
+ return createVoiceAgentTool({
8855
+ description,
8856
+ execute: async ({ args, context }) => {
8857
+ const query = typeof args?.query === "string" ? args.query.trim() : "";
8858
+ if (query.length === 0) {
8859
+ const empty = {
8860
+ citations: [],
8861
+ message: "Knowledge base search requires a non-empty query.",
8862
+ query: "",
8863
+ topK: 0
8864
+ };
8865
+ return empty;
8866
+ }
8867
+ const requestedTopK = typeof args?.topK === "number" && Number.isFinite(args.topK) ? Math.min(maxTopK, Math.max(1, Math.floor(args.topK))) : defaultTopK;
8868
+ const llmFilter = filterAllowedFilterKeys(args?.filter, options.allowedFilterKeys);
8869
+ const fixedFilter = typeof options.fixedFilter === "function" ? options.fixedFilter({ context }) : options.fixedFilter;
8870
+ const filter = mergeFilters(fixedFilter, llmFilter);
8871
+ const rawResults = await collection.search({
8872
+ filter,
8873
+ query,
8874
+ scoreThreshold: options.scoreThreshold,
8875
+ topK: requestedTopK
8876
+ });
8877
+ const citations = Array.from(rawResults).slice(0, requestedTopK);
8878
+ const formatter = options.formatResult ? options.formatResult : (entries, innerArgs) => buildDefaultCitationMessage(entries, innerArgs, maxChunkChars);
8879
+ const message = formatter(citations, {
8880
+ filter,
8881
+ query,
8882
+ topK: requestedTopK
8883
+ });
8884
+ return {
8885
+ citations,
8886
+ message,
8887
+ query,
8888
+ topK: requestedTopK
8889
+ };
8890
+ },
8891
+ name,
8892
+ parameters,
8893
+ resultToMessage: options.resultToMessage ?? ((result) => result.message)
8894
+ });
8895
+ };
8896
+
8736
8897
  // src/agent.ts
8737
8898
  var normalizeText3 = (value) => typeof value === "string" ? value.trim() : "";
8738
8899
  var toErrorMessage3 = (error) => error instanceof Error ? error.message : String(error);
@@ -9106,9 +9267,11 @@ var createVoiceAgent = (options) => {
9106
9267
  turn: input.turn,
9107
9268
  type: "agent.result"
9108
9269
  });
9270
+ const citations = extractVoiceRAGCitations(toolResults);
9109
9271
  return {
9110
9272
  agentId: options.id,
9111
9273
  assistantText: output.assistantText,
9274
+ ...citations.length > 0 ? { citations } : {},
9112
9275
  complete: output.complete,
9113
9276
  escalate: output.escalate,
9114
9277
  handoff: output.handoff,
@@ -36341,158 +36504,6 @@ var createMonologueAMDDetector = (options = {}) => {
36341
36504
  intervalMs: options.intervalMs ?? 1000
36342
36505
  };
36343
36506
  };
36344
- // src/ragTool.ts
36345
- var extractVoiceRAGCitations = (toolResults, toolName = "searchKnowledgeBase") => {
36346
- const out = [];
36347
- for (const entry of toolResults) {
36348
- if (entry.toolName !== toolName) {
36349
- continue;
36350
- }
36351
- const result = entry.result;
36352
- const citations = result?.citations;
36353
- if (!Array.isArray(citations)) {
36354
- continue;
36355
- }
36356
- for (const citation of citations) {
36357
- out.push({
36358
- chunkId: citation.chunkId,
36359
- score: citation.score,
36360
- source: citation.source,
36361
- title: citation.title
36362
- });
36363
- }
36364
- }
36365
- return out;
36366
- };
36367
- var DEFAULT_TOOL_NAME = "searchKnowledgeBase";
36368
- var DEFAULT_DESCRIPTION = "Search the knowledge base and return short grounded citations. Use this whenever the caller asks a question that may be answered by indexed reference material.";
36369
- var DEFAULT_TOP_K = 6;
36370
- var DEFAULT_MAX_TOP_K = 20;
36371
- var DEFAULT_MAX_CHUNK_CHARS = 320;
36372
- var truncate = (value, limit) => {
36373
- if (limit <= 0 || value.length <= limit)
36374
- return value;
36375
- return `${value.slice(0, Math.max(0, limit - 1)).trimEnd()}\u2026`;
36376
- };
36377
- var formatScore = (score) => {
36378
- if (!Number.isFinite(score))
36379
- return "n/a";
36380
- return score.toFixed(3);
36381
- };
36382
- var buildDefaultCitationMessage = (citations, args, maxChunkChars) => {
36383
- if (citations.length === 0) {
36384
- return `No knowledge base results for "${args.query}".`;
36385
- }
36386
- const lines = citations.map((citation, index) => {
36387
- const label = citation.title ?? citation.source ?? citation.chunkId;
36388
- const text = truncate(citation.chunkText, maxChunkChars);
36389
- return `${String(index + 1)}. ${label} (score ${formatScore(citation.score)}): ${text}`;
36390
- });
36391
- return [
36392
- `Knowledge base results for "${args.query}":`,
36393
- ...lines
36394
- ].join(`
36395
- `);
36396
- };
36397
- var filterAllowedFilterKeys = (filter, allowedKeys) => {
36398
- if (!filter)
36399
- return;
36400
- if (!allowedKeys)
36401
- return filter;
36402
- const allowed = new Set(allowedKeys);
36403
- const entries = Object.entries(filter).filter(([key]) => allowed.has(key));
36404
- if (entries.length === 0)
36405
- return;
36406
- return Object.fromEntries(entries);
36407
- };
36408
- var mergeFilters = (...filters) => {
36409
- const present = filters.filter((entry) => entry !== undefined);
36410
- if (present.length === 0)
36411
- return;
36412
- return Object.assign({}, ...present);
36413
- };
36414
- var buildVoiceRAGToolParameters = (options) => {
36415
- if (options.parameters)
36416
- return options.parameters;
36417
- const defaultTopK = options.topK ?? DEFAULT_TOP_K;
36418
- const maxTopK = options.maxTopK ?? DEFAULT_MAX_TOP_K;
36419
- const properties = {
36420
- query: {
36421
- description: "Natural-language question to look up in the knowledge base.",
36422
- type: "string"
36423
- },
36424
- topK: {
36425
- default: defaultTopK,
36426
- description: `How many citations to return (1-${String(maxTopK)}).`,
36427
- maximum: maxTopK,
36428
- minimum: 1,
36429
- type: "integer"
36430
- }
36431
- };
36432
- if (options.allowedFilterKeys && options.allowedFilterKeys.length > 0) {
36433
- properties.filter = {
36434
- additionalProperties: false,
36435
- description: "Optional metadata filter. Only keys listed here are honored: " + options.allowedFilterKeys.join(", "),
36436
- properties: Object.fromEntries(options.allowedFilterKeys.map((key) => [key, {}])),
36437
- type: "object"
36438
- };
36439
- }
36440
- return {
36441
- additionalProperties: false,
36442
- properties,
36443
- required: ["query"],
36444
- type: "object"
36445
- };
36446
- };
36447
- var createVoiceRAGTool = (collection, options = {}) => {
36448
- const name = options.name ?? DEFAULT_TOOL_NAME;
36449
- const description = options.description ?? DEFAULT_DESCRIPTION;
36450
- const defaultTopK = options.topK ?? DEFAULT_TOP_K;
36451
- const maxTopK = options.maxTopK ?? DEFAULT_MAX_TOP_K;
36452
- const maxChunkChars = options.maxChunkChars ?? DEFAULT_MAX_CHUNK_CHARS;
36453
- const parameters = buildVoiceRAGToolParameters(options);
36454
- return createVoiceAgentTool({
36455
- description,
36456
- execute: async ({ args, context }) => {
36457
- const query = typeof args?.query === "string" ? args.query.trim() : "";
36458
- if (query.length === 0) {
36459
- const empty = {
36460
- citations: [],
36461
- message: "Knowledge base search requires a non-empty query.",
36462
- query: "",
36463
- topK: 0
36464
- };
36465
- return empty;
36466
- }
36467
- const requestedTopK = typeof args?.topK === "number" && Number.isFinite(args.topK) ? Math.min(maxTopK, Math.max(1, Math.floor(args.topK))) : defaultTopK;
36468
- const llmFilter = filterAllowedFilterKeys(args?.filter, options.allowedFilterKeys);
36469
- const fixedFilter = typeof options.fixedFilter === "function" ? options.fixedFilter({ context }) : options.fixedFilter;
36470
- const filter = mergeFilters(fixedFilter, llmFilter);
36471
- const rawResults = await collection.search({
36472
- filter,
36473
- query,
36474
- scoreThreshold: options.scoreThreshold,
36475
- topK: requestedTopK
36476
- });
36477
- const citations = Array.from(rawResults).slice(0, requestedTopK);
36478
- const formatter = options.formatResult ? options.formatResult : (entries, innerArgs) => buildDefaultCitationMessage(entries, innerArgs, maxChunkChars);
36479
- const message = formatter(citations, {
36480
- filter,
36481
- query,
36482
- topK: requestedTopK
36483
- });
36484
- return {
36485
- citations,
36486
- message,
36487
- query,
36488
- topK: requestedTopK
36489
- };
36490
- },
36491
- name,
36492
- parameters,
36493
- resultToMessage: options.resultToMessage ?? ((result) => result.message)
36494
- });
36495
- };
36496
36507
  // src/agentTools.ts
36497
36508
  var createVoiceEndCallTool = (options = {}) => createVoiceAgentTool({
36498
36509
  description: options.description ?? "End the call gracefully. Call this only when the conversation is complete or the caller asks to hang up.",
package/dist/ragTool.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type VoiceAgentTool } from "./agent";
2
- import type { VoiceSessionRecord } from "./types";
2
+ import type { VoiceSessionRecord, VoiceTurnCitation } from "./types";
3
3
  export type VoiceRAGQueryResult = {
4
4
  chunkId: string;
5
5
  chunkText: string;
@@ -29,12 +29,7 @@ export type VoiceRAGToolResult = {
29
29
  query: string;
30
30
  topK: number;
31
31
  };
32
- export type VoiceRAGCitationSummary = {
33
- chunkId: string;
34
- score: number;
35
- source?: string;
36
- title?: string;
37
- };
32
+ export type VoiceRAGCitationSummary = VoiceTurnCitation;
38
33
  export declare const extractVoiceRAGCitations: (toolResults: ReadonlyArray<{
39
34
  result?: unknown;
40
35
  toolName: string;
@@ -5628,7 +5628,8 @@ var setTurnResult = (session, turnId, input) => {
5628
5628
  session.turns = session.turns.map((turn) => turn.id === turnId ? {
5629
5629
  ...turn,
5630
5630
  assistantText: input.assistantText ?? turn.assistantText,
5631
- result: input.result ?? turn.result
5631
+ result: input.result ?? turn.result,
5632
+ citations: input.citations && input.citations.length > 0 ? [...input.citations] : turn.citations
5632
5633
  } : turn);
5633
5634
  };
5634
5635
  var ensureCallLifecycleState = (session) => {
@@ -7016,6 +7017,7 @@ var createVoiceSession = (options) => {
7016
7017
  });
7017
7018
  const output = {
7018
7019
  assistantText: committedOutput?.assistantText,
7020
+ citations: committedOutput?.citations,
7019
7021
  complete: committedOutput?.complete,
7020
7022
  escalate: committedOutput?.escalate,
7021
7023
  noAnswer: committedOutput?.noAnswer,
@@ -7023,6 +7025,12 @@ var createVoiceSession = (options) => {
7023
7025
  transfer: committedOutput?.transfer,
7024
7026
  voicemail: committedOutput?.voicemail
7025
7027
  };
7028
+ if (output.citations && output.citations.length > 0) {
7029
+ const turnCitations = output.citations;
7030
+ await writeSession((currentSession) => {
7031
+ setTurnResult(currentSession, turn.id, { citations: turnCitations });
7032
+ });
7033
+ }
7026
7034
  if (output?.assistantText) {
7027
7035
  const assistantTextStartedAt = Date.now();
7028
7036
  await writeSession((currentSession) => {
package/dist/types.d.ts CHANGED
@@ -247,6 +247,12 @@ export type VoiceReconnectClientState = {
247
247
  nextAttemptAt?: number;
248
248
  status: VoiceReconnectClientStatus;
249
249
  };
250
+ export type VoiceTurnCitation = {
251
+ chunkId: string;
252
+ score: number;
253
+ source?: string;
254
+ title?: string;
255
+ };
250
256
  export type VoiceTurnRecord<TResult = unknown> = {
251
257
  id: string;
252
258
  text: string;
@@ -254,6 +260,7 @@ export type VoiceTurnRecord<TResult = unknown> = {
254
260
  transcripts: Transcript[];
255
261
  assistantText?: string;
256
262
  attachments?: import("./agent").VoiceAgentMessageAttachment[];
263
+ citations?: VoiceTurnCitation[];
257
264
  committedAt: number;
258
265
  result?: TResult;
259
266
  };
@@ -502,6 +509,7 @@ export type VoiceRouteResult<TResult = unknown> = {
502
509
  complete?: boolean;
503
510
  result?: TResult;
504
511
  assistantText?: string;
512
+ citations?: ReadonlyArray<VoiceTurnCitation>;
505
513
  transfer?: {
506
514
  metadata?: Record<string, unknown>;
507
515
  reason?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.518",
3
+ "version": "0.0.22-beta.519",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",