@voicelayer/sdk 0.1.8 → 0.1.9

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
@@ -3133,7 +3133,7 @@ var init_executors = __esm({
3133
3133
  const authoredSlot = slot === node.id ? "" : slot.trim();
3134
3134
  const label = authoredSlot.replace(/[_-]+/g, " ");
3135
3135
  if (hasSlot(deps.processRt.getData(), slot)) {
3136
- console.log("[graph] ask: slot already known, skipping", { slot: slot.trim() });
3136
+ deps.events.note("ask.skipped", { slot: slot.trim(), reason: "already known" });
3137
3137
  return { kind: "advance" };
3138
3138
  }
3139
3139
  const askText = interpolate(
@@ -3147,10 +3147,10 @@ var init_executors = __esm({
3147
3147
  state.lastUtterance = t.text;
3148
3148
  state.lastDtmf = t.dtmf;
3149
3149
  if (hasSlot(deps.processRt.getData(), slot)) {
3150
- console.log("[graph] ask: captured", { slot: slot.trim() });
3150
+ deps.events.note("ask.captured", { slot: slot.trim() });
3151
3151
  return { kind: "advance" };
3152
3152
  }
3153
- console.log("[graph] ask: clarify", { slot: slot.trim(), turn });
3153
+ deps.events.note("ask.clarify", { slot: slot.trim(), turn });
3154
3154
  await withHistory(
3155
3155
  deps,
3156
3156
  historyPolicyOf(node),
@@ -3252,10 +3252,16 @@ ${collected}`);
3252
3252
  for (const [slot, path] of Object.entries(cfg.outputAs)) {
3253
3253
  if (typeof path !== "string" || !path.trim()) continue;
3254
3254
  const value = resolvePath(result, path.trim());
3255
- if (value !== void 0 && value !== null) {
3256
- deps.processRt.captureField(slot, value);
3257
- deps.events.note("tool.output_captured", { node: node.id, slot });
3255
+ if (value === void 0 || value === null) {
3256
+ deps.events.note("tool.output_missing", { node: node.id, slot, path });
3257
+ continue;
3258
3258
  }
3259
+ const captured = deps.processRt.captureField(slot, value);
3260
+ deps.events.note(captured ? "tool.output_captured" : "tool.output_rejected", {
3261
+ node: node.id,
3262
+ slot,
3263
+ ...captured ? {} : { reason: "slot not declared or value not coercible" }
3264
+ });
3259
3265
  }
3260
3266
  }
3261
3267
  return routeByPort(node, deps, ok ? "ok" : "fail");
@@ -3764,13 +3770,19 @@ ${collected}`);
3764
3770
  setExecutor = async (node, state, deps) => {
3765
3771
  const assignments = Array.isArray(node.config.assignments) ? node.config.assignments : [];
3766
3772
  let applied = 0;
3773
+ const rejected = [];
3767
3774
  for (const a of assignments) {
3768
3775
  if (!a || typeof a.name !== "string" || !a.name.trim()) continue;
3776
+ const name = a.name.trim();
3769
3777
  const value = interpolate(typeof a.value === "string" ? a.value : "", scopeFor(state, deps));
3770
- deps.processRt.captureField(a.name.trim(), value);
3771
- applied += 1;
3778
+ if (deps.processRt.captureField(name, value)) applied += 1;
3779
+ else rejected.push(name);
3772
3780
  }
3773
- deps.events.note("set.applied", { node: node.id, count: applied });
3781
+ deps.events.note("set.applied", {
3782
+ node: node.id,
3783
+ count: applied,
3784
+ ...rejected.length ? { rejected } : {}
3785
+ });
3774
3786
  return { kind: "advance" };
3775
3787
  };
3776
3788
  MAX_SUBFLOW_DEPTH = 3;
@@ -7365,6 +7377,125 @@ function createTextSessionAdapter(transport) {
7365
7377
  return { adapter, push, setState, close };
7366
7378
  }
7367
7379
 
7380
+ // src/flow-runtime.ts
7381
+ init_define_tool();
7382
+ function processSchemaToDefinition(schema) {
7383
+ const required = new Set(schema.completionGate.requiredFields);
7384
+ const collect = {};
7385
+ for (const f of schema.fields) {
7386
+ collect[f.name] = {
7387
+ type: f.type,
7388
+ required: required.has(f.name) || f.required,
7389
+ ...f.ask !== void 0 ? { ask: f.ask } : {},
7390
+ ...f.pattern !== void 0 ? { pattern: new RegExp(f.pattern) } : {},
7391
+ ...f.min !== void 0 ? { min: f.min } : {},
7392
+ ...f.max !== void 0 ? { max: f.max } : {},
7393
+ ...f.enum !== void 0 ? { enum: f.enum } : {}
7394
+ };
7395
+ }
7396
+ return {
7397
+ collect,
7398
+ completeWhen: "all-required-captured",
7399
+ ...schema.completionGate.backendAck !== void 0 ? { backendAck: schema.completionGate.backendAck } : {}
7400
+ };
7401
+ }
7402
+ var DEFAULT_FLOW_PROMPT = "You are a helpful voice assistant. Keep replies short and natural.";
7403
+ function toTriggerCondition(on) {
7404
+ return on.startsWith("signal:") ? on : new RegExp(on, "i");
7405
+ }
7406
+ function toTriggerAction(then, graphNodeIds) {
7407
+ if (then === "endCall" || then === "end") return "endCall";
7408
+ if (then === "handoff") return "handoff";
7409
+ if (then.startsWith("say:")) return { say: then.slice(4).trim() };
7410
+ if (graphNodeIds?.has(then)) return { goto: then };
7411
+ return "handoff";
7412
+ }
7413
+ function processSchemaToAgentParts(schema, opts = {}) {
7414
+ const process2 = processSchemaToDefinition(schema);
7415
+ const promptParts = [];
7416
+ if (opts.basePrompt && opts.basePrompt.trim()) promptParts.push(opts.basePrompt.trim());
7417
+ for (const p of schema.prompts ?? []) {
7418
+ if (p.text.trim()) promptParts.push(p.text.trim());
7419
+ }
7420
+ const prompt = promptParts.length > 0 ? promptParts.join("\n\n") : DEFAULT_FLOW_PROMPT;
7421
+ let triggers;
7422
+ if (schema.triggers && schema.triggers.length > 0) {
7423
+ triggers = {};
7424
+ for (const t of schema.triggers) {
7425
+ triggers[t.name] = {
7426
+ on: toTriggerCondition(t.on),
7427
+ then: toTriggerAction(t.then, opts.graphNodeIds),
7428
+ ...t.onlyWhile ? { onlyWhile: t.onlyWhile } : {}
7429
+ };
7430
+ }
7431
+ }
7432
+ const handoff = schema.handoff?.fallback ? {
7433
+ fallback: schema.handoff.fallback,
7434
+ ...schema.handoff.routes ? { routes: schema.handoff.routes } : {}
7435
+ } : void 0;
7436
+ const memory = schema.memory ? {
7437
+ ...schema.memory.scope ? { scope: schema.memory.scope } : {},
7438
+ ...schema.memory.retentionDays !== void 0 ? { retentionDays: schema.memory.retentionDays } : {},
7439
+ ...schema.memory.piiFields ? { piiFields: schema.memory.piiFields } : {}
7440
+ } : void 0;
7441
+ let tools;
7442
+ if (schema.tools && schema.tools.length > 0) {
7443
+ tools = {};
7444
+ for (const t of schema.tools) {
7445
+ if (t.auth === "connection") {
7446
+ tools[t.name] = {
7447
+ description: t.description,
7448
+ input: t.input,
7449
+ run: () => ({
7450
+ kind: "unavailable",
7451
+ reason: "connection-auth tools need the vault resolver (not wired yet)"
7452
+ })
7453
+ };
7454
+ continue;
7455
+ }
7456
+ Object.assign(
7457
+ tools,
7458
+ httpTool({
7459
+ name: t.name,
7460
+ description: t.description,
7461
+ input: t.input,
7462
+ url: t.url,
7463
+ method: t.method,
7464
+ ...t.headers ? { headers: t.headers } : {}
7465
+ })
7466
+ );
7467
+ }
7468
+ }
7469
+ let speech;
7470
+ if (schema.speech) {
7471
+ const i = schema.speech.interruption;
7472
+ const e = schema.speech.endpointing;
7473
+ const interruption = i ? {
7474
+ ...i.enabled !== void 0 ? { enabled: i.enabled } : {},
7475
+ ...i.minWords !== void 0 ? { minWords: i.minWords } : {},
7476
+ ...i.minDuration !== void 0 ? { minDuration: i.minDuration } : {}
7477
+ } : void 0;
7478
+ const endpointing = e ? {
7479
+ ...e.minDelay !== void 0 ? { minDelay: e.minDelay } : {},
7480
+ ...e.maxDelay !== void 0 ? { maxDelay: e.maxDelay } : {}
7481
+ } : void 0;
7482
+ speech = {
7483
+ ...interruption && Object.keys(interruption).length ? { interruption } : {},
7484
+ ...endpointing && Object.keys(endpointing).length ? { endpointing } : {}
7485
+ };
7486
+ if (Object.keys(speech).length === 0) speech = void 0;
7487
+ }
7488
+ return {
7489
+ prompt,
7490
+ process: process2,
7491
+ ...triggers ? { triggers } : {},
7492
+ ...handoff ? { handoff } : {},
7493
+ ...memory ? { memory } : {},
7494
+ ...tools ? { tools } : {},
7495
+ ...speech ? { speech } : {}
7496
+ };
7497
+ }
7498
+
7368
7499
  // src/runtime/text-session.ts
7369
7500
  function buildTextContext(adapter, call, processRt) {
7370
7501
  return {
@@ -7423,14 +7554,51 @@ function runTextSession(opts) {
7423
7554
  end: () => handle.close()
7424
7555
  };
7425
7556
  }
7557
+ function deriveCollectFromProgram(program) {
7558
+ const collect = {};
7559
+ for (const [nodeId, node] of Object.entries(program.nodes)) {
7560
+ const cfg = node.config;
7561
+ if (node.type === "ask") {
7562
+ const name = typeof cfg.slot === "string" && cfg.slot ? cfg.slot : nodeId;
7563
+ const type = cfg.type;
7564
+ collect[name] = {
7565
+ type: type === "number" || type === "boolean" || type === "datetime" || type === "string[]" ? type : "string",
7566
+ ...cfg.required !== false ? { required: true } : {},
7567
+ ...typeof cfg.ask === "string" ? { ask: cfg.ask } : {},
7568
+ ...typeof cfg.pattern === "string" ? { pattern: new RegExp(cfg.pattern) } : {}
7569
+ };
7570
+ }
7571
+ if (cfg.outputAs && typeof cfg.outputAs === "object") {
7572
+ for (const slot of Object.keys(cfg.outputAs)) {
7573
+ collect[slot] ??= { type: "string" };
7574
+ }
7575
+ }
7576
+ if (Array.isArray(cfg.assignments)) {
7577
+ for (const a of cfg.assignments) {
7578
+ if (a && typeof a.name === "string" && a.name.trim()) collect[a.name.trim()] ??= { type: "string" };
7579
+ }
7580
+ }
7581
+ }
7582
+ return { collect, completeWhen: "all-required-captured" };
7583
+ }
7584
+ function definitionFor(opts) {
7585
+ if (opts.schema) {
7586
+ try {
7587
+ return processSchemaToDefinition(opts.schema);
7588
+ } catch {
7589
+ }
7590
+ }
7591
+ return deriveCollectFromProgram(opts.program);
7592
+ }
7426
7593
  async function runTextTranscript(opts) {
7427
7594
  const replies = [];
7428
7595
  const trace7 = [];
7596
+ const processRt = opts.processRt ?? createProcessRuntime(definitionFor(opts));
7429
7597
  const session = runTextSession({
7430
7598
  program: opts.program,
7431
7599
  onAgentText: (t) => void replies.push(t),
7432
7600
  onTrace: (e) => void trace7.push(e),
7433
- ...opts.processRt ? { processRt: opts.processRt } : {},
7601
+ ...processRt ? { processRt } : {},
7434
7602
  ...opts.generate ? { generate: opts.generate } : {},
7435
7603
  ...opts.call ? { call: opts.call } : {},
7436
7604
  ...opts.maxSteps !== void 0 ? { maxSteps: opts.maxSteps } : {}
@@ -8190,125 +8358,6 @@ function computeEmptyRequired(view) {
8190
8358
  }
8191
8359
  return empty;
8192
8360
  }
8193
-
8194
- // src/flow-runtime.ts
8195
- init_define_tool();
8196
- function processSchemaToDefinition(schema) {
8197
- const required = new Set(schema.completionGate.requiredFields);
8198
- const collect = {};
8199
- for (const f of schema.fields) {
8200
- collect[f.name] = {
8201
- type: f.type,
8202
- required: required.has(f.name) || f.required,
8203
- ...f.ask !== void 0 ? { ask: f.ask } : {},
8204
- ...f.pattern !== void 0 ? { pattern: new RegExp(f.pattern) } : {},
8205
- ...f.min !== void 0 ? { min: f.min } : {},
8206
- ...f.max !== void 0 ? { max: f.max } : {},
8207
- ...f.enum !== void 0 ? { enum: f.enum } : {}
8208
- };
8209
- }
8210
- return {
8211
- collect,
8212
- completeWhen: "all-required-captured",
8213
- ...schema.completionGate.backendAck !== void 0 ? { backendAck: schema.completionGate.backendAck } : {}
8214
- };
8215
- }
8216
- var DEFAULT_FLOW_PROMPT = "You are a helpful voice assistant. Keep replies short and natural.";
8217
- function toTriggerCondition(on) {
8218
- return on.startsWith("signal:") ? on : new RegExp(on, "i");
8219
- }
8220
- function toTriggerAction(then, graphNodeIds) {
8221
- if (then === "endCall" || then === "end") return "endCall";
8222
- if (then === "handoff") return "handoff";
8223
- if (then.startsWith("say:")) return { say: then.slice(4).trim() };
8224
- if (graphNodeIds?.has(then)) return { goto: then };
8225
- return "handoff";
8226
- }
8227
- function processSchemaToAgentParts(schema, opts = {}) {
8228
- const process2 = processSchemaToDefinition(schema);
8229
- const promptParts = [];
8230
- if (opts.basePrompt && opts.basePrompt.trim()) promptParts.push(opts.basePrompt.trim());
8231
- for (const p of schema.prompts ?? []) {
8232
- if (p.text.trim()) promptParts.push(p.text.trim());
8233
- }
8234
- const prompt = promptParts.length > 0 ? promptParts.join("\n\n") : DEFAULT_FLOW_PROMPT;
8235
- let triggers;
8236
- if (schema.triggers && schema.triggers.length > 0) {
8237
- triggers = {};
8238
- for (const t of schema.triggers) {
8239
- triggers[t.name] = {
8240
- on: toTriggerCondition(t.on),
8241
- then: toTriggerAction(t.then, opts.graphNodeIds),
8242
- ...t.onlyWhile ? { onlyWhile: t.onlyWhile } : {}
8243
- };
8244
- }
8245
- }
8246
- const handoff = schema.handoff?.fallback ? {
8247
- fallback: schema.handoff.fallback,
8248
- ...schema.handoff.routes ? { routes: schema.handoff.routes } : {}
8249
- } : void 0;
8250
- const memory = schema.memory ? {
8251
- ...schema.memory.scope ? { scope: schema.memory.scope } : {},
8252
- ...schema.memory.retentionDays !== void 0 ? { retentionDays: schema.memory.retentionDays } : {},
8253
- ...schema.memory.piiFields ? { piiFields: schema.memory.piiFields } : {}
8254
- } : void 0;
8255
- let tools;
8256
- if (schema.tools && schema.tools.length > 0) {
8257
- tools = {};
8258
- for (const t of schema.tools) {
8259
- if (t.auth === "connection") {
8260
- tools[t.name] = {
8261
- description: t.description,
8262
- input: t.input,
8263
- run: () => ({
8264
- kind: "unavailable",
8265
- reason: "connection-auth tools need the vault resolver (not wired yet)"
8266
- })
8267
- };
8268
- continue;
8269
- }
8270
- Object.assign(
8271
- tools,
8272
- httpTool({
8273
- name: t.name,
8274
- description: t.description,
8275
- input: t.input,
8276
- url: t.url,
8277
- method: t.method,
8278
- ...t.headers ? { headers: t.headers } : {}
8279
- })
8280
- );
8281
- }
8282
- }
8283
- let speech;
8284
- if (schema.speech) {
8285
- const i = schema.speech.interruption;
8286
- const e = schema.speech.endpointing;
8287
- const interruption = i ? {
8288
- ...i.enabled !== void 0 ? { enabled: i.enabled } : {},
8289
- ...i.minWords !== void 0 ? { minWords: i.minWords } : {},
8290
- ...i.minDuration !== void 0 ? { minDuration: i.minDuration } : {}
8291
- } : void 0;
8292
- const endpointing = e ? {
8293
- ...e.minDelay !== void 0 ? { minDelay: e.minDelay } : {},
8294
- ...e.maxDelay !== void 0 ? { maxDelay: e.maxDelay } : {}
8295
- } : void 0;
8296
- speech = {
8297
- ...interruption && Object.keys(interruption).length ? { interruption } : {},
8298
- ...endpointing && Object.keys(endpointing).length ? { endpointing } : {}
8299
- };
8300
- if (Object.keys(speech).length === 0) speech = void 0;
8301
- }
8302
- return {
8303
- prompt,
8304
- process: process2,
8305
- ...triggers ? { triggers } : {},
8306
- ...handoff ? { handoff } : {},
8307
- ...memory ? { memory } : {},
8308
- ...tools ? { tools } : {},
8309
- ...speech ? { speech } : {}
8310
- };
8311
- }
8312
8361
  var BrainConfigError = class extends Error {
8313
8362
  constructor(message) {
8314
8363
  super(message);
@@ -10987,7 +11036,7 @@ async function executeHandoff(args, config, deps) {
10987
11036
  });
10988
11037
  }
10989
11038
  }
10990
- if (sipOps) {
11039
+ if (sipOps && isSipParticipant(deps.callerIdentity)) {
10991
11040
  if (mode === "warm") {
10992
11041
  await sayFixed(deps, "I'm transferring you now \u2014 one moment.");
10993
11042
  }
@@ -11003,6 +11052,19 @@ async function executeHandoff(args, config, deps) {
11003
11052
  error: err instanceof Error ? err.message : String(err)
11004
11053
  });
11005
11054
  }
11055
+ } else if (sipOps) {
11056
+ console.warn("[handoff] caller has no SIP leg; cannot transfer this channel", {
11057
+ callerIdentity: deps.callerIdentity,
11058
+ conferenceAvailable: sipOps.canConference
11059
+ });
11060
+ notify("handoff.unavailable", {
11061
+ to: args.to,
11062
+ reason: sipOps.canConference ? "caller has no SIP leg (web/playground call)" : "caller has no SIP leg and no outbound trunk is configured for conferencing"
11063
+ });
11064
+ await sayFixed(
11065
+ deps,
11066
+ "I'm not able to connect you to a person on this channel \u2014 please call our phone line and we'll pick up right where we left off."
11067
+ );
11006
11068
  }
11007
11069
  try {
11008
11070
  await deps.disconnect();
@@ -11052,6 +11114,9 @@ function buildDefaultSipOps() {
11052
11114
  }
11053
11115
  };
11054
11116
  }
11117
+ function isSipParticipant(identity) {
11118
+ return !/^(user[-_]|web[-_]|playground[-_]|vl-client)/i.test(identity.trim());
11119
+ }
11055
11120
  function normalizeSipTarget(target) {
11056
11121
  if (target.startsWith("sip:") || target.startsWith("tel:")) return target;
11057
11122
  return `tel:${target}`;
@@ -1,3 +1,3 @@
1
- export { a6 as GraphTraceEvent, q as RunTextSessionOptions, r as RunTextTranscriptOptions, T as TextSession, O as TextTranscriptResult, a3 as runTextSession, a4 as runTextTranscript } from '../text-session-BoUmDEX9.js';
1
+ export { aa as GraphTraceEvent, u as RunTextSessionOptions, v as RunTextTranscriptOptions, V as TextSession, W as TextTranscriptResult, a7 as runTextSession, a8 as runTextTranscript } from '../text-session-D1j8nQac.js';
2
2
  import '@livekit/agents';
3
3
  import 'zod';