@absolutejs/voice 0.0.22-beta.2 → 0.0.22-beta.3

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.
@@ -1,6 +1,7 @@
1
1
  import { type VoiceAgent, type VoiceAgentModel, type VoiceAgentOptions, type VoiceAgentSquadOptions, type VoiceAgentTool } from './agent';
2
2
  import { type VoiceOutcomeRecipeName, type VoiceOutcomeRecipeOptions } from './outcomeRecipes';
3
3
  import type { VoiceNormalizedRouteConfig, VoiceOnTurnObjectHandler, VoiceRouteConfig, VoiceRouteResult, VoiceRuntimeOpsConfig, VoiceSessionRecord } from './types';
4
+ import type { StoredVoiceTraceEvent, VoiceTraceEventStore } from './trace';
4
5
  export type VoiceAssistantPreset = VoiceOutcomeRecipeName;
5
6
  export type VoiceAssistantArtifactPlan<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
6
7
  ops?: VoiceRuntimeOpsConfig<TContext, TSession, TResult>;
@@ -94,6 +95,29 @@ export type VoiceAssistant<TContext = unknown, TSession extends VoiceSessionReco
94
95
  onComplete?: VoiceRouteConfig<TContext, TSession, TResult>['onComplete'];
95
96
  }) => VoiceNormalizedRouteConfig<TContext, TSession, TResult>;
96
97
  };
98
+ export type VoiceAssistantRunSummary = {
99
+ assistantId: string;
100
+ artifactPlans: Record<string, number>;
101
+ averageElapsedMs?: number;
102
+ blockedGuardrailCount: number;
103
+ escalationCount: number;
104
+ experiments: Record<string, number>;
105
+ guardrailCount: number;
106
+ outcomes: Record<string, number>;
107
+ runCount: number;
108
+ sessions: number;
109
+ toolCalls: Record<string, number>;
110
+ transferCount: number;
111
+ variants: Record<string, number>;
112
+ };
113
+ export type VoiceAssistantRunsSummary = {
114
+ assistants: VoiceAssistantRunSummary[];
115
+ totalRuns: number;
116
+ };
97
117
  export declare const createVoiceExperiment: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: VoiceAssistantExperimentOptions<TContext, TSession, TResult>) => VoiceAssistantExperiment<TContext, TSession, TResult>;
98
118
  export declare const createVoiceAssistant: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: VoiceAssistantOptions<TContext, TSession, TResult>) => VoiceAssistant<TContext, TSession, TResult>;
119
+ export declare const summarizeVoiceAssistantRuns: (input: StoredVoiceTraceEvent[] | {
120
+ events?: StoredVoiceTraceEvent[];
121
+ store?: VoiceTraceEventStore;
122
+ }) => Promise<VoiceAssistantRunsSummary>;
99
123
  export {};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { voice } from './plugin';
2
- export { createVoiceAssistant, createVoiceExperiment } from './assistant';
2
+ export { createVoiceAssistant, createVoiceExperiment, summarizeVoiceAssistantRuns } from './assistant';
3
3
  export { createVoiceAgent, createVoiceAgentSquad, createVoiceAgentTool } from './agent';
4
4
  export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
5
5
  export { buildVoiceTraceReplay, createVoiceMemoryTraceSinkDeliveryStore, createVoiceTraceHTTPSink, createVoiceMemoryTraceEventStore, createVoiceTraceSinkDeliveryId, createVoiceTraceSinkDeliveryRecord, createVoiceTraceSinkStore, createVoiceTraceEvent, createVoiceTraceEventId, deliverVoiceTraceEventsToSinks, evaluateVoiceTrace, exportVoiceTrace, filterVoiceTraceEvents, pruneVoiceTraceEvents, redactVoiceTraceEvent, redactVoiceTraceEvents, redactVoiceTraceText, renderVoiceTraceHTML, renderVoiceTraceMarkdown, resolveVoiceTraceRedactionOptions, selectVoiceTraceEventsForPrune, summarizeVoiceTrace } from './trace';
@@ -22,7 +22,7 @@ export { conditionAudioChunk, resolveAudioConditioningConfig } from './audioCond
22
22
  export { resolveVoiceRuntimePreset } from './presets';
