@absolutejs/voice 0.0.22-beta.668 → 0.0.22-beta.669

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.
@@ -36,6 +36,10 @@ export type VoiceAgentToolResult<TResult = unknown> = {
36
36
  toolCallId?: string;
37
37
  toolName: string;
38
38
  };
39
+ export type VoiceAgentToolPolicyDecision = {
40
+ allowed: boolean;
41
+ reason?: string;
42
+ };
39
43
  export type VoiceAgentTool<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TArgs = Record<string, unknown>, TToolResult = unknown, TRouteResult = unknown> = {
40
44
  description?: string;
41
45
  execute: (input: {
@@ -47,6 +51,22 @@ export type VoiceAgentTool<TContext = unknown, TSession extends VoiceSessionReco
47
51
  }) => Promise<TToolResult> | TToolResult;
48
52
  name: string;
49
53
  parameters?: Record<string, unknown>;
54
+ /** Authorize a model-requested side effect before `execute` runs. Unlike
55
+ * post-turn guardrails, this policy sees the assistant text produced in the
56
+ * same model round and can prevent an unsafe tool from mutating call state.
57
+ * A blocked terminal tool still ends the conversational turn so the already
58
+ * streamed reply is not followed by a second model response. */
59
+ policy?: (input: {
60
+ api: VoiceSessionHandle<TContext, TSession, TRouteResult>;
61
+ args: TArgs;
62
+ assistantText?: string;
63
+ context: TContext;
64
+ messages: ReadonlyArray<VoiceAgentMessage>;
65
+ round: number;
66
+ session: TSession;
67
+ toolCall: VoiceAgentToolCall<TArgs>;
68
+ turn: VoiceTurnRecord;
69
+ }) => Promise<VoiceAgentToolPolicyDecision> | VoiceAgentToolPolicyDecision;
50
70
  resultToMessage?: (result: TToolResult) => string;
51
71
  /** End the turn after this tool runs — do NOT loop back to the model for
52
72
  * another generation. Use for tools that wrap up the call (an app-defined
package/dist/index.d.ts CHANGED
@@ -257,7 +257,7 @@ export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncid
257
257
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds, } from "./core/qualityRoutes";
258
258
  export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions, } from "./core/resilienceRoutes";
259
259
  export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions, } from "./core/providerAdapters";
260
- export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadContextPolicyResult, VoiceAgentSquadHandoffPolicyResult, VoiceAgentSquadHandoffStatus, VoiceAgentSquadOptions, VoiceAgentSquadState, VoiceAgentSquadStateHandoff, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolResult, } from "./core/agent";
260
+ export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadContextPolicyResult, VoiceAgentSquadHandoffPolicyResult, VoiceAgentSquadHandoffStatus, VoiceAgentSquadOptions, VoiceAgentSquadState, VoiceAgentSquadStateHandoff, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolPolicyDecision, VoiceAgentToolResult, } from "./core/agent";
261
261
  export type { VoiceAgentSquadContractAssertionInput, VoiceAgentSquadContractAssertionReport, VoiceAgentSquadContractDefinition, VoiceAgentSquadContractIssue, VoiceAgentSquadContractOutcome, VoiceAgentSquadContractReport, VoiceAgentSquadContractRunOptions, VoiceAgentSquadContractTurn, VoiceAgentSquadContractTurnReport, VoiceAgentSquadHandoffExpectation, VoiceAgentSquadTurnExpectation, } from "./core/agentSquadContract";
262
262
  export type { VoiceToolRetryDelay, VoiceToolRuntime, VoiceToolRuntimeExecuteInput, VoiceToolRuntimeOptions, VoiceToolRuntimeResult, } from "./core/toolRuntime";
263
263
  export type { VoiceToolContractAssertionInput, VoiceToolContractAssertionReport, VoiceToolContractCase, VoiceToolContractCaseReport, VoiceToolContractDefinition, VoiceToolContractExpectation, VoiceToolContractHandlerOptions, VoiceToolContractHTMLHandlerOptions, VoiceToolContractIssue, VoiceToolContractReport, VoiceToolContractRoutesOptions, VoiceToolContractSuiteReport, } from "./core/toolContract";
package/dist/index.js CHANGED
@@ -8546,6 +8546,63 @@ var createVoiceAgent = (options) => {
8546
8546
  });
8547
8547
  continue;
8548
8548
  }
8549
+ const policyDecision = await tool.policy?.({
8550
+ api: input.api,
8551
+ args: toolCall.args,
8552
+ assistantText: output.assistantText,
8553
+ context: input.context,
8554
+ messages,
8555
+ round,
8556
+ session: input.session,
8557
+ toolCall,
8558
+ turn: input.turn
8559
+ });
8560
+ if (policyDecision && !policyDecision.allowed) {
8561
+ const error = policyDecision.reason ?? `Voice agent tool policy blocked ${tool.name}.`;
8562
+ const blockedResult = {
8563
+ error,
8564
+ status: "error",
8565
+ toolCallId: toolCall.id,
8566
+ toolName: tool.name
8567
+ };
8568
+ toolResults.push(blockedResult);
8569
+ await appendVoiceAgentTrace({
8570
+ agentId: options.id,
8571
+ event: {
8572
+ error,
8573
+ policyBlocked: true,
8574
+ status: "error",
8575
+ toolCallId: toolCall.id,
8576
+ toolName: tool.name
8577
+ },
8578
+ session: input.session,
8579
+ trace: options.trace,
8580
+ turn: input.turn,
8581
+ type: "agent.tool"
8582
+ });
8583
+ await audit?.toolCall({
8584
+ actor: {
8585
+ id: options.id,
8586
+ kind: "agent"
8587
+ },
8588
+ error,
8589
+ metadata: { policyBlocked: true },
8590
+ outcome: "error",
8591
+ sessionId: input.session.id,
8592
+ toolCallId: toolCall.id,
8593
+ toolName: tool.name
8594
+ });
8595
+ messages.push({
8596
+ content: error,
8597
+ name: tool.name,
8598
+ role: "tool",
8599
+ toolCallId: toolCall.id
8600
+ });
8601
+ if (tool.endsTurn) {
8602
+ endTurnAfterDispatch = true;
8603
+ }
8604
+ continue;
8605
+ }
8549
8606
  try {
8550
8607
  const toolStartedAt = Date.now();
8551
8608
  const runtimeResult = options.toolRuntime ? await options.toolRuntime.execute({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.668",
3
+ "version": "0.0.22-beta.669",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",