@voicelayer/sdk 0.5.0 → 0.6.0

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.
@@ -81,14 +81,14 @@ declare const ConnectorUpFrame: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
81
81
  code: z.ZodEnum<["upstream_timeout", "upstream_error", "bad_response", "normalize_failed", "unreachable"]>;
82
82
  message: z.ZodString;
83
83
  }, "strip", z.ZodTypeAny, {
84
+ kind: "brain.error";
84
85
  code: "upstream_timeout" | "upstream_error" | "bad_response" | "normalize_failed" | "unreachable";
85
86
  message: string;
86
- kind: "brain.error";
87
87
  streamId: string;
88
88
  }, {
89
+ kind: "brain.error";
89
90
  code: "upstream_timeout" | "upstream_error" | "bad_response" | "normalize_failed" | "unreachable";
90
91
  message: string;
91
- kind: "brain.error";
92
92
  streamId: string;
93
93
  }>]>;
94
94
  type ConnectorUpFrame = z.infer<typeof ConnectorUpFrame>;
@@ -434,6 +434,8 @@ var FlowNodeType = z.enum([
434
434
  "ask",
435
435
  "confirm",
436
436
  "tool",
437
+ // Send an email through the workspace's email (metered, wallet-gated; From on a verified domain) — burn-down G-22.
438
+ "email",
437
439
  "decision",
438
440
  "handoff",
439
441
  "end",
@@ -626,7 +628,15 @@ var ProcessToolDTO = z.object({
626
628
  * Self-hosted workers only: allow a private / loopback address (a localhost service of your own). A platform
627
629
  * worker (it holds the internal service token) never honours it.
628
630
  */
629
- allowPrivateNetwork: z.boolean().optional()
631
+ allowPrivateNetwork: z.boolean().optional(),
632
+ /**
633
+ * Burn-down G-33: the model reads the caller's PII as tokens (`<PII_PHONE_1>`). `true` — this tool's arguments carry
634
+ * the caller's real values instead, when its URL fixes the host (publish refuses it on a host the call fills in).
635
+ * Absent — real values only when it signs in with a connection; otherwise the endpoint gets the tokens. `false` —
636
+ * always the tokens.
637
+ * (packages/sdk/test/tool-detokenise.test.ts)
638
+ */
639
+ sendRealValues: z.boolean().optional()
630
640
  });
631
641
  var ProcessSchemaDTO = z.object({
632
642
  id: z.string().min(1).max(64),
@@ -1186,8 +1196,14 @@ var AgentConfig = z.object({
1186
1196
  // collects nothing structured. DERIVED from the agents row; read-only.
1187
1197
  requiredInfo: z.array(RequiredInfoField).max(64).default([]),
1188
1198
  createdAt: z.string().datetime(),
1189
- // Optimistic-lock token. PATCH must echo this in If-Match.
1190
- updatedAt: z.string().datetime()
1199
+ // On the draft view: when the draft row last changed. On the published view (GET /config's default): when what runs
1200
+ // last changed — the published version's createdAt. Only the draft's is the PATCH lock token: send draftUpdatedAt.
1201
+ updatedAt: z.string().datetime(),
1202
+ // The optimistic-lock token PATCH /v1/agents/:id/config checks (If-Match; also sent, quoted, as the ETag): the DRAFT
1203
+ // row's updatedAt. Always on the draft view; on the published view only while the draft equals what's published —
1204
+ // otherwise absent, and an editor reads ?view=draft, so it never writes over unpublished changes it didn't see
1205
+ // (burn-down G-37). A projection of the existing column, not a stored field (agents DECISIONS A-7 stands).
1206
+ draftUpdatedAt: z.string().datetime().optional()
1191
1207
  });
1192
1208
 
1193
1209
  // ../contracts/src/call-plan.ts
@@ -1395,6 +1411,56 @@ z.object({
1395
1411
  ok: z.literal(true),
1396
1412
  scopesPurged: z.array(MemoryScope)
1397
1413
  });
1414
+ var EMAIL_RE = /^[^\s@<>"]+@[^\s@<>"]+\.[^\s@<>"]+$/;
1415
+ function isEmailAddress(value) {
1416
+ return EMAIL_RE.test(value) && value.length <= 254;
1417
+ }
1418
+ var EMAIL_SUBJECT_MAX = 200;
1419
+ var EMAIL_TEXT_MAX = 5e4;
1420
+ var EMAIL_HTML_MAX = 2e5;
1421
+ var address = z.string().max(254).refine(isEmailAddress, { message: "must be an email address" });
1422
+ z.object({
1423
+ to: address,
1424
+ subject: z.string().min(1).max(EMAIL_SUBJECT_MAX),
1425
+ text: z.string().min(1).max(EMAIL_TEXT_MAX),
1426
+ html: z.string().min(1).max(EMAIL_HTML_MAX).optional(),
1427
+ // An address on one of the workspace's verified sending domains; omitted → the platform sender.
1428
+ from: address.optional(),
1429
+ // The display name shown beside `from` (or beside the platform sender's address).
1430
+ fromName: z.string().trim().min(1).max(64).refine((v) => !/[\r\n<>"]/.test(v), { message: 'must not contain line breaks, <, > or "' }).optional(),
1431
+ // Where a reply goes — any address; it needs no verification.
1432
+ replyTo: address.optional(),
1433
+ // The conversation (a call, a text conversation) the email belongs to — a conversation sends at most 3 emails.
1434
+ conversationId: z.string().min(1).max(128).optional()
1435
+ });
1436
+ var DOMAIN_RE = /^(?=.{4,253}$)(?!-)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/;
1437
+ function normalizeDomain(input) {
1438
+ return input.trim().toLowerCase().replace(/^[a-z]+:\/\//, "").replace(/\/.*$/, "").replace(/\.$/, "");
1439
+ }
1440
+ function isDomainName(value) {
1441
+ return DOMAIN_RE.test(value);
1442
+ }
1443
+ z.object({
1444
+ domain: z.string().max(253).transform(normalizeDomain).refine(isDomainName, { message: "must be a domain like example.com" })
1445
+ });
1446
+ var EmailDomainStatus = z.enum(["pending", "verified", "failed"]);
1447
+ var EmailDnsRecord = z.object({
1448
+ type: z.enum(["CNAME", "TXT"]),
1449
+ name: z.string(),
1450
+ value: z.string(),
1451
+ // dkim: proves the domain (required); dmarc: recommended, only when the domain has no DMARC record yet.
1452
+ purpose: z.enum(["dkim", "dmarc"]),
1453
+ required: z.boolean()
1454
+ });
1455
+ z.object({
1456
+ id: z.string(),
1457
+ domain: z.string(),
1458
+ status: EmailDomainStatus,
1459
+ records: z.array(EmailDnsRecord),
1460
+ createdAt: z.string().datetime(),
1461
+ lastCheckedAt: z.string().datetime().nullable(),
1462
+ verifiedAt: z.string().datetime().nullable()
1463
+ });
1398
1464
  z.object({
1399
1465
  systemPrompt: z.string().max(64e3),
1400
1466
  routingInstructions: z.string().max(32e3).nullable(),
@@ -1470,21 +1536,27 @@ z.object({
1470
1536
 
1471
1537
  // ../contracts/src/providers.ts
1472
1538
  var PROVIDERS = {
1473
- openai: { id: "openai", label: "OpenAI", capabilities: ["llm", "tts", "realtime"], byok: true, supportsBaseUrl: true, keyPlaceholder: "sk-..." },
1474
- anthropic: { id: "anthropic", label: "Anthropic", capabilities: ["llm"], byok: true, supportsBaseUrl: true, keyPlaceholder: "sk-ant-..." },
1475
- deepgram: { id: "deepgram", label: "Deepgram", capabilities: ["stt", "tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "Deepgram API key" },
1476
- elevenlabs: { id: "elevenlabs", label: "ElevenLabs", capabilities: ["tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "ElevenLabs API key" },
1477
- cartesia: { id: "cartesia", label: "Cartesia", capabilities: ["stt", "tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "Cartesia API key" },
1478
- assemblyai: { id: "assemblyai", label: "AssemblyAI", capabilities: ["stt"], byok: true, supportsBaseUrl: false, keyPlaceholder: "AssemblyAI API key" },
1479
- google: { id: "google", label: "Google (Gemini)", capabilities: ["llm", "realtime"], byok: true, supportsBaseUrl: false, keyPlaceholder: "AIza..." },
1480
- groq: { id: "groq", label: "Groq", capabilities: ["llm"], byok: true, supportsBaseUrl: true, keyPlaceholder: "gsk_..." },
1539
+ openai: { id: "openai", label: "OpenAI", capabilities: ["llm", "tts", "realtime"], byok: true, supportsBaseUrl: true, keyPlaceholder: "sk-...", runsOn: { llm: ["voice", "text"], tts: ["voice"], realtime: ["voice"] }, platformKeyEnv: "OPENAI_API_KEY" },
1540
+ // No platform runtime: LiveKit's anthropic plugin needs @livekit/agents >= 1.5 (the workers pin 1.4.0 — the 1.7 audio
1541
+ // regression), and the API's text replies run OpenAI only (burn-down G-9).
1542
+ anthropic: { id: "anthropic", label: "Anthropic", capabilities: ["llm"], byok: true, supportsBaseUrl: true, keyPlaceholder: "sk-ant-...", runsOn: { llm: [] }, platformKeyEnv: "ANTHROPIC_API_KEY" },
1543
+ deepgram: { id: "deepgram", label: "Deepgram", capabilities: ["stt", "tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "Deepgram API key", runsOn: { stt: ["voice"], tts: ["voice"] }, platformKeyEnv: "DEEPGRAM_API_KEY" },
1544
+ elevenlabs: { id: "elevenlabs", label: "ElevenLabs", capabilities: ["tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "ElevenLabs API key", runsOn: { tts: ["voice"] }, platformKeyEnv: "ELEVEN_API_KEY" },
1545
+ // Cartesia's LiveKit plugin (1.4.0) ships TTS only: its speech-to-text has no runtime.
1546
+ cartesia: { id: "cartesia", label: "Cartesia", capabilities: ["stt", "tts"], byok: true, supportsBaseUrl: false, keyPlaceholder: "Cartesia API key", runsOn: { stt: [], tts: ["voice"] }, platformKeyEnv: "CARTESIA_API_KEY" },
1547
+ assemblyai: { id: "assemblyai", label: "AssemblyAI", capabilities: ["stt"], byok: true, supportsBaseUrl: false, keyPlaceholder: "AssemblyAI API key", runsOn: { stt: ["voice"] }, platformKeyEnv: "ASSEMBLYAI_API_KEY" },
1548
+ // Gemini on text waits on burn-down G-9 (the API's text replies run OpenAI only).
1549
+ google: { id: "google", label: "Google (Gemini)", capabilities: ["llm", "realtime"], byok: true, supportsBaseUrl: false, keyPlaceholder: "AIza...", runsOn: { llm: ["voice"], realtime: ["voice"] }, platformKeyEnv: "GOOGLE_API_KEY" },
1550
+ groq: { id: "groq", label: "Groq", capabilities: ["llm"], byok: true, supportsBaseUrl: true, keyPlaceholder: "gsk_...", runsOn: { llm: [] }, platformKeyEnv: "GROQ_API_KEY" },
1481
1551
  // Runtime-only providers (no external key): local VAD.
1482
- silero: { id: "silero", label: "Silero", capabilities: ["vad"], byok: false, supportsBaseUrl: false }
1552
+ silero: { id: "silero", label: "Silero", capabilities: ["vad"], byok: false, supportsBaseUrl: false, runsOn: { vad: ["voice"] } }
1483
1553
  };
1484
1554
  function byokProviders() {
1485
1555
  return Object.values(PROVIDERS).filter((p) => p.byok);
1486
1556
  }
1487
1557
  var ProviderKind = z.enum(["llm", "stt", "tts", "realtime"]);
1558
+ var ModelSurface = z.enum(["voice", "text"]);
1559
+ var ProviderKeySource = z.enum(["workspace", "platform", "none"]);
1488
1560
  var CatalogVoice = z.object({
1489
1561
  id: z.string().min(1).max(128),
1490
1562
  label: z.string().min(1).max(128),
@@ -1518,7 +1590,12 @@ var CatalogProvider = z.object({
1518
1590
  // Populated for tts / realtime providers.
1519
1591
  voices: z.array(CatalogVoice).optional(),
1520
1592
  // Pre-selected when the provider is chosen.
1521
- defaultModel: z.string().max(128).optional()
1593
+ defaultModel: z.string().max(128).optional(),
1594
+ // The surfaces the platform runs this provider's models on (contracts PROVIDERS `runsOn`). A picker offers the
1595
+ // provider only for a surface listed here; absent means none, so an unrunnable provider is never offered by default.
1596
+ surfaces: z.array(ModelSurface).default([]),
1597
+ // Whose key this provider would run on for the requesting workspace; unknown means none.
1598
+ key: ProviderKeySource.default("none")
1522
1599
  });
1523
1600
  z.object({
1524
1601
  llm: z.array(CatalogProvider).default([]),
@@ -1573,8 +1650,26 @@ z.object({
1573
1650
  // The assumptions actually used (after defaults) — drives the UI footnote.
1574
1651
  assumptions: CostEstimateAssumptions.required()
1575
1652
  });
1653
+
1654
+ // ../contracts/src/openai-models.ts
1655
+ function categorizeOpenAiModel(id) {
1656
+ const s = id.toLowerCase();
1657
+ if (s.includes("realtime")) return "realtime";
1658
+ if (s.includes("transcribe") || s.includes("whisper")) return "stt";
1659
+ if (s.includes("tts") || s.includes("audio-speech")) return "tts";
1660
+ if (/embedding|moderation|dall-e|image|^omni-|^text-|search|rerank|babbage|davinci|codex/.test(s)) {
1661
+ return null;
1662
+ }
1663
+ if (/-pro\b|deep-research|computer-use/.test(s)) return null;
1664
+ if (/^(gpt|o[0-9]|chatgpt)/.test(s)) return "llm";
1665
+ return null;
1666
+ }
1667
+ function isOpenAiChatModel(id) {
1668
+ return categorizeOpenAiModel(id) === "llm";
1669
+ }
1576
1670
  var EvaluationMetric = z.enum(["rating", "binary", "options", "text"]);
1577
1671
  var EvaluationStatus = z.enum(["pending", "scored", "failed"]);
1672
+ var EvaluationJudgeModel = z.string().min(1).max(128).refine(isOpenAiChatModel, { message: "The judge runs OpenAI chat models only (e.g. gpt-4o-mini)." });
1578
1673
  var EvaluationOption = z.object({
1579
1674
  value: z.string().min(1).max(64),
1580
1675
  label: z.string().min(1).max(120),
@@ -1586,6 +1681,7 @@ z.object({
1586
1681
  name: z.string().min(1).max(120),
1587
1682
  criteria: z.string().max(4e3),
1588
1683
  metric: EvaluationMetric,
1684
+ // a stored row may predate the judge-model rule; it is judged on the default (EVALUATION_JUDGE_SUGGESTIONS)
1589
1685
  model: z.string().min(1).max(128),
1590
1686
  minValue: z.number().int().nullable(),
1591
1687
  minLabel: z.string().nullable(),
@@ -1601,7 +1697,7 @@ var EvaluationInput = z.object({
1601
1697
  name: z.string().min(1).max(120),
1602
1698
  criteria: z.string().max(4e3).default(""),
1603
1699
  metric: EvaluationMetric.default("rating"),
1604
- model: z.string().min(1).max(128).default("gpt-4o-mini"),
1700
+ model: EvaluationJudgeModel.default("gpt-4o-mini"),
1605
1701
  minValue: z.number().int().nullable().optional(),
1606
1702
  minLabel: z.string().max(200).nullable().optional(),
1607
1703
  maxValue: z.number().int().nullable().optional(),
@@ -1763,7 +1859,10 @@ var ToolCallAudit = z.object({
1763
1859
  ok: z.boolean(),
1764
1860
  // refused by the Action Guard before it ran
1765
1861
  blocked: z.boolean(),
1766
- errorMessage: z.string().optional()
1862
+ errorMessage: z.string().optional(),
1863
+ // Burn-down G-33: the call's PII tokens swapped back for the caller's real values in this tool's arguments (it went to
1864
+ // a trusted destination) — how many, and the host they went to (null: the agent's own code). Never a value.
1865
+ detokenized: z.object({ count: z.number().int().min(1), destinationHost: z.string().nullable() }).optional()
1767
1866
  });
1768
1867
  var McpInteractionAudit = z.object({
1769
1868
  // One of the four runtime tools — closed set, no growth allowed.
@@ -2429,7 +2528,14 @@ z.discriminatedUnion("kind", [
2429
2528
  BrainRequestFrame,
2430
2529
  BrainCancelFrame
2431
2530
  ]);
2432
- var FLOW_BOOT_FAILURES = ["schema_fetch_failed", "no_process_schema", "missing_agent_id", "no_api_key", "worker_identity_refused"];
2531
+ var FLOW_BOOT_FAILURES = [
2532
+ "schema_fetch_failed",
2533
+ "no_process_schema",
2534
+ "missing_agent_id",
2535
+ "no_api_key",
2536
+ "worker_identity_refused",
2537
+ "provider_unavailable"
2538
+ ];
2433
2539
  z.enum(
2434
2540
  FLOW_BOOT_FAILURES.map((cause) => `flow_boot:${cause}`)
2435
2541
  );