23
23
  export { resolveTurnDetectionConfig, TURN_PROFILE_DEFAULTS } from './turnProfiles';
24
24
  export { createVoiceCallReviewFromLiveTelephonyReport, createVoiceCallReviewRecorder, renderVoiceCallReviewHTML, renderVoiceCallReviewMarkdown } from './testing/review';
25
- export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperiment, VoiceAssistantExperimentOptions, VoiceAssistantGuardrailInput, VoiceAssistantGuardrails, VoiceAssistantOptions, VoiceAssistantOutputGuardrailInput, VoiceAssistantPreset, VoiceAssistantVariant } from './assistant';
25
+ export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperiment, VoiceAssistantExperimentOptions, VoiceAssistantGuardrailInput, VoiceAssistantGuardrails, VoiceAssistantOptions, VoiceAssistantOutputGuardrailInput, VoiceAssistantPreset, VoiceAssistantRunsSummary, VoiceAssistantRunSummary, VoiceAssistantVariant } from './assistant';
26
26
  export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadOptions, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolResult } from './agent';
27
27
  export type { VoiceOpsRuntime, VoiceOpsRuntimeConfig, VoiceOpsRuntimeSummary, VoiceOpsRuntimeSinkWorkerConfig, VoiceOpsRuntimeTaskWorkerConfig, VoiceOpsRuntimeTickResult, VoiceOpsRuntimeWebhookWorkerConfig } from './opsRuntime';
28
28
  export type { VoiceOpsPresetName, VoiceOpsPresetOverrides, VoiceResolvedOpsPreset } from './opsPresets';
package/dist/index.js CHANGED
@@ -5603,6 +5603,47 @@ var hashString = (value) => {
5603
5603
  }
5604
5604
  return hash >>> 0;
5605
5605
  };
5606
+ var increment = (record, key) => {
5607
+ record[key] = (record[key] ?? 0) + 1;
5608
+ };
5609
+ var resolveOutcome = (result) => {
5610
+ if (result.transfer) {
5611
+ return "transferred";
5612
+ }
5613
+ if (result.escalate) {
5614
+ return "escalated";
5615
+ }
5616
+ if (result.voicemail) {
5617
+ return "voicemail";
5618
+ }
5619
+ if (result.noAnswer) {
5620
+ return "no-answer";
5621
+ }
5622
+ if (result.complete) {
5623
+ return "completed";
5624
+ }
5625
+ return "continued";
5626
+ };
5627
+ var resolveArtifactPlanName = (artifactPlan) => {
5628
+ const preset = artifactPlan?.preset;
5629
+ if (!preset) {
5630
+ return artifactPlan?.ops ? "custom" : undefined;
5631
+ }
5632
+ return typeof preset === "string" ? preset : preset.name;
5633
+ };
5634
+ var appendAssistantTrace = async (input) => {
5635
+ await input.trace?.append({
5636
+ at: Date.now(),
5637
+ payload: {
5638
+ assistantId: input.assistantId,
5639
+ ...input.event
5640
+ },
5641
+ scenarioId: input.session.scenarioId,
5642
+ sessionId: input.session.id,
5643
+ turnId: input.turnId,
5644
+ type: input.type
5645
+ });
5646
+ };
5606
5647
  var resolvePresetOps = (artifactPlan) => {
5607
5648
  const preset = artifactPlan?.preset;
5608
5649
  if (!preset) {
@@ -5671,6 +5712,7 @@ var createVoiceExperiment = (options) => {
5671
5712
  };
5672
5713
  var createVoiceAssistant = (options) => {
5673
5714
  const ops = mergeOps(resolvePresetOps(options.artifactPlan), options.ops);
5715
+ const artifactPlanName = resolveArtifactPlanName(options.artifactPlan);
5674
5716
  let agent;
5675
5717
  const baseModelOptions = "model" in options && options.model ? {
5676
5718
  maxToolRounds: options.maxToolRounds,
@@ -5706,8 +5748,34 @@ var createVoiceAssistant = (options) => {
5706
5748
  };
5707
5749
  const blocked = await options.guardrails?.beforeTurn?.(guardrailInput);
5708
5750
  if (blocked) {
5751
+ await appendAssistantTrace({
5752
+ assistantId: options.id,
5753
+ event: {
5754
+ action: "blocked",
5755
+ artifactPlan: artifactPlanName,
5756
+ outcome: resolveOutcome(blocked)
5757
+ },
5758
+ session: input.session,
5759
+ trace: options.trace,
5760
+ turnId: input.turn.id,
5761
+ type: "assistant.guardrail"
5762
+ });
5763
+ await appendAssistantTrace({
5764
+ assistantId: options.id,
5765
+ event: {
5766
+ artifactPlan: artifactPlanName,
5767
+ blocked: true,
5768
+ experimentId: options.experiment?.id,
5769
+ outcome: resolveOutcome(blocked)
5770
+ },
5771
+ session: input.session,
5772
+ trace: options.trace,
5773
+ turnId: input.turn.id,
5774
+ type: "assistant.run"
5775
+ });
5709
5776
  return blocked;
5710
5777
  }
5778
+ const startedAt = Date.now();
5711
5779
  const variant = options.experiment?.resolve({
5712
5780
  assistantId: options.id,
5713
5781
  context: input.context,
@@ -5722,12 +5790,48 @@ var createVoiceAssistant = (options) => {
5722
5790
  trace: options.trace,
5723
5791
  tools: variant.tools ?? baseModelOptions.tools
5724
5792
  }) : agent;
5725
- const result = await runner.run(input) ?? {};
5793
+ const runResult = await runner.run(input) ?? {};
5794
+ const result = runResult;
5726
5795
  const guarded = await options.guardrails?.afterTurn?.({
5727
5796
  ...guardrailInput,
5728
5797
  result
5729
5798
  });
5730
- return guarded ?? result;
5799
+ const finalResult = guarded ?? result;
5800
+ if (guarded) {
5801
+ await appendAssistantTrace({
5802
+ assistantId: options.id,
5803
+ event: {
5804
+ action: "rewritten",
5805
+ artifactPlan: artifactPlanName,
5806
+ experimentId: options.experiment?.id,
5807
+ outcome: resolveOutcome(finalResult),
5808
+ variantId: variant?.id
5809
+ },
5810
+ session: input.session,
5811
+ trace: options.trace,
5812
+ turnId: input.turn.id,
5813
+ type: "assistant.guardrail"
5814
+ });
5815
+ }
5816
+ await appendAssistantTrace({
5817
+ assistantId: options.id,
5818
+ event: {
5819
+ artifactPlan: artifactPlanName,
5820
+ blocked: false,
5821
+ elapsedMs: Date.now() - startedAt,
5822
+ escalated: Boolean(finalResult.escalate),
5823
+ experimentId: options.experiment?.id,
5824
+ outcome: resolveOutcome(finalResult),
5825
+ toolNames: result.toolResults?.map((tool) => tool.toolName) ?? [],
5826
+ transferred: Boolean(finalResult.transfer),
5827
+ variantId: variant?.id
5828
+ },
5829
+ session: input.session,
5830
+ trace: options.trace,
5831
+ turnId: input.turn.id,
5832
+ type: "assistant.run"
5833
+ });
5834
+ return finalResult;
5731
5835
  };
5732
5836
  return {
5733
5837
  agent,
@@ -5743,6 +5847,88 @@ var createVoiceAssistant = (options) => {
5743
5847
  })
5744
5848
  };
5745
5849
  };
5850
+ var summarizeVoiceAssistantRuns = async (input) => {
5851
+ const events = Array.isArray(input) ? input : input.events ?? await input.store?.list() ?? [];
5852
+ const assistantRuns = events.filter((event) => event.type === "assistant.run");
5853
+ const guardrails = events.filter((event) => event.type === "assistant.guardrail");
5854
+ const byAssistant = new Map;
5855
+ const getSummary = (assistantId) => {
5856
+ let summary = byAssistant.get(assistantId);
5857
+ if (!summary) {
5858
+ summary = {
5859
+ assistantId,
5860
+ artifactPlans: {},
5861
+ blockedGuardrailCount: 0,
5862
+ elapsedCount: 0,
5863
+ elapsedTotal: 0,
5864
+ escalationCount: 0,
5865
+ experiments: {},
5866
+ guardrailCount: 0,
5867
+ outcomes: {},
5868
+ runCount: 0,
5869
+ sessionIds: new Set,
5870
+ sessions: 0,
5871
+ toolCalls: {},
5872
+ transferCount: 0,
5873
+ variants: {}
5874
+ };
5875
+ byAssistant.set(assistantId, summary);
5876
+ }
5877
+ return summary;
5878
+ };
5879
+ for (const event of assistantRuns) {
5880
+ const assistantId = typeof event.payload.assistantId === "string" ? event.payload.assistantId : "unknown";
5881
+ const summary = getSummary(assistantId);
5882
+ summary.runCount += 1;
5883
+ summary.sessionIds.add(event.sessionId);
5884
+ if (typeof event.payload.artifactPlan === "string") {
5885
+ increment(summary.artifactPlans, event.payload.artifactPlan);
5886
+ }
5887
+ if (typeof event.payload.experimentId === "string") {
5888
+ increment(summary.experiments, event.payload.experimentId);
5889
+ }
5890
+ if (typeof event.payload.variantId === "string") {
5891
+ increment(summary.variants, event.payload.variantId);
5892
+ }
5893
+ if (typeof event.payload.outcome === "string") {
5894
+ increment(summary.outcomes, event.payload.outcome);
5895
+ }
5896
+ if (event.payload.escalated === true) {
5897
+ summary.escalationCount += 1;
5898
+ }
5899
+ if (event.payload.transferred === true) {
5900
+ summary.transferCount += 1;
5901
+ }
5902
+ if (event.payload.blocked === true) {
5903
+ summary.blockedGuardrailCount += 1;
5904
+ }
5905
+ if (typeof event.payload.elapsedMs === "number") {
5906
+ summary.elapsedCount += 1;
5907
+ summary.elapsedTotal += event.payload.elapsedMs;
5908
+ }
5909
+ if (Array.isArray(event.payload.toolNames)) {
5910
+ for (const toolName of event.payload.toolNames) {
5911
+ if (typeof toolName === "string") {
5912
+ increment(summary.toolCalls, toolName);
5913
+ }
5914
+ }
5915
+ }
5916
+ }
5917
+ for (const event of guardrails) {
5918
+ const assistantId = typeof event.payload.assistantId === "string" ? event.payload.assistantId : "unknown";
5919
+ const summary = getSummary(assistantId);
5920
+ summary.guardrailCount += 1;
5921
+ }
5922
+ const assistants = [...byAssistant.values()].map(({ elapsedCount, elapsedTotal, sessionIds, ...summary }) => ({
5923
+ ...summary,
5924
+ averageElapsedMs: elapsedCount > 0 ? Math.round(elapsedTotal / elapsedCount) : undefined,
5925
+ sessions: sessionIds.size
5926
+ }));
5927
+ return {
5928
+ assistants: assistants.sort((left, right) => left.assistantId.localeCompare(right.assistantId)),
5929
+ totalRuns: assistantRuns.length
5930
+ };
5931
+ };
5746
5932
  // src/fileStore.ts
5747
5933
  import { mkdir, readFile, readdir, rename, rm, writeFile } from "fs/promises";
5748
5934
  import { join } from "path";
@@ -9141,6 +9327,7 @@ export {
9141
9327
  summarizeVoiceOpsTaskQueue,
9142
9328
  summarizeVoiceOpsTaskAnalytics,
9143
9329
  summarizeVoiceIntegrationEvents,
9330
+ summarizeVoiceAssistantRuns,
9144
9331
  startVoiceOpsTask,
9145
9332
  shapeTelephonyAssistantText,
9146
9333
  selectVoiceTraceEventsForPrune,
package/dist/trace.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type VoiceTraceEventType = 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.lifecycle' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript';
1
+ export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.lifecycle' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript';
2
2
  export type VoiceTraceEvent<TPayload extends Record<string, unknown> = Record<string, unknown>> = {
3
3
  at: number;
4
4
  id?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.2",
3
+ "version": "0.0.22-beta.3",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",